Skip to content

fix(#429): resolve a saved query before navigating, trim blank tile titles (phase 1) - #490

Merged
BorisTyshkevich merged 2 commits into
mainfrom
fix/resolve-before-navigate-429p1
Jul 27, 2026
Merged

fix(#429): resolve a saved query before navigating, trim blank tile titles (phase 1)#490
BorisTyshkevich merged 2 commits into
mainfrom
fix/resolve-before-navigate-429p1

Conversation

@BorisTyshkevich

Copy link
Copy Markdown
Collaborator

What & why

Part of #429phase 1 of 6: the two prerequisites every later phase builds on. Both halves are corrections to primitives rather than features, so they land green and self-consistent on their own.

openSavedQuery resolves before it navigates (#443)

app.openSavedQuery(queryId) called showQuerySurface() before it knew whether the id resolved. An unresolved id therefore threw the user off whatever surface they were on, pushed a history entry, opened no tab and reported nothing — a dead click that also lost their place.

It resolves first now. A miss reports one diagnostic ("That query is no longer part of this workspace.", the wording openDashboard already uses for a missing Dashboard) and changes no surface, no route, no tab. A resolving id behaves exactly as before.

The issue asks for a caller audit before tightening. There are three production callers, and none depended on the unconditional switch:

Caller Why it is safe
src/ui/dashboard-tree.ts:289 — the row's open-query command addresses a query the row was just painted from
src/ui/dashboard-tree.ts:350 — the post-assignment reveal opens the id the assignment mutation just created
src/ui/dashboard.ts:1855 — per-tile Open in Workbench the button is null unless queryById.has(ts.queryId)

Not reachable through the tree today (#426 cancels pending clicks on workspace switch and disposal), which is precisely why it lands here: it goes live the moment phases 2–5 add more row commands over the same primitive.

A whitespace-only tile title never reaches a heading or an accessible name (#476)

dashboardTileV1.title carries no minLength, so a hand-authored or imported " " is a schema-legal document — and being truthy it beat the query-name fallback unfiltered. The visible .dash-tile-name heading rendered blank, and the names composed from it announced as "Open, — , in Workbench" and "Remove, — , from the dashboard".

The viewer now trims the authored title before the fallback chain, in the one place a tile's display title is resolved — so every consumer of state.title is settled at once: the heading, the KPI card aria-label, the Open in Workbench and Remove tile labels, the tile-search haystack, the parameter-analysis labels, and the variable-conflict diagnostic. A padded authored title is kept, trimmed.

This is a deliberate behaviour change for existing documents carrying such a title: they start showing the query name. No shipped UI writes tile.title, so only hand-authored and imported documents are affected. (dashboard-tree-model.ts already trimmed, so the tree row was correct and the canvas disagreed with it.)

Acceptance criteria claimed

Every other bullet is explicitly deferred: the pencil/trash row actions, the one-create-command reconcile (#481), the chevron/name/trailing gesture split (#472), ownership safety, concurrency, and the repair-planner decision (#449/#431) → phases 2–6. Per the issue's #438 note: this phase adds no focus-tile gesture, so no layout engine needs verifying for one.

Verification

  • npm test — 5816 passed, 177 files, per-file gate held (statements/lines 100%).
  • Sabotage-checked: with both production changes reverted, exactly the four new tests fail and nothing else — so they are genuinely falsifying, and no existing test depended on the old behaviour.
  • npx tsc --noEmit clean; npm run build clean.
  • npm run test:e2e — 281 passed on chromium + webkit (Firefox can't launch locally; it comes from CI).

Follow-up filed

tile.description has the identical untrimmed-fallback shape one line below the title (dashboard-viewer-session.ts:563), so a whitespace-only description still renders an empty .dash-tile-desc span instead of falling back to the query description. Out of #476's scope (it corrupts no accessible name), filed as #489 (inbox) rather than folded in here.

Checklist

  • npm test passes (the per-file coverage gate is non-negotiable)
  • Tests added/updated in the same change as the code
  • npm run build succeeds (single-file dist/sql.html)
  • Layers kept honest: pure logic in src/core/, network in src/net/ (injected fetch), DOM in src/ui/
  • No new runtime dependency (or it's a deliberate, justified addition — see CONTRIBUTING)
  • README / CHANGELOG.md ([Unreleased]) updated if behavior or the deployed surface changed
  • Reconciled affected tracked work (roadmap Roadmap to 1.0.0 #68, the issue body, ADR/CHANGELOG) if this change reshaped it

BorisTyshkevich and others added 2 commits July 27, 2026 07:40
…itles

Phase 1 of #429 — the two prerequisites later phases build row commands on.

#443: `openSavedQuery` switched to the Query surface and pushed a history
entry before it knew whether the id resolved, so a dead click threw the user
off their surface, opened no tab and reported nothing. It resolves first now;
a miss toasts and changes no surface, no route and no tab. All three callers
(the tree's open-query command, its post-assignment reveal, and the per-tile
Open in Workbench) address a query they just resolved or created, so none
depended on the unconditional switch.

#476: `dashboardTileV1.title` has no `minLength`, so `"   "` is a legal
document, and being truthy it beat the query-name fallback — a blank
`.dash-tile-name` heading and accessible names reading "Open, — , in
Workbench". The viewer trims the authored title before the fallback, in the
one place a tile's display title is resolved, so every consumer of
`state.title` is settled at once. Behaviour change for such documents: they
now show the query name.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018mujm1kW7jDGpTEfscndcU
…ss wording

Review follow-ups on phase 1.

`flashToast` reuses ONE `.share-toast` element per document, so counting
elements can never distinguish one report from two — the "reports once" test
was asserting something it could not fail on. It now materialises the element
and counts how many times a report raises it, which a deliberate double-report
does fail.

The miss wording matches `openDashboard`'s exactly ("no longer part of this
workspace") rather than inventing a third phrasing next to it, and the #426
click-cancellation rationale no longer cites the dead-id hazard #443 just moved
to the callee.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018mujm1kW7jDGpTEfscndcU
@BorisTyshkevich
BorisTyshkevich merged commit b556280 into main Jul 27, 2026
7 checks passed
@BorisTyshkevich
BorisTyshkevich deleted the fix/resolve-before-navigate-429p1 branch August 6, 2026 15:28
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