mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-08 04:36:13 +08:00
refactor(infra): migrate to new infra (#5565)
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import { Menu } from '@affine/component/ui/menu';
|
||||
import { WorkspaceFallback } from '@affine/component/workspace';
|
||||
import { workspaceListAtom } from '@affine/core/modules/workspace';
|
||||
import { WorkspaceSubPath } from '@affine/core/shared';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { WorkspaceManager } from '@toeverything/infra';
|
||||
import { WorkspaceListService } from '@toeverything/infra';
|
||||
import { useService } from '@toeverything/infra';
|
||||
import { useLiveData } from '@toeverything/infra';
|
||||
import { lazy, useEffect, useLayoutEffect, useState } from 'react';
|
||||
import { type LoaderFunction, redirect } from 'react-router-dom';
|
||||
|
||||
@@ -10,6 +11,7 @@ import { createFirstAppData } from '../bootstrap/first-app-data';
|
||||
import { UserWithWorkspaceList } from '../components/pure/workspace-slider-bar/user-with-workspace-list';
|
||||
import { appConfigStorage } from '../hooks/use-app-config-storage';
|
||||
import { useNavigateHelper } from '../hooks/use-navigate-helper';
|
||||
import { WorkspaceSubPath } from '../shared';
|
||||
|
||||
const AllWorkspaceModals = lazy(() =>
|
||||
import('../providers/modal-provider').then(({ AllWorkspaceModals }) => ({
|
||||
@@ -29,7 +31,7 @@ export const Component = () => {
|
||||
const [navigating, setNavigating] = useState(false);
|
||||
const [creating, setCreating] = useState(false);
|
||||
|
||||
const list = useAtomValue(workspaceListAtom);
|
||||
const list = useLiveData(useService(WorkspaceListService).workspaceList);
|
||||
const { openPage } = useNavigateHelper();
|
||||
|
||||
useLayoutEffect(() => {
|
||||
@@ -44,16 +46,18 @@ export const Component = () => {
|
||||
setNavigating(true);
|
||||
}, [list, openPage]);
|
||||
|
||||
const workspaceManager = useService(WorkspaceManager);
|
||||
|
||||
useEffect(() => {
|
||||
setCreating(true);
|
||||
createFirstAppData()
|
||||
createFirstAppData(workspaceManager)
|
||||
.catch(err => {
|
||||
console.error('Failed to create first app data', err);
|
||||
})
|
||||
.finally(() => {
|
||||
setCreating(false);
|
||||
});
|
||||
}, []);
|
||||
}, [workspaceManager]);
|
||||
|
||||
if (navigating || creating) {
|
||||
return <WorkspaceFallback></WorkspaceFallback>;
|
||||
|
||||
@@ -1,17 +1,27 @@
|
||||
import { MainContainer } from '@affine/component/workspace';
|
||||
import { usePageDocumentTitle } from '@affine/core/hooks/use-global-state';
|
||||
import { DebugLogger } from '@affine/debug';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { fetchWithTraceReport } from '@affine/graphql';
|
||||
import { globalBlockSuiteSchema } from '@affine/workspace';
|
||||
import {
|
||||
createAffineCloudBlobStorage,
|
||||
createStaticBlobStorage,
|
||||
AffineCloudBlobStorage,
|
||||
StaticBlobStorage,
|
||||
} from '@affine/workspace-impl';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import { type Page, Workspace } from '@blocksuite/store';
|
||||
import {
|
||||
EmptyBlobStorage,
|
||||
LocalBlobStorage,
|
||||
LocalSyncStorage,
|
||||
Page,
|
||||
PageManager,
|
||||
ReadonlyMappingSyncStorage,
|
||||
RemoteBlobStorage,
|
||||
useService,
|
||||
useServiceOptional,
|
||||
WorkspaceIdContext,
|
||||
WorkspaceManager,
|
||||
WorkspaceScope,
|
||||
} from '@toeverything/infra';
|
||||
import { noop } from 'foxact/noop';
|
||||
import type { ReactElement } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import type { LoaderFunction } from 'react-router-dom';
|
||||
import {
|
||||
isRouteErrorResponse,
|
||||
@@ -19,12 +29,13 @@ import {
|
||||
useLoaderData,
|
||||
useRouteError,
|
||||
} from 'react-router-dom';
|
||||
import { applyUpdate } from 'yjs';
|
||||
|
||||
import type { PageMode } from '../../atoms';
|
||||
import { AppContainer } from '../../components/affine/app-container';
|
||||
import { PageDetailEditor } from '../../components/page-detail-editor';
|
||||
import { SharePageNotFoundError } from '../../components/share-page-not-found-error';
|
||||
import { CurrentPageService } from '../../modules/page';
|
||||
import { CurrentWorkspaceService } from '../../modules/workspace';
|
||||
import { ShareHeader } from './share-header';
|
||||
|
||||
type DocPublishMode = 'edgeless' | 'page';
|
||||
@@ -57,8 +68,11 @@ export async function downloadBinaryFromCloud(
|
||||
}
|
||||
|
||||
type LoaderData = {
|
||||
page: Page;
|
||||
pageId: string;
|
||||
workspaceId: string;
|
||||
publishMode: PageMode;
|
||||
pageArrayBuffer: ArrayBuffer;
|
||||
workspaceArrayBuffer: ArrayBuffer;
|
||||
};
|
||||
|
||||
function assertDownloadResponse(
|
||||
@@ -73,55 +87,104 @@ function assertDownloadResponse(
|
||||
}
|
||||
}
|
||||
|
||||
const logger = new DebugLogger('public:share-page');
|
||||
|
||||
export const loader: LoaderFunction = async ({ params }) => {
|
||||
const workspaceId = params?.workspaceId;
|
||||
const pageId = params?.pageId;
|
||||
if (!workspaceId || !pageId) {
|
||||
return redirect('/404');
|
||||
}
|
||||
const workspace = new Workspace({
|
||||
id: workspaceId,
|
||||
blobStorages: [
|
||||
() => ({
|
||||
crud: createAffineCloudBlobStorage(workspaceId),
|
||||
}),
|
||||
() => ({
|
||||
crud: createStaticBlobStorage(),
|
||||
}),
|
||||
],
|
||||
schema: globalBlockSuiteSchema,
|
||||
});
|
||||
// download root workspace
|
||||
{
|
||||
const response = await downloadBinaryFromCloud(workspaceId, workspaceId);
|
||||
assertDownloadResponse(response);
|
||||
const { arrayBuffer } = response;
|
||||
applyUpdate(workspace.doc, new Uint8Array(arrayBuffer));
|
||||
workspace.doc.emit('sync', []);
|
||||
}
|
||||
const page = workspace.getPage(pageId);
|
||||
assertExists(page, 'cannot find page');
|
||||
// download page
|
||||
|
||||
const response = await downloadBinaryFromCloud(
|
||||
const [workspaceResponse, pageResponse] = await Promise.all([
|
||||
downloadBinaryFromCloud(workspaceId, workspaceId),
|
||||
downloadBinaryFromCloud(workspaceId, pageId),
|
||||
]);
|
||||
assertDownloadResponse(workspaceResponse);
|
||||
const { arrayBuffer: workspaceArrayBuffer } = workspaceResponse;
|
||||
assertDownloadResponse(pageResponse);
|
||||
const { arrayBuffer: pageArrayBuffer, publishMode } = pageResponse;
|
||||
|
||||
return {
|
||||
workspaceId,
|
||||
page.spaceDoc.guid
|
||||
);
|
||||
assertDownloadResponse(response);
|
||||
const { arrayBuffer, publishMode } = response;
|
||||
|
||||
applyUpdate(page.spaceDoc, new Uint8Array(arrayBuffer));
|
||||
|
||||
logger.info('workspace', workspace);
|
||||
workspace.awarenessStore.setReadonly(page, true);
|
||||
return { page, publishMode };
|
||||
pageId,
|
||||
publishMode,
|
||||
workspaceArrayBuffer,
|
||||
pageArrayBuffer,
|
||||
} satisfies LoaderData;
|
||||
};
|
||||
|
||||
export const Component = (): ReactElement => {
|
||||
const { page, publishMode } = useLoaderData() as LoaderData;
|
||||
usePageDocumentTitle(page.meta);
|
||||
export const Component = () => {
|
||||
const {
|
||||
workspaceId,
|
||||
pageId,
|
||||
publishMode,
|
||||
workspaceArrayBuffer,
|
||||
pageArrayBuffer,
|
||||
} = useLoaderData() as LoaderData;
|
||||
const workspaceManager = useService(WorkspaceManager);
|
||||
|
||||
const currentWorkspace = useService(CurrentWorkspaceService);
|
||||
|
||||
useEffect(() => {
|
||||
// create a workspace for share page
|
||||
const workspace = workspaceManager.instantiate(
|
||||
{
|
||||
id: workspaceId,
|
||||
flavour: WorkspaceFlavour.AFFINE_CLOUD,
|
||||
},
|
||||
services => {
|
||||
services
|
||||
.scope(WorkspaceScope)
|
||||
.addImpl(LocalBlobStorage, EmptyBlobStorage)
|
||||
.addImpl(RemoteBlobStorage('affine'), AffineCloudBlobStorage, [
|
||||
WorkspaceIdContext,
|
||||
])
|
||||
.addImpl(RemoteBlobStorage('static'), StaticBlobStorage)
|
||||
.addImpl(
|
||||
LocalSyncStorage,
|
||||
ReadonlyMappingSyncStorage({
|
||||
[workspaceId]: new Uint8Array(workspaceArrayBuffer),
|
||||
[pageId]: new Uint8Array(pageArrayBuffer),
|
||||
})
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
workspace.engine.sync
|
||||
.waitForSynced()
|
||||
.then(() => {
|
||||
const { page } = workspace.services
|
||||
.get(PageManager)
|
||||
.openByPageId(pageId);
|
||||
|
||||
workspace.blockSuiteWorkspace.awarenessStore.setReadonly(
|
||||
page.blockSuitePage,
|
||||
true
|
||||
);
|
||||
|
||||
const currentPage = workspace.services.get(CurrentPageService);
|
||||
|
||||
currentWorkspace.openWorkspace(workspace);
|
||||
currentPage.openPage(page);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
});
|
||||
}, [
|
||||
currentWorkspace,
|
||||
pageArrayBuffer,
|
||||
pageId,
|
||||
workspaceArrayBuffer,
|
||||
workspaceId,
|
||||
workspaceManager,
|
||||
]);
|
||||
|
||||
const page = useServiceOptional(Page);
|
||||
|
||||
usePageDocumentTitle(page?.meta);
|
||||
|
||||
if (!page) {
|
||||
return;
|
||||
}
|
||||
|
||||
return (
|
||||
<AppContainer>
|
||||
@@ -129,14 +192,14 @@ export const Component = (): ReactElement => {
|
||||
<ShareHeader
|
||||
pageId={page.id}
|
||||
publishMode={publishMode}
|
||||
blockSuiteWorkspace={page.workspace}
|
||||
blockSuiteWorkspace={page.blockSuitePage.workspace}
|
||||
/>
|
||||
<PageDetailEditor
|
||||
isPublic
|
||||
publishMode={publishMode}
|
||||
workspace={page.workspace}
|
||||
workspace={page.blockSuitePage.workspace}
|
||||
pageId={page.id}
|
||||
onLoad={useCallback(() => noop, [])}
|
||||
onLoad={() => noop}
|
||||
/>
|
||||
</MainContainer>
|
||||
</AppContainer>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { waitForCurrentWorkspaceAtom } from '@affine/core/modules/workspace';
|
||||
import { CollectionService } from '@affine/core/modules/collection';
|
||||
import type { Collection, Filter } from '@affine/env/filter';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useService } from '@toeverything/infra';
|
||||
import { Workspace } from '@toeverything/infra';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { collectionsCRUDAtom } from '../../../atoms/collections';
|
||||
import { filterContainerStyle } from '../../../components/filter-container.css';
|
||||
import {
|
||||
FilterList,
|
||||
@@ -13,9 +13,9 @@ import {
|
||||
import { useNavigateHelper } from '../../../hooks/use-navigate-helper';
|
||||
|
||||
export const FilterContainer = () => {
|
||||
const currentWorkspace = useAtomValue(waitForCurrentWorkspaceAtom);
|
||||
const currentWorkspace = useService(Workspace);
|
||||
const navigateHelper = useNavigateHelper();
|
||||
const setting = useCollectionManager(collectionsCRUDAtom);
|
||||
const setting = useCollectionManager(useService(CollectionService));
|
||||
const saveToCollection = useCallback(
|
||||
(collection: Collection) => {
|
||||
setting.createCollection({
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { IconButton } from '@affine/component';
|
||||
import type { AllPageFilterOption } from '@affine/core/atoms';
|
||||
import { collectionsCRUDAtom } from '@affine/core/atoms/collections';
|
||||
import {
|
||||
CollectionList,
|
||||
PageListNewPageButton,
|
||||
@@ -13,9 +12,11 @@ import { useAllPageListConfig } from '@affine/core/hooks/affine/use-all-page-lis
|
||||
import { useDeleteCollectionInfo } from '@affine/core/hooks/affine/use-delete-collection-info';
|
||||
import { PlusIcon } from '@blocksuite/icons';
|
||||
import type { Workspace } from '@blocksuite/store';
|
||||
import { useService } from '@toeverything/infra/di';
|
||||
import clsx from 'clsx';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { CollectionService } from '../../../modules/collection';
|
||||
import * as styles from './all-page.css';
|
||||
import { FilterContainer } from './all-page-filter';
|
||||
|
||||
@@ -32,7 +33,7 @@ export const AllPageHeader = ({
|
||||
activeFilter: AllPageFilterOption;
|
||||
onCreateCollection?: () => void;
|
||||
}) => {
|
||||
const setting = useCollectionManager(collectionsCRUDAtom);
|
||||
const setting = useCollectionManager(useService(CollectionService));
|
||||
const config = useAllPageListConfig();
|
||||
const userInfo = useDeleteCollectionInfo();
|
||||
const isWindowsDesktop = environment.isDesktop && environment.isWindows;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import type { AllPageFilterOption } from '@affine/core/atoms';
|
||||
import { collectionsCRUDAtom } from '@affine/core/atoms/collections';
|
||||
import { HubIsland } from '@affine/core/components/affine/hub-island';
|
||||
import {
|
||||
CollectionListHeader,
|
||||
@@ -10,7 +9,6 @@ import {
|
||||
useCollectionManager,
|
||||
useEditCollectionName,
|
||||
useFilteredPageMetas,
|
||||
useSavedCollections,
|
||||
useTagMetas,
|
||||
VirtualizedCollectionList,
|
||||
VirtualizedPageList,
|
||||
@@ -22,15 +20,18 @@ import {
|
||||
import { useAllPageListConfig } from '@affine/core/hooks/affine/use-all-page-list-config';
|
||||
import { useBlockSuitePageMeta } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper';
|
||||
import { waitForCurrentWorkspaceAtom } from '@affine/core/modules/workspace';
|
||||
import { performanceRenderLogger } from '@affine/core/shared';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useAtomValue, useSetAtom } from 'jotai';
|
||||
import { useService } from '@toeverything/infra';
|
||||
import { useLiveData } from '@toeverything/infra';
|
||||
import { Workspace } from '@toeverything/infra';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useLocation, useParams } from 'react-router-dom';
|
||||
import { NIL } from 'uuid';
|
||||
|
||||
import { CollectionService } from '../../../modules/collection';
|
||||
import {
|
||||
EmptyCollectionList,
|
||||
EmptyPageList,
|
||||
@@ -47,13 +48,14 @@ export const AllPage = ({
|
||||
}) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const params = useParams();
|
||||
const currentWorkspace = useAtomValue(waitForCurrentWorkspaceAtom);
|
||||
const currentWorkspace = useService(Workspace);
|
||||
const pageMetas = useBlockSuitePageMeta(currentWorkspace.blockSuiteWorkspace);
|
||||
const [hideHeaderCreateNew, setHideHeaderCreateNew] = useState(true);
|
||||
|
||||
const setting = useCollectionManager(collectionsCRUDAtom);
|
||||
const collectionService = useService(CollectionService);
|
||||
const collections = useLiveData(collectionService.collections);
|
||||
const setting = useCollectionManager(collectionService);
|
||||
const config = useAllPageListConfig();
|
||||
const { collections } = useSavedCollections(collectionsCRUDAtom);
|
||||
const { tags, tagMetas, filterPageMetaByTag, deleteTags } = useTagMetas(
|
||||
currentWorkspace.blockSuiteWorkspace,
|
||||
pageMetas
|
||||
@@ -212,7 +214,7 @@ export const AllPage = ({
|
||||
export const Component = () => {
|
||||
performanceRenderLogger.info('AllPage');
|
||||
|
||||
const currentWorkspace = useAtomValue(waitForCurrentWorkspaceAtom);
|
||||
const currentWorkspace = useService(Workspace);
|
||||
const currentCollection = useSetAtom(currentCollectionAtom);
|
||||
const navigateHelper = useNavigateHelper();
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
import { WindowsAppControls } from '@affine/core/components/pure/header/windows-app-controls';
|
||||
import { useAllPageListConfig } from '@affine/core/hooks/affine/use-all-page-list-config';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { waitForCurrentWorkspaceAtom } from '@affine/core/modules/workspace';
|
||||
import { CollectionService } from '@affine/core/modules/collection';
|
||||
import type { Collection } from '@affine/env/filter';
|
||||
import { Trans } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
@@ -22,19 +22,17 @@ import {
|
||||
PageIcon,
|
||||
ViewLayersIcon,
|
||||
} from '@blocksuite/icons';
|
||||
import { Workspace } from '@toeverything/infra';
|
||||
import { getCurrentStore } from '@toeverything/infra/atom';
|
||||
import { useService } from '@toeverything/infra/di';
|
||||
import { useLiveData } from '@toeverything/infra/livedata';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { type LoaderFunction, redirect, useParams } from 'react-router-dom';
|
||||
|
||||
import {
|
||||
collectionsCRUDAtom,
|
||||
pageCollectionBaseAtom,
|
||||
} from '../../atoms/collections';
|
||||
import { useNavigateHelper } from '../../hooks/use-navigate-helper';
|
||||
import { WorkspaceSubPath } from '../../shared';
|
||||
import { getWorkspaceSetting } from '../../utils/workspace-setting';
|
||||
import { AllPage } from './all-page/all-page';
|
||||
import * as styles from './collection.css';
|
||||
|
||||
@@ -48,18 +46,19 @@ export const loader: LoaderFunction = async args => {
|
||||
};
|
||||
|
||||
export const Component = function CollectionPage() {
|
||||
const { collections, loading } = useAtomValue(pageCollectionBaseAtom);
|
||||
const collectionService = useService(CollectionService);
|
||||
const collections = useLiveData(collectionService.collections);
|
||||
const navigate = useNavigateHelper();
|
||||
const params = useParams();
|
||||
const workspace = useAtomValue(waitForCurrentWorkspaceAtom);
|
||||
const workspace = useService(Workspace);
|
||||
const collection = collections.find(v => v.id === params.collectionId);
|
||||
const pushNotification = useSetAtom(pushNotificationAtom);
|
||||
useEffect(() => {
|
||||
if (!loading && !collection) {
|
||||
if (!collection) {
|
||||
navigate.jumpToSubPath(workspace.id, WorkspaceSubPath.ALL);
|
||||
const collection = getWorkspaceSetting(
|
||||
workspace.blockSuiteWorkspace
|
||||
).collectionsTrash.find(v => v.collection.id === params.collectionId);
|
||||
const collection = collectionService.collectionsTrash.value.find(
|
||||
v => v.collection.id === params.collectionId
|
||||
);
|
||||
let text = 'Collection is not exist';
|
||||
if (collection) {
|
||||
if (collection.userId) {
|
||||
@@ -75,21 +74,18 @@ export const Component = function CollectionPage() {
|
||||
}
|
||||
}, [
|
||||
collection,
|
||||
loading,
|
||||
collectionService.collectionsTrash.value,
|
||||
navigate,
|
||||
params.collectionId,
|
||||
pushNotification,
|
||||
workspace.blockSuiteWorkspace,
|
||||
workspace.id,
|
||||
]);
|
||||
if (loading) {
|
||||
return null;
|
||||
}
|
||||
if (!collection) {
|
||||
return null;
|
||||
}
|
||||
return isEmpty(collection) ? (
|
||||
<Placeholder collection={collection} workspaceId={workspace.id} />
|
||||
<Placeholder collection={collection} />
|
||||
) : (
|
||||
<AllPage activeFilter="collections" />
|
||||
);
|
||||
@@ -97,24 +93,19 @@ export const Component = function CollectionPage() {
|
||||
|
||||
const isWindowsDesktop = environment.isDesktop && environment.isWindows;
|
||||
|
||||
const Placeholder = ({
|
||||
collection,
|
||||
workspaceId,
|
||||
}: {
|
||||
collection: Collection;
|
||||
workspaceId: string;
|
||||
}) => {
|
||||
const { updateCollection } = useCollectionManager(collectionsCRUDAtom);
|
||||
const Placeholder = ({ collection }: { collection: Collection }) => {
|
||||
const workspace = useService(Workspace);
|
||||
const collectionService = useCollectionManager(useService(CollectionService));
|
||||
const { node, open } = useEditCollection(useAllPageListConfig());
|
||||
const { jumpToCollections } = useNavigateHelper();
|
||||
const openPageEdit = useAsyncCallback(async () => {
|
||||
const ret = await open({ ...collection }, 'page');
|
||||
updateCollection(ret);
|
||||
}, [open, collection, updateCollection]);
|
||||
collectionService.updateCollection(ret);
|
||||
}, [open, collection, collectionService]);
|
||||
const openRuleEdit = useAsyncCallback(async () => {
|
||||
const ret = await open({ ...collection }, 'rule');
|
||||
updateCollection(ret);
|
||||
}, [collection, open, updateCollection]);
|
||||
collectionService.updateCollection(ret);
|
||||
}, [collection, open, collectionService]);
|
||||
const [showTips, setShowTips] = useState(false);
|
||||
useEffect(() => {
|
||||
setShowTips(!localStorage.getItem('hide-empty-collection-help-info'));
|
||||
@@ -127,8 +118,8 @@ const Placeholder = ({
|
||||
const leftSidebarOpen = useAtomValue(appSidebarOpenAtom);
|
||||
|
||||
const handleJumpToCollections = useCallback(() => {
|
||||
jumpToCollections(workspaceId);
|
||||
}, [jumpToCollections, workspaceId]);
|
||||
jumpToCollections(workspace.id);
|
||||
}, [jumpToCollections, workspace]);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
@@ -11,9 +11,9 @@ import { JournalTodayButton } from '@affine/core/components/blocksuite/block-sui
|
||||
import { PageHeaderMenuButton } from '@affine/core/components/blocksuite/block-suite-header/menu';
|
||||
import { EditorModeSwitch } from '@affine/core/components/blocksuite/block-suite-mode-switch';
|
||||
import { useJournalInfoHelper } from '@affine/core/hooks/use-journal';
|
||||
import type { Workspace } from '@affine/workspace';
|
||||
import { RightSidebarIcon } from '@blocksuite/icons';
|
||||
import type { Page } from '@blocksuite/store';
|
||||
import type { Workspace } from '@toeverything/infra';
|
||||
import { useAtomValue, useSetAtom } from 'jotai';
|
||||
import { useCallback, useRef } from 'react';
|
||||
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
import { PageDetailSkeleton } from '@affine/component/page-detail-skeleton';
|
||||
import { ResizePanel } from '@affine/component/resize-panel';
|
||||
import { useBlockSuitePageMeta } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { useWorkspaceStatus } from '@affine/core/hooks/use-workspace-status';
|
||||
import { waitForCurrentWorkspaceAtom } from '@affine/core/modules/workspace';
|
||||
import { WorkspaceSubPath } from '@affine/core/shared';
|
||||
import { globalBlockSuiteSchema, SyncEngineStep } from '@affine/workspace';
|
||||
import { CollectionService } from '@affine/core/modules/collection';
|
||||
import {
|
||||
BookmarkService,
|
||||
customImageProxyMiddleware,
|
||||
ImageService,
|
||||
} from '@blocksuite/blocks';
|
||||
import type { AffineEditorContainer } from '@blocksuite/presets';
|
||||
import type { Page, Workspace } from '@blocksuite/store';
|
||||
import { appSettingAtom } from '@toeverything/infra/atom';
|
||||
import type { Page as BlockSuitePage } from '@blocksuite/store';
|
||||
import {
|
||||
globalBlockSuiteSchema,
|
||||
Page,
|
||||
PageListService,
|
||||
PageManager,
|
||||
useLiveData,
|
||||
useServiceOptional,
|
||||
} from '@toeverything/infra';
|
||||
import { appSettingAtom, Workspace } from '@toeverything/infra';
|
||||
import { useService } from '@toeverything/infra';
|
||||
import { useAtom, useAtomValue, useSetAtom } from 'jotai';
|
||||
import {
|
||||
memo,
|
||||
@@ -20,13 +26,12 @@ import {
|
||||
type ReactNode,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useState,
|
||||
useMemo,
|
||||
} from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import type { Map as YMap } from 'yjs';
|
||||
|
||||
import { setPageModeAtom } from '../../../atoms';
|
||||
import { collectionsCRUDAtom } from '../../../atoms/collections';
|
||||
import { currentModeAtom, currentPageIdAtom } from '../../../atoms/mode';
|
||||
import { AffineErrorBoundary } from '../../../components/affine/affine-error-boundary';
|
||||
import { HubIsland } from '../../../components/affine/hub-island';
|
||||
@@ -42,7 +47,8 @@ import { TopTip } from '../../../components/top-tip';
|
||||
import { useRegisterBlocksuiteEditorCommands } from '../../../hooks/affine/use-register-blocksuite-editor-commands';
|
||||
import { usePageDocumentTitle } from '../../../hooks/use-global-state';
|
||||
import { useNavigateHelper } from '../../../hooks/use-navigate-helper';
|
||||
import { performanceRenderLogger } from '../../../shared';
|
||||
import { CurrentPageService } from '../../../modules/page';
|
||||
import { performanceRenderLogger, WorkspaceSubPath } from '../../../shared';
|
||||
import { PageNotFound } from '../../404';
|
||||
import * as styles from './detail-page.css';
|
||||
import { DetailPageHeader, RightSidebarHeader } from './detail-page-header';
|
||||
@@ -104,10 +110,11 @@ const DetailPageLayout = ({
|
||||
);
|
||||
};
|
||||
|
||||
const DetailPageImpl = memo(function DetailPageImpl({ page }: { page: Page }) {
|
||||
const DetailPageImpl = memo(function DetailPageImpl() {
|
||||
const page = useService(Page);
|
||||
const currentPageId = page.id;
|
||||
const { openPage, jumpToSubPath } = useNavigateHelper();
|
||||
const currentWorkspace = useAtomValue(waitForCurrentWorkspaceAtom);
|
||||
const currentWorkspace = useService(Workspace);
|
||||
const blockSuiteWorkspace = currentWorkspace.blockSuiteWorkspace;
|
||||
|
||||
const pageMeta = useBlockSuitePageMeta(blockSuiteWorkspace).find(
|
||||
@@ -116,14 +123,15 @@ const DetailPageImpl = memo(function DetailPageImpl({ page }: { page: Page }) {
|
||||
|
||||
const isInTrash = pageMeta?.trash;
|
||||
|
||||
const { setTemporaryFilter } = useCollectionManager(collectionsCRUDAtom);
|
||||
const collectionService = useService(CollectionService);
|
||||
const { setTemporaryFilter } = useCollectionManager(collectionService);
|
||||
const mode = useAtomValue(currentModeAtom);
|
||||
const setPageMode = useSetAtom(setPageModeAtom);
|
||||
useRegisterBlocksuiteEditorCommands(currentPageId, mode);
|
||||
usePageDocumentTitle(pageMeta);
|
||||
|
||||
const onLoad = useCallback(
|
||||
(page: Page, editor: AffineEditorContainer) => {
|
||||
(page: BlockSuitePage, editor: AffineEditorContainer) => {
|
||||
try {
|
||||
// todo(joooye34): improve the following migration code
|
||||
const surfaceBlock = page.getBlockByFlavour('affine:surface')[0];
|
||||
@@ -182,7 +190,7 @@ const DetailPageImpl = memo(function DetailPageImpl({ page }: { page: Page }) {
|
||||
header={
|
||||
<>
|
||||
<DetailPageHeader
|
||||
page={page}
|
||||
page={page.blockSuitePage}
|
||||
workspace={currentWorkspace}
|
||||
showSidebarSwitch={!isInTrash}
|
||||
/>
|
||||
@@ -206,8 +214,14 @@ const DetailPageImpl = memo(function DetailPageImpl({ page }: { page: Page }) {
|
||||
sidebar={
|
||||
!isInTrash ? (
|
||||
<div className={styles.sidebarContainerInner}>
|
||||
<RightSidebarHeader workspace={currentWorkspace} page={page} />
|
||||
<EditorSidebar workspace={blockSuiteWorkspace} page={page} />
|
||||
<RightSidebarHeader
|
||||
workspace={currentWorkspace}
|
||||
page={page.blockSuitePage}
|
||||
/>
|
||||
<EditorSidebar
|
||||
workspace={blockSuiteWorkspace}
|
||||
page={page.blockSuitePage}
|
||||
/>
|
||||
</div>
|
||||
) : null
|
||||
}
|
||||
@@ -221,38 +235,44 @@ const DetailPageImpl = memo(function DetailPageImpl({ page }: { page: Page }) {
|
||||
);
|
||||
});
|
||||
|
||||
const useForceUpdate = () => {
|
||||
const [, setCount] = useState(0);
|
||||
return useCallback(() => setCount(count => count + 1), []);
|
||||
};
|
||||
const useSafePage = (workspace: Workspace, pageId: string) => {
|
||||
const forceUpdate = useForceUpdate();
|
||||
useEffect(() => {
|
||||
const disposable = workspace.slots.pagesUpdated.on(() => {
|
||||
forceUpdate();
|
||||
});
|
||||
return disposable.dispose;
|
||||
}, [pageId, workspace.slots.pagesUpdated, forceUpdate]);
|
||||
|
||||
return workspace.getPage(pageId);
|
||||
};
|
||||
|
||||
export const DetailPage = ({ pageId }: { pageId: string }): ReactElement => {
|
||||
const currentWorkspace = useAtomValue(waitForCurrentWorkspaceAtom);
|
||||
const currentSyncEngineStep = useWorkspaceStatus(
|
||||
currentWorkspace,
|
||||
s => s.engine.sync.step
|
||||
const pageListService = useService(PageListService);
|
||||
|
||||
const pageListReady = useLiveData(pageListService.isReady);
|
||||
|
||||
const pageMetas = useLiveData(pageListService.pages);
|
||||
|
||||
const pageMeta = useMemo(
|
||||
() => pageMetas.find(page => page.id === pageId),
|
||||
[pageMetas, pageId]
|
||||
);
|
||||
|
||||
const pageManager = useService(PageManager);
|
||||
const currentPageService = useService(CurrentPageService);
|
||||
|
||||
useEffect(() => {
|
||||
if (!pageMeta) {
|
||||
return;
|
||||
}
|
||||
const { page, release } = pageManager.open(pageMeta);
|
||||
currentPageService.openPage(page);
|
||||
return () => {
|
||||
currentPageService.closePage();
|
||||
release();
|
||||
};
|
||||
}, [currentPageService, pageManager, pageMeta]);
|
||||
|
||||
const page = useServiceOptional(Page);
|
||||
|
||||
const currentWorkspace = useService(Workspace);
|
||||
|
||||
// set sync engine priority target
|
||||
useEffect(() => {
|
||||
currentWorkspace.setPriorityRule(id => id.endsWith(pageId));
|
||||
}, [pageId, currentWorkspace]);
|
||||
|
||||
const page = useSafePage(currentWorkspace?.blockSuiteWorkspace, pageId);
|
||||
|
||||
// if sync engine has been synced and the page is null, show 404 page.
|
||||
if (currentSyncEngineStep === SyncEngineStep.Synced && !page) {
|
||||
if (pageListReady && !page) {
|
||||
return <PageNotFound />;
|
||||
}
|
||||
|
||||
@@ -266,7 +286,7 @@ export const DetailPage = ({ pageId }: { pageId: string }): ReactElement => {
|
||||
});
|
||||
}
|
||||
|
||||
return <DetailPageImpl page={page} />;
|
||||
return <DetailPageImpl />;
|
||||
};
|
||||
|
||||
export const Component = () => {
|
||||
|
||||
+1
-1
@@ -2,8 +2,8 @@ import { IconButton } from '@affine/component';
|
||||
import { useJournalInfoHelper } from '@affine/core/hooks/use-journal';
|
||||
import { useWorkspaceEnabledFeatures } from '@affine/core/hooks/use-workspace-features';
|
||||
import { FeatureType } from '@affine/graphql';
|
||||
import type { Workspace } from '@affine/workspace/workspace';
|
||||
import type { Page } from '@blocksuite/store';
|
||||
import type { Workspace } from '@toeverything/infra';
|
||||
import { assignInlineVars } from '@vanilla-extract/dynamic';
|
||||
import { useAtom, useAtomValue } from 'jotai';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import { WorkspaceFallback } from '@affine/component/workspace';
|
||||
import { useWorkspace } from '@affine/core/hooks/use-workspace';
|
||||
import {
|
||||
currentWorkspaceAtom,
|
||||
workspaceListAtom,
|
||||
workspaceListLoadingStatusAtom,
|
||||
workspaceManagerAtom,
|
||||
} from '@affine/core/modules/workspace';
|
||||
import { type Workspace } from '@affine/workspace';
|
||||
import { useAtom, useAtomValue } from 'jotai';
|
||||
Workspace,
|
||||
WorkspaceListService,
|
||||
WorkspaceManager,
|
||||
} from '@toeverything/infra';
|
||||
import { useService, useServiceOptional } from '@toeverything/infra/di';
|
||||
import { useLiveData } from '@toeverything/infra/livedata';
|
||||
import { type ReactElement, Suspense, useEffect, useMemo } from 'react';
|
||||
import { Outlet, useParams } from 'react-router-dom';
|
||||
|
||||
import { AffineErrorBoundary } from '../../components/affine/affine-error-boundary';
|
||||
import { WorkspaceLayout } from '../../layouts/workspace-layout';
|
||||
import { CurrentWorkspaceService } from '../../modules/workspace/current-workspace';
|
||||
import { performanceRenderLogger } from '../../shared';
|
||||
import { PageNotFound } from '../404';
|
||||
|
||||
@@ -30,29 +30,27 @@ declare global {
|
||||
export const Component = (): ReactElement => {
|
||||
performanceRenderLogger.info('WorkspaceLayout');
|
||||
|
||||
const [
|
||||
_ /* read this atom here to make sure children refresh when currentWorkspace changed */,
|
||||
setCurrentWorkspace,
|
||||
] = useAtom(currentWorkspaceAtom);
|
||||
const currentWorkspaceService = useService(CurrentWorkspaceService);
|
||||
|
||||
const params = useParams();
|
||||
|
||||
const list = useAtomValue(workspaceListAtom);
|
||||
const listLoading = useAtomValue(workspaceListLoadingStatusAtom);
|
||||
const workspaceManager = useAtomValue(workspaceManagerAtom);
|
||||
const { workspaceList, loading: listLoading } = useLiveData(
|
||||
useService(WorkspaceListService).status
|
||||
);
|
||||
const workspaceManager = useService(WorkspaceManager);
|
||||
|
||||
const meta = useMemo(() => {
|
||||
return list.find(({ id }) => id === params.workspaceId);
|
||||
}, [list, params.workspaceId]);
|
||||
return workspaceList.find(({ id }) => id === params.workspaceId);
|
||||
}, [workspaceList, params.workspaceId]);
|
||||
|
||||
const workspace = useWorkspace(meta);
|
||||
|
||||
useEffect(() => {
|
||||
if (!workspace) {
|
||||
setCurrentWorkspace(null);
|
||||
currentWorkspaceService.closeWorkspace();
|
||||
return undefined;
|
||||
}
|
||||
setCurrentWorkspace(workspace);
|
||||
currentWorkspaceService.openWorkspace(workspace ?? null);
|
||||
|
||||
// for debug purpose
|
||||
window.currentWorkspace = workspace;
|
||||
@@ -65,14 +63,16 @@ export const Component = (): ReactElement => {
|
||||
);
|
||||
|
||||
localStorage.setItem('last_workspace_id', workspace.id);
|
||||
}, [setCurrentWorkspace, meta, workspaceManager, workspace]);
|
||||
}, [meta, workspaceManager, workspace, currentWorkspaceService]);
|
||||
|
||||
const currentWorkspace = useServiceOptional(Workspace);
|
||||
|
||||
// if listLoading is false, we can show 404 page, otherwise we should show loading page.
|
||||
if (listLoading === false && meta === undefined) {
|
||||
return <PageNotFound />;
|
||||
}
|
||||
|
||||
if (!workspace) {
|
||||
if (!currentWorkspace) {
|
||||
return <WorkspaceFallback key="workspaceLoading" />;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { TagListHeader, useTagMetas } from '@affine/core/components/page-list';
|
||||
import { useBlockSuitePageMeta } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { waitForCurrentWorkspaceAtom } from '@affine/core/modules/workspace';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useService, Workspace } from '@toeverything/infra';
|
||||
import { useMemo } from 'react';
|
||||
import { type LoaderFunction, redirect, useParams } from 'react-router-dom';
|
||||
|
||||
@@ -19,7 +18,7 @@ export const loader: LoaderFunction = async args => {
|
||||
|
||||
export const Component = function TagPage() {
|
||||
const params = useParams();
|
||||
const currentWorkspace = useAtomValue(waitForCurrentWorkspaceAtom);
|
||||
const currentWorkspace = useService(Workspace);
|
||||
const pageMetas = useBlockSuitePageMeta(currentWorkspace.blockSuiteWorkspace);
|
||||
const { tagUsageCounts } = useTagMetas(
|
||||
currentWorkspace.blockSuiteWorkspace,
|
||||
|
||||
@@ -14,13 +14,13 @@ import { Header } from '@affine/core/components/pure/header';
|
||||
import { WindowsAppControls } from '@affine/core/components/pure/header/windows-app-controls';
|
||||
import { useBlockSuiteMetaHelper } from '@affine/core/hooks/affine/use-block-suite-meta-helper';
|
||||
import { useBlockSuitePageMeta } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { waitForCurrentWorkspaceAtom } from '@affine/core/modules/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import { DeleteIcon } from '@blocksuite/icons';
|
||||
import type { PageMeta } from '@blocksuite/store';
|
||||
import { Workspace } from '@toeverything/infra';
|
||||
import { getCurrentStore } from '@toeverything/infra/atom';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { useService } from '@toeverything/infra/di';
|
||||
import { useCallback } from 'react';
|
||||
import { type LoaderFunction } from 'react-router-dom';
|
||||
import { NIL } from 'uuid';
|
||||
@@ -61,7 +61,7 @@ export const loader: LoaderFunction = async () => {
|
||||
};
|
||||
|
||||
export const TrashPage = () => {
|
||||
const currentWorkspace = useAtomValue(waitForCurrentWorkspaceAtom);
|
||||
const currentWorkspace = useService(Workspace);
|
||||
const blockSuiteWorkspace = currentWorkspace.blockSuiteWorkspace;
|
||||
assertExists(blockSuiteWorkspace);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user