Skip to content

@memberjunction/ng-task-graph-editor

View and edit a TaskGraphSpec on a canvas — the one graph contract shared by design-time flows and runtime task graphs. Also the drop-in debugger for a live parent MJ: Tasks row.

Import TaskGraphSpec itself from @memberjunction/ai-core-plus. This package does not re-export it.

Stepping a live run? Start with the Workflow Debugger Guide. This README is the package API.

Layer: widgets (L1 canvas + L2 session wrap). No @angular/router. See UI Layering.


flowchart TD
    subgraph L2["L2 — session owner"]
        DBG["mj-task-graph-debugger"]
    end
    subgraph L1["L1 — paint only"]
        ED["mj-task-graph-editor"]
        RV["mj-task-graph-run-view"]
        TB["mj-task-graph-debug-toolbar"]
        VAR["mj-task-graph-variables"]
        PP["mj-task-graph-properties-panel"]
    end
    FE["@memberjunction/ng-flow-editor"]

    DBG --> TB
    DBG --> RV
    RV --> FE
    ED --> FE
    RV --> VAR
    ED --> PP

    style L2 fill:#7c5295,stroke:#563a6b,color:#fff
    style L1 fill:#2d6a9f,stroke:#1a4971,color:#fff
    style FE fill:#2d8659,stroke:#1a5c3a,color:#fff
SelectorJob
mj-task-graph-editorDesign-time: edit a TaskGraphSpec. Emits intent; the host saves.
mj-task-graph-run-viewRuntime paint: project rows + $.debug onto the same canvas. No RouteOperation.
mj-task-graph-debuggerDrop-in wrap: parent task id in, frames + verbs owned. Hosts stay zero-code.
mj-task-graph-debug-toolbarVCR chrome (Continue / Over / Into / Stop).
mj-task-graph-variablesInvocation / input / output in the left data pane.
mj-task-graph-properties-panelDesign-time field inspector.

The wrap is a wrap — not a rewrite. Canvas, toolbar, and Remote Operations are the ones Runs and the harness already used. New code is the shell so those hosts do not each re-subscribe to frames.


Terminal window
pnpm add @memberjunction/ng-task-graph-editor
import { TaskGraphEditorModule } from '@memberjunction/ng-task-graph-editor';
@NgModule({
imports: [TaskGraphEditorModule],
})
export class YourModule {}

Give it the parent task id. That is the whole contract.

<mj-task-graph-debugger
[ParentTaskID]="parentTaskId"
[WorkflowName]="name"
[AllowBreakpointEditing]="true"
[ShowChrome]="true"
[ShowVariables]="true"
(Settled)="onSettled()"
(PausedChange)="onPaused($event)"
(Frame)="onFrame($event)"
(NodeSelected)="onNode($event)"
(ConnectionSelected)="onEdge($event)"
(ControlFailed)="onControlFailed($event)">
</mj-task-graph-debugger>
InputDefaultNotes
ParentTaskIDParent MJ: Tasks row. Attach/detach frames and refresh $.debug on change.
WorkflowName'Workflow'Label in the chrome.
LiveUpdatestrueSubscribe to TaskGraphFrames when the provider has it.
PollIntervalSeconds3Fallback poll for the run view if frames are quiet.
Height'100%'
ShowLegendfalse
ShowCanvasToolbartrueZoom / pan / fit chip (starts minimized).
ToolbarVisibility'minimized'
ToolbarAlign'left'
AllowBreakpointEditingtrueRight-click Add / Remove Breakpoint. Compare IDs with HasBreakpoint (UUIDsEqual).
ShowVariablestrueLeft data pane.
ShowChrometrueVCR bar. Off if the host already has its own.
Enabledtrue
ReplayAtnullHistorical replay cursor.

Pause · Resume · Step('one' \| 'wave') · Cancel · ToggleBreakpoint · OverrideEdge · SkipTask · RetryTask · UpdateTaskInput · ForceCompleteTask · Refresh · HasBreakpoint · GetEdgeOverride.

ForceCompleteTask and UpdateTaskInput send the RO field payload (not output). For force complete that value becomes the step output downstream conditions evaluate against.

NodeSelected · ConnectionSelected · LegendToggled · SettledChange · PausedChange · Frame · ControlFailed · Settled.

  • TaskGraphFrames (duck-typed on the provider — GraphQL has it; others simply do not).
  • IRemoteOperationProvider.RouteOperation for every TaskGraph.* verb.
  • Re-read of $.debug after each control so a two-console write cannot drop breakpoints.

Hosts must not also attach frames or call RouteOperation for the same parent. Runs keeps stall/engine chrome by listening to (Frame).

The run view is L1 — props in, paint out. The wrap is L2 because its job is the session: it reads the parent row through ProviderToUse and writes via RouteOperation so every host does not re-implement the verbs. It never navigates. See UI Layering §5.


SpecToNodes / SpecToConnections in task-graph-canvas-adapter.ts project rows + overlay onto flow-editor. Rules that are easy to get wrong:

  • Queued (NextToRun): prerequisites Complete (or entry), not awaiting, not terminal, not in progress. Banner: Next — waiting for the engine. Incoming edge animates.
  • Running: In Progress. Solid pulse.
  • Awaiting user: breakpoint / start-paused. Banner: Waiting on you. Not drawn as a spinner.
  • Traveled edge: origin in {Complete, Failed, Cancelled} and dest in {In Progress, Complete, Failed, Cancelled}. Pending dests stay dashed — a gate has not fired.
  • Conditional: dashed until traveled, then solid, if label kept. Forced is always dotted with a hand. Untaken (skipped) edges are omitted unless forced.

One typed bag per surface, via UserInfoEngine — never localStorage.

KeyTypeDefault
mj.taskGraphRun.prefs.v1TaskGraphRunPrefs{ InvocationOpen: false, InvocationSplit: [22, 78] }

TaskGraphRunPrefsStore merges unknown JSON onto defaults. Size and openness are separate fields so minimizing the left pane and opening it again restores the width the user dragged.

The harness Starting Payload disclosure is a different bag (mj.aiTestHarness.prefs.v1) because it is harness chrome, not run-view chrome.


<mj-task-graph-editor
[Spec]="spec"
(SpecChange)="onSpec($event)"
(NodeSelected)="onNode($event)">
</mj-task-graph-editor>

Same canvas, no runtime overlay. Host owns persistence of the Flow agent’s steps/paths.