feat(browse): Wave-0 Batch A — SupportsOnlineDiscovery gate, Commons ref, TagModal editor plumbing

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).
This commit is contained in:
Joseph Doherty
2026-07-15 17:15:32 -04:00
parent c006363ec2
commit 85776cf650
11 changed files with 63 additions and 0 deletions
@@ -10,4 +10,8 @@
<PackageReference Include="ZB.MOM.WW.Audit"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ZB.MOM.WW.OtOpcUa.Core.Abstractions\ZB.MOM.WW.OtOpcUa.Core.Abstractions.csproj"/>
</ItemGroup>
</Project>
@@ -30,4 +30,12 @@ public interface ITagDiscovery
/// <summary>Post-connect re-discovery policy. Default preserves the original retry-until-stable behavior.</summary>
DiscoveryRediscoverPolicy RediscoverPolicy => DiscoveryRediscoverPolicy.UntilStable;
/// <summary>
/// True when <see cref="DiscoverAsync"/> 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.
/// </summary>
bool SupportsOnlineDiscovery => false;
}
@@ -41,6 +41,10 @@
@code {
[Parameter] public string? ConfigJson { get; set; }
[Parameter] public EventCallback<string> ConfigJsonChanged { get; set; }
/// <summary>DriverType of the selected driver — lets browse-capable pickers open a universal session.</summary>
[Parameter] public string DriverType { get; set; } = "";
/// <summary>Live accessor for the selected driver's DriverConfig JSON (browse connect config).</summary>
[Parameter] public Func<string> GetDriverConfigJson { get; set; } = () => "{}";
private AbCipTagConfigModel _m = new();
private string? _lastConfigJson;
@@ -41,6 +41,10 @@
@code {
[Parameter] public string? ConfigJson { get; set; }
[Parameter] public EventCallback<string> ConfigJsonChanged { get; set; }
/// <summary>DriverType of the selected driver — lets browse-capable pickers open a universal session.</summary>
[Parameter] public string DriverType { get; set; } = "";
/// <summary>Live accessor for the selected driver's DriverConfig JSON (browse connect config).</summary>
[Parameter] public Func<string> GetDriverConfigJson { get; set; } = () => "{}";
private AbLegacyTagConfigModel _m = new();
private string? _lastConfigJson;
@@ -39,6 +39,10 @@
@code {
[Parameter] public string? ConfigJson { get; set; }
[Parameter] public EventCallback<string> ConfigJsonChanged { get; set; }
/// <summary>DriverType of the selected driver — lets browse-capable pickers open a universal session.</summary>
[Parameter] public string DriverType { get; set; } = "";
/// <summary>Live accessor for the selected driver's DriverConfig JSON (browse connect config).</summary>
[Parameter] public Func<string> GetDriverConfigJson { get; set; } = () => "{}";
private FocasTagConfigModel _m = new();
private string? _lastConfigJson;
@@ -49,6 +49,10 @@
@code {
[Parameter] public string? ConfigJson { get; set; }
[Parameter] public EventCallback<string> ConfigJsonChanged { get; set; }
/// <summary>DriverType of the selected driver — lets browse-capable pickers open a universal session.</summary>
[Parameter] public string DriverType { get; set; } = "";
/// <summary>Live accessor for the selected driver's DriverConfig JSON (browse connect config).</summary>
[Parameter] public Func<string> GetDriverConfigJson { get; set; } = () => "{}";
private ModbusTagConfigModel _m = new();
private string? _lastConfigJson;
@@ -11,6 +11,10 @@
@code {
[Parameter] public string? ConfigJson { get; set; }
[Parameter] public EventCallback<string> ConfigJsonChanged { get; set; }
/// <summary>DriverType of the selected driver — lets browse-capable pickers open a universal session.</summary>
[Parameter] public string DriverType { get; set; } = "";
/// <summary>Live accessor for the selected driver's DriverConfig JSON (browse connect config).</summary>
[Parameter] public Func<string> GetDriverConfigJson { get; set; } = () => "{}";
private OpcUaClientTagConfigModel _m = new();
private string? _lastConfigJson;
@@ -41,6 +41,10 @@
@code {
[Parameter] public string? ConfigJson { get; set; }
[Parameter] public EventCallback<string> ConfigJsonChanged { get; set; }
/// <summary>DriverType of the selected driver — lets browse-capable pickers open a universal session.</summary>
[Parameter] public string DriverType { get; set; } = "";
/// <summary>Live accessor for the selected driver's DriverConfig JSON (browse connect config).</summary>
[Parameter] public Func<string> GetDriverConfigJson { get; set; } = () => "{}";
private S7TagConfigModel _m = new();
private string? _lastConfigJson;
@@ -41,6 +41,10 @@
@code {
[Parameter] public string? ConfigJson { get; set; }
[Parameter] public EventCallback<string> ConfigJsonChanged { get; set; }
/// <summary>DriverType of the selected driver — lets browse-capable pickers open a universal session.</summary>
[Parameter] public string DriverType { get; set; } = "";
/// <summary>Live accessor for the selected driver's DriverConfig JSON (browse connect config).</summary>
[Parameter] public Func<string> GetDriverConfigJson { get; set; } = () => "{}";
private TwinCATTagConfigModel _m = new();
private string? _lastConfigJson;
@@ -353,6 +353,8 @@
{
["ConfigJson"] = _form.TagConfig,
["ConfigJsonChanged"] = EventCallback.Factory.Create<string>(this, v => _form.TagConfig = v),
["DriverType"] = SelectedDriverType ?? "",
["GetDriverConfigJson"] = (Func<string>)(() => SelectedDriverConfig),
};
// Cache a single NativeAlarmModel parse keyed on the current TagConfig string, so the two computed
@@ -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);
}