Repository navigation
fix(app-shell): the flow designer's three add-node paths open one palette and add into the path (objectui#11778) - #11832
Merged
objectstack-fleet[bot] merged 3 commits intoOct 7, 2026
Conversation
…ette and add into the path Every "+" on the flow canvas (an edge's, a node's Add connected node, the toolbar's Add node) opens the same add-node palette, and the picked node goes into the flow's path: the edge "+" splits its edge, the other two put the node after a node (the selected one, else Start, for the toolbar) by one rule, `placeAfter`. A node inserted on an edge is no longer pinned at its endpoints' midpoint, so the layered layout places it. The node inspector's Node Type select offers the palette's list with its display names, so `notify` is offered and no raw type name is shown; the hand list FLOW_NODE_TYPE_OPTIONS it read is retired, and the table's own types (FLOW_NODE_CONFIG_TYPES) are what the sweep tests walk. Claude-Session: https://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8 Co-authored-by: Claude <noreply@anthropic.com>
…ot the Node Type trigger The Node Type select now names a connector_action node "Connector" (the palette's name), so an unscoped text query for "Connector" found two elements. The pin asks for the field's label, which is what it meant. Claude-Session: https://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8 Co-authored-by: Claude <noreply@anthropic.com>
…i#11778) Claude-Session: https://claude.ai/code/session_01CGZy1BGCjdN5cXqL9cnvB8 Co-authored-by: Claude <noreply@anthropic.com>
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
This was referenced Oct 7, 2026
objectstack-fleet
Bot
deleted the
claude/issue-11778-flow-add-node-paths
branch
October 7, 2026 21:40
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #11778
Clause-②: no
What was wrong, measured on
main(2b30d39)A probe through the real
FlowCanvason the draft Studio creates for a new flow (start → end, edgee1), before any change:create_recordnode at once, no palette, pinned atposition {x: 28, y: 89}: the midpoint of the two cards' corners, on top of the Start cardcreate_recordnode at once, no palette, wiredstart → node_1besidestart → end: a second branch that leads nowherenotifynode with no edge at allnotifynode as a second branchstart → node_1besidestart → end(the card's report)start; the list was the hand listFLOW_NODE_TYPE_OPTIONS, which has nonotifyand spellshttp_request,connector_actionandtry_catchrawWhat changed
Every "+" opens the one add-node palette. The edge's "+" and a card's "Add connected node" now wrap their button in the same
NodePalettethe toolbar uses (grouped, searchable, with Recently used). Nothing is added until a type is picked. The canvas keeps one key for which "+" has the palette open (toolbar,edge:EDGEKEYornode:ID), so at most one is open and a pick closes it wherever it was opened. No second picker was built.The picked node goes into the path, by one named rule. The edge "+" splits its edge, as before: A → B becomes A → N (the original edge, its id and guard kept) plus N → B. The other two entry points share
placeAfter, "add after this node":start → endbecomesstart → N → end);decision,approval,parallel_gateway), or one that already leads to two or more nodes, has no single path after it: N becomes a new branch from it. That is the existing append, so a decision still carries its next unused condition onto the new edge;"A way on" is a forward edge between two distinct nodes that both exist: a declared back-edge is not one, and neither is an edge naming a missing node (objectui#11772 leaves those for the Problems panel to name).
Because the canvas selects the node it adds, toolbar adds in a row build the path in order:
start → N1 → N2 → N3 → end(pinned).The inserted node is laid out. The edge insert no longer pins
positionat its endpoints' midpoint. The new node carries no position, like an append always did, so the layered layout gives it its own row and moves the nodes below it down. Nodes the author dragged keep their stored positions.The Node Type select is the palette's list.
FlowNodeInspectorreadsuseFlowNodePalette()(the hardcodedNODE_PALETTEmerged with the engine's published descriptors, the same list the canvas adds from) through a new module-local helperpaletteTypeOptions, which keeps the palette's order (its category sections) and its display names (translateNodeLabelover the palette's label, exactly as the palette draws them). Sonotifyis offered, no raw type name is shown, and an engine-published type joins the list as it joins the palette. A stored type the palette does not offer (start, the deprecated aliashttp_request, a plugin type whose engine is not answering) is added for that node only, under its display name, so the trigger still says what the node is.FLOW_NODE_TYPE_OPTIONSis retired. The select was its only production reader. Its six test readers used it as the population of a sweep over the inspector's field-group table; they now walkFLOW_NODE_CONFIG_TYPES, the table's own keys, a strict superset of the retired list (it addsnotify,boundary_event,parallel_gateway,join_gateway,legacy_action), so no sweep lost a type.flow-node-config.spec-reconciliation.test.tsnow also asserts its source-parsed table keys equal that export exactly.The PM's mechanism hypotheses, measured
addNode('create_record', { from }), and the toolbar passedfrom: selectedId, so with nothing selected it wrote no edge and with Start selected it wrote the second branch.FLOW_NODE_TYPE_OPTIONSreaders): one production reader (the select) and six test readers, handled as above.NodePalette): confirmed, with one finding. A palette opened from an edge or a card is portaled out of the canvas in the DOM but still sits inside the canvas viewport in the React tree, so a press on a palette row bubbled to the viewport's pan handler, which clears the selection and takes pointer capture; the browser then fires the click at the viewport and the row's select never runs (objectui#11546's shape).NodePalette's content now stops that press. Ablation B below shows the five edge- and card-palette picks red without it, and the toolbar's (outside the viewport) green.objectui#11772's pins
FlowPreview.removeNode-11772.test.tsxchanged in three places, none of them an assertion's strength:[], which is not the hook's offline answer (NODE_PALETTE, as the stub's own comment says) and leaves a palette with nothing to pick; it returnsNODE_PALETTEnow;node_1,edge_1) and its exacttoEqual, but its wiring is this card's:e1: start → node_1,edge_1: node_1 → end, where it used to pin the second branchstart → node_1besidestart → end, which is the defect this card reports.The byte-for-byte round trip assertion is unchanged and green.
FlowNodeInspector.removeEdges-11772.test.tsxandflow-problems.repeatedEdge-11772.test.tsare untouched and green.Tests
New pins, through the real components:
previews/FlowCanvas.addNodePaths-11778.test.tsx(11): each "+" opens the palette and adds nothing before a pick; the edge "+" with Notify givesstart → notify → end, keepse1, and the node has no position and sits a full row below Start with End moved below it; Add connected node on Start inserts into the path, on a node with no way on appends, on a decision adds a branch carrying itsElsedefault; the toolbar with nothing selected, with Start selected and with End selected, and three adds in a row. Palette rows are pressed withbrowserClick, which routes a click the way a browser does after pointer capture.inspectors/FlowNodeInspector.nodeTypeOptions-11778.test.tsx(6): the option list equals the palette's labels in its order, Notify included; no raw type name; picking Notify writestype: 'notify'; zh-CN names; Start shown as "Start" on its own node and not offered to another; an engine-published type joins the list.Touched existing tests:
FlowCanvas.test.tsx(the insert pin now asserts no position, and both gestures pick a type),flow-node-producers.label.test.tsx(both gestures pick a type),FlowNodeInspector.connectorInput.test.tsx(its text query for the "Connector" field label is scoped to the label, because the Node Type trigger now reads "Connector" too), and the six sweep tests above.Ablations, each through
ablation-replace.mjsfrom the committed tree at84f3800, each restore proven by blob hash equal to HEAD and an emptygit diff HEAD, over the two new pin files,FlowCanvas.test.tsxand the objectui#11772 pin file (50 tests):create_recordat once, no palette (the card's suggested ablation)FlowCanvas.test.tsxinsert pinaddNode(type, { from: selectedId })fromappendFlowCanvas.test.tsxposition pins; the 11772 round trip stays greenThe first attempt at B measured nothing: the tool refused it before running, because the replacement text was a substring of the anchor. It was re-run with a distinct marker; the row above is that run.
Browser check: Chromium (
/opt/pw-browsers/chromium) on the console's preview gallery (preview-gallery.html?only=flow, the offline palette), real mouse clicks. The edge "+" opened the palette beside the "+" and added nothing; picking Notify insertednode_1between Start and the next node on its own row (card tops after the pick: Start 28, new node 150, the next node 272); a card's "+" then Create record inserted below that card; the toolbar then put a Script node after the selected one; the inspector's Node Type read "Script" and listed the palette's 18 names, Notify among them; no page errors.Local verification at
3947a9a(HEAD):pnpm exec vitest runoverpackages/app-shell/src/views/metadata-admin/previews/,.../inspectors/and the two Studio files that count the canvas's "+" buttons: 230 files, 3043 passed, 1 skipped.pnpm --filter @object-ui/app-shell type-check: exit 0. Both of its projects ran;tsconfig.test.json --listFilesincludes every touched and new test file.pnpm exec eslinton the 16 touched.ts/.tsxfiles: 0 errors, 12 warnings, one more than onmain(areact-refresh/only-export-componentswarning for the newpaletteTypeOptionsexport, the same warning the file's seven other non-component exports carry).check:control-bytes,check:test-path-roots,check:changeset-claims,check:pending-changeset-literals,check:new-line-citations,check:vi-mock-specifiers,check:vi-mock-inherit,check:vi-mock-override-shape,check:unreferenced-sources,check-changeset-presence,check-changeset-no-major: all exit 0.@object-ui/app-shellsuite ran once, atacdf998: 1064 files, 2 failed. One wasFlowNodeInspector.connectorInput.test.tsx, the label query fixed in84f3800. The other,AppContent.inaccessibleAppStrand.test.tsx, failed on a network escape tolocalhost:3000under full-suite load; this branch does not touch it, and it passed alone. The suite was not re-run after84f3800, which changed a test file and the changeset only; CI runs it.Files and surface
Every file is on the claim's file surface:
FlowCanvas.tsx,flow-canvas-parts.tsx,flow-node-config.ts,FlowNodeInspector.tsx, tests inpreviews/andinspectors/, and.changeset/11778-flow-add-node-paths.md.i18n.tsis not touched: every string these entry points show already existed.StudioDesignSurface.tsxis not touched.Nothing is added to the package entry. After a build, none of the four changed source modules is reachable from
dist/index.d.tsby its relative imports (168 declaration files reached;SchemaForm.d.ts, which the entry re-exports, is the positive control). Patch changeset on@object-ui/app-shell.Acceptance notes
content/docs/guide/flow-designer.mdstill describes the card's "+" as "Append a connected child node", and its palette section names only the toolbar's Add node. It is not wrong, but it does not mention that every "+" opens the palette or the edge "+". It is off the claim's surface, so it is not edited here.GET /api/v1/automation/actionstwice per mount (useActionConfigSchemasanduseFlowNodePaletteeach runuseActionDescriptors). Sharing one read means changinguseFlowNodePalette.ts, which is off the surface; nearly every inspector test stubs that module by name, so a combined hook would also need those stubs changed.map, which the hand list had:NODE_PALETTEdoes not list it. The engine publishes amapdescriptor, so against a running backend the palette and the list both offer it.mainmoved tod53fd02after this branch was cut (objectui#11773, objectui#11780). Neither commit touches the flow canvas or inspector files; this branch has not merged it.Generated by Claude Code