-
Notifications
You must be signed in to change notification settings - Fork 26
Add example Relay provider and export relay Feedback example component #141
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| { | ||
| "type": "minor", | ||
| "comment": "[examples] Add example Relay provider and export relay Feedback example component", | ||
| "packageName": "@nova/examples", | ||
| "email": "eloy.de.enige@gmail.com", | ||
| "dependentChangeType": "patch" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,45 @@ | ||
| # Nova examples | ||
|
|
||
| This package contains examples of nova components as well as related good testing approaches for them. | ||
|
|
||
| ## Nova host integration canary | ||
|
|
||
| When configuring a host application, this package can be used as a light-weight canary package to test the host's Nova integration. | ||
|
|
||
| ### GraphQL | ||
|
|
||
| #### Relay | ||
|
|
||
| - [Configure your project to have Relay.](https://relay.dev/docs/getting-started/installation-and-setup/) | ||
| - [Create a Relay environment.](https://relay.dev/docs/api-reference/relay-environment-provider/) | ||
| - Instantiate the Nova Relay example provider: | ||
|
|
||
| ```tsx | ||
| import { | ||
| NovaExampleRelayGraphQLProvider, | ||
| NovaExampleRelayComponent, | ||
| } from "@nova/examples"; | ||
| import { createRelayEnvironment } from "./myHostRelayEnvironment"; | ||
|
|
||
| const environment = createRelayEnvironment(); | ||
|
|
||
| const MyHostNovaIntegrationTest = () => { | ||
| return ( | ||
| <NovaExampleRelayGraphQLProvider relayEnvironment={environment}> | ||
| <NovaExampleRelayComponent /> | ||
| </NovaExampleRelayGraphQLProvider> | ||
| ); | ||
| }; | ||
| ``` | ||
|
|
||
| #### Apollo | ||
|
|
||
| TODO | ||
|
|
||
| ### Eventing | ||
|
|
||
| TODO | ||
|
|
||
| ### Commanding | ||
|
|
||
| TODO |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| export { NovaExampleRelayGraphQLProvider } from "./relay/NovaExampleRelayGraphQLProvider"; | ||
| export { FeedbackContainer as NovaExampleRelayComponent } from "./relay/Feedback/FeedbackContainer"; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| import type { NovaGraphQL } from "@nova/types"; | ||
| import type RelayModernEnvironment from "relay-runtime/lib/store/RelayModernEnvironment"; | ||
|
|
||
| import * as React from "react"; | ||
| import { | ||
| useFragment, | ||
| useRefetchableFragment, | ||
| usePaginationFragment, | ||
| useSubscription, | ||
| RelayEnvironmentProvider, | ||
| } from "react-relay/hooks"; | ||
| import { NovaGraphQLProvider } from "@nova/react"; | ||
| import { useRelayLazyLoadQueryWithApolloAPI } from "./useRelayLazyLoadQueryWithApolloAPI"; | ||
| import { useRelayMutationWithApolloAPI } from "./useRelayMutationWithApolloAPI"; | ||
|
|
||
| const GraphQLInterface: NovaGraphQL = { | ||
| useFragment, | ||
| useRefetchableFragment, | ||
| usePaginationFragment, | ||
| useLazyLoadQuery: useRelayLazyLoadQueryWithApolloAPI, | ||
| useMutation: useRelayMutationWithApolloAPI, | ||
| useSubscription, | ||
| }; | ||
|
|
||
| export const NovaExampleRelayGraphQLProvider: React.FC< | ||
| React.PropsWithChildren<{ relayEnvironment: RelayModernEnvironment }> | ||
| > = ({ children, relayEnvironment }) => { | ||
| return ( | ||
| <RelayEnvironmentProvider environment={relayEnvironment}> | ||
| <NovaGraphQLProvider graphql={GraphQLInterface}> | ||
| {children} | ||
| </NovaGraphQLProvider> | ||
| </RelayEnvironmentProvider> | ||
| ); | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| /** | ||
| * NOTE: Taken from TMP packages/frameworks/frameworks-relay/src/react/hooks | ||
| * | ||
| * If needing to make changes, please make them in the upstream frameworks package. | ||
| */ | ||
|
|
||
| import { useQuery } from "relay-hooks"; | ||
| import type { | ||
| FetchPolicy, | ||
| GraphQLTaggedNode, | ||
| OperationType, | ||
| } from "relay-runtime"; | ||
|
|
||
| /** | ||
| * Hook that wraps useQuery hook from "relay-hooks" library and returns a Nova API compatible response. | ||
| * We can't use original Relay useLazyLoadQuery, since its implementation is heavily relies on Suspense. | ||
| */ | ||
| export function useRelayLazyLoadQueryWithApolloAPI< | ||
| TQuery extends OperationType, | ||
| >( | ||
| query: GraphQLTaggedNode, | ||
| variables: TQuery["variables"], | ||
| options?: { fetchPolicy?: FetchPolicy }, | ||
| ): { error?: Error; data?: TQuery["response"] } { | ||
| const result = useQuery(query, variables, options); | ||
| return { | ||
| ...result, | ||
| error: result.error ?? undefined, | ||
| }; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| /** | ||
| * NOTE: Taken from TMP packages/frameworks/frameworks-relay/src/react/hooks | ||
| * | ||
| * If needing to make changes, please make them in the upstream frameworks package. | ||
| */ | ||
|
|
||
| import { useMutation as useRelayMutation } from "react-relay/hooks"; | ||
| import type { GraphQLTaggedNode, MutationParameters } from "relay-runtime"; | ||
|
|
||
| type MutationCommitter<TMutation extends MutationParameters> = (options: { | ||
| variables: { [name: string]: unknown }; | ||
| context?: { [name: string]: unknown }; | ||
| optimisticResponse?: unknown | null; | ||
| onCompleted?: (response: unknown) => void; | ||
| }) => Promise<{ errors?: Error[]; data?: TMutation["response"] }>; | ||
|
|
||
| /** | ||
| * Hook that wraps original Relay useMutation hook and returns mutation committer, | ||
| * that returns a promise. This is required for alignment with Apollo client | ||
| * useMutation hook API for smoother migration of production code to Relay. | ||
| * @param mutation Mutation document. | ||
| * @returns Array containing mutation committer function and a flag | ||
| * indicating whether mutation is "in flight". | ||
| */ | ||
| export function useRelayMutationWithApolloAPI< | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With this change we start having two different implementation of Nova relay based environment, the other one exists in In 1JS (and in Outlook) nova env based on relay is using suspending For now I will approve and merge the PR, to allow you to share this with folks, but without this need I would block it until we aligned, so please follow up on it
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed, and yesterday I was reminded of this PR that I recall was attempting to align some of this #117 @sergey-stoyan Can you make sure to join a next nova sync together with @sjwilczynski so we can discuss this topic?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, let's discuss during the next sync |
||
| TMutation extends MutationParameters, | ||
| >(mutation: GraphQLTaggedNode): [MutationCommitter<TMutation>, boolean] { | ||
| const [commitMutation, isMutationInFlight] = useRelayMutation(mutation); | ||
| return [ | ||
| (options) => { | ||
| return new Promise((resolve, reject) => { | ||
| commitMutation({ | ||
| variables: options.variables, | ||
| onCompleted: (response, errors) => { | ||
| resolve( | ||
| errors | ||
| ? { | ||
| data: response, | ||
| errors: errors.map((e) => new Error(e.message)), | ||
| } | ||
| : { data: response }, | ||
| ); | ||
| }, | ||
| onError: (error) => { | ||
| reject(error); | ||
| }, | ||
| }); | ||
| }); | ||
| }, | ||
| isMutationInFlight, | ||
| ]; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.