Forge
csharpdeeb25a2
1using System.Globalization;
2using CascadeIDE.Cockpit.DataBus;
3using CascadeIDE.Contracts;
4using CascadeIDE.Models;
5
6namespace CascadeIDE.Features.HybridIndex.Application;
7
8/// <summary>Статические строки лампы/сводки HIS (MFD) по событию DataBus без VM.</summary>
9[PresentationProjection("hybrid-index-his")]
10public static class HybridIndexHisPresentationProjection
11{
12 public static string LampText(HybridIndexStateChanged? last) =>
13 last is null
14 ? "NO DATA"
15 : string.IsNullOrWhiteSpace(last.LastError)
16 ? "OK"
17 : "CAUTION";
18
19 public static string StateShort(HybridIndexStateChanged? last) =>
20 last is null
21 ? "—"
22 : string.IsNullOrWhiteSpace(last.LastError)
23 ? "IDLE"
24 : "ERROR";
25
26 /// <param name="lastErrorBannerText">Текст ошибки для баннера HIS или «—», если пусто.</param>
27 public static string SecondMessageLine(string lastErrorBannerText) =>
28 string.IsNullOrWhiteSpace(lastErrorBannerText) || lastErrorBannerText == "—"
29 ? "NO FAILURES"
30 : lastErrorBannerText;
31
32 /// <summary>Шкала 0..1 по числу документов (верхняя граница — выбор UX).</summary>
33 public static double DocsGauge01(int documentCount, double maxDocs = 3000.0)
34 {
35 if (documentCount <= 0 || maxDocs <= 0)
36 return 0;
37 return Math.Clamp(documentCount / maxDocs, 0, 1);
38 }
39
40 public static double FreshnessTotalMinutes(string? indexedAtIso, DateTimeOffset utcNow)
41 {
42 if (string.IsNullOrWhiteSpace(indexedAtIso))
43 return 0;
44 if (!DateTimeOffset.TryParse(indexedAtIso, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var ts))
45 return 0;
46 var age = utcNow - ts;
47 if (age < TimeSpan.Zero)
48 age = TimeSpan.Zero;
49 return age.TotalMinutes;
50 }
51
52 public static string FreshnessMinutesRoundedText(double totalMinutes)
53 {
54 if (totalMinutes <= 0.5)
55 return "0";
56 if (totalMinutes >= 10_000)
57 return "9999";
58 return Math.Floor(totalMinutes).ToString(CultureInfo.InvariantCulture);
59 }
60
61 public static string FreshnessEcamText(double totalMinutes)
62 {
63 if (totalMinutes <= 0.5)
64 return "0m";
65
66 if (totalMinutes < 60)
67 return $"{Math.Floor(totalMinutes).ToString(CultureInfo.InvariantCulture)}m";
68
69 var h = totalMinutes / 60.0;
70 if (h < 24)
71 return $"{Math.Floor(h).ToString(CultureInfo.InvariantCulture)}h";
72
73 var d = h / 24.0;
74 if (d >= 100)
75 return "99d";
76 return $"{Math.Floor(d).ToString(CultureInfo.InvariantCulture)}d";
77 }
78
79 public static string IndexedAtOrDash(string? indexedAtIso) =>
80 string.IsNullOrWhiteSpace(indexedAtIso) ? "—" : indexedAtIso;
81
82 public static string FreshnessColonLine(string? indexedAtIso, DateTimeOffset utcNow)
83 {
84 if (string.IsNullOrWhiteSpace(indexedAtIso))
85 return "freshness: —";
86 if (!DateTimeOffset.TryParse(indexedAtIso, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var ts))
87 return "freshness: ?";
88 var age = utcNow - ts;
89 if (age < TimeSpan.Zero)
90 age = TimeSpan.Zero;
91 if (age.TotalHours >= 24)
92 return $"freshness: {Math.Floor(age.TotalDays)}d";
93 if (age.TotalMinutes >= 60)
94 return $"freshness: {Math.Floor(age.TotalHours)}h";
95 return $"freshness: {Math.Floor(age.TotalMinutes)}m";
96 }
97
98 public static string OptionalFieldOrDash(string? value) =>
99 string.IsNullOrWhiteSpace(value) ? "—" : value;
100
101 public static string LastErrorOrDash(string? lastError) =>
102 string.IsNullOrWhiteSpace(lastError) ? "—" : lastError!;
103
104 public static AnnunciatorLampItem LampItem(HybridIndexStateChanged? last)
105 {
106 if (last is null)
107 {
108 return new AnnunciatorLampItem(
109 Id: "hci",
110 Title: "HCI",
111 Detail: "No data yet.",
112 Level: AnnunciatorLampLevel.Advisory,
113 LampShortLabel: "HCI");
114 }
115
116 var level = string.IsNullOrWhiteSpace(last.LastError)
117 ? AnnunciatorLampLevel.Ok
118 : AnnunciatorLampLevel.Caution;
119
120 var detail = string.IsNullOrWhiteSpace(last.LastError)
121 ? "OK"
122 : last.LastError!;
123
124 return new AnnunciatorLampItem(
125 Id: "hci",
126 Title: "HCI",
127 Detail: detail,
128 Level: level,
129 LampShortLabel: "HCI");
130 }
131}
132
View only · write via MCP/CIDE