Files
lmxopcua/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Shared/Drivers/DriverTestConnectButton.razor
T
Joseph Doherty 4b374fd177 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).
2026-05-28 11:02:49 -04:00

83 lines
2.6 KiB
Plaintext

@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 &middot; @_result.LatencyMs?.ToString("F0") ms
</span>
}
else
{
<span class="chip chip-bad" title="@_result.Message">
Failed &middot; @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();
}