diff --git a/webui2/src/App.tsx b/webui2/src/App.tsx index 3f8dcf795a618d45affc702be754fcfb3726502b..fdb288d1e660c9d5686cadb5e88ad29fe963364b 100644 --- a/webui2/src/App.tsx +++ b/webui2/src/App.tsx @@ -1,11 +1,14 @@ import { createRouter, RouterProvider } from "@tanstack/react-router"; +import { preloadQuery } from "@/lib/apollo"; + import { routeTree } from "./routeTree.gen"; const router = createRouter({ routeTree, defaultPreload: "intent", scrollRestoration: true, + context: { preloadQuery }, }); declare module "@tanstack/react-router" { diff --git a/webui2/src/routes/$repo.tsx b/webui2/src/routes/$repo.tsx index 77cd795d8ba5d770bea08291e828df410b4c9135..8eaac5c9d2457e7291396cca9cb49ee6b9408728 100644 --- a/webui2/src/routes/$repo.tsx +++ b/webui2/src/routes/$repo.tsx @@ -1,7 +1,28 @@ import { createFileRoute } from "@tanstack/react-router"; +import { + type ValidLabelsQuery, + ValidLabelsDocument, + type AllIdentitiesQuery, + AllIdentitiesDocument, +} from "@/__generated__/graphql"; import { RepoShell } from "@/lib/repo"; export const Route = createFileRoute("/$repo")({ component: RepoShell, + beforeLoad: ({ params: { repo }, context: { preloadQuery } }) => { + // Normalize the repo slug: "_" means the default (null) repo + const ref = repo === "_" ? null : repo; + + // Preload labels and identities shared by all child routes (issue list, + // bug detail, etc.). These are stable across filter/page changes. + const labelsRef = preloadQuery(ValidLabelsDocument, { + variables: { ref }, + }); + const identitiesRef = preloadQuery(AllIdentitiesDocument, { + variables: { ref }, + }); + + return { ref, labelsRef, identitiesRef }; + }, }); diff --git a/webui2/src/routes/$repo/commit/$hash.tsx b/webui2/src/routes/$repo/commit/$hash.tsx index 4aafd19c179001607505562aeb9a5de63b2804f6..930c26411b760c5048ee147a5ae5209d72adc270 100644 --- a/webui2/src/routes/$repo/commit/$hash.tsx +++ b/webui2/src/routes/$repo/commit/$hash.tsx @@ -9,7 +9,6 @@ import { ArrowLeft, GitCommit } from "lucide-react"; import { FileDiffView } from "@/components/code/FileDiffView"; import { Skeleton } from "@/components/ui/skeleton"; -import { preloadQuery } from "@/lib/apollo"; import { useRepo } from "@/lib/repo"; const COMMIT_QUERY = gql` @@ -57,9 +56,9 @@ interface CommitQueryData { export const Route = createFileRoute("/$repo/commit/$hash")({ component: RouteComponent, pendingComponent: CommitPageSkeleton, - loader: async ({ params: { repo, hash } }) => { + loader: async ({ context: { preloadQuery, ref }, params: { hash } }) => { const commitRef = preloadQuery(COMMIT_QUERY, { - variables: { repo: repo === "_" ? null : repo, hash }, + variables: { repo: ref, hash }, }); return { commitRef: await preloadQuery.toPromise(commitRef) }; }, diff --git a/webui2/src/routes/$repo/index.tsx b/webui2/src/routes/$repo/index.tsx index 96ea0aec4fa9f0f1cac2c4e7109b9c068fa20d59..dea0dec7896dcc733e7de503d61c36a4b8239b2d 100644 --- a/webui2/src/routes/$repo/index.tsx +++ b/webui2/src/routes/$repo/index.tsx @@ -24,7 +24,6 @@ import { RefSelector } from "@/components/code/RefSelector"; import { Markdown } from "@/components/content/Markdown"; import { ButtonLink } from "@/components/ui/button-link"; import { Skeleton } from "@/components/ui/skeleton"; -import { preloadQuery } from "@/lib/apollo"; import { useRepo } from "@/lib/repo"; const REFS_QUERY = gql` @@ -126,9 +125,9 @@ export const Route = createFileRoute("/$repo/")({ component: RouteComponent, pendingComponent: CodePageSkeleton, validateSearch: (search) => v.parse(codePageSearchSchema, search), - loader: async ({ params: { repo } }) => { + loader: async ({ context: { preloadQuery, ref } }) => { const refsRef = preloadQuery(REFS_QUERY, { - variables: { repo: repo === "_" ? null : repo }, + variables: { repo: ref }, }); return { refsRef: await preloadQuery.toPromise(refsRef) }; }, diff --git a/webui2/src/routes/$repo/issues/$id.tsx b/webui2/src/routes/$repo/issues/$id.tsx index 33b675e481f954388c3c1ad3e6005ae9189a3e55..54668672b26cd2de681ca9e77c27db3fbebb0b4f 100644 --- a/webui2/src/routes/$repo/issues/$id.tsx +++ b/webui2/src/routes/$repo/issues/$id.tsx @@ -3,12 +3,7 @@ import { createFileRoute, Link } from "@tanstack/react-router"; import { formatDistanceToNow } from "date-fns"; import { ArrowLeft } from "lucide-react"; -import { - type BugDetailQuery, - BugDetailDocument, - type ValidLabelsQuery, - ValidLabelsDocument, -} from "@/__generated__/graphql"; +import { type BugDetailQuery, BugDetailDocument } from "@/__generated__/graphql"; import { CommentBox } from "@/components/bugs/CommentBox"; import { LabelEditor } from "@/components/bugs/LabelEditor"; import { StatusBadge } from "@/components/bugs/StatusBadge"; @@ -17,24 +12,16 @@ import { TitleEditor } from "@/components/bugs/TitleEditor"; import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Separator } from "@/components/ui/separator"; import { Skeleton } from "@/components/ui/skeleton"; -import { preloadQuery } from "@/lib/apollo"; import { useRepo } from "@/lib/repo"; export const Route = createFileRoute("/$repo/issues/$id")({ component: RouteComponent, pendingComponent: BugDetailSkeleton, - loader: async ({ params: { repo, id } }) => { - const ref = repo === "_" ? null : repo; + loader: async ({ context: { preloadQuery, ref }, params: { id } }) => { const bugDetailRef = preloadQuery(BugDetailDocument, { variables: { ref, prefix: id }, }); - const labelsRef = preloadQuery(ValidLabelsDocument, { - variables: { ref }, - }); - return { - bugDetailRef: await preloadQuery.toPromise(bugDetailRef), - labelsRef: await preloadQuery.toPromise(labelsRef), - }; + return { bugDetailRef: await preloadQuery.toPromise(bugDetailRef) }; }, }); @@ -42,7 +29,8 @@ export const Route = createFileRoute("/$repo/issues/$id")({ // comments and events, and a sidebar with labels and participants. function RouteComponent() { const repo = useRepo(); - const { bugDetailRef, labelsRef } = Route.useLoaderData(); + const { bugDetailRef } = Route.useLoaderData(); + const { labelsRef } = Route.useRouteContext(); const { data } = useReadQuery(bugDetailRef); const { data: labelsData } = useReadQuery(labelsRef); const validLabels = labelsData?.repository?.validLabels.nodes ?? []; diff --git a/webui2/src/routes/$repo/issues/index.tsx b/webui2/src/routes/$repo/issues/index.tsx index 5e7c770df947fddfefd665e025eb7022553f23eb..b8a941b2433ecbc95a861b9c3dce4652d30e363c 100644 --- a/webui2/src/routes/$repo/issues/index.tsx +++ b/webui2/src/routes/$repo/issues/index.tsx @@ -4,14 +4,7 @@ import { CircleDot, CircleCheck, ChevronLeft, ChevronRight } from "lucide-react" import { useState } from "react"; import * as v from "valibot"; -import { - type BugListQuery, - BugListDocument, - type ValidLabelsQuery, - ValidLabelsDocument, - type AllIdentitiesQuery, - AllIdentitiesDocument, -} from "@/__generated__/graphql"; +import { type BugListQuery, BugListDocument } from "@/__generated__/graphql"; import { BugRow } from "@/components/bugs/BugRow"; import { IssueFilters } from "@/components/bugs/IssueFilters"; import type { SortValue } from "@/components/bugs/IssueFilters"; @@ -19,7 +12,6 @@ import { QueryInput } from "@/components/bugs/QueryInput"; import { Button } from "@/components/ui/button"; import { ButtonLink } from "@/components/ui/button-link"; import { Skeleton } from "@/components/ui/skeleton"; -import { preloadQuery } from "@/lib/apollo"; import { useRepo } from "@/lib/repo"; import { cn } from "@/lib/utils"; @@ -33,8 +25,7 @@ export const Route = createFileRoute("/$repo/issues/")({ pendingComponent: BugListSkeleton, validateSearch: (search) => v.parse(issuesSearchSchema, search), loaderDeps: ({ search: { q, after } }) => ({ q, after }), - loader: async ({ params: { repo }, deps: { q, after } }) => { - const ref = repo === "_" ? null : repo; + loader: async ({ context: { preloadQuery, ref }, deps: { q, after } }) => { const parsed = parseQueryString(q); const baseQuery = buildBaseQuery(parsed.labels, parsed.author, parsed.freeText); const bugListRef = preloadQuery(BugListDocument, { @@ -47,17 +38,7 @@ export const Route = createFileRoute("/$repo/issues/")({ after: after || undefined, }, }); - const labelsRef = preloadQuery(ValidLabelsDocument, { - variables: { ref }, - }); - const identitiesRef = preloadQuery(AllIdentitiesDocument, { - variables: { ref }, - }); - return { - bugListRef: await preloadQuery.toPromise(bugListRef), - labelsRef: await preloadQuery.toPromise(labelsRef), - identitiesRef: await preloadQuery.toPromise(identitiesRef), - }; + return { bugListRef: await preloadQuery.toPromise(bugListRef) }; }, }); @@ -84,7 +65,8 @@ function RouteComponent() { // Draft is the text input value — starts from URL, only committed on submit const [draft, setDraft] = useState(q); - const { bugListRef, labelsRef, identitiesRef } = Route.useLoaderData(); + const { bugListRef } = Route.useLoaderData(); + const { labelsRef, identitiesRef } = Route.useRouteContext(); const { data } = useReadQuery(bugListRef); const { data: labelsData } = useReadQuery(labelsRef); const { data: identitiesData } = useReadQuery(identitiesRef); diff --git a/webui2/src/routes/__root.tsx b/webui2/src/routes/__root.tsx index be549dea3884f041b6b92c7e410f691389944fa2..30a7f77da9489da2fc6af9ede63bb18e85c07b73 100644 --- a/webui2/src/routes/__root.tsx +++ b/webui2/src/routes/__root.tsx @@ -1,11 +1,16 @@ -import { createRootRoute, useRouter } from "@tanstack/react-router"; +import { createRootRouteWithContext, useRouter } from "@tanstack/react-router"; import { AlertTriangle } from "lucide-react"; import { Shell } from "@/components/layout/Shell"; import { Button } from "@/components/ui/button"; import { ButtonLink } from "@/components/ui/button-link"; +import type { preloadQuery } from "@/lib/apollo"; -export const Route = createRootRoute({ +export interface RouterContext { + preloadQuery: typeof preloadQuery; +} + +export const Route = createRootRouteWithContext()({ component: Shell, errorComponent: ErrorPage, }); diff --git a/webui2/src/routes/index.tsx b/webui2/src/routes/index.tsx index e684a35c97fee6a824bb8766b3532d2cbf892e20..8a38c6e1dffd260aac7789566effe345bd97d298 100644 --- a/webui2/src/routes/index.tsx +++ b/webui2/src/routes/index.tsx @@ -7,11 +7,10 @@ import { GitFork, FolderOpen, AlertCircle } from "lucide-react"; import { useEffect } from "react"; import { type RepositoriesQuery, RepositoriesDocument } from "@/__generated__/graphql"; -import { preloadQuery } from "@/lib/apollo"; export const Route = createFileRoute("/")({ component: RouteComponent, - loader: async () => { + loader: async ({ context: { preloadQuery } }) => { const repositoriesRef = preloadQuery(RepositoriesDocument); return { repositoriesRef: await preloadQuery.toPromise(repositoriesRef) }; },