refactor(web): use typed document nodes, eliminate wide type imports

Quentin Gliech and Claude Opus 4.6 (1M context) created

Replace wide GraphQL type imports (GitRef) with query-derived types
using ResultOf. Un-export fragment consts that are only used locally
for codegen registration. Replace GitRef with RefsQueryRef in the
ref-selector and code layout.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Change summary

webui2/src/components/bugs/timeline.tsx       | 10 +++++-----
webui2/src/components/code/ref-selector.tsx   |  9 +++++----
webui2/src/components/shared/comment-card.tsx |  2 +-
webui2/src/components/shared/issue-row.tsx    |  2 +-
webui2/src/components/shared/label-badge.tsx  |  2 +-
webui2/src/routes/$repo.tsx                   |  8 ++++++++
webui2/src/routes/$repo/_code.tsx             |  6 +++---
webui2/src/routes/$repo/index.tsx             |  4 ++--
8 files changed, 26 insertions(+), 17 deletions(-)

Detailed changes

webui2/src/components/bugs/timeline.tsx 🔗

@@ -13,7 +13,7 @@ import { LabelBadge } from "@/components/shared/label-badge";
 import { Textarea } from "@/components/ui/textarea";
 import { useAuth } from "@/lib/auth";
 
-export const BUG_CREATE_COMMENT_FIELDS = graphql(`
+const BUG_CREATE_COMMENT_FIELDS = graphql(`
   fragment BugCreateCommentFields on BugCreateTimelineItem {
     author {
       ...IdentitySummary
@@ -25,7 +25,7 @@ export const BUG_CREATE_COMMENT_FIELDS = graphql(`
   }
 `);
 
-export const BUG_ADD_COMMENT_FIELDS = graphql(`
+const BUG_ADD_COMMENT_FIELDS = graphql(`
   fragment BugAddCommentFields on BugAddCommentTimelineItem {
     author {
       ...IdentitySummary
@@ -37,7 +37,7 @@ export const BUG_ADD_COMMENT_FIELDS = graphql(`
   }
 `);
 
-export const LABEL_CHANGE_FIELDS = graphql(`
+const LABEL_CHANGE_FIELDS = graphql(`
   fragment LabelChangeFields on BugLabelChangeTimelineItem {
     author {
       humanId
@@ -53,7 +53,7 @@ export const LABEL_CHANGE_FIELDS = graphql(`
   }
 `);
 
-export const STATUS_CHANGE_FIELDS = graphql(`
+const STATUS_CHANGE_FIELDS = graphql(`
   fragment StatusChangeFields on BugSetStatusTimelineItem {
     author {
       humanId
@@ -64,7 +64,7 @@ export const STATUS_CHANGE_FIELDS = graphql(`
   }
 `);
 
-export const TITLE_CHANGE_FIELDS = graphql(`
+const TITLE_CHANGE_FIELDS = graphql(`
   fragment TitleChangeFields on BugSetTitleTimelineItem {
     author {
       humanId

webui2/src/components/code/ref-selector.tsx 🔗

@@ -13,15 +13,16 @@ import {
 import { GitBranch, Tag } from "lucide-react";
 import { useEffect, useRef, useState } from "react";
 
-import { GitRefType, type GitRef } from "@/__generated__/graphql";
+import { GitRefType } from "@/__generated__/graphql";
+import type { RefsQueryRef } from "@/routes/$repo";
 import { Button } from "@/components/ui/button";
 import * as Listbox from "@/components/ui/listbox";
 import { cn } from "@/lib/utils";
 
 interface RefSelectorProps {
-  gitRefs: GitRef[];
+  gitRefs: RefsQueryRef[];
   currentRef: string;
-  onSelect: (ref: GitRef) => void;
+  onSelect: (ref: RefsQueryRef) => void;
 }
 
 // Branch / tag selector dropdown for the code browser. Shown in two groups
@@ -200,7 +201,7 @@ function RefItem({
   onSelect,
 }: {
   id: string;
-  ref_: GitRef;
+  ref_: RefsQueryRef;
   index: number;
   active: boolean;
   selected: boolean;

webui2/src/components/shared/comment-card.tsx 🔗

@@ -4,7 +4,7 @@ import { cn } from "@/lib/utils";
 
 import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
 
-export const IDENTITY_SUMMARY_FRAGMENT = graphql(`
+const IDENTITY_SUMMARY_FRAGMENT = graphql(`
   fragment IdentitySummary on Identity {
     id
     humanId

webui2/src/components/shared/issue-row.tsx 🔗

@@ -4,7 +4,7 @@ import { Status } from "@/__generated__/graphql";
 import { graphql } from "@/__generated__/gql";
 import { cn } from "@/lib/utils";
 
-export const BUG_SUMMARY_FRAGMENT = graphql(`
+const BUG_SUMMARY_FRAGMENT = graphql(`
   fragment BugSummary on Bug {
     id
     humanId

webui2/src/components/shared/label-badge.tsx 🔗

@@ -4,7 +4,7 @@ import * as React from "react";
 import type { LabelFieldsFragment } from "@/__generated__/graphql";
 import { graphql } from "@/__generated__/gql";
 
-export const LABEL_FIELDS_FRAGMENT = graphql(`
+const LABEL_FIELDS_FRAGMENT = graphql(`
   fragment LabelFields on Label {
     name
     color {

webui2/src/routes/$repo.tsx 🔗

@@ -1,4 +1,5 @@
 import { createFileRoute } from "@tanstack/react-router";
+import type { ResultOf } from "@graphql-typed-document-node/core";
 
 import { graphql } from "@/__generated__/gql";
 
@@ -21,6 +22,13 @@ export const REFS_QUERY = graphql(`
   }
 `);
 
+export type RefsQueryData = ResultOf<typeof REFS_QUERY>;
+
+/** A single git ref as returned by the REFS_QUERY. */
+export type RefsQueryRef = NonNullable<
+  NonNullable<RefsQueryData["repository"]>["refs"]
+>["nodes"][number];
+
 export const Route = createFileRoute("/$repo")({
   beforeLoad: ({ params: { repo }, context: { preloadQuery } }) => {
     // Normalize the repo slug: "_" means the default (null) repo

webui2/src/routes/$repo/_code.tsx 🔗

@@ -12,7 +12,7 @@ import {
 } from "@tanstack/react-router";
 import { GitCommit } from "lucide-react";
 
-import type { GitRef } from "@/__generated__/graphql";
+import type { RefsQueryRef } from "@/routes/$repo";
 import { CodeBreadcrumb } from "@/components/code/code-breadcrumb";
 import { RefSelector } from "@/components/code/ref-selector";
 import { ButtonLink } from "@/components/ui/button-link";
@@ -29,7 +29,7 @@ function CodeLayout() {
   const { repo } = Route.useParams();
   const { ref: repoRef, refsRef } = Route.useRouteContext();
   const { data: refsData } = useReadQuery(refsRef);
-  const refs: GitRef[] = refsData?.repository?.refs?.nodes ?? [];
+  const refs: RefsQueryRef[] = refsData?.repository?.refs?.nodes ?? [];
   const repoName = refsData?.repository?.name ?? repoRef ?? "default-repo";
 
   // Read child route params (ref and splat path)
@@ -51,7 +51,7 @@ function CodeLayout() {
 
   const navigate = useNavigate();
 
-  function handleRefSelect(newRef: GitRef) {
+  function handleRefSelect(newRef: RefsQueryRef) {
     const refName = newRef.shortName;
     if (viewMode === "commits") {
       void navigate({ to: "/$repo/commits/$ref", params: { repo, ref: refName }, search: { path: currentPath || undefined } });

webui2/src/routes/$repo/index.tsx 🔗

@@ -5,11 +5,11 @@
 import { createFileRoute, redirect } from "@tanstack/react-router";
 
 import { client } from "@/lib/apollo";
-import { REFS_QUERY, type RefsQueryData } from "@/routes/$repo";
+import { REFS_QUERY } from "@/routes/$repo";
 
 export const Route = createFileRoute("/$repo/")({
   beforeLoad: async ({ context: { ref }, params: { repo } }) => {
-    const { data } = await client.query<RefsQueryData>({
+    const { data } = await client.query({
       query: REFS_QUERY,
       variables: { repo: ref },
     });