feat(adminui): Test Connect button on every typed driver page
- AdminProbeService routes TestDriverConnect through IAdminOperationsClient with a 65s outer guard (actor side already clamps to [1,60]). - Added generic AskAsync<T> to IAdminOperationsClient interface and AdminOperationsClient impl, delegating straight to the Akka proxy. - DriverTestConnectButton renders the button + inline result chip, auto-clears after 30s, disables during in-flight. - Wired into all 9 typed driver pages directly under the identity section. Sources timeout from the form's ProbeTimeoutSeconds; sources config JSON from the form's current Options (operator can test BEFORE saving).
This commit is contained in:
+10
@@ -3,6 +3,7 @@
|
||||
@rendermode RenderMode.InteractiveServer
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Clients
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration.Entities
|
||||
@@ -41,6 +42,12 @@ else
|
||||
<DriverStatusPanel DriverInstanceId="@DriverInstanceId" Enabled="@_identityModel.Enabled" />
|
||||
}
|
||||
|
||||
<div class="mt-2 mb-3">
|
||||
<DriverTestConnectButton DriverType="@DriverTypeKey"
|
||||
GetConfigJson="@SerializeCurrentConfig"
|
||||
TimeoutSeconds="@_form.AdminProbeTimeoutSeconds" />
|
||||
</div>
|
||||
|
||||
@* Operation timeout *@
|
||||
<section class="panel rise mt-3" style="animation-delay:.06s">
|
||||
<div class="panel-head">Operation settings</div>
|
||||
@@ -304,6 +311,9 @@ else
|
||||
finally { _busy = false; }
|
||||
}
|
||||
|
||||
private string SerializeCurrentConfig()
|
||||
=> System.Text.Json.JsonSerializer.Serialize(_form.ToOptions(_devices, _tags), _jsonOpts);
|
||||
|
||||
private static AbCipDriverOptions? TryDeserialize(string json)
|
||||
{
|
||||
try { return System.Text.Json.JsonSerializer.Deserialize<AbCipDriverOptions>(json, _jsonOpts); }
|
||||
|
||||
+10
@@ -3,6 +3,7 @@
|
||||
@rendermode RenderMode.InteractiveServer
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Clients
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration.Entities
|
||||
@@ -42,6 +43,12 @@ else
|
||||
<DriverStatusPanel DriverInstanceId="@DriverInstanceId" Enabled="@_identityModel.Enabled" />
|
||||
}
|
||||
|
||||
<div class="mt-2 mb-3">
|
||||
<DriverTestConnectButton DriverType="@DriverTypeKey"
|
||||
GetConfigJson="@SerializeCurrentConfig"
|
||||
TimeoutSeconds="@_form.AdminProbeTimeoutSeconds" />
|
||||
</div>
|
||||
|
||||
@* Operation settings *@
|
||||
<section class="panel rise mt-3" style="animation-delay:.06s">
|
||||
<div class="panel-head">Operation settings</div>
|
||||
@@ -273,6 +280,9 @@ else
|
||||
finally { _busy = false; }
|
||||
}
|
||||
|
||||
private string SerializeCurrentConfig()
|
||||
=> System.Text.Json.JsonSerializer.Serialize(_form.ToOptions(_devices, _tags), _jsonOpts);
|
||||
|
||||
private static AbLegacyDriverOptions? TryDeserialize(string json)
|
||||
{
|
||||
try { return System.Text.Json.JsonSerializer.Deserialize<AbLegacyDriverOptions>(json, _jsonOpts); }
|
||||
|
||||
+10
@@ -3,6 +3,7 @@
|
||||
@rendermode RenderMode.InteractiveServer
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Clients
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration.Entities
|
||||
@@ -41,6 +42,12 @@ else
|
||||
<DriverStatusPanel DriverInstanceId="@DriverInstanceId" Enabled="@_identityModel.Enabled" />
|
||||
}
|
||||
|
||||
<div class="mt-2 mb-3">
|
||||
<DriverTestConnectButton DriverType="@DriverTypeKey"
|
||||
GetConfigJson="@SerializeCurrentConfig"
|
||||
TimeoutSeconds="@_form.AdminProbeTimeoutSeconds" />
|
||||
</div>
|
||||
|
||||
@* Connection *@
|
||||
<section class="panel rise mt-3" style="animation-delay:.05s">
|
||||
<div class="panel-head">Connection</div>
|
||||
@@ -344,6 +351,9 @@ else
|
||||
finally { _busy = false; }
|
||||
}
|
||||
|
||||
private string SerializeCurrentConfig()
|
||||
=> System.Text.Json.JsonSerializer.Serialize(_form.ToOptions(), _jsonOpts);
|
||||
|
||||
private static FocasDriverOptions? TryDeserialize(string json)
|
||||
{
|
||||
try { return System.Text.Json.JsonSerializer.Deserialize<FocasDriverOptions>(json, _jsonOpts); }
|
||||
|
||||
+10
@@ -3,6 +3,7 @@
|
||||
@rendermode RenderMode.InteractiveServer
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Clients
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration.Entities
|
||||
@@ -41,6 +42,12 @@ else
|
||||
<DriverStatusPanel DriverInstanceId="@DriverInstanceId" Enabled="@_identityModel.Enabled" />
|
||||
}
|
||||
|
||||
<div class="mt-2 mb-3">
|
||||
<DriverTestConnectButton DriverType="@DriverTypeKey"
|
||||
GetConfigJson="@SerializeCurrentConfig"
|
||||
TimeoutSeconds="@_form.Galaxy.ProbeTimeoutSeconds" />
|
||||
</div>
|
||||
|
||||
@* mxaccessgw connection *@
|
||||
<section class="panel rise mt-3" style="animation-delay:.06s">
|
||||
<div class="panel-head">mxaccessgw connection</div>
|
||||
@@ -331,6 +338,9 @@ else
|
||||
finally { _busy = false; }
|
||||
}
|
||||
|
||||
private string SerializeCurrentConfig()
|
||||
=> System.Text.Json.JsonSerializer.Serialize(_form.Galaxy.ToRecord(), _jsonOpts);
|
||||
|
||||
private static GalaxyDriverOptions? TryDeserialize(string json)
|
||||
{
|
||||
try { return System.Text.Json.JsonSerializer.Deserialize<GalaxyDriverOptions>(json, _jsonOpts); }
|
||||
|
||||
+10
@@ -3,6 +3,7 @@
|
||||
@rendermode RenderMode.InteractiveServer
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Clients
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration.Entities
|
||||
@@ -41,6 +42,12 @@ else
|
||||
<DriverStatusPanel DriverInstanceId="@DriverInstanceId" Enabled="@_identityModel.Enabled" />
|
||||
}
|
||||
|
||||
<div class="mt-2 mb-3">
|
||||
<DriverTestConnectButton DriverType="@DriverTypeKey"
|
||||
GetConfigJson="@SerializeCurrentConfig"
|
||||
TimeoutSeconds="@_form.Historian.ProbeTimeoutSeconds" />
|
||||
</div>
|
||||
|
||||
@* Connection *@
|
||||
<section class="panel rise mt-3" style="animation-delay:.06s">
|
||||
<div class="panel-head">Connection</div>
|
||||
@@ -260,6 +267,9 @@ else
|
||||
finally { _busy = false; }
|
||||
}
|
||||
|
||||
private string SerializeCurrentConfig()
|
||||
=> System.Text.Json.JsonSerializer.Serialize(_form.Historian.ToRecord(), _jsonOpts);
|
||||
|
||||
private static WonderwareHistorianClientOptions? TryDeserialize(string json)
|
||||
{
|
||||
try { return System.Text.Json.JsonSerializer.Deserialize<WonderwareHistorianClientOptions>(json, _jsonOpts); }
|
||||
|
||||
+10
@@ -3,6 +3,7 @@
|
||||
@rendermode RenderMode.InteractiveServer
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Clients
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration.Entities
|
||||
@@ -41,6 +42,12 @@ else
|
||||
<DriverStatusPanel DriverInstanceId="@DriverInstanceId" Enabled="@_identityModel.Enabled" />
|
||||
}
|
||||
|
||||
<div class="mt-2 mb-3">
|
||||
<DriverTestConnectButton DriverType="@DriverTypeKey"
|
||||
GetConfigJson="@SerializeCurrentConfig"
|
||||
TimeoutSeconds="@_form.AdminProbeTimeoutSeconds" />
|
||||
</div>
|
||||
|
||||
@* Transport *@
|
||||
<section class="panel rise mt-3" style="animation-delay:.06s">
|
||||
<div class="panel-head">Transport</div>
|
||||
@@ -415,6 +422,9 @@ else
|
||||
finally { _busy = false; }
|
||||
}
|
||||
|
||||
private string SerializeCurrentConfig()
|
||||
=> System.Text.Json.JsonSerializer.Serialize(_form.ToOptions(_tags), _jsonOpts);
|
||||
|
||||
private static ModbusDriverOptions? TryDeserialize(string json)
|
||||
{
|
||||
try { return System.Text.Json.JsonSerializer.Deserialize<ModbusDriverOptions>(json, _jsonOpts); }
|
||||
|
||||
+10
@@ -3,6 +3,7 @@
|
||||
@rendermode RenderMode.InteractiveServer
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Clients
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration.Entities
|
||||
@@ -41,6 +42,12 @@ else
|
||||
<DriverStatusPanel DriverInstanceId="@DriverInstanceId" Enabled="@_identityModel.Enabled" />
|
||||
}
|
||||
|
||||
<div class="mt-2 mb-3">
|
||||
<DriverTestConnectButton DriverType="@DriverTypeKey"
|
||||
GetConfigJson="@SerializeCurrentConfig"
|
||||
TimeoutSeconds="@_form.OpcUa.ProbeTimeoutSeconds" />
|
||||
</div>
|
||||
|
||||
@* Endpoint *@
|
||||
<section class="panel rise mt-3" style="animation-delay:.06s">
|
||||
<div class="panel-head">Endpoint</div>
|
||||
@@ -379,6 +386,9 @@ else
|
||||
finally { _busy = false; }
|
||||
}
|
||||
|
||||
private string SerializeCurrentConfig()
|
||||
=> System.Text.Json.JsonSerializer.Serialize(_form.OpcUa.ToRecord(), _jsonOpts);
|
||||
|
||||
private static OpcUaClientDriverOptions? TryDeserialize(string json)
|
||||
{
|
||||
try { return System.Text.Json.JsonSerializer.Deserialize<OpcUaClientDriverOptions>(json, _jsonOpts); }
|
||||
|
||||
+10
@@ -3,6 +3,7 @@
|
||||
@rendermode RenderMode.InteractiveServer
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Clients
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration.Entities
|
||||
@@ -41,6 +42,12 @@ else
|
||||
<DriverStatusPanel DriverInstanceId="@DriverInstanceId" Enabled="@_identityModel.Enabled" />
|
||||
}
|
||||
|
||||
<div class="mt-2 mb-3">
|
||||
<DriverTestConnectButton DriverType="@DriverTypeKey"
|
||||
GetConfigJson="@SerializeCurrentConfig"
|
||||
TimeoutSeconds="@_form.AdminProbeTimeoutSeconds" />
|
||||
</div>
|
||||
|
||||
@* Connection *@
|
||||
<section class="panel rise mt-3" style="animation-delay:.05s">
|
||||
<div class="panel-head">Connection</div>
|
||||
@@ -280,6 +287,9 @@ else
|
||||
finally { _busy = false; }
|
||||
}
|
||||
|
||||
private string SerializeCurrentConfig()
|
||||
=> System.Text.Json.JsonSerializer.Serialize(_form.ToOptions(), _jsonOpts);
|
||||
|
||||
private static S7DriverOptions? TryDeserialize(string json)
|
||||
{
|
||||
try { return System.Text.Json.JsonSerializer.Deserialize<S7DriverOptions>(json, _jsonOpts); }
|
||||
|
||||
+10
@@ -3,6 +3,7 @@
|
||||
@rendermode RenderMode.InteractiveServer
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Clients
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration
|
||||
@using ZB.MOM.WW.OtOpcUa.Configuration.Entities
|
||||
@@ -41,6 +42,12 @@ else
|
||||
<DriverStatusPanel DriverInstanceId="@DriverInstanceId" Enabled="@_identityModel.Enabled" />
|
||||
}
|
||||
|
||||
<div class="mt-2 mb-3">
|
||||
<DriverTestConnectButton DriverType="@DriverTypeKey"
|
||||
GetConfigJson="@SerializeCurrentConfig"
|
||||
TimeoutSeconds="@_form.AdminProbeTimeoutSeconds" />
|
||||
</div>
|
||||
|
||||
@* Options *@
|
||||
<section class="panel rise mt-3" style="animation-delay:.05s">
|
||||
<div class="panel-head">Options</div>
|
||||
@@ -286,6 +293,9 @@ else
|
||||
finally { _busy = false; }
|
||||
}
|
||||
|
||||
private string SerializeCurrentConfig()
|
||||
=> System.Text.Json.JsonSerializer.Serialize(_form.ToOptions(), _jsonOpts);
|
||||
|
||||
private static TwinCATDriverOptions? TryDeserialize(string json)
|
||||
{
|
||||
try { return System.Text.Json.JsonSerializer.Deserialize<TwinCATDriverOptions>(json, _jsonOpts); }
|
||||
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
@using ZB.MOM.WW.OtOpcUa.AdminUI.Clients
|
||||
@using ZB.MOM.WW.OtOpcUa.Commons.Messages.Admin
|
||||
@inject AdminProbeService Probe
|
||||
@implements IDisposable
|
||||
|
||||
<div class="d-inline-flex align-items-center gap-2">
|
||||
<button type="button" class="btn btn-outline-primary btn-sm" disabled="@_busy" @onclick="OnClickAsync">
|
||||
@if (_busy) { <span class="spinner-border spinner-border-sm me-1"></span> }
|
||||
Test Connect
|
||||
</button>
|
||||
|
||||
@if (_result is not null)
|
||||
{
|
||||
@if (_result.Ok)
|
||||
{
|
||||
<span class="chip chip-ok" title="@($"Probe succeeded in {_result.LatencyMs:F0} ms")">
|
||||
OK · @_result.LatencyMs?.ToString("F0") ms
|
||||
</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="chip chip-bad" title="@_result.Message">
|
||||
Failed · @TruncatedMessage()
|
||||
</span>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
||||
@code {
|
||||
/// <summary>Driver type key — must match an installed <c>IDriverProbe.DriverType</c>.</summary>
|
||||
[Parameter, EditorRequired] public string DriverType { get; set; } = "";
|
||||
|
||||
/// <summary>Callback that returns the current form config as JSON. Called at click time.</summary>
|
||||
[Parameter, EditorRequired] public Func<string> GetConfigJson { get; set; } = () => "{}";
|
||||
|
||||
/// <summary>Per-probe timeout forwarded to the actor (actor clamps to [1, 60] s). Default 10 s.</summary>
|
||||
[Parameter] public int TimeoutSeconds { get; set; } = 10;
|
||||
|
||||
private bool _busy;
|
||||
private TestDriverConnectResult? _result;
|
||||
private System.Timers.Timer? _clearTimer;
|
||||
|
||||
private async Task OnClickAsync()
|
||||
{
|
||||
_busy = true;
|
||||
_result = null;
|
||||
StateHasChanged();
|
||||
try
|
||||
{
|
||||
var json = GetConfigJson() ?? "{}";
|
||||
_result = await Probe.TestAsync(DriverType, json, TimeoutSeconds);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_result = new TestDriverConnectResult(false, ex.Message, null, Guid.Empty);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_busy = false;
|
||||
ScheduleClear();
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void ScheduleClear()
|
||||
{
|
||||
_clearTimer?.Dispose();
|
||||
_clearTimer = new System.Timers.Timer(30_000) { AutoReset = false };
|
||||
_clearTimer.Elapsed += async (_, _) =>
|
||||
{
|
||||
_result = null;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
};
|
||||
_clearTimer.Start();
|
||||
}
|
||||
|
||||
private string TruncatedMessage()
|
||||
=> _result?.Message is null ? "" :
|
||||
(_result.Message.Length > 60 ? _result.Message[..60] + "…" : _result.Message);
|
||||
|
||||
public void Dispose() => _clearTimer?.Dispose();
|
||||
}
|
||||
Reference in New Issue
Block a user