Skip to content

fix: reveal the editor on tab activation and anchor token boxes - #12

Merged
tranphucbol merged 1 commit into
mainfrom
fix/tab-activation-and-token-anchor
Sep 11, 2026
Merged

tranphucbol merged 1 commit into
mainfrom
fix/tab-activation-and-token-anchor

Conversation

@tranphucbol

@tranphucbol tranphucbol commented Sep 11, 2026 •

Copy link
Copy Markdown
Owner

1. Purpose & Motivation

Description

Two renderer bugs, both reported from normal use of the desktop app.

The tab strip went dead under an overlay. The Variables, Settings, Protos and Runner panes cover
the request editor but deliberately keep the tab strip drawn above them, on the promise that
returning to what you were editing is one click and no closing. Clicking a tab moved activeId and
nothing else, so the pane stayed up and the click appeared to do nothing.

The variable box landed in the wrong place. Clicking a {{token}} in a plain field opened its
value box below the field's left edge instead of below the token. On a URL bar holding six tokens
that is most of the window away from the one that was clicked, and the reader has to work out which
name the value belongs to.

Context & Flow

Click a tab in the strip → useTabsStore.activate(nodeId)
          │
          ├── [OLD] set({ activeId })
          │             └── overlay still set → EditorPane keeps rendering the pane
          │                                      └── strip repaints its selection, editor never returns
          │
          └── [NEW] set({ activeId }) → revealEditor()
                        └── useOverlayStore.dismiss() → overlay null
                                      └── EditorPane renders the request editor for activeId

Click a {{token}} in a Field → useTokenPills.onMouseUp → tokenAt(input.value, caret)
          │
          ├── [OLD] report(name, input.getBoundingClientRect())
          │             └── box anchors to the field → drops from its left edge
          │
          └── [NEW] report(name, anchorRect(input, token))
                        │
                        ├── no backdrop, or no pill for this offset → field rect (unchanged)
                        └── pill found → pill left/right + field top/height, clamped to the field
                                      └── box hangs under the clicked token

2. Key Changes

Description

revealEditor() in stores/tabs.ts dismisses the overlay, and open and activate both call it.
close deliberately does not: closing a tab hands activeId to a neighbour nobody asked to look
at, so uncovering the editor there would be an answer to a question the user did not ask.

anchorRect() in ui/TokenOverlay.tsx reads the geometry an <input> cannot give. The pill
backdrop behind the field is a real element, aligned character for character with the input by
construction, and each token is a <span> the browser has already measured. Pills now carry
data-token-from, so a click can find the pill for the offset it matched and take its horizontal
extent. Vertical extent still comes from the field, because the pill is a line box centred inside
it and anchoring to the pill's bottom would tuck the box under the text.

CodeMirror bodies already reported real token rects through template.ts; this brings plain fields
in line with them.

Technical Decisions

The dismissal lives in the store, not in TabStrip. Activation has four entrances — the strip, the
sidebar, the command palette and the search results — and a rule stated at one of them is a rule
the other three break. It is called outside set so a zustand updater never writes to a second
store and fires its subscribers from inside this one's.

The pill offset is a data attribute rather than a map of refs. Pills are rebuilt from value on
every render that can change one, there is one per token, and the only reader is a mouse handler
running long after the paint.

anchorRect clamps to the field and falls back to the field's own rect when the backdrop or the
pill is missing, so a token scrolled out of an overflow: hidden backdrop degrades to exactly the
previous behaviour instead of positioning the box off the control.

Critical Modules/Files

  • packages/desktop/src/renderer/stores/tabs.ts — a cross-store write. Every tab activation in the
    app now dismisses the overlay, including restore on workspace switch, which is safe only because
    session.ts already dismisses on a new engine port.
  • packages/desktop/src/renderer/ui/TokenOverlay.tsx — anchorRect depends on the backdrop being
    the input's immediately preceding sibling. Controls.tsx holds that invariant in both Field
    and CellField.

Recommended Review Order

  1. packages/desktop/src/renderer/stores/tabs.ts
  2. packages/desktop/src/renderer/ui/TokenOverlay.tsx
  3. test/renderer/stores.test.ts

3. Verification & Testing

Provide reproducible inputs or steps for each test case, followed by the result and supporting evidence.

  • With the Variables pane open and two tabs open, click the inactive tab — the request editor replaces the pane and shows that request

    Starting state for both runs: test/fixtures/http-ws with POST Login and GET Profile open, GET Profile active, Variables pane up with the tab strip above it.

    before-tab-1-overlay.png

    Before the fix, clicking POST Login moved the selection but left the Variables pane filling the editor area.

    before-tab-2-clicked.png

    After the fix, the same click shows the Login request editor with its URL and JSON body.

    after-tab-2-clicked.png

  • With the Settings pane open, open a request from the sidebar — the editor replaces the pane

  • With the Settings pane open, close a tab from the strip — the pane stays up and the editor is not revealed

  • Click a {{token}} near the right end of a long URL — the value box hangs under that token, not under the field's left edge

    URL set to {{http_url}}/api/v1/aev2/transactions?app_ids=241&access={{token}}, with {{token}} painted near the right edge of the field. Before the fix the box dropped from the field's left edge.

    before-token-anchor.png

    After the fix the box hangs directly under the clicked token.

    after-token-anchor.png

  • Click a different token in the same URL field — the box moves to the newly clicked token

  • Click a token inside a JSON body — the box still anchors to the token, unchanged from before

4. Impact and Scope

Renderer only. @preman/core and the CLI are untouched, and no engine message, workspace file or
stored state changes shape.

Behavioural change: any tab activation now closes an open overlay pane. A user who opened Settings,
switched to a tab and expected Settings to still be there will have to reopen it. That is the
reported bug, not a regression.

Three tests added to test/renderer/stores.test.ts covering activation, open and the close
exception. Full gate clean: typecheck, lint, format:check, and 1986 tests passing under
PREMAN_SKIP_PERF=1, the flag ci.yml sets.

@tranphucbol
tranphucbol merged commit c845754 into main Sep 11, 2026
3 checks passed
@tranphucbol
tranphucbol deleted the fix/tab-activation-and-token-anchor branch September 11, 2026 20:51
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.

1 participant