From 85776cf650adb101c598d1d1e4e03901ad9e6eaf Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Wed, 15 Jul 2026 17:15:32 -0400 Subject: [PATCH] =?UTF-8?q?feat(browse):=20Wave-0=20Batch=20A=20=E2=80=94?= =?UTF-8?q?=20SupportsOnlineDiscovery=20gate,=20Commons=20ref,=20TagModal?= =?UTF-8?q?=20editor=20plumbing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task 1: ITagDiscovery.SupportsOnlineDiscovery default member (=> false) Task 2: Commons -> Core.Abstractions ProjectReference Task 13: TagModal BuildEditorParameters passes DriverType + GetDriverConfigJson; all 7 typed tag editors declare the two new [Parameter]s (DynamicComponent throws on unmatched params, so every editor must accept them). --- .../ZB.MOM.WW.OtOpcUa.Commons.csproj | 4 ++++ .../ITagDiscovery.cs | 8 +++++++ .../Uns/TagEditors/AbCipTagConfigEditor.razor | 4 ++++ .../TagEditors/AbLegacyTagConfigEditor.razor | 4 ++++ .../Uns/TagEditors/FocasTagConfigEditor.razor | 4 ++++ .../TagEditors/ModbusTagConfigEditor.razor | 4 ++++ .../OpcUaClientTagConfigEditor.razor | 4 ++++ .../Uns/TagEditors/S7TagConfigEditor.razor | 4 ++++ .../TagEditors/TwinCATTagConfigEditor.razor | 4 ++++ .../Components/Shared/Uns/TagModal.razor | 2 ++ .../TagDiscoveryDefaultsTests.cs | 21 +++++++++++++++++++ 11 files changed, 63 insertions(+) create mode 100644 tests/Core/ZB.MOM.WW.OtOpcUa.Core.Abstractions.Tests/TagDiscoveryDefaultsTests.cs diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/ZB.MOM.WW.OtOpcUa.Commons.csproj b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/ZB.MOM.WW.OtOpcUa.Commons.csproj index f90281ea..55b52d43 100644 --- a/src/Core/ZB.MOM.WW.OtOpcUa.Commons/ZB.MOM.WW.OtOpcUa.Commons.csproj +++ b/src/Core/ZB.MOM.WW.OtOpcUa.Commons/ZB.MOM.WW.OtOpcUa.Commons.csproj @@ -10,4 +10,8 @@ + + + + diff --git a/src/Core/ZB.MOM.WW.OtOpcUa.Core.Abstractions/ITagDiscovery.cs b/src/Core/ZB.MOM.WW.OtOpcUa.Core.Abstractions/ITagDiscovery.cs index c63b5268..cc713a1b 100644 --- a/src/Core/ZB.MOM.WW.OtOpcUa.Core.Abstractions/ITagDiscovery.cs +++ b/src/Core/ZB.MOM.WW.OtOpcUa.Core.Abstractions/ITagDiscovery.cs @@ -30,4 +30,12 @@ public interface ITagDiscovery /// Post-connect re-discovery policy. Default preserves the original retry-until-stable behavior. DiscoveryRediscoverPolicy RediscoverPolicy => DiscoveryRediscoverPolicy.UntilStable; + + /// + /// True when enumerates the tag set from the live backend + /// (browsable by the universal discovery browser), rather than replaying + /// pre-declared/authored tags. Default false — flat-address drivers stay manual-entry. + /// See docs/plans/2026-07-15-universal-discovery-browser-design.md §5. + /// + bool SupportsOnlineDiscovery => false; } diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/AbCipTagConfigEditor.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/AbCipTagConfigEditor.razor index 27328ab8..8c400946 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/AbCipTagConfigEditor.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/AbCipTagConfigEditor.razor @@ -41,6 +41,10 @@ @code { [Parameter] public string? ConfigJson { get; set; } [Parameter] public EventCallback ConfigJsonChanged { get; set; } + /// DriverType of the selected driver — lets browse-capable pickers open a universal session. + [Parameter] public string DriverType { get; set; } = ""; + /// Live accessor for the selected driver's DriverConfig JSON (browse connect config). + [Parameter] public Func GetDriverConfigJson { get; set; } = () => "{}"; private AbCipTagConfigModel _m = new(); private string? _lastConfigJson; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/AbLegacyTagConfigEditor.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/AbLegacyTagConfigEditor.razor index 8f770103..9a657d1a 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/AbLegacyTagConfigEditor.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/AbLegacyTagConfigEditor.razor @@ -41,6 +41,10 @@ @code { [Parameter] public string? ConfigJson { get; set; } [Parameter] public EventCallback ConfigJsonChanged { get; set; } + /// DriverType of the selected driver — lets browse-capable pickers open a universal session. + [Parameter] public string DriverType { get; set; } = ""; + /// Live accessor for the selected driver's DriverConfig JSON (browse connect config). + [Parameter] public Func GetDriverConfigJson { get; set; } = () => "{}"; private AbLegacyTagConfigModel _m = new(); private string? _lastConfigJson; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/FocasTagConfigEditor.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/FocasTagConfigEditor.razor index 5eec1f55..bc114cd1 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/FocasTagConfigEditor.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/FocasTagConfigEditor.razor @@ -39,6 +39,10 @@ @code { [Parameter] public string? ConfigJson { get; set; } [Parameter] public EventCallback ConfigJsonChanged { get; set; } + /// DriverType of the selected driver — lets browse-capable pickers open a universal session. + [Parameter] public string DriverType { get; set; } = ""; + /// Live accessor for the selected driver's DriverConfig JSON (browse connect config). + [Parameter] public Func GetDriverConfigJson { get; set; } = () => "{}"; private FocasTagConfigModel _m = new(); private string? _lastConfigJson; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/ModbusTagConfigEditor.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/ModbusTagConfigEditor.razor index b9449866..116f9bd5 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/ModbusTagConfigEditor.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/ModbusTagConfigEditor.razor @@ -49,6 +49,10 @@ @code { [Parameter] public string? ConfigJson { get; set; } [Parameter] public EventCallback ConfigJsonChanged { get; set; } + /// DriverType of the selected driver — lets browse-capable pickers open a universal session. + [Parameter] public string DriverType { get; set; } = ""; + /// Live accessor for the selected driver's DriverConfig JSON (browse connect config). + [Parameter] public Func GetDriverConfigJson { get; set; } = () => "{}"; private ModbusTagConfigModel _m = new(); private string? _lastConfigJson; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/OpcUaClientTagConfigEditor.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/OpcUaClientTagConfigEditor.razor index 58ea6ade..ef4c9d34 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/OpcUaClientTagConfigEditor.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/OpcUaClientTagConfigEditor.razor @@ -11,6 +11,10 @@ @code { [Parameter] public string? ConfigJson { get; set; } [Parameter] public EventCallback ConfigJsonChanged { get; set; } + /// DriverType of the selected driver — lets browse-capable pickers open a universal session. + [Parameter] public string DriverType { get; set; } = ""; + /// Live accessor for the selected driver's DriverConfig JSON (browse connect config). + [Parameter] public Func GetDriverConfigJson { get; set; } = () => "{}"; private OpcUaClientTagConfigModel _m = new(); private string? _lastConfigJson; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/S7TagConfigEditor.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/S7TagConfigEditor.razor index aba5047a..7d95c364 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/S7TagConfigEditor.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/S7TagConfigEditor.razor @@ -41,6 +41,10 @@ @code { [Parameter] public string? ConfigJson { get; set; } [Parameter] public EventCallback ConfigJsonChanged { get; set; } + /// DriverType of the selected driver — lets browse-capable pickers open a universal session. + [Parameter] public string DriverType { get; set; } = ""; + /// Live accessor for the selected driver's DriverConfig JSON (browse connect config). + [Parameter] public Func GetDriverConfigJson { get; set; } = () => "{}"; private S7TagConfigModel _m = new(); private string? _lastConfigJson; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/TwinCATTagConfigEditor.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/TwinCATTagConfigEditor.razor index 143fdee0..cb369480 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/TwinCATTagConfigEditor.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagEditors/TwinCATTagConfigEditor.razor @@ -41,6 +41,10 @@ @code { [Parameter] public string? ConfigJson { get; set; } [Parameter] public EventCallback ConfigJsonChanged { get; set; } + /// DriverType of the selected driver — lets browse-capable pickers open a universal session. + [Parameter] public string DriverType { get; set; } = ""; + /// Live accessor for the selected driver's DriverConfig JSON (browse connect config). + [Parameter] public Func GetDriverConfigJson { get; set; } = () => "{}"; private TwinCATTagConfigModel _m = new(); private string? _lastConfigJson; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagModal.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagModal.razor index 677656b9..a91a79be 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagModal.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Uns/TagModal.razor @@ -353,6 +353,8 @@ { ["ConfigJson"] = _form.TagConfig, ["ConfigJsonChanged"] = EventCallback.Factory.Create(this, v => _form.TagConfig = v), + ["DriverType"] = SelectedDriverType ?? "", + ["GetDriverConfigJson"] = (Func)(() => SelectedDriverConfig), }; // Cache a single NativeAlarmModel parse keyed on the current TagConfig string, so the two computed diff --git a/tests/Core/ZB.MOM.WW.OtOpcUa.Core.Abstractions.Tests/TagDiscoveryDefaultsTests.cs b/tests/Core/ZB.MOM.WW.OtOpcUa.Core.Abstractions.Tests/TagDiscoveryDefaultsTests.cs new file mode 100644 index 00000000..dbe114b7 --- /dev/null +++ b/tests/Core/ZB.MOM.WW.OtOpcUa.Core.Abstractions.Tests/TagDiscoveryDefaultsTests.cs @@ -0,0 +1,21 @@ +using Shouldly; +using ZB.MOM.WW.OtOpcUa.Core.Abstractions; +using Xunit; + +namespace ZB.MOM.WW.OtOpcUa.Core.Abstractions.Tests; + +public class TagDiscoveryDefaultsTests +{ + private sealed class MinimalDiscovery : ITagDiscovery + { + public Task DiscoverAsync(IAddressSpaceBuilder builder, CancellationToken ct) => Task.CompletedTask; + } + + [Fact] + public void SupportsOnlineDiscovery_DefaultsToFalse() => + ((ITagDiscovery)new MinimalDiscovery()).SupportsOnlineDiscovery.ShouldBeFalse(); + + [Fact] + public void RediscoverPolicy_DefaultRemainsUntilStable() => + ((ITagDiscovery)new MinimalDiscovery()).RediscoverPolicy.ShouldBe(DiscoveryRediscoverPolicy.UntilStable); +}