diff --git a/docs/Client.CLI.md b/docs/Client.CLI.md index 7c6f1883..61b73e2a 100644 --- a/docs/Client.CLI.md +++ b/docs/Client.CLI.md @@ -41,6 +41,12 @@ All commands accept these options: | `-F` / `--failover-urls` | Comma-separated failover endpoint URLs for redundancy | | `--verbose` | Enable debug-level Serilog console logging (default: warning) | +**`--security none` does not fall back.** Endpoint selection picks the server's `None`-policy endpoint and +fails with an `InvalidOperationException` naming the endpoints the server does offer when it has none. The +older stack helper silently fell back to the first endpoint (often a secured one), so a command that +defaulted to `none` against a secured-only server used to connect and now errors. Pass `-S sign`, +`-S encrypt` or `-S signandencrypt` to talk to such a server. + ### Authentication When `-U` and `-P` are provided, the shared service passes a `UserIdentity(username, password)` to the OPC UA session. Without credentials, anonymous identity is used. diff --git a/docs/Client.UI.md b/docs/Client.UI.md index 0424a3cc..02497456 100644 --- a/docs/Client.UI.md +++ b/docs/Client.UI.md @@ -57,7 +57,7 @@ The top bar provides the endpoint URL, Connect, and Disconnect buttons. The **Co |---------|-------------| | Endpoint URL | OPC UA server endpoint (e.g., `opc.tcp://localhost:4840/OtOpcUa`) | | Username / Password | Credentials for `UserName` token authentication | -| Security Mode | Transport security: None, Sign, SignAndEncrypt | +| Security Mode | Transport security: None, Sign, SignAndEncrypt. `None` requires the server to offer a `None` endpoint — there is no fallback to a secured one; connecting fails naming the endpoints offered | | Failover URLs | Comma-separated backup endpoints for redundancy failover | | Session Timeout | Session timeout in seconds (1–3600, default 60) | | Certificate Store Path | Path to the client certificate store (folder chooser) | diff --git a/src/Client/ZB.MOM.WW.OtOpcUa.Client.Shared/Adapters/ClientTelemetry.cs b/src/Client/ZB.MOM.WW.OtOpcUa.Client.Shared/Adapters/ClientTelemetry.cs index d574bb18..3f4fbccf 100644 --- a/src/Client/ZB.MOM.WW.OtOpcUa.Client.Shared/Adapters/ClientTelemetry.cs +++ b/src/Client/ZB.MOM.WW.OtOpcUa.Client.Shared/Adapters/ClientTelemetry.cs @@ -29,7 +29,13 @@ internal static class DisposeBridge using var cts = new CancellationTokenSource(Timeout); try { - Task.Run(() => work(cts.Token), cts.Token).Wait(Timeout); + var task = Task.Run(() => work(cts.Token), cts.Token); + // Observe a late fault so it never surfaces as an unobserved-task exception. + _ = task.ContinueWith(t => _ = t.Exception, TaskContinuationOptions.OnlyOnFaulted); + // The CTS's own timer and this Wait race: when Wait loses, `using` would dispose the CTS before + // the token ever fired, leaving the work running while the caller goes on to dispose the session. + // Cancel explicitly so the in-flight Close/Delete is told to stop. + if (!task.Wait(Timeout)) { cts.Cancel(); } } catch { diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Layout/MainLayout.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Layout/MainLayout.razor index f6e31dfe..3951a806 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Layout/MainLayout.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Layout/MainLayout.razor @@ -1,5 +1,4 @@ @inherits LayoutComponentBase -@implements IDisposable @using System.Security.Claims @* Thin delegation to the shared ZB.MOM.WW.Theme side-rail chassis. ThemeShell owns @@ -71,33 +70,9 @@ - @* A throwing page would otherwise kill the whole circuit (blank "reload" bar). The boundary - confines it to the page body and offers Recover; navigating away also recovers it. It does NOT - catch exceptions from async-void handlers or timer callbacks. *@ - - @Body - - - - + @* No ErrorBoundary here: this layout renders statically (Routes is SSR), so it is not an ancestor + of any @rendermode InteractiveServer page and a boundary here would never see their failures. + Interactive pages wrap their body in instead. *@ + @Body - -@code { - private ErrorBoundary? _boundary; - - [Inject] private NavigationManager Nav { get; set; } = default!; - - protected override void OnInitialized() => Nav.LocationChanged += OnLocationChanged; - - // A fresh navigation clears a tripped boundary so the next page isn't stuck behind the old error. - private void OnLocationChanged(object? sender, Microsoft.AspNetCore.Components.Routing.LocationChangedEventArgs e) - => _boundary?.Recover(); - - /// - public void Dispose() => Nav.LocationChanged -= OnLocationChanged; -} diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/AlarmsHistorian.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/AlarmsHistorian.razor index 751d759b..f1fcf87e 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/AlarmsHistorian.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/AlarmsHistorian.razor @@ -11,6 +11,7 @@ @inject IRequiredActor HistorianActor @implements IDisposable +

Alarms historian sink

@@ -43,6 +44,7 @@ else } +
@code { private const int PollSeconds = 5; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Alerts.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Alerts.razor index da30583b..7cee1860 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Alerts.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Alerts.razor @@ -14,6 +14,7 @@ @inject IAdminOperationsClient AdminOps @implements IAsyncDisposable +

Alerts

@@ -131,6 +132,7 @@ else
} + @code { private const int Capacity = 200; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/ApiKeys.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/ApiKeys.razor index f8c69867..ec88539f 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/ApiKeys.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/ApiKeys.razor @@ -6,6 +6,7 @@ @using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Raw @inject IApiKeyAdminService Keys +

OPC UA API keys

@@ -117,6 +118,7 @@ +
@code { private IReadOnlyList? _keys; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Certificates.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Certificates.razor index 3c8b4d0b..a05898fe 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Certificates.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Certificates.razor @@ -11,6 +11,7 @@ @inject AuthenticationStateProvider AuthState @implements IDisposable +

OPC UA certificates

@@ -108,6 +109,7 @@ else } } +
@code { private List? _rows; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/AclEdit.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/AclEdit.razor index c541f38d..88f85e7e 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/AclEdit.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/AclEdit.razor @@ -14,6 +14,7 @@ @inject IAclScopeService Scopes @inject NavigationManager Nav +

@(IsNew ? "New ACL grant" : "Edit ACL grant") · @ClusterId

Cancel @@ -154,6 +155,7 @@ else } + @code { private static readonly NodePermissions[] PermissionBits = diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClusterAcls.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClusterAcls.razor index b3ef922a..566f34e7 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClusterAcls.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClusterAcls.razor @@ -8,6 +8,7 @@ @inject IDbContextFactory DbFactory @inject IAclScopeService Scopes +

ACLs · @ClusterId

New ACL grant @@ -95,6 +96,7 @@ else } } + @code { [Parameter] public string ClusterId { get; set; } = ""; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClusterAudit.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClusterAudit.razor index f7131fca..96da3c8a 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClusterAudit.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClusterAudit.razor @@ -7,6 +7,7 @@ @using ZB.MOM.WW.OtOpcUa.Configuration.Queries @inject IDbContextFactory DbFactory +

Audit log · @ClusterId

@@ -64,6 +65,7 @@ else } } +
@code { private const int PageSize = 200; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClusterEdit.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClusterEdit.razor index 87640b98..c1349d6b 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClusterEdit.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClusterEdit.razor @@ -13,6 +13,7 @@ @inject NavigationManager Nav @inject AuthenticationStateProvider AuthState +

Edit cluster · @ClusterId

Cancel @@ -104,6 +105,7 @@ else
} +
@code { [Parameter] public string ClusterId { get; set; } = ""; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClusterNamespaces.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClusterNamespaces.razor index f8d1d407..d3cac1c1 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClusterNamespaces.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClusterNamespaces.razor @@ -2,6 +2,7 @@ @attribute [Authorize(Policy = AdminUiPolicies.AuthenticatedRead)] @rendermode RenderMode.InteractiveServer +

Namespaces · @ClusterId

@@ -16,6 +17,7 @@ /uns pages. This page is a placeholder so existing links do not 404.
+
@code { [Parameter] public string ClusterId { get; set; } = ""; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClusterOverview.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClusterOverview.razor index c9070c49..fb05675b 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClusterOverview.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClusterOverview.razor @@ -7,6 +7,7 @@ @inject IDbContextFactory DbFactory @inject NavigationManager Nav + @if (!_loaded) {

Loading…

@@ -110,6 +111,7 @@ else } } +
@code { [Parameter] public string ClusterId { get; set; } = ""; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClusterRedundancy.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClusterRedundancy.razor index 507ab9f3..36fff264 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClusterRedundancy.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClusterRedundancy.razor @@ -12,6 +12,7 @@ @inject AuthenticationStateProvider AuthState @inject IAuthorizationService AuthorizationService + @if (!_loaded) {

Loading…

@@ -140,6 +141,7 @@ else } } +
@code { [Parameter] public string ClusterId { get; set; } = ""; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClustersList.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClustersList.razor index d76b6070..a64d3d44 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClustersList.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/ClustersList.razor @@ -7,6 +7,7 @@ @inject IDbContextFactory DbFactory @inject NavigationManager Nav +

Clusters

New cluster @@ -61,6 +62,7 @@ else
} +
@code { private List? _rows; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/NamespaceEdit.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/NamespaceEdit.razor index 3e0c1597..eceebcb2 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/NamespaceEdit.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/NamespaceEdit.razor @@ -3,6 +3,7 @@ @attribute [Authorize(Policy = AdminUiPolicies.ConfigEditor)] @rendermode RenderMode.InteractiveServer +

Namespaces · @ClusterId

Back @@ -18,6 +19,7 @@ /uns pages. This editor no longer applies.
+
@code { [Parameter] public string ClusterId { get; set; } = ""; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/NewCluster.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/NewCluster.razor index 2cccf6a5..5ada78d4 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/NewCluster.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/NewCluster.razor @@ -10,6 +10,7 @@ @inject NavigationManager Nav @inject AuthenticationStateProvider AuthState +

New cluster

Cancel @@ -79,6 +80,7 @@
+
@code { private FormModel _form = new(); diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/NodeEdit.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/NodeEdit.razor index d8eae5a4..f4f5392a 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/NodeEdit.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/NodeEdit.razor @@ -15,6 +15,7 @@ @inject NavigationManager Nav @inject AuthenticationStateProvider AuthState +

@(IsNew ? "New node" : "Edit node") · @ClusterId

Cancel @@ -122,6 +123,7 @@ else
} +
@code { [Parameter] public string ClusterId { get; set; } = ""; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Deployments.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Deployments.razor index 1f8b32eb..69fd15ba 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Deployments.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Deployments.razor @@ -15,6 +15,7 @@ @inject ZB.MOM.WW.OtOpcUa.AdminUI.Deployments.DeploymentDriftProbe DriftProbe @rendermode InteractiveServer + Deployments

Deployments

@@ -64,6 +65,7 @@ } +
@code { // Blob-free projection: the Deployment entity carries a varbinary(max) ArtifactBlob (a whole-fleet diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Dev/ContextMenuDemo.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Dev/ContextMenuDemo.razor index 77791f2a..d4180e38 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Dev/ContextMenuDemo.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Dev/ContextMenuDemo.razor @@ -3,6 +3,7 @@ @attribute [Authorize(Policy = AdminUiPolicies.AuthenticatedRead)] @rendermode InteractiveServer + ContextMenu demo

ContextMenu demo

@@ -19,6 +20,7 @@

Last action: @_lastAction

+
@code { private string _lastAction = "(none)"; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Fleet.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Fleet.razor index a9053fcb..6e91c695 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Fleet.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Fleet.razor @@ -15,6 +15,7 @@ @inject IDbContextFactory DbFactory @implements IAsyncDisposable +

Fleet status

@@ -98,6 +99,7 @@ else } +
@code { private const int RefreshIntervalSeconds = 10; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Hosts.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Hosts.razor index 453abd93..ecaca6c3 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Hosts.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Hosts.razor @@ -21,6 +21,7 @@ @inject Microsoft.Extensions.Logging.ILogger Logger @implements IAsyncDisposable +

Cluster hosts

@@ -311,6 +312,7 @@ else } } +
@code { private const int RefreshIntervalSeconds = 5; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Raw/GlobalRaw.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Raw/GlobalRaw.razor index 4398507e..7ef8633a 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Raw/GlobalRaw.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Raw/GlobalRaw.razor @@ -15,6 +15,7 @@ each container via IRawTreeService.LoadChildrenAsync and surfaces per-node context menus (real create/configure/tag modals arrive in later Batch-2 waves). *@ + Raw
@@ -48,6 +49,7 @@
} +
@code { private IReadOnlyList _roots = Array.Empty(); diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Reservations.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Reservations.razor index 63fdefe7..69352897 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Reservations.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Reservations.razor @@ -6,6 +6,7 @@ @using ZB.MOM.WW.OtOpcUa.Configuration.Entities @inject IDbContextFactory DbFactory +

External ID reservations

@@ -50,6 +51,7 @@ else } } +
@code { private List? _rows; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/RoleGrants.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/RoleGrants.razor index 51f99111..2031c4b5 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/RoleGrants.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/RoleGrants.razor @@ -9,6 +9,7 @@ @inject IOptionsSnapshot Ldap @inject ILdapGroupRoleMappingService RoleMappings +

Role grants

@@ -103,6 +104,7 @@ } } +
@code { private LdapOptions? _options; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/ScriptEdit.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/ScriptEdit.razor index df0a2e5b..e0a1d8af 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/ScriptEdit.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/ScriptEdit.razor @@ -14,6 +14,7 @@ @inject IDbContextFactory DbFactory @inject NavigationManager Nav +

@(IsNew ? "New script" : "Edit script")

Cancel @@ -72,6 +73,7 @@ else
} +
@code { [Parameter] public string? ScriptId { get; set; } diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/ScriptLog.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/ScriptLog.razor index ebdb8d17..ff2893a1 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/ScriptLog.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/ScriptLog.razor @@ -8,6 +8,7 @@ @inject IInProcessBroadcaster ScriptLogs @implements IDisposable +

Script log

@@ -76,6 +77,7 @@ else
} + @code { private const int Capacity = 500; diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Scripts.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Scripts.razor index 8f3612ac..a946dfec 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Scripts.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Scripts.razor @@ -6,6 +6,7 @@ @using ZB.MOM.WW.OtOpcUa.Configuration.Entities @inject IDbContextFactory DbFactory +

Scripts

New script @@ -104,6 +105,7 @@ else
} +
@code { private List