From 8128f2ab9972c183e6b7c820a08b245fadeeef96 Mon Sep 17 00:00:00 2001 From: DarynaAkhmedova <132382266+DarynaAkhmedova@users.noreply.github.com> Date: Sun, 22 Sep 2024 20:10:10 +0000 Subject: [PATCH 1/7] useMutation and useMutation_depricated --- packages/examples/src/Feedback/Feedback.tsx | 4 ++-- packages/nova-react/package.json | 1 + packages/nova-react/src/graphql/hooks.ts | 22 +++++++++++++++---- packages/nova-types/package.json | 4 ++++ .../nova-types/src/nova-graphql.interface.ts | 14 ++++++++++++ 5 files changed, 39 insertions(+), 6 deletions(-) diff --git a/packages/examples/src/Feedback/Feedback.tsx b/packages/examples/src/Feedback/Feedback.tsx index bfd244dd..fce10e2e 100644 --- a/packages/examples/src/Feedback/Feedback.tsx +++ b/packages/examples/src/Feedback/Feedback.tsx @@ -1,4 +1,4 @@ -import { graphql, useFragment, useMutation } from "@nova/react"; +import { graphql, useFragment, useMutation_depricated } from "@nova/react"; import * as React from "react"; import type { FeedbackComponent_LikeMutation } from "./__generated__/FeedbackComponent_LikeMutation.graphql"; import type { Feedback_feedbackFragment$key } from "./__generated__/Feedback_feedbackFragment.graphql"; @@ -20,7 +20,7 @@ export const Feedback_feedbackFragment = graphql` export const FeedbackComponent = (props: Props) => { const [errorMessage, setErrorMessage] = React.useState(null); const feedback = useFragment(Feedback_feedbackFragment, props.feedback); - const [like, isPending] = useMutation( + const [like, isPending] = useMutation_depricated( graphql` mutation FeedbackComponent_LikeMutation($input: FeedbackLikeInput!) { feedbackLike(input: $input) { diff --git a/packages/nova-react/package.json b/packages/nova-react/package.json index 861113ad..68cc4a37 100644 --- a/packages/nova-react/package.json +++ b/packages/nova-react/package.json @@ -12,6 +12,7 @@ }, "peerDependencies": { "react": "^17.0.2 || ^18", + "relay-runtime": "12.0.0", "@types/react": "^17.0.2 || ^18", "@graphitation/graphql-js-tag": "^0.9.0" }, diff --git a/packages/nova-react/src/graphql/hooks.ts b/packages/nova-react/src/graphql/hooks.ts index dc1cee90..55332f34 100644 --- a/packages/nova-react/src/graphql/hooks.ts +++ b/packages/nova-react/src/graphql/hooks.ts @@ -10,6 +10,7 @@ import type { RefetchFn, FetchPolicy } from "./types"; +import type { Disposable } from 'relay-runtime'; /** * Executes a GraphQL query. @@ -332,14 +333,12 @@ interface MutationCommitterOptions { context?: TMutationPayload["context"]; optimisticResponse?: Partial | null; onCompleted?: (response: TMutationPayload["response"]) => void; + onError?: (error: Error) => void; } type MutationCommitter = ( options: MutationCommitterOptions, -) => Promise<{ - errors?: readonly Error[]; - data?: TMutationPayload["response"]; -}>; +) => Disposable; export function useMutation( mutation: GraphQLTaggedNode, @@ -348,3 +347,18 @@ export function useMutation( invariant(graphql.useMutation, "Expected host to provide a useMutation hook"); return graphql.useMutation(mutation); } + +type MutationCommitter_depricated = ( + options: MutationCommitterOptions, +) => Promise<{ + errors?: readonly Error[]; + data?: TMutationPayload["response"]; +}>; + +export function useMutation_depricated( + mutation: GraphQLTaggedNode, +): [MutationCommitter_depricated, boolean] { + const graphql = useNovaGraphQL(); + invariant(graphql.useMutation_depricated, "Expected host to provide a useMutation hook"); + return graphql.useMutation_depricated(mutation); +} diff --git a/packages/nova-types/package.json b/packages/nova-types/package.json index 512d2a45..fed4a22a 100644 --- a/packages/nova-types/package.json +++ b/packages/nova-types/package.json @@ -9,8 +9,12 @@ "types": "monorepo-scripts types", "just": "monorepo-scripts" }, + "dependencies": { + "relay-runtime": "12.0.0" + }, "devDependencies": { "@types/jest": "^29.2.0", + "@types/relay-runtime": "^17.0.4", "monorepo-scripts": "*" }, "repository": { diff --git a/packages/nova-types/src/nova-graphql.interface.ts b/packages/nova-types/src/nova-graphql.interface.ts index 900376c9..e2375851 100644 --- a/packages/nova-types/src/nova-graphql.interface.ts +++ b/packages/nova-types/src/nova-graphql.interface.ts @@ -9,6 +9,7 @@ * In case the host application uses Apollo Client, these hooks can be provided by using the * `@graphitation/apollo-react-relay-duct-tape` package. See https://github.com/microsoft/graphitation for details. */ +import type { Disposable } from 'relay-runtime'; export interface NovaGraphQL { useFragment?: ( @@ -66,6 +67,19 @@ export interface NovaGraphQL { useMutation?: ( mutation: GraphQLDocument, + ) => [ + (options: { + variables: { [name: string]: unknown }; + context?: { [name: string]: unknown }; + optimisticResponse?: unknown | null; + onCompleted?: (response: unknown) => void; + onError?: (error: Error) => void; + }) => Disposable, + boolean, + ]; + + useMutation_depricated?: ( + mutation: GraphQLDocument, ) => [ (options: { variables: { [name: string]: unknown }; From 8e6b7d779bc83858d8bb2adeb4c95da527d25ebb Mon Sep 17 00:00:00 2001 From: DarynaAkhmedova <132382266+DarynaAkhmedova@users.noreply.github.com> Date: Tue, 24 Sep 2024 09:19:28 +0000 Subject: [PATCH 2/7] Fix spelling --- packages/examples/src/Feedback/Feedback.tsx | 4 ++-- packages/nova-react/src/graphql/hooks.ts | 10 +++++----- packages/nova-types/src/nova-graphql.interface.ts | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/examples/src/Feedback/Feedback.tsx b/packages/examples/src/Feedback/Feedback.tsx index fce10e2e..0e85e2bd 100644 --- a/packages/examples/src/Feedback/Feedback.tsx +++ b/packages/examples/src/Feedback/Feedback.tsx @@ -1,4 +1,4 @@ -import { graphql, useFragment, useMutation_depricated } from "@nova/react"; +import { graphql, useFragment, useMutation_deprecated } from "@nova/react"; import * as React from "react"; import type { FeedbackComponent_LikeMutation } from "./__generated__/FeedbackComponent_LikeMutation.graphql"; import type { Feedback_feedbackFragment$key } from "./__generated__/Feedback_feedbackFragment.graphql"; @@ -20,7 +20,7 @@ export const Feedback_feedbackFragment = graphql` export const FeedbackComponent = (props: Props) => { const [errorMessage, setErrorMessage] = React.useState(null); const feedback = useFragment(Feedback_feedbackFragment, props.feedback); - const [like, isPending] = useMutation_depricated( + const [like, isPending] = useMutation_deprecated( graphql` mutation FeedbackComponent_LikeMutation($input: FeedbackLikeInput!) { feedbackLike(input: $input) { diff --git a/packages/nova-react/src/graphql/hooks.ts b/packages/nova-react/src/graphql/hooks.ts index 55332f34..14790a98 100644 --- a/packages/nova-react/src/graphql/hooks.ts +++ b/packages/nova-react/src/graphql/hooks.ts @@ -348,17 +348,17 @@ export function useMutation( return graphql.useMutation(mutation); } -type MutationCommitter_depricated = ( +type MutationCommitter_deprecated = ( options: MutationCommitterOptions, ) => Promise<{ errors?: readonly Error[]; data?: TMutationPayload["response"]; }>; -export function useMutation_depricated( +export function useMutation_deprecated( mutation: GraphQLTaggedNode, -): [MutationCommitter_depricated, boolean] { +): [MutationCommitter_deprecated, boolean] { const graphql = useNovaGraphQL(); - invariant(graphql.useMutation_depricated, "Expected host to provide a useMutation hook"); - return graphql.useMutation_depricated(mutation); + invariant(graphql.useMutation_deprecated, "Expected host to provide a useMutation hook"); + return graphql.useMutation_deprecated(mutation); } diff --git a/packages/nova-types/src/nova-graphql.interface.ts b/packages/nova-types/src/nova-graphql.interface.ts index e2375851..57026530 100644 --- a/packages/nova-types/src/nova-graphql.interface.ts +++ b/packages/nova-types/src/nova-graphql.interface.ts @@ -78,7 +78,7 @@ export interface NovaGraphQL { boolean, ]; - useMutation_depricated?: ( + useMutation_deprecated?: ( mutation: GraphQLDocument, ) => [ (options: { From 12cdd58b0d66a28ba71bdc430a9ff151e5393ea0 Mon Sep 17 00:00:00 2001 From: DarynaAkhmedova <132382266+DarynaAkhmedova@users.noreply.github.com> Date: Tue, 24 Sep 2024 09:26:57 +0000 Subject: [PATCH 3/7] Change files --- ...nova-examples-4a9eba03-93cc-41c9-92fd-316b80aa0767.json | 7 +++++++ .../@nova-react-c9299b3a-611a-4555-ad5a-a1c2cf647f6f.json | 7 +++++++ ...ct-test-utils-c16efa64-6fae-4431-8824-1491ad927285.json | 7 +++++++ .../@nova-types-f14269f8-868b-49cf-9c08-777b5e415c9c.json | 7 +++++++ 4 files changed, 28 insertions(+) create mode 100644 change/@nova-examples-4a9eba03-93cc-41c9-92fd-316b80aa0767.json create mode 100644 change/@nova-react-c9299b3a-611a-4555-ad5a-a1c2cf647f6f.json create mode 100644 change/@nova-react-test-utils-c16efa64-6fae-4431-8824-1491ad927285.json create mode 100644 change/@nova-types-f14269f8-868b-49cf-9c08-777b5e415c9c.json diff --git a/change/@nova-examples-4a9eba03-93cc-41c9-92fd-316b80aa0767.json b/change/@nova-examples-4a9eba03-93cc-41c9-92fd-316b80aa0767.json new file mode 100644 index 00000000..1f38918b --- /dev/null +++ b/change/@nova-examples-4a9eba03-93cc-41c9-92fd-316b80aa0767.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Use useMutation_deprecated in FeedbackComponent", + "packageName": "@nova/examples", + "email": "132382266+DarynaAkhmedova@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/change/@nova-react-c9299b3a-611a-4555-ad5a-a1c2cf647f6f.json b/change/@nova-react-c9299b3a-611a-4555-ad5a-a1c2cf647f6f.json new file mode 100644 index 00000000..3552a700 --- /dev/null +++ b/change/@nova-react-c9299b3a-611a-4555-ad5a-a1c2cf647f6f.json @@ -0,0 +1,7 @@ +{ + "type": "major", + "comment": "Align useMutation with Relay", + "packageName": "@nova/react", + "email": "132382266+DarynaAkhmedova@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/change/@nova-react-test-utils-c16efa64-6fae-4431-8824-1491ad927285.json b/change/@nova-react-test-utils-c16efa64-6fae-4431-8824-1491ad927285.json new file mode 100644 index 00000000..bb99ef77 --- /dev/null +++ b/change/@nova-react-test-utils-c16efa64-6fae-4431-8824-1491ad927285.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Update @graphitation/apollo-react-relay-duct-tape", + "packageName": "@nova/react-test-utils", + "email": "132382266+DarynaAkhmedova@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/change/@nova-types-f14269f8-868b-49cf-9c08-777b5e415c9c.json b/change/@nova-types-f14269f8-868b-49cf-9c08-777b5e415c9c.json new file mode 100644 index 00000000..937932b9 --- /dev/null +++ b/change/@nova-types-f14269f8-868b-49cf-9c08-777b5e415c9c.json @@ -0,0 +1,7 @@ +{ + "type": "major", + "comment": "Align useMutation with Relay", + "packageName": "@nova/types", + "email": "132382266+DarynaAkhmedova@users.noreply.github.com", + "dependentChangeType": "patch" +} From acb795c7fc42ae44a769fd2b31dd9a040ca88a7c Mon Sep 17 00:00:00 2001 From: DarynaAkhmedova <132382266+DarynaAkhmedova@users.noreply.github.com> Date: Thu, 26 Sep 2024 11:43:05 +0000 Subject: [PATCH 4/7] PR suggestions. Removed relay-runtime dependency. Updated test utils --- .../src/storybook-nova-decorator.tsx | 6 +++- .../nova-react-test-utils/src/test-utils.tsx | 6 +++- packages/nova-react/package.json | 1 - packages/nova-react/src/graphql/hooks.ts | 4 +-- packages/nova-react/src/graphql/types.ts | 2 +- packages/nova-types/package.json | 4 --- .../nova-types/src/nova-graphql.interface.ts | 8 +++-- yarn.lock | 31 +++++++++++++++++-- 8 files changed, 46 insertions(+), 16 deletions(-) diff --git a/packages/nova-react-test-utils/src/storybook-nova-decorator.tsx b/packages/nova-react-test-utils/src/storybook-nova-decorator.tsx index 2f2f7366..e0f7367b 100644 --- a/packages/nova-react-test-utils/src/storybook-nova-decorator.tsx +++ b/packages/nova-react-test-utils/src/storybook-nova-decorator.tsx @@ -122,7 +122,11 @@ function createNovaEnvironment( const client = createMockClient(schema, options); const env: NovaMockEnvironment<"storybook"> = { graphql: { - ...(GraphQLHooks as NovaGraphQL), + ...(GraphQLHooks as unknown as NovaGraphQL), + useMutation_deprecated: GraphQLHooks.useMutation, + useMutation() { + throw new Error("Not supported yet in Apollo"); + }, mock: client.mock as MockFunctions, }, providerWrapper: ({ children }) => ( diff --git a/packages/nova-react-test-utils/src/test-utils.tsx b/packages/nova-react-test-utils/src/test-utils.tsx index a235771c..78e0fc6b 100644 --- a/packages/nova-react-test-utils/src/test-utils.tsx +++ b/packages/nova-react-test-utils/src/test-utils.tsx @@ -47,7 +47,11 @@ export function createMockEnvironment( bubble: jest.fn(), }, graphql: { - ...(GraphQLHooks as NovaGraphQL), + ...(GraphQLHooks as unknown as NovaGraphQL), + useMutation_deprecated: GraphQLHooks.useMutation, + useMutation() { + throw new Error("Not supported yet in Apollo"); + }, mock: client.mock as MockFunctions, }, providerWrapper: ({ children }) => ( diff --git a/packages/nova-react/package.json b/packages/nova-react/package.json index 68cc4a37..861113ad 100644 --- a/packages/nova-react/package.json +++ b/packages/nova-react/package.json @@ -12,7 +12,6 @@ }, "peerDependencies": { "react": "^17.0.2 || ^18", - "relay-runtime": "12.0.0", "@types/react": "^17.0.2 || ^18", "@graphitation/graphql-js-tag": "^0.9.0" }, diff --git a/packages/nova-react/src/graphql/hooks.ts b/packages/nova-react/src/graphql/hooks.ts index 14790a98..299319c0 100644 --- a/packages/nova-react/src/graphql/hooks.ts +++ b/packages/nova-react/src/graphql/hooks.ts @@ -3,6 +3,7 @@ import invariant from "invariant"; import type { GraphQLTaggedNode } from "./taggedNode"; import type { + Disposable, KeyType, KeyTypeData, OperationType, @@ -10,7 +11,6 @@ import type { RefetchFn, FetchPolicy } from "./types"; -import type { Disposable } from 'relay-runtime'; /** * Executes a GraphQL query. @@ -359,6 +359,6 @@ export function useMutation_deprecated( mutation: GraphQLTaggedNode, ): [MutationCommitter_deprecated, boolean] { const graphql = useNovaGraphQL(); - invariant(graphql.useMutation_deprecated, "Expected host to provide a useMutation hook"); + invariant(graphql.useMutation_deprecated, "Expected host to provide a useMutation_deprecated hook"); return graphql.useMutation_deprecated(mutation); } diff --git a/packages/nova-react/src/graphql/types.ts b/packages/nova-react/src/graphql/types.ts index fabe3f07..51e5d473 100644 --- a/packages/nova-react/src/graphql/types.ts +++ b/packages/nova-react/src/graphql/types.ts @@ -93,6 +93,6 @@ type RefetchOptions = { fetchPolicy?: FetchPolicy; }; -type Disposable = { +export type Disposable = { dispose(): void; }; diff --git a/packages/nova-types/package.json b/packages/nova-types/package.json index fed4a22a..512d2a45 100644 --- a/packages/nova-types/package.json +++ b/packages/nova-types/package.json @@ -9,12 +9,8 @@ "types": "monorepo-scripts types", "just": "monorepo-scripts" }, - "dependencies": { - "relay-runtime": "12.0.0" - }, "devDependencies": { "@types/jest": "^29.2.0", - "@types/relay-runtime": "^17.0.4", "monorepo-scripts": "*" }, "repository": { diff --git a/packages/nova-types/src/nova-graphql.interface.ts b/packages/nova-types/src/nova-graphql.interface.ts index 57026530..3755a64a 100644 --- a/packages/nova-types/src/nova-graphql.interface.ts +++ b/packages/nova-types/src/nova-graphql.interface.ts @@ -9,8 +9,6 @@ * In case the host application uses Apollo Client, these hooks can be provided by using the * `@graphitation/apollo-react-relay-duct-tape` package. See https://github.com/microsoft/graphitation for details. */ -import type { Disposable } from 'relay-runtime'; - export interface NovaGraphQL { useFragment?: ( fragmentInput: GraphQLDocument, @@ -84,9 +82,13 @@ export interface NovaGraphQL { (options: { variables: { [name: string]: unknown }; context?: { [name: string]: unknown }; - optimisticResponse?: unknown | null; + optimisticResponse?: Partial | null; onCompleted?: (response: unknown) => void; }) => Promise<{ errors?: readonly Error[]; data?: unknown }>, boolean, ]; } + +type Disposable = { + dispose(): void; +}; diff --git a/yarn.lock b/yarn.lock index b99e5822..38cf9721 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10446,7 +10446,16 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -10478,7 +10487,14 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -11440,7 +11456,7 @@ workspace-tools@^0.30.0: js-yaml "^4.1.0" micromatch "^4.0.0" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -11458,6 +11474,15 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" From 4e1ab7b12e3203ea36f614e5c6dc5e5a74ba7c6e Mon Sep 17 00:00:00 2001 From: DarynaAkhmedova <132382266+DarynaAkhmedova@users.noreply.github.com> Date: Thu, 26 Sep 2024 14:41:07 +0000 Subject: [PATCH 5/7] Add compatibility test --- packages/nova-react/package.json | 1 + .../nova-react/src/graphql/hooks.test.tsx | 6 +++++ packages/nova-react/src/graphql/hooks.ts | 14 ++++++++--- packages/nova-react/src/graphql/types.ts | 19 +++------------ .../nova-types/src/nova-graphql.interface.ts | 24 +++++++++++++++++-- yarn.lock | 13 ++++++++++ 6 files changed, 56 insertions(+), 21 deletions(-) diff --git a/packages/nova-react/package.json b/packages/nova-react/package.json index 861113ad..1df5c260 100644 --- a/packages/nova-react/package.json +++ b/packages/nova-react/package.json @@ -27,6 +27,7 @@ "@types/jest": "^29.2.0", "@types/react": "^18.3.1", "@types/react-dom": "^18.3.0", + "@types/react-relay": "^16.0.6", "monorepo-scripts": "*", "react": "^18.3.1", "react-dom": "^18.3.1" diff --git a/packages/nova-react/src/graphql/hooks.test.tsx b/packages/nova-react/src/graphql/hooks.test.tsx index dfb303fd..faa23995 100644 --- a/packages/nova-react/src/graphql/hooks.test.tsx +++ b/packages/nova-react/src/graphql/hooks.test.tsx @@ -14,13 +14,19 @@ import { usePaginationFragment, useRefetchableFragment, useSubscription, + useMutation, } from "./hooks"; import type { GraphQLTaggedNode } from "./taggedNode"; import type { FragmentRefs } from "./types"; +import type { useMutation as relayUseMutation, GraphQLTaggedNode as RelayGraphQLTaggedNode } from "react-relay"; type IsNotNull = null extends T ? false : true; type IsNotUndefined = undefined extends T ? false : true; +// This is used to verify type compatibility with Relay useMutation hook +declare function useMutationRelay(mutation: RelayGraphQLTaggedNode): ReturnType; +export const typeVerification: typeof relayUseMutation = useMutationRelay; + describe(useLazyLoadQuery, () => { it("ensures an implementation is supplied", () => { const graphql: NovaGraphQL = {}; diff --git a/packages/nova-react/src/graphql/hooks.ts b/packages/nova-react/src/graphql/hooks.ts index 299319c0..22bca2f7 100644 --- a/packages/nova-react/src/graphql/hooks.ts +++ b/packages/nova-react/src/graphql/hooks.ts @@ -8,6 +8,7 @@ import type { KeyTypeData, OperationType, PaginationFn, + PayloadError, RefetchFn, FetchPolicy } from "./types"; @@ -325,17 +326,24 @@ export function useSubscription( graphql.useSubscription(config); } -interface MutationCommitterOptions { +interface MutationCommitterOptionsBase { variables: TMutationPayload["variables"]; /** * Should be avoided when possible as it will not be compatible with Relay APIs. */ context?: TMutationPayload["context"]; optimisticResponse?: Partial | null; - onCompleted?: (response: TMutationPayload["response"]) => void; onError?: (error: Error) => void; } +interface MutationCommitterOptions extends MutationCommitterOptionsBase { + onCompleted?: ((response: TMutationPayload["response"], errors: PayloadError[] | null) => void | null) | undefined; +} + +interface MutationCommitterOptions_deprecated extends MutationCommitterOptionsBase { + onCompleted?: (response: TMutationPayload["response"]) => void; +} + type MutationCommitter = ( options: MutationCommitterOptions, ) => Disposable; @@ -349,7 +357,7 @@ export function useMutation( } type MutationCommitter_deprecated = ( - options: MutationCommitterOptions, + options: MutationCommitterOptions_deprecated, ) => Promise<{ errors?: readonly Error[]; data?: TMutationPayload["response"]; diff --git a/packages/nova-react/src/graphql/types.ts b/packages/nova-react/src/graphql/types.ts index 51e5d473..46e801b2 100644 --- a/packages/nova-react/src/graphql/types.ts +++ b/packages/nova-react/src/graphql/types.ts @@ -1,21 +1,8 @@ -export interface Variables { - [name: string]: any; -} - -export interface Context { - [name: string]: any; -} - -export interface OperationType { - readonly variables: Variables; - readonly context?: Context; - readonly response: unknown; - readonly rawResponse?: unknown; -} - /** * relay-compiler-language-typescript support for fragment references - */ +*/ + +export type { OperationType, PayloadError } from "@nova/types"; export interface _RefType { " $refType": Ref; diff --git a/packages/nova-types/src/nova-graphql.interface.ts b/packages/nova-types/src/nova-graphql.interface.ts index 3755a64a..a4b24d3a 100644 --- a/packages/nova-types/src/nova-graphql.interface.ts +++ b/packages/nova-types/src/nova-graphql.interface.ts @@ -1,3 +1,23 @@ +export interface OperationType { + readonly variables: { [name: string]: any }; + readonly context?: { [name: string]: any }; + readonly response: any; + readonly rawResponse?: unknown; +} + +export interface PayloadError { + message: string; + locations?: + | Array<{ + line: number; + column: number; + }> + | undefined; + path?: Array; + severity?: "CRITICAL" | "ERROR" | "WARNING" | undefined; +} + + /** * Describes the GraphQL contract a Nova component can expect to be provided by the host application. Refer to the equally * named React hooks provided by the `@nova/react-facade` package for their functional details. @@ -63,14 +83,14 @@ export interface NovaGraphQL { onError?: (error: Error) => void; }) => void; - useMutation?: ( + useMutation?: ( mutation: GraphQLDocument, ) => [ (options: { variables: { [name: string]: unknown }; context?: { [name: string]: unknown }; optimisticResponse?: unknown | null; - onCompleted?: (response: unknown) => void; + onCompleted?: ((response: TMutationPayload["response"], errors: PayloadError[] | null) => void | null) | undefined; onError?: (error: Error) => void; }) => Disposable, boolean, diff --git a/yarn.lock b/yarn.lock index 38cf9721..fc3d4f88 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3841,6 +3841,14 @@ dependencies: "@types/react" "*" +"@types/react-relay@^16.0.6": + version "16.0.6" + resolved "https://registry.yarnpkg.com/@types/react-relay/-/react-relay-16.0.6.tgz#afc467fab89dc4c96fb1424f84b869750f5c42f2" + integrity sha512-VTntVQJhlwQYNUlbNgGf8RYy7EtQPRZqsD/w2Si0ygZspJXuNlVdRkklWMFN99EMRhHDpqlNHD8i3wIs7QRz9g== + dependencies: + "@types/react" "*" + "@types/relay-runtime" "*" + "@types/react-test-renderer@^18.3.0": version "18.3.0" resolved "https://registry.yarnpkg.com/@types/react-test-renderer/-/react-test-renderer-18.3.0.tgz#839502eae70058a4ae161f63385a8e7929cef4c0" @@ -3856,6 +3864,11 @@ "@types/prop-types" "*" csstype "^3.0.2" +"@types/relay-runtime@*": + version "17.0.4" + resolved "https://registry.yarnpkg.com/@types/relay-runtime/-/relay-runtime-17.0.4.tgz#428526fc3e6dfb6e0a5730c38ad521cb1eea189b" + integrity sha512-fB77br4lXlBYM/HpI6VI6KCrj5pw0LiAnkZOkffjirNYso+dzXGWkeIm0G0MGszD8WY1et+r1Uj2TA6rscBXNQ== + "@types/resolve@^1.20.2": version "1.20.6" resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.20.6.tgz#e6e60dad29c2c8c206c026e6dd8d6d1bdda850b8" From a2458b827664edc327c0097157e4608c6e712e51 Mon Sep 17 00:00:00 2001 From: DarynaAkhmedova <132382266+DarynaAkhmedova@users.noreply.github.com> Date: Thu, 26 Sep 2024 14:48:15 +0000 Subject: [PATCH 6/7] Code cleanup --- packages/nova-react/src/graphql/hooks.ts | 2 +- packages/nova-react/src/graphql/types.ts | 8 +--- .../nova-types/src/nova-graphql.interface.ts | 41 +++++++++---------- 3 files changed, 23 insertions(+), 28 deletions(-) diff --git a/packages/nova-react/src/graphql/hooks.ts b/packages/nova-react/src/graphql/hooks.ts index 22bca2f7..74f2e5b1 100644 --- a/packages/nova-react/src/graphql/hooks.ts +++ b/packages/nova-react/src/graphql/hooks.ts @@ -3,7 +3,6 @@ import invariant from "invariant"; import type { GraphQLTaggedNode } from "./taggedNode"; import type { - Disposable, KeyType, KeyTypeData, OperationType, @@ -12,6 +11,7 @@ import type { RefetchFn, FetchPolicy } from "./types"; +import type { Disposable } from "@nova/types"; /** * Executes a GraphQL query. diff --git a/packages/nova-react/src/graphql/types.ts b/packages/nova-react/src/graphql/types.ts index 46e801b2..1ec4601e 100644 --- a/packages/nova-react/src/graphql/types.ts +++ b/packages/nova-react/src/graphql/types.ts @@ -2,7 +2,7 @@ * relay-compiler-language-typescript support for fragment references */ -export type { OperationType, PayloadError } from "@nova/types"; +export type { OperationType, PayloadError, Disposable } from "@nova/types"; export interface _RefType { " $refType": Ref; @@ -78,8 +78,4 @@ export type FetchPolicy = type RefetchOptions = { onComplete?: (error: Error | null) => void; fetchPolicy?: FetchPolicy; -}; - -export type Disposable = { - dispose(): void; -}; +}; \ No newline at end of file diff --git a/packages/nova-types/src/nova-graphql.interface.ts b/packages/nova-types/src/nova-graphql.interface.ts index a4b24d3a..74a77038 100644 --- a/packages/nova-types/src/nova-graphql.interface.ts +++ b/packages/nova-types/src/nova-graphql.interface.ts @@ -1,23 +1,3 @@ -export interface OperationType { - readonly variables: { [name: string]: any }; - readonly context?: { [name: string]: any }; - readonly response: any; - readonly rawResponse?: unknown; -} - -export interface PayloadError { - message: string; - locations?: - | Array<{ - line: number; - column: number; - }> - | undefined; - path?: Array; - severity?: "CRITICAL" | "ERROR" | "WARNING" | undefined; -} - - /** * Describes the GraphQL contract a Nova component can expect to be provided by the host application. Refer to the equally * named React hooks provided by the `@nova/react-facade` package for their functional details. @@ -109,6 +89,25 @@ export interface NovaGraphQL { ]; } -type Disposable = { +export type Disposable = { dispose(): void; }; + +export interface OperationType { + readonly variables: { [name: string]: any }; + readonly context?: { [name: string]: any }; + readonly response: any; + readonly rawResponse?: unknown; +} + +export interface PayloadError { + message: string; + locations?: + | Array<{ + line: number; + column: number; + }> + | undefined; + path?: Array; + severity?: "CRITICAL" | "ERROR" | "WARNING" | undefined; +} From e3fcb212dcabb7bea9c0149a6abaffdaad70bf39 Mon Sep 17 00:00:00 2001 From: DarynaAkhmedova <132382266+DarynaAkhmedova@users.noreply.github.com> Date: Tue, 1 Oct 2024 11:35:04 +0000 Subject: [PATCH 7/7] PR suggestions --- packages/nova-react/src/graphql/hooks.ts | 14 +++++++++----- packages/nova-react/src/graphql/types.ts | 4 ++++ packages/nova-types/src/nova-graphql.interface.ts | 8 ++++---- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/packages/nova-react/src/graphql/hooks.ts b/packages/nova-react/src/graphql/hooks.ts index 74f2e5b1..2217725d 100644 --- a/packages/nova-react/src/graphql/hooks.ts +++ b/packages/nova-react/src/graphql/hooks.ts @@ -326,7 +326,7 @@ export function useSubscription( graphql.useSubscription(config); } -interface MutationCommitterOptionsBase { +interface MutationCommitterOptions { variables: TMutationPayload["variables"]; /** * Should be avoided when possible as it will not be compatible with Relay APIs. @@ -334,13 +334,17 @@ interface MutationCommitterOptionsBase { context?: TMutationPayload["context"]; optimisticResponse?: Partial | null; onError?: (error: Error) => void; -} - -interface MutationCommitterOptions extends MutationCommitterOptionsBase { onCompleted?: ((response: TMutationPayload["response"], errors: PayloadError[] | null) => void | null) | undefined; } -interface MutationCommitterOptions_deprecated extends MutationCommitterOptionsBase { +interface MutationCommitterOptions_deprecated { + variables: TMutationPayload["variables"]; + /** + * Should be avoided when possible as it will not be compatible with Relay APIs. + */ + context?: TMutationPayload["context"]; + optimisticResponse?: Partial | null; + onError?: (error: Error) => void; onCompleted?: (response: TMutationPayload["response"]) => void; } diff --git a/packages/nova-react/src/graphql/types.ts b/packages/nova-react/src/graphql/types.ts index 1ec4601e..cfd451e1 100644 --- a/packages/nova-react/src/graphql/types.ts +++ b/packages/nova-react/src/graphql/types.ts @@ -78,4 +78,8 @@ export type FetchPolicy = type RefetchOptions = { onComplete?: (error: Error | null) => void; fetchPolicy?: FetchPolicy; +}; + +type Disposable = { + dispose(): void; }; \ No newline at end of file diff --git a/packages/nova-types/src/nova-graphql.interface.ts b/packages/nova-types/src/nova-graphql.interface.ts index 74a77038..5618ffab 100644 --- a/packages/nova-types/src/nova-graphql.interface.ts +++ b/packages/nova-types/src/nova-graphql.interface.ts @@ -94,10 +94,10 @@ export type Disposable = { }; export interface OperationType { - readonly variables: { [name: string]: any }; - readonly context?: { [name: string]: any }; - readonly response: any; - readonly rawResponse?: unknown; + readonly variables: { [name: string]: unknown }; + readonly context?: { [name: string]: unknown }; + readonly response: unknown; + readonly rawResponse?: unknown | undefined; } export interface PayloadError {