feat(ui): OpcUaEndpointEditor Blazor component
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
@namespace ScadaLink.CentralUI.Components.Forms
|
||||
@using ScadaLink.Commons.Types.DataConnections
|
||||
@using ScadaLink.Commons.Types.Flattening
|
||||
|
||||
<div class="opcua-endpoint-editor">
|
||||
<h6 class="text-muted border-bottom pb-1">@Title</h6>
|
||||
|
||||
@if (IsLegacy)
|
||||
{
|
||||
<div class="alert alert-warning py-1 small mb-2">
|
||||
This connection was migrated from a legacy format.
|
||||
Review the settings and Save to update.
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="row g-2 mb-2">
|
||||
<div class="col-md-7">
|
||||
<label class="form-label small">Endpoint URL</label>
|
||||
<input type="text" class="form-control form-control-sm"
|
||||
@bind="Config.EndpointUrl"
|
||||
placeholder="opc.tcp://host:4840" />
|
||||
@RenderFieldError("EndpointUrl")
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label small">Security Mode</label>
|
||||
<select class="form-select form-select-sm" @bind="Config.SecurityMode">
|
||||
<option value="@OpcUaSecurityMode.None">None</option>
|
||||
<option value="@OpcUaSecurityMode.Sign">Sign</option>
|
||||
<option value="@OpcUaSecurityMode.SignAndEncrypt">Sign & Encrypt</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2 d-flex align-items-end">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox"
|
||||
id="@($"{IdPrefix}-autoaccept")"
|
||||
@bind="Config.AutoAcceptUntrustedCerts" />
|
||||
<label class="form-check-label small"
|
||||
for="@($"{IdPrefix}-autoaccept")">Auto-accept certs</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-muted small mt-2 mb-1">Timing</div>
|
||||
<div class="row g-2 mb-2">
|
||||
<div class="col-md-3">
|
||||
<label class="form-label small">Session timeout (ms)</label>
|
||||
<input type="number" class="form-control form-control-sm"
|
||||
@bind="Config.SessionTimeoutMs" min="1" />
|
||||
@RenderFieldError("SessionTimeoutMs")
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label small">Operation timeout (ms)</label>
|
||||
<input type="number" class="form-control form-control-sm"
|
||||
@bind="Config.OperationTimeoutMs" min="1" />
|
||||
@RenderFieldError("OperationTimeoutMs")
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-muted small mt-2 mb-1">Subscription</div>
|
||||
<div class="row g-2 mb-2">
|
||||
<div class="col-md-3">
|
||||
<label class="form-label small">Publishing interval (ms)</label>
|
||||
<input type="number" class="form-control form-control-sm"
|
||||
@bind="Config.PublishingIntervalMs" min="1" />
|
||||
@RenderFieldError("PublishingIntervalMs")
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label small">Sampling interval (ms)</label>
|
||||
<input type="number" class="form-control form-control-sm"
|
||||
@bind="Config.SamplingIntervalMs" min="1" />
|
||||
@RenderFieldError("SamplingIntervalMs")
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label class="form-label small">Queue size</label>
|
||||
<input type="number" class="form-control form-control-sm"
|
||||
@bind="Config.QueueSize" min="1" />
|
||||
@RenderFieldError("QueueSize")
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label class="form-label small">Keep-alive count</label>
|
||||
<input type="number" class="form-control form-control-sm"
|
||||
@bind="Config.KeepAliveCount" min="1" />
|
||||
@RenderFieldError("KeepAliveCount")
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label class="form-label small">Lifetime count</label>
|
||||
<input type="number" class="form-control form-control-sm"
|
||||
@bind="Config.LifetimeCount" min="1" />
|
||||
@RenderFieldError("LifetimeCount")
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label small">Max notifications / publish</label>
|
||||
<input type="number" class="form-control form-control-sm"
|
||||
@bind="Config.MaxNotificationsPerPublish" min="1" />
|
||||
@RenderFieldError("MaxNotificationsPerPublish")
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-muted small mt-2 mb-1">Heartbeat</div>
|
||||
@if (Config.Heartbeat is null)
|
||||
{
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm mb-2"
|
||||
@onclick="EnableHeartbeat">Enable Heartbeat</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="row g-2 mb-2">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label small">Tag path</label>
|
||||
<input type="text" class="form-control form-control-sm"
|
||||
@bind="Config.Heartbeat.TagPath"
|
||||
placeholder="Sensors.Heartbeat" />
|
||||
@RenderFieldError("Heartbeat.TagPath")
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label small">Max silence (s)</label>
|
||||
<input type="number" class="form-control form-control-sm"
|
||||
@bind="Config.Heartbeat.MaxSilenceSeconds" min="1" />
|
||||
@RenderFieldError("Heartbeat.MaxSilenceSeconds")
|
||||
</div>
|
||||
<div class="col-md-3 d-flex align-items-end">
|
||||
<button type="button" class="btn btn-outline-danger btn-sm"
|
||||
@onclick="() => Config.Heartbeat = null">
|
||||
Remove Heartbeat
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter, EditorRequired] public OpcUaEndpointConfig Config { get; set; } = default!;
|
||||
[Parameter] public string Title { get; set; } = "Endpoint";
|
||||
[Parameter] public string IdPrefix { get; set; } = "endpoint";
|
||||
[Parameter] public bool IsLegacy { get; set; }
|
||||
[Parameter] public ValidationResult? Errors { get; set; }
|
||||
|
||||
private void EnableHeartbeat() =>
|
||||
Config.Heartbeat = new OpcUaHeartbeatConfig();
|
||||
|
||||
private RenderFragment? RenderFieldError(string field)
|
||||
{
|
||||
var match = Errors?.Errors.FirstOrDefault(e =>
|
||||
e.EntityName != null
|
||||
&& (e.EntityName == field || e.EntityName.EndsWith("." + field)));
|
||||
return match is null
|
||||
? null
|
||||
: @<div class="text-danger small">@match.Message</div>;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user