refactor(core): adjust graphql hook (#5339)

This commit is contained in:
EYHN
2023-12-28 07:43:25 +00:00
parent 7e75e19d04
commit 0b9cd00fd3
28 changed files with 137 additions and 119 deletions

View File

@@ -13,11 +13,11 @@ import {
sendSetPasswordEmailMutation,
} from '@affine/graphql';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { useMutation } from '@affine/workspace/affine/gql';
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
import { useSetAtom } from 'jotai/react';
import { useCallback, useState } from 'react';
import { useMutation } from '../../../hooks/use-mutation';
import type { AuthPanelProps } from './index';
const useEmailTitle = (emailType: AuthPanelProps['emailType']) => {

View File

@@ -7,7 +7,6 @@ import { Button } from '@affine/component/ui/button';
import { type GetUserQuery, getUserQuery } from '@affine/graphql';
import { Trans } from '@affine/i18n';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { useMutation } from '@affine/workspace/affine/gql';
import { ArrowDownBigIcon, GoogleDuotoneIcon } from '@blocksuite/icons';
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
import { GraphQLError } from 'graphql';
@@ -15,6 +14,7 @@ import { type FC, useState } from 'react';
import { useCallback } from 'react';
import { useCurrentLoginStatus } from '../../../hooks/affine/use-current-login-status';
import { useMutation } from '../../../hooks/use-mutation';
import { emailRegex } from '../../../utils/email-regex';
import type { AuthPanelProps } from './index';
import * as style from './style.css';

View File

@@ -9,16 +9,17 @@ import {
subscriptionQuery,
} from '@affine/graphql';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { useMutation, useQuery } from '@affine/workspace/affine/gql';
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
import { nanoid } from 'nanoid';
import { Suspense, useCallback, useEffect, useMemo } from 'react';
import { useCurrentUser } from '../../../hooks/affine/use-current-user';
import { useMutation } from '../../../hooks/use-mutation';
import {
RouteLogic,
useNavigateHelper,
} from '../../../hooks/use-navigate-helper';
import { useQuery } from '../../../hooks/use-query';
import * as styles from './subscription-redirect.css';
import { useSubscriptionSearch } from './use-subscription';

View File

@@ -9,11 +9,6 @@ import {
createAffineCloudBlobStorage,
globalBlockSuiteSchema,
} from '@affine/workspace';
import {
useMutateQueryResource,
useMutation,
useQueryInfinite,
} from '@affine/workspace/affine/gql';
import { assertEquals } from '@blocksuite/global/utils';
import { Workspace } from '@blocksuite/store';
import { usePageMetaHelper } from '@toeverything/hooks/use-block-suite-page-meta';
@@ -23,6 +18,12 @@ import { useMemo } from 'react';
import useSWRImmutable from 'swr/immutable';
import { applyUpdate } from 'yjs';
import {
useMutateQueryResource,
useMutation,
} from '../../../hooks/use-mutation';
import { useQueryInfinite } from '../../../hooks/use-query';
const logger = new DebugLogger('page-history');
type DocHistory = ListHistoryQuery['workspace']['histories'][number];

View File

@@ -14,7 +14,6 @@ import {
uploadAvatarMutation,
} from '@affine/graphql';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { useMutation, useQuery } from '@affine/workspace/affine/gql';
import { ArrowRightSmallIcon, CameraIcon } from '@blocksuite/icons';
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
import bytes from 'bytes';
@@ -35,6 +34,8 @@ import {
} from '../../../../atoms';
import { useCurrentUser } from '../../../../hooks/affine/use-current-user';
import { useSelfHosted } from '../../../../hooks/affine/use-server-config';
import { useMutation } from '../../../../hooks/use-mutation';
import { useQuery } from '../../../../hooks/use-query';
import { useUserSubscription } from '../../../../hooks/use-subscription';
import { validateAndReduceImage } from '../../../../utils/reduce-image';
import { Upload } from '../../../pure/file-upload';

View File

@@ -20,7 +20,6 @@ import {
} from '@affine/graphql';
import { Trans } from '@affine/i18n';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { useMutation, useQuery } from '@affine/workspace/affine/gql';
import { ArrowRightSmallIcon } from '@blocksuite/icons';
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
import { useSetAtom } from 'jotai';
@@ -28,6 +27,8 @@ import { Suspense, useCallback, useMemo, useState } from 'react';
import { openSettingModalAtom } from '../../../../../atoms';
import { useCurrentLoginStatus } from '../../../../../hooks/affine/use-current-login-status';
import { useMutation } from '../../../../../hooks/use-mutation';
import { useQuery } from '../../../../../hooks/use-query';
import {
type SubscriptionMutator,
useUserSubscription,

View File

@@ -3,12 +3,12 @@ import {
cancelSubscriptionMutation,
resumeSubscriptionMutation,
} from '@affine/graphql';
import { useMutation } from '@affine/workspace/affine/gql';
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
import { nanoid } from 'nanoid';
import type { PropsWithChildren } from 'react';
import { useState } from 'react';
import { useMutation } from '../../../../../hooks/use-mutation';
import { ConfirmLoadingModal, DowngradeModal } from './modals';
/**

View File

@@ -7,13 +7,13 @@ import {
} from '@affine/graphql';
import { Trans } from '@affine/i18n';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { useQuery } from '@affine/workspace/affine/gql';
import { useSetAtom } from 'jotai';
import { Suspense, useEffect, useRef, useState } from 'react';
import type { FallbackProps } from 'react-error-boundary';
import { SWRErrorBoundary } from '../../../../../components/pure/swr-error-bundary';
import { useCurrentLoginStatus } from '../../../../../hooks/affine/use-current-login-status';
import { useQuery } from '../../../../../hooks/use-query';
import { useUserSubscription } from '../../../../../hooks/use-subscription';
import { PlanLayout } from './layout';
import { type FixedPrice, getPlanDetail, PlanCard } from './plan-card';

View File

@@ -13,7 +13,6 @@ import {
} from '@affine/graphql';
import { Trans } from '@affine/i18n';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { useMutation } from '@affine/workspace/affine/gql';
import { DoneIcon } from '@blocksuite/icons';
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
import { useSetAtom } from 'jotai';
@@ -31,6 +30,7 @@ import {
import { openPaymentDisableAtom } from '../../../../../atoms';
import { authAtom } from '../../../../../atoms/index';
import { useCurrentLoginStatus } from '../../../../../hooks/affine/use-current-login-status';
import { useMutation } from '../../../../../hooks/use-mutation';
import { CancelAction, ResumeAction } from './actions';
import { BulledListIcon } from './icons/bulled-list';
import { ConfirmLoadingModal } from './modals';

View File

@@ -6,7 +6,8 @@ import { render } from '@testing-library/react';
import type { Mock } from 'vitest';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { useMutation, useQuery } from '../gql';
import { useMutation } from '../use-mutation';
import { useQuery } from '../use-query';
let fetch: Mock;
describe('GraphQL wrapper for SWR', () => {

View File

@@ -1,8 +1,8 @@
import type { Permission } from '@affine/graphql';
import { inviteByEmailMutation } from '@affine/graphql';
import { useMutation } from '@affine/workspace/affine/gql';
import { useCallback } from 'react';
import { useMutation } from '../use-mutation';
import { useMutateCloud } from './use-mutate-cloud';
export function useInviteMember(workspaceId: string) {

View File

@@ -6,11 +6,12 @@ import {
revokePublicPageMutation,
} from '@affine/graphql';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { useMutation, useQuery } from '@affine/workspace/affine/gql';
import { useSetAtom } from 'jotai';
import { useCallback, useMemo } from 'react';
import type { PageMode } from '../../atoms';
import { useMutation } from '../use-mutation';
import { useQuery } from '../use-query';
type NoParametersKeys<T> = {
[K in keyof T]: T[K] extends () => any ? K : never;

View File

@@ -1,8 +1,9 @@
import { WorkspaceFlavour } from '@affine/env/workspace';
import { getIsOwnerQuery } from '@affine/graphql';
import { useQueryImmutable } from '@affine/workspace/affine/gql';
import type { WorkspaceMetadata } from '@affine/workspace/metadata';
import { useQueryImmutable } from '../use-query';
export function useIsWorkspaceOwner(workspaceMetadata: WorkspaceMetadata) {
const { data } = useQueryImmutable(
workspaceMetadata.flavour !== WorkspaceFlavour.LOCAL

View File

@@ -1,5 +1,6 @@
import { getMemberCountByWorkspaceIdQuery } from '@affine/graphql';
import { useQuery } from '@affine/workspace/affine/gql';
import { useQuery } from '../use-query';
export function useMemberCount(workspaceId: string) {
const { data } = useQuery({

View File

@@ -2,7 +2,8 @@ import {
type GetMembersByWorkspaceIdQuery,
getMembersByWorkspaceIdQuery,
} from '@affine/graphql';
import { useQuery } from '@affine/workspace/affine/gql';
import { useQuery } from '../use-query';
export type Member = Omit<
GetMembersByWorkspaceIdQuery['workspace']['members'][number],

View File

@@ -1,7 +1,7 @@
import { revokeMemberPermissionMutation } from '@affine/graphql';
import { useMutation } from '@affine/workspace/affine/gql';
import { useCallback } from 'react';
import { useMutation } from '../use-mutation';
import { useMutateCloud } from './use-mutate-cloud';
export function useRevokeMemberPermission(workspaceId: string) {

View File

@@ -1,7 +1,8 @@
import { serverConfigQuery } from '@affine/graphql';
import { useQueryImmutable } from '@affine/workspace/affine/gql';
import type { BareFetcher, Middleware } from 'swr';
import { useQueryImmutable } from '../use-query';
const wrappedFetcher = (fetcher: BareFetcher<any> | null, ...args: any[]) =>
fetcher?.(...args).catch(() => null);

View File

@@ -1,7 +1,7 @@
import { setWorkspacePublicByIdMutation } from '@affine/graphql';
import { useMutation } from '@affine/workspace/affine/gql';
import { useCallback } from 'react';
import { useMutation } from '../use-mutation';
import { useMutateCloud } from './use-mutate-cloud';
export function useToggleCloudPublic(workspaceId: string) {

View File

@@ -0,0 +1,89 @@
import type {
GraphQLQuery,
MutationOptions,
QueryResponse,
QueryVariables,
RecursiveMaybeFields,
} from '@affine/graphql';
import { fetcher } from '@affine/graphql';
import type { GraphQLError } from 'graphql';
import { useMemo } from 'react';
import type { Key } from 'swr';
import { useSWRConfig } from 'swr';
import type {
SWRMutationConfiguration,
SWRMutationResponse,
} from 'swr/mutation';
import useSWRMutation from 'swr/mutation';
/**
* A useSWRMutation wrapper for sending graphql mutations
*
* @example
*
* ```ts
* import { someMutation } from '@affine/graphql'
*
* const { trigger } = useMutation({
* mutation: someMutation,
* })
*
* trigger({ name: 'John Doe' })
*/
export function useMutation<Mutation extends GraphQLQuery, K extends Key = Key>(
options: Omit<MutationOptions<Mutation>, 'variables'>,
config?: Omit<
SWRMutationConfiguration<
QueryResponse<Mutation>,
GraphQLError | GraphQLError[],
K,
QueryVariables<Mutation>
>,
'fetcher'
>
): SWRMutationResponse<
QueryResponse<Mutation>,
GraphQLError | GraphQLError[],
K,
QueryVariables<Mutation>
>;
export function useMutation(
options: Omit<MutationOptions<GraphQLQuery>, 'variables'>,
config?: any
) {
return useSWRMutation(
() => ['cloud', options.mutation.id],
(_: unknown[], { arg }: { arg: any }) =>
fetcher({ ...options, query: options.mutation, variables: arg }),
config
);
}
// use this to revalidate all queries that match the filter
export const useMutateQueryResource = () => {
const { mutate } = useSWRConfig();
const revalidateResource = useMemo(
() =>
<Q extends GraphQLQuery>(
query: Q,
varsFilter: (
vars: RecursiveMaybeFields<QueryVariables<Q>>
) => boolean = _vars => true
) => {
return mutate(key => {
const res =
Array.isArray(key) &&
key[0] === 'cloud' &&
key[1] === query.id &&
varsFilter(key[2]);
if (res) {
console.debug('revalidate resource', key);
}
return res;
});
},
[mutate]
);
return revalidateResource;
};

View File

@@ -1,28 +1,15 @@
import { setupGlobal } from '@affine/env/global';
import type {
GraphQLQuery,
MutationOptions,
QueryOptions,
QueryResponse,
QueryVariables,
RecursiveMaybeFields,
} from '@affine/graphql';
import { gqlFetcherFactory } from '@affine/graphql';
import { fetcher } from '@affine/graphql';
import type { GraphQLError } from 'graphql';
import { useCallback, useMemo } from 'react';
import type { Key, SWRConfiguration, SWRResponse } from 'swr';
import useSWR, { useSWRConfig } from 'swr';
import type { SWRConfiguration, SWRResponse } from 'swr';
import useSWR from 'swr';
import useSWRImutable from 'swr/immutable';
import useSWRInfinite from 'swr/infinite';
import type {
SWRMutationConfiguration,
SWRMutationResponse,
} from 'swr/mutation';
import useSWRMutation from 'swr/mutation';
setupGlobal();
export const fetcher = gqlFetcherFactory('/graphql');
/**
* A `useSWR` wrapper for sending graphql queries
@@ -140,77 +127,3 @@ export function useQueryInfinite<Query extends GraphQLQuery>(
loadMore,
};
}
/**
* A useSWRMutation wrapper for sending graphql mutations
*
* @example
*
* ```ts
* import { someMutation } from '@affine/graphql'
*
* const { trigger } = useMutation({
* mutation: someMutation,
* })
*
* trigger({ name: 'John Doe' })
*/
export function useMutation<Mutation extends GraphQLQuery, K extends Key = Key>(
options: Omit<MutationOptions<Mutation>, 'variables'>,
config?: Omit<
SWRMutationConfiguration<
QueryResponse<Mutation>,
GraphQLError | GraphQLError[],
K,
QueryVariables<Mutation>
>,
'fetcher'
>
): SWRMutationResponse<
QueryResponse<Mutation>,
GraphQLError | GraphQLError[],
K,
QueryVariables<Mutation>
>;
export function useMutation(
options: Omit<MutationOptions<GraphQLQuery>, 'variables'>,
config?: any
) {
return useSWRMutation(
() => ['cloud', options.mutation.id],
(_: unknown[], { arg }: { arg: any }) =>
fetcher({ ...options, query: options.mutation, variables: arg }),
config
);
}
export const gql = fetcher;
// use this to revalidate all queries that match the filter
export const useMutateQueryResource = () => {
const { mutate } = useSWRConfig();
const revalidateResource = useMemo(
() =>
<Q extends GraphQLQuery>(
query: Q,
varsFilter: (
vars: RecursiveMaybeFields<QueryVariables<Q>>
) => boolean = _vars => true
) => {
return mutate(key => {
const res =
Array.isArray(key) &&
key[0] === 'cloud' &&
key[1] === query.id &&
varsFilter(key[2]);
if (res) {
console.debug('revalidate resource', key);
}
return res;
});
},
[mutate]
);
return revalidateResource;
};

View File

@@ -1,5 +1,6 @@
import { quotaQuery } from '@affine/graphql';
import { useQuery } from '@affine/workspace/affine/gql';
import { useQuery } from './use-query';
export const useUserQuota = () => {
const { data } = useQuery({

View File

@@ -1,8 +1,8 @@
import { type SubscriptionQuery, subscriptionQuery } from '@affine/graphql';
import { useQuery } from '@affine/workspace/affine/gql';
import { useAsyncCallback } from '@toeverything/hooks/affine-async-hooks';
import { useSelfHosted } from './affine/use-server-config';
import { useQuery } from './use-query';
export type Subscription = NonNullable<
NonNullable<SubscriptionQuery['currentUser']>['subscription']

View File

@@ -13,8 +13,8 @@ import {
changePasswordMutation,
sendVerifyChangeEmailMutation,
} from '@affine/graphql';
import { fetcher } from '@affine/graphql';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { fetcher, useMutation } from '@affine/workspace/affine/gql';
import { useSetAtom } from 'jotai/react';
import type { ReactElement } from 'react';
import { useCallback } from 'react';
@@ -29,6 +29,7 @@ import { z } from 'zod';
import { SubscriptionRedirect } from '../components/affine/auth/subscription-redirect';
import { useCurrentLoginStatus } from '../hooks/affine/use-current-login-status';
import { useCurrentUser } from '../hooks/affine/use-current-user';
import { useMutation } from '../hooks/use-mutation';
import { RouteLogic, useNavigateHelper } from '../hooks/use-navigate-helper';
const authTypeSchema = z.enum([

View File

@@ -5,7 +5,7 @@ import {
type GetInviteInfoQuery,
getInviteInfoQuery,
} from '@affine/graphql';
import { fetcher } from '@affine/workspace/affine/gql';
import { fetcher } from '@affine/graphql';
import { useSetAtom } from 'jotai';
import { useCallback, useEffect } from 'react';
import { type LoaderFunction, redirect, useLoaderData } from 'react-router-dom';

View File

@@ -1,8 +1,8 @@
import { Button } from '@affine/component/ui/button';
import { type GetCurrentUserQuery, getCurrentUserQuery } from '@affine/graphql';
import { fetcher } from '@affine/graphql';
import { Trans } from '@affine/i18n';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { fetcher } from '@affine/workspace/affine/gql';
import { Logo1Icon } from '@blocksuite/icons';
import { useCallback, useMemo } from 'react';
import {

View File

@@ -3,3 +3,7 @@ export * from './graphql';
export * from './schema';
export * from './utils';
import '@affine/env/global';
import { gqlFetcherFactory } from './fetcher';
export const fetcher = gqlFetcherFactory('/graphql');

View File

@@ -5,8 +5,8 @@ import {
listBlobsQuery,
setBlobMutation,
} from '@affine/graphql';
import { fetcher } from '@affine/graphql';
import { fetcher } from '../../affine/gql';
import type { BlobStorage } from '../../engine/blob';
import { bufferToBlob } from '../../utils/buffer-to-blob';

View File

@@ -4,12 +4,12 @@ import {
deleteWorkspaceMutation,
getWorkspacesQuery,
} from '@affine/graphql';
import { fetcher } from '@affine/graphql';
import { Workspace as BlockSuiteWorkspace } from '@blocksuite/store';
import { difference } from 'lodash-es';
import { nanoid } from 'nanoid';
import { applyUpdate, encodeStateAsUpdate } from 'yjs';
import { fetcher } from '../../affine/gql';
import { globalBlockSuiteSchema } from '../../global-schema';
import type { WorkspaceListProvider } from '../../list';
import { createLocalBlobStorage } from '../local/blob';