@* Create / edit modal for a raw-tree DriverInstance's channel/protocol config (endpoint lives on the device — see DeviceModal). Dispatches to the right per-driver form body by DriverType; the form body carries its own resilience section. The coordinator wires this into RawTree via @bind-Visible. *@ @using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.Forms @using ZB.MOM.WW.OtOpcUa.AdminUI.Uns @using ZB.MOM.WW.OtOpcUa.Core.Abstractions @inject IRawTreeService Svc @if (Visible) { } @code { /// Whether the modal is shown (supports @bind-Visible). [Parameter] public bool Visible { get; set; } /// Two-way visibility callback. [Parameter] public EventCallback VisibleChanged { get; set; } /// The driver instance to edit; null ⇒ create a new driver. [Parameter] public string? DriverInstanceId { get; set; } // --- Create-mode inputs (ignored on edit) --- /// The owning cluster (required for create). [Parameter] public string? ClusterId { get; set; } /// The containing folder, or null for a cluster-root driver (create). [Parameter] public string? FolderId { get; set; } /// The driver type to create (required for create; immutable on edit). [Parameter] public string? DriverType { get; set; } /// Raised after a successful create/update so the tree can refresh. [Parameter] public EventCallback OnSaved { get; set; } private bool _isNew; private string _driverType = ""; private string _name = ""; private string _driverConfigJson = "{}"; private string? _resilienceConfig; private byte[] _rowVersion = []; private bool _busy; private string? _loadError; private string? _saveError; private bool _openHandled; protected override async Task OnParametersSetAsync() { if (Visible && !_openHandled) { _openHandled = true; await LoadAsync(); } else if (!Visible) { _openHandled = false; } } private async Task LoadAsync() { _busy = false; _loadError = null; _saveError = null; _isNew = string.IsNullOrEmpty(DriverInstanceId); if (_isNew) { _driverType = DriverType ?? ""; _name = ""; _driverConfigJson = "{}"; _resilienceConfig = null; _rowVersion = []; } else { var dto = await Svc.LoadDriverForEditAsync(DriverInstanceId!); if (dto is null) { _loadError = $"Driver '{DriverInstanceId}' was not found."; return; } _driverType = dto.DriverType; _name = dto.Name; _driverConfigJson = string.IsNullOrWhiteSpace(dto.DriverConfig) ? "{}" : dto.DriverConfig; _resilienceConfig = dto.ResilienceConfig; _rowVersion = dto.RowVersion; } } private async Task SaveAsync() { _busy = true; _saveError = null; try { UnsMutationResult result; if (_isNew) { if (string.IsNullOrEmpty(ClusterId)) { _saveError = "No owning cluster was supplied."; return; } result = await Svc.CreateDriverAsync(ClusterId, FolderId, _name, _driverType, _driverConfigJson); } else { result = await Svc.UpdateDriverAsync(DriverInstanceId!, _name, _driverConfigJson, _resilienceConfig, _rowVersion); } if (!result.Ok) { _saveError = result.Error ?? "Save failed."; return; } await OnSaved.InvokeAsync(); await SetVisibleAsync(false); } catch (Exception ex) { _saveError = ex.Message; } finally { _busy = false; } } private Task CloseAsync() => SetVisibleAsync(false); private async Task SetVisibleAsync(bool value) { Visible = value; _openHandled = value; await VisibleChanged.InvokeAsync(value); } }