From b8e45d059cafbd1e097a17ce23506ed5bc45ed62 Mon Sep 17 00:00:00 2001 From: Himself65 Date: Wed, 8 Mar 2023 00:21:01 -0600 Subject: [PATCH] refactor: add hook transform workspace (#1407) --- .../affine/workspace-setting-detail/index.tsx | 11 +- .../panel/collaboration/index.tsx | 18 +-- .../panel/publish/index.tsx | 16 +-- .../header/header-right-items/SyncUser.tsx | 45 +++--- apps/web/src/hooks/use-transform-workspace.ts | 37 +++++ apps/web/src/pages/_app.tsx | 129 ++++++++---------- .../src/pages/workspace/[workspaceId]/all.tsx | 7 + .../pages/workspace/[workspaceId]/setting.tsx | 41 +++--- apps/web/src/plugins/affine/index.tsx | 4 +- apps/web/src/plugins/index.tsx | 34 ++--- 10 files changed, 176 insertions(+), 166 deletions(-) create mode 100644 apps/web/src/hooks/use-transform-workspace.ts diff --git a/apps/web/src/components/affine/workspace-setting-detail/index.tsx b/apps/web/src/components/affine/workspace-setting-detail/index.tsx index 675622a68a..56dbe54ab8 100644 --- a/apps/web/src/components/affine/workspace-setting-detail/index.tsx +++ b/apps/web/src/components/affine/workspace-setting-detail/index.tsx @@ -13,6 +13,8 @@ import { useIsWorkspaceOwner } from '../../../hooks/affine/use-is-workspace-owne import { fetcher, QueryKey } from '../../../plugins/affine/fetcher'; import { AffineOfficialWorkspace, + FlavourToWorkspace, + RemWorkspaceFlavour, SettingPanel, settingPanel, } from '../../../shared'; @@ -33,7 +35,14 @@ export type WorkspaceSettingDetailProps = { currentTab: SettingPanel; onChangeTab: (tab: SettingPanel) => void; onDeleteWorkspace: () => void; - onTransferWorkspace: (targetWorkspaceId: string) => void; + onTransferWorkspace: < + From extends RemWorkspaceFlavour, + To extends RemWorkspaceFlavour + >( + from: From, + to: To, + workspace: FlavourToWorkspace[From] + ) => void; }; export type PanelProps = WorkspaceSettingDetailProps; diff --git a/apps/web/src/components/affine/workspace-setting-detail/panel/collaboration/index.tsx b/apps/web/src/components/affine/workspace-setting-detail/panel/collaboration/index.tsx index 86abb7f6a1..df462b5a05 100644 --- a/apps/web/src/components/affine/workspace-setting-detail/panel/collaboration/index.tsx +++ b/apps/web/src/components/affine/workspace-setting-detail/panel/collaboration/index.tsx @@ -15,9 +15,7 @@ import { } from '@blocksuite/icons'; import React, { useCallback, useState } from 'react'; -import { lockMutex } from '../../../../../atoms'; import { useMembers } from '../../../../../hooks/affine/use-members'; -import { transformWorkspace } from '../../../../../plugins'; import { AffineWorkspace, LocalWorkspace, @@ -194,16 +192,12 @@ const LocalCollaborationPanel: React.FC< setOpen(false); }} onConform={() => { - // todo(himself65): move this function out of affine component - lockMutex(async () => { - const id = await transformWorkspace( - RemWorkspaceFlavour.LOCAL, - RemWorkspaceFlavour.AFFINE, - workspace - ); - onTransferWorkspace(id); - setOpen(false); - }); + onTransferWorkspace( + RemWorkspaceFlavour.LOCAL, + RemWorkspaceFlavour.AFFINE, + workspace + ); + setOpen(false); }} /> diff --git a/apps/web/src/components/affine/workspace-setting-detail/panel/publish/index.tsx b/apps/web/src/components/affine/workspace-setting-detail/panel/publish/index.tsx index 07e5b24e55..8dd5f09ffc 100644 --- a/apps/web/src/components/affine/workspace-setting-detail/panel/publish/index.tsx +++ b/apps/web/src/components/affine/workspace-setting-detail/panel/publish/index.tsx @@ -11,14 +11,12 @@ import { Box } from '@mui/material'; import React, { useCallback, useEffect, useState } from 'react'; import { useToggleWorkspacePublish } from '../../../../../hooks/affine/use-toggle-workspace-publish'; -import { transformWorkspace } from '../../../../../plugins'; import { AffineOfficialWorkspace, AffineWorkspace, LocalWorkspace, RemWorkspaceFlavour, } from '../../../../../shared'; -import { apis } from '../../../../../shared/apis'; import { Unreachable } from '../../../affine-error-eoundary'; import { EnableAffineCloudModal } from '../../../enable-affine-cloud-modal'; import { WorkspaceSettingDetailProps } from '../../index'; @@ -102,8 +100,8 @@ const PublishPanelAffine: React.FC = ({ onClose={() => { setOpen(false); }} - onConfirm={async () => { - await publishWorkspace(true); + onConfirm={() => { + publishWorkspace(true); setOpen(false); }} /> @@ -144,18 +142,12 @@ const PublishPanelLocal: React.FC = ({ onClose={() => { setOpen(false); }} - onConfirm={async () => { - const id = await transformWorkspace( + onConfirm={() => { + onTransferWorkspace( RemWorkspaceFlavour.LOCAL, RemWorkspaceFlavour.AFFINE, workspace ); - await apis.updateWorkspace({ - id, - public: true, - }); - // fixme: there imply that reload the whole page - onTransferWorkspace(id); setOpen(false); }} /> diff --git a/apps/web/src/components/blocksuite/header/header-right-items/SyncUser.tsx b/apps/web/src/components/blocksuite/header/header-right-items/SyncUser.tsx index 4f2172b78c..0f8b371316 100644 --- a/apps/web/src/components/blocksuite/header/header-right-items/SyncUser.tsx +++ b/apps/web/src/components/blocksuite/header/header-right-items/SyncUser.tsx @@ -9,9 +9,8 @@ import { assertEquals, assertExists } from '@blocksuite/store'; import { useRouter } from 'next/router'; import React, { useEffect, useState } from 'react'; -import { lockMutex } from '../../../../atoms'; import { useCurrentWorkspace } from '../../../../hooks/current/use-current-workspace'; -import { transformWorkspace } from '../../../../plugins'; +import { useTransformWorkspace } from '../../../../hooks/use-transform-workspace'; import { AffineOfficialWorkspace, LocalWorkspace, @@ -75,6 +74,7 @@ export const SyncUser = () => { const [open, setOpen] = useState(false); const { t } = useTranslation(); + const transformWorkspace = useTransformWorkspace(); if (status === 'offline') { return ( @@ -111,28 +111,25 @@ export const SyncUser = () => { onClose={() => { setOpen(false); }} - onConform={() => { - // todo(himself65): move this function out of affine component - lockMutex(async () => { - assertEquals(workspace.flavour, RemWorkspaceFlavour.LOCAL); - const id = await transformWorkspace( - RemWorkspaceFlavour.LOCAL, - RemWorkspaceFlavour.AFFINE, - workspace as LocalWorkspace - ); - // fixme(himself65): refactor this - router - .replace({ - pathname: `/workspace/[workspaceId]/all`, - query: { - workspaceId: id, - }, - }) - .then(() => { - router.reload(); - }); - setOpen(false); - }); + onConform={async () => { + assertEquals(workspace.flavour, RemWorkspaceFlavour.LOCAL); + const id = await transformWorkspace( + RemWorkspaceFlavour.LOCAL, + RemWorkspaceFlavour.AFFINE, + workspace as LocalWorkspace + ); + // fixme(himself65): refactor this + router + .replace({ + pathname: `/workspace/[workspaceId]/all`, + query: { + workspaceId: id, + }, + }) + .then(() => { + router.reload(); + }); + setOpen(false); }} /> diff --git a/apps/web/src/hooks/use-transform-workspace.ts b/apps/web/src/hooks/use-transform-workspace.ts new file mode 100644 index 0000000000..c9178dfd16 --- /dev/null +++ b/apps/web/src/hooks/use-transform-workspace.ts @@ -0,0 +1,37 @@ +import { useSetAtom } from 'jotai'; +import { useCallback } from 'react'; + +import { jotaiWorkspacesAtom } from '../atoms'; +import { WorkspacePlugins } from '../plugins'; +import { FlavourToWorkspace, RemWorkspaceFlavour } from '../shared'; + +/** + * Transform workspace from one flavour to another + * + * The logic here is to delete the old workspace and create a new one. + */ +export function useTransformWorkspace() { + const set = useSetAtom(jotaiWorkspacesAtom); + return useCallback( + async ( + from: From, + to: To, + workspace: FlavourToWorkspace[From] + ): Promise => { + await WorkspacePlugins[from].CRUD.delete(workspace as any); + const newId = await WorkspacePlugins[to].CRUD.create( + workspace.blockSuiteWorkspace + ); + set(workspaces => { + const idx = workspaces.findIndex(ws => ws.id === workspace.id); + workspaces.splice(idx, 1, { + id: newId, + flavour: to, + }); + return [...workspaces]; + }); + return newId; + }, + [set] + ); +} diff --git a/apps/web/src/pages/_app.tsx b/apps/web/src/pages/_app.tsx index dd52ef69af..66b2775180 100644 --- a/apps/web/src/pages/_app.tsx +++ b/apps/web/src/pages/_app.tsx @@ -11,7 +11,6 @@ import Head from 'next/head'; import { useRouter } from 'next/router'; import React, { memo, ReactElement, Suspense, useEffect, useMemo } from 'react'; import { Helmet, HelmetProvider } from 'react-helmet-async'; -import { SWRConfig, SWRConfiguration } from 'swr'; import { jotaiStore } from '../atoms'; import { AffineErrorBoundary } from '../components/affine/affine-error-eoundary'; @@ -38,17 +37,6 @@ const DebugAtoms = memo(function DebugAtoms() { const clientSideEmotionCache = createEmotionCache(); const helmetContext = {}; -const defaultSWRConfig: SWRConfiguration = { - suspense: true, - fetcher: () => { - const error = new Error( - 'you might forget to warp your page with AffineSWRConfigProvider' - ); - console.log(error); - throw error; - }, -}; - const App = function App({ Component, pageProps, @@ -71,67 +59,62 @@ const App = function App({ - - - }> - [ - , - , - , - ], - [] - )} - > - - - AFFiNE - - - - - - - - - - - - - - - - {getLayout()} - - - - - + + }> + [ + , + , + , + ], + [] + )} + > + + + AFFiNE + + + + + + + + + + + + + + + + {getLayout()} + + + + ); diff --git a/apps/web/src/pages/workspace/[workspaceId]/all.tsx b/apps/web/src/pages/workspace/[workspaceId]/all.tsx index 1cd28523e4..d934cb717d 100644 --- a/apps/web/src/pages/workspace/[workspaceId]/all.tsx +++ b/apps/web/src/pages/workspace/[workspaceId]/all.tsx @@ -1,6 +1,7 @@ import { useTranslation } from '@affine/i18n'; import { FolderIcon } from '@blocksuite/icons'; import { assertExists } from '@blocksuite/store'; +import Head from 'next/head'; import { useRouter } from 'next/router'; import React, { useCallback } from 'react'; @@ -50,6 +51,9 @@ const AllPage: NextPageWithLayout = () => { const PageList = WorkspacePlugins[currentWorkspace.flavour].UI.PageList; return ( <> + + {t('All Pages')} - AFFiNE + }>{t('All pages')} { const PageList = WorkspacePlugins[currentWorkspace.flavour].UI.PageList; return ( <> + + {t('All Pages')} - AFFiNE + }>{t('All pages')} { const onDeleteWorkspace = useCallback(() => { assertExists(currentWorkspace); const workspaceId = currentWorkspace.id; - helper.deleteWorkspace(workspaceId); + return helper.deleteWorkspace(workspaceId); }, [currentWorkspace, helper]); + const transformWorkspace = useTransformWorkspace(); const onTransformWorkspace = useCallback( - (targetWorkspaceId: string) => { - router - .replace({ - pathname: `/workspace/[workspaceId]/setting`, - query: { - ...router.query, - workspaceId: targetWorkspaceId, - }, - }) - .then(() => { - router.reload(); - }); + async ( + from: From, + to: To, + workspace: FlavourToWorkspace[From] + ): Promise => { + const workspaceId = await transformWorkspace(from, to, workspace); + await router.replace({ + pathname: `/workspace/[workspaceId]/setting`, + query: { + ...router.query, + workspaceId, + }, + }); }, - [router] + [router, transformWorkspace] ); if (!router.isReady) { return ; @@ -125,9 +129,9 @@ const SettingPage: NextPageWithLayout = () => { WorkspacePlugins[currentWorkspace.flavour].UI.SettingsDetail; return ( <> - + {t('Workspace Settings')} - AFFiNE - + }> {t('Workspace Settings')} @@ -145,6 +149,9 @@ const SettingPage: NextPageWithLayout = () => { WorkspacePlugins[currentWorkspace.flavour].UI.SettingsDetail; return ( <> + + {t('Workspace Settings')} - AFFiNE + }> {t('Workspace Settings')} diff --git a/apps/web/src/plugins/affine/index.tsx b/apps/web/src/plugins/affine/index.tsx index edf1960a32..090a6ba88e 100644 --- a/apps/web/src/plugins/affine/index.tsx +++ b/apps/web/src/plugins/affine/index.tsx @@ -1,6 +1,6 @@ import { createJSONStorage } from 'jotai/utils'; import React from 'react'; -import { preload } from 'swr'; +import { mutate, preload } from 'swr'; import { z } from 'zod'; import { createAffineProviders } from '../../blocksuite'; @@ -65,6 +65,7 @@ export const AffinePlugin: WorkspacePlugin = { blockSuiteWorkspace.doc ); const { id } = await apis.createWorkspace(new Blob([binary.buffer])); + await mutate(matcher => matcher === QueryKey.getWorkspaces); // refresh the local storage await AffinePlugin.CRUD.list(); return id; @@ -83,6 +84,7 @@ export const AffinePlugin: WorkspacePlugin = { await apis.deleteWorkspace({ id: workspace.id, }); + await mutate(matcher => matcher === QueryKey.getWorkspaces); }, get: async workspaceId => { try { diff --git a/apps/web/src/plugins/index.tsx b/apps/web/src/plugins/index.tsx index af8b20cd70..3f6b1b3831 100644 --- a/apps/web/src/plugins/index.tsx +++ b/apps/web/src/plugins/index.tsx @@ -1,6 +1,5 @@ import React from 'react'; -import { jotaiStore, jotaiWorkspacesAtom } from '../atoms'; import { BlockSuiteWorkspace, FlavourToWorkspace, @@ -20,7 +19,14 @@ type SettingProps = currentTab: SettingPanel; onChangeTab: (tab: SettingPanel) => void; onDeleteWorkspace: () => void; - onTransformWorkspace: (targetWorkspaceId: string) => void; + onTransformWorkspace: < + From extends RemWorkspaceFlavour, + To extends RemWorkspaceFlavour + >( + from: From, + to: To, + workspace: FlavourToWorkspace[From] + ) => void; }; type PageDetailProps = @@ -64,27 +70,3 @@ export const WorkspacePlugins = { } satisfies { [Key in RemWorkspaceFlavour]: WorkspacePlugin; }; - -/** - * Transform workspace from one flavour to another - * - * The logic here is to delete the old workspace and create a new one. - */ -export async function transformWorkspace< - From extends RemWorkspaceFlavour, - To extends RemWorkspaceFlavour ->(from: From, to: To, workspace: FlavourToWorkspace[From]): Promise { - // fixme: type cast - await WorkspacePlugins[from].CRUD.delete(workspace as any); - const newId = await WorkspacePlugins[to].CRUD.create( - workspace.blockSuiteWorkspace - ); - const workspaces = jotaiStore.get(jotaiWorkspacesAtom); - const idx = workspaces.findIndex(ws => ws.id === workspace.id); - workspaces.splice(idx, 1, { - id: newId, - flavour: to, - }); - jotaiStore.set(jotaiWorkspacesAtom, [...workspaces]); - return newId; -}