docs: complete XML doc coverage (returns, summaries, inheritdoc)
Resolve all 622 issues flagged by the enhanced CommentChecker: add missing <returns> tags (incl. the standard phrasing on non-generic Task methods), add missing <summary> tags, and replace misused/redundant <inheritdoc/> on members that override or implement nothing with real documentation. Documentation-only — no behavior change; solution builds clean.
This commit is contained in:
@@ -61,6 +61,7 @@ public static class AuditExportEndpoints
|
||||
/// </summary>
|
||||
/// <param name="context">The HTTP context for the current request.</param>
|
||||
/// <param name="exportService">The export service used to stream audit rows as CSV.</param>
|
||||
/// <returns>A task representing the asynchronous export streaming operation.</returns>
|
||||
internal static async Task HandleExportAsync(HttpContext context, IAuditLogExportService exportService)
|
||||
{
|
||||
var filter = ParseFilter(context.Request.Query);
|
||||
@@ -94,6 +95,7 @@ public static class AuditExportEndpoints
|
||||
/// its own CLI / UI URL builder — so do NOT "fix" the two to one key name.
|
||||
/// </remarks>
|
||||
/// <param name="query">The query string parameters from the HTTP request.</param>
|
||||
/// <returns>An <see cref="AuditLogQueryFilter"/> populated from the query string values.</returns>
|
||||
internal static AuditLogQueryFilter ParseFilter(IQueryCollection query)
|
||||
{
|
||||
var channels = AuditQueryParamParsers.ParseEnumList<AuditChannel>(query["channel"]);
|
||||
|
||||
@@ -19,6 +19,7 @@ public static class AuthEndpoints
|
||||
{
|
||||
/// <summary>Registers the <c>/auth/login</c>, <c>/auth/logout</c>, and <c>/auth/ping</c> endpoints on the given route builder.</summary>
|
||||
/// <param name="endpoints">The route builder to add the endpoints to.</param>
|
||||
/// <returns>The same <paramref name="endpoints"/> instance, for call chaining.</returns>
|
||||
public static IEndpointRouteBuilder MapAuthEndpoints(this IEndpointRouteBuilder endpoints)
|
||||
{
|
||||
endpoints.MapPost("/auth/login", async (HttpContext context) =>
|
||||
@@ -198,6 +199,7 @@ public static class AuthEndpoints
|
||||
/// server-side. See CentralUI-020.
|
||||
/// </summary>
|
||||
/// <param name="context">The current HTTP context used to check authentication state and write the response.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
public static Task HandlePing(HttpContext context)
|
||||
{
|
||||
context.Response.StatusCode = context.User.Identity?.IsAuthenticated == true
|
||||
@@ -219,6 +221,7 @@ public static class AuthEndpoints
|
||||
/// <see cref="AuthenticationProperties.AllowRefresh"/> is left unset (null)
|
||||
/// so the middleware is free to slide the expiry on activity.
|
||||
/// </summary>
|
||||
/// <returns>An <see cref="AuthenticationProperties"/> instance with <see cref="AuthenticationProperties.IsPersistent"/> set to <c>true</c> and no fixed expiry.</returns>
|
||||
public static AuthenticationProperties BuildSignInProperties() => new()
|
||||
{
|
||||
IsPersistent = true
|
||||
|
||||
@@ -20,6 +20,7 @@ public static class ClaimsPrincipalExtensions
|
||||
/// <see cref="UnknownUser"/> when the claim is absent.
|
||||
/// </summary>
|
||||
/// <param name="principal">The claims principal to read the username from.</param>
|
||||
/// <returns>The username claim value, or <see cref="UnknownUser"/> if absent.</returns>
|
||||
public static string GetUsername(this ClaimsPrincipal principal)
|
||||
=> principal.FindFirst(JwtTokenService.UsernameClaimType)?.Value ?? UnknownUser;
|
||||
|
||||
@@ -28,6 +29,7 @@ public static class ClaimsPrincipalExtensions
|
||||
/// the claim is absent.
|
||||
/// </summary>
|
||||
/// <param name="principal">The claims principal to read the display name from.</param>
|
||||
/// <returns>The display name claim value, or <c>null</c> if the claim is absent.</returns>
|
||||
public static string? GetDisplayName(this ClaimsPrincipal principal)
|
||||
=> principal.FindFirst(JwtTokenService.DisplayNameClaimType)?.Value;
|
||||
|
||||
@@ -37,6 +39,7 @@ public static class ClaimsPrincipalExtensions
|
||||
/// ten components (CentralUI-024).
|
||||
/// </summary>
|
||||
/// <param name="authStateProvider">The Blazor authentication state provider to read from.</param>
|
||||
/// <returns>A task that resolves to the current user's audit username, or <see cref="UnknownUser"/> if not authenticated.</returns>
|
||||
public static async Task<string> GetCurrentUsernameAsync(
|
||||
this AuthenticationStateProvider authStateProvider)
|
||||
{
|
||||
|
||||
@@ -38,6 +38,7 @@ public sealed class SiteScopeService
|
||||
/// True when the user is not restricted to a site subset (no <c>SiteId</c>
|
||||
/// claims). System-wide users see and act on every site.
|
||||
/// </summary>
|
||||
/// <returns>A task that resolves to <c>true</c> if the user has no site-scope restriction.</returns>
|
||||
public async Task<bool> IsSystemWideAsync()
|
||||
=> (await ResolveAsync()).IsSystemWide;
|
||||
|
||||
@@ -46,6 +47,7 @@ public sealed class SiteScopeService
|
||||
/// system-wide user (callers should consult <see cref="IsSystemWideAsync"/>
|
||||
/// or use the filter/allowed helpers, which already account for that).
|
||||
/// </summary>
|
||||
/// <returns>A task that resolves to the set of permitted site IDs (empty for system-wide users).</returns>
|
||||
public async Task<IReadOnlySet<int>> PermittedSiteIdsAsync()
|
||||
=> (await ResolveAsync()).Sites;
|
||||
|
||||
@@ -54,6 +56,7 @@ public sealed class SiteScopeService
|
||||
/// see. A system-wide user gets the full list back unchanged.
|
||||
/// </summary>
|
||||
/// <param name="sites">The full set of sites to filter.</param>
|
||||
/// <returns>A task that resolves to the filtered list of sites the user is permitted to see.</returns>
|
||||
public async Task<List<Site>> FilterSitesAsync(IEnumerable<Site> sites)
|
||||
{
|
||||
var (isSystemWide, allowed) = await ResolveAsync();
|
||||
@@ -67,6 +70,7 @@ public sealed class SiteScopeService
|
||||
/// Must be re-checked server-side before any mutating cross-site command.
|
||||
/// </summary>
|
||||
/// <param name="siteId">The <c>Site.Id</c> to check.</param>
|
||||
/// <returns>A task that resolves to <c>true</c> when the user may operate on the given site.</returns>
|
||||
public async Task<bool> IsSiteAllowedAsync(int siteId)
|
||||
{
|
||||
var (isSystemWide, allowed) = await ResolveAsync();
|
||||
|
||||
@@ -114,6 +114,7 @@ public sealed class AuditQueryModel
|
||||
/// With one or more Channels selected, the union of the channel-specific kind
|
||||
/// lists is returned (deduplicated and order-stable on first-seen).
|
||||
/// </summary>
|
||||
/// <returns>The deduplicated, order-stable list of <see cref="AuditKind"/> values applicable to the selected channels.</returns>
|
||||
public IReadOnlyList<AuditKind> VisibleKinds()
|
||||
{
|
||||
if (Channels.Count == 0)
|
||||
|
||||
@@ -411,6 +411,7 @@ public partial class AuditResultsGrid : IAsyncDisposable
|
||||
/// </summary>
|
||||
/// <param name="columnKey">The stable key of the resized column.</param>
|
||||
/// <param name="widthPx">The new column width in pixels.</param>
|
||||
/// <returns>A task that completes when the column width has been persisted and the component re-rendered.</returns>
|
||||
[JSInvokable]
|
||||
public async Task OnColumnResized(string columnKey, int widthPx)
|
||||
{
|
||||
@@ -431,6 +432,7 @@ public partial class AuditResultsGrid : IAsyncDisposable
|
||||
/// </summary>
|
||||
/// <param name="fromKey">The stable key of the column being dragged.</param>
|
||||
/// <param name="toKey">The stable key of the target column drop slot.</param>
|
||||
/// <returns>A task that completes when the column order has been persisted and the component re-rendered.</returns>
|
||||
[JSInvokable]
|
||||
public async Task OnColumnReordered(string fromKey, string toKey)
|
||||
{
|
||||
@@ -472,6 +474,7 @@ public partial class AuditResultsGrid : IAsyncDisposable
|
||||
/// <summary>
|
||||
/// Releases the .NET object reference held for JS interop callbacks.
|
||||
/// </summary>
|
||||
/// <returns>A completed value task.</returns>
|
||||
public ValueTask DisposeAsync()
|
||||
{
|
||||
_selfRef?.Dispose();
|
||||
|
||||
@@ -254,6 +254,7 @@ public partial class AuditLogPage : IDisposable
|
||||
/// Builds the CSV export URL for the given filter, encoding all active filter dimensions as query parameters.
|
||||
/// </summary>
|
||||
/// <param name="filter">Currently applied filter; null returns the bare export endpoint.</param>
|
||||
/// <returns>The relative URL with encoded filter dimensions as query parameters.</returns>
|
||||
internal static string BuildExportUrl(AuditLogQueryFilter? filter)
|
||||
{
|
||||
const string basePath = "/api/centralui/audit/export";
|
||||
|
||||
@@ -182,6 +182,7 @@ public partial class TransportExport : ComponentBase
|
||||
/// importer enforces its own strength + lockout policies.
|
||||
/// </summary>
|
||||
/// <param name="s">The passphrase string to score.</param>
|
||||
/// <returns>An integer from 0 (blank) to 4 (long, mixed case, digits, and symbols).</returns>
|
||||
internal static int PassphraseStrength(string s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(s)) return 0;
|
||||
@@ -261,6 +262,7 @@ public partial class TransportExport : ComponentBase
|
||||
/// knows exactly what an unencrypted export would leak.
|
||||
/// </summary>
|
||||
/// <param name="resolved">The resolved export closure whose secret fields are counted.</param>
|
||||
/// <returns>The total number of non-empty secret fields across all external systems, SMTP configs, and database connections.</returns>
|
||||
internal static int CountSecrets(ResolvedExport resolved)
|
||||
{
|
||||
var count = 0;
|
||||
@@ -367,6 +369,7 @@ public partial class TransportExport : ComponentBase
|
||||
/// </summary>
|
||||
/// <param name="sourceEnvironment">The environment label to embed in the filename (sanitised to filename-safe characters).</param>
|
||||
/// <param name="nowUtc">Timestamp to use for the datetime segment; defaults to <see cref="DateTimeOffset.UtcNow"/> when null.</param>
|
||||
/// <returns>A filename of the form <c>scadabundle-{env}-{yyyy-MM-dd-HHmmss}.scadabundle</c>.</returns>
|
||||
internal static string BuildFilename(string sourceEnvironment, DateTimeOffset? nowUtc = null)
|
||||
{
|
||||
var safe = SanitizeForFilename(sourceEnvironment);
|
||||
@@ -427,6 +430,7 @@ public partial class TransportExport : ComponentBase
|
||||
/// <param name="all">The full resolved list including both seed and auto-included items.</param>
|
||||
/// <param name="seed">The set of explicitly selected item ids.</param>
|
||||
/// <param name="idOf">Function that extracts the integer id from an item.</param>
|
||||
/// <returns>Items from <paramref name="all"/> whose ids are not in <paramref name="seed"/> (auto-included dependencies).</returns>
|
||||
internal static IReadOnlyList<T> AutoIncluded<T>(IReadOnlyList<T> all, IReadOnlyCollection<int> seed, Func<T, int> idOf)
|
||||
{
|
||||
return all.Where(x => !seed.Contains(idOf(x))).ToList();
|
||||
|
||||
@@ -18,6 +18,7 @@ internal static class DurationInput
|
||||
/// <c>sec</c> unit.
|
||||
/// </summary>
|
||||
/// <param name="duration">The duration to split, or null for unset.</param>
|
||||
/// <returns>A tuple of the numeric string and unit token (ms/sec/min), or <c>(null, "sec")</c> for null or non-positive input.</returns>
|
||||
internal static (string? Value, string Unit) Split(TimeSpan? duration)
|
||||
{
|
||||
if (duration is not { } d || d <= TimeSpan.Zero) return (null, "sec");
|
||||
@@ -34,6 +35,7 @@ internal static class DurationInput
|
||||
/// </summary>
|
||||
/// <param name="value">The numeric string entered by the user.</param>
|
||||
/// <param name="unit">The selected unit token (ms, sec, or min).</param>
|
||||
/// <returns>The composed <see cref="TimeSpan"/>, or <c>null</c> for blank, unparseable, or non-positive input.</returns>
|
||||
internal static TimeSpan? Compose(string? value, string unit)
|
||||
{
|
||||
if (!long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var n)
|
||||
|
||||
@@ -18,6 +18,7 @@ public interface IDialogService
|
||||
/// <param name="danger">When <c>true</c>, the confirm button renders in
|
||||
/// <c>btn-danger</c> styling with the label "Delete"; otherwise a primary
|
||||
/// "Confirm" button is shown.</param>
|
||||
/// <returns>A task that resolves to <c>true</c> when the user confirms, or <c>false</c> when cancelled.</returns>
|
||||
Task<bool> ConfirmAsync(string title, string message, bool danger = false);
|
||||
|
||||
/// <summary>
|
||||
@@ -28,5 +29,6 @@ public interface IDialogService
|
||||
/// <param name="label">Label rendered above the input field.</param>
|
||||
/// <param name="initialValue">Pre-populated value for the input field.</param>
|
||||
/// <param name="placeholder">Optional placeholder shown when the input is empty.</param>
|
||||
/// <returns>A task that resolves to the entered string, or <c>null</c> if the user cancels.</returns>
|
||||
Task<string?> PromptAsync(string title, string label, string initialValue = "", string? placeholder = null);
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ internal static class SchemaBuilderModel
|
||||
/// </summary>
|
||||
/// <param name="json">JSON Schema string to parse, or null/empty to return the fallback.</param>
|
||||
/// <param name="fallback">The <see cref="SchemaNode"/> to return when the input cannot be parsed.</param>
|
||||
/// <returns>The parsed <see cref="SchemaNode"/> tree, or <paramref name="fallback"/> if the input is empty or malformed.</returns>
|
||||
public static SchemaNode Parse(string? json, SchemaNode fallback)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(json)) return fallback;
|
||||
@@ -66,15 +67,18 @@ internal static class SchemaBuilderModel
|
||||
}
|
||||
|
||||
/// <summary>Default empty object schema (parameters mode default).</summary>
|
||||
/// <returns>A new <see cref="SchemaNode"/> with type <c>object</c>.</returns>
|
||||
public static SchemaNode NewObject() => new() { Type = "object" };
|
||||
|
||||
/// <summary>Default scalar schema (return mode default).</summary>
|
||||
/// <returns>A new <see cref="SchemaNode"/> with type <c>string</c>.</returns>
|
||||
public static SchemaNode NewValue() => new() { Type = "string" };
|
||||
|
||||
/// <summary>
|
||||
/// Serializes a <see cref="SchemaNode"/> tree to its canonical JSON Schema string.
|
||||
/// </summary>
|
||||
/// <param name="node">The schema node to serialize.</param>
|
||||
/// <returns>The canonical JSON Schema string representing the node tree.</returns>
|
||||
public static string Serialize(SchemaNode node)
|
||||
{
|
||||
using var stream = new System.IO.MemoryStream();
|
||||
|
||||
@@ -13,6 +13,7 @@ public static class ScriptParameterNames
|
||||
/// Parses a parameter definitions JSON Schema and returns the declared parameter names.
|
||||
/// </summary>
|
||||
/// <param name="json">JSON Schema or legacy flat-array string; null/empty returns an empty list.</param>
|
||||
/// <returns>A read-only list of declared parameter names.</returns>
|
||||
public static IReadOnlyList<string> Parse(string? json) =>
|
||||
JsonSchemaShapeParser.ParseParameters(json)
|
||||
.Select(p => p.Name)
|
||||
@@ -23,6 +24,7 @@ public static class ScriptParameterNames
|
||||
/// Parses a parameter definitions JSON Schema and returns the full parameter shape objects.
|
||||
/// </summary>
|
||||
/// <param name="json">JSON Schema or legacy flat-array string; null/empty returns an empty list.</param>
|
||||
/// <returns>A read-only list of parameter shape objects with name and type information.</returns>
|
||||
public static IReadOnlyList<ParameterShape> ParseShapes(string? json) =>
|
||||
JsonSchemaShapeParser.ParseParameters(json);
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ internal static class ScriptTriggerConfigCodec
|
||||
|
||||
/// <summary>Classifies a raw <c>TriggerType</c> string (case-insensitive).</summary>
|
||||
/// <param name="triggerType">The raw trigger type string from the template script entity.</param>
|
||||
/// <returns>The matching <see cref="ScriptTriggerKind"/>, or <see cref="ScriptTriggerKind.None"/> for null/empty.</returns>
|
||||
internal static ScriptTriggerKind ParseKind(string? triggerType)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(triggerType)) return ScriptTriggerKind.None;
|
||||
@@ -89,6 +90,7 @@ internal static class ScriptTriggerConfigCodec
|
||||
/// (invoked explicitly, never throttled), and None/Unknown.
|
||||
/// </summary>
|
||||
/// <param name="triggerType">The raw trigger type string to classify.</param>
|
||||
/// <returns><see langword="true"/> if the trigger honours <c>MinTimeBetweenRuns</c>; otherwise <see langword="false"/>.</returns>
|
||||
internal static bool SupportsMinTimeBetweenRuns(string? triggerType) =>
|
||||
ParseKind(triggerType) is ScriptTriggerKind.ValueChange
|
||||
or ScriptTriggerKind.Conditional
|
||||
@@ -96,6 +98,7 @@ internal static class ScriptTriggerConfigCodec
|
||||
|
||||
/// <summary>Canonical <c>TriggerType</c> string for a kind; null for None/Unknown.</summary>
|
||||
/// <param name="kind">The trigger kind to convert.</param>
|
||||
/// <returns>The canonical trigger-type string, or null for <see cref="ScriptTriggerKind.None"/>/<see cref="ScriptTriggerKind.Unknown"/>.</returns>
|
||||
internal static string? KindToString(ScriptTriggerKind kind) => kind switch
|
||||
{
|
||||
ScriptTriggerKind.Interval => "Interval",
|
||||
@@ -113,6 +116,7 @@ internal static class ScriptTriggerConfigCodec
|
||||
/// </summary>
|
||||
/// <param name="json">The raw JSON trigger configuration string.</param>
|
||||
/// <param name="kind">The trigger kind, used to determine which fields to parse.</param>
|
||||
/// <returns>A <see cref="ScriptTriggerModel"/> populated from the JSON; defaults are used for absent or malformed fields.</returns>
|
||||
internal static ScriptTriggerModel Parse(string? json, ScriptTriggerKind kind)
|
||||
{
|
||||
var model = new ScriptTriggerModel();
|
||||
@@ -161,6 +165,7 @@ internal static class ScriptTriggerConfigCodec
|
||||
/// </summary>
|
||||
/// <param name="model">The trigger model to serialize.</param>
|
||||
/// <param name="kind">The trigger kind, used to determine which fields to emit.</param>
|
||||
/// <returns>The JSON configuration string, or null for <see cref="ScriptTriggerKind.None"/>/<see cref="ScriptTriggerKind.Unknown"/>.</returns>
|
||||
internal static string? Serialize(ScriptTriggerModel model, ScriptTriggerKind kind)
|
||||
{
|
||||
if (kind is ScriptTriggerKind.None or ScriptTriggerKind.Unknown) return null;
|
||||
@@ -214,6 +219,7 @@ internal static class ScriptTriggerConfigCodec
|
||||
|
||||
/// <summary>Returns <paramref name="raw"/> if it is a recognized operator, else ">".</summary>
|
||||
/// <param name="raw">The raw operator string to normalize.</param>
|
||||
/// <returns>A valid operator string from <see cref="Operators"/>; defaults to ">" for unrecognized input.</returns>
|
||||
internal static string NormalizeOperator(string? raw)
|
||||
{
|
||||
var op = raw?.Trim();
|
||||
|
||||
@@ -19,6 +19,7 @@ public static class TriggerAttributeMapper
|
||||
{
|
||||
/// <summary>Direct and inherited attributes, exposed as <c>Attributes["..."]</c>.</summary>
|
||||
/// <param name="choices">The full flattened attribute choice list from the trigger editor.</param>
|
||||
/// <returns>The list of <see cref="AttributeShape"/>s for Direct and Inherited attributes.</returns>
|
||||
public static IReadOnlyList<AttributeShape> SelfAttributes(
|
||||
IReadOnlyList<AlarmAttributeChoice> choices) =>
|
||||
choices
|
||||
@@ -32,6 +33,7 @@ public static class TriggerAttributeMapper
|
||||
/// are skipped (no child scope to attach them to).
|
||||
/// </summary>
|
||||
/// <param name="choices">The full flattened attribute choice list from the trigger editor.</param>
|
||||
/// <returns>The list of <see cref="CompositionContext"/>s, one per distinct composition-instance name.</returns>
|
||||
public static IReadOnlyList<CompositionContext> Children(
|
||||
IReadOnlyList<AlarmAttributeChoice> choices) =>
|
||||
choices
|
||||
|
||||
@@ -15,6 +15,7 @@ public static class EndpointExtensions
|
||||
/// </summary>
|
||||
/// <typeparam name="TApp">The root Blazor App component type, supplied by the Host assembly.</typeparam>
|
||||
/// <param name="endpoints">The endpoint route builder to register routes on.</param>
|
||||
/// <returns>The same <paramref name="endpoints"/> instance, for call chaining.</returns>
|
||||
public static IEndpointRouteBuilder MapCentralUI<TApp>(this IEndpointRouteBuilder endpoints)
|
||||
where TApp : Microsoft.AspNetCore.Components.IComponent
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace ZB.MOM.WW.ScadaBridge.CentralUI.ScriptAnalysis;
|
||||
public interface ISharedScriptCatalog
|
||||
{
|
||||
/// <summary>Returns the parameter and return shapes for all registered shared scripts.</summary>
|
||||
/// <returns>A task that resolves to the list of all shared script shapes.</returns>
|
||||
Task<IReadOnlyList<ScriptShape>> GetShapesAsync();
|
||||
|
||||
/// <summary>
|
||||
@@ -18,6 +19,7 @@ public interface ISharedScriptCatalog
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the shared script to retrieve.</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the async lookup.</param>
|
||||
/// <returns>A task that resolves to the matching shared script source, or null if none exists.</returns>
|
||||
Task<SharedScriptSource?> GetByNameAsync(string name, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ public class InboundScriptHost
|
||||
/// Targets a specific instance for method invocation.
|
||||
/// </summary>
|
||||
/// <param name="instanceCode">The instance code to target.</param>
|
||||
/// <returns>A <see cref="RouteTarget"/> scoped to the specified instance.</returns>
|
||||
public RouteTarget To(string instanceCode) => new();
|
||||
}
|
||||
|
||||
@@ -44,6 +45,7 @@ public class InboundScriptHost
|
||||
/// <param name="scriptName">The name of the script to call.</param>
|
||||
/// <param name="parameters">Optional parameters to pass to the script.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task that resolves to the script's return value, or null.</returns>
|
||||
public System.Threading.Tasks.Task<object?> Call(
|
||||
string scriptName,
|
||||
object? parameters = null,
|
||||
@@ -55,6 +57,7 @@ public class InboundScriptHost
|
||||
/// </summary>
|
||||
/// <param name="attributeName">The name of the attribute to retrieve.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task that resolves to the attribute value, or null if not found.</returns>
|
||||
public System.Threading.Tasks.Task<object?> GetAttribute(
|
||||
string attributeName,
|
||||
System.Threading.CancellationToken cancellationToken = default) =>
|
||||
@@ -65,6 +68,7 @@ public class InboundScriptHost
|
||||
/// </summary>
|
||||
/// <param name="attributeNames">The names of the attributes to retrieve.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task that resolves to a dictionary mapping attribute names to their values.</returns>
|
||||
public System.Threading.Tasks.Task<IReadOnlyDictionary<string, object?>> GetAttributes(
|
||||
IEnumerable<string> attributeNames,
|
||||
System.Threading.CancellationToken cancellationToken = default) =>
|
||||
@@ -77,6 +81,7 @@ public class InboundScriptHost
|
||||
/// <param name="attributeName">The name of the attribute to set.</param>
|
||||
/// <param name="value">The value to set.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task representing the asynchronous operation.</returns>
|
||||
public System.Threading.Tasks.Task SetAttribute(
|
||||
string attributeName,
|
||||
string value,
|
||||
@@ -88,6 +93,7 @@ public class InboundScriptHost
|
||||
/// </summary>
|
||||
/// <param name="attributeValues">Dictionary of attribute names to values.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task representing the asynchronous operation.</returns>
|
||||
public System.Threading.Tasks.Task SetAttributes(
|
||||
IReadOnlyDictionary<string, string> attributeValues,
|
||||
System.Threading.CancellationToken cancellationToken = default) =>
|
||||
|
||||
@@ -20,6 +20,7 @@ public static class JsonSchemaShapeParser
|
||||
{
|
||||
/// <summary>Parses a JSON Schema or legacy flat-array parameters definition and returns the resulting parameter shapes.</summary>
|
||||
/// <param name="json">The JSON string to parse; <c>null</c> or whitespace returns an empty list.</param>
|
||||
/// <returns>A read-only list of <see cref="ParameterShape"/> instances parsed from the definition; empty on null, whitespace, or malformed input.</returns>
|
||||
public static IReadOnlyList<ParameterShape> ParseParameters(string? json)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(json)) return Array.Empty<ParameterShape>();
|
||||
@@ -41,6 +42,7 @@ public static class JsonSchemaShapeParser
|
||||
|
||||
/// <summary>Parses a JSON Schema or legacy return-type definition and returns the normalised type name, or <c>null</c> if absent or unrecognised.</summary>
|
||||
/// <param name="json">The JSON string to parse; <c>null</c> or whitespace returns <c>null</c>.</param>
|
||||
/// <returns>The normalised type name string (e.g. <c>"Boolean"</c>, <c>"List<Integer>"</c>), or <c>null</c> if the input is null, whitespace, malformed, or unrecognised.</returns>
|
||||
public static string? ParseReturnType(string? json)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(json)) return null;
|
||||
|
||||
@@ -41,6 +41,7 @@ internal sealed class SandboxConsoleCapture : TextWriter
|
||||
/// <see cref="Console.Error"/> once for the process. Idempotent and
|
||||
/// thread-safe. Subsequent calls return the already-installed instances.
|
||||
/// </summary>
|
||||
/// <returns>The installed <see cref="SandboxConsoleCapture"/> instances for stdout and stderr.</returns>
|
||||
public static (SandboxConsoleCapture Out, SandboxConsoleCapture Error) Install()
|
||||
{
|
||||
if (_outInstance != null && _errorInstance != null)
|
||||
@@ -72,6 +73,7 @@ internal sealed class SandboxConsoleCapture : TextWriter
|
||||
/// other call-trees are unaffected.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The writer that receives console output for this scope.</param>
|
||||
/// <returns>A <see cref="CaptureScope"/> that, when disposed, restores the previous capture state.</returns>
|
||||
public CaptureScope BeginCapture(StringWriter buffer)
|
||||
{
|
||||
var previous = _current.Value;
|
||||
|
||||
@@ -32,6 +32,7 @@ public class SandboxExternalHelper
|
||||
/// <param name="methodName">The method name to invoke.</param>
|
||||
/// <param name="parameters">Optional method parameters.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task that resolves to the <see cref="ExternalCallResult"/> from the external system.</returns>
|
||||
public Task<ExternalCallResult> Call(
|
||||
string systemName,
|
||||
string methodName,
|
||||
@@ -49,6 +50,7 @@ public class SandboxExternalHelper
|
||||
/// <param name="methodName">The method name to invoke.</param>
|
||||
/// <param name="parameters">Optional method parameters.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task that resolves to the <see cref="ExternalCallResult"/> from the external system.</returns>
|
||||
public Task<ExternalCallResult> CachedCall(
|
||||
string systemName,
|
||||
string methodName,
|
||||
@@ -80,6 +82,7 @@ public class SandboxDatabaseHelper
|
||||
/// <summary>Gets a database connection by name.</summary>
|
||||
/// <param name="name">The database connection name.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task that resolves to the open <see cref="DbConnection"/> for the named database.</returns>
|
||||
public Task<DbConnection> Connection(string name, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (_gateway == null)
|
||||
@@ -93,6 +96,7 @@ public class SandboxDatabaseHelper
|
||||
/// <param name="sql">The SQL statement to execute.</param>
|
||||
/// <param name="parameters">Optional SQL parameters.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
public Task CachedWrite(
|
||||
string name,
|
||||
string sql,
|
||||
@@ -123,6 +127,7 @@ public class SandboxNotifyHelper
|
||||
{
|
||||
/// <summary>Selects the notification list to send to.</summary>
|
||||
/// <param name="listName">The notification list name.</param>
|
||||
/// <returns>A <see cref="SandboxNotifyTarget"/> for the specified list.</returns>
|
||||
public SandboxNotifyTarget To(string listName) =>
|
||||
new();
|
||||
|
||||
@@ -133,6 +138,7 @@ public class SandboxNotifyHelper
|
||||
/// <c>NotifyHelper.Status</c>.
|
||||
/// </summary>
|
||||
/// <param name="notificationId">The notification ID to check status for.</param>
|
||||
/// <returns>A task that resolves to a placeholder <see cref="NotificationDeliveryStatus"/> with status "Unknown".</returns>
|
||||
public Task<NotificationDeliveryStatus> Status(string notificationId) =>
|
||||
Task.FromResult(new NotificationDeliveryStatus("Unknown", 0, null, null));
|
||||
}
|
||||
@@ -156,6 +162,7 @@ public class SandboxNotifyTarget
|
||||
/// <param name="subject">The notification subject.</param>
|
||||
/// <param name="message">The notification message.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task that resolves to a fake notification ID string (a random GUID).</returns>
|
||||
public Task<string> Send(string subject, string message, CancellationToken cancellationToken = default) =>
|
||||
Task.FromResult(Guid.NewGuid().ToString("N"));
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ public class SandboxInboundScriptHost
|
||||
/// Creates a sandbox route target that throws on every operation.
|
||||
/// </summary>
|
||||
/// <param name="instanceCode">The instance code (used only in the exception message).</param>
|
||||
/// <returns>A sandbox route target bound to <paramref name="instanceCode"/>.</returns>
|
||||
public RouteTarget To(string instanceCode) => new(instanceCode);
|
||||
}
|
||||
|
||||
@@ -50,6 +51,7 @@ public class SandboxInboundScriptHost
|
||||
/// <param name="scriptName">Script name (included in the exception message).</param>
|
||||
/// <param name="parameters">Unused parameters.</param>
|
||||
/// <param name="cancellationToken">Unused token.</param>
|
||||
/// <returns>Never returns; always throws <see cref="ScriptSandboxException"/>.</returns>
|
||||
public Task<object?> Call(
|
||||
string scriptName,
|
||||
object? parameters = null,
|
||||
@@ -61,6 +63,7 @@ public class SandboxInboundScriptHost
|
||||
/// </summary>
|
||||
/// <param name="attributeName">Attribute name (included in the exception message).</param>
|
||||
/// <param name="cancellationToken">Unused token.</param>
|
||||
/// <returns>Never returns; always throws <see cref="ScriptSandboxException"/>.</returns>
|
||||
public Task<object?> GetAttribute(
|
||||
string attributeName,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
@@ -71,6 +74,7 @@ public class SandboxInboundScriptHost
|
||||
/// </summary>
|
||||
/// <param name="attributeNames">Attribute names (unused).</param>
|
||||
/// <param name="cancellationToken">Unused token.</param>
|
||||
/// <returns>Never returns; always throws <see cref="ScriptSandboxException"/>.</returns>
|
||||
public Task<IReadOnlyDictionary<string, object?>> GetAttributes(
|
||||
IEnumerable<string> attributeNames,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
@@ -82,6 +86,7 @@ public class SandboxInboundScriptHost
|
||||
/// <param name="attributeName">Attribute name (included in the exception message).</param>
|
||||
/// <param name="value">Unused value.</param>
|
||||
/// <param name="cancellationToken">Unused token.</param>
|
||||
/// <returns>Never returns; always throws <see cref="ScriptSandboxException"/>.</returns>
|
||||
public Task SetAttribute(
|
||||
string attributeName,
|
||||
string value,
|
||||
@@ -93,6 +98,7 @@ public class SandboxInboundScriptHost
|
||||
/// </summary>
|
||||
/// <param name="attributeValues">Unused attribute values.</param>
|
||||
/// <param name="cancellationToken">Unused token.</param>
|
||||
/// <returns>Never returns; always throws <see cref="ScriptSandboxException"/>.</returns>
|
||||
public Task SetAttributes(
|
||||
IReadOnlyDictionary<string, string> attributeValues,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
|
||||
@@ -102,6 +102,7 @@ public interface ISandboxInstanceGateway
|
||||
/// <param name="canonicalName">The canonical name of the attribute.</param>
|
||||
/// <param name="value">The value to set.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
Task SetAttributeAsync(string canonicalName, string value, CancellationToken ct);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -12,6 +12,7 @@ public static class ScriptShapeParser
|
||||
/// <param name="name">The canonical script name.</param>
|
||||
/// <param name="parametersJson">The JSON Schema or legacy flat-array parameters definition, or <c>null</c> for parameterless scripts.</param>
|
||||
/// <param name="returnJson">The JSON Schema or legacy return-type definition, or <c>null</c> for void scripts.</param>
|
||||
/// <returns>A <see cref="ScriptShape"/> describing the script's parameter list and return type.</returns>
|
||||
public static ScriptShape Parse(string name, string? parametersJson, string? returnJson)
|
||||
{
|
||||
var parameters = JsonSchemaShapeParser.ParseParameters(parametersJson);
|
||||
|
||||
@@ -14,6 +14,7 @@ public static class ServiceCollectionExtensions
|
||||
/// Registers all Central UI services including Blazor, auth state, dialogs, audit query, and script analysis.
|
||||
/// </summary>
|
||||
/// <param name="services">The service collection to configure.</param>
|
||||
/// <returns>The <paramref name="services"/> instance for chaining.</returns>
|
||||
public static IServiceCollection AddCentralUI(this IServiceCollection services)
|
||||
{
|
||||
services.AddRazorComponents()
|
||||
|
||||
@@ -45,6 +45,7 @@ public static class ApiMethodKeyScopeReconciler
|
||||
/// <param name="currentMethodsByKey">Each affected key's CURRENT full scope set, keyed by KeyId.
|
||||
/// Read fresh from the seam right before reconciling so concurrent edits do not get clobbered.</param>
|
||||
/// <param name="keyNamesById">Display names by KeyId, for human-readable empty-scope messages.</param>
|
||||
/// <returns>A <see cref="ReconcileResult"/> with the scope updates to apply and any empty-scope warnings.</returns>
|
||||
public static ReconcileResult Reconcile(
|
||||
string methodName,
|
||||
IReadOnlySet<string> selectedKeyIds,
|
||||
|
||||
@@ -70,6 +70,8 @@ public sealed record AuditEventView
|
||||
/// <summary>
|
||||
/// Decomposes a canonical <see cref="AuditEvent"/> into a flat view for the UI.
|
||||
/// </summary>
|
||||
/// <param name="evt">The canonical audit event to decompose.</param>
|
||||
/// <returns>A flat <see cref="AuditEventView"/> populated from the event's top-level and details fields.</returns>
|
||||
public static AuditEventView From(AuditEvent evt)
|
||||
{
|
||||
var r = AuditRowProjection.Decompose(evt);
|
||||
|
||||
@@ -42,6 +42,7 @@ public interface IAuditLogExportService
|
||||
/// enough to amortise the per-query overhead, small enough that one page in
|
||||
/// memory is bounded.
|
||||
/// </param>
|
||||
/// <returns>A task that completes when all matching rows (up to <paramref name="maxRows"/>) have been written to <paramref name="output"/>.</returns>
|
||||
Task ExportAsync(
|
||||
AuditLogQueryFilter filter,
|
||||
int maxRows,
|
||||
@@ -176,6 +177,7 @@ public sealed class AuditLogExportService : IAuditLogExportService
|
||||
/// cleanly on another.
|
||||
/// </summary>
|
||||
/// <param name="evt">The audit event view to format as a CSV row.</param>
|
||||
/// <returns>An RFC 4180 CSV row string (no trailing newline) for the supplied event.</returns>
|
||||
internal static string FormatCsvRow(AuditEventView evt)
|
||||
{
|
||||
var sb = new StringBuilder(256);
|
||||
|
||||
@@ -28,6 +28,7 @@ public interface IAuditLogQueryService
|
||||
/// <param name="filter">Filter criteria applied to the audit log query.</param>
|
||||
/// <param name="paging">Optional paging cursor; defaults to first page when null.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>A task that resolves to a page of audit event views matching the filter.</returns>
|
||||
Task<IReadOnlyList<AuditEventView>> QueryAsync(
|
||||
AuditLogQueryFilter filter,
|
||||
AuditLogPaging? paging = null,
|
||||
@@ -57,6 +58,7 @@ public interface IAuditLogQueryService
|
||||
/// dashboard.
|
||||
/// </remarks>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>A task that resolves to the current audit KPI snapshot.</returns>
|
||||
Task<AuditLogKpiSnapshot> GetKpiSnapshotAsync(CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
@@ -76,6 +78,7 @@ public interface IAuditLogQueryService
|
||||
/// </remarks>
|
||||
/// <param name="executionId">Any execution id in the chain to look up.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>A task that resolves to the flat list of execution tree nodes in the chain.</returns>
|
||||
Task<IReadOnlyList<ExecutionTreeNode>> GetExecutionTreeAsync(
|
||||
Guid executionId,
|
||||
CancellationToken ct = default);
|
||||
@@ -90,5 +93,6 @@ public interface IAuditLogQueryService
|
||||
/// filter affordance.
|
||||
/// </summary>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>A task that resolves to the distinct non-null source node names present in the audit log.</returns>
|
||||
Task<IReadOnlyList<string>> GetDistinctSourceNodesAsync(CancellationToken ct = default);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ public interface IBindingTester
|
||||
/// <param name="connectionName">Name of the site-local data connection — the site's <c>DataConnectionManagerActor</c> indexes its children by name.</param>
|
||||
/// <param name="tagPaths">Tag paths to read.</param>
|
||||
/// <param name="ct">Cancellation token.</param>
|
||||
/// <returns>A task that resolves to the read outcomes for all requested tag paths.</returns>
|
||||
Task<ReadTagValuesResult> ReadAsync(
|
||||
string siteId,
|
||||
string connectionName,
|
||||
|
||||
@@ -29,6 +29,7 @@ public interface IBrowseService
|
||||
/// <param name="connectionName">Name of the site-local data connection to browse against — the site's <c>DataConnectionManagerActor</c> indexes its children by name.</param>
|
||||
/// <param name="parentNodeId">Node to browse, or <c>null</c> to browse from the server root.</param>
|
||||
/// <param name="cancellationToken">Cancellation token.</param>
|
||||
/// <returns>A task that resolves to a <see cref="BrowseNodeResult"/> containing child nodes or a <see cref="BrowseFailure"/> on error.</returns>
|
||||
Task<BrowseNodeResult> BrowseChildrenAsync(
|
||||
string siteId,
|
||||
string connectionName,
|
||||
|
||||
Reference in New Issue
Block a user