fix(frontend): align add-node button consistently across node types - #28
Conversation
The "+" add-next button was duplicated across TriggerNode, LlmNode and ActionNode with an arbitrary -28px offset from the card, leaving it floating away from Vue Flow's own connection handle at the card's edge instead of being coordinated with it. Consolidate the button into a shared NodeAddButton component and anchor it the same way Vue Flow anchors its handle (right: 0; translate(50%, -50%)) so both sit at the same point, consistently, regardless of a node's border-radius or width. Adds a Playwright regression test asserting the button's vertical centering and its offset from the card's right edge stay consistent across trigger/llm/action node types. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Lukas Hirt <info@hirt.cz>
dj4oC
left a comment
There was a problem hiding this comment.
Review: fix(frontend): align add-node button consistently across node types
Stats: +106/-26 across 6 files — already merged, so this is retrospective feedback rather than a merge-blocking review.
Overview
Fixes the "+" add-next button floating away from its card with a visible gap from Vue Flow's own connection handle, by anchoring it the same way Vue Flow anchors its handle (right: 0; transform: translate(50%, -50%)) instead of an arbitrary -28px offset, and extracts the previously triplicated button markup into a shared NodeAddButton.vue.
What stood out (in a good way)
The investigation write-up is the best part of this PR. It explicitly names two hypotheses from the originating ticket (border-radius asymmetry, inconsistent positioning between node types) and rejects both with evidence — the border-radius only affects the left corners on the pill-shaped trigger, not the right edge where the button sits, and bounding-box measurements showed the button was already numerically consistent across node types (not "inconsistent" as assumed). Only then does it land on the real cause: a disconnected -28px magic number unrelated to the actual card edge. That's exactly the right way to fix a visual bug — measure first, don't fix the hypothesis in the ticket just because it's there. I checked the CSS math on the actual fix: right: 0 places the button's edge flush with the card, and translate(50%, -50%) then shifts it by half its own width/height, landing its center exactly on the boundary line — the same technique Vue Flow's own .vue-flow__handle-right uses, which is why the comment's claim ("anchored the same way Vue Flow anchors its own handle") checks out rather than just sounding plausible.
The E2E test is equally well-grounded: it measures real rendered bounding boxes against a live dev stack, and the PR body quotes the actual pre-fix failure (received 29.098..., expected <= 6) rather than just asserting red-then-green happened.
Minor forward-looking note
The currently-open PR #27 (conditional branch node) adds ConditionNode.vue with its own hand-rolled pair of "+ True"/"+ False" buttons, built independently of this NodeAddButton.vue extraction (the two branches were developed in parallel off the same base). They do reuse the workflows-node-add-button CSS class, so they're not visually inconsistent, but the button markup (the type="button", aria-label, @click.stop boilerplate) gets duplicated a third time in that PR — exactly the kind of repetition this PR set out to eliminate. Once both land, it'd be worth extending NodeAddButton.vue with an optional label/branch-id, so a two-button "add-next" variant doesn't recreate the problem this PR just fixed. Not a defect in this PR — just a heads-up given the timing.
One very minor, non-blocking thought on the new E2E test: the ±1px tolerances (vertical centering, cross-node-type consistency) are tight enough that they could be sensitive to font-metric or device-pixel-ratio differences between local and CI environments, though the PR reports it passing in the real suite, so this is speculative rather than an observed problem.
Summary
Clean, well-verified fix with a genuinely good debugging narrative behind it. Nothing to flag as incorrect; the only actionable item is the small DRY follow-up once PR #27 lands.
🤖 Generated with Claude Code
Summary
The "+" add-next button was duplicated verbatim across
TriggerNode.vue,LlmNode.vueandActionNode.vue, and positioned with an arbitraryright: -28pxoffset from the card, unrelated to where Vue Flow's own connection handle (.vue-flow__handle-right) sits on that same edge.Actual root cause found (verified visually, not assumed): the two stated hypotheses in the ticket didn't hold up under inspection:
border-radius: 24px 8px 8px 24pxonly rounds the left corners (order is top-left/top-right/bottom-right/bottom-left) — the right edge, where the button sits, uses the same8pxradius as the action/LLM cards on all three node types. Not the cause.The real, visually-confirmed issue: the button was anchored to the card via a disconnected, arbitrary
-28pxmagic number instead of the card's actual edge, so it rendered floating ~18-29px away from the card with Vue Flow's own small connection-handle dot sitting in the empty gap between the card and the button — two separate, uncoordinated circular affordances instead of one clear "add next" button. Screenshots against a real running dev stack (oCIS + backend viadocker compose) confirmed this: before the fix there's a visible detached gap between the card, the handle dot, and the floating "+" button; after the fix the button sits flush at the card's edge, directly coordinated with the connection handle, identically across trigger/LLM/action nodes.Changes
frontend/src/components/nodes/NodeAddButton.vuecomponent and switchedTriggerNode.vue,LlmNode.vue,ActionNode.vueto use it, eliminating the triplicated markup (the ticket's 3rd concern — a real, confirmed contributor to future drift risk)..workflows-node-add-buttoninfrontend/src/styles/canvas.cssto anchor the same way Vue Flow anchors its own handle (right: 0; top: 50%; transform: translate(50%, -50%)), so the button straddles the card's edge at the same point as the handle instead of an arbitrary fixed offset — consistent regardless of border-radius or card width. Also addeddisplay:flex; align-items:center; justify-content:centerso the "+" glyph is reliably centered in the circle rather than relying on default inline text layout.Test plan
frontend/tests/e2e/add-node-button-alignment.spec.ts: builds a trigger → LLM → action chain and asserts, for each node type, that the add-button is vertically centered on its card (±1px) and sits within 6px of the card's right edge, plus that the edge-offset is identical (±1px) across all three node types.received 29.098..., expected<= 6— the button floating away from the card edge), then confirmed it passes after the fix.automation,build-workflow,event-trigger,run-workflow, plus the new spec) passes against a real docker-compose stack (oCIS + workflows-backend + fake-llm,--profile test).pnpm test:unit— 4 tests passed.pnpm check:types— clean.pnpm lint— clean.🤖 Generated with Claude Code