76cffe1f49
Claude-Session: https://claude.ai/code/session_01LVneM3eh1UtJxEisFXgmox
398 lines
25 KiB
C#
398 lines
25 KiB
C#
using ZB.MOM.WW.OtOpcUa.Configuration.Enums;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Uns;
|
|
|
|
/// <summary>
|
|
/// Detached, editable projection of a raw <c>Tag</c> — the read side of tag editing. WP1 exposes this
|
|
/// loader; WP4 owns the create/update authoring surface and should align its input model with these
|
|
/// fields (identity is the RawPath, formed from the tag's device + optional group + name).
|
|
/// </summary>
|
|
/// <param name="TagId">The tag's stable logical id.</param>
|
|
/// <param name="DeviceId">The owning device's logical id.</param>
|
|
/// <param name="TagGroupId">The containing tag group's logical id, or null when directly under the device.</param>
|
|
/// <param name="Name">The tag name (a RawPath segment).</param>
|
|
/// <param name="DataType">The OPC UA built-in type name.</param>
|
|
/// <param name="AccessLevel">The tag's access-level baseline.</param>
|
|
/// <param name="WriteIdempotent">Whether writes to this tag are retry-eligible.</param>
|
|
/// <param name="PollGroupId">The optional poll-group id.</param>
|
|
/// <param name="TagConfig">The schemaless per-driver TagConfig JSON blob.</param>
|
|
/// <param name="RowVersion">The optimistic-concurrency token.</param>
|
|
public readonly record struct RawTagEditDto(
|
|
string TagId,
|
|
string DeviceId,
|
|
string? TagGroupId,
|
|
string Name,
|
|
string DataType,
|
|
TagAccessLevel AccessLevel,
|
|
bool WriteIdempotent,
|
|
string? PollGroupId,
|
|
string TagConfig,
|
|
byte[] RowVersion);
|
|
|
|
/// <summary>
|
|
/// Detached, editable projection of a <c>DriverInstance</c> — the read side of the Wave-B (WP3)
|
|
/// "Configure driver" modal. <c>DriverType</c> is included so the modal can dispatch to the correct
|
|
/// typed driver-config editor; it is immutable, so <see cref="IRawTreeService.UpdateDriverAsync"/> does
|
|
/// not change it.
|
|
/// </summary>
|
|
/// <param name="DriverInstanceId">The driver instance's stable logical id.</param>
|
|
/// <param name="Name">The driver instance name (a RawPath segment).</param>
|
|
/// <param name="DriverType">The immutable driver-type string (see <c>DriverTypeNames</c>).</param>
|
|
/// <param name="DriverConfig">The schemaless per-driver-type <c>DriverConfig</c> JSON blob.</param>
|
|
/// <param name="ResilienceConfig">Optional per-instance resilience-pipeline overrides JSON, or null.</param>
|
|
/// <param name="RowVersion">The optimistic-concurrency token.</param>
|
|
public sealed record RawDriverEditDto(
|
|
string DriverInstanceId,
|
|
string Name,
|
|
string DriverType,
|
|
string DriverConfig,
|
|
string? ResilienceConfig,
|
|
byte[] RowVersion);
|
|
|
|
/// <summary>
|
|
/// Detached, editable projection of a <c>Device</c> — the read side of the Wave-B (WP3) "Configure
|
|
/// device" modal. <c>DriverType</c> is joined in from the parent <c>DriverInstance</c> so the modal can
|
|
/// dispatch to the correct typed device-config editor (endpoint/connection settings now live in
|
|
/// <c>DeviceConfig</c>).
|
|
/// </summary>
|
|
/// <param name="DeviceId">The device's stable logical id.</param>
|
|
/// <param name="DriverInstanceId">The owning driver instance's logical id.</param>
|
|
/// <param name="Name">The device name (a RawPath segment).</param>
|
|
/// <param name="DeviceConfig">The schemaless per-driver-type <c>DeviceConfig</c> JSON blob (host/endpoint + per-device settings).</param>
|
|
/// <param name="Enabled">Whether the device is enabled.</param>
|
|
/// <param name="DriverType">The parent driver's type string, joined in for editor dispatch.</param>
|
|
/// <param name="RowVersion">The optimistic-concurrency token.</param>
|
|
public sealed record RawDeviceEditDto(
|
|
string DeviceId,
|
|
string DriverInstanceId,
|
|
string Name,
|
|
string DeviceConfig,
|
|
bool Enabled,
|
|
string DriverType,
|
|
byte[] RowVersion);
|
|
|
|
/// <summary>
|
|
/// Loads and mutates the v3 Raw project tree (<c>/raw</c>) — the cluster-rooted
|
|
/// Enterprise → Cluster → Folder → Driver → Device → TagGroup → Tag hierarchy — from the config
|
|
/// database. The peer of <see cref="IUnsTreeService"/> for the Raw subtree.
|
|
/// <para>
|
|
/// <b>Contract split (Batch 2 Wave A):</b> this file's committed surface is the <b>read</b> contract
|
|
/// the <c>RawTree</c> component consumes — <see cref="LoadRootsAsync"/> (eager Enterprise→Cluster roots)
|
|
/// and <see cref="LoadChildrenAsync"/> (one lazy level per expand). B2-WP1 (<c>RawTreeService</c>)
|
|
/// <b>extends this interface</b> with the mutation surface — create/rename/delete per node type,
|
|
/// move-into-folder, and the per-node edit projections — enforcing the integrity rules with
|
|
/// user-readable errors (a delete blocked by a <c>UnsTagReference</c> names the referencing equipment).
|
|
/// Rename methods return <see cref="RawRenameResult"/> so the UI can show non-blocking warnings.
|
|
/// Mutations reuse <see cref="UnsMutationResult"/>. WP2 must not add to this interface.
|
|
/// </para>
|
|
/// </summary>
|
|
public interface IRawTreeService
|
|
{
|
|
/// <summary>
|
|
/// Loads the eager top of the Raw tree: Enterprise → Cluster roots, each cluster marked
|
|
/// <see cref="RawNode.HasLazyChildren"/> so its folders + drivers load on first expand. Empty
|
|
/// clusters are retained so they stay visible and authorable. The returned nodes are detached
|
|
/// view-models, safe to hold and mutate UI state on after the underlying context is disposed.
|
|
/// </summary>
|
|
/// <param name="ct">A token to cancel the load.</param>
|
|
/// <returns>The enterprise roots, populated down to (but not through) their clusters.</returns>
|
|
Task<IReadOnlyList<RawNode>> LoadRootsAsync(CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Loads the direct children of one container node — the next level down, keyed off
|
|
/// <paramref name="parent"/>'s <see cref="RawNode.Kind"/> and <see cref="RawNode.EntityId"/>:
|
|
/// a Cluster yields its root Folders + Drivers; a Folder yields sub-Folders + Drivers; a Driver
|
|
/// yields its Devices; a Device yields its root TagGroups + Tags; a TagGroup yields sub-TagGroups
|
|
/// + Tags. Tags are leaves and yield nothing. Ordering is deterministic and ordinal. Reads
|
|
/// untracked; returns detached nodes. Per-device tag counts can be large — the implementation may
|
|
/// page, but the committed shape returns the level's nodes (paging knobs, if any, are WP1's to add
|
|
/// on the concrete type without changing this signature's meaning for the tree).
|
|
/// </summary>
|
|
/// <param name="parent">The container node whose direct children to load.</param>
|
|
/// <param name="ct">A token to cancel the load.</param>
|
|
/// <returns>The parent's direct child nodes; empty for a leaf or an empty container.</returns>
|
|
Task<IReadOnlyList<RawNode>> LoadChildrenAsync(RawNode parent, CancellationToken ct = default);
|
|
|
|
// --- Folder mutations ---
|
|
|
|
/// <summary>
|
|
/// Creates a new <c>RawFolder</c> under a cluster (<paramref name="parentFolderId"/> null) or under
|
|
/// another folder. The name is validated as a RawPath segment and must be unique among its siblings
|
|
/// (case-sensitive ordinal). On success the result's <c>CreatedId</c> carries the new folder's
|
|
/// logical id.
|
|
/// </summary>
|
|
/// <param name="clusterId">The owning cluster id.</param>
|
|
/// <param name="parentFolderId">The parent folder's logical id, or null for a cluster-root folder.</param>
|
|
/// <param name="name">The folder name (a RawPath segment).</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>The create outcome; <c>CreatedId</c> is the new <c>RawFolderId</c> on success.</returns>
|
|
Task<UnsMutationResult> CreateFolderAsync(string clusterId, string? parentFolderId, string name, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Renames a <c>RawFolder</c>. Validates the new name as a RawPath segment and sibling-unique.
|
|
/// Because a folder rename changes the RawPath of every tag beneath it, the returned
|
|
/// <see cref="RawRenameResult"/> carries advisory warnings for historized and equipment-referenced
|
|
/// tags in the folder's subtree.
|
|
/// </summary>
|
|
/// <param name="rawFolderId">The folder's logical id.</param>
|
|
/// <param name="newName">The new folder name.</param>
|
|
/// <param name="rowVersion">The optimistic-concurrency token echoed from the loaded node.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>The rename outcome with any downstream-impact warnings.</returns>
|
|
Task<RawRenameResult> RenameFolderAsync(string rawFolderId, string newName, byte[] rowVersion, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Deletes an empty <c>RawFolder</c>. Blocked (with the blocker named) while it still contains child
|
|
/// folders or driver instances.
|
|
/// </summary>
|
|
/// <param name="rawFolderId">The folder's logical id.</param>
|
|
/// <param name="rowVersion">The optimistic-concurrency token echoed from the loaded node.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>The delete outcome.</returns>
|
|
Task<UnsMutationResult> DeleteFolderAsync(string rawFolderId, byte[] rowVersion, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Moves a driver instance into a folder (<paramref name="targetFolderId"/>) or to the cluster root
|
|
/// (null target). The target folder must be in the driver's cluster and the driver's name must be
|
|
/// unique among the target's driver siblings.
|
|
/// </summary>
|
|
/// <param name="driverInstanceId">The driver instance's logical id.</param>
|
|
/// <param name="targetFolderId">The destination folder's logical id, or null for the cluster root.</param>
|
|
/// <param name="rowVersion">The optimistic-concurrency token echoed from the loaded node.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>The move outcome.</returns>
|
|
Task<UnsMutationResult> MoveDriverToFolderAsync(string driverInstanceId, string? targetFolderId, byte[] rowVersion, CancellationToken ct = default);
|
|
|
|
// --- Driver mutations ---
|
|
|
|
/// <summary>
|
|
/// Creates a minimal driver instance and its auto-created default <c>Device</c> so the tree has a
|
|
/// child to show. Full typed driver/device config authoring is Wave B (WP3) — this create takes the
|
|
/// driver config JSON verbatim and seeds an empty (<c>{}</c>) default device. The driver name is a
|
|
/// RawPath segment, unique among its cluster/folder siblings.
|
|
/// </summary>
|
|
/// <param name="clusterId">The owning cluster id.</param>
|
|
/// <param name="folderId">The containing folder's logical id, or null for a cluster-root driver.</param>
|
|
/// <param name="name">The driver instance name (a RawPath segment).</param>
|
|
/// <param name="driverType">The driver-type string (see <c>DriverTypeNames</c>).</param>
|
|
/// <param name="driverConfigJson">The driver config JSON blob (opaque here; validated in Wave B).</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>The create outcome; <c>CreatedId</c> is the new <c>DriverInstanceId</c> on success.</returns>
|
|
Task<UnsMutationResult> CreateDriverAsync(string clusterId, string? folderId, string name, string driverType, string driverConfigJson, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Renames a driver instance. Validates the new name as a sibling-unique RawPath segment and returns
|
|
/// downstream-impact warnings for historized/equipment-referenced tags beneath the driver.
|
|
/// </summary>
|
|
/// <param name="driverInstanceId">The driver instance's logical id.</param>
|
|
/// <param name="newName">The new driver name.</param>
|
|
/// <param name="rowVersion">The optimistic-concurrency token echoed from the loaded node.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>The rename outcome with any downstream-impact warnings.</returns>
|
|
Task<RawRenameResult> RenameDriverAsync(string driverInstanceId, string newName, byte[] rowVersion, CancellationToken ct = default);
|
|
|
|
/// <summary>Enables or disables a driver instance (last-write-wins on <paramref name="rowVersion"/>).</summary>
|
|
/// <param name="driverInstanceId">The driver instance's logical id.</param>
|
|
/// <param name="enabled">The new enabled state.</param>
|
|
/// <param name="rowVersion">The optimistic-concurrency token echoed from the loaded node.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>The update outcome.</returns>
|
|
Task<UnsMutationResult> SetDriverEnabledAsync(string driverInstanceId, bool enabled, byte[] rowVersion, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Deletes a driver instance, cascading its auto-created empty devices. Blocked (with the blocking
|
|
/// device named) when any of its devices still contains tag groups or tags — remove those first.
|
|
/// </summary>
|
|
/// <param name="driverInstanceId">The driver instance's logical id.</param>
|
|
/// <param name="rowVersion">The optimistic-concurrency token echoed from the loaded node.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>The delete outcome.</returns>
|
|
Task<UnsMutationResult> DeleteDriverAsync(string driverInstanceId, byte[] rowVersion, CancellationToken ct = default);
|
|
|
|
// --- Device mutations ---
|
|
|
|
/// <summary>
|
|
/// Creates a minimal <c>Device</c> under a driver. Full typed device-config authoring is Wave B
|
|
/// (WP3) — this create takes the device config JSON verbatim. The device name must be unique among
|
|
/// the driver's devices.
|
|
/// </summary>
|
|
/// <param name="driverInstanceId">The owning driver instance's logical id.</param>
|
|
/// <param name="name">The device name (a RawPath segment).</param>
|
|
/// <param name="deviceConfigJson">The device config JSON blob (opaque here; validated in Wave B).</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>The create outcome; <c>CreatedId</c> is the new <c>DeviceId</c> on success.</returns>
|
|
Task<UnsMutationResult> CreateDeviceAsync(string driverInstanceId, string name, string deviceConfigJson, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Renames a <c>Device</c>. Validates the new name as a driver-unique RawPath segment and returns
|
|
/// downstream-impact warnings for historized/equipment-referenced tags beneath the device.
|
|
/// </summary>
|
|
/// <param name="deviceId">The device's logical id.</param>
|
|
/// <param name="newName">The new device name.</param>
|
|
/// <param name="rowVersion">The optimistic-concurrency token echoed from the loaded node.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>The rename outcome with any downstream-impact warnings.</returns>
|
|
Task<RawRenameResult> RenameDeviceAsync(string deviceId, string newName, byte[] rowVersion, CancellationToken ct = default);
|
|
|
|
/// <summary>Deletes a <c>Device</c>. Blocked (with the blocker named) while it holds tag groups or tags.</summary>
|
|
/// <param name="deviceId">The device's logical id.</param>
|
|
/// <param name="rowVersion">The optimistic-concurrency token echoed from the loaded node.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>The delete outcome.</returns>
|
|
Task<UnsMutationResult> DeleteDeviceAsync(string deviceId, byte[] rowVersion, CancellationToken ct = default);
|
|
|
|
// --- TagGroup mutations ---
|
|
|
|
/// <summary>
|
|
/// Creates a new <c>TagGroup</c> under a device (<paramref name="parentGroupId"/> null) or under
|
|
/// another group. The name is validated as a RawPath segment, unique among its siblings.
|
|
/// </summary>
|
|
/// <param name="deviceId">The owning device's logical id.</param>
|
|
/// <param name="parentGroupId">The parent group's logical id, or null for a device-root group.</param>
|
|
/// <param name="name">The group name (a RawPath segment).</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>The create outcome; <c>CreatedId</c> is the new <c>TagGroupId</c> on success.</returns>
|
|
Task<UnsMutationResult> CreateTagGroupAsync(string deviceId, string? parentGroupId, string name, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Renames a <c>TagGroup</c>. Validates the new name as a sibling-unique RawPath segment and returns
|
|
/// downstream-impact warnings for historized/equipment-referenced tags beneath the group.
|
|
/// </summary>
|
|
/// <param name="tagGroupId">The group's logical id.</param>
|
|
/// <param name="newName">The new group name.</param>
|
|
/// <param name="rowVersion">The optimistic-concurrency token echoed from the loaded node.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>The rename outcome with any downstream-impact warnings.</returns>
|
|
Task<RawRenameResult> RenameTagGroupAsync(string tagGroupId, string newName, byte[] rowVersion, CancellationToken ct = default);
|
|
|
|
/// <summary>Deletes a <c>TagGroup</c>. Blocked (with the blocker named) while it holds child groups or tags.</summary>
|
|
/// <param name="tagGroupId">The group's logical id.</param>
|
|
/// <param name="rowVersion">The optimistic-concurrency token echoed from the loaded node.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>The delete outcome.</returns>
|
|
Task<UnsMutationResult> DeleteTagGroupAsync(string tagGroupId, byte[] rowVersion, CancellationToken ct = default);
|
|
|
|
// --- Tag mutations / projections (create + update are WP4) ---
|
|
|
|
/// <summary>
|
|
/// Deletes a raw <c>Tag</c>. Blocked while any <c>UnsTagReference</c> points at it; the failure
|
|
/// message names the referencing equipment(s) so the operator can remove the reference(s) first.
|
|
/// </summary>
|
|
/// <param name="tagId">The tag's logical id.</param>
|
|
/// <param name="rowVersion">The optimistic-concurrency token echoed from the loaded node.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>The delete outcome.</returns>
|
|
Task<UnsMutationResult> DeleteTagAsync(string tagId, byte[] rowVersion, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Loads a raw tag's editable fields as a detached projection. WP1 provides the read-only projection;
|
|
/// the create/update authoring surface is WP4 (which should align its input shape with
|
|
/// <see cref="RawTagEditDto"/>).
|
|
/// </summary>
|
|
/// <param name="tagId">The tag's logical id.</param>
|
|
/// <param name="ct">A token to cancel the load.</param>
|
|
/// <returns>The tag's editable projection, or null when the tag does not exist.</returns>
|
|
Task<RawTagEditDto?> LoadTagForEditAsync(string tagId, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Creates a raw <c>Tag</c> under a device (<paramref name="tagGroupId"/> null) or a tag group. The
|
|
/// name is validated as a RawPath segment and must be unique among its siblings on the same
|
|
/// <c>(DeviceId, TagGroupId)</c>; the <see cref="RawTagInput.TagConfig"/> is validated for JSON
|
|
/// well-formedness. On success the result's <c>CreatedId</c> carries the new tag's logical id.
|
|
/// </summary>
|
|
/// <param name="deviceId">The owning device's logical id.</param>
|
|
/// <param name="tagGroupId">The containing tag group's logical id, or null for a device-root tag.</param>
|
|
/// <param name="input">The tag's editable fields (identity is the RawPath — no TagId here).</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>The create outcome; <c>CreatedId</c> is the new <c>TagId</c> on success.</returns>
|
|
Task<UnsMutationResult> CreateTagAsync(string deviceId, string? tagGroupId, RawTagInput input, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Updates a raw <c>Tag</c>'s editable fields. The new name is re-validated as a RawPath segment and
|
|
/// sibling-unique on the tag's existing <c>(DeviceId, TagGroupId)</c> excluding itself; the
|
|
/// <see cref="RawTagInput.TagConfig"/> is validated for JSON well-formedness. Last-write-wins on
|
|
/// <paramref name="rowVersion"/>. The tag's <c>DeviceId</c>/<c>TagGroupId</c> (its identity location)
|
|
/// are preserved — moving a tag is not this method's job.
|
|
/// </summary>
|
|
/// <param name="tagId">The tag's logical id.</param>
|
|
/// <param name="input">The tag's edited fields.</param>
|
|
/// <param name="rowVersion">The optimistic-concurrency token echoed from the loaded tag.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>The update outcome.</returns>
|
|
Task<UnsMutationResult> UpdateTagAsync(string tagId, RawTagInput input, byte[] rowVersion, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Commits a batch of raw tags under a device — the WP5 CSV-import path. Each row's
|
|
/// <c>TagGroupPath</c> is a <c>/</c>-separated tag-group path under the device whose segments are
|
|
/// auto-created as nested <c>TagGroup</c>s (reusing existing ones). Per-row validation errors (bad
|
|
/// name segment, malformed <c>TagConfig</c> JSON, a duplicate name within the device+group) are
|
|
/// collected, not thrown. The import is <b>all-or-nothing</b>: if any row errors, nothing is inserted
|
|
/// and the errors are returned; otherwise all tags (and any newly-needed groups) are committed in one
|
|
/// <c>SaveChanges</c>.
|
|
/// </summary>
|
|
/// <param name="deviceId">The target device's logical id.</param>
|
|
/// <param name="rows">The rows to import.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>The import outcome: the inserted count on success, or the per-row errors with a 0 count.</returns>
|
|
Task<RawTagImportResult> ImportTagsAsync(string deviceId, IReadOnlyList<RawTagImportRow> rows, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Loads a driver instance's editable fields as a detached projection for the WP3 "Configure driver"
|
|
/// modal. <c>DriverType</c> is included for typed-editor dispatch (it is immutable).
|
|
/// </summary>
|
|
/// <param name="driverInstanceId">The driver instance's logical id.</param>
|
|
/// <param name="ct">A token to cancel the load.</param>
|
|
/// <returns>The driver's editable projection, or null when it does not exist.</returns>
|
|
Task<RawDriverEditDto?> LoadDriverForEditAsync(string driverInstanceId, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Updates a driver instance's name + config from the WP3 "Configure driver" modal. The name is
|
|
/// validated as a sibling-unique RawPath segment (same scope as <see cref="RenameDriverAsync"/>);
|
|
/// last-write-wins on <paramref name="rowVersion"/>. <c>DriverType</c> is immutable and is not changed.
|
|
/// </summary>
|
|
/// <param name="driverInstanceId">The driver instance's logical id.</param>
|
|
/// <param name="name">The (possibly changed) driver name.</param>
|
|
/// <param name="driverConfigJson">The new <c>DriverConfig</c> JSON blob.</param>
|
|
/// <param name="resilienceConfig">The new resilience-config JSON, or null/blank to clear.</param>
|
|
/// <param name="rowVersion">The optimistic-concurrency token echoed from the loaded projection.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>The update outcome.</returns>
|
|
Task<UnsMutationResult> UpdateDriverAsync(string driverInstanceId, string name, string driverConfigJson, string? resilienceConfig, byte[] rowVersion, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Loads a device's editable fields as a detached projection for the WP3 "Configure device" modal.
|
|
/// <c>DriverType</c> is joined in from the parent driver so the modal can dispatch to the correct typed
|
|
/// device-config editor.
|
|
/// </summary>
|
|
/// <param name="deviceId">The device's logical id.</param>
|
|
/// <param name="ct">A token to cancel the load.</param>
|
|
/// <returns>The device's editable projection, or null when it does not exist.</returns>
|
|
Task<RawDeviceEditDto?> LoadDeviceForEditAsync(string deviceId, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Updates a device's name + config + enabled state from the WP3 "Configure device" modal. The name
|
|
/// is validated as a RawPath segment unique among the driver's devices; last-write-wins on
|
|
/// <paramref name="rowVersion"/>.
|
|
/// </summary>
|
|
/// <param name="deviceId">The device's logical id.</param>
|
|
/// <param name="name">The (possibly changed) device name.</param>
|
|
/// <param name="deviceConfigJson">The new <c>DeviceConfig</c> JSON blob (endpoint + per-device settings).</param>
|
|
/// <param name="enabled">The new enabled state.</param>
|
|
/// <param name="rowVersion">The optimistic-concurrency token echoed from the loaded projection.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>The update outcome.</returns>
|
|
Task<UnsMutationResult> UpdateDeviceAsync(string deviceId, string name, string deviceConfigJson, bool enabled, byte[] rowVersion, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Builds the single merged config blob the driver-probe (test-connect) path binds from for one device:
|
|
/// the parent driver's <c>DriverConfig</c> folded together with this device's <c>DeviceConfig</c> (via
|
|
/// <c>DriverDeviceConfigMerger</c>, endpoint keys merging up from <c>DeviceConfig</c>). Used by the
|
|
/// "Test connect" button inside the WP3 driver/device modals now that the endpoint lives in
|
|
/// <c>DeviceConfig</c>.
|
|
/// </summary>
|
|
/// <param name="deviceId">The device to probe.</param>
|
|
/// <param name="ct">A token to cancel the load.</param>
|
|
/// <returns>The parent driver's type + the merged config JSON, or null when the device/driver cannot be resolved.</returns>
|
|
Task<(string DriverType, string MergedConfigJson)?> LoadMergedProbeConfigAsync(string deviceId, CancellationToken ct = default);
|
|
}
|