Skip to content

fix(frontend): analysis progress freeze and deep-link 404 crash#198

Merged
parthrohit22 merged 2 commits into
Second-Origin:devfrom
parthrohit22:fix/175-179-ux-freeze-deeplink
Jul 26, 2026
Merged

fix(frontend): analysis progress freeze and deep-link 404 crash#198
parthrohit22 merged 2 commits into
Second-Origin:devfrom
parthrohit22:fix/175-179-ux-freeze-deeplink

Conversation

@parthrohit22

Copy link
Copy Markdown
Collaborator

Summary

Two related P1 frontend bugs, fixed in one branch per issue owner's request: the "Analysing Repository" page could get stuck displaying a non-terminal state after the backend job actually finished, and direct navigation to certain in-app URLs crashed with react-router's raw "Unexpected Application Error! 404 Not Found" screen instead of a real page. Both are frontend-only; no backend files were touched.

Linked issue

Closes #175. Closes #179.

What changed

Frontend — #175 (useAnalysisPipeline.ts)

  • The poll loop kept scheduling another fetchAnalysisStatus request even after receiving a completed/failed/cancelled response, relying entirely on the surrounding effect tearing itself down on the next render to actually stop. It now returns immediately after handling a terminal response, so the loop's own control flow — not incidental render timing — is what stops it.
  • The polling effect depended on the whole repository object, whose identity changes on every single progress tick (not just on a real status change), tearing down and rebuilding the interval on every tick (called out in-code as a "known limitation"). The effect now depends on the derived repositoryStatus/repositoryErrorMessage primitives instead, so it only restarts on an actual status or error-message change.
  • Retry/backoff for transient network/timeout errors (from bug: analysis page reports 'Analysis Failed' when a status poll drops, while the durable job is still running #164) is unchanged and still covered by the existing tests.

Frontend — #179 (router.tsx + two new pages)

  • Added a catch-all path: '*' route rendering a new NotFoundPage instead of falling through to react-router's default error boundary. It still sits behind RequireAuth/MainLayout, so an unauthenticated visitor to a bogus path is redirected to /login first, same as any other route.
  • Added /dashboard as an alias (<Navigate to="/" replace />) for the Dashboard surface, whose registered path is /.
  • Added /analysis/:id/architecture, backed by a new AnalysisArchitectureRedirect component that selects the requested repository (setActiveRepositoryId) and hands off to the existing top-level /architecture route, since Architecture (like Review/Dependencies/Insights) reads the globally-selected repository rather than being mounted per-repository.

Acceptance criteria completed

#175

#179

  • Primary authenticated routes (/dashboard, /analysis/{id}/architecture) are directly reachable without a hard-refresh 404.
  • Invalid/unknown routes render a proper NotFound page rather than crashing.
  • The auth guard still gates every route, including the new ones.

Testing performed

npm --prefix apps/frontend run test
 Test Files  29 passed (29)
      Tests  164 passed (164)

npm run lint:frontend
 (clean, no output)

npm run build:frontend
 tsc -b && vite build — succeeded

New/changed test coverage:

  • useAnalysisPipeline.test.ts: added a case asserting the poll loop stops issuing requests once it observes a terminal status, instead of scheduling another one.
  • AnalysisPipelinePage.integration.test.tsx (new): exercises the real hook wired to the real store (the sibling AnalysisPipelinePage.test.tsx mocks the hook entirely, which is exactly the gap between "hook transitions correctly in isolation" and "page actually sees it"). Covers: poll → completed navigates to the repo detail route with no reload; a real job failure renders "Analysis Failed"; a transient network error shows the retrying banner and then recovers to completed.
  • router.test.tsx (new): renders the real createAppRouter() output (not a mocked route table) for /dashboard, /analysis/{id}/architecture, and an unknown path, asserting each renders its real page (Dashboard / Architecture / NotFound) instead of the crash screen, and that the architecture deep link selects the requested repository.

I could not exercise this in an actual browser in this environment (no backend running, no browser/screenshot tooling available) — verification is via the vitest suite above, which renders the real react-router-dom route table and the real hook/store wiring in jsdom rather than mocking route matching or the poll loop away.

Screenshots

Not applicable for the #175 fix (no markup changes, only control-flow/state-management changes to an existing page).

For #179, NotFoundPage is a new visible surface, but I have no browser/screenshot tooling in this environment to capture it. It reuses the existing PageHeader + EmptyState components already used by DeferredSurfacePage (title "Page not found", a compass icon, a short description, and a "Back to Dashboard" action) so it matches the app's existing empty-state styling rather than introducing new visual design. Reviewer can verify with npm run dev and a hard refresh on /dashboard, /analysis/<a-repo-id>/architecture, or any bogus path.

Security and data considerations

None. The catch-all and new aliases add no new data access — they only add routes/redirects, and all of them remain nested under the existing RequireAuth guard, so an unauthenticated request to any of them still redirects to /login first. No secrets, auth logic, or owner-scoping were touched.

Dependencies and blocked work

None.

Scope changes or remaining work

None for the verified repro steps in both issues. Note: Review/Dependencies/Insights follow the same "reads the globally-selected repository" pattern as Architecture but weren't reported as 404ing and aren't part of either issue's acceptance criteria, so I left them as top-level-only routes rather than adding matching /analysis/:id/<surface> deep links for all of them.

Contributor checklist

  • This PR targets dev
  • I claimed the issue and had it assigned or acknowledged before starting substantial work
  • The branch was created from an up-to-date upstream/dev
  • The branch is rebased on the latest upstream/dev
  • This PR addresses one clearly scoped issue
  • Every acceptance criterion I claim as complete is actually complete
  • Relevant tests pass
  • Documentation is updated for any user-visible change
  • No secrets, credentials, local env files, or generated artifacts are included
  • No unrelated files were changed
  • Closing syntax (Closes) is used only because the issue is fully resolved
  • Dependencies and follow-up work are linked

The poll loop rebuilt its interval on every progress tick (repository
object identity changed each response) and kept scheduling another
request even after a completed/failed/cancelled response, leaving the
"Analysing Repository" page stuck until a manual reload. The loop now
stops itself on a terminal status and the effect only restarts on an
actual status/error change, not every progress percentage.
Direct navigation to /dashboard or /analysis/{id}/architecture hit
react-router's default error boundary ("Unexpected Application Error!
404 Not Found") because no route matched them and there was no
catch-all. /dashboard now aliases the Dashboard surface at /, the
architecture deep link selects that repository and hands off to
/architecture, and any other unmatched path renders a NotFound page
instead of crashing. The auth guard still gates all of this.
@parthrohit22
parthrohit22 merged commit bcfc89b into Second-Origin:dev Jul 26, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant