namespace ZB.MOM.WW.OtOpcUa.Commons.Browsing; /// One node in a driver-agnostic browse tree. /// Stable identifier passed back to the picker on commit. For OPC UA /// this is the nsu=...;... form; for Galaxy this is the tag_name. /// Label shown in the tree. /// Whether this node terminates the address (Leaf) or has children /// (Folder). Galaxy never returns Leaves; only the attribute side-panel terminates. /// When true, the UI renders an expand affordance before /// the children have been fetched. public sealed record BrowseNode( string NodeId, string DisplayName, BrowseNodeKind Kind, bool HasChildrenHint); /// Discriminates terminal vs. expandable nodes for UI rendering. public enum BrowseNodeKind { /// Expandable — has (or may have) children. UI shows expand affordance. Folder, /// Terminal — commit on select. Leaf, } /// Metadata for an attribute of a Galaxy object (or the equivalent /// per-driver concept). Surfaced in the picker's attribute side-panel. /// True when this attribute is itself an alarm condition (Galaxy: carries an /// AlarmExtension primitive). The picker pre-fills a default native-alarm alarm object /// into the TagConfig when an alarm attribute is selected. Defaults to false so non-alarm-aware /// drivers (e.g. the OPC UA client browser) aren't forced to flow a flag they don't produce. /// /// The structured address this leaf binds by, as TagConfig key → value in the /// driver's own key vocabulary, for a driver whose address is a tuple rather than a single /// reference string. Null (the default) for every driver whose address IS the /// — nothing changes for them. /// /// It exists because a tuple cannot be recovered from an id string in general. MQTT/Sparkplug /// is the case in point: a browse node id is /// {group}/{node}[/{device}]::{metric}, and a metric name may itself contain / /// (Node Control/Rebirth) — so the session keeps the decomposition it already has and /// states it here, rather than the AdminUI's browse-commit mapper re-deriving it by /// splitting the id and hoping. Same discipline as the v3 address space carrying /// AddressSpaceRealm explicitly instead of parsing it out of a NodeId. /// /// /// The producer states the binding shape too, by which keys it emits — so a consumer /// never has to infer a driver's sub-mode from the tree's geometry. Consumers must read the /// keys they know and ignore the rest; this is a description, not a config blob to splat into /// a persisted TagConfig. /// /// public sealed record AttributeInfo( string Name, string DriverDataType, bool IsArray, string SecurityClass, bool IsAlarm = false, IReadOnlyDictionary? AddressFields = null);