Mercurial
diff hg-web/src/components/app.tsx @ 223:0e7b9464248d hg-web
[hg-web] Add browser route regression coverage
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Sun, 02 Aug 2026 10:07:40 -0700 |
| parents | ce7f4400c2de |
| children | 70de0c80d093 |
line wrap: on
line diff
--- a/hg-web/src/components/app.tsx Sun Aug 02 09:07:36 2026 -0700 +++ b/hg-web/src/components/app.tsx Sun Aug 02 10:07:40 2026 -0700 @@ -13,6 +13,7 @@ graphTip?: string; dirPath?: string; changesetId?: string; + returnDepth?: number; } type ChangesetDetail = { @@ -24,7 +25,10 @@ tags: string[]; user: string; parents: string[]; - files: string[]; + files: Array<{ + file: string; + status: string; + }>; diff: Array<{ blockno: number; lines: Array<{ t: string; n: number; l: string }>; @@ -106,6 +110,13 @@ } } +function isRouteState(value: unknown): value is RouteState { + if (!value || typeof value !== 'object' || !('page' in value)) return false; + return ['landing', 'graph', 'directory', 'changeset'].includes( + String((value as { page: unknown }).page), + ); +} + // Landing Page Component function LandingPage({ onNavigateToGraph, @@ -242,7 +253,7 @@ return ( <div> <div className="page-header"> - <button className="back-button" onClick={onBack}> + <button className="back-button" onClick={onBack} aria-label="Back"> ← Back </button> <span className="page-title">Commit Graph</span> @@ -320,8 +331,8 @@ return ( <div> <div className="page-header"> - <button className="back-button" onClick={onBack}> - ← Back to graph + <button className="back-button" onClick={onBack} aria-label="Back"> + ← Back </button> <span className="page-title">Changeset</span> </div> @@ -364,7 +375,14 @@ {changeset.files.length > 0 && ( <div className="changeset-files"> <strong>Files</strong> - {changeset.files.map(file => <code key={file}>{file}</code>)} + {changeset.files.map(file => ( + <code key={file.file}> + <span className={`changeset-file-status status-${file.status}`}> + {file.status} + </span> + {file.file} + </code> + ))} </div> )} @@ -409,7 +427,7 @@ return ( <div> <div className="page-header"> - <button className="back-button" onClick={onBack}> + <button className="back-button" onClick={onBack} aria-label="Back"> ← Back </button> <span className="page-title">Repository Files</span> @@ -430,8 +448,8 @@ // Handle browser back/forward useEffect(() => { - const handlePopState = () => { - setRoute(parseRoute()); + const handlePopState = (event: PopStateEvent) => { + setRoute(isRouteState(event.state) ? event.state : parseRoute()); }; window.addEventListener('popstate', handlePopState); return () => window.removeEventListener('popstate', handlePopState); @@ -456,8 +474,19 @@ }, [navigate]); const navigateToChangeset = useCallback((changesetId: string) => { - navigate({ page: 'changeset', changesetId }); - }, [navigate]); + const returnDepth = route.page === 'changeset' + ? (route.returnDepth ?? 0) + 1 + : 1; + navigate({ page: 'changeset', changesetId, returnDepth }); + }, [navigate, route.page, route.returnDepth]); + + const navigateBackFromChangeset = useCallback(() => { + if (route.returnDepth !== undefined && route.returnDepth > 0) { + window.history.go(-route.returnDepth); + return; + } + navigateToGraph(); + }, [navigateToGraph, route.returnDepth]); const handleDirectoryPathChange = useCallback((path: string) => { // Update URL without full navigation @@ -530,7 +559,7 @@ {route.page === 'changeset' && route.changesetId && ( <ChangesetPage changesetId={route.changesetId} - onBack={() => navigateToGraph()} + onBack={navigateBackFromChangeset} onOpenChangeset={navigateToChangeset} /> )}