Workflow Visual Diff Design
Overview
Issue: #93 introduces a visual diff view for workflow definitions in @apitomy/flow-ui.
This design adds a new exported component, WorkflowDiffViewer, that compares two workflow definitions and
renders a graph-aware diff. The key goal is to separate semantic changes (structure/behavior) from cosmetic
changes (position-only edits and array ordering noise).
Goals
- Provide a visual diff for two workflow definitions using existing graph rendering patterns.
- Clearly classify nodes/edges as added, removed, changed, unchanged, or cosmetic-only.
- Keep comparison logic pure and independently testable.
- Surface version context in the UI so comparisons are anchored to meaningful labels.
Non-Goals
- No workflow registry, persistence layer, or version history backend.
- No merge/conflict resolution workflow.
- No migration strategy for in-flight instances across workflow versions.
Public API
Add a new exported component:
WorkflowDiffViewer
Proposed props shape:
baseWorkflow: WorkflowcompareWorkflow: Workflowtheme?: FlowTheme
Behavioral decisions:
- Identity matching uses IDs only.
- Node identity: same
node.id. - Edge identity: same
edge.id. versionis optional but surfaced prominently when present.- Labels resolve as
name (vN)whenversionexists. - Fallback order:
name, thenid.
Architecture
New UI Component
ui/src/components/WorkflowDiffViewer.tsx
Responsibilities:
- Accept base and compare workflows.
- Compute diff model in
useMemovia pure utility. - Render one overlaid React Flow graph with diff-aware styles.
- Show summary counts and legend.
- Show details panel for selected node/edge with before/after fields.
New Diff Utility Module
ui/src/diff/workflowDiff.ts
Responsibilities:
- Compare two workflows and return a typed
WorkflowDiffResult. - Normalize entities via ID maps.
- Ignore array ordering in
nodesandedgesarrays. - Classify changes and attach structured change metadata.
- Emit warning metadata for duplicate IDs.
New Diff Types Module
ui/src/diff/workflowDiffTypes.ts
Defines shared contracts for statuses, per-entity diff records, warnings, and summary counts.
Styling
ui/src/components/WorkflowDiffViewer.css
Defines status treatments for:
- added
- removed
- changed (semantic)
- cosmetic (position-only)
- unchanged
Includes styles for legend, warning banner, and detail panel.
Library Exports
Update ui/src/index.ts to export:
WorkflowDiffViewer- public diff types that hosts may consume
Diff Semantics
Node Classification
added: node exists only incompareWorkflow.removed: node exists only inbaseWorkflow.unchanged: node fields match semantically.cosmetic: onlypositionchanged.changed: semantic fields changed.
Node semantic fields:
typenameconfig
Node cosmetic field:
position
Edge Classification
added: edge exists only incompareWorkflow.removed: edge exists only inbaseWorkflow.unchanged: edge semantic fields unchanged.changed: one or more semantic fields changed.
Edge semantic fields:
sourcetargetconditionpriorityisDefaultlabel
Render Data Flow
- Receive
baseWorkflowandcompareWorkflowprops. - Compute
WorkflowDiffResultwithdiffWorkflows(base, compare). - Build render graph from union of node/edge IDs.
- Prefer compare-side position where present.
- Fallback to base-side position.
- Optionally run existing layout pass when positions are absent (
needsLayout/layoutWorkflow). - Render graph, legend, summary counts, and detail panel.
Error Handling and Warnings
- Do not throw for expected mismatch states (added/removed/changed).
- Return warning metadata for ambiguous input (for example, duplicate IDs).
- Show warnings in a non-blocking viewer banner.
- If layout cannot be applied, render with available coordinates.
Testing Strategy
Add unit tests for ui/src/diff/workflowDiff.ts covering:
- unchanged workflow
- node added/removed
- edge added/removed
- node semantic change (
name,type,config) - node cosmetic-only position change
- edge semantic changes (
source,target,condition,priority,isDefault,label) - array reordering ignored
- duplicate ID warnings
- label resolution with and without
version
Add focused component-level tests for deterministic formatting/summary logic where practical.
Verification commands during implementation:
npx vitest runnpx tsc --noEmit
File Impact
New files (planned):
ui/src/components/WorkflowDiffViewer.tsxui/src/components/WorkflowDiffViewer.cssui/src/diff/workflowDiff.tsui/src/diff/workflowDiffTypes.tsui/src/diff/workflowDiff.test.ts
Updated files (planned):
ui/src/index.ts- any existing shared style/theme files needed for status color tokens
Open Decisions Resolved
- Comparison source: explicit
baseWorkflow+compareWorkflowprops. - UI surface: new exported
WorkflowDiffViewercomponent. - Node identity: ID-only matching.
- Position diffs: cosmetic-only (not semantic changed).
- Edge semantics:
prioritychanges are semantic. - Version surfacing: show
vNprominently when available, fallback otherwise.