@* Lazy tree component with per-node text filter. Driver-agnostic — consumes
IBrowserSessionService for root/expand. Selected node is bound back to parent
via OnNodeSelected EventCallback. *@
@using ZB.MOM.WW.OtOpcUa.AdminUI.Browsing
@using ZB.MOM.WW.OtOpcUa.Commons.Browsing
@inject IBrowserSessionService BrowserService
@if (_loading)
{
Loading…
}
else if (_error is not null)
{
@_error
}
else if (_roots is null || _roots.Count == 0)
{
No nodes.
}
else
{
@foreach (var n in _roots) { @RenderNode(n, 0) }
}
@code {
/// The browse-session token returned by IBrowserSessionService.OpenAsync.
[Parameter, EditorRequired] public Guid SessionToken { get; set; }
/// The currently-selected node's NodeId, for visual selection highlighting.
[Parameter] public string SelectedNodeId { get; set; } = "";
/// Fired when the user clicks a leaf (or any node — caller decides what to do with it).
[Parameter] public EventCallback OnNodeSelected { get; set; }
private bool _loading = true;
private string? _error;
private List? _roots;
protected override async Task OnInitializedAsync()
{
await LoadRootAsync();
}
private async Task LoadRootAsync()
{
try
{
var roots = await BrowserService.RootAsync(SessionToken, default);
_roots = roots.Select(n => new TreeItem(n)).ToList();
}
catch (Exception ex) { _error = ex.Message; }
finally { _loading = false; }
}
private async Task ToggleAsync(TreeItem item)
{
item.Expanded = !item.Expanded;
if (item.Expanded && !item.Loaded) await ExpandAsync(item);
}
private async Task ExpandAsync(TreeItem item)
{
if (item.Loaded || item.Loading) return;
item.Loading = true; StateHasChanged();
try
{
var kids = await BrowserService.ExpandAsync(SessionToken, item.Node.NodeId, default);
item.Children = kids.Select(k => new TreeItem(k)).ToList();
item.Loaded = true;
}
catch (Exception ex) { item.Error = ex.Message; }
finally { item.Loading = false; StateHasChanged(); }
}
private async Task SelectAsync(TreeItem item)
{
SelectedNodeId = item.Node.NodeId;
await OnNodeSelected.InvokeAsync(item.Node);
}
private RenderFragment RenderNode(TreeItem item, int depth) => __builder =>
{
var indent = $"padding-left:{depth * 18}px";
var selectedCls = SelectedNodeId == item.Node.NodeId ? "bg-primary-subtle" : "";