mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-01 14:19:40 +08:00
refactor: lazy load workspaces (#3091)
(cherry picked from commit 283f0cd263)
This commit is contained in:
@@ -11,7 +11,7 @@ import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name';
|
||||
import type { FC } from 'react';
|
||||
|
||||
import type { AffineOfficialWorkspace } from '../../../shared';
|
||||
import { useWorkspace } from '../../../hooks/use-workspace';
|
||||
import { DeleteLeaveWorkspace } from './delete-leave-workspace';
|
||||
import { ExportPanel } from './export';
|
||||
import { ProfilePanel } from './profile';
|
||||
@@ -19,7 +19,7 @@ import { PublishPanel } from './publish';
|
||||
import { StoragePanel } from './storage';
|
||||
|
||||
export type WorkspaceSettingDetailProps = {
|
||||
workspace: AffineOfficialWorkspace;
|
||||
workspaceId: string;
|
||||
onDeleteWorkspace: (id: string) => Promise<void>;
|
||||
onTransferWorkspace: <
|
||||
From extends WorkspaceFlavour,
|
||||
@@ -32,11 +32,12 @@ export type WorkspaceSettingDetailProps = {
|
||||
};
|
||||
|
||||
export const WorkspaceSettingDetail: FC<WorkspaceSettingDetailProps> = ({
|
||||
workspace,
|
||||
workspaceId,
|
||||
onDeleteWorkspace,
|
||||
...props
|
||||
}) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const workspace = useWorkspace(workspaceId);
|
||||
const [name] = useBlockSuiteWorkspaceName(workspace.blockSuiteWorkspace);
|
||||
|
||||
return (
|
||||
|
||||
@@ -64,7 +64,10 @@ export const ProfilePanel: FC<{
|
||||
<div className="camera-icon-wrapper">
|
||||
<CameraIcon />
|
||||
</div>
|
||||
<WorkspaceAvatar size={56} workspace={workspace} />
|
||||
<WorkspaceAvatar
|
||||
size={56}
|
||||
workspace={workspace.blockSuiteWorkspace}
|
||||
/>
|
||||
</>
|
||||
</Upload>
|
||||
</div>
|
||||
|
||||
@@ -18,13 +18,22 @@ import { TmpDisableAffineCloudModal } from '../tmp-disable-affine-cloud-modal';
|
||||
import type { WorkspaceSettingDetailProps } from './index';
|
||||
import * as style from './style.css';
|
||||
|
||||
export type PublishPanelProps = WorkspaceSettingDetailProps & {
|
||||
export type PublishPanelProps = Omit<
|
||||
WorkspaceSettingDetailProps,
|
||||
'workspaceId'
|
||||
> & {
|
||||
workspace: AffineOfficialWorkspace;
|
||||
};
|
||||
export type PublishPanelLocalProps = WorkspaceSettingDetailProps & {
|
||||
export type PublishPanelLocalProps = Omit<
|
||||
WorkspaceSettingDetailProps,
|
||||
'workspaceId'
|
||||
> & {
|
||||
workspace: LocalWorkspace;
|
||||
};
|
||||
export type PublishPanelAffineProps = WorkspaceSettingDetailProps & {
|
||||
export type PublishPanelAffineProps = Omit<
|
||||
WorkspaceSettingDetailProps,
|
||||
'workspaceId'
|
||||
> & {
|
||||
workspace: AffineCloudWorkspace;
|
||||
};
|
||||
|
||||
|
||||
@@ -4,14 +4,13 @@ import {
|
||||
} from '@affine/component/setting-components';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { rootWorkspacesMetadataAtom } from '@affine/workspace/atom';
|
||||
import { ContactWithUsIcon } from '@blocksuite/icons';
|
||||
import type { PassiveDocProvider } from '@blocksuite/store';
|
||||
import { noop } from 'foxact/noop';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import type React from 'react';
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
import { useCurrentWorkspace } from '../../../hooks/current/use-current-workspace';
|
||||
import { useWorkspaces } from '../../../hooks/use-workspaces';
|
||||
import type { AllWorkspace } from '../../../shared';
|
||||
import { AccountSetting } from './account-setting';
|
||||
import {
|
||||
@@ -26,70 +25,52 @@ import { WorkspaceSetting } from './workspace-setting';
|
||||
type ActiveTab = GeneralSettingKeys | 'workspace' | 'account';
|
||||
export type SettingProps = {
|
||||
activeTab: ActiveTab;
|
||||
workspace: AllWorkspace | null;
|
||||
workspaceId: string | null;
|
||||
onSettingClick: (params: {
|
||||
activeTab: ActiveTab;
|
||||
workspace: AllWorkspace | null;
|
||||
workspaceId: string | null;
|
||||
}) => void;
|
||||
};
|
||||
export const SettingModal: React.FC<SettingModalProps & SettingProps> = ({
|
||||
open,
|
||||
setOpen,
|
||||
activeTab = 'appearance',
|
||||
workspace = null,
|
||||
workspaceId = null,
|
||||
onSettingClick,
|
||||
}) => {
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
const workspaces = useWorkspaces();
|
||||
const workspaces = useAtomValue(rootWorkspacesMetadataAtom);
|
||||
const [currentWorkspace] = useCurrentWorkspace();
|
||||
const generalSettingList = useGeneralSettingList();
|
||||
const workspaceList = useMemo(() => {
|
||||
return workspaces.filter(
|
||||
({ flavour }) => flavour !== WorkspaceFlavour.PUBLIC
|
||||
) as AllWorkspace[];
|
||||
);
|
||||
}, [workspaces]);
|
||||
|
||||
const onGeneralSettingClick = useCallback(
|
||||
(key: GeneralSettingKeys) => {
|
||||
onSettingClick({
|
||||
activeTab: key,
|
||||
workspace: null,
|
||||
workspaceId: null,
|
||||
});
|
||||
},
|
||||
[onSettingClick]
|
||||
);
|
||||
const onWorkspaceSettingClick = useCallback(
|
||||
(workspace: AllWorkspace) => {
|
||||
(workspaceId: string) => {
|
||||
onSettingClick({
|
||||
activeTab: 'workspace',
|
||||
workspace,
|
||||
workspaceId,
|
||||
});
|
||||
},
|
||||
[onSettingClick]
|
||||
);
|
||||
const onAccountSettingClick = useCallback(() => {
|
||||
onSettingClick({ activeTab: 'account', workspace: null });
|
||||
onSettingClick({ activeTab: 'account', workspaceId: null });
|
||||
}, [onSettingClick]);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace && workspace !== currentWorkspace) {
|
||||
const providers = workspace.blockSuiteWorkspace.providers.filter(
|
||||
(provider): provider is PassiveDocProvider =>
|
||||
'passive' in provider && provider.passive
|
||||
);
|
||||
providers.forEach(provider => {
|
||||
provider.connect();
|
||||
});
|
||||
return () => {
|
||||
providers.forEach(provider => {
|
||||
provider.disconnect();
|
||||
});
|
||||
};
|
||||
}
|
||||
return noop;
|
||||
}, [currentWorkspace, workspace]);
|
||||
|
||||
return (
|
||||
<SettingModalBase open={open} setOpen={setOpen}>
|
||||
<SettingSidebar
|
||||
@@ -99,15 +80,15 @@ export const SettingModal: React.FC<SettingModalProps & SettingProps> = ({
|
||||
workspaceList={workspaceList}
|
||||
onWorkspaceSettingClick={onWorkspaceSettingClick}
|
||||
selectedGeneralKey={activeTab}
|
||||
selectedWorkspace={workspace}
|
||||
selectedWorkspaceId={workspaceId}
|
||||
onAccountSettingClick={onAccountSettingClick}
|
||||
/>
|
||||
|
||||
<div className={settingContent}>
|
||||
<div className="wrapper">
|
||||
<div className="content">
|
||||
{activeTab === 'workspace' && workspace ? (
|
||||
<WorkspaceSetting key={workspace.id} workspace={workspace} />
|
||||
{activeTab === 'workspace' && workspaceId ? (
|
||||
<WorkspaceSetting key={workspaceId} workspaceId={workspaceId} />
|
||||
) : null}
|
||||
{generalSettingList.find(v => v.key === activeTab) ? (
|
||||
<GeneralSetting generalKey={activeTab as GeneralSettingKeys} />
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { UserAvatar } from '@affine/component/user-avatar';
|
||||
import { WorkspaceAvatar } from '@affine/component/workspace-avatar';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { RootWorkspaceMetadata } from '@affine/workspace/atom';
|
||||
import { useStaticBlockSuiteWorkspace } from '@affine/workspace/utils';
|
||||
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name';
|
||||
import clsx from 'clsx';
|
||||
|
||||
@@ -24,17 +26,17 @@ export const SettingSidebar = ({
|
||||
currentWorkspace,
|
||||
workspaceList,
|
||||
onWorkspaceSettingClick,
|
||||
selectedWorkspace,
|
||||
selectedWorkspaceId,
|
||||
selectedGeneralKey,
|
||||
onAccountSettingClick,
|
||||
}: {
|
||||
generalSettingList: GeneralSettingList;
|
||||
onGeneralSettingClick: (key: GeneralSettingKeys) => void;
|
||||
currentWorkspace: AllWorkspace;
|
||||
workspaceList: AllWorkspace[];
|
||||
onWorkspaceSettingClick: (workspace: AllWorkspace) => void;
|
||||
workspaceList: RootWorkspaceMetadata[];
|
||||
onWorkspaceSettingClick: (workspaceId: string) => void;
|
||||
|
||||
selectedWorkspace: AllWorkspace | null;
|
||||
selectedWorkspaceId: string | null;
|
||||
selectedGeneralKey: string | null;
|
||||
onAccountSettingClick: () => void;
|
||||
}) => {
|
||||
@@ -72,12 +74,12 @@ export const SettingSidebar = ({
|
||||
return (
|
||||
<WorkspaceListItem
|
||||
key={workspace.id}
|
||||
workspace={workspace}
|
||||
meta={workspace}
|
||||
onClick={() => {
|
||||
onWorkspaceSettingClick(workspace);
|
||||
onWorkspaceSettingClick(workspace.id);
|
||||
}}
|
||||
isCurrent={workspace.id === currentWorkspace.id}
|
||||
isActive={workspace.id === selectedWorkspace?.id}
|
||||
isActive={workspace.id === selectedWorkspaceId}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
@@ -107,19 +109,18 @@ export const SettingSidebar = ({
|
||||
};
|
||||
|
||||
const WorkspaceListItem = ({
|
||||
workspace,
|
||||
meta,
|
||||
onClick,
|
||||
isCurrent,
|
||||
isActive,
|
||||
}: {
|
||||
workspace: AllWorkspace;
|
||||
meta: RootWorkspaceMetadata;
|
||||
onClick: () => void;
|
||||
isCurrent: boolean;
|
||||
isActive: boolean;
|
||||
}) => {
|
||||
const [workspaceName] = useBlockSuiteWorkspaceName(
|
||||
workspace.blockSuiteWorkspace ?? null
|
||||
);
|
||||
const workspace = useStaticBlockSuiteWorkspace(meta.id);
|
||||
const [workspaceName] = useBlockSuiteWorkspaceName(workspace);
|
||||
return (
|
||||
<div
|
||||
className={clsx(sidebarSelectItem, { active: isActive })}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { Suspense, useCallback } from 'react';
|
||||
|
||||
import { getUIAdapter } from '../../../../adapters/workspace';
|
||||
import { usePassiveWorkspaceEffect } from '../../../../hooks/current/use-current-workspace';
|
||||
import { useOnTransformWorkspace } from '../../../../hooks/root/use-on-transform-workspace';
|
||||
import { useWorkspace } from '../../../../hooks/use-workspace';
|
||||
import { useAppHelper } from '../../../../hooks/use-workspaces';
|
||||
import type { AllWorkspace } from '../../../../shared';
|
||||
|
||||
export const WorkspaceSetting = ({
|
||||
workspace,
|
||||
}: {
|
||||
workspace: AllWorkspace;
|
||||
}) => {
|
||||
export const WorkspaceSetting = ({ workspaceId }: { workspaceId: string }) => {
|
||||
const workspace = useWorkspace(workspaceId);
|
||||
usePassiveWorkspaceEffect(workspace.blockSuiteWorkspace);
|
||||
const helper = useAppHelper();
|
||||
|
||||
const { NewSettingsDetail } = getUIAdapter(workspace.flavour);
|
||||
|
||||
const onDeleteWorkspace = useCallback(
|
||||
@@ -26,7 +26,7 @@ export const WorkspaceSetting = ({
|
||||
<NewSettingsDetail
|
||||
onTransformWorkspace={onTransformWorkspace}
|
||||
onDeleteWorkspace={onDeleteWorkspace}
|
||||
currentWorkspace={workspace}
|
||||
currentWorkspaceId={workspaceId}
|
||||
/>
|
||||
</Suspense>
|
||||
);
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
import { rootBlockHubAtom } from '@affine/workspace/atom';
|
||||
import type { EditorContainer } from '@blocksuite/editor';
|
||||
import { assertExists } from '@blocksuite/global/utils';
|
||||
import type { Page } from '@blocksuite/store';
|
||||
import type { Page, Workspace } from '@blocksuite/store';
|
||||
import { useBlockSuitePageMeta } from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
import { useBlockSuiteWorkspacePage } from '@toeverything/hooks/use-block-suite-workspace-page';
|
||||
import { useBlockSuiteWorkspacePageTitle } from '@toeverything/hooks/use-block-suite-workspace-page-title';
|
||||
@@ -28,14 +28,13 @@ import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
|
||||
import { pageSettingFamily } from '../atoms';
|
||||
import { contentLayoutAtom } from '../atoms/layout';
|
||||
import { useAppSetting } from '../atoms/settings';
|
||||
import type { AffineOfficialWorkspace } from '../shared';
|
||||
import { BlockSuiteEditor as Editor } from './blocksuite/block-suite-editor';
|
||||
import { editor } from './page-detail-editor.css';
|
||||
import { pluginContainer } from './page-detail-editor.css';
|
||||
|
||||
export type PageDetailEditorProps = {
|
||||
isPublic?: boolean;
|
||||
workspace: AffineOfficialWorkspace;
|
||||
workspace: Workspace;
|
||||
pageId: string;
|
||||
onInit: (page: Page, editor: Readonly<EditorContainer>) => void;
|
||||
onLoad?: (page: Page, editor: EditorContainer) => () => void;
|
||||
@@ -53,12 +52,11 @@ const EditorWrapper = memo(function EditorWrapper({
|
||||
() => Object.values(affinePluginsMap),
|
||||
[affinePluginsMap]
|
||||
);
|
||||
const blockSuiteWorkspace = workspace.blockSuiteWorkspace;
|
||||
const page = useBlockSuiteWorkspacePage(blockSuiteWorkspace, pageId);
|
||||
const page = useBlockSuiteWorkspacePage(workspace, pageId);
|
||||
if (!page) {
|
||||
throw new PageNotFoundError(blockSuiteWorkspace, pageId);
|
||||
throw new PageNotFoundError(workspace, pageId);
|
||||
}
|
||||
const meta = useBlockSuitePageMeta(blockSuiteWorkspace).find(
|
||||
const meta = useBlockSuitePageMeta(workspace).find(
|
||||
meta => meta.id === pageId
|
||||
);
|
||||
const pageSettingAtom = pageSettingFamily(pageId);
|
||||
@@ -77,7 +75,7 @@ const EditorWrapper = memo(function EditorWrapper({
|
||||
className={clsx(editor, {
|
||||
'full-screen': appSettings?.fullWidthLayout,
|
||||
})}
|
||||
key={`${workspace.flavour}-${workspace.id}-${pageId}`}
|
||||
key={`${workspace.id}-${pageId}`}
|
||||
mode={isPublic ? 'page' : currentMode}
|
||||
page={page}
|
||||
onInit={useCallback(
|
||||
@@ -181,12 +179,11 @@ const LayoutPanel = memo(function LayoutPanel(
|
||||
|
||||
export const PageDetailEditor: FC<PageDetailEditorProps> = props => {
|
||||
const { workspace, pageId } = props;
|
||||
const blockSuiteWorkspace = workspace.blockSuiteWorkspace;
|
||||
const page = useBlockSuiteWorkspacePage(blockSuiteWorkspace, pageId);
|
||||
const page = useBlockSuiteWorkspacePage(workspace, pageId);
|
||||
if (!page) {
|
||||
throw new PageNotFoundError(blockSuiteWorkspace, pageId);
|
||||
throw new PageNotFoundError(workspace, pageId);
|
||||
}
|
||||
const title = useBlockSuiteWorkspacePageTitle(blockSuiteWorkspace, pageId);
|
||||
const title = useBlockSuiteWorkspacePageTitle(workspace, pageId);
|
||||
|
||||
const layout = useAtomValue(contentLayoutAtom);
|
||||
const affinePluginsMap = useAtomValue(affinePluginsAtom);
|
||||
|
||||
@@ -41,7 +41,7 @@ export const HelpIsland = ({
|
||||
setOpenSettingModalAtom({
|
||||
open: true,
|
||||
activeTab: 'about',
|
||||
workspace: null,
|
||||
workspaceId: null,
|
||||
});
|
||||
}, [setOpenSettingModalAtom]);
|
||||
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import {
|
||||
DeleteTemporarilyIcon,
|
||||
FolderIcon,
|
||||
SettingsIcon,
|
||||
} from '@blocksuite/icons';
|
||||
import { DeleteTemporarilyIcon, FolderIcon } from '@blocksuite/icons';
|
||||
import type { FC, SVGProps } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
@@ -23,11 +19,11 @@ export const useSwitchToConfig = (
|
||||
href: pathGenerator.all(workspaceId),
|
||||
icon: FolderIcon,
|
||||
},
|
||||
{
|
||||
title: t['Workspace Settings'](),
|
||||
href: pathGenerator.setting(workspaceId),
|
||||
icon: SettingsIcon,
|
||||
},
|
||||
// {
|
||||
// title: t['Workspace Settings'](),
|
||||
// href: pathGenerator.setting(workspaceId),
|
||||
// icon: SettingsIcon,
|
||||
// },
|
||||
{
|
||||
title: t['Trash'](),
|
||||
href: pathGenerator.trash(workspaceId),
|
||||
|
||||
@@ -14,6 +14,7 @@ import type {
|
||||
} from '@affine/env/workspace';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type { RootWorkspaceMetadata } from '@affine/workspace/atom';
|
||||
import { HelpIcon, ImportIcon, PlusIcon } from '@blocksuite/icons';
|
||||
import type { DragEndEvent } from '@dnd-kit/core';
|
||||
import { useCallback, useRef } from 'react';
|
||||
@@ -40,12 +41,12 @@ import {
|
||||
|
||||
interface WorkspaceModalProps {
|
||||
disabled?: boolean;
|
||||
workspaces: AllWorkspace[];
|
||||
workspaces: RootWorkspaceMetadata[];
|
||||
currentWorkspaceId: AllWorkspace['id'] | null;
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
onClickWorkspace: (workspace: AllWorkspace) => void;
|
||||
onClickWorkspaceSetting: (workspace: AllWorkspace) => void;
|
||||
onClickWorkspace: (workspace: RootWorkspaceMetadata['id']) => void;
|
||||
onClickWorkspaceSetting: (workspace: RootWorkspaceMetadata['id']) => void;
|
||||
onNewWorkspace: () => void;
|
||||
onAddWorkspace: () => void;
|
||||
onMoveWorkspace: (activeId: string, overId: string) => void;
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ export const WorkspaceSelector: React.FC<WorkspaceSelectorProps> = ({
|
||||
data-testid="workspace-avatar"
|
||||
className={workspaceAvatarStyle}
|
||||
size={40}
|
||||
workspace={currentWorkspace}
|
||||
workspace={currentWorkspace?.blockSuiteWorkspace ?? null}
|
||||
/>
|
||||
<StyledSelectorWrapper>
|
||||
<StyledWorkspaceName data-testid="workspace-name">
|
||||
|
||||
@@ -44,7 +44,6 @@ export type RootAppSidebarProps = {
|
||||
paths: {
|
||||
all: (workspaceId: string) => string;
|
||||
trash: (workspaceId: string) => string;
|
||||
setting: (workspaceId: string) => string;
|
||||
shared: (workspaceId: string) => string;
|
||||
};
|
||||
};
|
||||
@@ -173,16 +172,6 @@ export const RootAppSidebar = ({
|
||||
>
|
||||
<span data-testid="all-pages">{t['All pages']()}</span>
|
||||
</RouteMenuLinkItem>
|
||||
{!runtimeConfig.enableNewSettingModal && (
|
||||
<RouteMenuLinkItem
|
||||
data-testid="slider-bar-workspace-setting-button"
|
||||
icon={<SettingsIcon />}
|
||||
currentPath={currentPath}
|
||||
path={currentWorkspaceId && paths.setting(currentWorkspaceId)}
|
||||
>
|
||||
<span data-testid="settings">{t['Settings']()}</span>
|
||||
</RouteMenuLinkItem>
|
||||
)}
|
||||
{runtimeConfig.enableNewSettingModal ? (
|
||||
<MenuItem
|
||||
data-testid="slider-bar-workspace-setting-button"
|
||||
|
||||
@@ -14,12 +14,13 @@ import type { ReactElement } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { useGetPageInfoById } from '../hooks/use-get-page-info';
|
||||
import { useWorkspace } from '../hooks/use-workspace';
|
||||
import { BlockSuiteEditorHeader } from './blocksuite/workspace-header';
|
||||
import { filterContainerStyle } from './filter-container.css';
|
||||
import { WorkspaceModeFilterTab, WorkspaceTitle } from './pure/workspace-title';
|
||||
|
||||
export function WorkspaceHeader({
|
||||
currentWorkspace,
|
||||
currentWorkspaceId,
|
||||
currentEntry,
|
||||
}: WorkspaceHeaderProps<WorkspaceFlavour>): ReactElement {
|
||||
const setting = useCollectionManager();
|
||||
@@ -31,6 +32,9 @@ export function WorkspaceHeader({
|
||||
},
|
||||
[setting]
|
||||
);
|
||||
|
||||
const currentWorkspace = useWorkspace(currentWorkspaceId);
|
||||
|
||||
const getPageInfoById = useGetPageInfoById();
|
||||
if ('subPath' in currentEntry) {
|
||||
if (currentEntry.subPath === WorkspaceSubPath.ALL) {
|
||||
|
||||
Reference in New Issue
Block a user