refactor(web): switch to graphql-codegen client-preset

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

Replace typescript + typescript-operations + typescript-react-apollo
plugins with the client-preset. This generates typed document nodes and
a graphql() function, removing the need for generated hooks.

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

Change summary

webui2/codegen.ts                                     |  23 
webui2/package.json                                   |   7 
webui2/pnpm-lock.yaml                                 | 123 ++--
webui2/src/__generated__/fragment-masking.ts          |  87 +++
webui2/src/__generated__/gql.ts                       | 157 +++++
webui2/src/__generated__/graphql.ts                   | 369 +++++++-----
webui2/src/__generated__/index.ts                     |   1 
webui2/src/components/bugs/comment-box.tsx            |  74 ++
webui2/src/components/bugs/label-editor.tsx           |  25 
webui2/src/components/bugs/timeline.graphql           |  52 -
webui2/src/components/bugs/timeline.tsx               |  85 ++
webui2/src/components/bugs/title-editor.tsx           |  17 
webui2/src/components/code/commit-list.tsx            |  17 
webui2/src/components/code/file-diff-view.tsx         |  23 
webui2/src/components/shared/comment-card.tsx         |  10 
webui2/src/components/shared/identity-summary.graphql |   6 
webui2/src/components/shared/issue-row.graphql        |  16 
webui2/src/components/shared/issue-row.tsx            |  20 
webui2/src/components/shared/label-badge.graphql      |   8 
webui2/src/components/shared/label-badge.tsx          |  12 
webui2/src/graphql/AllIdentities.graphql              |  15 
webui2/src/graphql/BugDetail.graphql                  |  34 -
webui2/src/graphql/BugList.graphql                    |  30 -
webui2/src/graphql/BugMutations.graphql               |  83 --
webui2/src/graphql/Repositories.graphql               |   9 
webui2/src/graphql/UserProfile.graphql                |  42 -
webui2/src/graphql/ValidLabels.graphql                |  14 
webui2/src/lib/auth.tsx                               |  13 
webui2/src/routes/$repo.tsx                           |  17 
webui2/src/routes/$repo/_code/blob/$ref/$.tsx         |  13 
webui2/src/routes/$repo/_code/tree/$ref/$.tsx         |  75 +-
webui2/src/routes/$repo/_issues.tsx                   |  46 +
webui2/src/routes/$repo/_issues/issues/$id.tsx        |  41 +
webui2/src/routes/$repo/_issues/issues/index.tsx      |  34 +
webui2/src/routes/$repo/_issues/issues/new.tsx        |  16 
webui2/src/routes/$repo/_issues/user/$id.tsx          |  44 +
webui2/src/routes/$repo/commit/$hash.tsx              |  26 
webui2/src/routes/index.tsx                           |  15 
38 files changed, 1,000 insertions(+), 699 deletions(-)

Detailed changes

webui2/codegen.ts 🔗

@@ -1,16 +1,25 @@
 import type { CodegenConfig } from "@graphql-codegen/cli";
 
 const config: CodegenConfig = {
+  overwrite: true,
   schema: "../api/graphql/schema/*.graphql",
-  documents: ["src/graphql/**/*.graphql", "src/components/**/*.graphql"],
+  documents: ["src/**/*.{ts,tsx}", "!src/__generated__/**/*"],
+  ignoreNoDocuments: true,
   generates: {
-    "src/__generated__/graphql.ts": {
-      plugins: ["typescript", "typescript-operations", "typescript-react-apollo"],
+    "./src/__generated__/": {
+      preset: "client",
+      presetConfig: {
+        fragmentMasking: false,
+      },
       config: {
-        withHooks: true,
-        withComponent: false,
-        withHOC: false,
-        apolloReactHooksImportFrom: "@apollo/client/react",
+        useTypeImports: true,
+        avoidOptionals: {
+          field: true,
+          inputValue: false,
+        },
+        defaultScalarType: "unknown",
+        nonOptionalTypename: true,
+        skipTypeNameForRoot: true,
         scalars: {
           Time: "string",
           Hash: "string",

webui2/package.json 🔗

@@ -19,7 +19,7 @@
     "build-storybook": "storybook build"
   },
   "dependencies": {
-    "@apollo/client": "^4.1.6",
+    "@apollo/client": "^4.1.7",
     "@base-ui/react": "^1.3.0",
     "@floating-ui/react": "^0.27.19",
     "@fontsource-variable/geist": "^5.2.8",
@@ -52,9 +52,8 @@
   },
   "devDependencies": {
     "@graphql-codegen/cli": "^6.2.1",
-    "@graphql-codegen/typescript": "^5.0.9",
-    "@graphql-codegen/typescript-operations": "^5.0.9",
-    "@graphql-codegen/typescript-react-apollo": "^4.3.2",
+    "@graphql-codegen/client-preset": "^5.2.4",
+    "@graphql-typed-document-node/core": "^3.2.0",
     "@storybook/addon-a11y": "^10.3.4",
     "@storybook/addon-vitest": "^10.3.4",
     "@storybook/react": "^10.3.4",

webui2/pnpm-lock.yaml 🔗

@@ -9,8 +9,8 @@ importers:
   .:
     dependencies:
       '@apollo/client':
-        specifier: ^4.1.6
-        version: 4.1.6(graphql-ws@6.0.8(graphql@16.13.2)(ws@8.20.0))(graphql@16.13.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rxjs@7.8.2)
+        specifier: ^4.1.7
+        version: 4.1.7(graphql-ws@6.0.8(graphql@16.13.2)(ws@8.20.0))(graphql@16.13.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rxjs@7.8.2)
       '@base-ui/react':
         specifier: ^1.3.0
         version: 1.3.0(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
@@ -102,15 +102,12 @@ importers:
       '@graphql-codegen/cli':
         specifier: ^6.2.1
         version: 6.2.1(@types/node@25.5.0)(graphql@16.13.2)(typescript@6.0.2)
-      '@graphql-codegen/typescript':
-        specifier: ^5.0.9
-        version: 5.0.9(graphql@16.13.2)
-      '@graphql-codegen/typescript-operations':
-        specifier: ^5.0.9
-        version: 5.0.9(graphql@16.13.2)
-      '@graphql-codegen/typescript-react-apollo':
-        specifier: ^4.3.2
-        version: 4.4.1(graphql@16.13.2)
+      '@graphql-codegen/client-preset':
+        specifier: ^5.2.4
+        version: 5.2.4(graphql@16.13.2)
+      '@graphql-typed-document-node/core':
+        specifier: ^3.2.0
+        version: 3.2.0(graphql@16.13.2)
       '@storybook/addon-a11y':
         specifier: ^10.3.4
         version: 10.3.4(storybook@10.3.4(@testing-library/dom@10.4.1)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))
@@ -210,8 +207,8 @@ packages:
   '@adobe/css-tools@4.4.4':
     resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==}
 
-  '@apollo/client@4.1.6':
-    resolution: {integrity: sha512-ak8uzqmKeX3u9BziGf83RRyODAJKFkPG72hTNvEj4WjMWFmuKW2gGN1i3OfajKT6yuGjvo+n23ES2zqWDKFCZg==}
+  '@apollo/client@4.1.7':
+    resolution: {integrity: sha512-CE1Pe22vszRBMGrBOovIXzTa5infy1kwF0kWX2JBLcGFXoOPBOAo9zoM++tuSRZr8PscWJyv2ka2FKoyEquEHw==}
     peerDependencies:
       graphql: ^16.0.0
       graphql-ws: ^5.5.5 || ^6.0.3
@@ -234,12 +231,12 @@ packages:
     peerDependencies:
       graphql: '*'
 
-  '@asamuzakjp/css-color@5.1.5':
-    resolution: {integrity: sha512-8cMAA1bE66Mb/tfmkhcfJLjEPgyT7SSy6lW6id5XL113ai1ky76d/1L27sGnXCMsLfq66DInAU3OzuahB4lu9Q==}
+  '@asamuzakjp/css-color@5.1.8':
+    resolution: {integrity: sha512-OISPR9c2uPo23rUdvfEQiLPjoMLOpEeLNnP5iGkxr6tDDxJd3NjD+6fxY0mdaMbIPUjFGL4HFOJqLvow5q4aqQ==}
     engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
 
-  '@asamuzakjp/dom-selector@7.0.6':
-    resolution: {integrity: sha512-Tgmk6EQM0nc9xvp7sEHRVavbknhb/vGKht+04yAT3t5KQwZ02CSobCtcFgaHH04ZrjD1BhEKNA8tRhzFV20gkA==}
+  '@asamuzakjp/dom-selector@7.0.8':
+    resolution: {integrity: sha512-erMO6FgtM02dC24NGm0xufMzWz5OF0wXKR7BpvGD973bq/GbmR8/DbxNZbj0YevQ5hlToJaWSVK/G9/NDgGEVw==}
     engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
 
   '@asamuzakjp/nwsapi@2.3.9':
@@ -649,24 +646,24 @@ packages:
     resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==}
     engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
 
-  '@eslint/config-array@0.23.4':
-    resolution: {integrity: sha512-lf19F24LSMfF8weXvW5QEtnLqW70u7kgit5e9PSx0MsHAFclGd1T9ynvWEMDT1w5J4Qt54tomGeAhdoAku1Xow==}
+  '@eslint/config-array@0.23.5':
+    resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==}
     engines: {node: ^20.19.0 || ^22.13.0 || >=24}
 
-  '@eslint/config-helpers@0.5.4':
-    resolution: {integrity: sha512-jJhqiY3wPMlWWO3370M86CPJ7pt8GmEwSLglMfQhjXal07RCvhmU0as4IuUEW5SJeunfItiEetHmSxCCe9lDBg==}
+  '@eslint/config-helpers@0.5.5':
+    resolution: {integrity: sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w==}
     engines: {node: ^20.19.0 || ^22.13.0 || >=24}
 
-  '@eslint/core@1.2.0':
-    resolution: {integrity: sha512-8FTGbNzTvmSlc4cZBaShkC6YvFMG0riksYWRFKXztqVdXaQbcZLXlFbSpC05s70sGEsXAw0qwhx69JiW7hQS7A==}
+  '@eslint/core@1.2.1':
+    resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==}
     engines: {node: ^20.19.0 || ^22.13.0 || >=24}
 
-  '@eslint/object-schema@3.0.4':
-    resolution: {integrity: sha512-55lO/7+Yp0ISKRP0PsPtNTeNGapXaO085aELZmWCVc5SH3jfrqpuU6YgOdIxMS99ZHkQN1cXKE+cdIqwww9ptw==}
+  '@eslint/object-schema@3.0.5':
+    resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==}
     engines: {node: ^20.19.0 || ^22.13.0 || >=24}
 
-  '@eslint/plugin-kit@0.7.0':
-    resolution: {integrity: sha512-ejvBr8MQCbVsWNZnCwDXjUKq40MDmHalq7cJ6e9s/qzTUFIIo/afzt1Vui9T97FM/V/pN4YsFVoed5NIa96RDg==}
+  '@eslint/plugin-kit@0.7.1':
+    resolution: {integrity: sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==}
     engines: {node: ^20.19.0 || ^22.13.0 || >=24}
 
   '@exodus/bytes@1.15.0':
@@ -772,12 +769,6 @@ packages:
       graphql-sock:
         optional: true
 
-  '@graphql-codegen/typescript-react-apollo@4.4.1':
-    resolution: {integrity: sha512-lrjUfDCNlCWQU07jO6EvZE8I2OLfJl9XKKGCcol27OhW6B9xaUEPaId+TvL6o/NfV+T4z4eQ/Y8BuKWyYjD+mQ==}
-    engines: {node: '>= 16.0.0'}
-    peerDependencies:
-      graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
-
   '@graphql-codegen/typescript@5.0.9':
     resolution: {integrity: sha512-YlIZ4nqdFdzr5vxuNtQtZnnMYuZ5cLYB2HaGhGI2zvqHxCmkBjIRpu/5sfccawKy23wetV+aoWvoNqxGKIryig==}
     engines: {node: '>=16'}
@@ -3558,6 +3549,10 @@ packages:
     resolution: {integrity: sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==}
     engines: {node: 20 || >=22}
 
+  lru-cache@11.3.3:
+    resolution: {integrity: sha512-JvNw9Y81y33E+BEYPr0U7omo+U9AySnsMsEiXgwT6yqd31VQWTLNQqmT4ou5eqPFUrTfIDFta2wKhB1hyohtAQ==}
+    engines: {node: 20 || >=22}
+
   lru-cache@5.1.1:
     resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
 
@@ -3775,6 +3770,10 @@ packages:
     resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==}
     engines: {node: 18 || 20 || >=22}
 
+  minimatch@10.2.5:
+    resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==}
+    engines: {node: 18 || 20 || >=22}
+
   minimist@1.2.8:
     resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
 
@@ -4970,7 +4969,7 @@ snapshots:
 
   '@adobe/css-tools@4.4.4': {}
 
-  '@apollo/client@4.1.6(graphql-ws@6.0.8(graphql@16.13.2)(ws@8.20.0))(graphql@16.13.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rxjs@7.8.2)':
+  '@apollo/client@4.1.7(graphql-ws@6.0.8(graphql@16.13.2)(ws@8.20.0))(graphql@16.13.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rxjs@7.8.2)':
     dependencies:
       '@graphql-typed-document-node/core': 3.2.0(graphql@16.13.2)
       '@wry/caches': 1.0.1
@@ -4993,22 +4992,20 @@ snapshots:
       immutable: 5.1.5
       invariant: 2.2.4
 
-  '@asamuzakjp/css-color@5.1.5':
+  '@asamuzakjp/css-color@5.1.8':
     dependencies:
       '@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
       '@csstools/css-color-parser': 4.0.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)
       '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0)
       '@csstools/css-tokenizer': 4.0.0
-      lru-cache: 11.2.7
     optional: true
 
-  '@asamuzakjp/dom-selector@7.0.6':
+  '@asamuzakjp/dom-selector@7.0.8':
     dependencies:
       '@asamuzakjp/nwsapi': 2.3.9
       bidi-js: 1.0.3
       css-tree: 3.2.1
       is-potential-custom-element-name: 1.0.1
-      lru-cache: 11.2.7
     optional: true
 
   '@asamuzakjp/nwsapi@2.3.9':
@@ -5405,27 +5402,27 @@ snapshots:
 
   '@eslint-community/regexpp@4.12.2': {}
 
-  '@eslint/config-array@0.23.4':
+  '@eslint/config-array@0.23.5':
     dependencies:
-      '@eslint/object-schema': 3.0.4
+      '@eslint/object-schema': 3.0.5
       debug: 4.4.3
-      minimatch: 10.2.4
+      minimatch: 10.2.5
     transitivePeerDependencies:
       - supports-color
 
-  '@eslint/config-helpers@0.5.4':
+  '@eslint/config-helpers@0.5.5':
     dependencies:
-      '@eslint/core': 1.2.0
+      '@eslint/core': 1.2.1
 
-  '@eslint/core@1.2.0':
+  '@eslint/core@1.2.1':
     dependencies:
       '@types/json-schema': 7.0.15
 
-  '@eslint/object-schema@3.0.4': {}
+  '@eslint/object-schema@3.0.5': {}
 
-  '@eslint/plugin-kit@0.7.0':
+  '@eslint/plugin-kit@0.7.1':
     dependencies:
-      '@eslint/core': 1.2.0
+      '@eslint/core': 1.2.1
       levn: 0.4.1
 
   '@exodus/bytes@1.15.0(@noble/hashes@1.8.0)':
@@ -5586,15 +5583,6 @@ snapshots:
       graphql: 16.13.2
       tslib: 2.6.3
 
-  '@graphql-codegen/typescript-react-apollo@4.4.1(graphql@16.13.2)':
-    dependencies:
-      '@graphql-codegen/plugin-helpers': 6.2.0(graphql@16.13.2)
-      '@graphql-codegen/visitor-plugin-common': 6.2.4(graphql@16.13.2)
-      auto-bind: 4.0.0
-      change-case-all: 1.0.15
-      graphql: 16.13.2
-      tslib: 2.8.1
-
   '@graphql-codegen/typescript@5.0.9(graphql@16.13.2)':
     dependencies:
       '@graphql-codegen/plugin-helpers': 6.2.0(graphql@16.13.2)
@@ -7563,10 +7551,10 @@ snapshots:
     dependencies:
       '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.0(jiti@2.6.1))
       '@eslint-community/regexpp': 4.12.2
-      '@eslint/config-array': 0.23.4
-      '@eslint/config-helpers': 0.5.4
-      '@eslint/core': 1.2.0
-      '@eslint/plugin-kit': 0.7.0
+      '@eslint/config-array': 0.23.5
+      '@eslint/config-helpers': 0.5.5
+      '@eslint/core': 1.2.1
+      '@eslint/plugin-kit': 0.7.1
       '@humanfs/node': 0.16.7
       '@humanwhocodes/module-importer': 1.0.1
       '@humanwhocodes/retry': 0.4.3
@@ -7588,7 +7576,7 @@ snapshots:
       imurmurhash: 0.1.4
       is-glob: 4.0.3
       json-stable-stringify-without-jsonify: 1.0.1
-      minimatch: 10.2.4
+      minimatch: 10.2.5
       natural-compare: 1.4.0
       optionator: 0.9.4
     optionalDependencies:
@@ -8229,8 +8217,8 @@ snapshots:
 
   jsdom@29.0.1(@noble/hashes@1.8.0):
     dependencies:
-      '@asamuzakjp/css-color': 5.1.5
-      '@asamuzakjp/dom-selector': 7.0.6
+      '@asamuzakjp/css-color': 5.1.8
+      '@asamuzakjp/dom-selector': 7.0.8
       '@bramus/specificity': 2.4.2
       '@csstools/css-syntax-patches-for-csstree': 1.1.2(css-tree@3.2.1)
       '@exodus/bytes': 1.15.0(@noble/hashes@1.8.0)
@@ -8239,7 +8227,7 @@ snapshots:
       decimal.js: 10.6.0
       html-encoding-sniffer: 6.0.0(@noble/hashes@1.8.0)
       is-potential-custom-element-name: 1.0.1
-      lru-cache: 11.2.7
+      lru-cache: 11.3.3
       parse5: 8.0.0
       saxes: 6.0.0
       symbol-tree: 3.2.4
@@ -8398,6 +8386,9 @@ snapshots:
 
   lru-cache@11.2.7: {}
 
+  lru-cache@11.3.3:
+    optional: true
+
   lru-cache@5.1.1:
     dependencies:
       yallist: 3.1.1
@@ -8808,6 +8799,10 @@ snapshots:
     dependencies:
       brace-expansion: 5.0.5
 
+  minimatch@10.2.5:
+    dependencies:
+      brace-expansion: 5.0.5
+
   minimist@1.2.8: {}
 
   minipass@7.1.3: {}

webui2/src/__generated__/fragment-masking.ts 🔗

@@ -0,0 +1,87 @@
+/* eslint-disable */
+import type { ResultOf, DocumentTypeDecoration, TypedDocumentNode } from '@graphql-typed-document-node/core';
+import type { FragmentDefinitionNode } from 'graphql';
+import type { Incremental } from './graphql';
+
+
+export type FragmentType<TDocumentType extends DocumentTypeDecoration<any, any>> = TDocumentType extends DocumentTypeDecoration<
+  infer TType,
+  any
+>
+  ? [TType] extends [{ ' $fragmentName'?: infer TKey }]
+    ? TKey extends string
+      ? { ' $fragmentRefs'?: { [key in TKey]: TType } }
+      : never
+    : never
+  : never;
+
+// return non-nullable if `fragmentType` is non-nullable
+export function useFragment<TType>(
+  _documentNode: DocumentTypeDecoration<TType, any>,
+  fragmentType: FragmentType<DocumentTypeDecoration<TType, any>>
+): TType;
+// return nullable if `fragmentType` is undefined
+export function useFragment<TType>(
+  _documentNode: DocumentTypeDecoration<TType, any>,
+  fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | undefined
+): TType | undefined;
+// return nullable if `fragmentType` is nullable
+export function useFragment<TType>(
+  _documentNode: DocumentTypeDecoration<TType, any>,
+  fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | null
+): TType | null;
+// return nullable if `fragmentType` is nullable or undefined
+export function useFragment<TType>(
+  _documentNode: DocumentTypeDecoration<TType, any>,
+  fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | null | undefined
+): TType | null | undefined;
+// return array of non-nullable if `fragmentType` is array of non-nullable
+export function useFragment<TType>(
+  _documentNode: DocumentTypeDecoration<TType, any>,
+  fragmentType: Array<FragmentType<DocumentTypeDecoration<TType, any>>>
+): Array<TType>;
+// return array of nullable if `fragmentType` is array of nullable
+export function useFragment<TType>(
+  _documentNode: DocumentTypeDecoration<TType, any>,
+  fragmentType: Array<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined
+): Array<TType> | null | undefined;
+// return readonly array of non-nullable if `fragmentType` is array of non-nullable
+export function useFragment<TType>(
+  _documentNode: DocumentTypeDecoration<TType, any>,
+  fragmentType: ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>>
+): ReadonlyArray<TType>;
+// return readonly array of nullable if `fragmentType` is array of nullable
+export function useFragment<TType>(
+  _documentNode: DocumentTypeDecoration<TType, any>,
+  fragmentType: ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined
+): ReadonlyArray<TType> | null | undefined;
+export function useFragment<TType>(
+  _documentNode: DocumentTypeDecoration<TType, any>,
+  fragmentType: FragmentType<DocumentTypeDecoration<TType, any>> | Array<FragmentType<DocumentTypeDecoration<TType, any>>> | ReadonlyArray<FragmentType<DocumentTypeDecoration<TType, any>>> | null | undefined
+): TType | Array<TType> | ReadonlyArray<TType> | null | undefined {
+  return fragmentType as any;
+}
+
+
+export function makeFragmentData<
+  F extends DocumentTypeDecoration<any, any>,
+  FT extends ResultOf<F>
+>(data: FT, _fragment: F): FragmentType<F> {
+  return data as FragmentType<F>;
+}
+export function isFragmentReady<TQuery, TFrag>(
+  queryNode: DocumentTypeDecoration<TQuery, any>,
+  fragmentNode: TypedDocumentNode<TFrag>,
+  data: FragmentType<TypedDocumentNode<Incremental<TFrag>, any>> | null | undefined
+): data is FragmentType<typeof fragmentNode> {
+  const deferredFields = (queryNode as { __meta__?: { deferredFields: Record<string, (keyof TFrag)[]> } }).__meta__
+    ?.deferredFields;
+
+  if (!deferredFields) return true;
+
+  const fragDef = fragmentNode.definitions[0] as FragmentDefinitionNode | undefined;
+  const fragName = fragDef?.name?.value;
+
+  const fields = (fragName && deferredFields[fragName]) || [];
+  return fields.length > 0 && fields.every(field => data && field in data);
+}

webui2/src/__generated__/gql.ts 🔗

@@ -0,0 +1,232 @@
+/* eslint-disable */
+import * as types from './graphql';
+import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
+
+/**
+ * Map of all GraphQL operations in the project.
+ *
+ * This map has several performance disadvantages:
+ * 1. It is not tree-shakeable, so it will include all operations in the project.
+ * 2. It is not minifiable, so the string of a GraphQL query will be multiple times inside the bundle.
+ * 3. It does not support dead code elimination, so it will add unused operations.
+ *
+ * Therefore it is highly recommended to use the babel or swc plugin for production.
+ * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size
+ */
+type Documents = {
+    "\n  mutation BugAddComment($input: BugAddCommentInput!) {\n    bugAddComment(input: $input) {\n      bug {\n        id\n      }\n    }\n  }\n": typeof types.BugAddCommentDocument,
+    "\n  mutation BugAddCommentAndClose($input: BugAddCommentAndCloseInput!) {\n    bugAddCommentAndClose(input: $input) {\n      bug {\n        id\n      }\n    }\n  }\n": typeof types.BugAddCommentAndCloseDocument,
+    "\n  mutation BugAddCommentAndReopen($input: BugAddCommentAndReopenInput!) {\n    bugAddCommentAndReopen(input: $input) {\n      bug {\n        id\n      }\n    }\n  }\n": typeof types.BugAddCommentAndReopenDocument,
+    "\n  mutation BugStatusOpen($input: BugStatusOpenInput!) {\n    bugStatusOpen(input: $input) {\n      bug {\n        id\n        status\n      }\n    }\n  }\n": typeof types.BugStatusOpenDocument,
+    "\n  mutation BugStatusClose($input: BugStatusCloseInput!) {\n    bugStatusClose(input: $input) {\n      bug {\n        id\n        status\n      }\n    }\n  }\n": typeof types.BugStatusCloseDocument,
+    "\n  mutation BugChangeLabels($input: BugChangeLabelInput) {\n    bugChangeLabels(input: $input) {\n      bug {\n        id\n        labels {\n          name\n          color {\n            R\n            G\n            B\n          }\n        }\n      }\n    }\n  }\n": typeof types.BugChangeLabelsDocument,
+    "\n  fragment BugCreateCommentFields on BugCreateTimelineItem {\n    author {\n      ...IdentitySummary\n    }\n    message\n    createdAt\n    lastEdit\n    edited\n  }\n": typeof types.BugCreateCommentFieldsFragmentDoc,
+    "\n  fragment BugAddCommentFields on BugAddCommentTimelineItem {\n    author {\n      ...IdentitySummary\n    }\n    message\n    createdAt\n    lastEdit\n    edited\n  }\n": typeof types.BugAddCommentFieldsFragmentDoc,
+    "\n  fragment LabelChangeFields on BugLabelChangeTimelineItem {\n    author {\n      humanId\n      displayName\n    }\n    date\n    added {\n      ...LabelFields\n    }\n    removed {\n      ...LabelFields\n    }\n  }\n": typeof types.LabelChangeFieldsFragmentDoc,
+    "\n  fragment StatusChangeFields on BugSetStatusTimelineItem {\n    author {\n      humanId\n      displayName\n    }\n    date\n    status\n  }\n": typeof types.StatusChangeFieldsFragmentDoc,
+    "\n  fragment TitleChangeFields on BugSetTitleTimelineItem {\n    author {\n      humanId\n      displayName\n    }\n    date\n    title\n    was\n  }\n": typeof types.TitleChangeFieldsFragmentDoc,
+    "\n  mutation BugEditComment($input: BugEditCommentInput!) {\n    bugEditComment(input: $input) {\n      bug {\n        id\n      }\n    }\n  }\n": typeof types.BugEditCommentDocument,
+    "\n  mutation BugSetTitle($input: BugSetTitleInput!) {\n    bugSetTitle(input: $input) {\n      bug {\n        id\n        title\n      }\n    }\n  }\n": typeof types.BugSetTitleDocument,
+    "\n  query CommitList($repo: String, $ref: String!, $path: String, $after: String, $first: Int) {\n    repository(ref: $repo) {\n      commits(ref: $ref, path: $path, after: $after, first: $first) {\n        nodes {\n          hash\n          shortHash\n          message\n          authorName\n          date\n        }\n        pageInfo {\n          hasNextPage\n          endCursor\n        }\n      }\n    }\n  }\n": typeof types.CommitListDocument,
+    "\n  query FileDiff($repo: String, $hash: String!, $path: String!) {\n    repository(ref: $repo) {\n      commit(hash: $hash) {\n        diff(path: $path) {\n          path\n          oldPath\n          isBinary\n          isNew\n          isDelete\n          hunks {\n            oldStart\n            oldLines\n            newStart\n            newLines\n            lines {\n              type\n              content\n              oldLine\n              newLine\n            }\n          }\n        }\n      }\n    }\n  }\n": typeof types.FileDiffDocument,
+    "\n  fragment IdentitySummary on Identity {\n    id\n    humanId\n    displayName\n    avatarUrl\n  }\n": typeof types.IdentitySummaryFragmentDoc,
+    "\n  fragment BugSummary on Bug {\n    id\n    humanId\n    status\n    title\n    labels {\n      ...LabelFields\n    }\n    author {\n      ...IdentitySummary\n    }\n    createdAt\n    comments {\n      totalCount\n    }\n  }\n": typeof types.BugSummaryFragmentDoc,
+    "\n  fragment LabelFields on Label {\n    name\n    color {\n      R\n      G\n      B\n    }\n  }\n": typeof types.LabelFieldsFragmentDoc,
+    "\n  query UserIdentity {\n    repository {\n      userIdentity {\n        id\n        humanId\n        name\n        displayName\n        avatarUrl\n        email\n        login\n      }\n    }\n  }\n": typeof types.UserIdentityDocument,
+    "\n  query CodePageRefs($repo: String) {\n    repository(ref: $repo) {\n      name\n      head {\n        shortName\n      }\n      refs {\n        nodes {\n          name\n          shortName\n          type\n          hash\n        }\n      }\n    }\n  }\n": typeof types.CodePageRefsDocument,
+    "\n  query CodePageBlob($repo: String, $ref: String!, $path: String!) {\n    repository(ref: $repo) {\n      blob(ref: $ref, path: $path) {\n        path\n        hash\n        text\n        size\n        isBinary\n        isTruncated\n      }\n    }\n  }\n": typeof types.CodePageBlobDocument,
+    "\n  query CodePageTree($repo: String, $ref: String!, $path: String) {\n    repository(ref: $repo) {\n      tree(ref: $ref, path: $path) {\n        name\n        type\n        hash\n      }\n    }\n  }\n": typeof types.CodePageTreeDocument,
+    "\n  query CodePageLastCommits(\n    $repo: String\n    $ref: String!\n    $path: String\n    $names: [String!]!\n  ) {\n    repository(ref: $repo) {\n      lastCommits(ref: $ref, path: $path, names: $names) {\n        name\n        commit {\n          hash\n          shortHash\n          message\n          date\n        }\n      }\n    }\n  }\n": typeof types.CodePageLastCommitsDocument,
+    "\n  query CodePageReadme($repo: String, $ref: String!, $path: String!) {\n    repository(ref: $repo) {\n      blob(ref: $ref, path: $path) {\n        text\n      }\n    }\n  }\n": typeof types.CodePageReadmeDocument,
+    "\n  query AllIdentities($ref: String) {\n    repository(ref: $ref) {\n      allIdentities(first: 1000) {\n        nodes {\n          id\n          humanId\n          name\n          email\n          login\n          displayName\n          avatarUrl\n        }\n      }\n    }\n  }\n": typeof types.AllIdentitiesDocument,
+    "\n  query ValidLabels($ref: String) {\n    repository(ref: $ref) {\n      validLabels {\n        nodes {\n          name\n          color {\n            R\n            G\n            B\n          }\n        }\n      }\n    }\n  }\n": typeof types.ValidLabelsDocument,
+    "\n  query BugDetail($ref: String, $prefix: String!) {\n    repository(ref: $ref) {\n      bug(prefix: $prefix) {\n        ...BugSummary\n        lastEdit\n        participants(first: 20) {\n          nodes {\n            ...IdentitySummary\n          }\n        }\n        timeline(first: 250) {\n          nodes {\n            __typename\n            id\n            ... on BugCreateTimelineItem {\n              ...BugCreateCommentFields\n            }\n            ... on BugAddCommentTimelineItem {\n              ...BugAddCommentFields\n            }\n            ... on BugLabelChangeTimelineItem {\n              ...LabelChangeFields\n            }\n            ... on BugSetStatusTimelineItem {\n              ...StatusChangeFields\n            }\n            ... on BugSetTitleTimelineItem {\n              ...TitleChangeFields\n            }\n          }\n        }\n      }\n    }\n  }\n": typeof types.BugDetailDocument,
+    "\n  query BugList(\n    $ref: String\n    $openQuery: String!\n    $closedQuery: String!\n    $listQuery: String!\n    $first: Int\n    $after: String\n  ) {\n    repository(ref: $ref) {\n      openCount: allBugs(query: $openQuery, first: 1) {\n        totalCount\n      }\n      closedCount: allBugs(query: $closedQuery, first: 1) {\n        totalCount\n      }\n      bugs: allBugs(query: $listQuery, first: $first, after: $after) {\n        totalCount\n        pageInfo {\n          hasNextPage\n          endCursor\n        }\n        nodes {\n          ...BugSummary\n        }\n      }\n    }\n  }\n": typeof types.BugListDocument,
+    "\n  mutation BugCreate($input: BugCreateInput!) {\n    bugCreate(input: $input) {\n      bug {\n        id\n        humanId\n      }\n    }\n  }\n": typeof types.BugCreateDocument,
+    "\n  query UserProfile(\n    $ref: String\n    $prefix: String!\n    $openQuery: String!\n    $closedQuery: String!\n    $listQuery: String!\n    $after: String\n  ) {\n    repository(ref: $ref) {\n      identity(prefix: $prefix) {\n        id\n        humanId\n        name\n        email\n        login\n        displayName\n        avatarUrl\n        isProtected\n      }\n      openCount: allBugs(query: $openQuery, first: 1) {\n        totalCount\n      }\n      closedCount: allBugs(query: $closedQuery, first: 1) {\n        totalCount\n      }\n      bugs: allBugs(query: $listQuery, first: 25, after: $after) {\n        totalCount\n        pageInfo {\n          hasNextPage\n          endCursor\n        }\n        nodes {\n          ...BugSummary\n        }\n      }\n    }\n  }\n": typeof types.UserProfileDocument,
+    "\n  query CommitPageDetail($repo: String, $hash: String!) {\n    repository(ref: $repo) {\n      commit(hash: $hash) {\n        hash\n        shortHash\n        message\n        fullMessage\n        authorName\n        authorEmail\n        date\n        parents\n        files {\n          nodes {\n            path\n            oldPath\n            status\n          }\n        }\n      }\n    }\n  }\n": typeof types.CommitPageDetailDocument,
+    "\n  query Repositories {\n    repositories {\n      nodes {\n        name\n      }\n      totalCount\n    }\n  }\n": typeof types.RepositoriesDocument,
+};
+const documents: Documents = {
+    "\n  mutation BugAddComment($input: BugAddCommentInput!) {\n    bugAddComment(input: $input) {\n      bug {\n        id\n      }\n    }\n  }\n": types.BugAddCommentDocument,
+    "\n  mutation BugAddCommentAndClose($input: BugAddCommentAndCloseInput!) {\n    bugAddCommentAndClose(input: $input) {\n      bug {\n        id\n      }\n    }\n  }\n": types.BugAddCommentAndCloseDocument,
+    "\n  mutation BugAddCommentAndReopen($input: BugAddCommentAndReopenInput!) {\n    bugAddCommentAndReopen(input: $input) {\n      bug {\n        id\n      }\n    }\n  }\n": types.BugAddCommentAndReopenDocument,
+    "\n  mutation BugStatusOpen($input: BugStatusOpenInput!) {\n    bugStatusOpen(input: $input) {\n      bug {\n        id\n        status\n      }\n    }\n  }\n": types.BugStatusOpenDocument,
+    "\n  mutation BugStatusClose($input: BugStatusCloseInput!) {\n    bugStatusClose(input: $input) {\n      bug {\n        id\n        status\n      }\n    }\n  }\n": types.BugStatusCloseDocument,
+    "\n  mutation BugChangeLabels($input: BugChangeLabelInput) {\n    bugChangeLabels(input: $input) {\n      bug {\n        id\n        labels {\n          name\n          color {\n            R\n            G\n            B\n          }\n        }\n      }\n    }\n  }\n": types.BugChangeLabelsDocument,
+    "\n  fragment BugCreateCommentFields on BugCreateTimelineItem {\n    author {\n      ...IdentitySummary\n    }\n    message\n    createdAt\n    lastEdit\n    edited\n  }\n": types.BugCreateCommentFieldsFragmentDoc,
+    "\n  fragment BugAddCommentFields on BugAddCommentTimelineItem {\n    author {\n      ...IdentitySummary\n    }\n    message\n    createdAt\n    lastEdit\n    edited\n  }\n": types.BugAddCommentFieldsFragmentDoc,
+    "\n  fragment LabelChangeFields on BugLabelChangeTimelineItem {\n    author {\n      humanId\n      displayName\n    }\n    date\n    added {\n      ...LabelFields\n    }\n    removed {\n      ...LabelFields\n    }\n  }\n": types.LabelChangeFieldsFragmentDoc,
+    "\n  fragment StatusChangeFields on BugSetStatusTimelineItem {\n    author {\n      humanId\n      displayName\n    }\n    date\n    status\n  }\n": types.StatusChangeFieldsFragmentDoc,
+    "\n  fragment TitleChangeFields on BugSetTitleTimelineItem {\n    author {\n      humanId\n      displayName\n    }\n    date\n    title\n    was\n  }\n": types.TitleChangeFieldsFragmentDoc,
+    "\n  mutation BugEditComment($input: BugEditCommentInput!) {\n    bugEditComment(input: $input) {\n      bug {\n        id\n      }\n    }\n  }\n": types.BugEditCommentDocument,
+    "\n  mutation BugSetTitle($input: BugSetTitleInput!) {\n    bugSetTitle(input: $input) {\n      bug {\n        id\n        title\n      }\n    }\n  }\n": types.BugSetTitleDocument,
+    "\n  query CommitList($repo: String, $ref: String!, $path: String, $after: String, $first: Int) {\n    repository(ref: $repo) {\n      commits(ref: $ref, path: $path, after: $after, first: $first) {\n        nodes {\n          hash\n          shortHash\n          message\n          authorName\n          date\n        }\n        pageInfo {\n          hasNextPage\n          endCursor\n        }\n      }\n    }\n  }\n": types.CommitListDocument,
+    "\n  query FileDiff($repo: String, $hash: String!, $path: String!) {\n    repository(ref: $repo) {\n      commit(hash: $hash) {\n        diff(path: $path) {\n          path\n          oldPath\n          isBinary\n          isNew\n          isDelete\n          hunks {\n            oldStart\n            oldLines\n            newStart\n            newLines\n            lines {\n              type\n              content\n              oldLine\n              newLine\n            }\n          }\n        }\n      }\n    }\n  }\n": types.FileDiffDocument,
+    "\n  fragment IdentitySummary on Identity {\n    id\n    humanId\n    displayName\n    avatarUrl\n  }\n": types.IdentitySummaryFragmentDoc,
+    "\n  fragment BugSummary on Bug {\n    id\n    humanId\n    status\n    title\n    labels {\n      ...LabelFields\n    }\n    author {\n      ...IdentitySummary\n    }\n    createdAt\n    comments {\n      totalCount\n    }\n  }\n": types.BugSummaryFragmentDoc,
+    "\n  fragment LabelFields on Label {\n    name\n    color {\n      R\n      G\n      B\n    }\n  }\n": types.LabelFieldsFragmentDoc,
+    "\n  query UserIdentity {\n    repository {\n      userIdentity {\n        id\n        humanId\n        name\n        displayName\n        avatarUrl\n        email\n        login\n      }\n    }\n  }\n": types.UserIdentityDocument,
+    "\n  query CodePageRefs($repo: String) {\n    repository(ref: $repo) {\n      name\n      head {\n        shortName\n      }\n      refs {\n        nodes {\n          name\n          shortName\n          type\n          hash\n        }\n      }\n    }\n  }\n": types.CodePageRefsDocument,
+    "\n  query CodePageBlob($repo: String, $ref: String!, $path: String!) {\n    repository(ref: $repo) {\n      blob(ref: $ref, path: $path) {\n        path\n        hash\n        text\n        size\n        isBinary\n        isTruncated\n      }\n    }\n  }\n": types.CodePageBlobDocument,
+    "\n  query CodePageTree($repo: String, $ref: String!, $path: String) {\n    repository(ref: $repo) {\n      tree(ref: $ref, path: $path) {\n        name\n        type\n        hash\n      }\n    }\n  }\n": types.CodePageTreeDocument,
+    "\n  query CodePageLastCommits(\n    $repo: String\n    $ref: String!\n    $path: String\n    $names: [String!]!\n  ) {\n    repository(ref: $repo) {\n      lastCommits(ref: $ref, path: $path, names: $names) {\n        name\n        commit {\n          hash\n          shortHash\n          message\n          date\n        }\n      }\n    }\n  }\n": types.CodePageLastCommitsDocument,
+    "\n  query CodePageReadme($repo: String, $ref: String!, $path: String!) {\n    repository(ref: $repo) {\n      blob(ref: $ref, path: $path) {\n        text\n      }\n    }\n  }\n": types.CodePageReadmeDocument,
+    "\n  query AllIdentities($ref: String) {\n    repository(ref: $ref) {\n      allIdentities(first: 1000) {\n        nodes {\n          id\n          humanId\n          name\n          email\n          login\n          displayName\n          avatarUrl\n        }\n      }\n    }\n  }\n": types.AllIdentitiesDocument,
+    "\n  query ValidLabels($ref: String) {\n    repository(ref: $ref) {\n      validLabels {\n        nodes {\n          name\n          color {\n            R\n            G\n            B\n          }\n        }\n      }\n    }\n  }\n": types.ValidLabelsDocument,
+    "\n  query BugDetail($ref: String, $prefix: String!) {\n    repository(ref: $ref) {\n      bug(prefix: $prefix) {\n        ...BugSummary\n        lastEdit\n        participants(first: 20) {\n          nodes {\n            ...IdentitySummary\n          }\n        }\n        timeline(first: 250) {\n          nodes {\n            __typename\n            id\n            ... on BugCreateTimelineItem {\n              ...BugCreateCommentFields\n            }\n            ... on BugAddCommentTimelineItem {\n              ...BugAddCommentFields\n            }\n            ... on BugLabelChangeTimelineItem {\n              ...LabelChangeFields\n            }\n            ... on BugSetStatusTimelineItem {\n              ...StatusChangeFields\n            }\n            ... on BugSetTitleTimelineItem {\n              ...TitleChangeFields\n            }\n          }\n        }\n      }\n    }\n  }\n": types.BugDetailDocument,
+    "\n  query BugList(\n    $ref: String\n    $openQuery: String!\n    $closedQuery: String!\n    $listQuery: String!\n    $first: Int\n    $after: String\n  ) {\n    repository(ref: $ref) {\n      openCount: allBugs(query: $openQuery, first: 1) {\n        totalCount\n      }\n      closedCount: allBugs(query: $closedQuery, first: 1) {\n        totalCount\n      }\n      bugs: allBugs(query: $listQuery, first: $first, after: $after) {\n        totalCount\n        pageInfo {\n          hasNextPage\n          endCursor\n        }\n        nodes {\n          ...BugSummary\n        }\n      }\n    }\n  }\n": types.BugListDocument,
+    "\n  mutation BugCreate($input: BugCreateInput!) {\n    bugCreate(input: $input) {\n      bug {\n        id\n        humanId\n      }\n    }\n  }\n": types.BugCreateDocument,
+    "\n  query UserProfile(\n    $ref: String\n    $prefix: String!\n    $openQuery: String!\n    $closedQuery: String!\n    $listQuery: String!\n    $after: String\n  ) {\n    repository(ref: $ref) {\n      identity(prefix: $prefix) {\n        id\n        humanId\n        name\n        email\n        login\n        displayName\n        avatarUrl\n        isProtected\n      }\n      openCount: allBugs(query: $openQuery, first: 1) {\n        totalCount\n      }\n      closedCount: allBugs(query: $closedQuery, first: 1) {\n        totalCount\n      }\n      bugs: allBugs(query: $listQuery, first: 25, after: $after) {\n        totalCount\n        pageInfo {\n          hasNextPage\n          endCursor\n        }\n        nodes {\n          ...BugSummary\n        }\n      }\n    }\n  }\n": types.UserProfileDocument,
+    "\n  query CommitPageDetail($repo: String, $hash: String!) {\n    repository(ref: $repo) {\n      commit(hash: $hash) {\n        hash\n        shortHash\n        message\n        fullMessage\n        authorName\n        authorEmail\n        date\n        parents\n        files {\n          nodes {\n            path\n            oldPath\n            status\n          }\n        }\n      }\n    }\n  }\n": types.CommitPageDetailDocument,
+    "\n  query Repositories {\n    repositories {\n      nodes {\n        name\n      }\n      totalCount\n    }\n  }\n": types.RepositoriesDocument,
+};
+
+/**
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
+ *
+ *
+ * @example
+ * ```ts
+ * const query = graphql(`query GetUser($id: ID!) { user(id: $id) { name } }`);
+ * ```
+ *
+ * The query argument is unknown!
+ * Please regenerate the types.
+ */
+export function graphql(source: string): unknown;
+
+/**
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
+ */
+export function graphql(source: "\n  mutation BugAddComment($input: BugAddCommentInput!) {\n    bugAddComment(input: $input) {\n      bug {\n        id\n      }\n    }\n  }\n"): (typeof documents)["\n  mutation BugAddComment($input: BugAddCommentInput!) {\n    bugAddComment(input: $input) {\n      bug {\n        id\n      }\n    }\n  }\n"];
+/**
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
+ */
+export function graphql(source: "\n  mutation BugAddCommentAndClose($input: BugAddCommentAndCloseInput!) {\n    bugAddCommentAndClose(input: $input) {\n      bug {\n        id\n      }\n    }\n  }\n"): (typeof documents)["\n  mutation BugAddCommentAndClose($input: BugAddCommentAndCloseInput!) {\n    bugAddCommentAndClose(input: $input) {\n      bug {\n        id\n      }\n    }\n  }\n"];
+/**
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
+ */
+export function graphql(source: "\n  mutation BugAddCommentAndReopen($input: BugAddCommentAndReopenInput!) {\n    bugAddCommentAndReopen(input: $input) {\n      bug {\n        id\n      }\n    }\n  }\n"): (typeof documents)["\n  mutation BugAddCommentAndReopen($input: BugAddCommentAndReopenInput!) {\n    bugAddCommentAndReopen(input: $input) {\n      bug {\n        id\n      }\n    }\n  }\n"];
+/**
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
+ */
+export function graphql(source: "\n  mutation BugStatusOpen($input: BugStatusOpenInput!) {\n    bugStatusOpen(input: $input) {\n      bug {\n        id\n        status\n      }\n    }\n  }\n"): (typeof documents)["\n  mutation BugStatusOpen($input: BugStatusOpenInput!) {\n    bugStatusOpen(input: $input) {\n      bug {\n        id\n        status\n      }\n    }\n  }\n"];
+/**
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
+ */
+export function graphql(source: "\n  mutation BugStatusClose($input: BugStatusCloseInput!) {\n    bugStatusClose(input: $input) {\n      bug {\n        id\n        status\n      }\n    }\n  }\n"): (typeof documents)["\n  mutation BugStatusClose($input: BugStatusCloseInput!) {\n    bugStatusClose(input: $input) {\n      bug {\n        id\n        status\n      }\n    }\n  }\n"];
+/**
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
+ */
+export function graphql(source: "\n  mutation BugChangeLabels($input: BugChangeLabelInput) {\n    bugChangeLabels(input: $input) {\n      bug {\n        id\n        labels {\n          name\n          color {\n            R\n            G\n            B\n          }\n        }\n      }\n    }\n  }\n"): (typeof documents)["\n  mutation BugChangeLabels($input: BugChangeLabelInput) {\n    bugChangeLabels(input: $input) {\n      bug {\n        id\n        labels {\n          name\n          color {\n            R\n            G\n            B\n          }\n        }\n      }\n    }\n  }\n"];
+/**
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
+ */
+export function graphql(source: "\n  fragment BugCreateCommentFields on BugCreateTimelineItem {\n    author {\n      ...IdentitySummary\n    }\n    message\n    createdAt\n    lastEdit\n    edited\n  }\n"): (typeof documents)["\n  fragment BugCreateCommentFields on BugCreateTimelineItem {\n    author {\n      ...IdentitySummary\n    }\n    message\n    createdAt\n    lastEdit\n    edited\n  }\n"];
+/**
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
+ */
+export function graphql(source: "\n  fragment BugAddCommentFields on BugAddCommentTimelineItem {\n    author {\n      ...IdentitySummary\n    }\n    message\n    createdAt\n    lastEdit\n    edited\n  }\n"): (typeof documents)["\n  fragment BugAddCommentFields on BugAddCommentTimelineItem {\n    author {\n      ...IdentitySummary\n    }\n    message\n    createdAt\n    lastEdit\n    edited\n  }\n"];
+/**
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
+ */
+export function graphql(source: "\n  fragment LabelChangeFields on BugLabelChangeTimelineItem {\n    author {\n      humanId\n      displayName\n    }\n    date\n    added {\n      ...LabelFields\n    }\n    removed {\n      ...LabelFields\n    }\n  }\n"): (typeof documents)["\n  fragment LabelChangeFields on BugLabelChangeTimelineItem {\n    author {\n      humanId\n      displayName\n    }\n    date\n    added {\n      ...LabelFields\n    }\n    removed {\n      ...LabelFields\n    }\n  }\n"];
+/**
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
+ */
+export function graphql(source: "\n  fragment StatusChangeFields on BugSetStatusTimelineItem {\n    author {\n      humanId\n      displayName\n    }\n    date\n    status\n  }\n"): (typeof documents)["\n  fragment StatusChangeFields on BugSetStatusTimelineItem {\n    author {\n      humanId\n      displayName\n    }\n    date\n    status\n  }\n"];
+/**
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
+ */
+export function graphql(source: "\n  fragment TitleChangeFields on BugSetTitleTimelineItem {\n    author {\n      humanId\n      displayName\n    }\n    date\n    title\n    was\n  }\n"): (typeof documents)["\n  fragment TitleChangeFields on BugSetTitleTimelineItem {\n    author {\n      humanId\n      displayName\n    }\n    date\n    title\n    was\n  }\n"];
+/**
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
+ */
+export function graphql(source: "\n  mutation BugEditComment($input: BugEditCommentInput!) {\n    bugEditComment(input: $input) {\n      bug {\n        id\n      }\n    }\n  }\n"): (typeof documents)["\n  mutation BugEditComment($input: BugEditCommentInput!) {\n    bugEditComment(input: $input) {\n      bug {\n        id\n      }\n    }\n  }\n"];
+/**
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
+ */
+export function graphql(source: "\n  mutation BugSetTitle($input: BugSetTitleInput!) {\n    bugSetTitle(input: $input) {\n      bug {\n        id\n        title\n      }\n    }\n  }\n"): (typeof documents)["\n  mutation BugSetTitle($input: BugSetTitleInput!) {\n    bugSetTitle(input: $input) {\n      bug {\n        id\n        title\n      }\n    }\n  }\n"];
+/**
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
+ */
+export function graphql(source: "\n  query CommitList($repo: String, $ref: String!, $path: String, $after: String, $first: Int) {\n    repository(ref: $repo) {\n      commits(ref: $ref, path: $path, after: $after, first: $first) {\n        nodes {\n          hash\n          shortHash\n          message\n          authorName\n          date\n        }\n        pageInfo {\n          hasNextPage\n          endCursor\n        }\n      }\n    }\n  }\n"): (typeof documents)["\n  query CommitList($repo: String, $ref: String!, $path: String, $after: String, $first: Int) {\n    repository(ref: $repo) {\n      commits(ref: $ref, path: $path, after: $after, first: $first) {\n        nodes {\n          hash\n          shortHash\n          message\n          authorName\n          date\n        }\n        pageInfo {\n          hasNextPage\n          endCursor\n        }\n      }\n    }\n  }\n"];
+/**
+ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
+ */

webui2/src/__generated__/graphql.ts 🔗

@@ -1,14 +1,12 @@
-import { gql } from '@apollo/client';
-import * as Apollo from '@apollo/client';
-import * as ApolloReactHooks from '@apollo/client/react';
+/* eslint-disable */
+import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';
 export type Maybe<T> = T | null;
-export type InputMaybe<T> = Maybe<T>;
+export type InputMaybe<T> = T | null | undefined;
 export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
 export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> };
 export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };
 export type MakeEmpty<T extends { [key: string]: unknown }, K extends keyof T> = { [_ in K]?: never };
 export type Incremental<T> = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never };
-const defaultOptions = {} as const;
 /** All built-in and custom scalars, mapped to their actual values */
 export type Scalars = {
   ID: { input: string; output: string; }
@@ -28,7 +26,7 @@ export type Authored = {
 };
 
 export type Bug = Authored & Entity & {
-  __typename?: 'Bug';
+  __typename: 'Bug';
   /** The actors of the bug. Actors are Identity that have interacted with the bug. */
   actors: IdentityConnection;
   author: Identity;
@@ -105,11 +103,11 @@ export type BugAddCommentAndCloseInput = {
 };
 
 export type BugAddCommentAndClosePayload = {
-  __typename?: 'BugAddCommentAndClosePayload';
+  __typename: 'BugAddCommentAndClosePayload';
   /** The affected bug. */
   bug: Bug;
   /** A unique identifier for the client performing the mutation. */
-  clientMutationId?: Maybe<Scalars['String']['output']>;
+  clientMutationId: Maybe<Scalars['String']['output']>;
   /** The resulting AddComment operation. */
   commentOperation: BugAddCommentOperation;
   /** The resulting SetStatusOperation. */
@@ -130,11 +128,11 @@ export type BugAddCommentAndReopenInput = {
 };
 
 export type BugAddCommentAndReopenPayload = {
-  __typename?: 'BugAddCommentAndReopenPayload';
+  __typename: 'BugAddCommentAndReopenPayload';
   /** The affected bug. */
   bug: Bug;
   /** A unique identifier for the client performing the mutation. */
-  clientMutationId?: Maybe<Scalars['String']['output']>;
+  clientMutationId: Maybe<Scalars['String']['output']>;
   /** The resulting AddComment operation. */
   commentOperation: BugAddCommentOperation;
   /** The resulting SetStatusOperation. */
@@ -155,7 +153,7 @@ export type BugAddCommentInput = {
 };
 
 export type BugAddCommentOperation = Authored & Operation & {
-  __typename?: 'BugAddCommentOperation';
+  __typename: 'BugAddCommentOperation';
   /** The author of this object. */
   author: Identity;
   /** The datetime when this operation was issued. */
@@ -167,18 +165,18 @@ export type BugAddCommentOperation = Authored & Operation & {
 };
 
 export type BugAddCommentPayload = {
-  __typename?: 'BugAddCommentPayload';
+  __typename: 'BugAddCommentPayload';
   /** The affected bug. */
   bug: Bug;
   /** A unique identifier for the client performing the mutation. */
-  clientMutationId?: Maybe<Scalars['String']['output']>;
+  clientMutationId: Maybe<Scalars['String']['output']>;
   /** The resulting operation. */
   operation: BugAddCommentOperation;
 };
 
 /** BugAddCommentTimelineItem is a BugTimelineItem that represent a BugComment and its edition history */
 export type BugAddCommentTimelineItem = Authored & BugTimelineItem & {
-  __typename?: 'BugAddCommentTimelineItem';
+  __typename: 'BugAddCommentTimelineItem';
   author: Identity;
   createdAt: Scalars['Time']['output'];
   edited: Scalars['Boolean']['output'];
@@ -205,11 +203,11 @@ export type BugChangeLabelInput = {
 };
 
 export type BugChangeLabelPayload = {
-  __typename?: 'BugChangeLabelPayload';
+  __typename: 'BugChangeLabelPayload';
   /** The affected bug. */
   bug: Bug;
   /** A unique identifier for the client performing the mutation. */
-  clientMutationId?: Maybe<Scalars['String']['output']>;
+  clientMutationId: Maybe<Scalars['String']['output']>;
   /** The resulting operation. */
   operation: BugLabelChangeOperation;
   /** The effect each source label had. */
@@ -218,7 +216,7 @@ export type BugChangeLabelPayload = {
 
 /** Represents a comment on a bug. */
 export type BugComment = Authored & {
-  __typename?: 'BugComment';
+  __typename: 'BugComment';
   /** The author of this comment. */
   author: Identity;
   /** All media's hash referenced in this comment */
@@ -229,7 +227,7 @@ export type BugComment = Authored & {
 };
 
 export type BugCommentConnection = {
-  __typename?: 'BugCommentConnection';
+  __typename: 'BugCommentConnection';
   edges: Array<BugCommentEdge>;
   nodes: Array<BugComment>;
   pageInfo: PageInfo;
@@ -237,21 +235,21 @@ export type BugCommentConnection = {
 };
 
 export type BugCommentEdge = {
-  __typename?: 'BugCommentEdge';
+  __typename: 'BugCommentEdge';
   cursor: Scalars['String']['output'];
   node: BugComment;
 };
 
 /** CommentHistoryStep hold one version of a message in the history */
 export type BugCommentHistoryStep = {
-  __typename?: 'BugCommentHistoryStep';
+  __typename: 'BugCommentHistoryStep';
   date: Scalars['Time']['output'];
   message: Scalars['String']['output'];
 };
 
 /** The connection type for Bug. */
 export type BugConnection = {
-  __typename?: 'BugConnection';
+  __typename: 'BugConnection';
   /** A list of edges. */
   edges: Array<BugEdge>;
   nodes: Array<Bug>;
@@ -275,7 +273,7 @@ export type BugCreateInput = {
 };
 
 export type BugCreateOperation = Authored & Operation & {
-  __typename?: 'BugCreateOperation';
+  __typename: 'BugCreateOperation';
   /** The author of this object. */
   author: Identity;
   /** The datetime when this operation was issued. */
@@ -288,18 +286,18 @@ export type BugCreateOperation = Authored & Operation & {
 };
 
 export type BugCreatePayload = {
-  __typename?: 'BugCreatePayload';
+  __typename: 'BugCreatePayload';
   /** The created bug. */
   bug: Bug;
   /** A unique identifier for the client performing the mutation. */
-  clientMutationId?: Maybe<Scalars['String']['output']>;
+  clientMutationId: Maybe<Scalars['String']['output']>;
   /** The resulting operation. */
   operation: BugCreateOperation;
 };
 
 /** BugCreateTimelineItem is a BugTimelineItem that represent the creation of a bug and its message edition history */
 export type BugCreateTimelineItem = Authored & BugTimelineItem & {
-  __typename?: 'BugCreateTimelineItem';
+  __typename: 'BugCreateTimelineItem';
   author: Identity;
   createdAt: Scalars['Time']['output'];
   edited: Scalars['Boolean']['output'];
@@ -314,7 +312,7 @@ export type BugCreateTimelineItem = Authored & BugTimelineItem & {
 
 /** An edge in a connection. */
 export type BugEdge = {
-  __typename?: 'BugEdge';
+  __typename: 'BugEdge';
   /** A cursor for use in pagination. */
   cursor: Scalars['String']['output'];
   /** The item at the end of the edge. */
@@ -335,7 +333,7 @@ export type BugEditCommentInput = {
 };
 
 export type BugEditCommentOperation = Authored & Operation & {
-  __typename?: 'BugEditCommentOperation';
+  __typename: 'BugEditCommentOperation';
   /** The author of this object. */
   author: Identity;
   /** The datetime when this operation was issued. */
@@ -348,23 +346,23 @@ export type BugEditCommentOperation = Authored & Operation & {
 };
 
 export type BugEditCommentPayload = {
-  __typename?: 'BugEditCommentPayload';
+  __typename: 'BugEditCommentPayload';
   /** The affected bug. */
   bug: Bug;
   /** A unique identifier for the client performing the mutation. */
-  clientMutationId?: Maybe<Scalars['String']['output']>;
+  clientMutationId: Maybe<Scalars['String']['output']>;
   /** The resulting operation. */
   operation: BugEditCommentOperation;
 };
 
 export type BugEvent = {
-  __typename?: 'BugEvent';
+  __typename: 'BugEvent';
   bug: Bug;
   type: EntityEventType;
 };
 
 export type BugLabelChangeOperation = Authored & Operation & {
-  __typename?: 'BugLabelChangeOperation';
+  __typename: 'BugLabelChangeOperation';
   added: Array<Label>;
   /** The author of this object. */
   author: Identity;
@@ -377,7 +375,7 @@ export type BugLabelChangeOperation = Authored & Operation & {
 
 /** BugLabelChangeTimelineItem is a BugTimelineItem that represent a change in the labels of a bug */
 export type BugLabelChangeTimelineItem = Authored & BugTimelineItem & {
-  __typename?: 'BugLabelChangeTimelineItem';
+  __typename: 'BugLabelChangeTimelineItem';
   added: Array<Label>;
   author: Identity;
   date: Scalars['Time']['output'];
@@ -387,7 +385,7 @@ export type BugLabelChangeTimelineItem = Authored & BugTimelineItem & {
 };
 
 export type BugSetStatusOperation = Authored & Operation & {
-  __typename?: 'BugSetStatusOperation';
+  __typename: 'BugSetStatusOperation';
   /** The author of this object. */
   author: Identity;
   /** The datetime when this operation was issued. */
@@ -399,7 +397,7 @@ export type BugSetStatusOperation = Authored & Operation & {
 
 /** BugSetStatusTimelineItem is a BugTimelineItem that represent a change in the status of a bug */
 export type BugSetStatusTimelineItem = Authored & BugTimelineItem & {
-  __typename?: 'BugSetStatusTimelineItem';
+  __typename: 'BugSetStatusTimelineItem';
   author: Identity;
   date: Scalars['Time']['output'];
   /** The identifier of the source operation */
@@ -419,7 +417,7 @@ export type BugSetTitleInput = {
 };
 
 export type BugSetTitleOperation = Authored & Operation & {
-  __typename?: 'BugSetTitleOperation';
+  __typename: 'BugSetTitleOperation';
   /** The author of this object. */
   author: Identity;
   /** The datetime when this operation was issued. */
@@ -431,18 +429,18 @@ export type BugSetTitleOperation = Authored & Operation & {
 };
 
 export type BugSetTitlePayload = {
-  __typename?: 'BugSetTitlePayload';
+  __typename: 'BugSetTitlePayload';
   /** The affected bug. */
   bug: Bug;
   /** A unique identifier for the client performing the mutation. */
-  clientMutationId?: Maybe<Scalars['String']['output']>;
+  clientMutationId: Maybe<Scalars['String']['output']>;
   /** The resulting operation */
   operation: BugSetTitleOperation;
 };
 
 /** BugLabelChangeTimelineItem is a BugTimelineItem that represent a change in the title of a bug */
 export type BugSetTitleTimelineItem = Authored & BugTimelineItem & {
-  __typename?: 'BugSetTitleTimelineItem';
+  __typename: 'BugSetTitleTimelineItem';
   author: Identity;
   date: Scalars['Time']['output'];
   /** The identifier of the source operation */
@@ -461,11 +459,11 @@ export type BugStatusCloseInput = {
 };
 
 export type BugStatusClosePayload = {
-  __typename?: 'BugStatusClosePayload';
+  __typename: 'BugStatusClosePayload';
   /** The affected bug. */
   bug: Bug;
   /** A unique identifier for the client performing the mutation. */
-  clientMutationId?: Maybe<Scalars['String']['output']>;
+  clientMutationId: Maybe<Scalars['String']['output']>;
   /** The resulting operation. */
   operation: BugSetStatusOperation;
 };
@@ -480,11 +478,11 @@ export type BugStatusOpenInput = {
 };
 
 export type BugStatusOpenPayload = {
-  __typename?: 'BugStatusOpenPayload';
+  __typename: 'BugStatusOpenPayload';
   /** The affected bug. */
   bug: Bug;
   /** A unique identifier for the client performing the mutation. */
-  clientMutationId?: Maybe<Scalars['String']['output']>;
+  clientMutationId: Maybe<Scalars['String']['output']>;
   /** The resulting operation. */
   operation: BugSetStatusOperation;
 };
@@ -497,7 +495,7 @@ export type BugTimelineItem = {
 
 /** The connection type for TimelineItem */
 export type BugTimelineItemConnection = {
-  __typename?: 'BugTimelineItemConnection';
+  __typename: 'BugTimelineItemConnection';
   edges: Array<BugTimelineItemEdge>;
   nodes: Array<BugTimelineItem>;
   pageInfo: PageInfo;
@@ -506,14 +504,14 @@ export type BugTimelineItemConnection = {
 
 /** Represent a TimelineItem */
 export type BugTimelineItemEdge = {
-  __typename?: 'BugTimelineItemEdge';
+  __typename: 'BugTimelineItemEdge';
   cursor: Scalars['String']['output'];
   node: BugTimelineItem;
 };
 
 /** Defines a color by red, green and blue components. */
 export type Color = {
-  __typename?: 'Color';
+  __typename: 'Color';
   /** Blue component of the color. */
   B: Scalars['Int']['output'];
   /** Green component of the color. */
@@ -531,8 +529,8 @@ export type Entity = {
 };
 
 export type EntityEvent = {
-  __typename?: 'EntityEvent';
-  entity?: Maybe<Entity>;
+  __typename: 'EntityEvent';
+  entity: Maybe<Entity>;
   type: EntityEventType;
 };
 
@@ -544,7 +542,7 @@ export enum EntityEventType {
 
 /** The content of a git blob (file). */
 export type GitBlob = {
-  __typename?: 'GitBlob';
+  __typename: 'GitBlob';
   /**
    * Git object hash. Can be used as a stable cache key or to construct a
    * raw download URL.
@@ -568,7 +566,7 @@ export type GitBlob = {
    * UTF-8 text content of the file. Null when isBinary is true or when
    * the file is too large to be returned inline (see isTruncated).
    */
-  text?: Maybe<Scalars['String']['output']>;
+  text: Maybe<Scalars['String']['output']>;
 };
 
 /** How a file was affected by a commit. */
@@ -585,9 +583,9 @@ export enum GitChangeStatus {
 
 /** A file that was changed in a commit. */
 export type GitChangedFile = {
-  __typename?: 'GitChangedFile';
+  __typename: 'GitChangedFile';
   /** Previous path, non-null only for renames. */
-  oldPath?: Maybe<Scalars['String']['output']>;
+  oldPath: Maybe<Scalars['String']['output']>;
   /** Path of the file in the new version of the commit. */
   path: Scalars['String']['output'];
   /** How the file was affected by the commit. */
@@ -595,7 +593,7 @@ export type GitChangedFile = {
 };
 
 export type GitChangedFileConnection = {
-  __typename?: 'GitChangedFileConnection';
+  __typename: 'GitChangedFileConnection';
   nodes: Array<GitChangedFile>;
   pageInfo: PageInfo;
   totalCount: Scalars['Int']['output'];
@@ -603,7 +601,7 @@ export type GitChangedFileConnection = {
 
 /** Metadata for a single git commit. */
 export type GitCommit = {
-  __typename?: 'GitCommit';
+  __typename: 'GitCommit';
   /** Email address of the commit author. */
   authorEmail: Scalars['String']['output'];
   /** Name of the commit author. */
@@ -611,7 +609,7 @@ export type GitCommit = {
   /** Timestamp from the author field (when the change was originally made). */
   date: Scalars['Time']['output'];
   /** Unified diff for a single file in this commit. */
-  diff?: Maybe<GitFileDiff>;
+  diff: Maybe<GitFileDiff>;
   /**
    * Files changed relative to the first parent (or the empty tree for the
    * initial commit).
@@ -646,7 +644,7 @@ export type GitCommitFilesArgs = {
 
 /** Paginated list of commits. */
 export type GitCommitConnection = {
-  __typename?: 'GitCommitConnection';
+  __typename: 'GitCommitConnection';
   nodes: Array<GitCommit>;
   pageInfo: PageInfo;
   totalCount: Scalars['Int']['output'];
@@ -654,7 +652,7 @@ export type GitCommitConnection = {
 
 /** A contiguous block of changes in a unified diff. */
 export type GitDiffHunk = {
-  __typename?: 'GitDiffHunk';
+  __typename: 'GitDiffHunk';
   /** Lines in this hunk, including context, additions, and deletions. */
   lines: Array<GitDiffLine>;
   /** Number of lines from the new file included in this hunk. */
@@ -669,7 +667,7 @@ export type GitDiffHunk = {
 
 /** A single line in a unified diff hunk. */
 export type GitDiffLine = {
-  __typename?: 'GitDiffLine';
+  __typename: 'GitDiffLine';
   /** Raw line content, without the leading +/- prefix. */
   content: Scalars['String']['output'];
   /** Line number in the new file. 0 for deleted lines. */
@@ -692,7 +690,7 @@ export enum GitDiffLineType {
 
 /** The diff for a single file in a commit. */
 export type GitFileDiff = {
-  __typename?: 'GitFileDiff';
+  __typename: 'GitFileDiff';
   /** Contiguous blocks of changes. Empty for binary files. */
   hunks: Array<GitDiffHunk>;
   /** True when the file is binary and no textual diff is available. */
@@ -702,14 +700,14 @@ export type GitFileDiff = {
   /** True when the file was created in this commit. */
   isNew: Scalars['Boolean']['output'];
   /** Previous path, non-null only for renames. */
-  oldPath?: Maybe<Scalars['String']['output']>;
+  oldPath: Maybe<Scalars['String']['output']>;
   /** Path of the file in the new version. */
   path: Scalars['String']['output'];
 };
 
 /** The last commit that touched each requested entry in a directory. */
 export type GitLastCommit = {
-  __typename?: 'GitLastCommit';
+  __typename: 'GitLastCommit';
   /** Most recent commit that modified this entry. */
   commit: GitCommit;
   /** Entry name within the directory. */
@@ -730,7 +728,7 @@ export enum GitObjectType {
 
 /** A git branch or tag reference. */
 export type GitRef = {
-  __typename?: 'GitRef';
+  __typename: 'GitRef';
   /** Git commit the reference points to. */
   commit: GitCommit;
   /** Commit hash the reference points to. */
@@ -744,7 +742,7 @@ export type GitRef = {
 };
 
 export type GitRefConnection = {
-  __typename?: 'GitRefConnection';
+  __typename: 'GitRefConnection';
   nodes: Array<GitRef>;
   pageInfo: PageInfo;
   totalCount: Scalars['Int']['output'];
@@ -762,14 +760,14 @@ export enum GitRefType {
 
 /** An entry in a git tree (directory listing). */
 export type GitTreeEntry = {
-  __typename?: 'GitTreeEntry';
+  __typename: 'GitTreeEntry';
   /** Git object hash. */
   hash: Scalars['String']['output'];
   /**
    * The last git commit that touched this tree entry. Null when the entry
    * cannot be resolved within the history depth limit.
    */
-  lastCommit?: Maybe<GitCommit>;
+  lastCommit: Maybe<GitCommit>;
   /** File or directory name within the parent tree. */
   name: Scalars['String']['output'];
   /** Whether this entry is a file, directory, symlink, or submodule. */
@@ -778,13 +776,13 @@ export type GitTreeEntry = {
 
 /** Represents an identity */
 export type Identity = Entity & {
-  __typename?: 'Identity';
+  __typename: 'Identity';
   /** An url to an avatar */
-  avatarUrl?: Maybe<Scalars['String']['output']>;
+  avatarUrl: Maybe<Scalars['String']['output']>;
   /** A non-empty string to display, representing the identity, based on the non-empty values. */
   displayName: Scalars['String']['output'];
   /** The email of the person, if known. */
-  email?: Maybe<Scalars['String']['output']>;
+  email: Maybe<Scalars['String']['output']>;
   /** The human version (truncated) identifier for this identity */
   humanId: Scalars['String']['output'];
   /** The identifier for this identity */
@@ -795,13 +793,13 @@ export type Identity = Entity & {
    */
   isProtected: Scalars['Boolean']['output'];
   /** The login of the person, if known. */
-  login?: Maybe<Scalars['String']['output']>;
+  login: Maybe<Scalars['String']['output']>;
   /** The name of the person, if known. */
-  name?: Maybe<Scalars['String']['output']>;
+  name: Maybe<Scalars['String']['output']>;
 };
 
 export type IdentityConnection = {
-  __typename?: 'IdentityConnection';
+  __typename: 'IdentityConnection';
   edges: Array<IdentityEdge>;
   nodes: Array<Identity>;
   pageInfo: PageInfo;
@@ -809,20 +807,20 @@ export type IdentityConnection = {
 };
 
 export type IdentityEdge = {
-  __typename?: 'IdentityEdge';
+  __typename: 'IdentityEdge';
   cursor: Scalars['String']['output'];
   node: Identity;
 };
 
 export type IdentityEvent = {
-  __typename?: 'IdentityEvent';
+  __typename: 'IdentityEvent';
   identity: Identity;
   type: EntityEventType;
 };
 
 /** Label for a bug. */
 export type Label = {
-  __typename?: 'Label';
+  __typename: 'Label';
   /** Color of the label. */
   color: Color;
   /** The name of the label. */
@@ -830,7 +828,7 @@ export type Label = {
 };
 
 export type LabelChangeResult = {
-  __typename?: 'LabelChangeResult';
+  __typename: 'LabelChangeResult';
   /** The source label. */
   label: Label;
   /** The effect this label had. */
@@ -846,7 +844,7 @@ export enum LabelChangeStatus {
 }
 
 export type LabelConnection = {
-  __typename?: 'LabelConnection';
+  __typename: 'LabelConnection';
   edges: Array<LabelEdge>;
   nodes: Array<Label>;
   pageInfo: PageInfo;
@@ -854,13 +852,13 @@ export type LabelConnection = {
 };
 
 export type LabelEdge = {
-  __typename?: 'LabelEdge';
+  __typename: 'LabelEdge';
   cursor: Scalars['String']['output'];
   node: Label;
 };
 
 export type Mutation = {
-  __typename?: 'Mutation';
+  __typename: 'Mutation';
   /** Add a new comment to a bug */
   bugAddComment: BugAddCommentPayload;
   /** Add a new comment to a bug and close it */
@@ -938,7 +936,7 @@ export type Operation = {
 
 /** The connection type for an Operation */
 export type OperationConnection = {
-  __typename?: 'OperationConnection';
+  __typename: 'OperationConnection';
   edges: Array<OperationEdge>;
   nodes: Array<Operation>;
   pageInfo: PageInfo;
@@ -947,14 +945,14 @@ export type OperationConnection = {
 
 /** Represent an Operation */
 export type OperationEdge = {
-  __typename?: 'OperationEdge';
+  __typename: 'OperationEdge';
   cursor: Scalars['String']['output'];
   node: Operation;
 };
 
 /** Information about pagination in a connection. */
 export type PageInfo = {
-  __typename?: 'PageInfo';
+  __typename: 'PageInfo';
   /** When paginating forwards, the cursor to continue. */
   endCursor: Scalars['String']['output'];
   /** When paginating forwards, are there more items? */
@@ -966,14 +964,14 @@ export type PageInfo = {
 };
 
 export type Query = {
-  __typename?: 'Query';
+  __typename: 'Query';
   /** List all registered repositories. */
   repositories: RepositoryConnection;
   /**
    * Access a repository by reference/name. If no ref is given, the default repository is returned if any.
    * Returns null if the referenced repository does not exist.
    */
-  repository?: Maybe<Repository>;
+  repository: Maybe<Repository>;
 };
 
 
@@ -990,7 +988,7 @@ export type QueryRepositoryArgs = {
 };
 
 export type Repository = {
-  __typename?: 'Repository';
+  __typename: 'Repository';
   /** All the bugs */
   allBugs: BugConnection;
   /** All the identities */
@@ -999,11 +997,11 @@ export type Repository = {
    * Content of the file at path under ref. Null if the path does not exist
    * or resolves to a tree rather than a blob.
    */
-  blob?: Maybe<GitBlob>;
+  blob: Maybe<GitBlob>;
   /** Look up a bug by id prefix. Returns null if no bug matches the prefix. */
-  bug?: Maybe<Bug>;
+  bug: Maybe<Bug>;
   /** A single commit by hash. Returns null if the hash does not exist in the repository. */
-  commit?: Maybe<GitCommit>;
+  commit: Maybe<GitCommit>;
   /**
    * Paginated commit log reachable from ref, optionally filtered to commits
    * touching path.
@@ -1014,9 +1012,9 @@ export type Repository = {
    * Null if HEAD cannot be resolved, for example in an empty or unborn
    * repository, or if HEAD is missing or invalid.
    */
-  head?: Maybe<GitRef>;
+  head: Maybe<GitRef>;
   /** Look up an identity by id prefix. Returns null if no identity matches the prefix. */
-  identity?: Maybe<Identity>;
+  identity: Maybe<Identity>;
   /**
    * The most recent commit that touched each of the named entries in the
    * directory at path under ref. Use this to populate last-commit info on a
@@ -1024,7 +1022,7 @@ export type Repository = {
    */
   lastCommits: Array<GitLastCommit>;
   /** The name of the repository. Null for the default (unnamed) repository in a single-repo setup. */
-  name?: Maybe<Scalars['String']['output']>;
+  name: Maybe<Scalars['String']['output']>;
   /**
    * All branches and tags, optionally filtered by type. BRANCH and TAG are
    * the only accepted filter values; passing COMMIT returns an error.
@@ -1033,7 +1031,7 @@ export type Repository = {
   /** Directory listing at path under ref. An empty path returns the root tree. */
   tree: Array<GitTreeEntry>;
   /** The identity created or selected by the user as its own */
-  userIdentity?: Maybe<Identity>;
+  userIdentity: Maybe<Identity>;
   /** List of valid labels. */
   validLabels: LabelConnection;
 };
@@ -1117,7 +1115,7 @@ export type RepositoryValidLabelsArgs = {
 };
 
 export type RepositoryConnection = {
-  __typename?: 'RepositoryConnection';
+  __typename: 'RepositoryConnection';
   edges: Array<RepositoryEdge>;
   nodes: Array<Repository>;
   pageInfo: PageInfo;
@@ -1125,7 +1123,7 @@ export type RepositoryConnection = {
 };
 
 export type RepositoryEdge = {
-  __typename?: 'RepositoryEdge';
+  __typename: 'RepositoryEdge';
   cursor: Scalars['String']['output'];
   node: Repository;
 };
@@ -1136,7 +1134,7 @@ export enum Status {
 }
 
 export type Subscription = {
-  __typename?: 'Subscription';
+  __typename: 'Subscription';
   /** Subscribe to events on all entities. For events on a specific repo you can provide a repo reference. Without it, you get the unique default repo or all repo events. */
   allEvents: EntityEvent;
   /** Subscribe to bug entity events. For events on a specific repo you can provide a repo reference. Without it, you get the unique default repo or all repo events. */
@@ -1161,122 +1159,193 @@ export type SubscriptionIdentityEventsArgs = {
   repoRef?: InputMaybe<Scalars['String']['input']>;
 };
 
-export type BugCreateCommentFieldsFragment = { __typename?: 'BugCreateTimelineItem', message: string, createdAt: string, lastEdit: string, edited: boolean, author: { __typename?: 'Identity', id: string, humanId: string, displayName: string, avatarUrl?: string | null } };
+export type BugAddCommentMutationVariables = Exact<{
+  input: BugAddCommentInput;
+}>;
 
-export type BugAddCommentFieldsFragment = { __typename?: 'BugAddCommentTimelineItem', message: string, createdAt: string, lastEdit: string, edited: boolean, author: { __typename?: 'Identity', id: string, humanId: string, displayName: string, avatarUrl?: string | null } };
 
-export type LabelChangeFieldsFragment = { __typename?: 'BugLabelChangeTimelineItem', date: string, author: { __typename?: 'Identity', humanId: string, displayName: string }, added: Array<{ __typename?: 'Label', name: string, color: { __typename?: 'Color', R: number, G: number, B: number } }>, removed: Array<{ __typename?: 'Label', name: string, color: { __typename?: 'Color', R: number, G: number, B: number } }> };
+export type BugAddCommentMutation = { bugAddComment: { __typename: 'BugAddCommentPayload', bug: { __typename: 'Bug', id: string } } };
 
-export type StatusChangeFieldsFragment = { __typename?: 'BugSetStatusTimelineItem', date: string, status: Status, author: { __typename?: 'Identity', humanId: string, displayName: string } };
+export type BugAddCommentAndCloseMutationVariables = Exact<{
+  input: BugAddCommentAndCloseInput;
+}>;
 
-export type TitleChangeFieldsFragment = { __typename?: 'BugSetTitleTimelineItem', date: string, title: string, was: string, author: { __typename?: 'Identity', humanId: string, displayName: string } };
 
-export type IdentitySummaryFragment = { __typename?: 'Identity', id: string, humanId: string, displayName: string, avatarUrl?: string | null };
+export type BugAddCommentAndCloseMutation = { bugAddCommentAndClose: { __typename: 'BugAddCommentAndClosePayload', bug: { __typename: 'Bug', id: string } } };
 
-export type BugSummaryFragment = { __typename?: 'Bug', id: string, humanId: string, status: Status, title: string, createdAt: string, labels: Array<{ __typename?: 'Label', name: string, color: { __typename?: 'Color', R: number, G: number, B: number } }>, author: { __typename?: 'Identity', id: string, humanId: string, displayName: string, avatarUrl?: string | null }, comments: { __typename?: 'BugCommentConnection', totalCount: number } };
+export type BugAddCommentAndReopenMutationVariables = Exact<{
+  input: BugAddCommentAndReopenInput;
+}>;
 
-export type LabelFieldsFragment = { __typename?: 'Label', name: string, color: { __typename?: 'Color', R: number, G: number, B: number } };
 
-export type AllIdentitiesQueryVariables = Exact<{
-  ref?: InputMaybe<Scalars['String']['input']>;
+export type BugAddCommentAndReopenMutation = { bugAddCommentAndReopen: { __typename: 'BugAddCommentAndReopenPayload', bug: { __typename: 'Bug', id: string } } };
+
+export type BugStatusOpenMutationVariables = Exact<{
+  input: BugStatusOpenInput;
 }>;
 
 
-export type AllIdentitiesQuery = { __typename?: 'Query', repository?: { __typename?: 'Repository', allIdentities: { __typename?: 'IdentityConnection', nodes: Array<{ __typename?: 'Identity', id: string, humanId: string, name?: string | null, email?: string | null, login?: string | null, displayName: string, avatarUrl?: string | null }> } } | null };
+export type BugStatusOpenMutation = { bugStatusOpen: { __typename: 'BugStatusOpenPayload', bug: { __typename: 'Bug', id: string, status: Status } } };
 
-export type BugDetailQueryVariables = Exact<{
-  ref?: InputMaybe<Scalars['String']['input']>;
-  prefix: Scalars['String']['input'];
+export type BugStatusCloseMutationVariables = Exact<{
+  input: BugStatusCloseInput;
 }>;
 
 
-export type BugDetailQuery = { __typename?: 'Query', repository?: { __typename?: 'Repository', bug?: { __typename?: 'Bug', lastEdit: string, id: string, humanId: string, status: Status, title: string, createdAt: string, participants: { __typename?: 'IdentityConnection', nodes: Array<{ __typename?: 'Identity', id: string, humanId: string, displayName: string, avatarUrl?: string | null }> }, timeline: { __typename?: 'BugTimelineItemConnection', nodes: Array<
-          | { __typename: 'BugAddCommentTimelineItem', id: string, message: string, createdAt: string, lastEdit: string, edited: boolean, author: { __typename?: 'Identity', id: string, humanId: string, displayName: string, avatarUrl?: string | null } }
-          | { __typename: 'BugCreateTimelineItem', id: string, message: string, createdAt: string, lastEdit: string, edited: boolean, author: { __typename?: 'Identity', id: string, humanId: string, displayName: string, avatarUrl?: string | null } }
-          | { __typename: 'BugLabelChangeTimelineItem', id: string, date: string, author: { __typename?: 'Identity', humanId: string, displayName: string }, added: Array<{ __typename?: 'Label', name: string, color: { __typename?: 'Color', R: number, G: number, B: number } }>, removed: Array<{ __typename?: 'Label', name: string, color: { __typename?: 'Color', R: number, G: number, B: number } }> }
-          | { __typename: 'BugSetStatusTimelineItem', id: string, date: string, status: Status, author: { __typename?: 'Identity', humanId: string, displayName: string } }
-          | { __typename: 'BugSetTitleTimelineItem', id: string, date: string, title: string, was: string, author: { __typename?: 'Identity', humanId: string, displayName: string } }
-        > }, labels: Array<{ __typename?: 'Label', name: string, color: { __typename?: 'Color', R: number, G: number, B: number } }>, author: { __typename?: 'Identity', id: string, humanId: string, displayName: string, avatarUrl?: string | null }, comments: { __typename?: 'BugCommentConnection', totalCount: number } } | null } | null };
+export type BugStatusCloseMutation = { bugStatusClose: { __typename: 'BugStatusClosePayload', bug: { __typename: 'Bug', id: string, status: Status } } };
 
-export type BugListQueryVariables = Exact<{
-  ref?: InputMaybe<Scalars['String']['input']>;
-  openQuery: Scalars['String']['input'];
-  closedQuery: Scalars['String']['input'];
-  listQuery: Scalars['String']['input'];
-  first?: InputMaybe<Scalars['Int']['input']>;
+export type BugChangeLabelsMutationVariables = Exact<{
+  input?: InputMaybe<BugChangeLabelInput>;
+}>;
+
+
+export type BugChangeLabelsMutation = { bugChangeLabels: { __typename: 'BugChangeLabelPayload', bug: { __typename: 'Bug', id: string, labels: Array<{ __typename: 'Label', name: string, color: { __typename: 'Color', R: number, G: number, B: number } }> } } };
+
+export type BugCreateCommentFieldsFragment = { __typename: 'BugCreateTimelineItem', message: string, createdAt: string, lastEdit: string, edited: boolean, author: { __typename: 'Identity', id: string, humanId: string, displayName: string, avatarUrl: string | null } };
+
+export type BugAddCommentFieldsFragment = { __typename: 'BugAddCommentTimelineItem', message: string, createdAt: string, lastEdit: string, edited: boolean, author: { __typename: 'Identity', id: string, humanId: string, displayName: string, avatarUrl: string | null } };
+
+export type LabelChangeFieldsFragment = { __typename: 'BugLabelChangeTimelineItem', date: string, author: { __typename: 'Identity', humanId: string, displayName: string }, added: Array<{ __typename: 'Label', name: string, color: { __typename: 'Color', R: number, G: number, B: number } }>, removed: Array<{ __typename: 'Label', name: string, color: { __typename: 'Color', R: number, G: number, B: number } }> };
+
+export type StatusChangeFieldsFragment = { __typename: 'BugSetStatusTimelineItem', date: string, status: Status, author: { __typename: 'Identity', humanId: string, displayName: string } };
+
+export type TitleChangeFieldsFragment = { __typename: 'BugSetTitleTimelineItem', date: string, title: string, was: string, author: { __typename: 'Identity', humanId: string, displayName: string } };
+
+export type BugEditCommentMutationVariables = Exact<{
+  input: BugEditCommentInput;
+}>;
+
+
+export type BugEditCommentMutation = { bugEditComment: { __typename: 'BugEditCommentPayload', bug: { __typename: 'Bug', id: string } } };
+
+export type BugSetTitleMutationVariables = Exact<{
+  input: BugSetTitleInput;
+}>;
+
+
+export type BugSetTitleMutation = { bugSetTitle: { __typename: 'BugSetTitlePayload', bug: { __typename: 'Bug', id: string, title: string } } };
+
+export type CommitListQueryVariables = Exact<{
+  repo?: InputMaybe<Scalars['String']['input']>;
+  ref: Scalars['String']['input'];
+  path?: InputMaybe<Scalars['String']['input']>;
   after?: InputMaybe<Scalars['String']['input']>;
+  first?: InputMaybe<Scalars['Int']['input']>;
 }>;
 
 
-export type BugListQuery = { __typename?: 'Query', repository?: { __typename?: 'Repository', openCount: { __typename?: 'BugConnection', totalCount: number }, closedCount: { __typename?: 'BugConnection', totalCount: number }, bugs: { __typename?: 'BugConnection', totalCount: number, pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean, endCursor: string }, nodes: Array<{ __typename?: 'Bug', id: string, humanId: string, status: Status, title: string, createdAt: string, labels: Array<{ __typename?: 'Label', name: string, color: { __typename?: 'Color', R: number, G: number, B: number } }>, author: { __typename?: 'Identity', id: string, humanId: string, displayName: string, avatarUrl?: string | null }, comments: { __typename?: 'BugCommentConnection', totalCount: number } }> } } | null };
+export type CommitListQuery = { repository: { __typename: 'Repository', commits: { __typename: 'GitCommitConnection', nodes: Array<{ __typename: 'GitCommit', hash: string, shortHash: string, message: string, authorName: string, date: string }>, pageInfo: { __typename: 'PageInfo', hasNextPage: boolean, endCursor: string } } } | null };
 
-export type BugCreateMutationVariables = Exact<{
-  input: BugCreateInput;
+export type FileDiffQueryVariables = Exact<{
+  repo?: InputMaybe<Scalars['String']['input']>;
+  hash: Scalars['String']['input'];
+  path: Scalars['String']['input'];
 }>;
 
 
-export type BugCreateMutation = { __typename?: 'Mutation', bugCreate: { __typename?: 'BugCreatePayload', bug: { __typename?: 'Bug', id: string, humanId: string } } };
+export type FileDiffQuery = { repository: { __typename: 'Repository', commit: { __typename: 'GitCommit', diff: { __typename: 'GitFileDiff', path: string, oldPath: string | null, isBinary: boolean, isNew: boolean, isDelete: boolean, hunks: Array<{ __typename: 'GitDiffHunk', oldStart: number, oldLines: number, newStart: number, newLines: number, lines: Array<{ __typename: 'GitDiffLine', type: GitDiffLineType, content: string, oldLine: number, newLine: number }> }> } | null } | null } | null };
 
-export type BugAddCommentMutationVariables = Exact<{
-  input: BugAddCommentInput;
+export type IdentitySummaryFragment = { __typename: 'Identity', id: string, humanId: string, displayName: string, avatarUrl: string | null };
+
+export type BugSummaryFragment = { __typename: 'Bug', id: string, humanId: string, status: Status, title: string, createdAt: string, labels: Array<{ __typename: 'Label', name: string, color: { __typename: 'Color', R: number, G: number, B: number } }>, author: { __typename: 'Identity', id: string, humanId: string, displayName: string, avatarUrl: string | null }, comments: { __typename: 'BugCommentConnection', totalCount: number } };
+
+export type LabelFieldsFragment = { __typename: 'Label', name: string, color: { __typename: 'Color', R: number, G: number, B: number } };
+
+export type UserIdentityQueryVariables = Exact<{ [key: string]: never; }>;
+
+
+export type UserIdentityQuery = { repository: { __typename: 'Repository', userIdentity: { __typename: 'Identity', id: string, humanId: string, name: string | null, displayName: string, avatarUrl: string | null, email: string | null, login: string | null } | null } | null };
+
+export type CodePageRefsQueryVariables = Exact<{
+  repo?: InputMaybe<Scalars['String']['input']>;
 }>;
 
 
-export type BugAddCommentMutation = { __typename?: 'Mutation', bugAddComment: { __typename?: 'BugAddCommentPayload', bug: { __typename?: 'Bug', id: string } } };
+export type CodePageRefsQuery = { repository: { __typename: 'Repository', name: string | null, head: { __typename: 'GitRef', shortName: string } | null, refs: { __typename: 'GitRefConnection', nodes: Array<{ __typename: 'GitRef', name: string, shortName: string, type: GitRefType, hash: string }> } } | null };
 
-export type BugAddCommentAndCloseMutationVariables = Exact<{
-  input: BugAddCommentAndCloseInput;
+export type CodePageBlobQueryVariables = Exact<{
+  repo?: InputMaybe<Scalars['String']['input']>;
+  ref: Scalars['String']['input'];
+  path: Scalars['String']['input'];
 }>;
 
 
-export type BugAddCommentAndCloseMutation = { __typename?: 'Mutation', bugAddCommentAndClose: { __typename?: 'BugAddCommentAndClosePayload', bug: { __typename?: 'Bug', id: string } } };
+export type CodePageBlobQuery = { repository: { __typename: 'Repository', blob: { __typename: 'GitBlob', path: string, hash: string, text: string | null, size: number, isBinary: boolean, isTruncated: boolean } | null } | null };
 
-export type BugAddCommentAndReopenMutationVariables = Exact<{
-  input: BugAddCommentAndReopenInput;
+export type CodePageTreeQueryVariables = Exact<{
+  repo?: InputMaybe<Scalars['String']['input']>;
+  ref: Scalars['String']['input'];
+  path?: InputMaybe<Scalars['String']['input']>;
 }>;
 
 
-export type BugAddCommentAndReopenMutation = { __typename?: 'Mutation', bugAddCommentAndReopen: { __typename?: 'BugAddCommentAndReopenPayload', bug: { __typename?: 'Bug', id: string } } };
+export type CodePageTreeQuery = { repository: { __typename: 'Repository', tree: Array<{ __typename: 'GitTreeEntry', name: string, type: GitObjectType, hash: string }> } | null };
 
-export type BugEditCommentMutationVariables = Exact<{
-  input: BugEditCommentInput;
+export type CodePageLastCommitsQueryVariables = Exact<{
+  repo?: InputMaybe<Scalars['String']['input']>;
+  ref: Scalars['String']['input'];
+  path?: InputMaybe<Scalars['String']['input']>;
+  names: Array<Scalars['String']['input']> | Scalars['String']['input'];
 }>;
 
 
-export type BugEditCommentMutation = { __typename?: 'Mutation', bugEditComment: { __typename?: 'BugEditCommentPayload', bug: { __typename?: 'Bug', id: string } } };
+export type CodePageLastCommitsQuery = { repository: { __typename: 'Repository', lastCommits: Array<{ __typename: 'GitLastCommit', name: string, commit: { __typename: 'GitCommit', hash: string, shortHash: string, message: string, date: string } }> } | null };
 
-export type BugChangeLabelsMutationVariables = Exact<{
-  input?: InputMaybe<BugChangeLabelInput>;
+export type CodePageReadmeQueryVariables = Exact<{
+  repo?: InputMaybe<Scalars['String']['input']>;
+  ref: Scalars['String']['input'];
+  path: Scalars['String']['input'];
 }>;
 
 
-export type BugChangeLabelsMutation = { __typename?: 'Mutation', bugChangeLabels: { __typename?: 'BugChangeLabelPayload', bug: { __typename?: 'Bug', id: string, labels: Array<{ __typename?: 'Label', name: string, color: { __typename?: 'Color', R: number, G: number, B: number } }> } } };
+export type CodePageReadmeQuery = { repository: { __typename: 'Repository', blob: { __typename: 'GitBlob', text: string | null } | null } | null };
 
-export type BugStatusOpenMutationVariables = Exact<{
-  input: BugStatusOpenInput;
+export type AllIdentitiesQueryVariables = Exact<{
+  ref?: InputMaybe<Scalars['String']['input']>;
 }>;
 
 
-export type BugStatusOpenMutation = { __typename?: 'Mutation', bugStatusOpen: { __typename?: 'BugStatusOpenPayload', bug: { __typename?: 'Bug', id: string, status: Status } } };
+export type AllIdentitiesQuery = { repository: { __typename: 'Repository', allIdentities: { __typename: 'IdentityConnection', nodes: Array<{ __typename: 'Identity', id: string, humanId: string, name: string | null, email: string | null, login: string | null, displayName: string, avatarUrl: string | null }> } } | null };
 
-export type BugStatusCloseMutationVariables = Exact<{
-  input: BugStatusCloseInput;
+export type ValidLabelsQueryVariables = Exact<{
+  ref?: InputMaybe<Scalars['String']['input']>;
 }>;
 
 
-export type BugStatusCloseMutation = { __typename?: 'Mutation', bugStatusClose: { __typename?: 'BugStatusClosePayload', bug: { __typename?: 'Bug', id: string, status: Status } } };
+export type ValidLabelsQuery = { repository: { __typename: 'Repository', validLabels: { __typename: 'LabelConnection', nodes: Array<{ __typename: 'Label', name: string, color: { __typename: 'Color', R: number, G: number, B: number } }> } } | null };
 
-export type BugSetTitleMutationVariables = Exact<{
-  input: BugSetTitleInput;
+export type BugDetailQueryVariables = Exact<{
+  ref?: InputMaybe<Scalars['String']['input']>;
+  prefix: Scalars['String']['input'];
 }>;
 
 
-export type BugSetTitleMutation = { __typename?: 'Mutation', bugSetTitle: { __typename?: 'BugSetTitlePayload', bug: { __typename?: 'Bug', id: string, title: string } } };
+export type BugDetailQuery = { repository: { __typename: 'Repository', bug: { __typename: 'Bug', lastEdit: string, id: string, humanId: string, status: Status, title: string, createdAt: string, participants: { __typename: 'IdentityConnection', nodes: Array<{ __typename: 'Identity', id: string, humanId: string, displayName: string, avatarUrl: string | null }> }, timeline: { __typename: 'BugTimelineItemConnection', nodes: Array<
+          | { __typename: 'BugAddCommentTimelineItem', id: string, message: string, createdAt: string, lastEdit: string, edited: boolean, author: { __typename: 'Identity', id: string, humanId: string, displayName: string, avatarUrl: string | null } }
+          | { __typename: 'BugCreateTimelineItem', id: string, message: string, createdAt: string, lastEdit: string, edited: boolean, author: { __typename: 'Identity', id: string, humanId: string, displayName: string, avatarUrl: string | null } }
+          | { __typename: 'BugLabelChangeTimelineItem', id: string, date: string, author: { __typename: 'Identity', humanId: string, displayName: string }, added: Array<{ __typename: 'Label', name: string, color: { __typename: 'Color', R: number, G: number, B: number } }>, removed: Array<{ __typename: 'Label', name: string, color: { __typename: 'Color', R: number, G: number, B: number } }> }
+          | { __typename: 'BugSetStatusTimelineItem', id: string, date: string, status: Status, author: { __typename: 'Identity', humanId: string, displayName: string } }
+          | { __typename: 'BugSetTitleTimelineItem', id: string, date: string, title: string, was: string, author: { __typename: 'Identity', humanId: string, displayName: string } }
+        > }, labels: Array<{ __typename: 'Label', name: string, color: { __typename: 'Color', R: number, G: number, B: number } }>, author: { __typename: 'Identity', id: string, humanId: string, displayName: string, avatarUrl: string | null }, comments: { __typename: 'BugCommentConnection', totalCount: number } } | null } | null };
+
+export type BugListQueryVariables = Exact<{
+  ref?: InputMaybe<Scalars['String']['input']>;
+  openQuery: Scalars['String']['input'];
+  closedQuery: Scalars['String']['input'];
+  listQuery: Scalars['String']['input'];
+  first?: InputMaybe<Scalars['Int']['input']>;
+  after?: InputMaybe<Scalars['String']['input']>;
+}>;
 
-export type RepositoriesQueryVariables = Exact<{ [key: string]: never; }>;
 
+export type BugListQuery = { repository: { __typename: 'Repository', openCount: { __typename: 'BugConnection', totalCount: number }, closedCount: { __typename: 'BugConnection', totalCount: number }, bugs: { __typename: 'BugConnection', totalCount: number, pageInfo: { __typename: 'PageInfo', hasNextPage: boolean, endCursor: string }, nodes: Array<{ __typename: 'Bug', id: string, humanId: string, status: Status, title: string, createdAt: string, labels: Array<{ __typename: 'Label', name: string, color: { __typename: 'Color', R: number, G: number, B: number } }>, author: { __typename: 'Identity', id: string, humanId: string, displayName: string, avatarUrl: string | null }, comments: { __typename: 'BugCommentConnection', totalCount: number } }> } } | null };
 
-export type RepositoriesQuery = { __typename?: 'Query', repositories: { __typename?: 'RepositoryConnection', totalCount: number, nodes: Array<{ __typename?: 'Repository', name?: string | null }> } };
+export type BugCreateMutationVariables = Exact<{
+  input: BugCreateInput;
+}>;
+
+
+export type BugCreateMutation = { bugCreate: { __typename: 'BugCreatePayload', bug: { __typename: 'Bug', id: string, humanId: string } } };
 
 export type UserProfileQueryVariables = Exact<{
   ref?: InputMaybe<Scalars['String']['input']>;
@@ -1288,799 +1357,50 @@ export type UserProfileQueryVariables = Exact<{
 }>;
 
 

webui2/src/components/bugs/comment-box.tsx 🔗

@@ -1,14 +1,8 @@
+import { useMutation } from "@apollo/client/react";
 import { useState } from "react";
 
-import { Status } from "@/__generated__/graphql";
-import {
-  useBugAddCommentMutation,
-  useBugAddCommentAndCloseMutation,
-  useBugAddCommentAndReopenMutation,
-  useBugStatusCloseMutation,
-  useBugStatusOpenMutation,
-  BugDetailDocument,
-} from "@/__generated__/graphql";
+import { Status, BugDetailDocument } from "@/__generated__/graphql";
+import { graphql } from "@/__generated__/gql";
 import { Markdown } from "@/components/content/markdown";
 import { Button } from "@/components/ui/button";
 import * as CommentCard from "@/components/shared/comment-card";
@@ -16,6 +10,58 @@ import { Textarea } from "@/components/ui/textarea";
 import * as WritePreview from "@/components/shared/write-preview";
 import { useAuth } from "@/lib/auth";
 
+const BUG_ADD_COMMENT_MUTATION = graphql(`
+  mutation BugAddComment($input: BugAddCommentInput!) {
+    bugAddComment(input: $input) {
+      bug {
+        id
+      }
+    }
+  }
+`);
+
+const BUG_ADD_COMMENT_AND_CLOSE_MUTATION = graphql(`
+  mutation BugAddCommentAndClose($input: BugAddCommentAndCloseInput!) {
+    bugAddCommentAndClose(input: $input) {
+      bug {
+        id
+      }
+    }
+  }
+`);
+
+const BUG_ADD_COMMENT_AND_REOPEN_MUTATION = graphql(`
+  mutation BugAddCommentAndReopen($input: BugAddCommentAndReopenInput!) {
+    bugAddCommentAndReopen(input: $input) {
+      bug {
+        id
+      }
+    }
+  }
+`);
+
+const BUG_STATUS_OPEN_MUTATION = graphql(`
+  mutation BugStatusOpen($input: BugStatusOpenInput!) {
+    bugStatusOpen(input: $input) {
+      bug {
+        id
+        status
+      }
+    }
+  }
+`);
+
+const BUG_STATUS_CLOSE_MUTATION = graphql(`
+  mutation BugStatusClose($input: BugStatusCloseInput!) {
+    bugStatusClose(input: $input) {
+      bug {
+        id
+        status
+      }
+    }
+  }
+`);
+
 interface CommentBoxProps {
   bugPrefix: string;
   bugStatus: Status;
@@ -33,12 +79,12 @@ export function CommentBox({ bugPrefix, bugStatus, ref_ }: CommentBoxProps) {
   const refetchVars = { variables: { ref: ref_, prefix: bugPrefix } };
   const refetch = { refetchQueries: [{ query: BugDetailDocument, ...refetchVars }] };
 
-  const [addComment, { loading: addingComment }] = useBugAddCommentMutation(refetch);
-  const [addAndClose, { loading: addingAndClosing }] = useBugAddCommentAndCloseMutation(refetch);
+  const [addComment, { loading: addingComment }] = useMutation(BUG_ADD_COMMENT_MUTATION, refetch);
+  const [addAndClose, { loading: addingAndClosing }] = useMutation(BUG_ADD_COMMENT_AND_CLOSE_MUTATION, refetch);
   const [addAndReopen, { loading: addingAndReopening }] =
-    useBugAddCommentAndReopenMutation(refetch);
-  const [statusClose, { loading: closing }] = useBugStatusCloseMutation(refetch);
-  const [statusOpen, { loading: reopening }] = useBugStatusOpenMutation(refetch);
+    useMutation(BUG_ADD_COMMENT_AND_REOPEN_MUTATION, refetch);
+  const [statusClose, { loading: closing }] = useMutation(BUG_STATUS_CLOSE_MUTATION, refetch);
+  const [statusOpen, { loading: reopening }] = useMutation(BUG_STATUS_OPEN_MUTATION, refetch);
 
   const isOpen = bugStatus === Status.Open;
   const busy = addingComment || addingAndClosing || addingAndReopening || closing || reopening;

webui2/src/components/bugs/label-editor.tsx 🔗

@@ -1,3 +1,4 @@
+import { useMutation } from "@apollo/client/react";
 import {
   useFloating,
   useClick,
@@ -13,12 +14,30 @@ import {
 import { Settings2 } from "lucide-react";
 import { useRef, useState } from "react";
 
-import { useBugChangeLabelsMutation, BugDetailDocument } from "@/__generated__/graphql";
+import { BugDetailDocument } from "@/__generated__/graphql";
+import { graphql } from "@/__generated__/gql";
 import * as Listbox from "@/components/ui/listbox";
+import { LabelBadge } from "@/components/shared/label-badge";
 import { SectionHeading } from "@/components/shared/section-heading";
 import { useAuth } from "@/lib/auth";
 
-import { LabelBadge } from "@/components/shared/label-badge";
+const BUG_CHANGE_LABELS_MUTATION = graphql(`
+  mutation BugChangeLabels($input: BugChangeLabelInput) {
+    bugChangeLabels(input: $input) {
+      bug {
+        id
+        labels {
+          name
+          color {
+            R
+            G
+            B
+          }
+        }
+      }
+    }
+  }
+`);
 
 interface LabelEditorProps {
   bugPrefix: string;
@@ -34,7 +53,7 @@ interface LabelEditorProps {
 // Hidden in read-only mode.
 export function LabelEditor({ bugPrefix, currentLabels, ref_, validLabels }: LabelEditorProps) {
   const { user } = useAuth();
-  const [changeLabels] = useBugChangeLabelsMutation({
+  const [changeLabels] = useMutation(BUG_CHANGE_LABELS_MUTATION, {
     refetchQueries: [{ query: BugDetailDocument, variables: { ref: ref_, prefix: bugPrefix } }],
   });
 

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

@@ -1,52 +0,0 @@
-fragment BugCreateCommentFields on BugCreateTimelineItem {
-  author {
-    ...IdentitySummary
-  }
-  message
-  createdAt
-  lastEdit
-  edited
-}
-
-fragment BugAddCommentFields on BugAddCommentTimelineItem {
-  author {
-    ...IdentitySummary
-  }
-  message
-  createdAt
-  lastEdit
-  edited
-}
-
-fragment LabelChangeFields on BugLabelChangeTimelineItem {
-  author {
-    humanId
-    displayName
-  }
-  date
-  added {
-    ...LabelFields
-  }
-  removed {
-    ...LabelFields
-  }
-}
-
-fragment StatusChangeFields on BugSetStatusTimelineItem {
-  author {
-    humanId
-    displayName
-  }
-  date
-  status
-}
-
-fragment TitleChangeFields on BugSetTitleTimelineItem {
-  author {
-    humanId
-    displayName
-  }
-  date
-  title
-  was
-}

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

@@ -1,21 +1,90 @@
+import { useMutation } from "@apollo/client/react";
 import { Link } from "@tanstack/react-router";
 import { formatDistanceToNow } from "date-fns";
 import { Tag, GitPullRequestClosed, Pencil, CircleDot } from "lucide-react";
 import { useState } from "react";
 
-import {
-  Status,
-  type BugDetailQuery,
-  useBugEditCommentMutation,
-  BugDetailDocument,
-} from "@/__generated__/graphql";
+import { Status, type BugDetailQuery, BugDetailDocument } from "@/__generated__/graphql";
+import { graphql } from "@/__generated__/gql";
 import { Markdown } from "@/components/content/markdown";
 import { Button } from "@/components/ui/button";
 import * as CommentCard from "@/components/shared/comment-card";
+import { LabelBadge } from "@/components/shared/label-badge";
 import { Textarea } from "@/components/ui/textarea";
 import { useAuth } from "@/lib/auth";
 
-import { LabelBadge } from "@/components/shared/label-badge";
+export const BUG_CREATE_COMMENT_FIELDS = graphql(`
+  fragment BugCreateCommentFields on BugCreateTimelineItem {
+    author {
+      ...IdentitySummary
+    }
+    message
+    createdAt
+    lastEdit
+    edited
+  }
+`);
+
+export const BUG_ADD_COMMENT_FIELDS = graphql(`
+  fragment BugAddCommentFields on BugAddCommentTimelineItem {
+    author {
+      ...IdentitySummary
+    }
+    message
+    createdAt
+    lastEdit
+    edited
+  }
+`);
+
+export const LABEL_CHANGE_FIELDS = graphql(`
+  fragment LabelChangeFields on BugLabelChangeTimelineItem {
+    author {
+      humanId
+      displayName
+    }
+    date
+    added {
+      ...LabelFields
+    }
+    removed {
+      ...LabelFields
+    }
+  }
+`);
+
+export const STATUS_CHANGE_FIELDS = graphql(`
+  fragment StatusChangeFields on BugSetStatusTimelineItem {
+    author {
+      humanId
+      displayName
+    }
+    date
+    status
+  }
+`);
+
+export const TITLE_CHANGE_FIELDS = graphql(`
+  fragment TitleChangeFields on BugSetTitleTimelineItem {
+    author {
+      humanId
+      displayName
+    }
+    date
+    title
+    was
+  }
+`);
+
+const BUG_EDIT_COMMENT_MUTATION = graphql(`
+  mutation BugEditComment($input: BugEditCommentInput!) {
+    bugEditComment(input: $input) {
+      bug {
+        id
+      }
+    }
+  }
+`);
 
 type TimelineNode = NonNullable<
   NonNullable<NonNullable<BugDetailQuery["repository"]>["bug"]>["timeline"]["nodes"][number]
@@ -72,7 +141,7 @@ function CommentItem({
   const [editing, setEditing] = useState(false);
   const [editValue, setEditValue] = useState(item.message ?? "");
 
-  const [editComment, { loading }] = useBugEditCommentMutation({
+  const [editComment, { loading }] = useMutation(BUG_EDIT_COMMENT_MUTATION, {
     refetchQueries: [{ query: BugDetailDocument, variables: { prefix: bugPrefix } }],
   });
 

webui2/src/components/bugs/title-editor.tsx 🔗

@@ -1,11 +1,24 @@
+import { useMutation } from "@apollo/client/react";
 import { Pencil } from "lucide-react";
 import { useState, useRef, useEffect } from "react";
 
-import { useBugSetTitleMutation, BugDetailDocument } from "@/__generated__/graphql";
+import { BugDetailDocument } from "@/__generated__/graphql";
+import { graphql } from "@/__generated__/gql";
 import { Button } from "@/components/ui/button";
 import { Input } from "@/components/ui/input";
 import { useAuth } from "@/lib/auth";
 
+const BUG_SET_TITLE_MUTATION = graphql(`
+  mutation BugSetTitle($input: BugSetTitleInput!) {
+    bugSetTitle(input: $input) {
+      bug {
+        id
+        title
+      }
+    }
+  }
+`);
+
 interface TitleEditorProps {
   bugPrefix: string;
   title: string;
@@ -22,7 +35,7 @@ export function TitleEditor({ bugPrefix, title, humanId, ref_ }: TitleEditorProp
   const [value, setValue] = useState(title);
   const inputRef = useRef<HTMLInputElement>(null);
 
-  const [setTitle, { loading }] = useBugSetTitleMutation({
+  const [setTitle, { loading }] = useMutation(BUG_SET_TITLE_MUTATION, {
     refetchQueries: [{ query: BugDetailDocument, variables: { ref: ref_, prefix: bugPrefix } }],
   });
 

webui2/src/components/code/commit-list.tsx 🔗

@@ -1,17 +1,17 @@
 // Paginated commit history grouped by calendar date. Each row links to the
 // commit detail page. Used in CodePage's "History" view.
 
-import { gql } from "@apollo/client";
 import { useQuery } from "@apollo/client/react";
 import { Link } from "@tanstack/react-router";
 import { formatDistanceToNow } from "date-fns";
 import { GitCommit } from "lucide-react";
 import { useEffect, useState } from "react";
 
+import { graphql } from "@/__generated__/gql";
 import { Button } from "@/components/ui/button";
 import { Skeleton } from "@/components/ui/skeleton";
 
-const COMMITS_QUERY = gql`
+const COMMITS_QUERY = graphql(`
   query CommitList($repo: String, $ref: String!, $path: String, $after: String, $first: Int) {
     repository(ref: $repo) {
       commits(ref: $ref, path: $path, after: $after, first: $first) {
@@ -29,19 +29,10 @@ const COMMITS_QUERY = gql`
       }
     }
   }
-`;
+`);
 
 const PAGE_SIZE = 30;
 
-interface CommitListQueryData {
-  repository: {
-    commits: {
-      nodes: CommitNode[];
-      pageInfo: { hasNextPage: boolean; endCursor: string | null };
-    } | null;
-  } | null;
-}
-
 interface CommitListProps {
   repo: string | null;
   ref_: string;
@@ -60,7 +51,7 @@ export function CommitList({ repo, ref_, path }: CommitListProps) {
   const [cursor, setCursor] = useState<string | null>(null);
   const [allCommits, setAllCommits] = useState<CommitNode[]>([]);
 
-  const { data, loading, error, fetchMore } = useQuery<CommitListQueryData>(COMMITS_QUERY, {
+  const { data, loading, error, fetchMore } = useQuery(COMMITS_QUERY, {
     variables: { repo, ref: ref_, path: path ?? null, after: null, first: PAGE_SIZE },
     skip: !ref_,
   });

webui2/src/components/code/file-diff-view.tsx 🔗

@@ -1,14 +1,14 @@
 // Collapsible diff view for a single file in a commit.
 // Diff is fetched lazily on first expand via GraphQL.
 
-import { gql } from "@apollo/client";
 import { useLazyQuery } from "@apollo/client/react";
 import { ChevronRight, FilePlus, FileMinus, FileEdit } from "lucide-react";
 import { useState } from "react";
 
+import { graphql } from "@/__generated__/gql";
 import { cn } from "@/lib/utils";
 
-const DIFF_QUERY = gql`
+const DIFF_QUERY = graphql(`
   query FileDiff($repo: String, $hash: String!, $path: String!) {
     repository(ref: $repo) {
       commit(hash: $hash) {
@@ -34,22 +34,7 @@ const DIFF_QUERY = gql`
       }
     }
   }
-`;
-
-interface DiffQueryData {
-  repository: {
-    commit: {
-      diff: {
-        path: string;
-        oldPath: string | null;
-        isBinary: boolean;
-        isNew: boolean;
-        isDelete: boolean;
-        hunks: HunkType[];
-      } | null;
-    } | null;
-  } | null;
-}
+`);
 
 interface FileDiffViewProps {
   repo: string | null;
@@ -74,7 +59,7 @@ const statusBadge: Record<string, string> = {
 
 export function FileDiffView({ repo, hash, path, oldPath, status }: FileDiffViewProps) {
   const [open, setOpen] = useState(false);
-  const [fetchDiff, { data, loading, error }] = useLazyQuery<DiffQueryData>(DIFF_QUERY);
+  const [fetchDiff, { data, loading, error }] = useLazyQuery(DIFF_QUERY);
 
   function toggle() {
     if (!open && !data && !loading) {

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

@@ -1,8 +1,18 @@
 import type { IdentitySummaryFragment } from "@/__generated__/graphql";
+import { graphql } from "@/__generated__/gql";
 import { cn } from "@/lib/utils";
 
 import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
 
+export const IDENTITY_SUMMARY_FRAGMENT = graphql(`
+  fragment IdentitySummary on Identity {
+    id
+    humanId
+    displayName
+    avatarUrl
+  }
+`);
+
 interface RootProps {
   children: React.ReactNode;
   className?: string;

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

@@ -1,8 +1,28 @@
 import { CircleDot, CircleCheck, MessageSquare } from "lucide-react";
 
 import { Status } from "@/__generated__/graphql";
+import { graphql } from "@/__generated__/gql";
 import { cn } from "@/lib/utils";
 
+export const BUG_SUMMARY_FRAGMENT = graphql(`
+  fragment BugSummary on Bug {
+    id
+    humanId
+    status
+    title
+    labels {
+      ...LabelFields
+    }
+    author {
+      ...IdentitySummary
+    }
+    createdAt
+    comments {
+      totalCount
+    }
+  }
+`);
+
 interface RootProps {
   className?: string;
   children: React.ReactNode;

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

@@ -2,6 +2,18 @@ import { createLink, type LinkComponent } from "@tanstack/react-router";
 import * as React from "react";
 
 import type { LabelFieldsFragment } from "@/__generated__/graphql";
+import { graphql } from "@/__generated__/gql";
+
+export const LABEL_FIELDS_FRAGMENT = graphql(`
+  fragment LabelFields on Label {
+    name
+    color {
+      R
+      G
+      B
+    }
+  }
+`);
 
 type LabelBadgeProps = LabelFieldsFragment & {
   className?: string;

webui2/src/graphql/AllIdentities.graphql 🔗

@@ -1,15 +0,0 @@
-query AllIdentities($ref: String) {
-  repository(ref: $ref) {
-    allIdentities(first: 1000) {
-      nodes {
-        id
-        humanId
-        name
-        email
-        login
-        displayName
-        avatarUrl
-      }
-    }
-  }
-}

webui2/src/graphql/BugDetail.graphql 🔗

@@ -1,34 +0,0 @@
-query BugDetail($ref: String, $prefix: String!) {
-  repository(ref: $ref) {
-    bug(prefix: $prefix) {
-      ...BugSummary
-      lastEdit
-      participants(first: 20) {
-        nodes {
-          ...IdentitySummary
-        }
-      }
-      timeline(first: 250) {
-        nodes {
-          __typename
-          id
-          ... on BugCreateTimelineItem {
-            ...BugCreateCommentFields
-          }
-          ... on BugAddCommentTimelineItem {
-            ...BugAddCommentFields
-          }
-          ... on BugLabelChangeTimelineItem {
-            ...LabelChangeFields
-          }
-          ... on BugSetStatusTimelineItem {
-            ...StatusChangeFields
-          }
-          ... on BugSetTitleTimelineItem {
-            ...TitleChangeFields
-          }
-        }
-      }
-    }
-  }
-}

webui2/src/graphql/BugList.graphql 🔗

@@ -1,30 +0,0 @@
-# Always fetch open and closed counts unconditionally so both numbers are
-# visible in the toggle header regardless of which tab is active.
-# The paginated `bugs` alias fetches the selected-status list separately.
-query BugList(
-  $ref: String
-  $openQuery: String!
-  $closedQuery: String!
-  $listQuery: String!
-  $first: Int
-  $after: String
-) {
-  repository(ref: $ref) {
-    openCount: allBugs(query: $openQuery, first: 1) {
-      totalCount
-    }
-    closedCount: allBugs(query: $closedQuery, first: 1) {
-      totalCount
-    }
-    bugs: allBugs(query: $listQuery, first: $first, after: $after) {
-      totalCount
-      pageInfo {
-        hasNextPage
-        endCursor
-      }
-      nodes {
-        ...BugSummary
-      }
-    }
-  }
-}

webui2/src/graphql/BugMutations.graphql 🔗

@@ -1,83 +0,0 @@
-mutation BugCreate($input: BugCreateInput!) {
-  bugCreate(input: $input) {
-    bug {
-      id
-      humanId
-    }
-  }
-}
-
-mutation BugAddComment($input: BugAddCommentInput!) {
-  bugAddComment(input: $input) {
-    bug {
-      id
-    }
-  }
-}
-
-mutation BugAddCommentAndClose($input: BugAddCommentAndCloseInput!) {
-  bugAddCommentAndClose(input: $input) {
-    bug {
-      id
-    }
-  }
-}
-
-mutation BugAddCommentAndReopen($input: BugAddCommentAndReopenInput!) {
-  bugAddCommentAndReopen(input: $input) {
-    bug {
-      id
-    }
-  }
-}
-
-mutation BugEditComment($input: BugEditCommentInput!) {
-  bugEditComment(input: $input) {
-    bug {
-      id
-    }
-  }
-}
-
-mutation BugChangeLabels($input: BugChangeLabelInput) {
-  bugChangeLabels(input: $input) {
-    bug {
-      id
-      labels {
-        name
-        color {
-          R
-          G
-          B
-        }
-      }
-    }
-  }
-}
-
-mutation BugStatusOpen($input: BugStatusOpenInput!) {
-  bugStatusOpen(input: $input) {
-    bug {
-      id
-      status
-    }
-  }
-}
-
-mutation BugStatusClose($input: BugStatusCloseInput!) {
-  bugStatusClose(input: $input) {
-    bug {
-      id
-      status
-    }
-  }
-}
-
-mutation BugSetTitle($input: BugSetTitleInput!) {
-  bugSetTitle(input: $input) {
-    bug {
-      id
-      title
-    }
-  }
-}

webui2/src/graphql/UserProfile.graphql 🔗

@@ -1,42 +0,0 @@
-# Profile page query. We fetch open and closed counts unconditionally so both
-# can be shown in the toggle header regardless of which tab is active. The
-# paginated `bugs` alias fetches the selected status list separately.
-query UserProfile(
-  $ref: String
-  $prefix: String!
-  $openQuery: String!
-  $closedQuery: String!
-  $listQuery: String!
-  $after: String
-) {
-  repository(ref: $ref) {
-    identity(prefix: $prefix) {
-      id
-      humanId
-      name
-      email
-      login
-      displayName
-      avatarUrl
-      isProtected
-    }
-    # Always-fetched counts so we can show both numbers in the toggle.
-    openCount: allBugs(query: $openQuery, first: 1) {
-      totalCount
-    }
-    closedCount: allBugs(query: $closedQuery, first: 1) {
-      totalCount
-    }
-    # Paginated list for the currently-selected tab.
-    bugs: allBugs(query: $listQuery, first: 25, after: $after) {
-      totalCount
-      pageInfo {
-        hasNextPage
-        endCursor
-      }
-      nodes {
-        ...BugSummary
-      }
-    }
-  }
-}

webui2/src/lib/auth.tsx 🔗

@@ -3,10 +3,11 @@
 // The UserIdentity query is preloaded in the root route loader and consumed
 // via useSuspenseQuery, so useAuth() always returns a resolved user.
 
-import { gql } from "@apollo/client";
 import { useSuspenseQuery } from "@apollo/client/react";
 
-export const USER_IDENTITY_QUERY = gql`
+import { graphql } from "@/__generated__/gql";
+
+export const USER_IDENTITY_QUERY = graphql(`
   query UserIdentity {
     repository {
       userIdentity {
@@ -20,7 +21,7 @@ export const USER_IDENTITY_QUERY = gql`
       }
     }
   }
-`;
+`);
 
 export interface AuthUser {
   id: string;
@@ -33,8 +34,6 @@ export interface AuthUser {
 }
 
 export function useAuth(): { user: AuthUser } {
-  const { data } = useSuspenseQuery<{ repository: { userIdentity: AuthUser } }>(
-    USER_IDENTITY_QUERY,
-  );
-  return { user: data.repository.userIdentity };
+  const { data } = useSuspenseQuery(USER_IDENTITY_QUERY);
+  return { user: data.repository!.userIdentity! as AuthUser };
 }

webui2/src/routes/$repo.tsx 🔗

@@ -1,9 +1,8 @@
-import { gql } from "@apollo/client";
 import { createFileRoute } from "@tanstack/react-router";
 
-import type { GitRef } from "@/__generated__/graphql";
+import { graphql } from "@/__generated__/gql";
 
-export const REFS_QUERY = gql`
+export const REFS_QUERY = graphql(`
   query CodePageRefs($repo: String) {
     repository(ref: $repo) {
       name
@@ -20,15 +19,7 @@ export const REFS_QUERY = gql`
       }
     }
   }
-`;
-
-export interface RefsQueryData {
-  repository: {
-    name: string;
-    head: { shortName: string } | null;
-    refs: { nodes: GitRef[] } | null;
-  } | null;
-}
+`);
 
 export const Route = createFileRoute("/$repo")({
   beforeLoad: ({ params: { repo }, context: { preloadQuery } }) => {
@@ -37,7 +28,7 @@ export const Route = createFileRoute("/$repo")({
 
     // Preload refs once for the entire repo — shared by code browser,
     // and used for the /$repo → tree redirect.
-    const refsRef = preloadQuery<RefsQueryData>(REFS_QUERY, {
+    const refsRef = preloadQuery(REFS_QUERY, {
       variables: { repo: ref },
     });
 

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

@@ -1,14 +1,13 @@
 // Blob (file) view: /$repo/blob/$ref/...path
 
-import { gql } from "@apollo/client";
 import { useReadQuery } from "@apollo/client/react";
 import { createFileRoute } from "@tanstack/react-router";
 
-import type { GitBlob } from "@/__generated__/graphql";
+import { graphql } from "@/__generated__/gql";
 import { FileViewer } from "@/components/code/file-viewer";
 import { Skeleton } from "@/components/ui/skeleton";
 
-const BLOB_QUERY = gql`
+const BLOB_QUERY = graphql(`
   query CodePageBlob($repo: String, $ref: String!, $path: String!) {
     repository(ref: $repo) {
       blob(ref: $ref, path: $path) {
@@ -21,11 +20,7 @@ const BLOB_QUERY = gql`
       }
     }
   }
-`;
-
-interface BlobQueryData {
-  repository: { blob: GitBlob | null } | null;
-}
+`);
 
 function BlobSkeleton() {
   return (
@@ -45,7 +40,7 @@ export const Route = createFileRoute("/$repo/_code/blob/$ref/$")({
   pendingComponent: BlobSkeleton,
   beforeLoad: () => ({ viewMode: "blob" as const }),
   loader: async ({ context: { preloadQuery, ref }, params: { ref: gitRef, _splat: path } }) => {
-    const blobRef = preloadQuery<BlobQueryData>(BLOB_QUERY, {
+    const blobRef = preloadQuery(BLOB_QUERY, {
       variables: { repo: ref, ref: gitRef, path: path || "" },
     });
     return { blobRef: await preloadQuery.toPromise(blobRef) };

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

@@ -1,21 +1,15 @@
 // Tree view: /$repo/tree/$ref/...path
 
-import { gql } from "@apollo/client";
 import { useQuery, useReadQuery } from "@apollo/client/react";
 import { createFileRoute } from "@tanstack/react-router";
 
-import {
-  GitObjectType,
-  type GitTreeEntry,
-  type GitLastCommit,
-  type GitBlob,
-} from "@/__generated__/graphql";
+import { GitObjectType } from "@/__generated__/graphql";
+import { graphql } from "@/__generated__/gql";
 import { FileTree } from "@/components/code/file-tree";
-import type { TreeEntryWithCommit } from "@/components/code/file-tree";
 import { Markdown } from "@/components/content/markdown";
 import { Skeleton } from "@/components/ui/skeleton";
 
-const TREE_QUERY = gql`
+const TREE_QUERY = graphql(`
   query CodePageTree($repo: String, $ref: String!, $path: String) {
     repository(ref: $repo) {
       tree(ref: $ref, path: $path) {
@@ -25,10 +19,15 @@ const TREE_QUERY = gql`
       }
     }
   }
-`;
+`);
 
-const LAST_COMMITS_QUERY = gql`
-  query CodePageLastCommits($repo: String, $ref: String!, $path: String, $names: [String!]!) {
+const LAST_COMMITS_QUERY = graphql(`
+  query CodePageLastCommits(
+    $repo: String
+    $ref: String!
+    $path: String
+    $names: [String!]!
+  ) {
     repository(ref: $repo) {
       lastCommits(ref: $ref, path: $path, names: $names) {
         name
@@ -41,9 +40,9 @@ const LAST_COMMITS_QUERY = gql`
       }
     }
   }
-`;
+`);
 
-const README_QUERY = gql`
+const README_QUERY = graphql(`
   query CodePageReadme($repo: String, $ref: String!, $path: String!) {
     repository(ref: $repo) {
       blob(ref: $ref, path: $path) {
@@ -51,17 +50,7 @@ const README_QUERY = gql`
       }
     }
   }
-`;
-
-interface TreeQueryData {
-  repository: { tree: GitTreeEntry[] | null } | null;
-}
-interface LastCommitsQueryData {
-  repository: { lastCommits: GitLastCommit[] | null } | null;
-}
-interface ReadmeQueryData {
-  repository: { blob: GitBlob | null } | null;
-}
+`);
 
 function TreeSkeleton() {
   return (
@@ -84,9 +73,12 @@ export const Route = createFileRoute("/$repo/_code/tree/$ref/$")({
   component: TreeView,
   pendingComponent: TreeSkeleton,
   beforeLoad: () => ({ viewMode: "tree" as const }),
-  loader: async ({ context: { preloadQuery, ref }, params: { ref: gitRef, _splat: path } }) => {
-    const treeRef = preloadQuery<TreeQueryData>(TREE_QUERY, {
-      variables: { repo: ref, ref: gitRef, path: path || null },
+  loader: async ({
+    context: { preloadQuery, ref },
+    params: { ref: gitRef, _splat: path },
+  }) => {
+    const treeRef = preloadQuery(TREE_QUERY, {
+      variables: { repo: ref, ref: gitRef, ...(path ? { path } : {}) },
     });
     return { treeRef: await preloadQuery.toPromise(treeRef) };
   },
@@ -97,32 +89,39 @@ function TreeView() {
   const { ref: repoRef } = Route.useRouteContext();
   const { treeRef } = Route.useLoaderData();
   const { data: treeData } = useReadQuery(treeRef);
-  const entries: GitTreeEntry[] = treeData?.repository?.tree ?? [];
+  const entries = treeData?.repository?.tree ?? [];
 
   // Last commits and readme are cascading queries — they depend on the tree result
   const entryNames = entries.map((e) => e.name);
-  const { data: lastCommitsData } = useQuery<LastCommitsQueryData>(LAST_COMMITS_QUERY, {
-    variables: { repo: repoRef, ref: currentRef, path: currentPath || null, names: entryNames },
+  const { data: lastCommitsData } = useQuery(LAST_COMMITS_QUERY, {
+    variables: {
+      repo: repoRef,
+      ref: currentRef,
+      path: currentPath || null,
+      names: entryNames,
+    },
     skip: entryNames.length === 0,
   });
-  const lastCommitsByName = new Map<string, GitLastCommit>(
+  const lastCommitsByName = new Map(
     (lastCommitsData?.repository?.lastCommits ?? []).map((lc) => [lc.name, lc]),
   );
-  const entriesWithCommits: TreeEntryWithCommit[] = entries.map((e) => ({
+  const entriesWithCommits = entries.map((e) => ({
     ...e,
     lastCommit: lastCommitsByName.get(e.name)?.commit ?? undefined,
   }));
 
   const readmeEntry = entries.find(
-    (e) => e.type === GitObjectType.Blob && /^readme(\.md|\.txt|\.rst)?$/i.test(e.name),
+    (e) =>
+      e.type === GitObjectType.Blob &&
+      /^readme(\.md|\.txt|\.rst)?$/i.test(e.name),
   );
   const readmePath = readmeEntry
     ? currentPath
       ? `${currentPath}/${readmeEntry.name}`
       : readmeEntry.name
     : null;
-  const { data: readmeBlobData } = useQuery<ReadmeQueryData>(README_QUERY, {
-    variables: { repo: repoRef, ref: currentRef, path: readmePath },
+  const { data: readmeBlobData } = useQuery(README_QUERY, {
+    variables: { repo: repoRef, ref: currentRef, path: readmePath || "" },
     skip: !readmePath,
   });
   const readme: string | null = readmeBlobData?.repository?.blob?.text ?? null;
@@ -137,7 +136,9 @@ function TreeView() {
       />
       {readme && (
         <div className="rounded-md border">
-          <div className="text-muted-foreground border-b px-4 py-2 text-xs font-medium">README</div>
+          <div className="text-muted-foreground border-b px-4 py-2 text-xs font-medium">
+            README
+          </div>
           <div className="px-6 py-4">
             <Markdown
               content={readme}

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

@@ -1,21 +1,51 @@
 import { createFileRoute } from "@tanstack/react-router";
 
-import {
-  type ValidLabelsQuery,
-  ValidLabelsDocument,
-  type AllIdentitiesQuery,
-  AllIdentitiesDocument,
-} from "@/__generated__/graphql";
+import { graphql } from "@/__generated__/gql";
+
+const ALL_IDENTITIES_QUERY = graphql(`
+  query AllIdentities($ref: String) {
+    repository(ref: $ref) {
+      allIdentities(first: 1000) {
+        nodes {
+          id
+          humanId
+          name
+          email
+          login
+          displayName
+          avatarUrl
+        }
+      }
+    }
+  }
+`);
+
+const VALID_LABELS_QUERY = graphql(`
+  query ValidLabels($ref: String) {
+    repository(ref: $ref) {
+      validLabels {
+        nodes {
+          name
+          color {
+            R
+            G
+            B
+          }
+        }
+      }
+    }
+  }
+`);
 
 // Pathless layout route for all issue-related pages under /$repo.
 // Preloads labels and identities shared by the issue list, detail,
 // new issue form, and user profile pages.
 export const Route = createFileRoute("/$repo/_issues")({
   beforeLoad: ({ context: { preloadQuery, ref } }) => {
-    const labelsRef = preloadQuery<ValidLabelsQuery>(ValidLabelsDocument, {
+    const labelsRef = preloadQuery(VALID_LABELS_QUERY, {
       variables: { ref },
     });
-    const identitiesRef = preloadQuery<AllIdentitiesQuery>(AllIdentitiesDocument, {
+    const identitiesRef = preloadQuery(ALL_IDENTITIES_QUERY, {
       variables: { ref },
     });
     return { labelsRef, identitiesRef };

webui2/src/routes/$repo/_issues/issues/$id.tsx 🔗

@@ -2,8 +2,45 @@ import { useReadQuery } from "@apollo/client/react";
 import { createFileRoute, Link } from "@tanstack/react-router";
 import { formatDistanceToNow } from "date-fns";
 
-import { type BugDetailQuery, BugDetailDocument } from "@/__generated__/graphql";
+import { graphql } from "@/__generated__/gql";
 import { CommentBox } from "@/components/bugs/comment-box";
+
+const BUG_DETAIL_QUERY = graphql(`
+  query BugDetail($ref: String, $prefix: String!) {
+    repository(ref: $ref) {
+      bug(prefix: $prefix) {
+        ...BugSummary
+        lastEdit
+        participants(first: 20) {
+          nodes {
+            ...IdentitySummary
+          }
+        }
+        timeline(first: 250) {
+          nodes {
+            __typename
+            id
+            ... on BugCreateTimelineItem {
+              ...BugCreateCommentFields
+            }
+            ... on BugAddCommentTimelineItem {
+              ...BugAddCommentFields
+            }
+            ... on BugLabelChangeTimelineItem {
+              ...LabelChangeFields
+            }
+            ... on BugSetStatusTimelineItem {
+              ...StatusChangeFields
+            }
+            ... on BugSetTitleTimelineItem {
+              ...TitleChangeFields
+            }
+          }
+        }
+      }
+    }
+  }
+`);
 import { LabelEditor } from "@/components/bugs/label-editor";
 import { StatusBadge } from "@/components/shared/status-badge";
 import { Timeline } from "@/components/bugs/timeline";
@@ -19,7 +56,7 @@ export const Route = createFileRoute("/$repo/_issues/issues/$id")({
   component: RouteComponent,
   pendingComponent: BugDetailSkeleton,
   loader: async ({ context: { preloadQuery, ref }, params: { id } }) => {
-    const bugDetailRef = preloadQuery<BugDetailQuery>(BugDetailDocument, {
+    const bugDetailRef = preloadQuery(BUG_DETAIL_QUERY, {
       variables: { ref, prefix: id },
     });
     return { bugDetailRef: await preloadQuery.toPromise(bugDetailRef) };

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

@@ -5,8 +5,38 @@ import { Search } from "lucide-react";
 import { useEffect, useMemo, useState } from "react";
 import * as v from "valibot";
 
-import { type BugListQuery, BugListDocument } from "@/__generated__/graphql";
+import { graphql } from "@/__generated__/gql";
 import { IssueFilters } from "@/components/shared/issue-filters";
+
+const BUG_LIST_QUERY = graphql(`
+  query BugList(
+    $ref: String
+    $openQuery: String!
+    $closedQuery: String!
+    $listQuery: String!
+    $first: Int
+    $after: String
+  ) {
+    repository(ref: $ref) {
+      openCount: allBugs(query: $openQuery, first: 1) {
+        totalCount
+      }
+      closedCount: allBugs(query: $closedQuery, first: 1) {
+        totalCount
+      }
+      bugs: allBugs(query: $listQuery, first: $first, after: $after) {
+        totalCount
+        pageInfo {
+          hasNextPage
+          endCursor
+        }
+        nodes {
+          ...BugSummary
+        }
+      }
+    }
+  }
+`);
 import * as IssueRow from "@/components/shared/issue-row";
 import * as StatusTabs from "@/components/shared/status-tabs";
 import { LabelBadgeLink } from "@/components/shared/label-badge";
@@ -32,7 +62,7 @@ export const Route = createFileRoute("/$repo/_issues/issues/")({
   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, {
+    const bugListRef = preloadQuery(BUG_LIST_QUERY, {
       variables: {
         ref,
         openQuery: `status:open ${baseQuery}`.trim(),

webui2/src/routes/$repo/_issues/issues/new.tsx 🔗

@@ -1,7 +1,8 @@
+import { useMutation } from "@apollo/client/react";
 import { createFileRoute, useNavigate } from "@tanstack/react-router";
 import { useState } from "react";
 
-import { useBugCreateMutation } from "@/__generated__/graphql";
+import { graphql } from "@/__generated__/gql";
 import { Markdown } from "@/components/content/markdown";
 import { BackLink } from "@/components/ui/back-link";
 import { Button } from "@/components/ui/button";
@@ -10,6 +11,17 @@ import { Input } from "@/components/ui/input";
 import { Textarea } from "@/components/ui/textarea";
 import * as WritePreview from "@/components/shared/write-preview";
 
+const BUG_CREATE_MUTATION = graphql(`
+  mutation BugCreate($input: BugCreateInput!) {
+    bugCreate(input: $input) {
+      bug {
+        id
+        humanId
+      }
+    }
+  }
+`);
+
 export const Route = createFileRoute("/$repo/_issues/issues/new")({
   component: RouteComponent,
 });
@@ -20,7 +32,7 @@ function RouteComponent() {
   const { repo } = Route.useParams();
   const [title, setTitle] = useState("");
   const [message, setMessage] = useState("");
-  const [createBug, { loading, error }] = useBugCreateMutation();
+  const [createBug, { loading, error }] = useMutation(BUG_CREATE_MUTATION);
 
   async function handleSubmit(e: React.FormEvent) {
     e.preventDefault();

webui2/src/routes/$repo/_issues/user/$id.tsx 🔗

@@ -9,8 +9,48 @@ import { formatDistanceToNow } from "date-fns";
 import { CircleDot, CircleCheck, ShieldCheck } from "lucide-react";
 import * as v from "valibot";
 
-import { type UserProfileQuery, UserProfileDocument } from "@/__generated__/graphql";
+import { graphql } from "@/__generated__/gql";
 import * as IssueRow from "@/components/shared/issue-row";
+
+const USER_PROFILE_QUERY = graphql(`
+  query UserProfile(
+    $ref: String
+    $prefix: String!
+    $openQuery: String!
+    $closedQuery: String!
+    $listQuery: String!
+    $after: String
+  ) {
+    repository(ref: $ref) {
+      identity(prefix: $prefix) {
+        id
+        humanId
+        name
+        email
+        login
+        displayName
+        avatarUrl
+        isProtected
+      }
+      openCount: allBugs(query: $openQuery, first: 1) {
+        totalCount
+      }
+      closedCount: allBugs(query: $closedQuery, first: 1) {
+        totalCount
+      }
+      bugs: allBugs(query: $listQuery, first: 25, after: $after) {
+        totalCount
+        pageInfo {
+          hasNextPage
+          endCursor
+        }
+        nodes {
+          ...BugSummary
+        }
+      }
+    }
+  }
+`);
 import { LabelBadge } from "@/components/shared/label-badge";
 import { EmptyState } from "@/components/shared/empty-state";
 import * as Pagination from "@/components/shared/pagination";
@@ -32,7 +72,7 @@ export const Route = createFileRoute("/$repo/_issues/user/$id")({
   validateSearch: (search) => v.parse(profileSearchSchema, search),
   loaderDeps: ({ search: { status, after } }) => ({ status, after }),
   loader: async ({ context: { preloadQuery, ref }, params: { id }, deps: { status, after } }) => {
-    const profileRef = preloadQuery<UserProfileQuery>(UserProfileDocument, {
+    const profileRef = preloadQuery(USER_PROFILE_QUERY, {
       variables: {
         ref,
         prefix: id,

webui2/src/routes/$repo/commit/$hash.tsx 🔗

@@ -1,17 +1,17 @@
 // Commit detail page (/:repo/commit/:hash). Shows commit metadata, full
 // message, parent links, and changed files with lazy diffs.
 
-import { gql } from "@apollo/client";
 import { useReadQuery } from "@apollo/client/react";
 import { createFileRoute, Link } from "@tanstack/react-router";
 import { format } from "date-fns";
 import { GitCommit } from "lucide-react";
 
+import { graphql } from "@/__generated__/gql";
 import { FileDiffView } from "@/components/code/file-diff-view";
 import { BackLink } from "@/components/ui/back-link";
 import { Skeleton } from "@/components/ui/skeleton";
 
-const COMMIT_QUERY = gql`
+const COMMIT_QUERY = graphql(`
   query CommitPageDetail($repo: String, $hash: String!) {
     repository(ref: $repo) {
       commit(hash: $hash) {
@@ -33,31 +33,13 @@ const COMMIT_QUERY = gql`
       }
     }
   }
-`;
-
-interface CommitQueryData {
-  repository: {
-    commit: {
-      hash: string;
-      shortHash: string;
-      message: string;
-      fullMessage: string;
-      authorName: string;
-      authorEmail: string | null;
-      date: string;
-      parents: string[];
-      files: {
-        nodes: { path: string; oldPath: string | null; status: string }[];
-      } | null;
-    } | null;
-  } | null;
-}
+`);
 
 export const Route = createFileRoute("/$repo/commit/$hash")({
   component: RouteComponent,
   pendingComponent: CommitPageSkeleton,
   loader: async ({ context: { preloadQuery, ref }, params: { hash } }) => {
-    const commitRef = preloadQuery<CommitQueryData>(COMMIT_QUERY, {
+    const commitRef = preloadQuery(COMMIT_QUERY, {
       variables: { repo: ref, hash },
     });
     return { commitRef: await preloadQuery.toPromise(commitRef) };

webui2/src/routes/index.tsx 🔗

@@ -6,12 +6,23 @@ import { createFileRoute, Link, useNavigate } from "@tanstack/react-router";
 import { GitFork, FolderOpen, AlertCircle } from "lucide-react";
 import { useEffect } from "react";
 
-import { type RepositoriesQuery, RepositoriesDocument } from "@/__generated__/graphql";
+import { graphql } from "@/__generated__/gql";
+
+const REPOSITORIES_QUERY = graphql(`
+  query Repositories {
+    repositories {
+      nodes {
+        name
+      }
+      totalCount
+    }
+  }
+`);
 
 export const Route = createFileRoute("/")({
   component: RouteComponent,
   loader: async ({ context: { preloadQuery } }) => {
-    const repositoriesRef = preloadQuery<RepositoriesQuery>(RepositoriesDocument);
+    const repositoriesRef = preloadQuery(REPOSITORIES_QUERY);
     return { repositoriesRef: await preloadQuery.toPromise(repositoriesRef) };
   },
 });