fix: deep-link master-detail selections (#2025)#2053
Merged
Conversation
…mpt Manager) (#2025) Move the open record into the URL for the master-detail views that kept it in local state, so every selection is shareable, bookmarkable, reload-safe, and reachable from ⌘K / voice / the back button: - Authors: /authors/:authorId (:authorId also captures the `new` create sentinel) - Music tabs: /music/:tab/:id (artists, albums, tracks) - Sharing buckets: /sharing/:section/:bucketId - Prompt Manager: ?stage= / ?var= search params - JIRA Reports: ?reportApp=&reportDate= (appId+date is the stable report id) Selection handlers navigate to the id'd route; deletes/clears navigate back to the index; a stale/deleted id renders a not-found fallback. OpenClaw's session picker is documented as an intentional exemption (ephemeral runtime state). Claude-Session: https://claude.ai/code/session_016N3afFZfp7gFiXLM4LEjkp
…ds (#2025) Review-gate follow-ups: - Sharing: distinguish "no bucket selected" from a stale/removed bucketId with an explicit "could not be found" fallback (matches the other master-detail views). - JiraReports: clear selectedReport when the URL-named report fails to resolve (deleted / bad deep link) instead of stranding the previously-open report. Claude-Session: https://claude.ai/code/session_016N3afFZfp7gFiXLM4LEjkp
#2025) Codex review: record selection in Prompt Manager (?stage/?var) and JIRA Reports (?reportApp/?reportDate) used history-replace, so the back button skipped past prior selections — inconsistent with Authors/Music/Sharing (which push). Selection is now a push; the tab toggle and auto-select canonicalization keep replace. Claude-Session: https://claude.ai/code/session_016N3afFZfp7gFiXLM4LEjkp
Claude review: the hydration effect's idle/not-found branch skipped clearGeneration()/setConfirmDelete() (and resetTrackViewState for tracks), so navigating from an editing record to the index or a stale id could let a stray render land on the prior record. Restructured all four effects (Authors, Artists, Albums, Tracks) to run the resets for every selection change via a normalized selectionKey guard. Claude-Session: https://claude.ai/code/session_016N3afFZfp7gFiXLM4LEjkp
# Conflicts: # .changelog/NEXT.md
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.
Closes #2025
What
Several master-detail views kept their selected record in
useState, so a pasted URL or a reload dropped you back on an empty list — violating the repo's "ID-based deep linking for every selectable UI element" convention. This moves each selection into the URL.selectedIdstate/authors/:authorId(:authorIdalso captures thenewcreate sentinel — UUIDs never collide)selectedIdstate per manager/music/:tab/:id(new= create)selectedIdstate/sharing/:section/:bucketId(auto-selects first bucket withreplacewhen none is named)selectedStage/selectedVarstate?stage=/?var=search params (drawer-tab style)selectedReportstate?reportApp=&reportDate=(appId+date is the stable report id)Each: selection handlers
navigate()to the id'd route; deletes/clearsnavigate()to the index; a stale/deleted id renders a "could not be found" fallback. Form state is hydrated from the URL selection via an effect keyed on the id, with ahydratedRefguard so a list refresh (create/update/delete) doesn't clobber the open form.Verify-first items
getJiraReport(appId, date), card key${appId}-${date}), so it was fixed (deep-linked).selectedSessionIdis ephemeral runtime state, not a user-owned record: the session list is discovered from an external runtime, selection is auto-managed (preferredSessionId→defaultSession→ first), and it's wired into live SSE streaming with in-flight refs.Routes added (
App.jsx)authors/:authorId,music/:tab/:id,sharing/:section/:bucketId. Base paths were already registered inNAV_COMMANDS; no new manifest entries needed. Prompt Manager stays at/prompts(search params), so no Layout scroll-mode change.Test plan
cd client && npm test -- --run→ 285 files / 3076 tests pass (updatedAuthors.test.jsxto mount inside aMemoryRouterwith the authors routes, since selection is now navigation-driven).cd client && npm run build→ clean.cd client && npm run lint→ no new errors/warnings on changed files (3 pre-existing warnings in the untouchedMusicGenPanel.jsx).