diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/DriverEdit.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/DriverEdit.razor deleted file mode 100644 index 06b1688b..00000000 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/DriverEdit.razor +++ /dev/null @@ -1,247 +0,0 @@ -@* Per Q1 of the AdminUI rebuild plan — JSON editor only, typed driver editors deferred. - DriverInstance is the keystone for everything downstream (Equipment, Tag, VirtualTag, - ScriptedAlarm all reference DriverInstanceId), so this is the second edit page after - Namespace. *@ -@attribute [Microsoft.AspNetCore.Authorization.Authorize] -@rendermode RenderMode.InteractiveServer -@using Microsoft.AspNetCore.Components.Forms -@using Microsoft.EntityFrameworkCore -@using System.ComponentModel.DataAnnotations -@using ZB.MOM.WW.OtOpcUa.Configuration -@using ZB.MOM.WW.OtOpcUa.Configuration.Entities -@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers -@inject IDbContextFactory DbFactory -@inject NavigationManager Nav - -
-

@(IsNew ? "New driver instance" : "Edit driver instance") · @ClusterId

- Cancel -
- - - -@if (!_loaded) -{ -

Loading…

-} -else if (!IsNew && _existing is null) -{ -
- Driver instance @DriverInstanceId was not found in cluster @ClusterId. -
-} -else -{ - - - - - - @* Driver config (JSON) — inlined; will be replaced by typed forms in Phase 4 *@ -
-
Driver config (JSON)
-
- -
Schemaless per driver type — validated server-side at deploy time. JSON is reformatted on save.
-
-
- - -
-
-} - -@code { - [Parameter] public string ClusterId { get; set; } = ""; - [Parameter] public string? DriverInstanceId { get; set; } - - private bool IsNew => string.IsNullOrEmpty(DriverInstanceId); - - private DriverIdentitySection.DriverIdentityModel _identityModel = new(); - private FormModel _form = new(); - private DriverInstance? _existing; - private List _namespaces = new(); - private bool _loaded; - private bool _busy; - private string? _error; - - protected override async Task OnInitializedAsync() - { - await using var db = await DbFactory.CreateDbContextAsync(); - _namespaces = await db.Namespaces.AsNoTracking() - .Where(n => n.ClusterId == ClusterId) - .OrderBy(n => n.NamespaceId) - .ToListAsync(); - - if (IsNew) - { - _identityModel = new DriverIdentitySection.DriverIdentityModel - { - DriverInstanceId = "", - Name = "", - DriverType = "ModbusTcp", - NamespaceId = _namespaces.FirstOrDefault()?.NamespaceId ?? "", - Enabled = true, - }; - _form = new FormModel - { - DriverConfig = "{}", - }; - } - else - { - _existing = await db.DriverInstances.AsNoTracking() - .FirstOrDefaultAsync(d => d.ClusterId == ClusterId && d.DriverInstanceId == DriverInstanceId); - if (_existing is not null) - { - _identityModel = new DriverIdentitySection.DriverIdentityModel - { - DriverInstanceId = _existing.DriverInstanceId, - Name = _existing.Name, - DriverType = _existing.DriverType, - NamespaceId = _existing.NamespaceId, - Enabled = _existing.Enabled, - }; - _form = new FormModel - { - DriverConfig = _existing.DriverConfig, - ResilienceConfig = _existing.ResilienceConfig, - RowVersion = _existing.RowVersion, - }; - } - } - _loaded = true; - } - - private async Task SubmitAsync() - { - _busy = true; - _error = null; - try - { - var normalizedConfig = NormalizeJson(_form.DriverConfig); - if (normalizedConfig is null) - { - _error = "DriverConfig is not valid JSON."; - return; - } - var normalizedResilience = NormalizeOptionalJson(_form.ResilienceConfig); - if (!string.IsNullOrWhiteSpace(_form.ResilienceConfig) && normalizedResilience is null) - { - _error = "ResilienceConfig is not valid JSON. Leave blank to use defaults."; - return; - } - - await using var db = await DbFactory.CreateDbContextAsync(); - if (IsNew) - { - if (await db.DriverInstances.AnyAsync(d => d.DriverInstanceId == _identityModel.DriverInstanceId)) - { - _error = $"Driver instance '{_identityModel.DriverInstanceId}' already exists."; - return; - } - db.DriverInstances.Add(new DriverInstance - { - DriverInstanceId = _identityModel.DriverInstanceId, - ClusterId = ClusterId, - NamespaceId = _identityModel.NamespaceId, - Name = _identityModel.Name, - DriverType = _identityModel.DriverType, - Enabled = _identityModel.Enabled, - DriverConfig = normalizedConfig, - ResilienceConfig = normalizedResilience, - }); - } - else - { - var entity = await db.DriverInstances.FirstOrDefaultAsync( - d => d.ClusterId == ClusterId && d.DriverInstanceId == DriverInstanceId); - if (entity is null) - { - _error = "Row no longer exists."; - return; - } - db.Entry(entity).Property(e => e.RowVersion).OriginalValue = _form.RowVersion; - entity.NamespaceId = _identityModel.NamespaceId; - entity.Name = _identityModel.Name; - entity.Enabled = _identityModel.Enabled; - entity.DriverConfig = normalizedConfig; - entity.ResilienceConfig = normalizedResilience; - } - await db.SaveChangesAsync(); - Nav.NavigateTo($"/clusters/{ClusterId}/drivers"); - } - catch (DbUpdateConcurrencyException) - { - _error = "Another user changed this driver instance while you were editing. Reload to see the latest values, then re-apply your changes."; - } - catch (Exception ex) - { - _error = ex.Message; - } - finally - { - _busy = false; - } - } - - private async Task DeleteAsync() - { - if (IsNew) return; - _busy = true; - _error = null; - try - { - await using var db = await DbFactory.CreateDbContextAsync(); - var entity = await db.DriverInstances.FirstOrDefaultAsync( - d => d.ClusterId == ClusterId && d.DriverInstanceId == DriverInstanceId); - if (entity is null) - { - Nav.NavigateTo($"/clusters/{ClusterId}/drivers"); - return; - } - db.Entry(entity).Property(e => e.RowVersion).OriginalValue = _form.RowVersion; - db.DriverInstances.Remove(entity); - await db.SaveChangesAsync(); - Nav.NavigateTo($"/clusters/{ClusterId}/drivers"); - } - catch (DbUpdateConcurrencyException) - { - _error = "Another user changed this driver instance while you were viewing it. Reload before deleting."; - } - catch (Exception ex) - { - _error = $"Delete failed: {ex.Message}. (Likely because equipment/tags still reference this driver — remove them first.)"; - } - finally - { - _busy = false; - } - } - - private static string? NormalizeJson(string? input) - { - if (string.IsNullOrWhiteSpace(input)) return null; - try - { - using var doc = System.Text.Json.JsonDocument.Parse(input); - return System.Text.Json.JsonSerializer.Serialize(doc.RootElement); - } - catch { return null; } - } - - private static string? NormalizeOptionalJson(string? input) => - string.IsNullOrWhiteSpace(input) ? null : NormalizeJson(input); - - private sealed class FormModel - { - [Required] - public string DriverConfig { get; set; } = "{}"; - public string? ResilienceConfig { get; set; } - public byte[] RowVersion { get; set; } = []; - } -} diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/Drivers/DriverEditRouter.razor b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/Drivers/DriverEditRouter.razor index 1d8e4915..0b7bb07f 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/Drivers/DriverEditRouter.razor +++ b/src/Server/ZB.MOM.WW.OtOpcUa.AdminUI/Components/Pages/Clusters/Drivers/DriverEditRouter.razor @@ -26,9 +26,22 @@ else if (_existing is null) Driver instance @DriverInstanceId was not found in cluster @ClusterId. } +else if (ResolveComponentType() is { } pageType) +{ + +} else { - +
+

Edit driver instance · @ClusterId

+ Cancel +
+ +
+ Driver instance @DriverInstanceId has an unknown DriverType value of + @_existing.DriverType. No editor is registered for this type. + Likely causes: the row was written by a newer build, or the type-string was corrupted in the database. +
} @code { @@ -60,10 +73,8 @@ else _loaded = true; } - private Type ResolveComponentType() - => _componentMap.TryGetValue(_existing!.DriverType, out var t) - ? t - : typeof(ZB.MOM.WW.OtOpcUa.AdminUI.Components.Pages.Clusters.DriverEdit); + private Type? ResolveComponentType() + => _componentMap.TryGetValue(_existing!.DriverType, out var t) ? t : null; private IDictionary BuildParameters() => new Dictionary