namespace ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared; /// /// Rendering helpers for operator-facing text that comes out of the database. /// /// /// /// Why this exists (#504). Several pages abbreviated a hash / thumbprint with the range /// operator — @s.SourceHash[..12]… — which throws /// the moment the value is shorter than the slice. /// In Blazor that escapes BuildRenderTree unhandled and takes the whole page to an /// HTTP 500, not just the offending row. Nothing enforces a minimum length at the schema, the /// entity, or the render layer, so any hand-written / seeded / migrated row is a live page-kill. /// The docker-dev seed proved it: its placeholder SourceHash values (h1, /// h-abs-hr200) made /scripts a hard 500 on every stock bring-up. /// /// /// Use for every such prefix. It never throws, and it appends the /// ellipsis only when it actually truncated — a 2-character hash renders as h1, not /// h1…, so the display never implies more text than exists. /// /// public static class DisplayText { /// Placeholder rendered for a null / blank value. Matches the em-dash convention the /// Admin UI already uses for "nothing to show" cells. public const string Empty = "—"; /// /// The first characters of , followed by an /// ellipsis when (and only when) characters were dropped. /// /// The value to abbreviate. May be null, blank, or shorter than /// — none of which throw. /// Maximum number of characters to keep. Values below 1 are treated as 1, /// so a caller cannot turn a display bug into a crash. /// for a null/blank value; the value verbatim when it already fits; /// otherwise the truncated prefix plus an ellipsis. public static string Abbreviate(string? value, int maxLength) { if (string.IsNullOrWhiteSpace(value)) return Empty; if (maxLength < 1) maxLength = 1; return value.Length <= maxLength ? value : string.Concat(value.AsSpan(0, maxLength), "…"); } }