Skip to content

fix: resolve workflow editor bugs and improve creation UX#9

Merged
tsmarvin merged 11 commits intorefactor/additional-actionsfrom
bugfix/workflow-expectations
Mar 16, 2026
Merged

fix: resolve workflow editor bugs and improve creation UX#9
tsmarvin merged 11 commits intorefactor/additional-actionsfrom
bugfix/workflow-expectations

Conversation

@tsmarvin
Copy link
Copy Markdown
Contributor

@tsmarvin tsmarvin commented Mar 12, 2026

Workflow UI Refactor, Interactive DAG Editor & Editor UX Improvements

This PR delivers a complete UI refactor: a TypeScript/Node.js build pipeline, real-time run monitoring via SignalR, a vis-timeline Gantt view, and a full AntV X6-based DAG renderer and interactive workflow editor — replacing the previous server-rendered SVG DagView.razor entirely. It also includes targeted workflow editor bug fixes and creation UX improvements: renaming ControlStatement.Sequential to Default, adding structured condition editing, workflow target tags, schedule association, and inline task creation.


Workflow Editor Bug Fixes & Creation UX

Why: The original workflow editor had usability gaps — freeform condition input was error-prone, the Sequential enum name was misleading, and creating workflows required excessive navigation between pages.

  • ControlStatement renameControlStatement.Sequential renamed to ControlStatement.Default with a backward-compatible DB value converter that reads legacy Sequential, Parallel, ConditionalIf, ConditionalElseIf, ConditionalWhile, and ConditionalDo values as their modern equivalents. Unrecognized strings fall back to Default. Full round-trip test coverage in ControlStatementConverterTests.
  • ConditionBuilder — Replaces freeform condition input with a structured component supporting exit code comparisons and success status checks, with raw/advanced mode toggle and regex validation.
  • TargetTags — Added TargetTags (string[] stored as JSON) to the Workflow entity with custom ValueComparer; exposed via TagInput component in the workflow editor.
  • Schedule association UI — Associate/disassociate actions and available-schedule dropdown added to the workflow editor.
  • TaskCreateModal (TaskSetupModal) — Inline task creation from the workflow editor with full form support (action types, arguments, tags, success criteria, timeout). Supports both create (POST) and edit (PUT) modes. bUnit tests cover modal visibility, form rendering, submission, cancellation, and edit mode.
  • DagView node coloring updated to match the renamed Default control type.
  • Regenerated Postgres and SQLite InitialCreate migrations with target_tags column on the workflows table.
  • New unit testsControlStatementConverterTests (round-trip, legacy value mapping, unknown fallback), WorkflowServiceTests (diamond DAG, three-independent-steps, mixed control statements), TaskSetupModalTests (modal lifecycle, edit mode, HTTP methods, callbacks).

Interactive Visual Workflow Editor

Why: The form-based step/dependency management was not intuitive or visually appealing. The best visual workflow editors share a common set of critical UX patterns: composable architecture (separating mapping, operations, layout, and traversal concerns), connection-drop-to-node-creator, undo/redo with grouped history, node dirtiness tracking, fixed connection points with visual feedback state machines (green/blue port indicators), and searchable, categorized shape palettes.

The editor uses a batch-save architecture: all mutations modify local X6 graph state and an in-memory changeset. An explicit "Save" syncs to the API. Undo/redo operates purely on local state - avoiding the complexity of reversing per-action API calls.

  • DagEditor.razor - Top-level editor page at /workflows/{Id}/dag-editor. Three-column layout: StepPalette | DagEditorCanvas | NodeConfigPanel. Manages draft restore, metadata editing, DAG validation. Authorized for Admin/Operator roles.
  • DagEditorCanvas.razor - Interactive X6 canvas with minimap
  • DagEditorJsInterop - Editor interop: InitEditorAsync, LoadGraphAsync, AddNodeAsync, UpdateNodeDataAsync, GetChangesetJsonAsync, UndoAsync/RedoAsync, SetLayoutDirectionAsync, ZoomToAsync/ZoomToFitAsync. JS→.NET callbacks: OnNodeSelected, OnNodeDropped, OnSaveRequested, OnCycleDetected, OnGraphDirtyChanged.
  • StepPalette.razor - Categorized, searchable sidebar with drag-to-canvas via X6 Dnd. Collapsible categories with filtered step creation for rapid discovery.
  • NodeConfigPanel.razor - Right-side property editor for task info, control flow, conditions, variable bindings, dependencies. Enables task-level I/O inspection - the number 1 debugging capability for workflow operators.
  • EditorToolbar.razor - Save, undo/redo, validate, zoom, export controls
  • Undo/redo via X6 History plugin - tracks all mutations with grouped operations (e.g., delete node + edges = one undo step)
  • Keyboard shortcuts via X6 Keyboard: Delete, Ctrl+A, Ctrl+C/V, Ctrl+Z/Y, Escape, arrow keys
  • Clipboard via X6 Clipboard: copy/paste subgraphs with preserved internal edges
  • changeset.ts - Tracks add/delete/move mutations locally. Debounced: rapid operations accumulate, Save sends a single batch.
  • cycle-detection.ts - Client-side DFS cycle detection O(V+E) with visual feedback on invalid connections. Most diagramming tools don't perform cycle detection; this is a Werkr addition required for DAG integrity.
  • draft-storage.ts - Auto-save drafts to localStorage. beforeunload warning for unsaved changes.
  • export-handler.ts - PNG and SVG export via graph.toSVG() / graph.toPNG()
  • dnd-handler.ts - Drag-and-drop from palette to canvas
  • annotation-node.ts - Free-form sticky note annotations on canvas for documenting workflow sections

AntV X6 DAG Renderer - Replacing Server-Rendered SVG

Why: The previous DagView.razor was a server-rendered SVG using Kahn's algorithm with fixed-size nodes (160x52) and click-to-select only. SVG + foreignObject rendering with Dagre layout is the proven approach for rich node content (full HTML/CSS) while maintaining SVG coordinates for pan, zoom, and edges. AntV X6 provides all visual interactions client-side at 0ms latency, with built-in undo/redo, clipboard, drag-from-toolbar, minimap, and snapline alignment.

  • DagCanvas.razor - Read-only X6 DAG component with toolbar (LR/TB layout switching)
  • DagJsInterop - Typed C# wrapper inheriting GraphJsInteropBase. Methods: CreateGraphAsync, LoadGraphAsync, ZoomToFitAsync, ApplyStatusOverlayAsync. No scattered IJSRuntime.InvokeAsync("eval", ...) calls.
  • TypeScript core: create-graph.ts, dag-readonly.ts, werkr-node.ts, werkr-edge.ts
  • Dagre hierarchical layout via layout-engine.ts - configurable TB/LR rank direction. The tight-tree ranker was chosen over network-simplex for dramatically better performance at scale (minutes → seconds for large graphs).
  • foreignObject HTML nodes with Bootstrap styling: cards, badges, action-type indicators - enabling full HTML/CSS inside graph nodes rather than flat SVG text
  • parallel-lanes.ts - Light background lanes behind same-level parallel nodes for visual concurrency indication
  • status-overlay.ts - Color-coded execution status per selected run via cell.setData(). Consistent color language: Green=Success, Red=Failed, Amber=Running, Purple=Pending, Gray=Skipped.
  • X6 plugins: Selection, Snapline, Scroller, Transform, MiniMap - all built into X6 3.x core
  • Type definitions: dag-types.ts (node/edge DTOs), dotnet-interop.d.ts (.NET callback interface)

Real-Time Run Monitoring & Execution Views

Why: The workflow debugging experience is the primary functionality for the product - building workflows happens once; debugging them happens daily.

  • Three-view tiered complexity - different users need different detail levels (Compact for quick glance, Timeline for duration analysis, Detail for debugging)
  • Steps × Runs grid view - the most effective at-a-glance cross-run pattern recognition, with color-coded cells making failures immediately visible
  • Gantt charts - essential for bottleneck identification and understanding parallelism
  • Sparkline bar charts - quick pattern recognition for duration and failure trends without drilling in
  • Event grouping - collapsing related events (Scheduled→Started→Completed) into one logical unit reduces cognitive load
  • Real-time liveness - all views update as events stream, rather than polling on a timer
  • Task-level I/O inspection - see exactly what went in/out at every task boundary
  • Saved filter views - operators managing many workflows need personalized, filtered views by status, agent, tag, and owner

Workflow event types in Werkr.Core/Communication/:

  • WorkflowEvent.cs - Six new event types: StepStartedEvent, StepCompletedEvent, StepFailedEvent, StepSkippedEvent, RunCompletedEvent, LogAppendedEvent
  • WorkflowEventBroadcaster - Singleton fan-out via System.Threading.Channels. Published from gRPC service handlers (JobReportingGrpcService, OutputStreamingService, VariableService) when agents report execution progress.
  • WorkflowEventSubscription - Consumer subscription pattern for SSE endpoints

Real-time data pipeline:

Agent → gRPC → API WorkflowEventBroadcaster → SSE stream → JobEventRelayService → SignalR WorkflowRunHub → Browser
  • WorkflowRunHub - SignalR hub at /hubs/workflow-run. Authorized clients join groups keyed by run ID to receive StepStatusChanged, RunCompleted, and LogAppended events.
  • JobEventRelayService - BackgroundService + IHealthCheck that opens a long-lived SSE connection to GET /api/events/workflow-runs via the "ApiServiceSse" named HttpClient, deserializes events, and relays them to the hub via IHubContext<WorkflowRunHub>. Auto-reconnects with exponential backoff (1s → 30s). Tracks active run subscriptions in a ConcurrentDictionary. Registered as health check ("sse-relay") for operational visibility into SSE connection status.
  • ConnectionStatus.razor - Visual indicator (Live / Reconnecting / Polling) in the UI
  • RunDetail.razor - Multi-view run detail page (Compact / Timeline / Log tabs)
  • GanttTab.razor + TimelineJsInterop - vis-timeline Gantt chart showing horizontal bars per task with duration and status. Live bars grow during active runs via SignalR push.
  • RunSparkline.razor - Server-side SVG mini bar charts (bar height = duration, bar color = status) inline on the workflow list
  • RunGridView.razor - Steps × Runs 2D status matrix for cross-run comparison
  • StepDetailPanel.razor - Step-level log preview and error messages
  • TimelineView.razor - Chronological step execution list with attempt tracking and event grouping
  • SavedFilterService + FilterBar.razor - Named saved filter views persisted via localStorage. Backed by a full filter model ecosystem: FilterField, FilterDefinition, FilterCriteria, FilterFieldType, SavedFilterView in Werkr.Common/Models/.
  • SignalR DTOs - StepStatusDto, RunStatusDto, LogLineDto in WorkflowRunHubDtos.cs - typed payloads for each hub broadcast method
  • Additional DTOs - RunSparklineDto, StepStatusSummaryDto, AnnotationDto, DagValidationResult in Werkr.Common/Models/
  • Dedicated SSE HttpClient ("ApiServiceSse") configured with infinite timeout and no resilience handlers in Program.cs

API Endpoints & Batch Operations

Batch save endpoint - The server-side contract for the editor's batch-save architecture:

  • POST /api/workflows/{workflowId}/steps/batch - Atomic batch operations for editor save. Accepts a WorkflowStepBatchRequest containing ordered step operations.
  • Sign convention: negative StepId = temp ID (new nodes created in the editor), positive = real ID (existing nodes). The response includes StepIdMapping[] for temp→real ID resolution after save.
  • WorkflowStepBatchModels.cs - WorkflowStepBatchRequest, StepBatchOperation, DependencyBatchItem, WorkflowStepBatchResponse, StepIdMapping

Run management:

  • POST /api/workflows/{id}/runs/{runId}/retry-from/{stepId} - Retry from a failed step with optional variable overrides via RetryFromFailedRequest

SSE event streams:

  • GET /api/events/workflow-runs - Dedicated SSE stream for workflow run events (consumed by JobEventRelayService)
  • GET /api/workflows/runs/{runId}/events - Per-run filtered event stream
  • GET /api/events/jobs - Existing job event stream (backward-compatible)

Saved filter persistence:

  • Full CRUD at /api/filters/{pageKey} (GET list, POST create, PUT update, DELETE) with page keys for runs, workflows, jobs, agents, schedules, tasks. Admin-only share toggle.

Consistent Color Standard & Theme System

Why: A consistent color language across all views - where the same semantic colors map to the same states throughout the entire UI - is essential for quick visual parsing.

  • CSS custom properties in theme.css defining a standardized palette with dark/light theme support:
    • Status: --werkr-success (#28a745), --werkr-failed (#dc3545), --werkr-running (#ffc107), --werkr-pending (#6f42c1), --werkr-skipped (#6c757d), --werkr-not-run
    • Node types: --werkr-node-default, --werkr-node-conditional, --werkr-node-fallback, --werkr-node-loop
    • Structural: --werkr-edge-color, --werkr-node-stroke, --werkr-parallel-group-bg, --werkr-snapline
  • Applied consistently across DAG nodes, sparklines, grid view cells, Gantt bars, and status badges

JS/TS Build Infrastructure

Why: The X6 graph engine, vis-timeline, and Dagre layout all require a proper JS/TS build pipeline. Keeping all drag, zoom, pan, and connection drawing in the browser while reserving SignalR round-trips for state commits.

  • TypeScript 5.9 project with strict mode under graph-ui
  • esbuild bundler (~50ms incremental builds) with code-split output to wwwroot/js/dist/: dag-readonly.js, dag-editor.js, timeline-view.js, plus shared vendor chunks. Editor bundle lazy-loaded only when entering edit mode.
  • MSBuild integration in Werkr.Server.csproj: EnsureNodeNpmInstallBuildGraphUi targets fire automatically during dotnet build. No separate npm steps needed during development.
  • Vitest 3.0 test runner with 7 unit tests covering changeset operations, cycle detection, draft storage, clipboard handling, timeline item mapping, and status styling
  • Blazor<->JS interop hierarchy: GraphJsInteropBase<T> manages IJSObjectReference + DotNetObjectReference lifecycle with IAsyncDisposable. Three derived classes: DagJsInterop (read-only), DagEditorJsInterop (editor), TimelineJsInterop (Gantt).
  • .nvmrc pins Node.js 22. .gitignore excludes node_modules/ and wwwroot/js/dist/.

CI/CD & Dependency Updates

  • CI workflow (ci.yml): Added Node.js 22 setup → npm ci → Vitest → npm run build:prod → bundle size check via check-bundle-size.mjs (250 KB gzipped budget)
  • DocFX workflow (DocFX_gh-pages.yml): Simplified from multi-job Windows workflow to single Ubuntu-based job
  • NuGet dependency updates in Directory.Packages.props: Microsoft.Extensions, ASP.NET Core, EF Core, SignalR, and test packages updated to latest patch versions
  • Central package transitive pinning enabled in Directory.Packages.props to enforce consistent transitive dependency versions
  • Lock file updates across all projects to match new package versions
  • Cross-platform test fix in UrlValidatorTests.cs: RelativeUrl_Rejected test now handles Unix vs. Windows URI parsing differences
  • System.Text.Json transitive dependency update in installer project

New Dependencies

Package Version Purpose
@antv/x6 3.1.6 Graph visualization & editing engine (MIT)
dagre 0.8.5 Hierarchical DAG layout (MIT)
vis-timeline 7.7.3 Gantt timeline rendering (Apache-2.0 / MIT)
vis-data 7.1.9 Reactive data containers for vis-timeline (Apache-2.0 / MIT)
typescript 5.9.x TypeScript compiler
esbuild 0.27.x Bundler
vitest 3.0.x Test runner

No new NuGet packages - all required .NET packages already existed in Directory.Packages.props.

New Prerequisite

  • Node.js 22+ required on dev machines and CI agents

- Rename ControlStatement.Sequential to Default with backward-compatible
  DB converter that reads legacy Sequential values as Default
- Replace freeform condition input with structured ConditionBuilder
  component supporting exit code comparisons and success status checks,
  with raw/advanced mode and regex validation
- Add TargetTags (string[] as JSON) to Workflow entity with custom
  ValueComparer; expose via TagInput in workflow editor
- Add schedule association UI to workflow editor with associate/
  disassociate actions and available-schedule dropdown
- Add TaskCreateModal for inline task creation from workflow editor
  with full form support (action types, arguments, tags, success
  criteria, timeout)
- Update DagView node coloring to match renamed default control type
- Regenerate Postgres and SQLite InitialCreate migrations with
  target_tags column on workflows table
Copilot AI review requested due to automatic review settings March 12, 2026 07:18
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes and improves the workflow editor experience while evolving workflow semantics and persistence (control statement rename/back-compat, structured condition editing, workflow-level targeting tags, schedule association UI, and inline task creation).

Changes:

  • Renames the default workflow step control statement to Default and updates UI coloring and DTO defaults accordingly.
  • Adds workflow-level TargetTags persisted as JSON and surfaced in the workflow editor (and used for schedule-to-agent matching).
  • Adds workflow-schedule association endpoints/UI and introduces inline task creation via a modal, plus a structured ConditionBuilder UI.

Reviewed changes

Copilot reviewed 40 out of 40 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/Werkr.Server/Components/Shared/TaskCreateModal.razor Adds a modal UI to create tasks inline from the workflow editor.
src/Werkr.Server/Components/Shared/DagView.razor Updates node coloring to match the renamed Default control type.
src/Werkr.Server/Components/Shared/ConditionBuilder.razor Adds a structured + raw editor for workflow step condition expressions with regex validation.
src/Werkr.Server/Components/Pages/Workflows/Edit.razor Adds workflow Target Tags editing, schedule association UI, and inline task creation entrypoint; swaps condition input to ConditionBuilder.
src/Werkr.Data/WerkrDbContext.cs Adds JSON conversion + comparer for Workflow.TargetTags; updates ControlStatement string converter for back-compat.
src/Werkr.Data/Entities/Workflows/Workflow.cs Adds TargetTags to workflow entity.
src/Werkr.Data/Entities/Workflows/WorkflowStep.cs Changes default control statement to Default and updates docs accordingly.
src/Werkr.Data/Entities/Workflows/ControlStatement.cs Renames Sequential to Default and updates semantics description.
src/Werkr.Api/Endpoints/WorkflowEndpoints.cs Adds workflow-schedule association endpoints (list/associate/disassociate).
src/Werkr.Api/Services/ScheduleSyncGrpcService.cs Uses workflow-level TargetTags for agent matching when present, with task-level fallback.
src/Werkr.Api/Models/WorkflowMapper.cs Maps workflow TargetTags into/from API models/DTOs.
src/Werkr.Core/Workflows/WorkflowService.cs Persists workflow TargetTags on update.
src/Werkr.Common/Models/* Extends workflow DTOs/requests for TargetTags; updates step defaults; adds schedule associate request model.
src/Werkr.Agent/Scheduling/WorkflowExecutionService.cs Executes parallelizable steps concurrently and uses concurrent dictionaries for shared state.
src/Werkr.Data/Migrations/* + src/Werkr.Data.Identity/Migrations/* Regenerates initial migrations/snapshots to include target_tags and EF version bump.
src/Test/* Adds/updates integration/unit/component tests for TargetTags, schedule association, ConditionBuilder, TaskCreateModal, and converter behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Werkr.Server/Components/Shared/TaskSetupModal.razor Outdated
Comment thread src/Werkr.Server/Components/Pages/Workflows/Edit.razor Outdated
Comment thread src/Werkr.Data/WerkrDbContext.cs Outdated
Comment thread src/Werkr.Api/Endpoints/WorkflowEndpoints.cs Outdated
## Workflow UI & Interactive DAG Editor

This PR delivers a complete UI refactor: a TypeScript/Node.js build pipeline, real-time run monitoring via SignalR, a vis-timeline Gantt view, and a full AntV X6-based DAG renderer and interactive workflow editor - replacing the previous server-rendered SVG `DagView.razor` entirely.

---

### Interactive Visual Workflow Editor

**Why:** The form-based step/dependency management was not intuitive or visually appealing. The best visual workflow editors share a common set of critical UX patterns: composable architecture (separating mapping, operations, layout, and traversal concerns), connection-drop-to-node-creator, undo/redo with grouped history, node dirtiness tracking, fixed connection points with visual feedback state machines (green/blue port indicators), and searchable, categorized shape palettes.

The editor uses a **batch-save architecture**: all mutations modify local X6 graph state and an in-memory changeset. An explicit "Save" syncs to the API. Undo/redo operates purely on local state - avoiding the complexity of reversing per-action API calls.

- **DagEditor.razor** - Top-level editor page at `/workflows/{Id}/dag-editor`. Three-column layout: `StepPalette` | `DagEditorCanvas` | `NodeConfigPanel`. Manages draft restore, metadata editing, DAG validation. Authorized for Admin/Operator roles.
- **DagEditorCanvas.razor** - Interactive X6 canvas with minimap
- **DagEditorJsInterop** - Editor interop: `InitEditorAsync`, `LoadGraphAsync`, `AddNodeAsync`, `UpdateNodeDataAsync`, `GetChangesetJsonAsync`, `UndoAsync`/`RedoAsync`, `SetLayoutDirectionAsync`, `ZoomToAsync`/`ZoomToFitAsync`. JS→.NET callbacks: `OnNodeSelected`, `OnNodeDropped`, `OnSaveRequested`, `OnCycleDetected`, `OnGraphDirtyChanged`.
- **StepPalette.razor** - Categorized, searchable sidebar with drag-to-canvas via X6 Dnd. Collapsible categories with filtered step creation for rapid discovery.
- **NodeConfigPanel.razor** - Right-side property editor for task info, control flow, conditions, variable bindings, dependencies. Enables task-level I/O inspection - the #1 debugging capability for workflow operators.
- **EditorToolbar.razor** - Save, undo/redo, validate, zoom, export controls
- **Undo/redo** via X6 History plugin - tracks all mutations with grouped operations (e.g., delete node + edges = one undo step)
- **Keyboard shortcuts** via X6 Keyboard: Delete, Ctrl+A, Ctrl+C/V, Ctrl+Z/Y, Escape, arrow keys
- **Clipboard** via X6 Clipboard: copy/paste subgraphs with preserved internal edges
- **changeset.ts** - Tracks add/delete/move mutations locally. Debounced: rapid operations accumulate, Save sends a single batch.
- **cycle-detection.ts** - Client-side DFS cycle detection O(V+E) with visual feedback on invalid connections. Most diagramming tools don't perform cycle detection; this is a Werkr addition required for DAG integrity.
- **draft-storage.ts** - Auto-save drafts to localStorage. `beforeunload` warning for unsaved changes.
- **export-handler.ts** - PNG and SVG export via `graph.toSVG()` / `graph.toPNG()`
- **dnd-handler.ts** - Drag-and-drop from palette to canvas
- **annotation-node.ts** - Free-form sticky note annotations on canvas for documenting workflow sections

---

### AntV X6 DAG Renderer - Replacing Server-Rendered SVG

**Why:** The previous `DagView.razor` was a server-rendered SVG using Kahn's algorithm with fixed-size nodes (160x52) and click-to-select only. SVG + foreignObject rendering with Dagre layout is the proven approach for rich node content (full HTML/CSS) while maintaining SVG coordinates for pan, zoom, and edges. AntV X6 provides all visual interactions client-side at 0ms latency, with built-in undo/redo, clipboard, drag-from-toolbar, minimap, and snapline alignment.

- **DagCanvas.razor** - Read-only X6 DAG component with toolbar (LR/TB layout switching)
- **DagJsInterop** - Typed C# wrapper inheriting `GraphJsInteropBase`. Methods: `CreateGraphAsync`, `LoadGraphAsync`, `ZoomToFitAsync`, `ApplyStatusOverlayAsync`. No scattered `IJSRuntime.InvokeAsync("eval", ...)` calls.
- **TypeScript core:** create-graph.ts, dag-readonly.ts, werkr-node.ts, werkr-edge.ts
- **Dagre hierarchical layout** via layout-engine.ts - configurable TB/LR rank direction. The `tight-tree` ranker was chosen over `network-simplex` for dramatically better performance at scale (minutes → seconds for large graphs).
- **foreignObject HTML nodes** with Bootstrap styling: cards, badges, action-type indicators - enabling full HTML/CSS inside graph nodes rather than flat SVG text
- **parallel-lanes.ts** - Light background lanes behind same-level parallel nodes for visual concurrency indication
- **status-overlay.ts** - Color-coded execution status per selected run via `cell.setData()`. Consistent color language: Green=Success, Red=Failed, Amber=Running, Purple=Pending, Gray=Skipped.
- **X6 plugins:** Selection, Snapline, Scroller, Transform, MiniMap - all built into X6 3.x core
- **Type definitions:** dag-types.ts (node/edge DTOs), dotnet-interop.d.ts (.NET callback interface)

---

### Real-Time Run Monitoring & Execution Views

**Why:** The workflow debugging experience is the primary functionality for the product - building workflows happens once; debugging them happens daily.

- **Three-view tiered complexity** - different users need different detail levels (Compact for quick glance, Timeline for duration analysis, Detail for debugging)
- **Steps × Runs grid view** - the most effective at-a-glance cross-run pattern recognition, with color-coded cells making failures immediately visible
- **Gantt charts** - essential for bottleneck identification and understanding parallelism
- **Sparkline bar charts** - quick pattern recognition for duration and failure trends without drilling in
- **Event grouping** - collapsing related events (Scheduled→Started→Completed) into one logical unit reduces cognitive load
- **Real-time liveness** - all views update as events stream, rather than polling on a timer
- **Task-level I/O inspection** - see exactly what went in/out at every task boundary
- **Saved filter views** - operators managing many workflows need personalized, filtered views by status, agent, tag, and owner

**Workflow event types** in `Werkr.Core/Communication/`:

- **WorkflowEvent.cs** - Six new event types: `StepStartedEvent`, `StepCompletedEvent`, `StepFailedEvent`, `StepSkippedEvent`, `RunCompletedEvent`, `LogAppendedEvent`
- **WorkflowEventBroadcaster** - Singleton fan-out via `System.Threading.Channels`. Published from gRPC service handlers (`JobReportingGrpcService`, `OutputStreamingService`, `VariableService`) when agents report execution progress.
- **WorkflowEventSubscription** - Consumer subscription pattern for SSE endpoints

**Real-time data pipeline:**

```
Agent → gRPC → API WorkflowEventBroadcaster → SSE stream → JobEventRelayService → SignalR WorkflowRunHub → Browser
```

- **WorkflowRunHub** - SignalR hub at `/hubs/workflow-run`. Authorized clients join groups keyed by run ID to receive `StepStatusChanged`, `RunCompleted`, and `LogAppended` events.
- **JobEventRelayService** - `BackgroundService` + `IHealthCheck` that opens a long-lived SSE connection to `GET /api/events/workflow-runs` via the `"ApiServiceSse"` named `HttpClient`, deserializes events, and relays them to the hub via `IHubContext<WorkflowRunHub>`. Auto-reconnects with exponential backoff (1s → 30s). Tracks active run subscriptions in a `ConcurrentDictionary`. Registered as health check (`"sse-relay"`) for operational visibility into SSE connection status.
- **ConnectionStatus.razor** - Visual indicator (Live / Reconnecting / Polling) in the UI
- **RunDetail.razor** - Multi-view run detail page (Compact / Timeline / Log tabs)
- **GanttTab.razor** + **TimelineJsInterop** - vis-timeline Gantt chart showing horizontal bars per task with duration and status. Live bars grow during active runs via SignalR push.
- **RunSparkline.razor** - Server-side SVG mini bar charts (bar height = duration, bar color = status) inline on the workflow list
- **RunGridView.razor** - Steps × Runs 2D status matrix for cross-run comparison
- **StepDetailPanel.razor** - Step-level log preview and error messages
- **TimelineView.razor** - Chronological step execution list with attempt tracking and event grouping
- **SavedFilterService** + **FilterBar.razor** - Named saved filter views persisted via localStorage. Backed by a full filter model ecosystem: `FilterField`, `FilterDefinition`, `FilterCriteria`, `FilterFieldType`, `SavedFilterView` in `Werkr.Common/Models/`.
- **SignalR DTOs** - `StepStatusDto`, `RunStatusDto`, `LogLineDto` in `WorkflowRunHubDtos.cs` - typed payloads for each hub broadcast method
- **Additional DTOs** - `RunSparklineDto`, `StepStatusSummaryDto`, `AnnotationDto`, `DagValidationResult` in `Werkr.Common/Models/`
- Dedicated SSE `HttpClient` (`"ApiServiceSse"`) configured with infinite timeout and no resilience handlers in Program.cs

---

### API Endpoints & Batch Operations

**Batch save endpoint** - The server-side contract for the editor's batch-save architecture:

- `POST /api/workflows/{workflowId}/steps/batch` - Atomic batch operations for editor save. Accepts a `WorkflowStepBatchRequest` containing ordered step operations.
- **Sign convention**: negative `StepId` = temp ID (new nodes created in the editor), positive = real ID (existing nodes). The response includes `StepIdMapping[]` for temp→real ID resolution after save.
- **WorkflowStepBatchModels.cs** - `WorkflowStepBatchRequest`, `StepBatchOperation`, `DependencyBatchItem`, `WorkflowStepBatchResponse`, `StepIdMapping`

**Run management:**

- `POST /api/workflows/{id}/runs/{runId}/retry-from/{stepId}` - Retry from a failed step with optional variable overrides via `RetryFromFailedRequest`

**SSE event streams:**

- `GET /api/events/workflow-runs` - Dedicated SSE stream for workflow run events (consumed by `JobEventRelayService`)
- `GET /api/workflows/runs/{runId}/events` - Per-run filtered event stream
- `GET /api/events/jobs` - Existing job event stream (backward-compatible)

**Saved filter persistence:**

- Full CRUD at `/api/filters/{pageKey}` (GET list, POST create, PUT update, DELETE) with page keys for runs, workflows, jobs, agents, schedules, tasks. Admin-only share toggle.

---

### Consistent Color Standard & Theme System

**Why:** A consistent color language across all views - where the same semantic colors map to the same states throughout the entire UI - is essential for quick visual parsing.

- **CSS custom properties** in theme.css defining a standardized palette with dark/light theme support:
  - Status: `--werkr-success` (#28a745), `--werkr-failed` (#dc3545), `--werkr-running` (#ffc107), `--werkr-pending` (#6f42c1), `--werkr-skipped` (#6c757d), `--werkr-not-run`
  - Node types: `--werkr-node-default`, `--werkr-node-conditional`, `--werkr-node-fallback`, `--werkr-node-loop`
  - Structural: `--werkr-edge-color`, `--werkr-node-stroke`, `--werkr-parallel-group-bg`, `--werkr-snapline`
- Applied consistently across DAG nodes, sparklines, grid view cells, Gantt bars, and status badges

---

### JS/TS Build Infrastructure

**Why:** The X6 graph engine, vis-timeline, and Dagre layout all require a proper JS/TS build pipeline. Keeping all drag, zoom, pan, and connection drawing in the browser while reserving SignalR round-trips for state commits.

- **TypeScript 5.9** project with strict mode under `src/Werkr.Server/graph-ui/`
- **esbuild** bundler (~50ms incremental builds) with code-split output to `wwwroot/js/dist/`: `dag-readonly.js`, `dag-editor.js`, `timeline-view.js`, plus shared vendor chunks. Editor bundle lazy-loaded only when entering edit mode.
- **MSBuild integration** in Werkr.Server.csproj: `EnsureNode` → `NpmInstall` → `BuildGraphUi` targets fire automatically during `dotnet build`. No separate npm steps needed during development.
- **Vitest 3.0** test runner with 7 unit tests covering changeset operations, cycle detection, draft storage, clipboard handling, timeline item mapping, and status styling
- **Blazor<->JS interop hierarchy:** `GraphJsInteropBase<T>` manages `IJSObjectReference` + `DotNetObjectReference` lifecycle with `IAsyncDisposable`. Three derived classes: `DagJsInterop` (read-only), `DagEditorJsInterop` (editor), `TimelineJsInterop` (Gantt).
- `.nvmrc` pins Node.js 22. `.gitignore` excludes `node_modules/` and `wwwroot/js/dist/`.

---

### CI/CD & Dependency Updates

- **CI workflow** (ci.yml): Added Node.js 22 setup → `npm ci` → Vitest → `npm run build:prod` → bundle size check via check-bundle-size.mjs (250 KB gzipped budget)
- **DocFX workflow** (DocFX_gh-pages.yml): Simplified from multi-job Windows workflow to single Ubuntu-based job
- **NuGet dependency updates** in Directory.Packages.props: Microsoft.Extensions, ASP.NET Core, EF Core, SignalR, and test packages updated to latest patch versions
- **Lock file updates** across all projects to match new package versions
- **Cross-platform test fix** in UrlValidatorTests.cs: `RelativeUrl_Rejected` test now handles Unix vs. Windows URI parsing differences
- **`System.Text.Json` transitive dependency** update in installer project

---

### New Dependencies

| Package | Version | Purpose |
|---------|---------|---------|
| `@antv/x6` | 3.1.6 | Graph visualization & editing engine (MIT) |
| `dagre` | 0.8.5 | Hierarchical DAG layout (MIT) |
| `vis-timeline` | 7.7.3 | Gantt timeline rendering (Apache-2.0 / MIT) |
| `vis-data` | 7.1.9 | Reactive data containers for vis-timeline (Apache-2.0 / MIT) |
| `typescript` | 5.9.x | TypeScript compiler |
| `esbuild` | 0.27.x | Bundler |
| `vitest` | 3.0.x | Test runner |

No new NuGet packages - all required .NET packages already existed in Directory.Packages.props.

### New Prerequisite

- **Node.js 22+** required on dev machines and CI agents
@tsmarvin tsmarvin requested a review from Copilot March 14, 2026 22:42
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 165 out of 224 changed files in this pull request and generated 9 comments.

Files not reviewed (4)
  • src/Werkr.Data.Identity/Migrations/Postgres/20260312050754_InitialCreate.Designer.cs: Language not supported
  • src/Werkr.Data.Identity/Migrations/Sqlite/20260312050800_InitialCreate.Designer.cs: Language not supported
  • src/Werkr.Data/Migrations/Postgres/20260314004316_InitialCreate.Designer.cs: Language not supported
  • src/Werkr.Data/Migrations/Sqlite/20260314004323_InitialCreate.Designer.cs: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Werkr.Server/Program.cs
Comment thread src/Werkr.Server/Components/Shared/GanttTab.razor Outdated
Comment thread src/Werkr.Core/Scheduling/RetryFromFailedService.cs
Comment thread src/Werkr.Api/Services/OutputStreamingGrpcService.cs Outdated
Comment thread src/Werkr.Server/Components/Pages/Jobs/Index.razor Outdated
Comment thread src/Test/Werkr.Tests.Server/Authorization/PageAuthorizationTests.cs Outdated
Comment thread src/Werkr.AppHost/packages.lock.json Outdated
Comment thread src/Werkr.Api/Werkr.Api.csproj.user Outdated
Comment thread src/Werkr.Server/Components/Pages/Agents/Console.razor Outdated
tsmarvin and others added 2 commits March 14, 2026 16:08
- Remove .user files
- Run IDE Code Cleanup and dotnet format
@tsmarvin tsmarvin requested a review from Copilot March 15, 2026 00:41
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 158 out of 233 changed files in this pull request and generated 10 comments.

Files not reviewed (4)
  • src/Werkr.Data.Identity/Migrations/Postgres/20260312050754_InitialCreate.Designer.cs: Language not supported
  • src/Werkr.Data.Identity/Migrations/Sqlite/20260312050800_InitialCreate.Designer.cs: Language not supported
  • src/Werkr.Data/Migrations/Postgres/20260314004316_InitialCreate.Designer.cs: Language not supported
  • src/Werkr.Data/Migrations/Sqlite/20260314004323_InitialCreate.Designer.cs: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Werkr.Data/WerkrDbContext.cs
Comment thread src/Werkr.Api/Endpoints/FilterEndpoints.cs
Comment thread src/Werkr.Api/Endpoints/FilterEndpoints.cs Outdated
Comment thread src/Werkr.Common/Models/SavedFilterView.cs
Comment thread src/Werkr.Core/Scheduling/RetryFromFailedService.cs
Comment thread src/Werkr.Core/Scheduling/RetryFromFailedService.cs Outdated
Comment thread src/Werkr.Server/Components/Pages/Workflows/Runs.razor Outdated
Comment thread src/Werkr.Server/Components/Shared/LogViewer.razor Outdated
Comment thread src/Werkr.Core/Communication/WorkflowEventBroadcaster.cs
Comment thread src/Werkr.Server/Components/Shared/DagEditorCanvas.razor Outdated
@tsmarvin tsmarvin requested a review from Copilot March 15, 2026 02:31
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 155 out of 238 changed files in this pull request and generated 9 comments.

Files not reviewed (4)
  • src/Werkr.Data.Identity/Migrations/Postgres/20260312050754_InitialCreate.Designer.cs: Language not supported
  • src/Werkr.Data.Identity/Migrations/Sqlite/20260312050800_InitialCreate.Designer.cs: Language not supported
  • src/Werkr.Data/Migrations/Postgres/20260314004316_InitialCreate.Designer.cs: Language not supported
  • src/Werkr.Data/Migrations/Sqlite/20260314004323_InitialCreate.Designer.cs: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Werkr.Server/Components/Shared/GanttTab.razor
Comment thread src/Werkr.Server/Components/Shared/GanttTab.razor
Comment thread src/Werkr.Core/Scheduling/RetryFromFailedService.cs
Comment thread src/Werkr.Core/Scheduling/RetryFromFailedService.cs
Comment thread src/Werkr.Core/Scheduling/RetryFromFailedService.cs
Comment thread src/Werkr.Api/Services/ScheduleInvalidationDispatcher.cs
Comment thread src/Werkr.Server/Components/Pages/Workflows/Runs.razor Outdated
Comment thread src/Werkr.Server/Components/Shared/RunGridView.razor Outdated
Comment thread src/Werkr.Server/Components/Pages/Tasks/Index.razor Outdated
@tsmarvin tsmarvin requested a review from Copilot March 15, 2026 04:41
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 154 out of 238 changed files in this pull request and generated 10 comments.

Files not reviewed (4)
  • src/Werkr.Data.Identity/Migrations/Postgres/20260312050754_InitialCreate.Designer.cs: Language not supported
  • src/Werkr.Data.Identity/Migrations/Sqlite/20260312050800_InitialCreate.Designer.cs: Language not supported
  • src/Werkr.Data/Migrations/Postgres/20260314004316_InitialCreate.Designer.cs: Language not supported
  • src/Werkr.Data/Migrations/Sqlite/20260314004323_InitialCreate.Designer.cs: Language not supported
Comments suppressed due to low confidence (1)

src/Werkr.Core/Scheduling/RetryFromFailedService.cs:1

  • RetryFromFailedService introduces critical workflow state transitions (CAS status update, downstream reset, variable override versioning, schedule creation) but no automated tests are shown for this behavior. Adding unit/integration coverage for (1) downstream-step closure, (2) attempt increment semantics, (3) variable override version increments, and (4) transactional rollback on failure would help prevent regressions in a high-impact path.
using Microsoft.EntityFrameworkCore;

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Werkr.Server/Components/Shared/EditorToolbar.razor Outdated
Comment thread src/Werkr.Server/Components/Shared/EditorToolbar.razor Outdated
Comment thread src/Werkr.Server/Components/Shared/EditorToolbar.razor Outdated
Comment thread src/Werkr.Server/Components/Shared/EditorToolbar.razor
Comment thread src/Werkr.Server/Components/Shared/RunGridView.razor Outdated
Comment thread src/Werkr.Server/Components/Shared/RunGridView.razor Outdated
Comment thread src/Werkr.Api/Services/VariableGrpcService.cs Outdated
Comment thread src/Werkr.Api/Services/OutputStreamingGrpcService.cs
Comment thread src/Werkr.Core/Scheduling/ScheduleService.cs
Comment thread src/Werkr.Server/Components/Pages/Workflows/Runs.razor Outdated
@tsmarvin tsmarvin requested a review from Copilot March 15, 2026 05:58
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 154 out of 239 changed files in this pull request and generated 8 comments.

Files not reviewed (4)
  • src/Werkr.Data.Identity/Migrations/Postgres/20260312050754_InitialCreate.Designer.cs: Language not supported
  • src/Werkr.Data.Identity/Migrations/Sqlite/20260312050800_InitialCreate.Designer.cs: Language not supported
  • src/Werkr.Data/Migrations/Postgres/20260314004316_InitialCreate.Designer.cs: Language not supported
  • src/Werkr.Data/Migrations/Sqlite/20260314004323_InitialCreate.Designer.cs: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Werkr.Data/WerkrDbContext.cs
Comment thread src/Werkr.Server/Components/Shared/DagCanvas.razor
Comment thread src/Werkr.Server/Components/Shared/RunGridView.razor Outdated
Comment thread src/Werkr.Server/Components/Shared/RunSparkline.razor
Comment thread src/Werkr.Core/Communication/WorkflowEventBroadcaster.cs Outdated
Comment thread src/Werkr.Api/Services/VariableGrpcService.cs Outdated
Comment thread src/Werkr.Data/Entities/Workflows/WorkflowStep.cs
Comment thread src/Werkr.Api/Services/OutputStreamingGrpcService.cs Outdated
@tsmarvin tsmarvin requested a review from Copilot March 15, 2026 07:02
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 154 out of 239 changed files in this pull request and generated 6 comments.

Files not reviewed (4)
  • src/Werkr.Data.Identity/Migrations/Postgres/20260312050754_InitialCreate.Designer.cs: Language not supported
  • src/Werkr.Data.Identity/Migrations/Sqlite/20260312050800_InitialCreate.Designer.cs: Language not supported
  • src/Werkr.Data/Migrations/Postgres/20260314004316_InitialCreate.Designer.cs: Language not supported
  • src/Werkr.Data/Migrations/Sqlite/20260314004323_InitialCreate.Designer.cs: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Werkr.Server/Components/Shared/DagCanvas.razor Outdated
Comment thread src/Werkr.Server/Components/Shared/RunGridView.razor.css Outdated
Comment thread src/Werkr.Server/Components/Pages/Workflows/Runs.razor Outdated
Comment thread src/Werkr.Server/Components/Pages/Workflows/Runs.razor Outdated
Comment thread src/Werkr.Server/Components/Pages/Workflows/Runs.razor
Comment thread src/Werkr.Server/Components/Shared/ConditionBuilder.razor
@tsmarvin tsmarvin requested a review from Copilot March 15, 2026 08:19
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 152 out of 237 changed files in this pull request and generated 7 comments.

Files not reviewed (4)
  • src/Werkr.Data.Identity/Migrations/Postgres/20260312050754_InitialCreate.Designer.cs: Language not supported
  • src/Werkr.Data.Identity/Migrations/Sqlite/20260312050800_InitialCreate.Designer.cs: Language not supported
  • src/Werkr.Data/Migrations/Postgres/20260314004316_InitialCreate.Designer.cs: Language not supported
  • src/Werkr.Data/Migrations/Sqlite/20260314004323_InitialCreate.Designer.cs: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Werkr.Core/Scheduling/RetryFromFailedService.cs
Comment thread src/Werkr.Api/Services/VariableGrpcService.cs
Comment thread src/Werkr.Server/Components/Shared/GanttTab.razor
Comment thread src/Werkr.Server/Components/Shared/DagCanvas.razor
Comment thread src/Werkr.Api/Services/OutputStreamingGrpcService.cs
Comment thread src/Werkr.Server/Components/Shared/FilterBar.razor
Comment thread src/Werkr.Data/WerkrDbContext.cs
@tsmarvin tsmarvin merged commit b672b00 into refactor/additional-actions Mar 16, 2026
@tsmarvin tsmarvin deleted the bugfix/workflow-expectations branch March 16, 2026 07:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants