Skip to content
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

fix(admin): fix the admin app #9233

Open
wants to merge 1 commit into
base: canary
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions packages/frontend/admin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@
"update-shadcn": "shadcn-ui add -p src/components/ui"
},
"exports": {
"./utils": "./src/utils.ts",
"./components/ui/*": "./src/components/ui/*.tsx"
"./*": "./src/*"
}
}
57 changes: 11 additions & 46 deletions packages/frontend/admin/src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,5 @@
import { Toaster } from '@affine/admin/components/ui/sonner';
import {
configureCloudModule,
DefaultServerService,
} from '@affine/core/modules/cloud';
import { configureLocalStorageStateStorageImpls } from '@affine/core/modules/storage';
import { configureUrlModule } from '@affine/core/modules/url';
import { wrapCreateBrowserRouter } from '@sentry/react';
import {
configureGlobalContextModule,
configureGlobalStorageModule,
configureLifecycleModule,
Framework,
FrameworkRoot,
FrameworkScope,
LifecycleService,
} from '@toeverything/infra';
import { useEffect } from 'react';
import {
createBrowserRouter as reactRouterCreateBrowserRouter,
Expand Down Expand Up @@ -124,38 +109,18 @@ export const router = _createBrowserRouter(
}
);

const framework = new Framework();
configureLifecycleModule(framework);
configureLocalStorageStateStorageImpls(framework);
configureGlobalStorageModule(framework);
configureGlobalContextModule(framework);
configureUrlModule(framework);
configureCloudModule(framework);
const frameworkProvider = framework.provider();

// setup application lifecycle events, and emit application start event
window.addEventListener('focus', () => {
frameworkProvider.get(LifecycleService).applicationFocus();
});
frameworkProvider.get(LifecycleService).applicationStart();
const serverService = frameworkProvider.get(DefaultServerService);

export const App = () => {
return (
<FrameworkRoot framework={frameworkProvider}>
<FrameworkScope scope={serverService.server.scope}>
<TooltipProvider>
<SWRConfig
value={{
revalidateOnFocus: false,
revalidateOnMount: false,
}}
>
<RouterProvider router={router} />
</SWRConfig>
<Toaster />
</TooltipProvider>
</FrameworkScope>
</FrameworkRoot>
<TooltipProvider>
<SWRConfig
value={{
revalidateOnFocus: false,
revalidateOnMount: false,
}}
>
<RouterProvider router={router} />
</SWRConfig>
<Toaster />
</TooltipProvider>
);
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Button } from '@affine/admin/components/ui/button';
import { Input } from '@affine/admin/components/ui/input';
import { useQuery } from '@affine/core/components/hooks/use-query';
import { useQuery } from '@affine/admin/use-query';
import { getUserByEmailQuery } from '@affine/graphql';
import { PlusIcon } from 'lucide-react';
import type { SetStateAction } from 'react';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
import {
useMutateQueryResource,
useMutation,
} from '@affine/core/components/hooks/use-mutation';
import { useQuery } from '@affine/core/components/hooks/use-query';
} from '@affine/admin/use-mutation';
import { useQuery } from '@affine/admin/use-query';
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
import {
createChangePasswordUrlMutation,
createUserMutation,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useQuery } from '@affine/core/components/hooks/use-query';
import { useQuery } from '@affine/admin/use-query';
import { listUsersQuery } from '@affine/graphql';
import { useState } from 'react';

Expand Down
6 changes: 3 additions & 3 deletions packages/frontend/admin/src/modules/ai/use-prompt.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
import {
useMutateQueryResource,
useMutation,
} from '@affine/core/components/hooks/use-mutation';
import { useQuery } from '@affine/core/components/hooks/use-query';
} from '@affine/admin/use-mutation';
import { useQuery } from '@affine/admin/use-query';
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
import { getPromptsQuery, updatePromptMutation } from '@affine/graphql';
import { toast } from 'sonner';

Expand Down
5 changes: 3 additions & 2 deletions packages/frontend/admin/src/modules/common.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { useMutateQueryResource } from '@affine/core/components/hooks/use-mutation';
import { useQuery } from '@affine/core/components/hooks/use-query';
import type { GetCurrentUserFeaturesQuery } from '@affine/graphql';
import {
adminServerConfigQuery,
FeatureType,
getCurrentUserFeaturesQuery,
} from '@affine/graphql';

import { useMutateQueryResource } from '../use-mutation';
import { useQuery } from '../use-query';

export const useServerConfig = () => {
const { data } = useQuery({
query: adminServerConfigQuery,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useQueryImmutable } from '@affine/core/components/hooks/use-query';
import { useQueryImmutable } from '@affine/admin/use-query';
import { getServerServiceConfigsQuery } from '@affine/graphql';
import { useMemo } from 'react';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useQuery } from '@affine/core/components/hooks/use-query';
import { useQuery } from '@affine/admin/use-query';
import { getServerRuntimeConfigQuery } from '@affine/graphql';
import { useMemo } from 'react';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { notify } from '@affine/component';
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
import {
useMutateQueryResource,
useMutation,
} from '@affine/core/components/hooks/use-mutation';
} from '@affine/admin/use-mutation';
import { notify } from '@affine/component';
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
import {
getServerRuntimeConfigQuery,
updateServerRuntimeConfigsMutation,
Expand Down
94 changes: 94 additions & 0 deletions packages/frontend/admin/src/use-mutation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import type {
GraphQLQuery,
MutationOptions,
QueryResponse,
QueryVariables,
RecursiveMaybeFields,
} 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';

import { gqlFetcher } from './use-query';

/**
* 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,
K,
QueryVariables<Mutation>
>,
'fetcher'
>
): SWRMutationResponse<
QueryResponse<Mutation>,
GraphQLError,
K,
QueryVariables<Mutation>
>;
export function useMutation(
options: Omit<MutationOptions<GraphQLQuery>, 'variables'>,
config?: any
) {
return useSWRMutation(
() => ['cloud', options.mutation.id],
(_: unknown[], { arg }: { arg: any }) =>
gqlFetcher({
...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;
};
131 changes: 131 additions & 0 deletions packages/frontend/admin/src/use-query.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import {
gqlFetcherFactory,
type GraphQLQuery,
type QueryOptions,
type QueryResponse,
} from '@affine/graphql';
import type { GraphQLError } from 'graphql';
import { useCallback, useMemo } from 'react';
import type { SWRConfiguration, SWRResponse } from 'swr';
import useSWR from 'swr';
import useSWRImmutable from 'swr/immutable';
import useSWRInfinite from 'swr/infinite';

/**
* A `useSWR` wrapper for sending graphql queries
*
* @example
*
* ```ts
* import { someQuery, someQueryWithNoVars } from '@affine/graphql'
*
* const swrResponse1 = useQuery({
* query: workspaceByIdQuery,
* variables: { id: '1' }
* })
*
* const swrResponse2 = useQuery({
* query: someQueryWithNoVars
* })
* ```
*/
type useQueryFn = <Query extends GraphQLQuery>(
options?: QueryOptions<Query>,
config?: Omit<
SWRConfiguration<
QueryResponse<Query>,
GraphQLError,
(options: QueryOptions<Query>) => Promise<QueryResponse<Query>>
>,
'fetcher'
>
) => SWRResponse<
QueryResponse<Query>,
GraphQLError,
{
suspense: true;
}
>;

const createUseQuery =
(immutable: boolean): useQueryFn =>
(options, config) => {
const configWithSuspense: SWRConfiguration = useMemo(
() => ({
suspense: true,
...config,
}),
[config]
);

const useSWRFn = immutable ? useSWRImmutable : useSWR;
return useSWRFn(
options ? () => ['cloud', options.query.id, options.variables] : null,
options ? () => gqlFetcher(options) : null,
configWithSuspense
);
};

export const useQuery = createUseQuery(false);
export const useQueryImmutable = createUseQuery(true);

export const gqlFetcher = gqlFetcherFactory('/graphql', window.fetch);

export function useQueryInfinite<Query extends GraphQLQuery>(
options: Omit<QueryOptions<Query>, 'variables'> & {
getVariables: (
pageIndex: number,
previousPageData: QueryResponse<Query>
) => QueryOptions<Query>['variables'];
},
config?: Omit<
SWRConfiguration<
QueryResponse<Query>,
GraphQLError | GraphQLError[],
(options: QueryOptions<Query>) => Promise<QueryResponse<Query>>
>,
'fetcher'
>
) {
const configWithSuspense: SWRConfiguration = useMemo(
() => ({
suspense: true,
...config,
}),
[config]
);

const { data, setSize, size, error } = useSWRInfinite<
QueryResponse<Query>,
GraphQLError | GraphQLError[]
>(
(pageIndex: number, previousPageData: QueryResponse<Query>) => [
'cloud',
options.query.id,
options.getVariables(pageIndex, previousPageData),
],
async ([_, __, variables]) => {
const params = { ...options, variables } as QueryOptions<Query>;
return gqlFetcher(params);
},
configWithSuspense
);

const loadingMore = size > 0 && data && !data[size - 1];

// TODO(@Peng): find a generic way to know whether or not there are more items to load
const loadMore = useCallback(() => {
if (loadingMore) {
return;
}
setSize(size => size + 1).catch(err => {
console.error(err);
});
}, [loadingMore, setSize]);
return {
data,
error,
loadingMore,
loadMore,
};
}
Loading