feat(adminui): DriverTagPicker modal + 9 static address builders
- DriverTagPicker shell: modal chrome + per-driver picker body rendered as ChildContent. - 9 picker bodies (Modbus/AbCip/AbLegacy/S7/TwinCat/FOCAS/ OpcUaClient/Galaxy/Historian.Wonderware). 5 have computed builder logic + unit tests; 4 are free-text passthroughs (live browse for OPC UA + Galaxy is a documented follow-up). - Each typed driver page gets a "Pick address" button that opens the modal with the matching body. Picked address surfaces in the modal footer for manual copy — no JS interop in v1.
This commit is contained in:
+19
@@ -5,6 +5,7 @@
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Clients
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Pickers
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration.Entities
|
||||
@using ZB.MOM.WW.OtOpcUa.Driver.AbCip
|
||||
@@ -46,8 +47,20 @@ else
|
||||
<DriverTestConnectButton DriverType="@DriverTypeKey"
|
||||
GetConfigJson="@SerializeCurrentConfig"
|
||||
TimeoutSeconds="@_form.AdminProbeTimeoutSeconds" />
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary mt-2"
|
||||
@onclick="@(() => _showPicker = true)">
|
||||
Pick address
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<DriverTagPicker @bind-Visible="_showPicker"
|
||||
Title="AB CIP address"
|
||||
CurrentAddress="@_pickedAddress"
|
||||
OnPickAddress="@OnAddressPicked">
|
||||
<AbCipAddressPickerBody CurrentAddress="@_pickedAddress"
|
||||
CurrentAddressChanged="@((s) => _pickedAddress = s)" />
|
||||
</DriverTagPicker>
|
||||
|
||||
@* Operation timeout *@
|
||||
<section class="panel rise mt-3" style="animation-delay:.06s">
|
||||
<div class="panel-head">Operation settings</div>
|
||||
@@ -183,6 +196,12 @@ else
|
||||
private bool _busy;
|
||||
private string? _error;
|
||||
|
||||
// Address picker state
|
||||
private bool _showPicker;
|
||||
private string _pickedAddress = "";
|
||||
|
||||
private void OnAddressPicked(string address) => _pickedAddress = address;
|
||||
|
||||
// Collections are preserved through round-trip and shown as read-only JSON.
|
||||
private IReadOnlyList<AbCipDeviceOptions> _devices = [];
|
||||
private IReadOnlyList<AbCipTagDefinition> _tags = [];
|
||||
|
||||
+19
@@ -5,6 +5,7 @@
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Clients
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Pickers
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration.Entities
|
||||
@using ZB.MOM.WW.OtOpcUa.Driver.AbLegacy
|
||||
@@ -47,8 +48,20 @@ else
|
||||
<DriverTestConnectButton DriverType="@DriverTypeKey"
|
||||
GetConfigJson="@SerializeCurrentConfig"
|
||||
TimeoutSeconds="@_form.AdminProbeTimeoutSeconds" />
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary mt-2"
|
||||
@onclick="@(() => _showPicker = true)">
|
||||
Pick address
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<DriverTagPicker @bind-Visible="_showPicker"
|
||||
Title="AB Legacy address"
|
||||
CurrentAddress="@_pickedAddress"
|
||||
OnPickAddress="@OnAddressPicked">
|
||||
<AbLegacyAddressPickerBody CurrentAddress="@_pickedAddress"
|
||||
CurrentAddressChanged="@((s) => _pickedAddress = s)" />
|
||||
</DriverTagPicker>
|
||||
|
||||
@* Operation settings *@
|
||||
<section class="panel rise mt-3" style="animation-delay:.06s">
|
||||
<div class="panel-head">Operation settings</div>
|
||||
@@ -152,6 +165,12 @@ else
|
||||
private bool _busy;
|
||||
private string? _error;
|
||||
|
||||
// Address picker state
|
||||
private bool _showPicker;
|
||||
private string _pickedAddress = "";
|
||||
|
||||
private void OnAddressPicked(string address) => _pickedAddress = address;
|
||||
|
||||
// Collections are preserved through round-trip and shown as read-only JSON.
|
||||
private IReadOnlyList<AbLegacyDeviceOptions> _devices = [];
|
||||
private IReadOnlyList<AbLegacyTagDefinition> _tags = [];
|
||||
|
||||
+19
@@ -5,6 +5,7 @@
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Clients
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Pickers
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration.Entities
|
||||
@using ZB.MOM.WW.OtOpcUa.Driver.FOCAS
|
||||
@@ -46,8 +47,20 @@ else
|
||||
<DriverTestConnectButton DriverType="@DriverTypeKey"
|
||||
GetConfigJson="@SerializeCurrentConfig"
|
||||
TimeoutSeconds="@_form.AdminProbeTimeoutSeconds" />
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary mt-2"
|
||||
@onclick="@(() => _showPicker = true)">
|
||||
Pick address
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<DriverTagPicker @bind-Visible="_showPicker"
|
||||
Title="FOCAS address"
|
||||
CurrentAddress="@_pickedAddress"
|
||||
OnPickAddress="@OnAddressPicked">
|
||||
<FOCASAddressPickerBody CurrentAddress="@_pickedAddress"
|
||||
CurrentAddressChanged="@((s) => _pickedAddress = s)" />
|
||||
</DriverTagPicker>
|
||||
|
||||
@* Connection *@
|
||||
<section class="panel rise mt-3" style="animation-delay:.05s">
|
||||
<div class="panel-head">Connection</div>
|
||||
@@ -241,6 +254,12 @@ else
|
||||
private bool _loaded, _busy;
|
||||
private string? _error;
|
||||
|
||||
// Address picker state
|
||||
private bool _showPicker;
|
||||
private string _pickedAddress = "";
|
||||
|
||||
private void OnAddressPicked(string address) => _pickedAddress = address;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await using var db = await DbFactory.CreateDbContextAsync();
|
||||
|
||||
+19
@@ -5,6 +5,7 @@
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Clients
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Pickers
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration.Entities
|
||||
@using ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Config
|
||||
@@ -46,8 +47,20 @@ else
|
||||
<DriverTestConnectButton DriverType="@DriverTypeKey"
|
||||
GetConfigJson="@SerializeCurrentConfig"
|
||||
TimeoutSeconds="@_form.Galaxy.ProbeTimeoutSeconds" />
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary mt-2"
|
||||
@onclick="@(() => _showPicker = true)">
|
||||
Pick address
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<DriverTagPicker @bind-Visible="_showPicker"
|
||||
Title="Galaxy address"
|
||||
CurrentAddress="@_pickedAddress"
|
||||
OnPickAddress="@OnAddressPicked">
|
||||
<GalaxyAddressPickerBody CurrentAddress="@_pickedAddress"
|
||||
CurrentAddressChanged="@((s) => _pickedAddress = s)" />
|
||||
</DriverTagPicker>
|
||||
|
||||
@* mxaccessgw connection *@
|
||||
<section class="panel rise mt-3" style="animation-delay:.06s">
|
||||
<div class="panel-head">mxaccessgw connection</div>
|
||||
@@ -213,6 +226,12 @@ else
|
||||
private bool _busy;
|
||||
private string? _error;
|
||||
|
||||
// Address picker state
|
||||
private bool _showPicker;
|
||||
private string _pickedAddress = "";
|
||||
|
||||
private void OnAddressPicked(string address) => _pickedAddress = address;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await using var db = await DbFactory.CreateDbContextAsync();
|
||||
|
||||
+19
@@ -5,6 +5,7 @@
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Clients
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Pickers
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration.Entities
|
||||
@using ZB.MOM.WW.OtOpcUa.Driver.Historian.Wonderware.Client
|
||||
@@ -46,8 +47,20 @@ else
|
||||
<DriverTestConnectButton DriverType="@DriverTypeKey"
|
||||
GetConfigJson="@SerializeCurrentConfig"
|
||||
TimeoutSeconds="@_form.Historian.ProbeTimeoutSeconds" />
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary mt-2"
|
||||
@onclick="@(() => _showPicker = true)">
|
||||
Pick address
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<DriverTagPicker @bind-Visible="_showPicker"
|
||||
Title="Historian Wonderware address"
|
||||
CurrentAddress="@_pickedAddress"
|
||||
OnPickAddress="@OnAddressPicked">
|
||||
<HistorianWonderwareAddressPickerBody CurrentAddress="@_pickedAddress"
|
||||
CurrentAddressChanged="@((s) => _pickedAddress = s)" />
|
||||
</DriverTagPicker>
|
||||
|
||||
@* Connection *@
|
||||
<section class="panel rise mt-3" style="animation-delay:.06s">
|
||||
<div class="panel-head">Connection</div>
|
||||
@@ -145,6 +158,12 @@ else
|
||||
private bool _busy;
|
||||
private string? _error;
|
||||
|
||||
// Address picker state
|
||||
private bool _showPicker;
|
||||
private string _pickedAddress = "";
|
||||
|
||||
private void OnAddressPicked(string address) => _pickedAddress = address;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await using var db = await DbFactory.CreateDbContextAsync();
|
||||
|
||||
+20
@@ -5,6 +5,7 @@
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Clients
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Pickers
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration.Entities
|
||||
@using ZB.MOM.WW.OtOpcUa.Driver.Modbus
|
||||
@@ -46,8 +47,20 @@ else
|
||||
<DriverTestConnectButton DriverType="@DriverTypeKey"
|
||||
GetConfigJson="@SerializeCurrentConfig"
|
||||
TimeoutSeconds="@_form.AdminProbeTimeoutSeconds" />
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary mt-2"
|
||||
@onclick="@(() => _showPicker = true)">
|
||||
Pick address
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<DriverTagPicker @bind-Visible="_showPicker"
|
||||
Title="Modbus address"
|
||||
CurrentAddress="@_pickedAddress"
|
||||
OnPickAddress="@OnAddressPicked">
|
||||
<ModbusAddressPickerBody CurrentAddress="@_pickedAddress"
|
||||
CurrentAddressChanged="@((s) => _pickedAddress = s)" />
|
||||
</DriverTagPicker>
|
||||
|
||||
@* Transport *@
|
||||
<section class="panel rise mt-3" style="animation-delay:.06s">
|
||||
<div class="panel-head">Transport</div>
|
||||
@@ -298,6 +311,13 @@ else
|
||||
private bool _loaded;
|
||||
private bool _busy;
|
||||
private string? _error;
|
||||
|
||||
// Address picker state
|
||||
private bool _showPicker;
|
||||
private string _pickedAddress = "";
|
||||
|
||||
private void OnAddressPicked(string address) => _pickedAddress = address;
|
||||
|
||||
// Held separately because Tags is a collection — rendered as read-only JSON.
|
||||
private IReadOnlyList<ModbusTagDefinition> _tags = [];
|
||||
private string _tagsJson = "[]";
|
||||
|
||||
+19
@@ -5,6 +5,7 @@
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Clients
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Pickers
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration.Entities
|
||||
@using ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient
|
||||
@@ -46,8 +47,20 @@ else
|
||||
<DriverTestConnectButton DriverType="@DriverTypeKey"
|
||||
GetConfigJson="@SerializeCurrentConfig"
|
||||
TimeoutSeconds="@_form.OpcUa.ProbeTimeoutSeconds" />
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary mt-2"
|
||||
@onclick="@(() => _showPicker = true)">
|
||||
Pick address
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<DriverTagPicker @bind-Visible="_showPicker"
|
||||
Title="OPC UA address"
|
||||
CurrentAddress="@_pickedAddress"
|
||||
OnPickAddress="@OnAddressPicked">
|
||||
<OpcUaClientAddressPickerBody CurrentAddress="@_pickedAddress"
|
||||
CurrentAddressChanged="@((s) => _pickedAddress = s)" />
|
||||
</DriverTagPicker>
|
||||
|
||||
@* Endpoint *@
|
||||
<section class="panel rise mt-3" style="animation-delay:.06s">
|
||||
<div class="panel-head">Endpoint</div>
|
||||
@@ -261,6 +274,12 @@ else
|
||||
private bool _busy;
|
||||
private string? _error;
|
||||
|
||||
// Address picker state
|
||||
private bool _showPicker;
|
||||
private string _pickedAddress = "";
|
||||
|
||||
private void OnAddressPicked(string address) => _pickedAddress = address;
|
||||
|
||||
// Read-only JSON snippets for collections that have no list editor yet.
|
||||
private string _endpointUrlsJson = "[]";
|
||||
private string _unsMappingTableJson = "{}";
|
||||
|
||||
+19
@@ -5,6 +5,7 @@
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Clients
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Pickers
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration.Entities
|
||||
@using ZB.MOM.WW.OtOpcUa.Driver.S7
|
||||
@@ -46,8 +47,20 @@ else
|
||||
<DriverTestConnectButton DriverType="@DriverTypeKey"
|
||||
GetConfigJson="@SerializeCurrentConfig"
|
||||
TimeoutSeconds="@_form.AdminProbeTimeoutSeconds" />
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary mt-2"
|
||||
@onclick="@(() => _showPicker = true)">
|
||||
Pick address
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<DriverTagPicker @bind-Visible="_showPicker"
|
||||
Title="S7 address"
|
||||
CurrentAddress="@_pickedAddress"
|
||||
OnPickAddress="@OnAddressPicked">
|
||||
<S7AddressPickerBody CurrentAddress="@_pickedAddress"
|
||||
CurrentAddressChanged="@((s) => _pickedAddress = s)" />
|
||||
</DriverTagPicker>
|
||||
|
||||
@* Connection *@
|
||||
<section class="panel rise mt-3" style="animation-delay:.05s">
|
||||
<div class="panel-head">Connection</div>
|
||||
@@ -177,6 +190,12 @@ else
|
||||
private bool _loaded, _busy;
|
||||
private string? _error;
|
||||
|
||||
// Address picker state
|
||||
private bool _showPicker;
|
||||
private string _pickedAddress = "";
|
||||
|
||||
private void OnAddressPicked(string address) => _pickedAddress = address;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await using var db = await DbFactory.CreateDbContextAsync();
|
||||
|
||||
+19
@@ -5,6 +5,7 @@
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Clients
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Pickers
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration.Entities
|
||||
@using ZB.MOM.WW.OtOpcUa.Driver.TwinCAT
|
||||
@@ -46,8 +47,20 @@ else
|
||||
<DriverTestConnectButton DriverType="@DriverTypeKey"
|
||||
GetConfigJson="@SerializeCurrentConfig"
|
||||
TimeoutSeconds="@_form.AdminProbeTimeoutSeconds" />
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary mt-2"
|
||||
@onclick="@(() => _showPicker = true)">
|
||||
Pick address
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<DriverTagPicker @bind-Visible="_showPicker"
|
||||
Title="TwinCAT address"
|
||||
CurrentAddress="@_pickedAddress"
|
||||
OnPickAddress="@OnAddressPicked">
|
||||
<TwinCATAddressPickerBody CurrentAddress="@_pickedAddress"
|
||||
CurrentAddressChanged="@((s) => _pickedAddress = s)" />
|
||||
</DriverTagPicker>
|
||||
|
||||
@* Options *@
|
||||
<section class="panel rise mt-3" style="animation-delay:.05s">
|
||||
<div class="panel-head">Options</div>
|
||||
@@ -183,6 +196,12 @@ else
|
||||
private bool _loaded, _busy;
|
||||
private string? _error;
|
||||
|
||||
// Address picker state
|
||||
private bool _showPicker;
|
||||
private string _pickedAddress = "";
|
||||
|
||||
private void OnAddressPicked(string address) => _pickedAddress = address;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await using var db = await DbFactory.CreateDbContextAsync();
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
@* Shared modal shell for per-driver address pickers. Parent page toggles `Visible`;
|
||||
the child fragment renders the per-driver picker body. The shell handles modal
|
||||
chrome, the "Use this address" button, and dismisses on close. *@
|
||||
|
||||
@if (Visible)
|
||||
{
|
||||
<div class="modal-backdrop fade show" style="display:block"></div>
|
||||
<div class="modal fade show" tabindex="-1" role="dialog" style="display:block">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">@Title</h5>
|
||||
<button type="button" class="btn-close" aria-label="Close" @onclick="OnCloseAsync"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
@ChildContent
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
@if (!string.IsNullOrEmpty(CurrentAddress))
|
||||
{
|
||||
<code class="me-auto mono">@CurrentAddress</code>
|
||||
}
|
||||
<button type="button" class="btn btn-outline-secondary" @onclick="OnCloseAsync">Close</button>
|
||||
<button type="button" class="btn btn-primary" disabled="@string.IsNullOrEmpty(CurrentAddress)"
|
||||
@onclick="OnUseAsync">
|
||||
Use this address
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@code {
|
||||
[Parameter] public bool Visible { get; set; }
|
||||
[Parameter] public EventCallback<bool> VisibleChanged { get; set; }
|
||||
[Parameter] public string Title { get; set; } = "Address builder";
|
||||
[Parameter] public string CurrentAddress { get; set; } = "";
|
||||
[Parameter] public EventCallback<string> OnPickAddress { get; set; }
|
||||
[Parameter] public RenderFragment? ChildContent { get; set; }
|
||||
|
||||
private async Task OnCloseAsync()
|
||||
{
|
||||
await VisibleChanged.InvokeAsync(false);
|
||||
}
|
||||
|
||||
private async Task OnUseAsync()
|
||||
{
|
||||
await OnPickAddress.InvokeAsync(CurrentAddress);
|
||||
await VisibleChanged.InvokeAsync(false);
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
@* Static AB CIP address builder: tag name + optional element index → tag[idx] or tag *@
|
||||
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Tag name</label>
|
||||
<input type="text" class="form-control form-control-sm mono" placeholder="Program:Main.MyTag"
|
||||
@bind="_tagName" @bind:after="OnChangedAsync" />
|
||||
<div class="form-text">Use dot notation for nested tags or UDT members.</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Element index (optional)</label>
|
||||
<input type="number" class="form-control form-control-sm" min="0"
|
||||
@bind="_elementIndex" @bind:after="OnChangedAsync" />
|
||||
<div class="form-text">Leave 0 for non-array tags (no index appended).</div>
|
||||
</div>
|
||||
<div class="col-md-3 d-flex align-items-end">
|
||||
<div class="form-check mb-2">
|
||||
<input type="checkbox" class="form-check-input" id="abCipUseIdx"
|
||||
@bind="_useIndex" @bind:after="OnChangedAsync" />
|
||||
<label class="form-check-label" for="abCipUseIdx">Append index</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<span class="text-muted small">Result:</span>
|
||||
<code class="mono ms-2">@_built</code>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public string CurrentAddress { get; set; } = "";
|
||||
[Parameter] public EventCallback<string> CurrentAddressChanged { get; set; }
|
||||
|
||||
private string _tagName = "";
|
||||
private int _elementIndex = 0;
|
||||
private bool _useIndex = false;
|
||||
private string _built = "";
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_built = Build();
|
||||
_ = CurrentAddressChanged.InvokeAsync(_built);
|
||||
}
|
||||
|
||||
private async Task OnChangedAsync()
|
||||
{
|
||||
_built = Build();
|
||||
await CurrentAddressChanged.InvokeAsync(_built);
|
||||
}
|
||||
|
||||
private string Build()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_tagName))
|
||||
return "";
|
||||
return _useIndex ? $"{_tagName}[{_elementIndex}]" : _tagName;
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Pickers;
|
||||
|
||||
/// <summary>
|
||||
/// Pure static helper that converts AB Legacy PLC file-type + file-number + element
|
||||
/// into the canonical address string (e.g. N7:0).
|
||||
/// Extracted so unit tests can call it without bUnit.
|
||||
/// </summary>
|
||||
public static class AbLegacyAddressBuilder
|
||||
{
|
||||
public static string Build(string fileType, int fileNumber, int element)
|
||||
=> $"{fileType}{fileNumber}:{element}";
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
@* Static AB Legacy address builder: file type + file number + element → N7:0 *@
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Pickers
|
||||
|
||||
<div class="row g-3">
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">File type</label>
|
||||
<select class="form-select form-select-sm" @bind="_fileType" @bind:after="OnChangedAsync">
|
||||
<option value="N">N — Integer</option>
|
||||
<option value="B">B — Binary/Bit</option>
|
||||
<option value="F">F — Float</option>
|
||||
<option value="I">I — Input</option>
|
||||
<option value="O">O — Output</option>
|
||||
<option value="S">S — Status</option>
|
||||
<option value="T">T — Timer</option>
|
||||
<option value="C">C — Counter</option>
|
||||
<option value="R">R — Control</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">File number</label>
|
||||
<input type="number" class="form-control form-control-sm" min="0" max="999"
|
||||
@bind="_fileNumber" @bind:after="OnChangedAsync" />
|
||||
<div class="form-text">e.g. 7 for N7</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Element</label>
|
||||
<input type="number" class="form-control form-control-sm" min="0" max="9999"
|
||||
@bind="_element" @bind:after="OnChangedAsync" />
|
||||
<div class="form-text">e.g. 0 for N7:0</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<span class="text-muted small">Result:</span>
|
||||
<code class="mono ms-2">@_built</code>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public string CurrentAddress { get; set; } = "";
|
||||
[Parameter] public EventCallback<string> CurrentAddressChanged { get; set; }
|
||||
|
||||
private string _fileType = "N";
|
||||
private int _fileNumber = 7;
|
||||
private int _element = 0;
|
||||
private string _built = "";
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_built = AbLegacyAddressBuilder.Build(_fileType, _fileNumber, _element);
|
||||
_ = CurrentAddressChanged.InvokeAsync(_built);
|
||||
}
|
||||
|
||||
private async Task OnChangedAsync()
|
||||
{
|
||||
_built = AbLegacyAddressBuilder.Build(_fileType, _fileNumber, _element);
|
||||
await CurrentAddressChanged.InvokeAsync(_built);
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
@* Static FOCAS address builder: parameter group + parameter ID → axis:5 *@
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Pickers
|
||||
|
||||
<div class="row g-3">
|
||||
<div class="col-md-4">
|
||||
<label class="form-label">Parameter group</label>
|
||||
<select class="form-select form-select-sm" @bind="_group" @bind:after="OnChangedAsync">
|
||||
<option value="axis">axis</option>
|
||||
<option value="spindle">spindle</option>
|
||||
<option value="program">program</option>
|
||||
<option value="status">status</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Parameter ID</label>
|
||||
<input type="number" class="form-control form-control-sm" min="0"
|
||||
@bind="_parameterId" @bind:after="OnChangedAsync" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<span class="text-muted small">Result:</span>
|
||||
<code class="mono ms-2">@_built</code>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public string CurrentAddress { get; set; } = "";
|
||||
[Parameter] public EventCallback<string> CurrentAddressChanged { get; set; }
|
||||
|
||||
private string _group = "axis";
|
||||
private int _parameterId = 0;
|
||||
private string _built = "";
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_built = FocasAddressBuilder.Build(_group, _parameterId);
|
||||
_ = CurrentAddressChanged.InvokeAsync(_built);
|
||||
}
|
||||
|
||||
private async Task OnChangedAsync()
|
||||
{
|
||||
_built = FocasAddressBuilder.Build(_group, _parameterId);
|
||||
await CurrentAddressChanged.InvokeAsync(_built);
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Pickers;
|
||||
|
||||
/// <summary>
|
||||
/// Pure static helper that converts a FOCAS parameter group + parameter ID
|
||||
/// into the canonical address string (e.g. axis:5).
|
||||
/// Extracted so unit tests can call it without bUnit.
|
||||
/// </summary>
|
||||
public static class FocasAddressBuilder
|
||||
{
|
||||
public static string Build(string group, int parameterId)
|
||||
=> $"{group}:{parameterId}";
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
@* Static Galaxy address builder: tag_name.AttributeName free text → verbatim.
|
||||
Live Galaxy browse deferred to a follow-up phase. *@
|
||||
|
||||
<div class="alert alert-info py-2 px-3 mb-3 small">
|
||||
<strong>Note:</strong> Live Galaxy browse is deferred to a follow-up phase.
|
||||
Enter the tag and attribute name manually below.
|
||||
</div>
|
||||
|
||||
<div class="row g-3">
|
||||
<div class="col-md-5">
|
||||
<label class="form-label">Tag name</label>
|
||||
<input type="text" class="form-control form-control-sm mono" placeholder="DelmiaReceiver_001"
|
||||
@bind="_tagName" @bind:after="OnChangedAsync" />
|
||||
<div class="form-text">Globally unique system (tag) name.</div>
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<label class="form-label">Attribute name</label>
|
||||
<input type="text" class="form-control form-control-sm mono" placeholder="DownloadPath"
|
||||
@bind="_attributeName" @bind:after="OnChangedAsync" />
|
||||
<div class="form-text">MXAccess attribute name.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<span class="text-muted small">Result:</span>
|
||||
<code class="mono ms-2">@_built</code>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public string CurrentAddress { get; set; } = "";
|
||||
[Parameter] public EventCallback<string> CurrentAddressChanged { get; set; }
|
||||
|
||||
private string _tagName = "";
|
||||
private string _attributeName = "";
|
||||
private string _built = "";
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_built = Build();
|
||||
_ = CurrentAddressChanged.InvokeAsync(_built);
|
||||
}
|
||||
|
||||
private async Task OnChangedAsync()
|
||||
{
|
||||
_built = Build();
|
||||
await CurrentAddressChanged.InvokeAsync(_built);
|
||||
}
|
||||
|
||||
private string Build()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_tagName))
|
||||
return "";
|
||||
if (string.IsNullOrWhiteSpace(_attributeName))
|
||||
return _tagName;
|
||||
return $"{_tagName}.{_attributeName}";
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Pickers;
|
||||
|
||||
/// <summary>
|
||||
/// Pure static helper that converts a Wonderware Historian tag name + retrieval mode
|
||||
/// + interval into the canonical address query string (e.g. MyTag?mode=Cyclic&interval=60).
|
||||
/// Extracted so unit tests can call it without bUnit.
|
||||
/// </summary>
|
||||
public static class HistorianWonderwareAddressBuilder
|
||||
{
|
||||
public static string Build(string tagName, string mode, int interval)
|
||||
=> $"{tagName}?mode={mode}&interval={interval}";
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
@* Static Wonderware Historian address builder: tag name + retrieval mode + interval
|
||||
→ MyTag?mode=Cyclic&interval=60 *@
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Pickers
|
||||
|
||||
<div class="row g-3">
|
||||
<div class="col-md-4">
|
||||
<label class="form-label">Tag name</label>
|
||||
<input type="text" class="form-control form-control-sm mono" placeholder="SysTimeHour"
|
||||
@bind="_tagName" @bind:after="OnChangedAsync" />
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Retrieval mode</label>
|
||||
<select class="form-select form-select-sm" @bind="_mode" @bind:after="OnChangedAsync">
|
||||
<option value="Last">Last</option>
|
||||
<option value="Cyclic">Cyclic</option>
|
||||
<option value="Delta">Delta</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Interval (seconds)</label>
|
||||
<input type="number" class="form-control form-control-sm" min="1"
|
||||
@bind="_interval" @bind:after="OnChangedAsync" />
|
||||
<div class="form-text">Polling/retrieval interval.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<span class="text-muted small">Result:</span>
|
||||
<code class="mono ms-2">@_built</code>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public string CurrentAddress { get; set; } = "";
|
||||
[Parameter] public EventCallback<string> CurrentAddressChanged { get; set; }
|
||||
|
||||
private string _tagName = "";
|
||||
private string _mode = "Cyclic";
|
||||
private int _interval = 60;
|
||||
private string _built = "";
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_built = string.IsNullOrWhiteSpace(_tagName) ? "" : HistorianWonderwareAddressBuilder.Build(_tagName, _mode, _interval);
|
||||
_ = CurrentAddressChanged.InvokeAsync(_built);
|
||||
}
|
||||
|
||||
private async Task OnChangedAsync()
|
||||
{
|
||||
_built = string.IsNullOrWhiteSpace(_tagName) ? "" : HistorianWonderwareAddressBuilder.Build(_tagName, _mode, _interval);
|
||||
await CurrentAddressChanged.InvokeAsync(_built);
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Pickers;
|
||||
|
||||
/// <summary>
|
||||
/// Pure static helper that converts Modbus register-type + offset + length into
|
||||
/// the canonical address string used by the Modbus driver (e.g. 4x00001-1).
|
||||
/// Extracted so unit tests can call it without bUnit.
|
||||
/// </summary>
|
||||
public static class ModbusAddressBuilder
|
||||
{
|
||||
public static string Build(string regType, int offset, int length)
|
||||
{
|
||||
var prefix = regType switch
|
||||
{
|
||||
"Coil" => "0x",
|
||||
"DiscreteInput" => "1x",
|
||||
"Input" => "3x",
|
||||
"Holding" => "4x",
|
||||
_ => "4x",
|
||||
};
|
||||
return $"{prefix}{offset:00000}-{length}";
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
@* Static Modbus address builder: register type + offset + length → 4x00001-4 *@
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Pickers
|
||||
|
||||
<div class="row g-3">
|
||||
<div class="col-md-4">
|
||||
<label class="form-label">Register type</label>
|
||||
<select class="form-select form-select-sm" @bind="_regType" @bind:after="OnChangedAsync">
|
||||
<option value="Coil">Coil (0x)</option>
|
||||
<option value="DiscreteInput">DiscreteInput (1x)</option>
|
||||
<option value="Input">Input (3x)</option>
|
||||
<option value="Holding">Holding (4x)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Offset</label>
|
||||
<input type="number" class="form-control form-control-sm" min="0" max="99999"
|
||||
@bind="_offset" @bind:after="OnChangedAsync" />
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">Length</label>
|
||||
<input type="number" class="form-control form-control-sm" min="1" max="125"
|
||||
@bind="_length" @bind:after="OnChangedAsync" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<span class="text-muted small">Result:</span>
|
||||
<code class="mono ms-2">@_built</code>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public string CurrentAddress { get; set; } = "";
|
||||
[Parameter] public EventCallback<string> CurrentAddressChanged { get; set; }
|
||||
|
||||
private string _regType = "Holding";
|
||||
private int _offset = 1;
|
||||
private int _length = 1;
|
||||
private string _built = "";
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_built = ModbusAddressBuilder.Build(_regType, _offset, _length);
|
||||
_ = CurrentAddressChanged.InvokeAsync(_built);
|
||||
}
|
||||
|
||||
private async Task OnChangedAsync()
|
||||
{
|
||||
_built = ModbusAddressBuilder.Build(_regType, _offset, _length);
|
||||
await CurrentAddressChanged.InvokeAsync(_built);
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
@* Static OPC UA Client address builder: NodeId free text → verbatim.
|
||||
Live browse deferred to a follow-up phase. *@
|
||||
|
||||
<div class="alert alert-info py-2 px-3 mb-3 small">
|
||||
<strong>Note:</strong> Live OPC UA node browse is deferred to a follow-up phase.
|
||||
Enter the NodeId string manually below.
|
||||
</div>
|
||||
|
||||
<div class="row g-3">
|
||||
<div class="col-md-10">
|
||||
<label class="form-label">NodeId</label>
|
||||
<input type="text" class="form-control form-control-sm mono" placeholder="ns=2;s=Channel.Device.Tag"
|
||||
@bind="_nodeId" @bind:after="OnChangedAsync" />
|
||||
<div class="form-text">
|
||||
OPC UA NodeId string, e.g. <code>ns=2;s=Channel.Device.Tag</code> or <code>i=1001</code>.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<span class="text-muted small">Result:</span>
|
||||
<code class="mono ms-2">@_built</code>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public string CurrentAddress { get; set; } = "";
|
||||
[Parameter] public EventCallback<string> CurrentAddressChanged { get; set; }
|
||||
|
||||
private string _nodeId = "";
|
||||
private string _built = "";
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_built = _nodeId;
|
||||
_ = CurrentAddressChanged.InvokeAsync(_built);
|
||||
}
|
||||
|
||||
private async Task OnChangedAsync()
|
||||
{
|
||||
_built = _nodeId;
|
||||
await CurrentAddressChanged.InvokeAsync(_built);
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Pickers;
|
||||
|
||||
/// <summary>
|
||||
/// Pure static helper that converts S7 area + db-number + offset + data-type
|
||||
/// into the canonical S7 address string (e.g. DB10.DBD20:REAL, M0.0:X).
|
||||
/// Extracted so unit tests can call it without bUnit.
|
||||
/// </summary>
|
||||
public static class S7AddressBuilder
|
||||
{
|
||||
/// <param name="area">DB / M / I / Q</param>
|
||||
/// <param name="dbNumber">Only relevant when area == "DB".</param>
|
||||
/// <param name="offset">Byte offset (decimal).</param>
|
||||
/// <param name="s7Type">X / B / W / D / REAL</param>
|
||||
public static string Build(string area, int dbNumber, int offset, string s7Type)
|
||||
{
|
||||
if (area == "DB")
|
||||
{
|
||||
// e.g. DB10.DBD20:REAL / DB1.DBX0.0:X / DB5.DBW4:W
|
||||
var qualifier = s7Type switch
|
||||
{
|
||||
"X" => $"DBX{offset}.0",
|
||||
"B" => $"DBB{offset}",
|
||||
"W" => $"DBW{offset}",
|
||||
"D" => $"DBD{offset}",
|
||||
"REAL" => $"DBD{offset}",
|
||||
_ => $"DBD{offset}",
|
||||
};
|
||||
return $"DB{dbNumber}.{qualifier}:{s7Type}";
|
||||
}
|
||||
else
|
||||
{
|
||||
// e.g. M0.0:X / I4:B / Q2:W
|
||||
var offsetStr = s7Type == "X" ? $"{offset}.0" : $"{offset}";
|
||||
return $"{area}{offsetStr}:{s7Type}";
|
||||
}
|
||||
}
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
@* Static S7 address builder: area + db-number + offset + type → DB10.DBD20:REAL / M0.0:X *@
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Pickers
|
||||
|
||||
<div class="row g-3">
|
||||
<div class="col-md-2">
|
||||
<label class="form-label">Area</label>
|
||||
<select class="form-select form-select-sm" @bind="_area" @bind:after="OnChangedAsync">
|
||||
<option value="DB">DB — Data Block</option>
|
||||
<option value="M">M — Merker</option>
|
||||
<option value="I">I — Input</option>
|
||||
<option value="Q">Q — Output</option>
|
||||
</select>
|
||||
</div>
|
||||
@if (_area == "DB")
|
||||
{
|
||||
<div class="col-md-2">
|
||||
<label class="form-label">DB number</label>
|
||||
<input type="number" class="form-control form-control-sm" min="1" max="65535"
|
||||
@bind="_dbNumber" @bind:after="OnChangedAsync" />
|
||||
</div>
|
||||
}
|
||||
<div class="col-md-2">
|
||||
<label class="form-label">Offset (bytes)</label>
|
||||
<input type="number" class="form-control form-control-sm" min="0" max="65535"
|
||||
@bind="_offset" @bind:after="OnChangedAsync" />
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label class="form-label">S7 type</label>
|
||||
<select class="form-select form-select-sm" @bind="_s7Type" @bind:after="OnChangedAsync">
|
||||
<option value="X">X — Bit</option>
|
||||
<option value="B">B — Byte</option>
|
||||
<option value="W">W — Word</option>
|
||||
<option value="D">D — DWord</option>
|
||||
<option value="REAL">REAL — Float</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<span class="text-muted small">Result:</span>
|
||||
<code class="mono ms-2">@_built</code>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public string CurrentAddress { get; set; } = "";
|
||||
[Parameter] public EventCallback<string> CurrentAddressChanged { get; set; }
|
||||
|
||||
private string _area = "DB";
|
||||
private int _dbNumber = 1;
|
||||
private int _offset = 0;
|
||||
private string _s7Type = "REAL";
|
||||
private string _built = "";
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_built = S7AddressBuilder.Build(_area, _dbNumber, _offset, _s7Type);
|
||||
_ = CurrentAddressChanged.InvokeAsync(_built);
|
||||
}
|
||||
|
||||
private async Task OnChangedAsync()
|
||||
{
|
||||
_built = S7AddressBuilder.Build(_area, _dbNumber, _offset, _s7Type);
|
||||
await CurrentAddressChanged.InvokeAsync(_built);
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
@* Static TwinCAT address builder: ADS variable name (free text) → verbatim *@
|
||||
|
||||
<div class="row g-3">
|
||||
<div class="col-md-8">
|
||||
<label class="form-label">ADS variable name</label>
|
||||
<input type="text" class="form-control form-control-sm mono" placeholder="MAIN.fValue"
|
||||
@bind="_varName" @bind:after="OnChangedAsync" />
|
||||
<div class="form-text">
|
||||
Full ADS symbol path, e.g. <code>MAIN.fValue</code> or <code>GVL.iCounter</code>.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-3">
|
||||
<span class="text-muted small">Result:</span>
|
||||
<code class="mono ms-2">@_built</code>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter] public string CurrentAddress { get; set; } = "";
|
||||
[Parameter] public EventCallback<string> CurrentAddressChanged { get; set; }
|
||||
|
||||
private string _varName = "";
|
||||
private string _built = "";
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_built = _varName;
|
||||
_ = CurrentAddressChanged.InvokeAsync(_built);
|
||||
}
|
||||
|
||||
private async Task OnChangedAsync()
|
||||
{
|
||||
_built = _varName;
|
||||
await CurrentAddressChanged.InvokeAsync(_built);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Pickers;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Pickers;
|
||||
|
||||
public sealed class AbLegacyAddressBuilderTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("N", 7, 0, "N7:0")]
|
||||
[InlineData("B", 3, 1, "B3:1")]
|
||||
[InlineData("F", 8, 12, "F8:12")]
|
||||
[InlineData("T", 4, 0, "T4:0")]
|
||||
[InlineData("C", 5, 2, "C5:2")]
|
||||
public void Build_Canonical(string fileType, int fileNumber, int element, string expected)
|
||||
=> AbLegacyAddressBuilder.Build(fileType, fileNumber, element).ShouldBe(expected);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Pickers;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Pickers;
|
||||
|
||||
public sealed class FocasAddressBuilderTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("axis", 5, "axis:5")]
|
||||
[InlineData("spindle", 0, "spindle:0")]
|
||||
[InlineData("program", 100, "program:100")]
|
||||
[InlineData("status", 1, "status:1")]
|
||||
public void Build_Canonical(string group, int parameterId, string expected)
|
||||
=> FocasAddressBuilder.Build(group, parameterId).ShouldBe(expected);
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Pickers;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Pickers;
|
||||
|
||||
public sealed class HistorianWonderwareAddressBuilderTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("SysTimeHour", "Cyclic", 60, "SysTimeHour?mode=Cyclic&interval=60")]
|
||||
[InlineData("ReactorTemp", "Last", 1, "ReactorTemp?mode=Last&interval=1")]
|
||||
[InlineData("FlowRate", "Delta", 30, "FlowRate?mode=Delta&interval=30")]
|
||||
public void Build_Canonical(string tag, string mode, int interval, string expected)
|
||||
=> HistorianWonderwareAddressBuilder.Build(tag, mode, interval).ShouldBe(expected);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Pickers;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Pickers;
|
||||
|
||||
public sealed class ModbusAddressBuilderTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("Holding", 1, 1, "4x00001-1")]
|
||||
[InlineData("Coil", 0, 1, "0x00000-1")]
|
||||
[InlineData("Holding", 123, 4, "4x00123-4")]
|
||||
[InlineData("DiscreteInput", 5, 1, "1x00005-1")]
|
||||
[InlineData("Input", 99999, 125, "3x99999-125")]
|
||||
public void Build_Canonical(string type, int offset, int length, string expected)
|
||||
=> ModbusAddressBuilder.Build(type, offset, length).ShouldBe(expected);
|
||||
|
||||
[Fact]
|
||||
public void Build_UnknownType_FallsBackToHolding()
|
||||
=> ModbusAddressBuilder.Build("Unknown", 1, 1).ShouldBe("4x00001-1");
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Pickers;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Pickers;
|
||||
|
||||
public sealed class S7AddressBuilderTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("DB", 10, 20, "REAL", "DB10.DBD20:REAL")]
|
||||
[InlineData("DB", 1, 0, "X", "DB1.DBX0.0:X")]
|
||||
[InlineData("DB", 5, 4, "W", "DB5.DBW4:W")]
|
||||
[InlineData("DB", 2, 6, "B", "DB2.DBB6:B")]
|
||||
[InlineData("M", 1, 0, "X", "M0.0:X")]
|
||||
[InlineData("M", 1, 4, "W", "M4:W")]
|
||||
[InlineData("I", 1, 0, "B", "I0:B")]
|
||||
[InlineData("Q", 1, 2, "W", "Q2:W")]
|
||||
public void Build_Canonical(string area, int dbNumber, int offset, string s7Type, string expected)
|
||||
=> S7AddressBuilder.Build(area, dbNumber, offset, s7Type).ShouldBe(expected);
|
||||
}
|
||||
Reference in New Issue
Block a user