Migrate thread selection to URL-driven state with browser history support#883
Migrate thread selection to URL-driven state with browser history support#883
Conversation
…ead nav Three issues addressed: 1. Mobile corpus home view had no way to access sidebar tabs. Added a MobileMenuButton (kebab icon) to both CorpusLandingView (in breadcrumbs) and CorpusDetailsView (in header) that opens the sidebar bottom sheet, consistent with how other tabs expose the MobileKebabButton. 2. Discussion thread navigation was not URL-driven, making browser back/forward unusable. Replaced the local inlineSelectedThreadIdAtom (Jotai) with the URL-synced selectedThreadId reactive var (?thread= param), already handled by CentralRouteManager. Added updateThreadParam utility that pushes history entries for proper back/forward. 3. Tab switching used replace instead of push, preventing browser back/forward between tabs. Changed updateTabParam and updateDetailViewParam to push new history entries. updateTabParam also now clears thread/message params when switching tabs. https://claude.ai/code/session_015gUfjhz6wHKpvJiEiXgBA7
Pull Request Review: URL-Driven Thread Selection MigrationThis PR successfully migrates thread selection from local Jotai atom state to URL-driven state via the ✅ StrengthsArchitecture Alignment
Browser Navigation Support
Mobile UX Improvements
Code Quality
|
- Remove dead `onViewModeChange` prop and `useEffect` from
CorpusDiscussionsView — parent now derives thread view state directly
from the URL-synced selectedThreadId reactive var
- Remove unused `useEffect` import
- Update existing `updateTabParam()` tests to assert push semantics
(no `{ replace: true }`) and add 3 new tests for thread/message
param clearing on tab switch
- Add 5 new `updateThreadParam()` tests covering set, clear, push
behavior, param preservation, and update
- Add CHANGELOG.md entry documenting mobile nav and URL-driven thread
selection changes
https://claude.ai/code/session_015gUfjhz6wHKpvJiEiXgBA7
Code Review - PR #883I've completed a thorough review of this PR. Overall, this is a well-architected migration that successfully aligns thread selection with the CentralRouteManager pattern. The implementation is clean, well-tested, and follows the project's established conventions. ✅ Strengths1. Excellent Architecture Alignment
2. Comprehensive Test CoverageThe test updates in
3. Clean Code Quality
4. Mobile UX EnhancementThe mobile menu button addition is a thoughtful improvement:
5. Excellent Changelog DocumentationThe CHANGELOG.md updates are detailed and follow the Keep a Changelog format properly, with clear file references and line numbers. 🔍 Code Quality ObservationsnavigationUtils.ts (Lines 806-857)The new utility functions are well-designed: ✅ Good:
✅ Good Pattern: Both functions preserve unrelated params while updating/clearing specific ones CorpusDiscussionsView.tsx (Lines 385-458)State management migration is clean: ✅ Good:
Corpuses.tsx (Lines 1582-1584)Parent component correctly derives state: ✅ Good:
|
- Remove console.log debug statements left in Corpuses.tsx - Replace navigate(-1) with updateThreadParam(null) in handleBackToList so back-to-list always explicitly clears the ?thread= param via URL, letting CentralRouteManager Phase 2 handle state — consistent with the routing mantra and safe for deep-linked/bookmarked URLs
Summary
This PR migrates thread selection in the Discussions tab from local atom state to URL-driven state via the
?thread=query parameter. This enables proper browser back/forward navigation between thread list and thread detail views, and aligns with the CentralRouteManager architecture for managing application state through URLs.Key Changes
Thread Selection State Migration: Replaced
inlineSelectedThreadIdAtomwith URL-driven state synced throughselectedThreadIdVarreactive var in the Apollo cache. The?thread=query parameter is now the source of truth.Navigation Utilities:
updateThreadParam()function to manage thread URL parameter updates with proper history handlingupdateTabParam()andupdateDetailViewParam()to usenavigate()instead ofreplace: true, enabling proper browser back/forward navigationCorpusDiscussionsView Refactoring:
handleThreadClick()to callupdateThreadParam()instead of setting atom statehandleBackToList()to usenavigate(-1)for proper history navigationselectedThreadIdVarreactive varState Derivation in Parent Component:
Corpuses.tsxnow derivesdiscussionInThreadViewfrom the URL-drivenselectedThreadIdreactive var instead of managing it as local stateonViewModeChangecallback fromCorpusDiscussionsViewsince state is now URL-drivenMobile UI Enhancements:
MobileMenuButtonstyled component for mobile navigation menu accessCorpusLandingViewandCorpusDetailsViewto include mobile menu button in headersonOpenMobileMenucallback prop to support mobile navigationCleanup: Removed
inlineSelectedThreadIdAtomfromthreadAtoms.tswith explanatory comment about URL-driven approachImplementation Details
The migration follows the CentralRouteManager Phase 2 pattern where:
updateThreadParam()?thread=param and syncs it toselectedThreadIdVarnavigate()instead ofreplace: trueThis approach eliminates the need for callback-based state synchronization and provides a single source of truth (the URL) for thread selection state.
https://claude.ai/code/session_015gUfjhz6wHKpvJiEiXgBA7