Skip to content

Commit 33f76bd

Browse files
refactor: consolidate url state hooks and add shared test utilities
1 parent f6d1767 commit 33f76bd

22 files changed

Lines changed: 290 additions & 264 deletions

frontend/src/components/navigation/DesktopSidebar.test.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,4 +228,26 @@ describe('DesktopSidebar', () => {
228228

229229
expect(screen.getByTestId('location').textContent).toBe('/?dialog=files&settings=open&settingsTab=account')
230230
})
231+
232+
it('preserves session route as return target when opening schedules', () => {
233+
vi.spyOn(useDesktopModule, 'useDesktop').mockReturnValue(true)
234+
vi.spyOn(useSidebarCollapsedModule, 'useSidebarCollapsed').mockReturnValue([false, vi.fn()])
235+
vi.spyOn(useAuthModule, 'useAuth').mockReturnValue({
236+
isAuthenticated: true,
237+
isLoading: false,
238+
logout: vi.fn(),
239+
} as any)
240+
241+
render(
242+
<>
243+
<DesktopSidebar />
244+
<LocationDisplay />
245+
</>,
246+
{ wrapper: createWrapper(['/repos/5/sessions/abc?assistant=1']) }
247+
)
248+
249+
fireEvent.click(screen.getByText('Schedules'))
250+
251+
expect(screen.getByTestId('location').textContent).toBe('/repos/5/schedules?returnTo=%2Frepos%2F5%2Fsessions%2Fabc%3Fassistant%3D1')
252+
})
231253
})

frontend/src/components/navigation/DesktopSidebar.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { useSidebarCollapsed } from '@/hooks/useSidebarCollapsed'
55
import { useAuth } from '@/hooks/useAuth'
66
import { useUrlParams } from '@/hooks/useUrlParams'
77
import { buildNavModel, type MoreDrawerItem, type NavPrimaryCta } from '@/components/navigation/moreDrawerItems'
8+
import { getPathWithReturnTo } from '@/lib/navigation'
89
import { RepoQuickSwitchSheet } from '@/components/navigation/RepoQuickSwitchSheet'
910
import {
1011
Sidebar,
@@ -48,7 +49,10 @@ export function DesktopSidebar() {
4849

4950
const handleItemClick = (item: MoreDrawerItem) => {
5051
if (item.to) {
51-
navigate(item.to)
52+
const to = item.key === 'schedules'
53+
? getPathWithReturnTo(item.to, `${location.pathname}${location.search}`)
54+
: item.to
55+
navigate(to)
5256
} else if (item.dialog) {
5357
updateParams((p) => {
5458
p.set('dialog', item.dialog!)

frontend/src/components/navigation/MoreDrawer.test.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,4 +250,16 @@ describe('MoreDrawer', () => {
250250
expect(screen.queryByText('wrong-repo')).not.toBeInTheDocument()
251251
})
252252

253+
it('preserves session route as return target when opening schedules', () => {
254+
const navigateMock = vi.fn()
255+
vi.mocked(useNavigate).mockReturnValue(navigateMock)
256+
mockAuth()
257+
mockServerHealth()
258+
renderMoreDrawer({ initialEntry: '/repos/1/sessions/session-1?assistant=1', routePath: '/repos/:id/sessions/:sessionId' })
259+
260+
fireEvent.click(screen.getByText('Schedules'))
261+
262+
expect(navigateMock).toHaveBeenCalledWith('/repos/1/schedules?returnTo=%2Frepos%2F1%2Fsessions%2Fsession-1%3Fassistant%3D1')
263+
})
264+
253265
})

frontend/src/components/navigation/MoreDrawer.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { FileBrowserSheet } from '@/components/file-browser/FileBrowserSheet'
1414
import { buildMoreItems } from './moreDrawerItems'
1515
import { useSwipeBack } from '@/hooks/useMobile'
1616
import { getRepoDisplayName } from '@/lib/utils'
17-
import { isAssistantPath } from '@/lib/navigation'
17+
import { getPathWithReturnTo, isAssistantPath } from '@/lib/navigation'
1818
import type { components } from '@/api/opencode-types'
1919

2020
type CommandType = components['schemas']['Command']
@@ -33,12 +33,12 @@ export function MoreDrawer({ isOpen, onClose }: MoreDrawerProps) {
3333
const [mentionFileBrowserOpen, setMentionFileBrowserOpen] = useState(false)
3434
const swipeRef = useRef<HTMLDivElement>(null)
3535
const { bind } = useSwipeBack(onClose, { enabled: isOpen, suspendsRouteSwipe: true })
36-
const { search, updateParams } = useUrlParams()
36+
const { searchParams, updateParams } = useUrlParams()
3737
const { logout } = useAuth()
3838
const { data: health } = useServerHealth()
3939
const isSessionDetail = /^\/repos\/\d+\/sessions\/[^/]+$/.test(location.pathname)
4040
const isAssistantRoute = isAssistantPath(location.pathname)
41-
const isAssistantSession = isSessionDetail && new URLSearchParams(search).get('assistant') === '1'
41+
const isAssistantSession = isSessionDetail && searchParams.get('assistant') === '1'
4242
const { filterCommands } = useCommands(isSessionDetail ? OPENCODE_API_ENDPOINT : null)
4343
const activePromptFileBasePath = useUIState((state) => state.activePromptFileBasePath)
4444
const selectPromptCommand = useUIState((state) => state.selectPromptCommand)
@@ -80,7 +80,10 @@ export function MoreDrawer({ isOpen, onClose }: MoreDrawerProps) {
8080

8181
const handleItemClick = (item: ReturnType<typeof buildMoreItems>[0]) => {
8282
if (item.to) {
83-
navigate(item.to)
83+
const to = item.key === 'schedules'
84+
? getPathWithReturnTo(item.to, `${location.pathname}${location.search}`)
85+
: item.to
86+
navigate(to)
8487
} else if (item.dialog) {
8588
updateParams((p) => {
8689
p.set('dialog', item.dialog!)

frontend/src/components/navigation/RepoQuickSwitchSheet.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { listRepos } from '@/api/repos'
99
import { AddRepoDialog } from '@/components/repo/AddRepoDialog'
1010
import { FolderGit2, Check, Plus, House } from 'lucide-react'
1111
import { isAssistantPath, getAssistantPath } from '@/lib/navigation'
12+
import { useUrlParams } from '@/hooks/useUrlParams'
1213

1314
interface RepoQuickSwitchSheetProps {
1415
isOpen: boolean
@@ -18,6 +19,7 @@ interface RepoQuickSwitchSheetProps {
1819
export function RepoQuickSwitchSheet({ isOpen, onClose }: RepoQuickSwitchSheetProps) {
1920
const navigate = useNavigate()
2021
const location = useLocation()
22+
const { searchParams } = useUrlParams()
2123
const [searchQuery, setSearchQuery] = useState('')
2224
const [addRepoOpen, setAddRepoOpen] = useState(false)
2325

@@ -45,7 +47,7 @@ export function RepoQuickSwitchSheet({ isOpen, onClose }: RepoQuickSwitchSheetPr
4547
)
4648
}, [repos, searchQuery])
4749

48-
const isUrlControlledSheet = new URLSearchParams(location.search).get('mobileTab') === 'repos'
50+
const isUrlControlledSheet = searchParams.get('mobileTab') === 'repos'
4951

5052
const navigateAndClose = (path: string, options?: { replace?: boolean }) => {
5153
navigate(path, options)
@@ -55,7 +57,7 @@ export function RepoQuickSwitchSheet({ isOpen, onClose }: RepoQuickSwitchSheetPr
5557
}
5658

5759
const handleClick = (id: number) => {
58-
const pendingAction = new URLSearchParams(location.search).get('mobileTabAction')
60+
const pendingAction = searchParams.get('mobileTabAction')
5961

6062
if (isAssistantRoute) {
6163
navigateAndClose(`/repos/${id}`, { replace: true })

0 commit comments

Comments
 (0)