Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| Merge branch 'claude/zen-ptolemy-01vsx1': never leave a page stuck on its loading bar | 1 | import { useEffect } from "react"; |
| 2 | import { type Location, createPath, useNavigation } from "react-router"; | |
| 3 | ||
| 4 | /** | |
| 5 | * How long a client navigation may load before the page gives up on it and | |
| 6 | * loads the address as a whole page. Longer than any read may take on the | |
| 7 | * server (lib/deadline.ts `SLOW_READ_DEADLINE_MS`): a slow page that would | |
| 8 | * arrive is never cut off and started again, and a stuck service shows its | |
| 9 | * error page first. This catches what the server cannot: a request lost on | |
| 10 | * the way, a connection that went quiet, a route's code that never arrived. | |
| 11 | */ | |
| 12 | export const STUCK_NAVIGATION_MS = 75_000; | |
| 13 | ||
| 14 | /** | |
| 15 | * Where to send a navigation that has been loading too long, or null when | |
| 16 | * there is nothing safe to retry. Only "loading" is retried: it reads, even | |
| 17 | * after a form was posted (the action already answered and the page is | |
| 18 | * reading what it changed). "submitting" is a write still on its way, and | |
| 19 | * sending it again could do it twice. | |
| 20 | */ | |
| 21 | export function stuckTarget(navigation: { state: string; location?: Pick<Location, "pathname" | "search" | "hash"> | null }): string | null { | |
| 22 | if (navigation.state !== "loading" || !navigation.location) return null; | |
| 23 | return createPath(navigation.location); | |
| 24 | } | |
| 25 | ||
| 26 | /** | |
| 27 | * Never leaves the page on its loading bar: a navigation still loading | |
| 28 | * after `STUCK_NAVIGATION_MS` is finished as a document load of the same | |
| 29 | * address, which either arrives or shows the server's error page. | |
| 30 | */ | |
| 31 | export function useStuckNavigationRescue(ms = STUCK_NAVIGATION_MS) { | |
| 32 | const target = stuckTarget(useNavigation()); | |
| 33 | useEffect(() => { | |
| 34 | if (!target) return; | |
| 35 | const timer = window.setTimeout(() => { | |
| 36 | console.warn(`g1t: navigation to ${target} still loading after ${ms}ms; loading it as a whole page`); | |
| 37 | window.location.assign(target); | |
| 38 | }, ms); | |
| 39 | return () => window.clearTimeout(timer); | |
| 40 | }, [target, ms]); | |
| 41 | } |
This file's history is long; its oldest lines are credited to the oldest commit read.