feat(home-v2): allow multiple internal pages open as tabs - #350
Merged
Conversation
Replaces the single internal slot (owner decision #17 reverses the A2 single-slot decision): ProductState gains an ordered internalPages list (each page open at most once; a non-'tab' destination is always a member). navigate appends-and-activates, a new close-internal action closes with neighbor -> first app tab -> reopen-dashboard fallback, and closing the last app tab returns to the last open internal page. TabStrip renders every open page as a closable tab (existing tabs.closeNamed key; no new i18n keys). Ctrl+W closes the active internal page when no app tab is active. Persistence serializes internalPages; restore validates, dedupes, drops transient pages (releases/core-docs/welcome, matching the destination downgrade), and migrates legacy states to a single dashboard tab. Contract tests cover navigate/close/fallback/restore paths. Parity review P-3 (projects/qortium-home-2.1/parity-review-2026-08-24). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This was referenced Aug 24, 2026
QuickMythril
added a commit
that referenced
this pull request
Aug 24, 2026
Replaces the grouped internalPages + tabs model (PR #350) with a single ordered `entries` list holding both internal pages and app tabs, each with its own id. `tabs` and `destination` are now DERIVED from it, so the ~24 existing consumers of destination/tabs are untouched. - Mixed ordering: one drag group, so an app tab can move ahead of a Home page and back. - Duplicates: `open-internal` always appends another instance and is wired to "+" / Ctrl+T, while `navigate` still focuses an open page. - Transient pages (welcome, releases, core-docs) render full-window via `transient` instead of taking a tab — they own unpersisted side state, so only one can exist and none may restore. Removes the stray Welcome tab. - Close falls to the neighbour whatever its kind; the strip is never left empty. - Internal tabs get per-page icons; Dashboard and Settings previously rendered the same Home mark and were distinguishable only by label. - Persistence serializes `entries`; pre-unified states (separate internalPages + tabs) migrate on restore. Smoke fix: the drag assertion released on the last tab's CENTRE, which is exactly the midpoint where "insert after" is by design a no-op, so it failed against correct behaviour. It now releases past that midpoint. Parity review I1 + I6 (projects/qortium-home-2.1/parity-review-2026-08-24). Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Summary
Parity review P-3 — owner decision #17 (2026-08-24) reversed the recorded "single internal slot" decision: Dashboard and Settings (and any other Home pages) must be openable at the same time.
Design keeps the
destinationsemantics everywhere (router, address bar, navigation guards untouched) and adds an orderedinternalPageslist toProductState:'tab'destination is always a member of the list.navigateappends-and-activates; re-navigating to an open page just activates it.close-internalaction: closing the active page falls back to its neighbor page, then the first app tab; closing the very last surface reopens the Dashboard (never an empty window). Closing the last app tab now returns to the last open internal page instead of unconditionally to Dashboard.tabs.closeNamedi18n key — no new keys, so catalog parity is untouched). Thehome-v2-tab--dashboardclass is kept on internal tabs so the existing desktop/Android smoke selectors keep working (dashboard remains the first internal tab).internalPagesserializes with the shell state; restore validates/dedupes (cap 8), drops transient pages (releases/core-docs/welcome— they carry unpersisted side state, matching the existing destination downgrade), and migrates legacy states without the field to a single Dashboard tab.Note for review: multiple simultaneous newtab pages are still one page (page-once model) — "+" activates the existing new-tab page; that matches the A2/A4 behavior. Internal tabs stay grouped before app tabs; mixed ordering comes with P-4 (tab drag) if wanted.
Testing
tscprojects clean;test:home-v2-foundation(extended),test:home-v2-browser-chrome,test:welcome-statepass;build:renderersucceeds.🤖 Generated with Claude Code