523 lines
34 KiB
C#
523 lines
34 KiB
C#
using ZB.MOM.WW.OtOpcUa.Configuration.Enums;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Uns;
|
|
|
|
/// <summary>
|
|
/// A UNS area projected for editing: its operator-editable fields plus the owning cluster and
|
|
/// the concurrency token the edit modal must echo back on save.
|
|
/// </summary>
|
|
/// <param name="UnsAreaId">The area's stable id (read-only on edit).</param>
|
|
/// <param name="Name">The area name.</param>
|
|
/// <param name="Notes">Optional notes; <c>null</c> when unset.</param>
|
|
/// <param name="ClusterId">The owning cluster id (the served-by selection).</param>
|
|
/// <param name="RowVersion">The optimistic-concurrency token last read.</param>
|
|
public sealed record AreaEditDto(string UnsAreaId, string Name, string? Notes, string ClusterId, byte[] RowVersion);
|
|
|
|
/// <summary>
|
|
/// A UNS line projected for editing: its operator-editable fields plus the parent area and the
|
|
/// concurrency token the edit modal must echo back on save.
|
|
/// </summary>
|
|
/// <param name="UnsLineId">The line's stable id (read-only on edit).</param>
|
|
/// <param name="UnsAreaId">The owning area id (the parent-area selection).</param>
|
|
/// <param name="Name">The line name.</param>
|
|
/// <param name="Notes">Optional notes; <c>null</c> when unset.</param>
|
|
/// <param name="RowVersion">The optimistic-concurrency token last read.</param>
|
|
public sealed record LineEditDto(string UnsLineId, string UnsAreaId, string Name, string? Notes, byte[] RowVersion);
|
|
|
|
/// <summary>
|
|
/// An equipment projected for editing: its system-generated id, the operator-editable identity and
|
|
/// OPC 40010 identification fields, plus the concurrency token the edit modal must echo back on save.
|
|
/// </summary>
|
|
/// <param name="EquipmentId">The system-generated stable id (read-only — never operator-edited, decision #125).</param>
|
|
/// <param name="Name">UNS level-5 segment name.</param>
|
|
/// <param name="MachineCode">Operator colloquial id; unique fleet-wide.</param>
|
|
/// <param name="UnsLineId">The owning line id (the UNS-line selection).</param>
|
|
/// <param name="DriverInstanceId">Optional driver binding; <c>null</c> when driver-less.</param>
|
|
/// <param name="ZTag">Optional ERP equipment id.</param>
|
|
/// <param name="SAPID">Optional SAP PM equipment id.</param>
|
|
/// <param name="Manufacturer">Optional OPC 40010 manufacturer name.</param>
|
|
/// <param name="Model">Optional OPC 40010 model designation.</param>
|
|
/// <param name="SerialNumber">Optional OPC 40010 serial number.</param>
|
|
/// <param name="HardwareRevision">Optional OPC 40010 hardware revision.</param>
|
|
/// <param name="SoftwareRevision">Optional OPC 40010 software revision.</param>
|
|
/// <param name="YearOfConstruction">Optional OPC 40010 year of construction.</param>
|
|
/// <param name="AssetLocation">Optional OPC 40010 asset location.</param>
|
|
/// <param name="ManufacturerUri">Optional OPC 40010 manufacturer URI.</param>
|
|
/// <param name="DeviceManualUri">Optional OPC 40010 device-manual URI.</param>
|
|
/// <param name="Enabled">Whether the equipment is surfaced in deployments.</param>
|
|
/// <param name="RowVersion">The optimistic-concurrency token last read.</param>
|
|
public sealed record EquipmentEditDto(string EquipmentId, string Name, string MachineCode, string UnsLineId,
|
|
string? DriverInstanceId, string? ZTag, string? SAPID, string? Manufacturer, string? Model, string? SerialNumber,
|
|
string? HardwareRevision, string? SoftwareRevision, short? YearOfConstruction, string? AssetLocation,
|
|
string? ManufacturerUri, string? DeviceManualUri, bool Enabled, byte[] RowVersion);
|
|
|
|
/// <summary>
|
|
/// An equipment-bound tag projected for editing: its operator-editable fields, the owning equipment
|
|
/// (so the host can scope the candidate-driver list and refresh the right node), plus the concurrency
|
|
/// token the edit modal must echo back on save. Tree tags are always equipment-bound (decision #110),
|
|
/// so <c>FolderPath</c> never surfaces here.
|
|
/// </summary>
|
|
/// <param name="TagId">The tag's stable id (read-only on edit).</param>
|
|
/// <param name="EquipmentId">The owning equipment id.</param>
|
|
/// <param name="Name">The tag name.</param>
|
|
/// <param name="DriverInstanceId">The bound driver id.</param>
|
|
/// <param name="DataType">The OPC UA built-in type name.</param>
|
|
/// <param name="AccessLevel">The tag-level access baseline.</param>
|
|
/// <param name="WriteIdempotent">Whether writes are safe to retry.</param>
|
|
/// <param name="PollGroupId">Optional poll-group key; <c>null</c> when unset.</param>
|
|
/// <param name="TagConfig">The schemaless per-driver-type JSON config.</param>
|
|
/// <param name="RowVersion">The optimistic-concurrency token last read.</param>
|
|
public sealed record TagEditDto(string TagId, string EquipmentId, string Name, string DriverInstanceId, string DataType,
|
|
TagAccessLevel AccessLevel, bool WriteIdempotent, string? PollGroupId, string TagConfig, byte[] RowVersion);
|
|
|
|
/// <summary>
|
|
/// An equipment-bound virtual tag projected for editing: its operator-editable fields, the owning
|
|
/// equipment (so the host can refresh the right node), plus the concurrency token the edit modal must
|
|
/// echo back on save. Virtual tags are always scoped to an equipment (plan decision #2), so the modal
|
|
/// never offers an equipment-change control.
|
|
/// </summary>
|
|
/// <param name="VirtualTagId">The virtual tag's stable id (read-only on edit).</param>
|
|
/// <param name="EquipmentId">The owning equipment id.</param>
|
|
/// <param name="Name">The virtual-tag name.</param>
|
|
/// <param name="DataType">The OPC UA built-in type name.</param>
|
|
/// <param name="ScriptId">The bound script id.</param>
|
|
/// <param name="ChangeTriggered">Whether the tag re-evaluates on dependency change.</param>
|
|
/// <param name="TimerIntervalMs">Optional periodic re-evaluation cadence in ms; <c>null</c> when unset.</param>
|
|
/// <param name="Historize">Whether the tag's values are historized.</param>
|
|
/// <param name="Enabled">Whether the tag is spawned in deployments.</param>
|
|
/// <param name="RowVersion">The optimistic-concurrency token last read.</param>
|
|
public sealed record VirtualTagEditDto(string VirtualTagId, string EquipmentId, string Name, string DataType, string ScriptId,
|
|
bool ChangeTriggered, int? TimerIntervalMs, bool Historize, bool Enabled, byte[] RowVersion);
|
|
|
|
/// <summary>
|
|
/// The outcome of a bulk equipment CSV import: how many rows were inserted, how many were skipped
|
|
/// (existing MachineCode — the importer is additive-only, never an update), and a per-row error list
|
|
/// for rows that could not be inserted (unknown line, unknown driver, or a decision-#122 cluster
|
|
/// mismatch). Skipped rows never appear in <see cref="Errors"/>.
|
|
/// </summary>
|
|
/// <param name="Inserted">The count of new Equipment rows added.</param>
|
|
/// <param name="Skipped">The count of rows skipped because their MachineCode already exists.</param>
|
|
/// <param name="Errors">The human-readable error strings for rows that failed validation.</param>
|
|
public sealed record EquipmentImportResult(int Inserted, int Skipped, IReadOnlyList<string> Errors);
|
|
|
|
/// <summary>
|
|
/// Loads the structural portion of the unified-namespace (UNS) browse tree —
|
|
/// Enterprise → Cluster → Area → Line → Equipment — from the config database.
|
|
/// Equipment is a leaf in the tree; its tags and virtual tags are accessed via the
|
|
/// equipment detail page, not via lazy tree expansion.
|
|
/// </summary>
|
|
public interface IUnsTreeService
|
|
{
|
|
/// <summary>
|
|
/// Loads the full structural tree. Empty clusters are retained so they remain
|
|
/// visible and editable. 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 root nodes, each populated down to equipment.</returns>
|
|
Task<IReadOnlyList<UnsNode>> LoadStructureAsync(CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Loads the driver tags bound to a single equipment as flat row projections for the equipment
|
|
/// page's Tags tab table, ordered by Name. Each row carries the display columns plus the
|
|
/// <c>TagId</c> the table uses to open the edit modal. Reads untracked. Returns an empty list when
|
|
/// the equipment has no tags.
|
|
/// </summary>
|
|
/// <param name="equipmentId">The equipment whose tags to load.</param>
|
|
/// <param name="ct">A token to cancel the load.</param>
|
|
/// <returns>The equipment's tag rows ordered by Name; empty if it has none.</returns>
|
|
Task<IReadOnlyList<EquipmentTagRow>> LoadTagsForEquipmentAsync(string equipmentId, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Loads the virtual tags scoped to a single equipment as flat row projections for the equipment
|
|
/// page's Virtual Tags tab table, ordered by Name. Each row carries the display columns plus the
|
|
/// <c>VirtualTagId</c> the table uses to open the edit modal. Reads untracked. Returns an empty list
|
|
/// when the equipment has no virtual tags.
|
|
/// </summary>
|
|
/// <param name="equipmentId">The equipment whose virtual tags to load.</param>
|
|
/// <param name="ct">A token to cancel the load.</param>
|
|
/// <returns>The equipment's virtual-tag rows ordered by Name; empty if it has none.</returns>
|
|
Task<IReadOnlyList<EquipmentVirtualTagRow>> LoadVirtualTagsForEquipmentAsync(string equipmentId, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Loads a single UNS area projected for editing, or <c>null</c> if it no longer exists.
|
|
/// Reads untracked and captures the current concurrency token for last-write-wins saves.
|
|
/// </summary>
|
|
/// <param name="unsAreaId">The area to load.</param>
|
|
/// <param name="ct">A token to cancel the load.</param>
|
|
/// <returns>The area's edit projection, or <c>null</c> when missing.</returns>
|
|
Task<AreaEditDto?> LoadAreaAsync(string unsAreaId, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Loads a single UNS line projected for editing, or <c>null</c> if it no longer exists.
|
|
/// Reads untracked and captures the current concurrency token for last-write-wins saves.
|
|
/// </summary>
|
|
/// <param name="unsLineId">The line to load.</param>
|
|
/// <param name="ct">A token to cancel the load.</param>
|
|
/// <returns>The line's edit projection, or <c>null</c> when missing.</returns>
|
|
Task<LineEditDto?> LoadLineAsync(string unsLineId, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Loads a single equipment projected for editing, or <c>null</c> if it no longer exists.
|
|
/// Reads untracked and captures the current concurrency token for last-write-wins saves.
|
|
/// </summary>
|
|
/// <param name="equipmentId">The equipment to load.</param>
|
|
/// <param name="ct">A token to cancel the load.</param>
|
|
/// <returns>The equipment's edit projection, or <c>null</c> when missing.</returns>
|
|
Task<EquipmentEditDto?> LoadEquipmentAsync(string equipmentId, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Loads a single equipment-bound tag projected for editing, or <c>null</c> if it no longer exists.
|
|
/// Reads untracked and captures the current concurrency token for last-write-wins saves.
|
|
/// </summary>
|
|
/// <param name="tagId">The tag to load.</param>
|
|
/// <param name="ct">A token to cancel the load.</param>
|
|
/// <returns>The tag's edit projection, or <c>null</c> when missing.</returns>
|
|
Task<TagEditDto?> LoadTagAsync(string tagId, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Loads a single equipment-bound virtual tag projected for editing, or <c>null</c> if it no longer
|
|
/// exists. Reads untracked and captures the current concurrency token for last-write-wins saves.
|
|
/// </summary>
|
|
/// <param name="virtualTagId">The virtual tag to load.</param>
|
|
/// <param name="ct">A token to cancel the load.</param>
|
|
/// <returns>The virtual tag's edit projection, or <c>null</c> when missing.</returns>
|
|
Task<VirtualTagEditDto?> LoadVirtualTagAsync(string virtualTagId, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Loads every driver instance in a cluster (regardless of namespace kind) so the equipment modal
|
|
/// can offer the full cluster driver list for binding. Ordered by <c>DriverInstanceId</c>. Each is
|
|
/// projected to a <c>(DriverInstanceId, Display)</c> pair where <c>Display</c> is
|
|
/// <c>"{DriverInstanceId} — {Name} ({DriverType})"</c>.
|
|
/// </summary>
|
|
/// <param name="clusterId">The cluster whose drivers to load.</param>
|
|
/// <param name="ct">A token to cancel the load.</param>
|
|
/// <returns>The cluster's drivers projected to <c>(DriverInstanceId, Display)</c> pairs.</returns>
|
|
Task<IReadOnlyList<(string DriverInstanceId, string Display)>> LoadDriversForClusterAsync(string clusterId, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Loads the UNS-line and driver <c>(Id, Display)</c> option lists the equipment page's Details tab
|
|
/// offers, scoped to the cluster that owns the supplied line: every line in that cluster (for the
|
|
/// line picker) and that cluster's drivers (reusing <see cref="LoadDriversForClusterAsync"/>).
|
|
/// Centralizes the resolution the page would otherwise need the loaded tree to perform. Returns
|
|
/// empty lists when <paramref name="lineId"/> is null/empty or cannot be resolved to a cluster.
|
|
/// </summary>
|
|
/// <param name="lineId">The line whose owning cluster scopes the option lists; null/empty yields empties.</param>
|
|
/// <param name="ct">A token to cancel the load.</param>
|
|
/// <returns>The cluster-scoped line and driver options, or empty lists when the line can't be resolved.</returns>
|
|
Task<EquipmentPickContext> LoadEquipmentPickContextAsync(string? lineId, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Creates a new UNS area under a cluster. Fails if an area with the same id already exists.
|
|
/// Whitespace-only notes are stored as <c>null</c>.
|
|
/// </summary>
|
|
/// <param name="clusterId">The owning cluster.</param>
|
|
/// <param name="unsAreaId">The unique area id to create.</param>
|
|
/// <param name="name">The area name.</param>
|
|
/// <param name="notes">Optional notes; whitespace collapses to <c>null</c>.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>Success, or a duplicate-id failure.</returns>
|
|
Task<UnsMutationResult> CreateAreaAsync(string clusterId, string unsAreaId, string name, string? notes, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Updates a UNS area's name, notes, and owning cluster. When the cluster changes, the
|
|
/// decision-#122 reassignment guard blocks the move if any driver-bound equipment under the
|
|
/// area is bound to a driver in a different cluster than the target. Uses last-write-wins
|
|
/// optimistic concurrency on <see cref="Configuration.Entities.UnsArea.RowVersion"/>.
|
|
/// </summary>
|
|
/// <param name="unsAreaId">The area to update.</param>
|
|
/// <param name="name">The new name.</param>
|
|
/// <param name="notes">The new notes; whitespace collapses to <c>null</c>.</param>
|
|
/// <param name="newClusterId">The target cluster (may equal the current one).</param>
|
|
/// <param name="rowVersion">The concurrency token the caller last read.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>Success, a missing-row failure, a #122 guard failure, or a concurrency failure.</returns>
|
|
Task<UnsMutationResult> UpdateAreaAsync(string unsAreaId, string name, string? notes, string newClusterId, byte[] rowVersion, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Deletes a UNS area. A missing row is treated as success (already gone). Uses last-write-wins
|
|
/// optimistic concurrency; a delete that fails because lines still reference the area surfaces a
|
|
/// guidance message.
|
|
/// </summary>
|
|
/// <param name="unsAreaId">The area to delete.</param>
|
|
/// <param name="rowVersion">The concurrency token the caller last read.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>Success, a concurrency failure, or a delete-failed failure.</returns>
|
|
Task<UnsMutationResult> DeleteAreaAsync(string unsAreaId, byte[] rowVersion, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Creates a new UNS line under an area. Fails if a line with the same id already exists.
|
|
/// Whitespace-only notes are stored as <c>null</c>.
|
|
/// </summary>
|
|
/// <param name="unsAreaId">The owning area.</param>
|
|
/// <param name="unsLineId">The unique line id to create.</param>
|
|
/// <param name="name">The line name.</param>
|
|
/// <param name="notes">Optional notes; whitespace collapses to <c>null</c>.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>Success, or a duplicate-id failure.</returns>
|
|
Task<UnsMutationResult> CreateLineAsync(string unsAreaId, string unsLineId, string name, string? notes, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Updates a UNS line's owning area, name, and notes. Uses last-write-wins optimistic
|
|
/// concurrency on <see cref="Configuration.Entities.UnsLine.RowVersion"/>.
|
|
/// </summary>
|
|
/// <param name="unsLineId">The line to update.</param>
|
|
/// <param name="name">The new name.</param>
|
|
/// <param name="notes">The new notes; whitespace collapses to <c>null</c>.</param>
|
|
/// <param name="newUnsAreaId">The target parent area.</param>
|
|
/// <param name="rowVersion">The concurrency token the caller last read.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>Success, a missing-row failure, or a concurrency failure.</returns>
|
|
Task<UnsMutationResult> UpdateLineAsync(string unsLineId, string name, string? notes, string newUnsAreaId, byte[] rowVersion, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Deletes a UNS line. A missing row is treated as success (already gone). Uses last-write-wins
|
|
/// optimistic concurrency; a delete that fails because equipment still references the line
|
|
/// surfaces a guidance message.
|
|
/// </summary>
|
|
/// <param name="unsLineId">The line to delete.</param>
|
|
/// <param name="rowVersion">The concurrency token the caller last read.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>Success, a concurrency failure, or a delete-failed failure.</returns>
|
|
Task<UnsMutationResult> DeleteLineAsync(string unsLineId, byte[] rowVersion, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Creates a new equipment under a UNS line. The <c>EquipmentId</c> is system-generated
|
|
/// (decision #125: <c>EQ-</c> + the first 12 hex chars of a fresh <c>EquipmentUuid</c>).
|
|
/// Fails if the line is unset, if the MachineCode is already used fleet-wide, or if the
|
|
/// decision-#122 driver-cluster guard trips. Whitespace-only DriverInstanceId/ZTag/SAPID
|
|
/// collapse to <c>null</c>.
|
|
/// </summary>
|
|
/// <param name="input">The operator-editable equipment fields.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>Success, a missing-line failure, a duplicate-MachineCode failure, or a #122 guard failure.</returns>
|
|
Task<UnsMutationResult> CreateEquipmentAsync(EquipmentInput input, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Bulk-imports equipment from a parsed set of <see cref="EquipmentInput"/> rows in a single
|
|
/// context, applying the same rules as the single-add path: a row whose <c>UnsLineId</c> does not
|
|
/// exist is an error; a row whose <c>DriverInstanceId</c> is set but does not resolve is an error;
|
|
/// a driver-bound row whose driver is in a different cluster than its line fails the decision-#122
|
|
/// guard; and a row whose <c>MachineCode</c> already exists in the DB <em>or</em> earlier in the
|
|
/// same batch is silently skipped (additive-only — never an update). Inserted rows get a
|
|
/// system-generated <c>EQ-</c> id and a fresh <c>EquipmentUuid</c>. All inserts are saved once at
|
|
/// the end.
|
|
/// </summary>
|
|
/// <param name="rows">The parsed equipment rows to import.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>The insert/skip counts and the per-row error list.</returns>
|
|
Task<EquipmentImportResult> ImportEquipmentAsync(IReadOnlyList<EquipmentInput> rows, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Updates an equipment's mutable fields (driver binding, line, name, MachineCode, external
|
|
/// ids, and the OPC 40010 identification fields). The decision-#122 driver-cluster guard blocks
|
|
/// binding to a driver in a different cluster than the equipment's line. Uses last-write-wins
|
|
/// optimistic concurrency on <see cref="Configuration.Entities.Equipment.RowVersion"/>.
|
|
/// </summary>
|
|
/// <param name="equipmentId">The equipment to update.</param>
|
|
/// <param name="input">The new operator-editable equipment fields.</param>
|
|
/// <param name="rowVersion">The concurrency token the caller last read.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>Success, a missing-row failure, a #122 guard failure, or a concurrency failure.</returns>
|
|
Task<UnsMutationResult> UpdateEquipmentAsync(string equipmentId, EquipmentInput input, byte[] rowVersion, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Deletes an equipment. A missing row is treated as success (already gone). Uses last-write-wins
|
|
/// optimistic concurrency; a delete that fails because tags or virtual tags still reference the
|
|
/// equipment surfaces a guidance message.
|
|
/// </summary>
|
|
/// <param name="equipmentId">The equipment to delete.</param>
|
|
/// <param name="rowVersion">The concurrency token the caller last read.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>Success, a concurrency failure, or a delete-failed failure.</returns>
|
|
Task<UnsMutationResult> DeleteEquipmentAsync(string equipmentId, byte[] rowVersion, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Loads the drivers eligible to back a tag on the given equipment: drivers in the equipment's
|
|
/// cluster (<c>Equipment.UnsLine → UnsArea.ClusterId</c>) whose namespace is Equipment-kind
|
|
/// (decision #110 — tree tags are equipment-bound). Ordered by <c>DriverInstanceId</c>. Returns
|
|
/// an empty list when the equipment cannot be resolved to a cluster.
|
|
/// </summary>
|
|
/// <param name="equipmentId">The equipment whose candidate drivers to load.</param>
|
|
/// <param name="ct">A token to cancel the load.</param>
|
|
/// <returns>The eligible drivers projected to <c>(DriverInstanceId, Display, DriverType)</c> triples,
|
|
/// where <c>DriverType</c> lets the TagModal dispatch to a per-driver-type typed config editor.</returns>
|
|
Task<IReadOnlyList<(string DriverInstanceId, string Display, string DriverType)>> LoadTagDriversForEquipmentAsync(string equipmentId, CancellationToken ct = default);
|
|
|
|
/// <summary>Galaxy gateway driver instances (DriverType "GalaxyMxGateway") in the equipment's
|
|
/// cluster, for the alias address picker. Tuple = (DriverInstanceId, Display, DriverConfig).</summary>
|
|
Task<IReadOnlyList<(string DriverInstanceId, string Display, string DriverConfig)>>
|
|
LoadGalaxyGatewaysForEquipmentAsync(string equipmentId, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Creates a new equipment-bound tag. <c>FolderPath</c> is always <c>null</c> (decision #110 —
|
|
/// the tree only edits equipment-bound tags). Fails on a duplicate <c>TagId</c>, invalid
|
|
/// <c>TagConfig</c> JSON, an unknown driver, a driver whose namespace is not Equipment-kind, a
|
|
/// driver in a different cluster than the equipment (decision #122), or a name already used on
|
|
/// the equipment. Whitespace-only <c>PollGroupId</c> collapses to <c>null</c>.
|
|
/// </summary>
|
|
/// <param name="equipmentId">The owning equipment.</param>
|
|
/// <param name="input">The operator-editable tag fields.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>Success, or one of the guard failures.</returns>
|
|
Task<UnsMutationResult> CreateTagAsync(string equipmentId, TagInput input, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Updates an equipment-bound tag's driver binding, name, data type, access level, write-retry
|
|
/// flag, poll group, and config. The owning <c>EquipmentId</c> and the <c>null</c>
|
|
/// <c>FolderPath</c> are preserved. Re-runs the JSON-validity, namespace-kind, and decision-#122
|
|
/// cluster guards against the tag's existing equipment, and enforces name uniqueness on that
|
|
/// equipment excluding this tag. Uses last-write-wins optimistic concurrency on
|
|
/// <see cref="Configuration.Entities.Tag.RowVersion"/>.
|
|
/// </summary>
|
|
/// <param name="tagId">The tag to update.</param>
|
|
/// <param name="input">The new operator-editable tag fields.</param>
|
|
/// <param name="rowVersion">The concurrency token the caller last read.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>Success, a missing-row failure, a guard failure, or a concurrency failure.</returns>
|
|
Task<UnsMutationResult> UpdateTagAsync(string tagId, TagInput input, byte[] rowVersion, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Deletes a tag. A missing row is treated as success (already gone). Uses last-write-wins
|
|
/// optimistic concurrency on <see cref="Configuration.Entities.Tag.RowVersion"/>.
|
|
/// </summary>
|
|
/// <param name="tagId">The tag to delete.</param>
|
|
/// <param name="rowVersion">The concurrency token the caller last read.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>Success, a concurrency failure, or a delete-failed failure.</returns>
|
|
Task<UnsMutationResult> DeleteTagAsync(string tagId, byte[] rowVersion, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Loads the scripts eligible to back a virtual tag, ordered by name. Each is projected to a
|
|
/// <c>(ScriptId, Display)</c> pair where <c>Display</c> is <c>"{Name} ({Language})"</c>.
|
|
/// </summary>
|
|
/// <param name="ct">A token to cancel the load.</param>
|
|
/// <returns>The scripts projected to <c>(ScriptId, Display)</c> pairs.</returns>
|
|
Task<IReadOnlyList<(string ScriptId, string Display)>> LoadScriptsAsync(CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Creates a new equipment-bound virtual tag (plan decision #2 — virtual tags are always scoped
|
|
/// to an equipment). Fails if the equipment does not exist, if no script is chosen, if neither a
|
|
/// change trigger nor a timer is set, if the timer is below the 50 ms minimum, on a duplicate
|
|
/// <c>VirtualTagId</c>, or on a name already used on the equipment.
|
|
/// </summary>
|
|
/// <param name="equipmentId">The owning equipment.</param>
|
|
/// <param name="input">The operator-editable virtual-tag fields.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>Success, or one of the guard failures; or if the chosen script uses the <c>{{equip}}</c>
|
|
/// token but the equipment has no derivable single tag base.</returns>
|
|
Task<UnsMutationResult> CreateVirtualTagAsync(string equipmentId, VirtualTagInput input, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Updates an equipment-bound virtual tag's name, data type, script binding, triggers, historize,
|
|
/// and enabled flags. The owning <c>EquipmentId</c> is preserved. Re-runs the script-chosen,
|
|
/// change-or-timer, and 50 ms timer-minimum guards, and enforces name uniqueness on the tag's
|
|
/// existing equipment excluding this virtual tag. Uses last-write-wins optimistic concurrency on
|
|
/// <see cref="Configuration.Entities.VirtualTag.RowVersion"/>.
|
|
/// </summary>
|
|
/// <param name="virtualTagId">The virtual tag to update.</param>
|
|
/// <param name="input">The new operator-editable virtual-tag fields.</param>
|
|
/// <param name="rowVersion">The concurrency token the caller last read.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>Success, a missing-row failure, a guard failure, or a concurrency failure; or if the
|
|
/// chosen script uses the <c>{{equip}}</c> token but the equipment has no derivable single tag base.</returns>
|
|
Task<UnsMutationResult> UpdateVirtualTagAsync(string virtualTagId, VirtualTagInput input, byte[] rowVersion, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Deletes a virtual tag. A missing row is treated as success (already gone). Uses last-write-wins
|
|
/// optimistic concurrency on <see cref="Configuration.Entities.VirtualTag.RowVersion"/>.
|
|
/// </summary>
|
|
/// <param name="virtualTagId">The virtual tag to delete.</param>
|
|
/// <param name="rowVersion">The concurrency token the caller last read.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>Success, a concurrency failure, or a delete-failed failure.</returns>
|
|
Task<UnsMutationResult> DeleteVirtualTagAsync(string virtualTagId, byte[] rowVersion, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Loads a script's editable source for the inline script-source panel in the virtual-tag modal,
|
|
/// along with the concurrency token the panel must echo back on save and the script's display name.
|
|
/// Reads untracked. Returns <c>null</c> when the script no longer exists.
|
|
/// </summary>
|
|
/// <param name="scriptId">The script whose source to load.</param>
|
|
/// <param name="ct">A token to cancel the load.</param>
|
|
/// <returns>The <c>(SourceCode, RowVersion, Name)</c> triple, or <c>null</c> when missing.</returns>
|
|
Task<(string SourceCode, byte[] RowVersion, string Name)?> GetScriptSourceAsync(string scriptId, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Counts how many virtual tags bind the given script, so the inline editor can warn the operator
|
|
/// that an edit to a shared script affects every virtual tag using it.
|
|
/// </summary>
|
|
/// <param name="scriptId">The script to count usages of.</param>
|
|
/// <param name="ct">A token to cancel the query.</param>
|
|
/// <returns>The number of virtual tags whose <c>ScriptId</c> matches.</returns>
|
|
Task<int> CountVirtualTagsUsingScriptAsync(string scriptId, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Saves an edited script body from the inline panel: updates <c>SourceCode</c> and recomputes the
|
|
/// SHA-256 <c>SourceHash</c> (lower-case hex, matching the Script-edit page). This save is separate
|
|
/// from the virtual-tag save and is guarded by its own last-write-wins optimistic concurrency on
|
|
/// <see cref="Configuration.Entities.Script.RowVersion"/>.
|
|
/// </summary>
|
|
/// <param name="scriptId">The script to update.</param>
|
|
/// <param name="sourceCode">The new source body.</param>
|
|
/// <param name="rowVersion">The concurrency token the panel last read.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>Success, a missing-row failure, or a concurrency failure.</returns>
|
|
Task<(bool Ok, string? Error)> UpdateScriptSourceAsync(string scriptId, string sourceCode, byte[] rowVersion, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Loads the scripted alarms owned by a single equipment as flat row projections for the equipment
|
|
/// page's Alarms tab table, ordered by Name. Each row carries the display columns plus the
|
|
/// <c>ScriptedAlarmId</c> the table uses to open the edit modal. Reads untracked. Returns an empty
|
|
/// list when the equipment has no scripted alarms.
|
|
/// </summary>
|
|
/// <param name="equipmentId">The equipment whose scripted alarms to load.</param>
|
|
/// <param name="ct">A token to cancel the load.</param>
|
|
/// <returns>The equipment's scripted-alarm rows ordered by Name; empty if it has none.</returns>
|
|
Task<IReadOnlyList<EquipmentAlarmRow>> LoadAlarmsForEquipmentAsync(string equipmentId, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Loads a single scripted alarm projected for editing, or <c>null</c> if it no longer exists.
|
|
/// Reads untracked and captures the current concurrency token for last-write-wins saves.
|
|
/// </summary>
|
|
/// <param name="scriptedAlarmId">The scripted alarm to load.</param>
|
|
/// <param name="ct">A token to cancel the load.</param>
|
|
/// <returns>The scripted alarm's edit projection, or <c>null</c> when missing.</returns>
|
|
Task<ScriptedAlarmEditDto?> LoadScriptedAlarmAsync(string scriptedAlarmId, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Creates a new scripted alarm under an equipment. The <c>ScriptedAlarmId</c> is operator-typed
|
|
/// (not system-generated). Fails on a duplicate <c>ScriptedAlarmId</c>. Field validation (severity
|
|
/// range, required fields) is enforced client-side in the modal. On success the operator-typed id is
|
|
/// echoed back via <see cref="UnsMutationResult.CreatedId"/>.
|
|
/// </summary>
|
|
/// <param name="equipmentId">The owning equipment.</param>
|
|
/// <param name="input">The operator-editable scripted-alarm fields.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>Success carrying the created id, or a duplicate-id failure.</returns>
|
|
Task<UnsMutationResult> CreateScriptedAlarmAsync(string equipmentId, ScriptedAlarmInput input, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Updates a scripted alarm's mutable fields (name, alarm type, severity, message template,
|
|
/// predicate script, and the historize/retain/enabled flags). The owning <c>EquipmentId</c> is
|
|
/// preserved (the Alarms tab fixes it). Uses last-write-wins optimistic concurrency on
|
|
/// <see cref="Configuration.Entities.ScriptedAlarm.RowVersion"/>.
|
|
/// </summary>
|
|
/// <param name="scriptedAlarmId">The scripted alarm to update.</param>
|
|
/// <param name="input">The new operator-editable scripted-alarm fields.</param>
|
|
/// <param name="rowVersion">The concurrency token the caller last read.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>Success, a missing-row failure, or a concurrency failure.</returns>
|
|
Task<UnsMutationResult> UpdateScriptedAlarmAsync(string scriptedAlarmId, ScriptedAlarmInput input, byte[] rowVersion, CancellationToken ct = default);
|
|
|
|
/// <summary>
|
|
/// Deletes a scripted alarm. A missing row is treated as success (already gone). Uses last-write-wins
|
|
/// optimistic concurrency on <see cref="Configuration.Entities.ScriptedAlarm.RowVersion"/>.
|
|
/// </summary>
|
|
/// <param name="scriptedAlarmId">The scripted alarm to delete.</param>
|
|
/// <param name="rowVersion">The concurrency token the caller last read.</param>
|
|
/// <param name="ct">A token to cancel the operation.</param>
|
|
/// <returns>Success, a concurrency failure, or a delete-failed failure.</returns>
|
|
Task<UnsMutationResult> DeleteScriptedAlarmAsync(string scriptedAlarmId, byte[] rowVersion, CancellationToken ct = default);
|
|
}
|