From b567e4096592d04c0713014509a895a24650a4a8 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Fri, 14 Jul 2023 17:17:25 +1000 Subject: [PATCH] Do "typecasting" the way graphql-codegen intends --- codegen.ts | 3 +++ src/gql/fragment-masking.ts | 10 ++++---- src/gql/gql.ts | 14 +++++++++-- src/gql/graphql.ts | 31 ++++++++++++++++++++++++- src/screens/VisualTests/VisualTests.tsx | 12 ++++++---- 5 files changed, 58 insertions(+), 12 deletions(-) diff --git a/codegen.ts b/codegen.ts index 3c257657..77bdf861 100644 --- a/codegen.ts +++ b/codegen.ts @@ -8,6 +8,9 @@ const config: CodegenConfig = { "./src/gql/": { preset: "client", plugins: [], + presetConfig: { + fragmentMasking: { unmaskFunctionName: "getFragment" }, + }, }, }, }; diff --git a/src/gql/fragment-masking.ts b/src/gql/fragment-masking.ts index 2ba06f10..da3a13ab 100644 --- a/src/gql/fragment-masking.ts +++ b/src/gql/fragment-masking.ts @@ -15,26 +15,26 @@ export type FragmentType> : never; // return non-nullable if `fragmentType` is non-nullable -export function useFragment( +export function getFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> ): TType; // return nullable if `fragmentType` is nullable -export function useFragment( +export function getFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | null | undefined ): TType | null | undefined; // return array of non-nullable if `fragmentType` is array of non-nullable -export function useFragment( +export function getFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> ): ReadonlyArray; // return array of nullable if `fragmentType` is array of nullable -export function useFragment( +export function getFragment( _documentNode: DocumentTypeDecoration, fragmentType: ReadonlyArray>> | null | undefined ): ReadonlyArray | null | undefined; -export function useFragment( +export function getFragment( _documentNode: DocumentTypeDecoration, fragmentType: FragmentType> | ReadonlyArray>> | null | undefined ): TType | ReadonlyArray | null | undefined { diff --git a/src/gql/gql.ts b/src/gql/gql.ts index dc114a67..dadf3944 100644 --- a/src/gql/gql.ts +++ b/src/gql/gql.ts @@ -14,7 +14,9 @@ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/ */ const documents = { "\n query ProjectQuery($projectId: ID!) {\n project(id: $projectId) {\n id\n name\n webUrl\n lastBuild {\n branch\n number\n }\n }\n }\n": types.ProjectQueryDocument, - "\n query Build($hasBuildId: Boolean!, $buildId: ID!, $projectId: ID!, $branch: String!) {\n build(id: $buildId) @include(if: $hasBuildId) {\n ...BuildFields\n }\n project(id: $projectId) @skip(if: $hasBuildId) {\n lastBuild(branches: [$branch]) {\n ...BuildFields\n }\n }\n }\n fragment BuildFields on Build {\n __typename\n id\n number\n branch\n commit\n status\n browsers {\n id\n key\n name\n }\n ... on StartedBuild {\n changeCount: testCount(results: [ADDED, CHANGED, FIXED])\n startedAt\n tests {\n nodes {\n ...TestFields\n }\n }\n }\n ... on CompletedBuild {\n result\n changeCount: testCount(results: [ADDED, CHANGED, FIXED])\n startedAt\n tests {\n nodes {\n ...TestFields\n }\n }\n }\n }\n fragment TestFields on Test {\n id\n status\n result\n webUrl\n comparisons {\n id\n result\n browser {\n id\n key\n name\n version\n }\n captureDiff {\n diffImage {\n imageUrl\n }\n }\n headCapture {\n captureImage {\n imageUrl\n }\n }\n viewport {\n id\n name\n width\n isDefault\n }\n }\n parameters {\n viewport {\n id\n name\n width\n isDefault\n }\n }\n story {\n storyId\n }\n }\n": types.BuildDocument, + "\n query Build($hasBuildId: Boolean!, $buildId: ID!, $projectId: ID!, $branch: String!) {\n build(id: $buildId) @include(if: $hasBuildId) {\n ...BuildFields\n }\n project(id: $projectId) @skip(if: $hasBuildId) {\n lastBuild(branches: [$branch]) {\n ...BuildFields\n }\n }\n }\n": types.BuildDocument, + "\n fragment BuildFields on Build {\n __typename\n id\n number\n branch\n commit\n status\n browsers {\n id\n key\n name\n }\n ... on StartedBuild {\n changeCount: testCount(results: [ADDED, CHANGED, FIXED])\n startedAt\n tests {\n nodes {\n ...TestFields\n }\n }\n }\n ... on CompletedBuild {\n result\n changeCount: testCount(results: [ADDED, CHANGED, FIXED])\n startedAt\n tests {\n nodes {\n ...TestFields\n }\n }\n }\n }\n": types.BuildFieldsFragmentDoc, + "\n fragment TestFields on Test {\n id\n status\n result\n webUrl\n comparisons {\n id\n result\n browser {\n id\n key\n name\n version\n }\n captureDiff {\n diffImage {\n imageUrl\n }\n }\n headCapture {\n captureImage {\n imageUrl\n }\n }\n viewport {\n id\n name\n width\n isDefault\n }\n }\n parameters {\n viewport {\n id\n name\n width\n isDefault\n }\n }\n story {\n storyId\n }\n }\n": types.TestFieldsFragmentDoc, }; /** @@ -38,7 +40,15 @@ export function graphql(source: "\n query ProjectQuery($projectId: ID!) {\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 Build($hasBuildId: Boolean!, $buildId: ID!, $projectId: ID!, $branch: String!) {\n build(id: $buildId) @include(if: $hasBuildId) {\n ...BuildFields\n }\n project(id: $projectId) @skip(if: $hasBuildId) {\n lastBuild(branches: [$branch]) {\n ...BuildFields\n }\n }\n }\n fragment BuildFields on Build {\n __typename\n id\n number\n branch\n commit\n status\n browsers {\n id\n key\n name\n }\n ... on StartedBuild {\n changeCount: testCount(results: [ADDED, CHANGED, FIXED])\n startedAt\n tests {\n nodes {\n ...TestFields\n }\n }\n }\n ... on CompletedBuild {\n result\n changeCount: testCount(results: [ADDED, CHANGED, FIXED])\n startedAt\n tests {\n nodes {\n ...TestFields\n }\n }\n }\n }\n fragment TestFields on Test {\n id\n status\n result\n webUrl\n comparisons {\n id\n result\n browser {\n id\n key\n name\n version\n }\n captureDiff {\n diffImage {\n imageUrl\n }\n }\n headCapture {\n captureImage {\n imageUrl\n }\n }\n viewport {\n id\n name\n width\n isDefault\n }\n }\n parameters {\n viewport {\n id\n name\n width\n isDefault\n }\n }\n story {\n storyId\n }\n }\n"): (typeof documents)["\n query Build($hasBuildId: Boolean!, $buildId: ID!, $projectId: ID!, $branch: String!) {\n build(id: $buildId) @include(if: $hasBuildId) {\n ...BuildFields\n }\n project(id: $projectId) @skip(if: $hasBuildId) {\n lastBuild(branches: [$branch]) {\n ...BuildFields\n }\n }\n }\n fragment BuildFields on Build {\n __typename\n id\n number\n branch\n commit\n status\n browsers {\n id\n key\n name\n }\n ... on StartedBuild {\n changeCount: testCount(results: [ADDED, CHANGED, FIXED])\n startedAt\n tests {\n nodes {\n ...TestFields\n }\n }\n }\n ... on CompletedBuild {\n result\n changeCount: testCount(results: [ADDED, CHANGED, FIXED])\n startedAt\n tests {\n nodes {\n ...TestFields\n }\n }\n }\n }\n fragment TestFields on Test {\n id\n status\n result\n webUrl\n comparisons {\n id\n result\n browser {\n id\n key\n name\n version\n }\n captureDiff {\n diffImage {\n imageUrl\n }\n }\n headCapture {\n captureImage {\n imageUrl\n }\n }\n viewport {\n id\n name\n width\n isDefault\n }\n }\n parameters {\n viewport {\n id\n name\n width\n isDefault\n }\n }\n story {\n storyId\n }\n }\n"]; +export function graphql(source: "\n query Build($hasBuildId: Boolean!, $buildId: ID!, $projectId: ID!, $branch: String!) {\n build(id: $buildId) @include(if: $hasBuildId) {\n ...BuildFields\n }\n project(id: $projectId) @skip(if: $hasBuildId) {\n lastBuild(branches: [$branch]) {\n ...BuildFields\n }\n }\n }\n"): (typeof documents)["\n query Build($hasBuildId: Boolean!, $buildId: ID!, $projectId: ID!, $branch: String!) {\n build(id: $buildId) @include(if: $hasBuildId) {\n ...BuildFields\n }\n project(id: $projectId) @skip(if: $hasBuildId) {\n lastBuild(branches: [$branch]) {\n ...BuildFields\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 BuildFields on Build {\n __typename\n id\n number\n branch\n commit\n status\n browsers {\n id\n key\n name\n }\n ... on StartedBuild {\n changeCount: testCount(results: [ADDED, CHANGED, FIXED])\n startedAt\n tests {\n nodes {\n ...TestFields\n }\n }\n }\n ... on CompletedBuild {\n result\n changeCount: testCount(results: [ADDED, CHANGED, FIXED])\n startedAt\n tests {\n nodes {\n ...TestFields\n }\n }\n }\n }\n"): (typeof documents)["\n fragment BuildFields on Build {\n __typename\n id\n number\n branch\n commit\n status\n browsers {\n id\n key\n name\n }\n ... on StartedBuild {\n changeCount: testCount(results: [ADDED, CHANGED, FIXED])\n startedAt\n tests {\n nodes {\n ...TestFields\n }\n }\n }\n ... on CompletedBuild {\n result\n changeCount: testCount(results: [ADDED, CHANGED, FIXED])\n startedAt\n tests {\n nodes {\n ...TestFields\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 TestFields on Test {\n id\n status\n result\n webUrl\n comparisons {\n id\n result\n browser {\n id\n key\n name\n version\n }\n captureDiff {\n diffImage {\n imageUrl\n }\n }\n headCapture {\n captureImage {\n imageUrl\n }\n }\n viewport {\n id\n name\n width\n isDefault\n }\n }\n parameters {\n viewport {\n id\n name\n width\n isDefault\n }\n }\n story {\n storyId\n }\n }\n"): (typeof documents)["\n fragment TestFields on Test {\n id\n status\n result\n webUrl\n comparisons {\n id\n result\n browser {\n id\n key\n name\n version\n }\n captureDiff {\n diffImage {\n imageUrl\n }\n }\n headCapture {\n captureImage {\n imageUrl\n }\n }\n viewport {\n id\n name\n width\n isDefault\n }\n }\n parameters {\n viewport {\n id\n name\n width\n isDefault\n }\n }\n story {\n storyId\n }\n }\n"]; export function graphql(source: string) { return (documents as any)[source] ?? {}; diff --git a/src/gql/graphql.ts b/src/gql/graphql.ts index cc2a93f7..cdc78706 100644 --- a/src/gql/graphql.ts +++ b/src/gql/graphql.ts @@ -24,6 +24,25 @@ export type Scalars = { URL: { input: any; output: any; } }; +export type Account = Node & Temporal & { + __typename?: 'Account'; + avatarUrl?: Maybe; + /** When the entity was first created in Chromatic. */ + createdAt: Scalars['DateTime']['output']; + /** GraphQL node identifier */ + id: Scalars['ID']['output']; + /** Account name, typically the repository owner. */ + name: Scalars['String']['output']; + projects?: Maybe>>; + /** When the entity was last updated or created in Chromatic. */ + updatedAt: Scalars['DateTime']['output']; +}; + + +export type AccountProjectsArgs = { + limit?: InputMaybe; +}; + /** A build that has been pre-announced but not published yet. */ export type AnnouncedBuild = Build & Node & Temporal & { __typename?: 'AnnouncedBuild'; @@ -695,6 +714,8 @@ export type Project = Node & Temporal & { lastBuild?: Maybe; /** Project name, typically the repository name. */ name: Scalars['String']['output']; + /** Project token to start builds with Chromatic CLI. */ + projectToken: Scalars['String']['output']; /** Account information which does not require the `account` scope. */ publicAccountInfo: PublicAccountInfo; /** When the entity was last updated or created in Chromatic. */ @@ -763,12 +784,19 @@ export type PublishedBuild = Build & Node & Temporal & { export type Query = { __typename?: 'Query'; + account?: Maybe; build?: Maybe; bulkFigmaMetadata?: Maybe>>; figmaMetadata?: Maybe; figmaMetadataById?: Maybe; project?: Maybe; storybook?: Maybe; + viewer?: Maybe; +}; + + +export type QueryAccountArgs = { + id: Scalars['ID']['input']; }; @@ -1102,8 +1130,9 @@ export enum TestStatus { Pending = 'PENDING' } -export type User = Node & Temporal & { +export type User = Node & { __typename?: 'User'; + accounts: Array; avatarUrl?: Maybe; /** When the entity was first created in Chromatic. */ createdAt: Scalars['DateTime']['output']; diff --git a/src/screens/VisualTests/VisualTests.tsx b/src/screens/VisualTests/VisualTests.tsx index 47aa0b3f..149ac4b7 100644 --- a/src/screens/VisualTests/VisualTests.tsx +++ b/src/screens/VisualTests/VisualTests.tsx @@ -6,9 +6,8 @@ import { useQuery } from "urql"; import { IconButton } from "../../components/IconButton"; import { Bar, Col, Row, Section, Sections, Text } from "../../components/layout"; import { TooltipMenu } from "../../components/TooltipMenu"; -import { graphql } from "../../gql"; +import { getFragment, graphql } from "../../gql"; import { - BuildFieldsFragment, BuildQuery, BuildQueryVariables, TestFieldsFragment, @@ -34,6 +33,9 @@ const QueryBuild = graphql(/* GraphQL */ ` } } } +`); + +const FragmentBuildFields = graphql(/* GraphQL */ ` fragment BuildFields on Build { __typename id @@ -66,6 +68,8 @@ const QueryBuild = graphql(/* GraphQL */ ` } } } +`); +const FragmentTestFields = graphql(/* GraphQL */ ` fragment TestFields on Test { id status @@ -149,7 +153,7 @@ export const VisualTests = ({ } }, [isRunning, setIsOutdated, setIsRunning, data]); - const build = (data?.build || data?.project.lastBuild) as BuildFieldsFragment; + const build = getFragment(FragmentBuildFields, data?.build || data?.project.lastBuild); useEffect(() => { let interval: any; @@ -206,7 +210,7 @@ export const VisualTests = ({ ); } - const allTests = ("tests" in build ? build.tests.nodes : []) as TestFieldsFragment[]; + const allTests = getFragment(FragmentTestFields, "tests" in build ? build.tests.nodes : []); const tests = allTests.filter((test) => test.story?.storyId === storyId); const { changeCount, brokenCount, resultsByBrowser, resultsByViewport, viewportInfoById } =