Skip to content

fix(frontend): align add-node button consistently across node types - #28

Merged
LukasHirt merged 1 commit into
mainfrom
fix/add-node-button-alignment
Jul 24, 2026
Merged

fix(frontend): align add-node button consistently across node types#28
LukasHirt merged 1 commit into
mainfrom
fix/add-node-button-alignment

Conversation

@LukasHirt

Copy link
Copy Markdown
Collaborator

Summary

The "+" add-next button was duplicated verbatim across TriggerNode.vue, LlmNode.vue and ActionNode.vue, and positioned with an arbitrary right: -28px offset 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:

  • The trigger's pill-shaped border-radius: 24px 8px 8px 24px only rounds the left corners (order is top-left/top-right/bottom-right/bottom-left) — the right edge, where the button sits, uses the same 8px radius as the action/LLM cards on all three node types. Not the cause.
  • Bounding-box measurements showed the button was already numerically centered/consistent across all three node types (vertical delta 0.00px, offset-from-edge identical to the hundredth of a pixel on trigger/llm/action) — so it wasn't "inconsistent between node types" in the way described.

The real, visually-confirmed issue: the button was anchored to the card via a disconnected, arbitrary -28px magic 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 via docker 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

  • Added a shared frontend/src/components/nodes/NodeAddButton.vue component and switched TriggerNode.vue, LlmNode.vue, ActionNode.vue to use it, eliminating the triplicated markup (the ticket's 3rd concern — a real, confirmed contributor to future drift risk).
  • Fixed .workflows-node-add-button in frontend/src/styles/canvas.css to 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 added display:flex; align-items:center; justify-content:center so the "+" glyph is reliably centered in the circle rather than relying on default inline text layout.

Test plan

  • Added 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.
  • Confirmed this test fails against the pre-fix code for the right reason (received 29.098..., expected <= 6 — the button floating away from the card edge), then confirmed it passes after the fix.
  • Full existing e2e suite (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.
  • Visually verified via Playwright screenshots against the real running stack (trigger/LLM/action node crops) before and after the fix.

🤖 Generated with Claude Code

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>
@LukasHirt
LukasHirt requested a review from a team as a code owner July 24, 2026 16:28
@LukasHirt LukasHirt self-assigned this Jul 24, 2026
@LukasHirt
LukasHirt merged commit 2bd00a0 into main Jul 24, 2026
5 checks passed
@LukasHirt
LukasHirt deleted the fix/add-node-button-alignment branch July 24, 2026 20:41

@dj4oC dj4oC left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants