refactor: lazy load workspaces (#3091)

(cherry picked from commit 283f0cd263)
This commit is contained in:
Alex Yang
2023-07-07 22:15:27 +08:00
parent e6530f5017
commit 1908d1a213
45 changed files with 446 additions and 750 deletions
@@ -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>
);