feat(web): NF-UI-9 — version diff + revert #395

Merged
code-lead merged 3 commits from dev/339 into main 2026-04-26 19:56:04 +00:00
Collaborator

Adds version inspection, diff overlay, and revert for flow graphs.

Test plan

  • Navigate to /flows/:id — "Version history" link appears in breadcrumb
  • Click "Version history" → /flows/:id/versions lists every version with author, timestamp, and node-change counts (green +, red −, amber ~)
  • Click "View →" on any row → /flows/:id/v/:version opens the historical canvas with the amber VersionBanner
  • "Compare to current" toggle merges the current body into the canvas: green outline = added since this version, red = removed, amber = changed args/inputs
  • Select a changed node → Inspector "Diff" tab is enabled; shows per-key deltas (added green, removed red, changed amber with old/new values)
  • "Revert to v{N}" button calls POST /flows/:id/revert?version=N and shows a success toast

Closes #339

Adds version inspection, diff overlay, and revert for flow graphs. ## Test plan - Navigate to `/flows/:id` — "Version history" link appears in breadcrumb - Click "Version history" → `/flows/:id/versions` lists every version with author, timestamp, and node-change counts (green +, red −, amber ~) - Click "View →" on any row → `/flows/:id/v/:version` opens the historical canvas with the amber VersionBanner - "Compare to current" toggle merges the current body into the canvas: green outline = added since this version, red = removed, amber = changed args/inputs - Select a changed node → Inspector "Diff" tab is enabled; shows per-key deltas (added green, removed red, changed amber with old/new values) - "Revert to v{N}" button calls `POST /flows/:id/revert?version=N` and shows a success toast Closes #339
feat(web): NF-UI-9 — version diff + revert
Some checks failed
qa / qa (pull_request) Failing after 3m36s
qa / dockerfile (pull_request) Successful in 9s
dd48ef7fb5
- Add `/flows/:id/v/:version` route: read-only canvas pinned to a
  historical version with a VersionBanner and VersionToolbar
- "Compare to current" toggle: merges current and historical node sets
  into one canvas with color-coded outlines (green = current-only,
  red = version-only, amber = changed args/inputs)
- Inspector Diff tab: arg-level JSON key deltas (added/removed/changed)
  for the selected node when compare mode is active
- "Revert to this version" button: calls POST /flows/:id/revert
- Add `/flows/:id/versions` route: version history table with author,
  timestamp, and nodes added/removed/modified counts
- Wire "Version history" link into the flow editor toolbar
- Enrich mock harness: listVersions now returns deterministic audit
  history up to the flow's current version

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix(ci): biome format + import-sort errors in version diff/revert files
All checks were successful
qa / qa (pull_request) Successful in 6m52s
qa / dockerfile (pull_request) Successful in 13s
7f3d38620b
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
dev requested review from reviewer 2026-04-26 19:29:24 +00:00
reviewer requested changes 2026-04-26 19:32:44 +00:00
Dismissed
reviewer left a comment
  • behavior (FlowCanvas.tsx, FlowCanvasVersion, handleRevert): After a successful revert the React Query cache is not invalidated. The current-flow query key ["flow", flowId, null] has staleTime: 60_000, so a user who reverts and navigates to the editor within 60 seconds will see the pre-revert body — and if they save, will overwrite the new revert version with the old graph. Fix: call queryClient.invalidateQueries({ queryKey: ["flow", flowId] }) after the showToast in handleRevert. The queryClient is already in scope via useQueryClient (used in EditorShell) — add the hook to FlowCanvasVersion and invalidate on success.

Everything else looks solid: all five AC items verified (list page, historical canvas, diff colour scheme, Inspector Diff tab, revert endpoint); CI green; mock handler for POST /flows/:id/revert and GET /flows/:id/versions both correct; computeNodeDiff logic is clean; Inspector.tsx DiffTab correctly handles all four diff kinds including the empty-state for kind === "unchanged".

- **behavior** (`FlowCanvas.tsx`, `FlowCanvasVersion`, `handleRevert`): After a successful revert the React Query cache is not invalidated. The current-flow query key `["flow", flowId, null]` has `staleTime: 60_000`, so a user who reverts and navigates to the editor within 60 seconds will see the pre-revert body — and if they save, will overwrite the new revert version with the old graph. Fix: call `queryClient.invalidateQueries({ queryKey: ["flow", flowId] })` after the `showToast` in `handleRevert`. The `queryClient` is already in scope via `useQueryClient` (used in `EditorShell`) — add the hook to `FlowCanvasVersion` and invalidate on success. Everything else looks solid: all five AC items verified (list page, historical canvas, diff colour scheme, Inspector Diff tab, revert endpoint); CI green; mock handler for `POST /flows/:id/revert` and `GET /flows/:id/versions` both correct; `computeNodeDiff` logic is clean; `Inspector.tsx` `DiffTab` correctly handles all four diff kinds including the empty-state for `kind === "unchanged"`.
fix(web): invalidate flow cache after revert in FlowCanvasVersion
Some checks failed
qa / qa (pull_request) Has been cancelled
qa / dockerfile (pull_request) Has been cancelled
7edb2bd050
After a successful revert, call `queryClient.invalidateQueries({ queryKey: ["flow", flowId] })`
so the cached current-flow body (staleTime 60 s) is evicted immediately — preventing
a stale pre-revert graph from being re-saved by the editor within the TTL window.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
dev left a comment

Fixed. Added useQueryClient() to FlowCanvasVersion and called queryClient.invalidateQueries({ queryKey: ["flow", flowId] }) immediately after the success toast in handleRevert — both the versioned and current-flow cache entries are now evicted on revert.

Fixed. Added `useQueryClient()` to `FlowCanvasVersion` and called `queryClient.invalidateQueries({ queryKey: ["flow", flowId] })` immediately after the success toast in `handleRevert` — both the versioned and current-flow cache entries are now evicted on revert.
dev force-pushed dev/339 from 7edb2bd050
Some checks failed
qa / qa (pull_request) Has been cancelled
qa / dockerfile (pull_request) Has been cancelled
to df182934b4
All checks were successful
qa / qa (pull_request) Successful in 6m57s
qa / dockerfile (pull_request) Successful in 13s
2026-04-26 19:40:21 +00:00
Compare
dev requested review from reviewer 2026-04-26 19:54:50 +00:00
reviewer approved these changes 2026-04-26 19:55:42 +00:00
reviewer left a comment

Cache invalidation fix confirmed: useQueryClient added to FlowCanvasVersion, invalidateQueries({ queryKey: ["flow", flowId] }) called after the success toast. CI green. All five AC items verified in round 1 remain intact.

Cache invalidation fix confirmed: `useQueryClient` added to `FlowCanvasVersion`, `invalidateQueries({ queryKey: ["flow", flowId] })` called after the success toast. CI green. All five AC items verified in round 1 remain intact.
code-lead deleted branch dev/339 2026-04-26 19:56:05 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/claude-hooks!395
No description provided.