feat(platform): add loading states for every tenant route + fix the window filter - #155
Merged
Conversation
…indow filter Every page under [tenant]/ is an async Server Component doing direct Supabase/session fetches with zero Suspense boundary and zero loading.tsx — clicking a nav link, a repo row, or a settings tab just sat there frozen until the new RSC payload streamed back, with nothing to signal the click registered (and nothing stopping a second click). - Added loading.tsx to every route segment that fetches data on the server: dashboard, repos, repos/[repoName], compare, ai-exposure, audit-log, team, settings, settings/integrations, settings/integrations/[provider], connect. Next's built-in mechanism — the nearest loading.tsx renders automatically as a Suspense fallback while a route segment's data is still resolving, on both <Link> navigation and router.push/replace. - Added a shared shadcn-style Skeleton primitive (components/ui/skeleton.tsx) each loading.tsx composes into a rough match of its page's real layout (header + card grid / table rows), not just a generic spinner. - WindowSelector (the org/window filter used on dashboard, compare, and repo-detail) had literally no pending feedback: it calls router.replace on change, which reruns the whole server page, and the <Select> just sat there unchanged until the round-trip finished. Wrapped the navigation in useTransition — the select disables and shows a spinner immediately, which also blocks a second click from firing another replace() before the first resolves. Deliberately NOT loading.tsx-driven here: wrapping in a transition keeps the current page visible with isPending=true instead of flashing to the route's skeleton, which is the right feel for a filter tweak vs. a full navigation. - Left compare-view's search/sort alone — both are pure client-side useState/useMemo over already-fetched data, no network round-trip, so a loading indicator there would be pure noise. Verification: npx tsc --noEmit clean, npm run test 253/253, npm run lint 0 errors (same 72 pre-existing warnings). Started the dev server with placeholder env vars and confirmed it boots without error and protected routes still redirect correctly (no auth/build regression). Could not visually verify the skeletons rendering in an authenticated browser session — this sandbox has no real Supabase project or user session configured, so every [tenant]/* page redirects to /auth/signin before reaching the data-fetching code the loading.tsx files guard. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Every page under
[tenant]/is an async Server Component doing direct Supabase/session fetches, with zero Suspense boundary and zeroloading.tsxanywhere in the app. Clicking a nav link, a repo row, or the window/period filter just sat there frozen until the new RSC payload streamed back — no visual feedback, and nothing stopping a second click before the first one resolves.What
loading.tsxon every data-fetching route segment: dashboard, repos, repos/[repoName], compare, ai-exposure, audit-log, team, settings, settings/integrations, settings/integrations/[provider], connect. This is Next's built-in mechanism — the nearestloading.tsxrenders automatically as a Suspense fallback while a route segment's data is resolving, for both<Link>navigation androuter.push/replace.components/ui/skeleton.tsx: a shared shadcn-style primitive eachloading.tsxcomposes into a rough match of its real layout (header + card grid / table rows), not a generic spinner.WindowSelectorfix: this is the actual "filtro" in the bug report — it callsrouter.replaceon change (reruns the whole server page for every dashboard/compare/repo-detail view that reads?window=), and had zero pending feedback. Wrapped the navigation inuseTransition: the<Select>disables and shows a spinner immediately, which also blocks a second click from firing anotherreplace()before the first resolves.What I deliberately left alone
WindowSelectorusesuseTransitioninstead of relying onloading.tsx— wrapping a navigation in a transition keeps the current page visible withisPending=truerather than flashing to the route's skeleton. Right feel for a filter tweak; a full skeleton flash would feel worse than nothing for a same-page param change.compare-view's search input and column-sort are pure client-sideuseState/useMemoover already-fetched data — no network round-trip, so a loading indicator there would be pure noise.Verification
npx tsc --noEmit: clean.npm run test: 253/253 passing.npm run lint: 0 errors, same 72 pre-existing warnings./auth/signin(no regression).Not verified: the actual skeleton appearance and the WindowSelector spinner in a live authenticated session — this sandbox has no real Supabase project or user session configured, so every
[tenant]/*page redirects before reaching the code theseloading.tsxfiles guard. Worth a manual pass in a real environment before/after merge.Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com