# Execution-Tree Node Detail Modal (Design) **Date:** 2026-05-22 **Status:** Validated — ready for implementation planning. ## Problem On the Central UI execution-chain tree page (`/audit/execution-tree`, the `ParentExecutionId` feature's Task 10), each node represents one execution and shows a small inline summary. The only interaction is the short-id link, which navigates away to `/audit/log?executionId=…`. There is no way to inspect an execution's actual audit rows without leaving the tree. ## Decision Double-clicking a tree node opens a **modal** showing that execution's audit rows. The modal mirrors the `/audit/log` detail experience: a list of the execution's rows, and clicking a row reveals that row's full field/payload detail — the exact content the Audit Log drilldown drawer shows. Resolved during brainstorming: - **Modal content** — the execution's audit rows, with per-row full detail. - **Multi-row executions** — list the rows; clicking one shows its detail. A single-row execution opens straight to the detail view. - **Trigger** — double-click anywhere on the node. The short-id link keeps its single-click navigation to the Audit Log grid (unchanged). ### Considered and rejected - **Reuse `AuditDrilldownDrawer` directly.** The drawer renders one `AuditEvent` by design; bending it into a list-or-detail hybrid is more invasive to a well-tested component than a purpose-built modal. - **Inline expansion under the node.** The user asked for a modal, and an inline panel inside the recursive tree fights the existing expand/collapse toggle and is visually messy. ## Components | Component | Change | |---|---| | `AuditEventDetail.razor` | **New.** The single-`AuditEvent` field/payload/drill-in-button block, extracted verbatim from `AuditDrilldownDrawer`'s body. | | `AuditDrilldownDrawer.razor` | **Modified.** Keeps its offcanvas chrome + close button; its body becomes ``. The one refactor with regression risk — existing drawer bUnit + Playwright tests guard it. | | `ExecutionDetailModal.razor` (+ `.razor.cs` + `.razor.css`) | **New.** A custom Bootstrap modal — hand-rolled `modal` / `modal-backdrop` markup, Blazor-toggled, no component framework (the same way `AuditDrilldownDrawer` hand-rolls `offcanvas`). | | `ExecutionTree.razor` / `.razor.cs` | **Modified.** `@ondblclick` on the node body invokes a new `OnNodeActivated` `EventCallback`; recursive child instances re-raise it upward so the event bubbles to the root. | | `ExecutionTreePage.razor` / `.razor.cs` | **Modified.** Hosts one `ExecutionDetailModal`; wires the tree's `OnNodeActivated` to open it. | No database, repository, or service changes — purely Central UI. The `IAuditLogQueryService.QueryAsync` method already filters by `ExecutionId`; the modal reuses it (no new service method). ## Data flow 1. Double-click a node → `ExecutionTree` invokes `OnNodeActivated(node.ExecutionId)`. 2. The event bubbles up the recursive `ExecutionTree` instances to `ExecutionTreePage`. 3. The page opens `ExecutionDetailModal` with the `ExecutionId`. 4. The modal calls `IAuditLogQueryService.QueryAsync(new AuditLogQueryFilter(ExecutionId: id), new AuditLogPaging(PageSize: 100))` → `IReadOnlyList`. 5. Render by row count: - **≥ 2 rows** — a compact row list (kind / status / target / time, each row a button); clicking a row swaps to its `` with a "← Back to rows" control. - **1 row** — opens straight to the detail view. - **0 rows** — a stub execution; a friendly empty state. 6. Close via the X button, the backdrop, or Esc. The list rows are full `AuditEvent` objects (that is what `QueryAsync` returns), so the list→detail transition needs no second fetch. ## Error handling - A `QueryAsync` failure surfaces an inline error inside the modal ("Couldn't load this execution's rows") and never tears down the SignalR circuit — mirroring the tree page's existing `try/catch` degrade-gracefully pattern. - An empty result renders the friendly empty state, not an error. ## Testing - **bUnit** — `ExecutionTree` raises `OnNodeActivated` on `@ondblclick` and bubbles it through a nested instance; `ExecutionDetailModal` list renders from a fake query service, row click → detail, 1-row jump-straight, 0-row empty state, close; `AuditEventDetail` renders the field block; the existing `AuditDrilldownDrawer` tests stay green after the body extraction. - **Playwright** — on `/audit/execution-tree`, double-click a node → modal opens → (multi-row) row list → click a row → detail → close. Uses a seeded chain. - `frontend-design` skill for the modal markup/CSS — clean corporate aesthetic, custom Blazor + Bootstrap, no component frameworks. ## Constraints - Central UI only — no DB / repository / service-contract changes. - Custom Blazor + Bootstrap; no component frameworks. - The short-id link's single-click navigation to `/audit/log?executionId=…` is unchanged.