@* v3 Batch 3 "+ Add reference" picker: reuses the Raw project tree (RawTree) in picker mode to multi-select raw tags, scoped to the equipment's own cluster. The cluster scope is structural — IUnsTreeService.LoadReferencePickerRootAsync hands back a SINGLE cluster root, so raw tags of any other cluster are simply unreachable through the tree, not merely hidden. On commit the selected tag ids are added as UnsTagReference rows via AddReferencesAsync; the host reloads its Tags list. *@ @using ZB.MOM.WW.OtOpcUa.AdminUI.Uns @using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Raw @inject IUnsTreeService Svc @if (Visible) { } @code { /// Whether the modal is shown. The host owns this flag. [Parameter] public bool Visible { get; set; } /// The equipment the selected raw tags are referenced under. [Parameter] public string? EquipmentId { get; set; } /// Raised after references are committed so the host can reload its Tags list and close. [Parameter] public EventCallback OnCommitted { get; set; } /// Raised when the user cancels so the host can close. [Parameter] public EventCallback OnCancel { get; set; } private IReadOnlyList _roots = Array.Empty(); private readonly HashSet _selected = new(StringComparer.Ordinal); private bool _busy; private bool _loading; private string? _error; private bool _wasVisible; protected override async Task OnParametersSetAsync() { // Reset + reload only on the false→true transition so re-renders while open don't wipe state. if (Visible && !_wasVisible) { _selected.Clear(); _error = null; _roots = Array.Empty(); _loading = true; StateHasChanged(); var root = string.IsNullOrEmpty(EquipmentId) ? null : await Svc.LoadReferencePickerRootAsync(EquipmentId); _roots = root is null ? Array.Empty() : new[] { root }; _loading = false; } _wasVisible = Visible; } private Task> ResolveDescendantsAsync(RawNode node) => Svc.LoadDescendantTagIdsAsync(node); // RawTree mutates _selected in place; this just re-renders the footer count. private void OnSelectionChanged() => StateHasChanged(); private async Task CommitAsync() { if (_selected.Count == 0) { return; } _busy = true; _error = null; try { var res = await Svc.AddReferencesAsync(EquipmentId!, _selected.ToList()); if (res.Ok) { await OnCommitted.InvokeAsync(); } else { _error = res.Error; } } finally { _busy = false; } } private Task CancelAsync() => OnCancel.InvokeAsync(); }