844f93f64f
Extract the 8 typed driver pages into embeddable <Driver>DriverForm bodies (channel/protocol config) and add per-driver <Driver>DeviceForm bodies (connection endpoint -> Device.DeviceConfig, v3 endpoint split). New DriverConfigModal + DeviceModal dispatch by DriverType (DriverTypeNames) for the /raw tree; Test-connect inside DeviceModal builds the merged Driver+Device config transiently via DriverDeviceConfigMerger. Routed pages now host the form bodies and keep working. Round-trip + enum-serialization guard tests for the Modbus driver form + Modbus device model; retargeted the existing page-form serialization tests + the _jsonOpts converter guard to the forms. Claude-Session: https://claude.ai/code/session_01LVneM3eh1UtJxEisFXgmox
51 lines
2.4 KiB
C#
51 lines
2.4 KiB
C#
using ZB.MOM.WW.OtOpcUa.AdminUI.Uns.TagEditors;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers.DeviceForms;
|
|
|
|
/// <summary>
|
|
/// Typed working model for an OPC UA Client <c>Device</c>'s connection endpoint. Authors the PascalCase
|
|
/// <c>EndpointUrl</c> key that <c>OpcUaClientDriverOptions</c> binds. (The driver-level <c>EndpointUrls</c>
|
|
/// failover list stays on the driver config; a device's <c>EndpointUrl</c> is used only when that list
|
|
/// is empty.) Preserves unrecognised keys across a load→save.
|
|
/// </summary>
|
|
public sealed class OpcUaClientDeviceModel
|
|
{
|
|
/// <summary>The single upstream server endpoint URL (opc.tcp://…).</summary>
|
|
public string EndpointUrl { get; set; } = "opc.tcp://localhost:4840";
|
|
|
|
private System.Text.Json.Nodes.JsonObject _bag = new();
|
|
|
|
/// <summary>Loads a model from a DeviceConfig JSON string, defaulting absent keys and retaining
|
|
/// every original key so fields this editor doesn't expose survive a load→save.</summary>
|
|
/// <param name="json">The raw DeviceConfig JSON string, or null for a new/empty device.</param>
|
|
/// <returns>The populated <see cref="OpcUaClientDeviceModel"/>.</returns>
|
|
public static OpcUaClientDeviceModel FromJson(string? json)
|
|
{
|
|
var o = TagConfigJson.ParseOrNew(json);
|
|
return new OpcUaClientDeviceModel
|
|
{
|
|
EndpointUrl = TagConfigJson.GetString(o, "EndpointUrl") ?? "opc.tcp://localhost:4840",
|
|
_bag = o,
|
|
};
|
|
}
|
|
|
|
/// <summary>Serializes this model back to a DeviceConfig JSON string, writing the PascalCase
|
|
/// <c>EndpointUrl</c> key over the preserved key bag.</summary>
|
|
/// <returns>The serialised DeviceConfig JSON string.</returns>
|
|
public string ToJson()
|
|
{
|
|
TagConfigJson.Set(_bag, "EndpointUrl", EndpointUrl);
|
|
return TagConfigJson.Serialize(_bag);
|
|
}
|
|
|
|
/// <summary>Validation hook; returns an error message or null when the model is valid.</summary>
|
|
/// <returns>An error message describing the validation failure, or <c>null</c> when the model is valid.</returns>
|
|
public string? Validate()
|
|
{
|
|
if (string.IsNullOrWhiteSpace(EndpointUrl)) return "Endpoint URL is required.";
|
|
if (!EndpointUrl.Trim().StartsWith("opc.tcp://", StringComparison.OrdinalIgnoreCase))
|
|
return "Endpoint URL must start with opc.tcp://";
|
|
return null;
|
|
}
|
|
}
|