mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-13 21:05:19 +00:00
refactor: workspace loading logic (#1966)
This commit is contained in:
@@ -2,14 +2,15 @@ import '@affine/component/theme/global.css';
|
||||
|
||||
import { config, setupGlobal } from '@affine/env';
|
||||
import { createI18n, I18nextProvider } from '@affine/i18n';
|
||||
import { jotaiStore } from '@affine/workspace/atom';
|
||||
import { rootStore } from '@affine/workspace/atom';
|
||||
import type { EmotionCache } from '@emotion/cache';
|
||||
import { CacheProvider } from '@emotion/react';
|
||||
import { Provider } from 'jotai';
|
||||
import { DevTools } from 'jotai-devtools';
|
||||
import type { AppProps } from 'next/app';
|
||||
import Head from 'next/head';
|
||||
import { useRouter } from 'next/router';
|
||||
import type { ReactElement } from 'react';
|
||||
import type { PropsWithChildren, ReactElement } from 'react';
|
||||
import React, { Suspense, useEffect, useMemo } from 'react';
|
||||
|
||||
import { AffineErrorBoundary } from '../components/affine/affine-error-eoundary';
|
||||
@@ -30,6 +31,15 @@ const EmptyLayout = (page: ReactElement) => page;
|
||||
|
||||
const clientSideEmotionCache = createEmotionCache();
|
||||
|
||||
const DebugProvider = ({ children }: PropsWithChildren): ReactElement => {
|
||||
return (
|
||||
<>
|
||||
{process.env.DEBUG_JOTAI === 'true' && <DevTools />}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const App = function App({
|
||||
Component,
|
||||
pageProps,
|
||||
@@ -55,10 +65,12 @@ const App = function App({
|
||||
<Suspense fallback={<PageLoading key="RootPageLoading" />}>
|
||||
<ProviderComposer
|
||||
contexts={useMemo(
|
||||
() => [
|
||||
<Provider key="JotaiProvider" store={jotaiStore} />,
|
||||
<ThemeProvider key="ThemeProvider" />,
|
||||
],
|
||||
() =>
|
||||
[
|
||||
<Provider key="JotaiProvider" store={rootStore} />,
|
||||
<DebugProvider key="DebugProvider" />,
|
||||
<ThemeProvider key="ThemeProvider" />,
|
||||
].filter(Boolean),
|
||||
[]
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { initPage } from '@affine/env/blocksuite';
|
||||
import { useRouter } from 'next/router';
|
||||
import { lazy, Suspense } from 'react';
|
||||
|
||||
import { StyledPage, StyledWrapper } from '../../layouts/styles';
|
||||
import type { NextPageWithLayout } from '../../shared';
|
||||
import { initPage } from '../../utils';
|
||||
|
||||
const Editor = lazy(() =>
|
||||
import('../../components/__debug__/client/Editor').then(module => ({
|
||||
|
||||
@@ -5,18 +5,18 @@ import React, { Suspense, useEffect } from 'react';
|
||||
|
||||
import { PageLoading } from '../components/pure/loading';
|
||||
import { useLastWorkspaceId } from '../hooks/affine/use-last-leave-workspace-id';
|
||||
import { useCreateFirstWorkspace } from '../hooks/use-create-first-workspace';
|
||||
import { RouteLogic, useRouterHelper } from '../hooks/use-router-helper';
|
||||
import { useWorkspaces } from '../hooks/use-workspaces';
|
||||
import { useAppHelper, useWorkspaces } from '../hooks/use-workspaces';
|
||||
import { WorkspaceSubPath } from '../shared';
|
||||
|
||||
const logger = new DebugLogger('IndexPage');
|
||||
const logger = new DebugLogger('index-page');
|
||||
|
||||
const IndexPageInner = () => {
|
||||
const router = useRouter();
|
||||
const { jumpToPage, jumpToSubPath } = useRouterHelper(router);
|
||||
const workspaces = useWorkspaces();
|
||||
const lastWorkspaceId = useLastWorkspaceId();
|
||||
const helper = useAppHelper();
|
||||
|
||||
useEffect(() => {
|
||||
if (!router.isReady) {
|
||||
@@ -32,13 +32,12 @@ const IndexPageInner = () => {
|
||||
targetWorkspace.blockSuiteWorkspace.meta.pageMetas.at(0)?.id;
|
||||
if (pageId) {
|
||||
logger.debug('Found target workspace. Jump to page', pageId);
|
||||
jumpToPage(targetWorkspace.id, pageId, RouteLogic.REPLACE);
|
||||
return;
|
||||
void jumpToPage(targetWorkspace.id, pageId, RouteLogic.REPLACE);
|
||||
} else {
|
||||
const clearId = setTimeout(() => {
|
||||
dispose.dispose();
|
||||
logger.debug('Found target workspace. Jump to all pages');
|
||||
jumpToSubPath(
|
||||
void jumpToSubPath(
|
||||
targetWorkspace.id,
|
||||
WorkspaceSubPath.ALL,
|
||||
RouteLogic.REPLACE
|
||||
@@ -47,7 +46,7 @@ const IndexPageInner = () => {
|
||||
const dispose =
|
||||
targetWorkspace.blockSuiteWorkspace.slots.pageAdded.once(pageId => {
|
||||
clearTimeout(clearId);
|
||||
jumpToPage(targetWorkspace.id, pageId, RouteLogic.REPLACE);
|
||||
void jumpToPage(targetWorkspace.id, pageId, RouteLogic.REPLACE);
|
||||
});
|
||||
return () => {
|
||||
clearTimeout(clearId);
|
||||
@@ -55,19 +54,16 @@ const IndexPageInner = () => {
|
||||
};
|
||||
}
|
||||
} else {
|
||||
logger.debug('No target workspace. jump to all pages');
|
||||
// fixme: should create new workspace
|
||||
jumpToSubPath('ERROR', WorkspaceSubPath.ALL, RouteLogic.REPLACE);
|
||||
console.warn('No target workspace. This should not happen in production');
|
||||
}
|
||||
}, [jumpToPage, jumpToSubPath, lastWorkspaceId, router, workspaces]);
|
||||
}, [helper, jumpToPage, jumpToSubPath, lastWorkspaceId, router, workspaces]);
|
||||
|
||||
return <PageLoading key="IndexPageInfinitePageLoading" />;
|
||||
};
|
||||
|
||||
const IndexPage: NextPage = () => {
|
||||
useCreateFirstWorkspace();
|
||||
return (
|
||||
<Suspense fallback={<PageLoading />}>
|
||||
<Suspense fallback={<PageLoading text="Loading all workspaces" />}>
|
||||
<IndexPageInner />
|
||||
</Suspense>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Breadcrumbs, displayFlex, styled } from '@affine/component';
|
||||
import { initPage } from '@affine/env/blocksuite';
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import { PageIcon } from '@blocksuite/icons';
|
||||
import { assertExists } from '@blocksuite/store';
|
||||
@@ -25,7 +26,6 @@ import {
|
||||
PublicWorkspaceLayout,
|
||||
} from '../../../layouts/public-workspace-layout';
|
||||
import type { NextPageWithLayout } from '../../../shared';
|
||||
import { initPage } from '../../../utils';
|
||||
|
||||
export const NavContainer = styled('div')(({ theme }) => {
|
||||
return {
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
import { rootCurrentPageIdAtom } from '@affine/workspace/atom';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import { assertExists } from '@blocksuite/store';
|
||||
import { useBlockSuiteWorkspacePage } from '@toeverything/hooks/use-blocksuite-workspace-page';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useRouter } from 'next/router';
|
||||
import type React from 'react';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
|
||||
import { rootCurrentWorkspaceAtom } from '../../../atoms/root';
|
||||
import { Unreachable } from '../../../components/affine/affine-error-eoundary';
|
||||
import { PageLoading } from '../../../components/pure/loading';
|
||||
import { useReferenceLinkEffect } from '../../../hooks/affine/use-reference-link-effect';
|
||||
import { useCurrentPageId } from '../../../hooks/current/use-current-page-id';
|
||||
import { useCurrentWorkspace } from '../../../hooks/current/use-current-workspace';
|
||||
import { usePageMeta, usePageMetaHelper } from '../../../hooks/use-page-meta';
|
||||
import { usePinboardHandler } from '../../../hooks/use-pinboard-handler';
|
||||
import { useSyncRecentViewsWithRouter } from '../../../hooks/use-recent-views';
|
||||
import { useRouterAndWorkspaceWithPageIdDefense } from '../../../hooks/use-router-and-workspace-with-page-id-defense';
|
||||
import { useRouterHelper } from '../../../hooks/use-router-helper';
|
||||
import { useSyncRouterWithCurrentWorkspaceAndPage } from '../../../hooks/use-sync-router-with-current-workspace-and-page';
|
||||
import { WorkspaceLayout } from '../../../layouts';
|
||||
import { WorkspaceLayout } from '../../../layouts/workspace-layout';
|
||||
import { WorkspacePlugins } from '../../../plugins';
|
||||
import type { BlockSuiteWorkspace, NextPageWithLayout } from '../../../shared';
|
||||
|
||||
@@ -32,7 +35,7 @@ function enableFullFlags(blockSuiteWorkspace: BlockSuiteWorkspace) {
|
||||
const WorkspaceDetail: React.FC = () => {
|
||||
const router = useRouter();
|
||||
const { openPage } = useRouterHelper(router);
|
||||
const [currentPageId] = useCurrentPageId();
|
||||
const currentPageId = useAtomValue(rootCurrentPageIdAtom);
|
||||
const [currentWorkspace] = useCurrentWorkspace();
|
||||
const blockSuiteWorkspace = currentWorkspace?.blockSuiteWorkspace ?? null;
|
||||
const { setPageMeta, getPageMeta } = usePageMetaHelper(blockSuiteWorkspace);
|
||||
@@ -80,7 +83,7 @@ const WorkspaceDetail: React.FC = () => {
|
||||
return <PageLoading />;
|
||||
}
|
||||
if (!currentPageId) {
|
||||
return <PageLoading />;
|
||||
return <PageLoading text="Loading page." />;
|
||||
}
|
||||
if (currentWorkspace.flavour === WorkspaceFlavour.AFFINE) {
|
||||
const PageDetail = WorkspacePlugins[currentWorkspace.flavour].UI.PageDetail;
|
||||
@@ -104,14 +107,17 @@ const WorkspaceDetail: React.FC = () => {
|
||||
|
||||
const WorkspaceDetailPage: NextPageWithLayout = () => {
|
||||
const router = useRouter();
|
||||
useSyncRouterWithCurrentWorkspaceAndPage(router);
|
||||
const currentWorkspace = useAtomValue(rootCurrentWorkspaceAtom);
|
||||
const currentPageId = useAtomValue(rootCurrentPageIdAtom);
|
||||
useRouterAndWorkspaceWithPageIdDefense(router);
|
||||
const page = useBlockSuiteWorkspacePage(
|
||||
currentWorkspace.blockSuiteWorkspace,
|
||||
currentPageId
|
||||
);
|
||||
if (!router.isReady) {
|
||||
return <PageLoading />;
|
||||
} else if (
|
||||
typeof router.query.pageId !== 'string' ||
|
||||
typeof router.query.workspaceId !== 'string'
|
||||
) {
|
||||
throw new Error('Invalid router query');
|
||||
return <PageLoading text="Router is loading" />;
|
||||
} else if (!currentPageId || !page) {
|
||||
return <PageLoading text="Page is loading" />;
|
||||
}
|
||||
return <WorkspaceDetail />;
|
||||
};
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { useTranslation } from '@affine/i18n';
|
||||
import type { LocalIndexedDBProvider } from '@affine/workspace/type';
|
||||
import { WorkspaceFlavour } from '@affine/workspace/type';
|
||||
import { FolderIcon } from '@blocksuite/icons';
|
||||
import { assertEquals, assertExists, nanoid } from '@blocksuite/store';
|
||||
import { assertExists } from '@blocksuite/store';
|
||||
import Head from 'next/head';
|
||||
import { useRouter } from 'next/router';
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import React, { useCallback } from 'react';
|
||||
|
||||
import {
|
||||
QueryParamError,
|
||||
@@ -15,56 +14,17 @@ import { PageLoading } from '../../../components/pure/loading';
|
||||
import { WorkspaceTitle } from '../../../components/pure/workspace-title';
|
||||
import { useCurrentWorkspace } from '../../../hooks/current/use-current-workspace';
|
||||
import { useRouterHelper } from '../../../hooks/use-router-helper';
|
||||
import { useSyncRouterWithCurrentWorkspace } from '../../../hooks/use-sync-router-with-current-workspace';
|
||||
import { WorkspaceLayout } from '../../../layouts';
|
||||
import { useSyncRouterWithCurrentWorkspaceId } from '../../../hooks/use-sync-router-with-current-workspace-id';
|
||||
import { WorkspaceLayout } from '../../../layouts/workspace-layout';
|
||||
import { WorkspacePlugins } from '../../../plugins';
|
||||
import type { NextPageWithLayout } from '../../../shared';
|
||||
import { ensureRootPinboard } from '../../../utils';
|
||||
|
||||
const AllPage: NextPageWithLayout = () => {
|
||||
const router = useRouter();
|
||||
const { jumpToPage } = useRouterHelper(router);
|
||||
const [currentWorkspace] = useCurrentWorkspace();
|
||||
const { t } = useTranslation();
|
||||
useSyncRouterWithCurrentWorkspace(router);
|
||||
useEffect(() => {
|
||||
if (!router.isReady) {
|
||||
return;
|
||||
}
|
||||
if (!currentWorkspace) {
|
||||
return;
|
||||
}
|
||||
if (currentWorkspace.flavour !== WorkspaceFlavour.LOCAL) {
|
||||
// only create a new page for local workspace
|
||||
// just ensure the root pinboard exists
|
||||
ensureRootPinboard(currentWorkspace.blockSuiteWorkspace);
|
||||
return;
|
||||
}
|
||||
const localProvider = currentWorkspace.providers.find(
|
||||
provider => provider.flavour === 'local-indexeddb'
|
||||
);
|
||||
if (localProvider && localProvider.flavour === 'local-indexeddb') {
|
||||
const provider = localProvider as LocalIndexedDBProvider;
|
||||
const callback = () => {
|
||||
if (currentWorkspace.blockSuiteWorkspace.isEmpty) {
|
||||
// this is a new workspace, so we should redirect to the new page
|
||||
const pageId = nanoid();
|
||||
const page = currentWorkspace.blockSuiteWorkspace.createPage(pageId);
|
||||
assertEquals(page.id, pageId);
|
||||
currentWorkspace.blockSuiteWorkspace.setPageMeta(page.id, {
|
||||
init: true,
|
||||
});
|
||||
jumpToPage(currentWorkspace.id, pageId);
|
||||
}
|
||||
// no matter workspace is empty, ensure the root pinboard exists
|
||||
ensureRootPinboard(currentWorkspace.blockSuiteWorkspace);
|
||||
};
|
||||
provider.callbacks.add(callback);
|
||||
return () => {
|
||||
provider.callbacks.delete(callback);
|
||||
};
|
||||
}
|
||||
}, [currentWorkspace, jumpToPage, router]);
|
||||
useSyncRouterWithCurrentWorkspaceId(router);
|
||||
const onClickPage = useCallback(
|
||||
(pageId: string, newTab?: boolean) => {
|
||||
assertExists(currentWorkspace);
|
||||
|
||||
@@ -10,8 +10,8 @@ import { PageLoading } from '../../../components/pure/loading';
|
||||
import { WorkspaceTitle } from '../../../components/pure/workspace-title';
|
||||
import { useCurrentWorkspace } from '../../../hooks/current/use-current-workspace';
|
||||
import { useRouterHelper } from '../../../hooks/use-router-helper';
|
||||
import { useSyncRouterWithCurrentWorkspace } from '../../../hooks/use-sync-router-with-current-workspace';
|
||||
import { WorkspaceLayout } from '../../../layouts';
|
||||
import { useSyncRouterWithCurrentWorkspaceId } from '../../../hooks/use-sync-router-with-current-workspace-id';
|
||||
import { WorkspaceLayout } from '../../../layouts/workspace-layout';
|
||||
import type { NextPageWithLayout } from '../../../shared';
|
||||
|
||||
const FavouritePage: NextPageWithLayout = () => {
|
||||
@@ -19,7 +19,7 @@ const FavouritePage: NextPageWithLayout = () => {
|
||||
const { jumpToPage } = useRouterHelper(router);
|
||||
const [currentWorkspace] = useCurrentWorkspace();
|
||||
const { t } = useTranslation();
|
||||
useSyncRouterWithCurrentWorkspace(router);
|
||||
useSyncRouterWithCurrentWorkspaceId(router);
|
||||
const onClickPage = useCallback(
|
||||
(pageId: string, newTab?: boolean) => {
|
||||
assertExists(currentWorkspace);
|
||||
|
||||
@@ -18,9 +18,9 @@ import { PageLoading } from '../../../components/pure/loading';
|
||||
import { WorkspaceTitle } from '../../../components/pure/workspace-title';
|
||||
import { useCurrentWorkspace } from '../../../hooks/current/use-current-workspace';
|
||||
import { useOnTransformWorkspace } from '../../../hooks/root/use-on-transform-workspace';
|
||||
import { useSyncRouterWithCurrentWorkspace } from '../../../hooks/use-sync-router-with-current-workspace';
|
||||
import { useWorkspacesHelper } from '../../../hooks/use-workspaces';
|
||||
import { WorkspaceLayout } from '../../../layouts';
|
||||
import { useSyncRouterWithCurrentWorkspaceId } from '../../../hooks/use-sync-router-with-current-workspace-id';
|
||||
import { useAppHelper } from '../../../hooks/use-workspaces';
|
||||
import { WorkspaceLayout } from '../../../layouts/workspace-layout';
|
||||
import { WorkspacePlugins } from '../../../plugins';
|
||||
import type { NextPageWithLayout } from '../../../shared';
|
||||
|
||||
@@ -33,7 +33,7 @@ const SettingPage: NextPageWithLayout = () => {
|
||||
const router = useRouter();
|
||||
const [currentWorkspace] = useCurrentWorkspace();
|
||||
const { t } = useTranslation();
|
||||
useSyncRouterWithCurrentWorkspace(router);
|
||||
useSyncRouterWithCurrentWorkspaceId(router);
|
||||
const [currentTab, setCurrentTab] = useAtom(settingPanelAtom);
|
||||
useEffect(() => {});
|
||||
const onChangeTab = useCallback(
|
||||
@@ -92,7 +92,7 @@ const SettingPage: NextPageWithLayout = () => {
|
||||
}
|
||||
}, [currentTab, router, setCurrentTab]);
|
||||
|
||||
const helper = useWorkspacesHelper();
|
||||
const helper = useAppHelper();
|
||||
|
||||
const onDeleteWorkspace = useCallback(() => {
|
||||
assertExists(currentWorkspace);
|
||||
|
||||
@@ -10,8 +10,8 @@ import { PageLoading } from '../../../components/pure/loading';
|
||||
import { WorkspaceTitle } from '../../../components/pure/workspace-title';
|
||||
import { useCurrentWorkspace } from '../../../hooks/current/use-current-workspace';
|
||||
import { useRouterHelper } from '../../../hooks/use-router-helper';
|
||||
import { useSyncRouterWithCurrentWorkspace } from '../../../hooks/use-sync-router-with-current-workspace';
|
||||
import { WorkspaceLayout } from '../../../layouts';
|
||||
import { useSyncRouterWithCurrentWorkspaceId } from '../../../hooks/use-sync-router-with-current-workspace-id';
|
||||
import { WorkspaceLayout } from '../../../layouts/workspace-layout';
|
||||
import type { NextPageWithLayout } from '../../../shared';
|
||||
|
||||
const SharedPages: NextPageWithLayout = () => {
|
||||
@@ -19,7 +19,7 @@ const SharedPages: NextPageWithLayout = () => {
|
||||
const { jumpToPage } = useRouterHelper(router);
|
||||
const [currentWorkspace] = useCurrentWorkspace();
|
||||
const { t } = useTranslation();
|
||||
useSyncRouterWithCurrentWorkspace(router);
|
||||
useSyncRouterWithCurrentWorkspaceId(router);
|
||||
const onClickPage = useCallback(
|
||||
(pageId: string, newTab?: boolean) => {
|
||||
assertExists(currentWorkspace);
|
||||
|
||||
@@ -10,8 +10,8 @@ import { PageLoading } from '../../../components/pure/loading';
|
||||
import { WorkspaceTitle } from '../../../components/pure/workspace-title';
|
||||
import { useCurrentWorkspace } from '../../../hooks/current/use-current-workspace';
|
||||
import { useRouterHelper } from '../../../hooks/use-router-helper';
|
||||
import { useSyncRouterWithCurrentWorkspace } from '../../../hooks/use-sync-router-with-current-workspace';
|
||||
import { WorkspaceLayout } from '../../../layouts';
|
||||
import { useSyncRouterWithCurrentWorkspaceId } from '../../../hooks/use-sync-router-with-current-workspace-id';
|
||||
import { WorkspaceLayout } from '../../../layouts/workspace-layout';
|
||||
import type { NextPageWithLayout } from '../../../shared';
|
||||
|
||||
const TrashPage: NextPageWithLayout = () => {
|
||||
@@ -19,7 +19,7 @@ const TrashPage: NextPageWithLayout = () => {
|
||||
const { jumpToPage } = useRouterHelper(router);
|
||||
const [currentWorkspace] = useCurrentWorkspace();
|
||||
const { t } = useTranslation();
|
||||
useSyncRouterWithCurrentWorkspace(router);
|
||||
useSyncRouterWithCurrentWorkspaceId(router);
|
||||
const onClickPage = useCallback(
|
||||
(pageId: string, newTab?: boolean) => {
|
||||
assertExists(currentWorkspace);
|
||||
|
||||
Reference in New Issue
Block a user