feat(web): flow canvas editing — palette, connect, validate, save (NF-UI-3) #351

Merged
code-lead merged 1 commit from feat/333-nfui3-canvas-editing into main 2026-04-24 13:15:15 +00:00
Collaborator

Summary

Upgrades the NF-UI-2 read-only FlowCanvas into a proper editor.

  • Palette (apps/web/src/features/flows/Palette.tsx) — Q hotkey + right-click opens a searchable, keyboard-navigable list of registry node types. Enter / click spawns the node at the cursor.
  • Node registry (apps/web/src/features/flows/nodeRegistry.ts) — hardcoded catalog of 35 node types across source / forge / agent / router / template / util, matching the server-side forge-nodes.ts + agent-nodes.ts + registry.ts surface. Temporary until NF-7 lands GET /flows/registry; explicitly called out in the file's doc comment.
  • Canvas editing (apps/web/src/features/flows/FlowCanvas.tsx) — React Flow v12 isValidConnection refuses mismatched port types + cycles (BFS forward from target); onBeforeDelete refuses the source node and lets the rest through with an error toast. Ctrl/Cmd+S saves.
  • Toolbar — priority number input, mutex-group autocomplete (datalist sourced from every flow's mutex_group via flowsApi.list()), enabled checkbox, dirty dot next to the flow name, save button disabled until dirty. beforeunload prompt on navigation while dirty.
  • Mock mutation API (apps/web/src/features/flows/flowsApi.ts) — updateFlow runs a client-side validateGraph (unknown types, duplicate ids, port-type compatibility, cycle detection) then bumps version + persists to the in-memory store. A typed FlowValidationError carries { nodes, edges, global } so the UI highlights offending nodes (red outline via data.invalid) and toasts the summary.

Palette-UX decision

Treated unnamed edges (port_from / port_to both absent) as pure control-flow ordering rather than typed data edges — the NF-UI-2 seed fixtures use {from: "src", to: "fetch_pr"} to express "runs after", with the actual data dependency living in the target's inputs map. Validating those strictly against the registry's declared port types would flag every existing seed graph as invalid; the docstring on validateGraph calls this out explicitly.

Test plan

  • bun x vitest run src/features/flows/ — 39 tests pass (13 registry + 18 editing + 8 pre-existing canvas tests adapted to the editor surface)
  • bun x turbo run typecheck — clean
  • bun x biome check — clean
  • Smoke-test the palette on a running dev server (follow-up — needs real React Flow DOM)

Out of scope

  • Inspector panel + args widgets — NF-UI-4.
  • Input-reference picker — NF-UI-5.
  • Annotations + sticky notes — NF-UI-6.
  • Real PATCH /flows/:id endpoint — NF-7 (the mock keeps the shape stable; swapping is a one-file change).

Closes #333

🤖 Generated with Claude Code

## Summary Upgrades the NF-UI-2 read-only `FlowCanvas` into a proper editor. - **Palette** (`apps/web/src/features/flows/Palette.tsx`) — `Q` hotkey + right-click opens a searchable, keyboard-navigable list of registry node types. Enter / click spawns the node at the cursor. - **Node registry** (`apps/web/src/features/flows/nodeRegistry.ts`) — hardcoded catalog of 35 node types across `source` / `forge` / `agent` / `router` / `template` / `util`, matching the server-side `forge-nodes.ts` + `agent-nodes.ts` + `registry.ts` surface. Temporary until NF-7 lands `GET /flows/registry`; explicitly called out in the file's doc comment. - **Canvas editing** (`apps/web/src/features/flows/FlowCanvas.tsx`) — React Flow v12 `isValidConnection` refuses mismatched port types + cycles (BFS forward from target); `onBeforeDelete` refuses the `source` node and lets the rest through with an error toast. `Ctrl/Cmd+S` saves. - **Toolbar** — priority number input, mutex-group autocomplete (datalist sourced from every flow's `mutex_group` via `flowsApi.list()`), enabled checkbox, dirty dot next to the flow name, save button disabled until dirty. `beforeunload` prompt on navigation while dirty. - **Mock mutation API** (`apps/web/src/features/flows/flowsApi.ts`) — `updateFlow` runs a client-side `validateGraph` (unknown types, duplicate ids, port-type compatibility, cycle detection) then bumps `version` + persists to the in-memory store. A typed `FlowValidationError` carries `{ nodes, edges, global }` so the UI highlights offending nodes (red outline via `data.invalid`) and toasts the summary. ### Palette-UX decision Treated unnamed edges (`port_from` / `port_to` both absent) as pure control-flow ordering rather than typed data edges — the NF-UI-2 seed fixtures use `{from: "src", to: "fetch_pr"}` to express "runs after", with the actual data dependency living in the target's `inputs` map. Validating those strictly against the registry's declared port types would flag every existing seed graph as invalid; the docstring on `validateGraph` calls this out explicitly. ## Test plan - [x] `bun x vitest run src/features/flows/` — 39 tests pass (13 registry + 18 editing + 8 pre-existing canvas tests adapted to the editor surface) - [x] `bun x turbo run typecheck` — clean - [x] `bun x biome check` — clean - [ ] Smoke-test the palette on a running dev server (follow-up — needs real React Flow DOM) ## Out of scope - Inspector panel + `args` widgets — **NF-UI-4**. - Input-reference picker — **NF-UI-5**. - Annotations + sticky notes — **NF-UI-6**. - Real `PATCH /flows/:id` endpoint — **NF-7** (the mock keeps the shape stable; swapping is a one-file change). Closes #333 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(web): flow canvas editing — palette, connect, validate, save (NF-UI-3)
All checks were successful
qa / qa (pull_request) Successful in 4m38s
qa / dockerfile (pull_request) Successful in 10s
747765bb10
Upgrade the NF-UI-2 read-only FlowCanvas into an editor:
- Hardcoded node registry (35 nodes across source / forge / agent /
  router / template / util) mirroring the server catalog until NF-7
  lands `GET /flows/registry`.
- Searchable, keyboard-driven Palette (Q hotkey + right-click) spawning
  nodes at the cursor.
- React Flow isValidConnection refuses mismatched port types + cycles;
  Delete / Backspace removes non-source selections.
- Client-side validateGraph (unknown types, duplicate ids, port
  compatibility, cycle detection) wraps a mocked `updateFlow` that
  bumps `version` + returns the refreshed summary. Validation failure
  surfaces via a typed FlowValidationError that highlights offending
  nodes.
- Toolbar: priority input, mutex-group datalist (sourced from every
  flow's mutex_group), enabled toggle, Save button, dirty-dot + Ctrl/
  Cmd+S hotkey, beforeunload prompt when dirty.

Closes #333

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
code-lead deleted branch feat/333-nfui3-canvas-editing 2026-04-24 13:15:16 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
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!351
No description provided.