@using ZB.MOM.WW.GalaxyRepository.Grpc @* Recursive Browse hierarchy node. Renders one Galaxy object, its child objects (recursively, lazy-loaded on first expand), and its attributes as right-clickable tag rows. Expansion state is local; children render only while expanded. The expand triangle is shown whenever the server's child_has_children projector hint is set (HasChildrenHint), even before children have been loaded — clicking it triggers OnLoadChildren so the parent page can fill in Node.Children, then the view re-renders. *@
@if (ShowToggle()) { } else { } @(Node.IsArea ? "▣" : "◇") @Node.DisplayName @if (!string.IsNullOrWhiteSpace(Node.Object.TagName) && !string.Equals(Node.Object.TagName, Node.DisplayName, StringComparison.Ordinal)) { @Node.Object.TagName }
@if (_expanded) {
@if (Node.LoadState == BrowseLoadState.Loading) {
⌛ Loading…
} else if (Node.LoadState == BrowseLoadState.Error) { @* Abbreviated: sibling tree rows are nowrap inside a fixed-height scroller, so a full COM/SQL error would stretch the whole pane. *@
Failed to load: @DashboardDisplay.Abbreviate(Node.LoadError, 60)
} @foreach (DashboardBrowseNode child in Node.Children) { } @foreach (GalaxyAttribute attr in Node.Attributes) { GalaxyAttribute row = attr;
· @row.AttributeName @DisplayType(row) @if (row.IsAlarm) { alarm } @if (row.IsHistorized) { hist }
}
}
@code { /// The hierarchy node this view renders. [Parameter] [EditorRequired] public DashboardBrowseNode Node { get; set; } = null!; /// Raised with a tag's full reference when the operator double-clicks it. [Parameter] public EventCallback OnAddTag { get; set; } /// Raised when an attribute row is right-clicked, for the context menu. [Parameter] public EventCallback<(MouseEventArgs Event, GalaxyAttribute Attribute)> OnTagContextMenu { get; set; } /// /// Invoked on first expand when the projector hint says this node has children /// but they have not been fetched yet. The callback is expected to populate /// on the node it receives and then /// trigger a re-render. /// [Parameter] public Func? OnLoadChildren { get; set; } private bool _expanded; // The triangle is shown whenever the projector says children exist (even // pre-load), or attributes are already present, or already-loaded children // are sitting on the node. private bool ShowToggle() { return Node.HasChildrenHint || Node.Attributes.Count > 0 || Node.Children.Count > 0; } private async Task ToggleAsync() { if (!ShowToggle()) { return; } _expanded = !_expanded; if (_expanded && Node.HasChildrenHint && Node.LoadState == BrowseLoadState.NotLoaded && OnLoadChildren is not null) { Node.LoadState = BrowseLoadState.Loading; try { await OnLoadChildren(Node); Node.LoadState = BrowseLoadState.Loaded; } catch (Exception ex) { Node.LoadState = BrowseLoadState.Error; Node.LoadError = ex.Message; } } } private static string DisplayType(GalaxyAttribute attribute) { string baseType = string.IsNullOrWhiteSpace(attribute.DataTypeName) ? "type?" : attribute.DataTypeName; if (attribute.IsArray) { return attribute.ArrayDimensionPresent ? $"{baseType}[{attribute.ArrayDimension}]" : $"{baseType}[]"; } return baseType; } }