9cff87fe85
Remove project bookkeeping citations from shipped code comments across the solution: hyphenated task IDs (WP-14, StoreAndForward-025), milestone/task/ issue refs (M3, Task 4, Audit Log #23, #21), Bundle X task-bundle labels, and C/D/K/S/T phase labels. Comment text only — no code logic, string/log literals, or XML-doc structure changed. Genuine descriptions are preserved (only the citation is stripped), and technical lookalikes are retained (UTF-8, SHA-256, T00:00:00, M365, UTC-5, pre-C4/pre-C5 schema versions). Flagged by the new CommentChecker TaskReferenceInComment / TrackingReferenceInComment checks plus targeted grep passes; full solution builds clean, append-only guard tests pass.
122 lines
4.5 KiB
C#
122 lines
4.5 KiB
C#
using Microsoft.AspNetCore.Components;
|
|
using Microsoft.AspNetCore.WebUtilities;
|
|
using ZB.MOM.WW.ScadaBridge.Commons.Types.Audit;
|
|
|
|
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Components.Pages.Audit;
|
|
|
|
/// <summary>
|
|
/// Code-behind for the execution-chain tree page (Audit Log ParentExecutionId
|
|
/// feature). Route <c>/audit/execution-tree</c>, reached via the Audit
|
|
/// Log drilldown drawer's "View execution chain" action with
|
|
/// <c>?executionId={guid}</c>.
|
|
///
|
|
/// <para>
|
|
/// On initialization the page parses <c>?executionId=</c> (lax-parsed, matching
|
|
/// the Audit Log page's drill-in contract — an absent or unparseable value
|
|
/// leaves the page in a guidance state and issues NO service call), then asks
|
|
/// <see cref="ZB.MOM.WW.ScadaBridge.CentralUI.Services.IAuditLogQueryService.GetExecutionTreeAsync"/>
|
|
/// for the whole chain. The flat <see cref="ExecutionTreeNode"/> list is handed
|
|
/// to the recursive <c>ExecutionTree</c> component, which assembles + renders
|
|
/// the tree.
|
|
/// </para>
|
|
///
|
|
/// <para>
|
|
/// The data path mirrors the Audit Log results grid: the page talks ONLY to the
|
|
/// CentralUI <c>IAuditLogQueryService</c> facade, never <c>IAuditLogRepository</c>
|
|
/// directly, so the page can be unit-tested with a substituted service.
|
|
/// </para>
|
|
/// </summary>
|
|
public partial class ExecutionTreePage
|
|
{
|
|
[Inject] private NavigationManager Navigation { get; set; } = null!;
|
|
|
|
// The parsed ?executionId= value, or null when absent / unparseable.
|
|
private Guid? _executionId;
|
|
|
|
// The flat chain returned by the query service; null until the load
|
|
// completes (or when no id was supplied).
|
|
private IReadOnlyList<ExecutionTreeNode>? _nodes;
|
|
|
|
private bool _loading;
|
|
private string? _error;
|
|
|
|
// Execution-Tree Node Detail Modal feature — state backing the
|
|
// <ExecutionDetailModal>. A double-click on a tree node sets
|
|
// _modalExecutionId + flips _modalOpen true; the modal loads that
|
|
// execution's audit rows on the closed → open transition. _modalOpen is the
|
|
// visibility gate — _modalExecutionId is left intact across a close (it is
|
|
// harmless while the modal is hidden and avoids a flicker if reopened).
|
|
private Guid? _modalExecutionId;
|
|
private bool _modalOpen;
|
|
|
|
/// <inheritdoc />
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
_executionId = ParseExecutionId();
|
|
if (_executionId is null)
|
|
{
|
|
// No id — render guidance, do not touch the service.
|
|
return;
|
|
}
|
|
|
|
await LoadChainAsync(_executionId.Value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Lax-parses <c>?executionId=</c>. Returns null when the param is absent or
|
|
/// is not a valid <see cref="Guid"/> — the page then shows guidance instead
|
|
/// of an error, consistent with the Audit Log page's drill-in handling.
|
|
/// </summary>
|
|
private Guid? ParseExecutionId()
|
|
{
|
|
var uri = Navigation.ToAbsoluteUri(Navigation.Uri);
|
|
var query = QueryHelpers.ParseQuery(uri.Query);
|
|
if (query.TryGetValue("executionId", out var values)
|
|
&& Guid.TryParse(values.ToString(), out var parsed))
|
|
{
|
|
return parsed;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private async Task LoadChainAsync(Guid executionId)
|
|
{
|
|
_loading = true;
|
|
_error = null;
|
|
try
|
|
{
|
|
_nodes = await AuditLogQueryService.GetExecutionTreeAsync(executionId);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// A transient DB outage degrades this page to an error banner
|
|
// rather than killing the circuit — the same defensive posture the
|
|
// Audit Log grid takes around its query.
|
|
_error = $"Could not load the execution chain: {ex.Message}";
|
|
_nodes = null;
|
|
}
|
|
finally
|
|
{
|
|
_loading = false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Raised by <c>ExecutionTree</c> (bubbled up from a node double-click) with
|
|
/// the activated node's <c>ExecutionId</c>. Opens the
|
|
/// <c>ExecutionDetailModal</c> for that execution — the modal loads its
|
|
/// audit rows on the closed → open transition.
|
|
/// </summary>
|
|
private void HandleNodeActivated(Guid executionId)
|
|
{
|
|
_modalExecutionId = executionId;
|
|
_modalOpen = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Raised by <c>ExecutionDetailModal</c> when the user dismisses it. Flips
|
|
/// the visibility gate closed; <see cref="_modalExecutionId"/> is left as-is.
|
|
/// </summary>
|
|
private void HandleModalClose() => _modalOpen = false;
|
|
}
|