Skip to content

Commit ad976b4

Browse files
authored
fix(workflow): fit the room side-panel Flow chart to its panel (#1547)
Fixes #1513 Written-by: Dev Owner: Chief Reviewer: Reviewer Base: `176d33d034e741b68041c0676da1707001cb6e88` (`main` head at 2026-10-28T06:56Z) Tip SHA: `74de9c6c77e140bc34c4ef2f41f2125ebdc24b9a` Tree: `74147a95640c11f4e0f9cd7d2c167ec6d0d2e1a0` Replay note (Rework, 2026-10-28T07:00Z): the reviewed tip `5111163e` sat on `62023599`, four commits behind `main`, and `main` had meanwhile changed this exact file set (#1535, #1497, #1536, #1522). This commit's parent is the current `main` head, the PR's own hunks are merged with those changes by hand, and `main...head` lists exactly the four files. Changes made while replaying: - `plugins/workflow/client.js`: the fitted drawer keeps the plain `wf-canvas` class and is selected by `data-fit="drawer"`; the narrow CSS now reads `.wf-canvas[data-fit="drawer"] …`. #1522's stage-control test looks the drawer canvas up as `className === 'wf-canvas'`, so it needs no edit and `tests-ok` is green on the merge tree. - `docs/subsystems/workflow.md:36`: one table row now carries both #1522's stage-control sentence and this PR's fitted-drawer sentence. Invariant 12 no longer claims the Settings canvas "keeps its own scrolling world plane" — #1536 made it scale to its own width, so the sentence names that instead. - The old body's Settings sentence and the checkpoint's `checks.ran` were stale; both are replaced below with what this tip actually ran. ## What changed The drawer Flow tab mounted the same absolute-coordinate canvas as Settings → Workflow graphs: `.wf-plane{width:0}`, node centres at raw `GAP_X=188` columns, wires on a `left:-480px;width:960px` svg, all inside a `.wf-canvas{overflow:auto}` in a 400px panel whose content box is 364px. Nodes past the first column, their wires, the parallel-branch label and the run strip were cut at the panel edge, inside an inner horizontal scrollbar next to the drawer's own vertical one. - `fitPlane(nodes, panelWidth)` is the new pure helper (exported): it scales node **centres** (never the node boxes, so text stays readable) into `panelWidth - 2*FIT_PAD - NODE_W`, centres the graph horizontally, keeps `scale <= 1`, and returns fitted nodes plus the `scale` / `offsetX` / `offsetY` an edit needs to invert a pointer position. - The drawer Flow (`DRAWER_FLOW_W = 400 - 2*18 = 364`) renders the fitted nodes, wires with `wirePath(from, to, 0)` in the plane's own coordinates, and `parallelFrameStyle` over the fitted members. The plane gets the panel width and the wires svg follows it. The Settings canvas keeps `wirePath`'s default `WIRE_SPAN`; its width scaling and the page's own scroll are #1536's, untouched here. - The drawer canvas carries `data-fit="drawer"`: `min-height:0;align-items:stretch;overflow:hidden` so there is no inner scroll; `.wf-dr-body` keeps the single vertical scroll and gets `overflow-x:hidden`. `.wf-plabel` wraps (`white-space:normal;text-align:center;max-width:calc(100% - 16px)`) and the drawer `.wf-term` wraps too. - Editing still commits world coordinates: a drag stores `x + dx/scale` (the scale the drag started with, so fitting does not chase the pointer) and a dropped Bot maps `offsetX/offsetY` back through `offsetX`/`offsetY`. Wire, reconnect and the per-node inspector are unchanged. - Docs: the client.js row and invariant 12 in `docs/subsystems/workflow.md` now name the fitted drawer; `changelog.d/1513-workflow-panel-fit.fixed.md` is the fragment. ## Verification at the tip Tip SHA: `74de9c6c77e140bc34c4ef2f41f2125ebdc24b9a` (parent `176d33d0`) Ran on this tree (the committed blobs are byte-identical to the files these ran on — `git hash-object` matched the tree's blob shas for all four): - `node --test` over the eleven runnable `plugins/workflow/test/*.test.js` — 116 tests, 116 pass. - `node --test test/client.test.js` (in `plugins/workflow`) — 40 tests, 40 pass (34 from this PR plus #1522's six; the merge tree the Reviewer built failed one of those before this replay). - Red first: the same test file with `plugins/workflow/client.js` back at `main`'s blob — 35 pass, 5 fail: the four new fit tests plus `the sidebar opens the flowchart, and a drag, a wire and a dropped Bot are saved` (it now asserts the `delta/scale` mapping). - `node .github/scripts/changelog.mjs check` — 58 fragments well formed. - `node scripts/ds-bot-patches.mjs check` — 10 patches apply cleanly in order; `core/` equals `ds-bot/` + `patches/ds-bot/`; the pin is skipped here (no `git` history in the extracted tree) and this diff touches neither. - `node .github/scripts/check-mojibake.mjs --check` — 0 occurrences of U+FFFD in 1243 text files. - `node --check plugins/workflow/client.js` and `node --check plugins/workflow/test/client.test.js` — exit 0. - Diff from `main` `176d33d0`: 4 files, +192/−55 (client.js +98/−45, tests +91/−8, docs +2/−2, fragment +1) — inside the T2 limits (250 lines / 12 files). Not run (and why): - `test/host.test.js` and the core suite — they load the DSH harness (`npm run harness`), which is not installed on this box; CI runs them on Node 24. - `node scripts/lint-plugins.mjs` (oxlint) and `node core/scripts/build-client.mjs --check` (esbuild) — no `node_modules` here; CI runs both. - A live 400px browser recheck: this box has no browser. The acceptance is covered by the pure fit test, the wire-anchor/plane test, the CSS assertions and the drawer-vs-Settings mount test. ## Risk Expected **T2**: `plugins/workflow/client.js` is plugin code no `risk-rules.json` rule names (the T3 list covers `plugins/social/**` and `core/src/shared/**`, and an unnamed path is never silently T0/T1); no T3 `diffPatterns` hit; no `package.json` / lockfile. T0/T1 would need the change to be pure copy, which a layout mapping is not. Scope is the drawer Flow only: the Settings canvas scaling (that is #1536's), the graph record, the wire/reconnect semantics and the inspector are unchanged, and `fitPlane` never enlarges a graph. ## Checkpoint <!-- flybot:checkpoint --> ```json { "pr": 1547, "claim": "Chief", "issue": 1513, "summary": "The 400px room side-panel Flow tab now paints the graph fitted to the panel instead of the Settings world canvas. fitPlane scales node centres (never the node boxes) into the panel width, wires and parallel frames draw in that fitted space, and drag/drop pointer deltas are divided by the fit scale so the stored graph keeps world coordinates. Labels wrap instead of clipping mid-word and the inner horizontal scrollbar is gone; the Settings canvas keeps #1536's own scaling untouched.", "files": [ "plugins/workflow/client.js", "plugins/workflow/test/client.test.js", "docs/subsystems/workflow.md", "changelog.d/1513-workflow-panel-fit.fixed.md" ], "checks": { "ran": "plugins/workflow node --test (11 files) 116/116; client.test.js 40/40; red first with main's client.js blob 35/40 (5 fail: 4 new + drag/drop); changelog check 58 fragments; ds-bot-patches check 10 patches; mojibake ok; node --check exit 0", "result": "green", "at": "74de9c6c77e140bc34c4ef2f41f2125ebdc24b9a" }, "next": "none — ready for review; T2 needs the Reviewer's PASS at this tip (the REQUEST_CHANGES at 5111163 is void by the new commit)." } ``` <!-- /flybot:checkpoint -->
1 parent bf5e878 commit ad976b4

4 files changed

Lines changed: 192 additions & 55 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
The Workflow room's right-hand Flow tab fits the whole graph to its 400px panel: every node, wire endpoint and parallel-branch frame stays inside the panel, labels wrap instead of being cut mid-word, and the inner horizontal scrollbar is gone. The drawer stays editable — drag and drop still store the same world coordinates, now divided by the fit scale — while Settings keeps its scrolling canvas. ([#1513](https://github.com/ThinkFlowLab/FlyBot/issues/1513))

‎docs/subsystems/workflow.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ Everything in `plugins/workflow/`: the graph rules, the run store, the matcher,
3333
| `plugins/workflow/src/match.js` | Which open card matches a Workflow or a local Bot. |
3434
| `plugins/workflow/src/template.js` | 发布交付流水线 (a parallel branch) and the weekly report, each node with the inputs and outputs that edge carries. |
3535
| `plugins/workflow/src/narrate.js` | Progress lines for a step. A live run quotes the Bot reply when present; otherwise delivery-template nodes may use canned copy. A join line is only for a rank of more than one node. |
36-
| `plugins/workflow/client.js` | Sidebar section (with mini-flowcharts), workflow stage (view/control: one card per live run with its own title, node line, segment progress, status chip, and Pause / Resume / Stop; click a card or its Flow button to focus that run in the drawer flowchart; optional aggregate chip when several run or the queue is non-empty — no message composer), assign dialog (scrollable with sticky footer), flowchart drawer (collapsed by default, per-node inspector), and Settings → Workflow graphs (canvas-first with inspector panel). The product UI starts only live runs (assign, ingest). The stage shows the queue and refreshes state while runs are active; a running node uses a breathing border animation. Visual flowcharts replace text chains across all surfaces. Sidebar rows (including factory ids such as `delivery`) support Delete with confirm. The stage and dialogs portal onto `document.body`; a missing container stays in the section tree. A stage control that fails — a graph save, Reset, Pause, Resume or Stop that throws, rejects, answers `{ok:false}` or does not answer within 10 s — ends on the section's `.wf-err` alert instead of being swallowed, and a success clears the alert. |
36+
| `plugins/workflow/client.js` | Sidebar section (with mini-flowcharts), workflow stage (view/control: one card per live run with its own title, node line, segment progress, status chip, and Pause / Resume / Stop; click a card or its Flow button to focus that run in the drawer flowchart; optional aggregate chip when several run or the queue is non-empty — no message composer), assign dialog (scrollable with sticky footer), flowchart drawer (collapsed by default, per-node inspector, fitted to the 400px panel so the graph needs no inner horizontal scroll), and Settings → Workflow graphs (canvas-first with inspector panel). The product UI starts only live runs (assign, ingest). The stage shows the queue and refreshes state while runs are active; a running node uses a breathing border animation. Visual flowcharts replace text chains across all surfaces. Sidebar rows (including factory ids such as `delivery`) support Delete with confirm. The stage and dialogs portal onto `document.body`; a missing container stays in the section tree. A stage control that fails — a graph save, Reset, Pause, Resume or Stop that throws, rejects, answers `{ok:false}` or does not answer within 10 s — ends on the section's `.wf-err` alert instead of being swallowed, and a success clears the alert. |
3737

3838
## Entry points
3939

@@ -55,7 +55,7 @@ Everything in `plugins/workflow/`: the graph rules, the run store, the matcher,
5555
9. The browser draws text only. Names and messages are React text children. The unit renderer asserts a hostile name is not markup.
5656
10. `enabled: false` registers no endpoint, tool or listener and writes nothing.
5757
11. A sidebar click opens the stage or a dialog and leaves the Workflows section in place. The stage and the dialogs portal onto `document.body`. When that container is missing they stay in the section tree; the click does not throw.
58-
12. A node's prompt and the graph are one record. Settings → Workflow graphs (canvas-first with per-node inspector), the flowchart drawer (collapsed by default, inspector on select), and `define_workflow` all write `workflow/graph`. A run reads that record; it does not define it. After a live run finishes, the stage shows the last finished live run (`lane.last` with `live === true`) until a new live run starts.
58+
12. A node's prompt and the graph are one record. Settings → Workflow graphs (canvas-first with per-node inspector), the flowchart drawer (collapsed by default, inspector on select), and `define_workflow` all write `workflow/graph`. The drawer paints that record fitted to its fixed 400px panel: `fitPlane` scales node centres (never the node boxes) into the panel width, wires and parallel frames use the fitted positions, and a pointer delta is divided by the fit scale before it is stored, so an edit still commits the same world coordinates. The Settings canvas paints the same record scaled to its own width (invariant 2), not as a second scroll container. A run reads that record; it does not define it. After a live run finishes, the stage shows the last finished live run (`lane.last` with `live === true`) until a new live run starts.
5959

6060
## Tests
6161

0 commit comments

Comments
 (0)