Detailed changes
@@ -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" {
@@ -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<ValidLabelsQuery>(ValidLabelsDocument, {
+ variables: { ref },
+ });
+ const identitiesRef = preloadQuery<AllIdentitiesQuery>(AllIdentitiesDocument, {
+ variables: { ref },
+ });
+
+ return { ref, labelsRef, identitiesRef };
+ },
});
@@ -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<CommitQueryData>(COMMIT_QUERY, {
- variables: { repo: repo === "_" ? null : repo, hash },
+ variables: { repo: ref, hash },
});
return { commitRef: await preloadQuery.toPromise(commitRef) };
},
@@ -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<RefsQueryData>(REFS_QUERY, {
- variables: { repo: repo === "_" ? null : repo },
+ variables: { repo: ref },
});
return { refsRef: await preloadQuery.toPromise(refsRef) };
},
@@ -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<BugDetailQuery>(BugDetailDocument, {
variables: { ref, prefix: id },
});
- const labelsRef = preloadQuery<ValidLabelsQuery>(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 ?? [];
@@ -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<BugListQuery>(BugListDocument, {
@@ -47,17 +38,7 @@ export const Route = createFileRoute("/$repo/issues/")({
after: after || undefined,
},
});
- const labelsRef = preloadQuery<ValidLabelsQuery>(ValidLabelsDocument, {
- variables: { ref },
- });
- const identitiesRef = preloadQuery<AllIdentitiesQuery>(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);
@@ -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<RouterContext>()({
component: Shell,
errorComponent: ErrorPage,
});
@@ -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<RepositoriesQuery>(RepositoriesDocument);
return { repositoriesRef: await preloadQuery.toPromise(repositoriesRef) };
},