feat(adminui): B2 Wave-B service prelude — tag CRUD/import + driver/device config + merged probe
Claude-Session: https://claude.ai/code/session_01LVneM3eh1UtJxEisFXgmox
This commit is contained in:
@@ -29,6 +29,48 @@ public readonly record struct RawTagEditDto(
|
||||
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
|
||||
@@ -251,4 +293,105 @@ public interface IRawTreeService
|
||||
/// <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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user