@@ -12,7 +12,7 @@ function setupRendererConnection(rendererPort: Electron.MessagePortMain) {
|
|||||||
try {
|
try {
|
||||||
const start = performance.now();
|
const start = performance.now();
|
||||||
const result = await handler(...args);
|
const result = await handler(...args);
|
||||||
logger.debug(
|
logger.info(
|
||||||
'[async-api]',
|
'[async-api]',
|
||||||
`${namespace}.${name}`,
|
`${namespace}.${name}`,
|
||||||
args.filter(
|
args.filter(
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ export function registerAffineHelpCommands({
|
|||||||
track.$.cmdk.help.contactUs();
|
track.$.cmdk.help.contactUs();
|
||||||
globalDialogService.open('setting', {
|
globalDialogService.open('setting', {
|
||||||
activeTab: 'about',
|
activeTab: 'about',
|
||||||
workspaceMetadata: null,
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -86,9 +86,8 @@ export const AFFiNESharePage = (props: ShareMenuProps) => {
|
|||||||
const onOpenWorkspaceSettings = useCallback(() => {
|
const onOpenWorkspaceSettings = useCallback(() => {
|
||||||
globalDialogService.open('setting', {
|
globalDialogService.open('setting', {
|
||||||
activeTab: 'workspace:preference',
|
activeTab: 'workspace:preference',
|
||||||
workspaceMetadata: props.workspaceMetadata,
|
|
||||||
});
|
});
|
||||||
}, [globalDialogService, props.workspaceMetadata]);
|
}, [globalDialogService]);
|
||||||
|
|
||||||
const onClickAnyoneReadOnlyShare = useAsyncCallback(async () => {
|
const onClickAnyoneReadOnlyShare = useAsyncCallback(async () => {
|
||||||
if (isSharedPage) {
|
if (isSharedPage) {
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { useWorkspace } from '@affine/core/components/hooks/use-workspace';
|
||||||
|
import { GlobalContextService } from '@affine/core/modules/global-context';
|
||||||
|
import { WorkspacesService } from '@affine/core/modules/workspace';
|
||||||
|
import { FrameworkScope, useLiveData, useService } from '@toeverything/infra';
|
||||||
|
|
||||||
|
export const CurrentWorkspaceScopeProvider = ({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}) => {
|
||||||
|
const globalContext = useService(GlobalContextService).globalContext;
|
||||||
|
const workspacesService = useService(WorkspacesService);
|
||||||
|
const workspaceMeta = useLiveData(workspacesService.list.workspaces$).find(
|
||||||
|
workspace => workspace.id === globalContext.workspaceId.get()
|
||||||
|
);
|
||||||
|
const workspace = useWorkspace(workspaceMeta);
|
||||||
|
if (!workspace) {
|
||||||
|
// todo(@pengx17): render a loading/error component here if not found?
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return <FrameworkScope scope={workspace.scope}>{children}</FrameworkScope>;
|
||||||
|
};
|
||||||
@@ -148,11 +148,7 @@ export const RootAppSidebar = memo((): ReactElement => {
|
|||||||
<SidebarContainer>
|
<SidebarContainer>
|
||||||
<div className={workspaceAndUserWrapper}>
|
<div className={workspaceAndUserWrapper}>
|
||||||
<div className={workspaceWrapper}>
|
<div className={workspaceWrapper}>
|
||||||
<WorkspaceNavigator
|
<WorkspaceNavigator showEnableCloudButton showSyncStatus />
|
||||||
showEnableCloudButton
|
|
||||||
showSettingsButton
|
|
||||||
showSyncStatus
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<UserInfo />
|
<UserInfo />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ interface WorkspaceSelectorProps {
|
|||||||
metadata: WorkspaceMetadata;
|
metadata: WorkspaceMetadata;
|
||||||
defaultDocId?: string;
|
defaultDocId?: string;
|
||||||
}) => void;
|
}) => void;
|
||||||
showSettingsButton?: boolean;
|
|
||||||
showEnableCloudButton?: boolean;
|
showEnableCloudButton?: boolean;
|
||||||
showArrowDownIcon?: boolean;
|
showArrowDownIcon?: boolean;
|
||||||
showSyncStatus?: boolean;
|
showSyncStatus?: boolean;
|
||||||
@@ -38,7 +37,6 @@ export const WorkspaceSelector = ({
|
|||||||
workspaceMetadata: outerWorkspaceMetadata,
|
workspaceMetadata: outerWorkspaceMetadata,
|
||||||
onSelectWorkspace,
|
onSelectWorkspace,
|
||||||
onCreatedWorkspace,
|
onCreatedWorkspace,
|
||||||
showSettingsButton,
|
|
||||||
showArrowDownIcon,
|
showArrowDownIcon,
|
||||||
disable,
|
disable,
|
||||||
open: outerOpen,
|
open: outerOpen,
|
||||||
@@ -89,7 +87,6 @@ export const WorkspaceSelector = ({
|
|||||||
onClickWorkspace={onSelectWorkspace}
|
onClickWorkspace={onSelectWorkspace}
|
||||||
onCreatedWorkspace={onCreatedWorkspace}
|
onCreatedWorkspace={onCreatedWorkspace}
|
||||||
showEnableCloudButton={showEnableCloudButton}
|
showEnableCloudButton={showEnableCloudButton}
|
||||||
showSettingsButton={showSettingsButton}
|
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
contentOptions={{
|
contentOptions={{
|
||||||
|
|||||||
@@ -55,7 +55,6 @@ interface UserWithWorkspaceListProps {
|
|||||||
metadata: WorkspaceMetadata;
|
metadata: WorkspaceMetadata;
|
||||||
defaultDocId?: string;
|
defaultDocId?: string;
|
||||||
}) => void;
|
}) => void;
|
||||||
showSettingsButton?: boolean;
|
|
||||||
showEnableCloudButton?: boolean;
|
showEnableCloudButton?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +62,6 @@ const UserWithWorkspaceListInner = ({
|
|||||||
onEventEnd,
|
onEventEnd,
|
||||||
onClickWorkspace,
|
onClickWorkspace,
|
||||||
onCreatedWorkspace,
|
onCreatedWorkspace,
|
||||||
showSettingsButton,
|
|
||||||
showEnableCloudButton,
|
showEnableCloudButton,
|
||||||
}: UserWithWorkspaceListProps) => {
|
}: UserWithWorkspaceListProps) => {
|
||||||
const globalDialogService = useService(GlobalDialogService);
|
const globalDialogService = useService(GlobalDialogService);
|
||||||
@@ -121,7 +119,6 @@ const UserWithWorkspaceListInner = ({
|
|||||||
onEventEnd={onEventEnd}
|
onEventEnd={onEventEnd}
|
||||||
onClickWorkspace={onClickWorkspace}
|
onClickWorkspace={onClickWorkspace}
|
||||||
showEnableCloudButton={showEnableCloudButton}
|
showEnableCloudButton={showEnableCloudButton}
|
||||||
showSettingsButton={showSettingsButton}
|
|
||||||
/>
|
/>
|
||||||
<AddWorkspace
|
<AddWorkspace
|
||||||
onAddWorkspace={onAddWorkspace}
|
onAddWorkspace={onAddWorkspace}
|
||||||
|
|||||||
@@ -50,13 +50,11 @@ const CloudWorkSpaceList = ({
|
|||||||
server,
|
server,
|
||||||
workspaces,
|
workspaces,
|
||||||
onClickWorkspace,
|
onClickWorkspace,
|
||||||
onClickWorkspaceSetting,
|
|
||||||
onClickEnableCloud,
|
onClickEnableCloud,
|
||||||
}: {
|
}: {
|
||||||
server: Server;
|
server: Server;
|
||||||
workspaces: WorkspaceMetadata[];
|
workspaces: WorkspaceMetadata[];
|
||||||
onClickWorkspace: (workspaceMetadata: WorkspaceMetadata) => void;
|
onClickWorkspace: (workspaceMetadata: WorkspaceMetadata) => void;
|
||||||
onClickWorkspaceSetting?: (workspaceMetadata: WorkspaceMetadata) => void;
|
|
||||||
onClickEnableCloud?: (meta: WorkspaceMetadata) => void;
|
onClickEnableCloud?: (meta: WorkspaceMetadata) => void;
|
||||||
}) => {
|
}) => {
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
@@ -161,7 +159,6 @@ const CloudWorkSpaceList = ({
|
|||||||
<WorkspaceList
|
<WorkspaceList
|
||||||
items={workspaces}
|
items={workspaces}
|
||||||
onClick={onClickWorkspace}
|
onClick={onClickWorkspace}
|
||||||
onSettingClick={onClickWorkspaceSetting}
|
|
||||||
onEnableCloudClick={onClickEnableCloud}
|
onEnableCloudClick={onClickEnableCloud}
|
||||||
/>
|
/>
|
||||||
<MenuItem
|
<MenuItem
|
||||||
@@ -215,16 +212,13 @@ export const AFFiNEWorkspaceList = ({
|
|||||||
onEventEnd,
|
onEventEnd,
|
||||||
onClickWorkspace,
|
onClickWorkspace,
|
||||||
showEnableCloudButton,
|
showEnableCloudButton,
|
||||||
showSettingsButton,
|
|
||||||
}: {
|
}: {
|
||||||
onClickWorkspace?: (workspaceMetadata: WorkspaceMetadata) => void;
|
onClickWorkspace?: (workspaceMetadata: WorkspaceMetadata) => void;
|
||||||
onEventEnd?: () => void;
|
onEventEnd?: () => void;
|
||||||
showSettingsButton?: boolean;
|
|
||||||
showEnableCloudButton?: boolean;
|
showEnableCloudButton?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const workspacesService = useService(WorkspacesService);
|
const workspacesService = useService(WorkspacesService);
|
||||||
const workspaces = useLiveData(workspacesService.list.workspaces$);
|
const workspaces = useLiveData(workspacesService.list.workspaces$);
|
||||||
const globalDialogService = useService(GlobalDialogService);
|
|
||||||
|
|
||||||
const confirmEnableCloud = useEnableCloud();
|
const confirmEnableCloud = useEnableCloud();
|
||||||
|
|
||||||
@@ -247,17 +241,6 @@ export const AFFiNEWorkspaceList = ({
|
|||||||
[workspaces]
|
[workspaces]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onClickWorkspaceSetting = useCallback(
|
|
||||||
(workspaceMetadata: WorkspaceMetadata) => {
|
|
||||||
globalDialogService.open('setting', {
|
|
||||||
activeTab: 'workspace:preference',
|
|
||||||
workspaceMetadata,
|
|
||||||
});
|
|
||||||
onEventEnd?.();
|
|
||||||
},
|
|
||||||
[globalDialogService, onEventEnd]
|
|
||||||
);
|
|
||||||
|
|
||||||
const onClickEnableCloud = useCallback(
|
const onClickEnableCloud = useCallback(
|
||||||
(meta: WorkspaceMetadata) => {
|
(meta: WorkspaceMetadata) => {
|
||||||
const { workspace, dispose } = workspacesService.open({ metadata: meta });
|
const { workspace, dispose } = workspacesService.open({ metadata: meta });
|
||||||
@@ -292,9 +275,6 @@ export const AFFiNEWorkspaceList = ({
|
|||||||
({ flavour }) => flavour === server.id
|
({ flavour }) => flavour === server.id
|
||||||
)}
|
)}
|
||||||
onClickWorkspace={handleClickWorkspace}
|
onClickWorkspace={handleClickWorkspace}
|
||||||
onClickWorkspaceSetting={
|
|
||||||
showSettingsButton ? onClickWorkspaceSetting : undefined
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
<Divider size="thinner" />
|
<Divider size="thinner" />
|
||||||
</FrameworkScope>
|
</FrameworkScope>
|
||||||
@@ -303,9 +283,6 @@ export const AFFiNEWorkspaceList = ({
|
|||||||
<LocalWorkspaces
|
<LocalWorkspaces
|
||||||
workspaces={localWorkspaces}
|
workspaces={localWorkspaces}
|
||||||
onClickWorkspace={handleClickWorkspace}
|
onClickWorkspace={handleClickWorkspace}
|
||||||
onClickWorkspaceSetting={
|
|
||||||
showSettingsButton ? onClickWorkspaceSetting : undefined
|
|
||||||
}
|
|
||||||
onClickEnableCloud={
|
onClickEnableCloud={
|
||||||
showEnableCloudButton ? onClickEnableCloud : undefined
|
showEnableCloudButton ? onClickEnableCloud : undefined
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
PenIcon,
|
PenIcon,
|
||||||
} from '@blocksuite/icons/rc';
|
} from '@blocksuite/icons/rc';
|
||||||
import { useLiveData, useServices } from '@toeverything/infra';
|
import { useLiveData, useServices } from '@toeverything/infra';
|
||||||
import type { ReactElement, SVGProps } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
import { AuthService, ServerService } from '../../../../modules/cloud';
|
import { AuthService, ServerService } from '../../../../modules/cloud';
|
||||||
@@ -27,7 +27,7 @@ import { Shortcuts } from './shortcuts';
|
|||||||
interface GeneralSettingListItem {
|
interface GeneralSettingListItem {
|
||||||
key: SettingTab;
|
key: SettingTab;
|
||||||
title: string;
|
title: string;
|
||||||
icon: (props: SVGProps<SVGSVGElement>) => ReactElement;
|
icon: ReactNode;
|
||||||
testId: string;
|
testId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,19 +58,19 @@ export const useGeneralSettingList = (): GeneralSettingList => {
|
|||||||
{
|
{
|
||||||
key: 'appearance',
|
key: 'appearance',
|
||||||
title: t['com.affine.settings.appearance'](),
|
title: t['com.affine.settings.appearance'](),
|
||||||
icon: AppearanceIcon,
|
icon: <AppearanceIcon />,
|
||||||
testId: 'appearance-panel-trigger',
|
testId: 'appearance-panel-trigger',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'shortcuts',
|
key: 'shortcuts',
|
||||||
title: t['com.affine.keyboardShortcuts.title'](),
|
title: t['com.affine.keyboardShortcuts.title'](),
|
||||||
icon: KeyboardIcon,
|
icon: <KeyboardIcon />,
|
||||||
testId: 'shortcuts-panel-trigger',
|
testId: 'shortcuts-panel-trigger',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'about',
|
key: 'about',
|
||||||
title: t['com.affine.aboutAFFiNE.title'](),
|
title: t['com.affine.aboutAFFiNE.title'](),
|
||||||
icon: InformationIcon,
|
icon: <InformationIcon />,
|
||||||
testId: 'about-panel-trigger',
|
testId: 'about-panel-trigger',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@@ -79,7 +79,7 @@ export const useGeneralSettingList = (): GeneralSettingList => {
|
|||||||
settings.splice(1, 0, {
|
settings.splice(1, 0, {
|
||||||
key: 'editor',
|
key: 'editor',
|
||||||
title: t['com.affine.settings.editorSettings'](),
|
title: t['com.affine.settings.editorSettings'](),
|
||||||
icon: PenIcon,
|
icon: <PenIcon />,
|
||||||
testId: 'editor-panel-trigger',
|
testId: 'editor-panel-trigger',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -88,14 +88,14 @@ export const useGeneralSettingList = (): GeneralSettingList => {
|
|||||||
settings.splice(3, 0, {
|
settings.splice(3, 0, {
|
||||||
key: 'plans',
|
key: 'plans',
|
||||||
title: t['com.affine.payment.title'](),
|
title: t['com.affine.payment.title'](),
|
||||||
icon: UpgradeIcon,
|
icon: <UpgradeIcon />,
|
||||||
testId: 'plans-panel-trigger',
|
testId: 'plans-panel-trigger',
|
||||||
});
|
});
|
||||||
if (status === 'authenticated') {
|
if (status === 'authenticated') {
|
||||||
settings.splice(3, 0, {
|
settings.splice(3, 0, {
|
||||||
key: 'billing',
|
key: 'billing',
|
||||||
title: t['com.affine.payment.billing-setting.title'](),
|
title: t['com.affine.payment.billing-setting.title'](),
|
||||||
icon: PaymentIcon,
|
icon: <PaymentIcon />,
|
||||||
testId: 'billing-panel-trigger',
|
testId: 'billing-panel-trigger',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -104,7 +104,7 @@ export const useGeneralSettingList = (): GeneralSettingList => {
|
|||||||
settings.push({
|
settings.push({
|
||||||
key: 'experimental-features',
|
key: 'experimental-features',
|
||||||
title: t['com.affine.settings.workspace.experimental-features'](),
|
title: t['com.affine.settings.workspace.experimental-features'](),
|
||||||
icon: ExperimentIcon,
|
icon: <ExperimentIcon />,
|
||||||
testId: 'experimental-features-trigger',
|
testId: 'experimental-features-trigger',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import type {
|
|||||||
} from '@affine/core/modules/dialogs';
|
} from '@affine/core/modules/dialogs';
|
||||||
import type { SettingTab } from '@affine/core/modules/dialogs/constant';
|
import type { SettingTab } from '@affine/core/modules/dialogs/constant';
|
||||||
import { GlobalContextService } from '@affine/core/modules/global-context';
|
import { GlobalContextService } from '@affine/core/modules/global-context';
|
||||||
import type { WorkspaceMetadata } from '@affine/core/modules/workspace';
|
|
||||||
import { Trans } from '@affine/i18n';
|
import { Trans } from '@affine/i18n';
|
||||||
import { ContactWithUsIcon } from '@blocksuite/icons/rc';
|
import { ContactWithUsIcon } from '@blocksuite/icons/rc';
|
||||||
import { FrameworkScope, useLiveData, useService } from '@toeverything/infra';
|
import { FrameworkScope, useLiveData, useService } from '@toeverything/infra';
|
||||||
@@ -37,7 +36,6 @@ import { WorkspaceSetting } from './workspace-setting';
|
|||||||
|
|
||||||
interface SettingProps extends ModalProps {
|
interface SettingProps extends ModalProps {
|
||||||
activeTab?: SettingTab;
|
activeTab?: SettingTab;
|
||||||
workspaceMetadata?: WorkspaceMetadata | null;
|
|
||||||
onCloseSetting: () => void;
|
onCloseSetting: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,12 +52,10 @@ const CenteredLoading = () => {
|
|||||||
|
|
||||||
const SettingModalInner = ({
|
const SettingModalInner = ({
|
||||||
activeTab: initialActiveTab = 'appearance',
|
activeTab: initialActiveTab = 'appearance',
|
||||||
workspaceMetadata: initialWorkspaceMetadata = null,
|
|
||||||
onCloseSetting,
|
onCloseSetting,
|
||||||
}: SettingProps) => {
|
}: SettingProps) => {
|
||||||
const [settingState, setSettingState] = useState<SettingState>({
|
const [settingState, setSettingState] = useState<SettingState>({
|
||||||
activeTab: initialActiveTab,
|
activeTab: initialActiveTab,
|
||||||
activeWorkspaceMetadata: initialWorkspaceMetadata,
|
|
||||||
scrollAnchor: undefined,
|
scrollAnchor: undefined,
|
||||||
});
|
});
|
||||||
const globalContextService = useService(GlobalContextService);
|
const globalContextService = useService(GlobalContextService);
|
||||||
@@ -122,8 +118,8 @@ const SettingModalInner = ({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onTabChange = useCallback(
|
const onTabChange = useCallback(
|
||||||
(key: SettingTab, meta: WorkspaceMetadata | null) => {
|
(key: SettingTab) => {
|
||||||
setSettingState({ activeTab: key, activeWorkspaceMetadata: meta });
|
setSettingState({ activeTab: key });
|
||||||
},
|
},
|
||||||
[setSettingState]
|
[setSettingState]
|
||||||
);
|
);
|
||||||
@@ -143,7 +139,6 @@ const SettingModalInner = ({
|
|||||||
<SettingSidebar
|
<SettingSidebar
|
||||||
activeTab={settingState.activeTab}
|
activeTab={settingState.activeTab}
|
||||||
onTabChange={onTabChange}
|
onTabChange={onTabChange}
|
||||||
selectedWorkspaceId={settingState.activeWorkspaceMetadata?.id ?? null}
|
|
||||||
/>
|
/>
|
||||||
<Scrollable.Root>
|
<Scrollable.Root>
|
||||||
<Scrollable.Viewport
|
<Scrollable.Viewport
|
||||||
@@ -158,11 +153,9 @@ const SettingModalInner = ({
|
|||||||
{settingState.activeTab === 'account' &&
|
{settingState.activeTab === 'account' &&
|
||||||
loginStatus === 'authenticated' ? (
|
loginStatus === 'authenticated' ? (
|
||||||
<AccountSetting onChangeSettingState={setSettingState} />
|
<AccountSetting onChangeSettingState={setSettingState} />
|
||||||
) : isWorkspaceSetting(settingState.activeTab) &&
|
) : isWorkspaceSetting(settingState.activeTab) ? (
|
||||||
settingState.activeWorkspaceMetadata ? (
|
|
||||||
<WorkspaceSetting
|
<WorkspaceSetting
|
||||||
activeTab={settingState.activeTab}
|
activeTab={settingState.activeTab}
|
||||||
workspaceMetadata={settingState.activeWorkspaceMetadata}
|
|
||||||
onCloseSetting={onCloseSetting}
|
onCloseSetting={onCloseSetting}
|
||||||
onChangeSettingState={setSettingState}
|
onChangeSettingState={setSettingState}
|
||||||
/>
|
/>
|
||||||
@@ -214,7 +207,6 @@ const SettingModalInner = ({
|
|||||||
export const SettingDialog = ({
|
export const SettingDialog = ({
|
||||||
close,
|
close,
|
||||||
activeTab,
|
activeTab,
|
||||||
workspaceMetadata,
|
|
||||||
}: DialogComponentProps<GLOBAL_DIALOG_SCHEMA['setting']>) => {
|
}: DialogComponentProps<GLOBAL_DIALOG_SCHEMA['setting']>) => {
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
@@ -234,11 +226,7 @@ export const SettingDialog = ({
|
|||||||
onOpenChange={() => close()}
|
onOpenChange={() => close()}
|
||||||
>
|
>
|
||||||
<Suspense fallback={<CenteredLoading />}>
|
<Suspense fallback={<CenteredLoading />}>
|
||||||
<SettingModalInner
|
<SettingModalInner activeTab={activeTab} onCloseSetting={close} />
|
||||||
activeTab={activeTab}
|
|
||||||
workspaceMetadata={workspaceMetadata}
|
|
||||||
onCloseSetting={close}
|
|
||||||
/>
|
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,30 +1,31 @@
|
|||||||
import {
|
import { WorkspaceListSkeleton } from '@affine/component/setting-components';
|
||||||
WorkspaceListItemSkeleton,
|
|
||||||
WorkspaceListSkeleton,
|
|
||||||
} from '@affine/component/setting-components';
|
|
||||||
import { Avatar } from '@affine/component/ui/avatar';
|
import { Avatar } from '@affine/component/ui/avatar';
|
||||||
import { Tooltip } from '@affine/component/ui/tooltip';
|
|
||||||
import { UserPlanButton } from '@affine/core/components/affine/auth/user-plan-button';
|
import { UserPlanButton } from '@affine/core/components/affine/auth/user-plan-button';
|
||||||
import { useCatchEventCallback } from '@affine/core/components/hooks/use-catch-event-hook';
|
import { useCatchEventCallback } from '@affine/core/components/hooks/use-catch-event-hook';
|
||||||
import { useWorkspaceInfo } from '@affine/core/components/hooks/use-workspace-info';
|
import { useWorkspaceInfo } from '@affine/core/components/hooks/use-workspace-info';
|
||||||
import { WorkspaceAvatar } from '@affine/core/components/workspace-avatar';
|
import { CurrentWorkspaceScopeProvider } from '@affine/core/components/providers/current-workspace-scope';
|
||||||
import { AuthService } from '@affine/core/modules/cloud';
|
import { AuthService } from '@affine/core/modules/cloud';
|
||||||
import { UserFeatureService } from '@affine/core/modules/cloud/services/user-feature';
|
import { UserFeatureService } from '@affine/core/modules/cloud/services/user-feature';
|
||||||
import { GlobalDialogService } from '@affine/core/modules/dialogs';
|
import { GlobalDialogService } from '@affine/core/modules/dialogs';
|
||||||
import type { SettingTab } from '@affine/core/modules/dialogs/constant';
|
import type { SettingTab } from '@affine/core/modules/dialogs/constant';
|
||||||
import { GlobalContextService } from '@affine/core/modules/global-context';
|
|
||||||
import {
|
import {
|
||||||
type WorkspaceMetadata,
|
type WorkspaceMetadata,
|
||||||
WorkspacesService,
|
WorkspaceService,
|
||||||
} from '@affine/core/modules/workspace';
|
} from '@affine/core/modules/workspace';
|
||||||
import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant';
|
|
||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
import { track } from '@affine/track';
|
import { track } from '@affine/track';
|
||||||
import { Logo1Icon } from '@blocksuite/icons/rc';
|
import {
|
||||||
|
Logo1Icon,
|
||||||
|
PaymentIcon,
|
||||||
|
PropertyIcon,
|
||||||
|
SettingsIcon,
|
||||||
|
} from '@blocksuite/icons/rc';
|
||||||
import { useLiveData, useService, useServices } from '@toeverything/infra';
|
import { useLiveData, useService, useServices } from '@toeverything/infra';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import {
|
import {
|
||||||
|
type HTMLAttributes,
|
||||||
type MouseEvent,
|
type MouseEvent,
|
||||||
|
type ReactNode,
|
||||||
Suspense,
|
Suspense,
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
@@ -117,17 +118,36 @@ export const SignInButton = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const SettingSidebarItem = ({
|
||||||
|
isActive,
|
||||||
|
icon,
|
||||||
|
label,
|
||||||
|
...props
|
||||||
|
}: {
|
||||||
|
isActive: boolean;
|
||||||
|
label: string;
|
||||||
|
icon: ReactNode;
|
||||||
|
} & HTMLAttributes<HTMLDivElement>) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
{...props}
|
||||||
|
title={label}
|
||||||
|
className={clsx(style.sidebarSelectItem, {
|
||||||
|
active: isActive,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<div className={style.sidebarSelectItemIcon}>{icon}</div>
|
||||||
|
<div className={style.sidebarSelectItemName}>{label}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const SettingSidebar = ({
|
export const SettingSidebar = ({
|
||||||
activeTab,
|
activeTab,
|
||||||
onTabChange,
|
onTabChange,
|
||||||
selectedWorkspaceId,
|
|
||||||
}: {
|
}: {
|
||||||
activeTab: SettingTab;
|
activeTab: SettingTab;
|
||||||
onTabChange: (
|
onTabChange: (key: SettingTab) => void;
|
||||||
key: SettingTab,
|
|
||||||
workspaceMetadata: WorkspaceMetadata | null
|
|
||||||
) => void;
|
|
||||||
selectedWorkspaceId: string | null;
|
|
||||||
}) => {
|
}) => {
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const loginStatus = useLiveData(useService(AuthService).session.status$);
|
const loginStatus = useLiveData(useService(AuthService).session.status$);
|
||||||
@@ -137,21 +157,21 @@ export const SettingSidebar = ({
|
|||||||
const tab = e.currentTarget.dataset.eventArg;
|
const tab = e.currentTarget.dataset.eventArg;
|
||||||
if (!tab) return;
|
if (!tab) return;
|
||||||
track.$.settingsPanel.menu.openSettings({ to: tab });
|
track.$.settingsPanel.menu.openSettings({ to: tab });
|
||||||
onTabChange(tab as SettingTab, null);
|
onTabChange(tab as SettingTab);
|
||||||
},
|
},
|
||||||
[onTabChange]
|
[onTabChange]
|
||||||
);
|
);
|
||||||
const onAccountSettingClick = useCallback(() => {
|
const onAccountSettingClick = useCallback(() => {
|
||||||
track.$.settingsPanel.menu.openSettings({ to: 'account' });
|
track.$.settingsPanel.menu.openSettings({ to: 'account' });
|
||||||
onTabChange('account', null);
|
onTabChange('account');
|
||||||
}, [onTabChange]);
|
}, [onTabChange]);
|
||||||
const onWorkspaceSettingClick = useCallback(
|
const onWorkspaceSettingClick = useCallback(
|
||||||
(tab: SettingTab, workspaceMetadata: WorkspaceMetadata) => {
|
(tab: SettingTab) => {
|
||||||
track.$.settingsPanel.menu.openSettings({
|
track.$.settingsPanel.menu.openSettings({
|
||||||
to: 'workspace',
|
to: 'workspace',
|
||||||
control: tab,
|
control: tab,
|
||||||
});
|
});
|
||||||
onTabChange(tab, workspaceMetadata);
|
onTabChange(tab);
|
||||||
},
|
},
|
||||||
[onTabChange]
|
[onTabChange]
|
||||||
);
|
);
|
||||||
@@ -161,43 +181,7 @@ export const SettingSidebar = ({
|
|||||||
<div className={style.sidebarTitle}>
|
<div className={style.sidebarTitle}>
|
||||||
{t['com.affine.settingSidebar.title']()}
|
{t['com.affine.settingSidebar.title']()}
|
||||||
</div>
|
</div>
|
||||||
<div className={style.sidebarSubtitle}>
|
|
||||||
{t['com.affine.settingSidebar.settings.general']()}
|
|
||||||
</div>
|
|
||||||
<div className={style.sidebarItemsWrapper}>
|
|
||||||
{generalList.map(({ title, icon, key, testId }) => {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={clsx(style.sidebarSelectItem, {
|
|
||||||
active: key === activeTab,
|
|
||||||
})}
|
|
||||||
key={key}
|
|
||||||
title={title}
|
|
||||||
data-event-arg={key}
|
|
||||||
onClick={gotoTab}
|
|
||||||
data-testid={testId}
|
|
||||||
>
|
|
||||||
{icon({ className: 'icon' })}
|
|
||||||
<span className="setting-name">{title}</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={style.sidebarSubtitle}>
|
|
||||||
{t['com.affine.settingSidebar.settings.workspace']()}
|
|
||||||
</div>
|
|
||||||
<div className={clsx(style.sidebarItemsWrapper, 'scroll')}>
|
|
||||||
<Suspense fallback={<WorkspaceListSkeleton />}>
|
|
||||||
<WorkspaceList
|
|
||||||
onWorkspaceSettingClick={onWorkspaceSettingClick}
|
|
||||||
selectedWorkspaceId={selectedWorkspaceId}
|
|
||||||
activeTab={activeTab}
|
|
||||||
/>
|
|
||||||
</Suspense>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={style.sidebarFooter}>
|
|
||||||
{loginStatus === 'unauthenticated' ? <SignInButton /> : null}
|
{loginStatus === 'unauthenticated' ? <SignInButton /> : null}
|
||||||
{loginStatus === 'authenticated' ? (
|
{loginStatus === 'authenticated' ? (
|
||||||
<Suspense>
|
<Suspense>
|
||||||
@@ -208,148 +192,118 @@ export const SettingSidebar = ({
|
|||||||
/>
|
/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const WorkspaceList = ({
|
<div className={style.sidebarGroup}>
|
||||||
onWorkspaceSettingClick,
|
<div className={style.sidebarSubtitle}>
|
||||||
selectedWorkspaceId,
|
{t['com.affine.settingSidebar.settings.general']()}
|
||||||
activeTab,
|
</div>
|
||||||
}: {
|
<div className={style.sidebarItemsWrapper}>
|
||||||
onWorkspaceSettingClick: (
|
{generalList.map(({ title, icon, key, testId }) => {
|
||||||
activeTab: SettingTab,
|
|
||||||
workspaceMetadata: WorkspaceMetadata
|
|
||||||
) => void;
|
|
||||||
selectedWorkspaceId: string | null;
|
|
||||||
activeTab: SettingTab;
|
|
||||||
}) => {
|
|
||||||
const workspaces = useLiveData(
|
|
||||||
useService(WorkspacesService).list.workspaces$
|
|
||||||
);
|
|
||||||
return (
|
return (
|
||||||
<>
|
<SettingSidebarItem
|
||||||
{workspaces.map(workspace => {
|
isActive={key === activeTab}
|
||||||
return (
|
key={key}
|
||||||
<Suspense key={workspace.id} fallback={<WorkspaceListItemSkeleton />}>
|
label={title}
|
||||||
<WorkspaceListItem
|
data-event-arg={key}
|
||||||
meta={workspace}
|
onClick={gotoTab}
|
||||||
onClick={subTab => {
|
data-testid={testId}
|
||||||
onWorkspaceSettingClick(subTab, workspace);
|
icon={icon}
|
||||||
}}
|
|
||||||
activeTab={
|
|
||||||
workspace.id === selectedWorkspaceId ? activeTab : undefined
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</Suspense>
|
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={style.sidebarGroup}>
|
||||||
|
<div className={style.sidebarSubtitle}>
|
||||||
|
{t['com.affine.settingSidebar.settings.workspace']()}
|
||||||
|
</div>
|
||||||
|
<div className={style.sidebarItemsWrapper}>
|
||||||
|
<Suspense fallback={<WorkspaceListSkeleton />}>
|
||||||
|
<CurrentWorkspaceScopeProvider>
|
||||||
|
<WorkspaceSettingItems
|
||||||
|
onWorkspaceSettingClick={onWorkspaceSettingClick}
|
||||||
|
activeTab={activeTab}
|
||||||
|
/>
|
||||||
|
</CurrentWorkspaceScopeProvider>
|
||||||
|
</Suspense>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const WorkspaceListItem = ({
|
const WorkspaceSettingItems = ({
|
||||||
|
onWorkspaceSettingClick,
|
||||||
activeTab,
|
activeTab,
|
||||||
meta,
|
|
||||||
onClick,
|
|
||||||
}: {
|
}: {
|
||||||
meta: WorkspaceMetadata;
|
onWorkspaceSettingClick: (activeTab: SettingTab) => void;
|
||||||
activeTab?: SettingTab;
|
activeTab: SettingTab;
|
||||||
onClick: (activeTab: SettingTab) => void;
|
|
||||||
}) => {
|
}) => {
|
||||||
const { globalContextService, userFeatureService } = useServices({
|
const { userFeatureService } = useServices({
|
||||||
GlobalContextService,
|
|
||||||
UserFeatureService,
|
UserFeatureService,
|
||||||
});
|
});
|
||||||
const information = useWorkspaceInfo(meta);
|
|
||||||
const name = information?.name ?? UNTITLED_WORKSPACE_NAME;
|
const workspaceService = useService(WorkspaceService);
|
||||||
const currentWorkspaceId = useLiveData(
|
const information = useWorkspaceInfo(workspaceService.workspace);
|
||||||
globalContextService.globalContext.workspaceId.$
|
|
||||||
);
|
|
||||||
const isCurrent = currentWorkspaceId === meta.id;
|
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
userFeatureService.userFeature.revalidate();
|
userFeatureService.userFeature.revalidate();
|
||||||
}, [userFeatureService]);
|
}, [userFeatureService]);
|
||||||
|
|
||||||
const onClickPreference = useCallback(() => {
|
|
||||||
onClick('workspace:preference');
|
|
||||||
}, [onClick]);
|
|
||||||
|
|
||||||
const showBilling = information?.isTeam && information?.isOwner;
|
const showBilling = information?.isTeam && information?.isOwner;
|
||||||
const subTabs = useMemo(() => {
|
const subTabs = useMemo(() => {
|
||||||
const subTabConfigs = [
|
const subTabConfigs = [
|
||||||
{
|
{
|
||||||
key: 'workspace:preference',
|
key: 'workspace:preference',
|
||||||
title: 'com.affine.settings.workspace.preferences',
|
title: 'com.affine.settings.workspace.preferences',
|
||||||
|
icon: <SettingsIcon />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'workspace:properties',
|
key: 'workspace:properties',
|
||||||
title: 'com.affine.settings.workspace.properties',
|
title: 'com.affine.settings.workspace.properties',
|
||||||
|
icon: <PropertyIcon />,
|
||||||
},
|
},
|
||||||
...(showBilling
|
...(showBilling
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
key: 'workspace:billing' as SettingTab,
|
key: 'workspace:billing' as SettingTab,
|
||||||
title: 'com.affine.settings.workspace.billing',
|
title: 'com.affine.settings.workspace.billing',
|
||||||
|
icon: <PaymentIcon />,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
] satisfies {
|
] satisfies {
|
||||||
key: SettingTab;
|
key: SettingTab;
|
||||||
title: keyof ReturnType<typeof useI18n>;
|
title: keyof ReturnType<typeof useI18n>;
|
||||||
|
icon: ReactNode;
|
||||||
}[];
|
}[];
|
||||||
|
|
||||||
return subTabConfigs.map(({ key, title }) => {
|
return subTabConfigs.map(({ key, title, icon }) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<SettingSidebarItem
|
||||||
|
isActive={activeTab === key}
|
||||||
|
label={t[title]()}
|
||||||
|
icon={icon}
|
||||||
data-testid={`workspace-list-item-${key}`}
|
data-testid={`workspace-list-item-${key}`}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
onClick(key);
|
onWorkspaceSettingClick(key);
|
||||||
}}
|
}}
|
||||||
className={clsx(style.sidebarSelectSubItem, {
|
className={clsx(style.sidebarSelectItem, {
|
||||||
active: activeTab === key,
|
active: activeTab === key,
|
||||||
})}
|
})}
|
||||||
key={key}
|
key={key}
|
||||||
>
|
/>
|
||||||
{t[title]()}
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}, [activeTab, onClick, showBilling, t]);
|
}, [activeTab, onWorkspaceSettingClick, showBilling, t]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className={style.sidebarItemsWrapper}>
|
||||||
<div
|
{/* TODO: remove the suspense? */}
|
||||||
className={clsx(style.sidebarSelectItem, { active: !!activeTab })}
|
<Suspense fallback={<WorkspaceListSkeleton />}>{subTabs}</Suspense>
|
||||||
title={name}
|
|
||||||
onClick={onClickPreference}
|
|
||||||
data-testid="workspace-list-item"
|
|
||||||
>
|
|
||||||
<WorkspaceAvatar
|
|
||||||
key={meta.id}
|
|
||||||
meta={meta}
|
|
||||||
size={16}
|
|
||||||
name={name}
|
|
||||||
colorfulFallback
|
|
||||||
style={{
|
|
||||||
marginRight: '10px',
|
|
||||||
}}
|
|
||||||
rounded={2}
|
|
||||||
/>
|
|
||||||
<span className="setting-name">{name}</span>
|
|
||||||
{isCurrent ? (
|
|
||||||
<Tooltip content="Current" side="top">
|
|
||||||
<div
|
|
||||||
className={style.currentWorkspaceLabel}
|
|
||||||
data-testid="current-workspace-label"
|
|
||||||
></div>
|
|
||||||
</Tooltip>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
{activeTab && subTabs.length > 1 ? subTabs : null}
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,28 +1,29 @@
|
|||||||
import { cssVar } from '@toeverything/theme';
|
import { cssVar } from '@toeverything/theme';
|
||||||
|
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||||
import { globalStyle, style } from '@vanilla-extract/css';
|
import { globalStyle, style } from '@vanilla-extract/css';
|
||||||
export const settingSlideBar = style({
|
export const settingSlideBar = style({
|
||||||
width: '25%',
|
width: '25%',
|
||||||
maxWidth: '242px',
|
maxWidth: '242px',
|
||||||
background: cssVar('backgroundSecondaryColor'),
|
background: cssVar('backgroundSecondaryColor'),
|
||||||
padding: '20px 0px',
|
padding: '20px 12px',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
|
gap: '16px',
|
||||||
|
overflowY: 'auto',
|
||||||
});
|
});
|
||||||
export const sidebarTitle = style({
|
export const sidebarTitle = style({
|
||||||
fontSize: cssVar('fontH6'),
|
fontSize: cssVar('fontH6'),
|
||||||
fontWeight: '600',
|
fontWeight: '600',
|
||||||
lineHeight: cssVar('lineHeight'),
|
lineHeight: cssVar('lineHeight'),
|
||||||
padding: '0px 16px 0px 24px',
|
padding: '0 8px',
|
||||||
});
|
});
|
||||||
export const sidebarSubtitle = style({
|
export const sidebarSubtitle = style({
|
||||||
fontSize: cssVar('fontSm'),
|
fontSize: cssVar('fontSm'),
|
||||||
lineHeight: cssVar('lineHeight'),
|
lineHeight: cssVar('lineHeight'),
|
||||||
color: cssVar('textSecondaryColor'),
|
color: cssVar('textSecondaryColor'),
|
||||||
padding: '0px 16px 0px 24px',
|
padding: '4px 8px',
|
||||||
marginTop: '20px',
|
|
||||||
marginBottom: '4px',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
@@ -31,18 +32,11 @@ export const sidebarItemsWrapper = style({
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
gap: 4,
|
gap: 4,
|
||||||
selectors: {
|
|
||||||
'&.scroll': {
|
|
||||||
flexGrow: 1,
|
|
||||||
overflowY: 'auto',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
export const sidebarSelectItem = style({
|
export const sidebarSelectItem = style({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
margin: '0px 16px',
|
padding: '4px 8px',
|
||||||
padding: '0px 8px',
|
|
||||||
height: '30px',
|
height: '30px',
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
fontSize: cssVar('fontSm'),
|
fontSize: cssVar('fontSm'),
|
||||||
@@ -76,19 +70,23 @@ export const sidebarSelectSubItem = style({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
globalStyle(`${settingSlideBar} .icon`, {
|
|
||||||
|
export const sidebarSelectItemIcon = style({
|
||||||
width: '16px',
|
width: '16px',
|
||||||
height: '16px',
|
height: '16px',
|
||||||
marginRight: '10px',
|
marginRight: '10px',
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
|
color: cssVarV2('icon/primary'),
|
||||||
});
|
});
|
||||||
globalStyle(`${settingSlideBar} .setting-name`, {
|
|
||||||
|
export const sidebarSelectItemName = style({
|
||||||
minWidth: 0,
|
minWidth: 0,
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
textOverflow: 'ellipsis',
|
textOverflow: 'ellipsis',
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const currentWorkspaceLabel = style({
|
export const currentWorkspaceLabel = style({
|
||||||
width: '20px',
|
width: '20px',
|
||||||
height: '20px',
|
height: '20px',
|
||||||
@@ -105,9 +103,13 @@ export const currentWorkspaceLabel = style({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
export const sidebarFooter = style({
|
|
||||||
padding: '0 16px',
|
export const sidebarGroup = style({
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
gap: '4px',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const accountButton = style({
|
export const accountButton = style({
|
||||||
padding: '4px 8px',
|
padding: '4px 8px',
|
||||||
borderRadius: '8px',
|
borderRadius: '8px',
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import type { SettingTab } from '@affine/core/modules/dialogs/constant';
|
import type { SettingTab } from '@affine/core/modules/dialogs/constant';
|
||||||
import type { WorkspaceMetadata } from '@affine/core/modules/workspace';
|
|
||||||
|
|
||||||
export interface SettingState {
|
export interface SettingState {
|
||||||
activeTab: SettingTab;
|
activeTab: SettingTab;
|
||||||
activeWorkspaceMetadata?: WorkspaceMetadata | null;
|
|
||||||
scrollAnchor?: string;
|
scrollAnchor?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import {
|
|||||||
import { getUpgradeQuestionnaireLink } from '@affine/core/components/hooks/affine/use-subscription-notify';
|
import { getUpgradeQuestionnaireLink } from '@affine/core/components/hooks/affine/use-subscription-notify';
|
||||||
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
|
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
|
||||||
import { useMutation } from '@affine/core/components/hooks/use-mutation';
|
import { useMutation } from '@affine/core/components/hooks/use-mutation';
|
||||||
import { useWorkspace } from '@affine/core/components/hooks/use-workspace';
|
|
||||||
import {
|
import {
|
||||||
AuthService,
|
AuthService,
|
||||||
SubscriptionService,
|
SubscriptionService,
|
||||||
@@ -17,7 +16,7 @@ import {
|
|||||||
} from '@affine/core/modules/cloud';
|
} from '@affine/core/modules/cloud';
|
||||||
import { WorkspaceQuotaService } from '@affine/core/modules/quota';
|
import { WorkspaceQuotaService } from '@affine/core/modules/quota';
|
||||||
import { UrlService } from '@affine/core/modules/url';
|
import { UrlService } from '@affine/core/modules/url';
|
||||||
import type { WorkspaceMetadata } from '@affine/core/modules/workspace';
|
import { WorkspaceService } from '@affine/core/modules/workspace';
|
||||||
import {
|
import {
|
||||||
createCustomerPortalMutation,
|
createCustomerPortalMutation,
|
||||||
type InvoicesQuery,
|
type InvoicesQuery,
|
||||||
@@ -27,7 +26,7 @@ import {
|
|||||||
UserFriendlyError,
|
UserFriendlyError,
|
||||||
} from '@affine/graphql';
|
} from '@affine/graphql';
|
||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
import { FrameworkScope, useLiveData, useService } from '@toeverything/infra';
|
import { useLiveData, useService } from '@toeverything/infra';
|
||||||
import { cssVar } from '@toeverything/theme';
|
import { cssVar } from '@toeverything/theme';
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
|
|
||||||
@@ -37,14 +36,8 @@ import {
|
|||||||
} from '../../general-setting/plans/actions';
|
} from '../../general-setting/plans/actions';
|
||||||
import * as styles from './styles.css';
|
import * as styles from './styles.css';
|
||||||
|
|
||||||
export const WorkspaceSettingBilling = ({
|
export const WorkspaceSettingBilling = () => {
|
||||||
workspaceMetadata,
|
const workspace = useService(WorkspaceService).workspace;
|
||||||
}: {
|
|
||||||
workspaceMetadata: WorkspaceMetadata;
|
|
||||||
}) => {
|
|
||||||
// useWorkspace hook is a vary heavy operation here, but we need syncing name and avatar changes here,
|
|
||||||
// we don't have a better way to do this now
|
|
||||||
const workspace = useWorkspace(workspaceMetadata);
|
|
||||||
|
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
|
|
||||||
@@ -68,7 +61,7 @@ export const WorkspaceSettingBilling = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FrameworkScope scope={workspace.scope}>
|
<>
|
||||||
<SettingHeader
|
<SettingHeader
|
||||||
title={t['com.affine.payment.billing-setting.title']()}
|
title={t['com.affine.payment.billing-setting.title']()}
|
||||||
subtitle={t['com.affine.payment.billing-setting.subtitle']()}
|
subtitle={t['com.affine.payment.billing-setting.subtitle']()}
|
||||||
@@ -87,7 +80,7 @@ export const WorkspaceSettingBilling = ({
|
|||||||
<SettingWrapper title={t['com.affine.payment.billing-setting.history']()}>
|
<SettingWrapper title={t['com.affine.payment.billing-setting.history']()}>
|
||||||
<BillingHistory />
|
<BillingHistory />
|
||||||
</SettingWrapper>
|
</SettingWrapper>
|
||||||
</FrameworkScope>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
|
import { CurrentWorkspaceScopeProvider } from '@affine/core/components/providers/current-workspace-scope';
|
||||||
import type { SettingTab } from '@affine/core/modules/dialogs/constant';
|
import type { SettingTab } from '@affine/core/modules/dialogs/constant';
|
||||||
import type { WorkspaceMetadata } from '@affine/core/modules/workspace';
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
import type { SettingState } from '../types';
|
import type { SettingState } from '../types';
|
||||||
import { WorkspaceSettingBilling } from './billing';
|
import { WorkspaceSettingBilling } from './billing';
|
||||||
@@ -7,31 +8,32 @@ import { WorkspaceSettingDetail } from './new-workspace-setting-detail';
|
|||||||
import { WorkspaceSettingProperties } from './properties';
|
import { WorkspaceSettingProperties } from './properties';
|
||||||
|
|
||||||
export const WorkspaceSetting = ({
|
export const WorkspaceSetting = ({
|
||||||
workspaceMetadata,
|
|
||||||
activeTab,
|
activeTab,
|
||||||
onCloseSetting,
|
onCloseSetting,
|
||||||
onChangeSettingState,
|
onChangeSettingState,
|
||||||
}: {
|
}: {
|
||||||
workspaceMetadata: WorkspaceMetadata;
|
|
||||||
activeTab: SettingTab;
|
activeTab: SettingTab;
|
||||||
onCloseSetting: () => void;
|
onCloseSetting: () => void;
|
||||||
onChangeSettingState: (settingState: SettingState) => void;
|
onChangeSettingState: (settingState: SettingState) => void;
|
||||||
}) => {
|
}) => {
|
||||||
|
const element = useMemo(() => {
|
||||||
switch (activeTab) {
|
switch (activeTab) {
|
||||||
case 'workspace:preference':
|
case 'workspace:preference':
|
||||||
return (
|
return (
|
||||||
<WorkspaceSettingDetail
|
<WorkspaceSettingDetail
|
||||||
onCloseSetting={onCloseSetting}
|
onCloseSetting={onCloseSetting}
|
||||||
onChangeSettingState={onChangeSettingState}
|
onChangeSettingState={onChangeSettingState}
|
||||||
workspaceMetadata={workspaceMetadata}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case 'workspace:properties':
|
case 'workspace:properties':
|
||||||
return (
|
return <WorkspaceSettingProperties />;
|
||||||
<WorkspaceSettingProperties workspaceMetadata={workspaceMetadata} />
|
|
||||||
);
|
|
||||||
case 'workspace:billing':
|
case 'workspace:billing':
|
||||||
return <WorkspaceSettingBilling workspaceMetadata={workspaceMetadata} />;
|
return <WorkspaceSettingBilling />;
|
||||||
}
|
default:
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
}, [activeTab, onCloseSetting, onChangeSettingState]);
|
||||||
|
return (
|
||||||
|
<CurrentWorkspaceScopeProvider>{element}</CurrentWorkspaceScopeProvider>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,25 +5,18 @@ import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hoo
|
|||||||
import { useSystemOnline } from '@affine/core/components/hooks/use-system-online';
|
import { useSystemOnline } from '@affine/core/components/hooks/use-system-online';
|
||||||
import { DesktopApiService } from '@affine/core/modules/desktop-api';
|
import { DesktopApiService } from '@affine/core/modules/desktop-api';
|
||||||
import { WorkspacePermissionService } from '@affine/core/modules/permissions';
|
import { WorkspacePermissionService } from '@affine/core/modules/permissions';
|
||||||
import type {
|
import type { Workspace } from '@affine/core/modules/workspace';
|
||||||
Workspace,
|
|
||||||
WorkspaceMetadata,
|
|
||||||
} from '@affine/core/modules/workspace';
|
|
||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
import track from '@affine/track';
|
import track from '@affine/track';
|
||||||
import { useLiveData, useService } from '@toeverything/infra';
|
import { useLiveData, useService } from '@toeverything/infra';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
interface ExportPanelProps {
|
interface ExportPanelProps {
|
||||||
workspaceMetadata: WorkspaceMetadata;
|
workspace: Workspace;
|
||||||
workspace: Workspace | null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DesktopExportPanel = ({
|
export const DesktopExportPanel = ({ workspace }: ExportPanelProps) => {
|
||||||
workspaceMetadata,
|
const workspaceId = workspace.id;
|
||||||
workspace,
|
|
||||||
}: ExportPanelProps) => {
|
|
||||||
const workspaceId = workspaceMetadata.id;
|
|
||||||
const workspacePermissionService = useService(
|
const workspacePermissionService = useService(
|
||||||
WorkspacePermissionService
|
WorkspacePermissionService
|
||||||
).permission;
|
).permission;
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ import {
|
|||||||
SettingRow,
|
SettingRow,
|
||||||
SettingWrapper,
|
SettingWrapper,
|
||||||
} from '@affine/component/setting-components';
|
} from '@affine/component/setting-components';
|
||||||
import { useWorkspace } from '@affine/core/components/hooks/use-workspace';
|
|
||||||
import { useWorkspaceInfo } from '@affine/core/components/hooks/use-workspace-info';
|
import { useWorkspaceInfo } from '@affine/core/components/hooks/use-workspace-info';
|
||||||
import { WorkspaceServerService } from '@affine/core/modules/cloud';
|
import { WorkspaceServerService } from '@affine/core/modules/cloud';
|
||||||
|
import { WorkspaceService } from '@affine/core/modules/workspace';
|
||||||
import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant';
|
import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant';
|
||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
import { ArrowRightSmallIcon } from '@blocksuite/icons/rc';
|
import { ArrowRightSmallIcon } from '@blocksuite/icons/rc';
|
||||||
import { FrameworkScope } from '@toeverything/infra';
|
import { FrameworkScope, useService } from '@toeverything/infra';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
import { DeleteLeaveWorkspace } from './delete-leave-workspace';
|
import { DeleteLeaveWorkspace } from './delete-leave-workspace';
|
||||||
@@ -24,18 +24,15 @@ import type { WorkspaceSettingDetailProps } from './types';
|
|||||||
import { WorkspaceQuotaPanel } from './workspace-quota';
|
import { WorkspaceQuotaPanel } from './workspace-quota';
|
||||||
|
|
||||||
export const WorkspaceSettingDetail = ({
|
export const WorkspaceSettingDetail = ({
|
||||||
workspaceMetadata,
|
|
||||||
onCloseSetting,
|
onCloseSetting,
|
||||||
onChangeSettingState,
|
onChangeSettingState,
|
||||||
}: WorkspaceSettingDetailProps) => {
|
}: WorkspaceSettingDetailProps) => {
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
|
|
||||||
// useWorkspace hook is a vary heavy operation here, but we need syncing name and avatar changes here,
|
const workspace = useService(WorkspaceService).workspace;
|
||||||
// we don't have a better way to do this now
|
|
||||||
const workspace = useWorkspace(workspaceMetadata);
|
|
||||||
const server = workspace?.scope.get(WorkspaceServerService).server;
|
const server = workspace?.scope.get(WorkspaceServerService).server;
|
||||||
|
|
||||||
const workspaceInfo = useWorkspaceInfo(workspaceMetadata);
|
const workspaceInfo = useWorkspaceInfo(workspace);
|
||||||
|
|
||||||
const handleResetSyncStatus = useCallback(() => {
|
const handleResetSyncStatus = useCallback(() => {
|
||||||
workspace?.engine.doc
|
workspace?.engine.doc
|
||||||
@@ -80,10 +77,7 @@ export const WorkspaceSettingDetail = ({
|
|||||||
<SharingPanel />
|
<SharingPanel />
|
||||||
{BUILD_CONFIG.isElectron && (
|
{BUILD_CONFIG.isElectron && (
|
||||||
<SettingWrapper title={t['Storage and Export']()}>
|
<SettingWrapper title={t['Storage and Export']()}>
|
||||||
<DesktopExportPanel
|
<DesktopExportPanel workspace={workspace} />
|
||||||
workspace={workspace}
|
|
||||||
workspaceMetadata={workspaceMetadata}
|
|
||||||
/>
|
|
||||||
</SettingWrapper>
|
</SettingWrapper>
|
||||||
)}
|
)}
|
||||||
<SettingWrapper>
|
<SettingWrapper>
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
import type { WorkspaceMetadata } from '@affine/core/modules/workspace';
|
|
||||||
|
|
||||||
import type { SettingState } from '../../types';
|
import type { SettingState } from '../../types';
|
||||||
|
|
||||||
export interface WorkspaceSettingDetailProps {
|
export interface WorkspaceSettingDetailProps {
|
||||||
workspaceMetadata: WorkspaceMetadata;
|
|
||||||
onCloseSetting: () => void;
|
onCloseSetting: () => void;
|
||||||
onChangeSettingState: (settingState: SettingState) => void;
|
onChangeSettingState: (settingState: SettingState) => void;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,13 +4,12 @@ import { DocPropertyManager } from '@affine/core/components/doc-properties/manag
|
|||||||
import { CreatePropertyMenuItems } from '@affine/core/components/doc-properties/menu/create-doc-property';
|
import { CreatePropertyMenuItems } from '@affine/core/components/doc-properties/menu/create-doc-property';
|
||||||
import { useWorkspaceInfo } from '@affine/core/components/hooks/use-workspace-info';
|
import { useWorkspaceInfo } from '@affine/core/components/hooks/use-workspace-info';
|
||||||
import type { DocCustomPropertyInfo } from '@affine/core/modules/db';
|
import type { DocCustomPropertyInfo } from '@affine/core/modules/db';
|
||||||
import type { WorkspaceMetadata } from '@affine/core/modules/workspace';
|
import { WorkspaceService } from '@affine/core/modules/workspace';
|
||||||
import { Trans, useI18n } from '@affine/i18n';
|
import { Trans, useI18n } from '@affine/i18n';
|
||||||
import track from '@affine/track';
|
import track from '@affine/track';
|
||||||
import { FrameworkScope } from '@toeverything/infra';
|
import { FrameworkScope, useService } from '@toeverything/infra';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
import { useWorkspace } from '../../../../../components/hooks/use-workspace';
|
|
||||||
import * as styles from './styles.css';
|
import * as styles from './styles.css';
|
||||||
|
|
||||||
const WorkspaceSettingPropertiesMain = () => {
|
const WorkspaceSettingPropertiesMain = () => {
|
||||||
@@ -47,14 +46,10 @@ const WorkspaceSettingPropertiesMain = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const WorkspaceSettingProperties = ({
|
export const WorkspaceSettingProperties = () => {
|
||||||
workspaceMetadata,
|
|
||||||
}: {
|
|
||||||
workspaceMetadata: WorkspaceMetadata;
|
|
||||||
}) => {
|
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const workspace = useWorkspace(workspaceMetadata);
|
const workspace = useService(WorkspaceService).workspace;
|
||||||
const workspaceInfo = useWorkspaceInfo(workspaceMetadata);
|
const workspaceInfo = useWorkspaceInfo(workspace);
|
||||||
const title = workspaceInfo?.name || 'untitled';
|
const title = workspaceInfo?.name || 'untitled';
|
||||||
|
|
||||||
if (workspace === null) {
|
if (workspace === null) {
|
||||||
|
|||||||
@@ -265,11 +265,7 @@ export function FallbackHeaderWithWorkspaceNavigator() {
|
|||||||
return (
|
return (
|
||||||
<div className={styles.fallbackHeader}>
|
<div className={styles.fallbackHeader}>
|
||||||
{currentWorkspace && navigate ? (
|
{currentWorkspace && navigate ? (
|
||||||
<WorkspaceNavigator
|
<WorkspaceNavigator showSyncStatus showEnableCloudButton />
|
||||||
showSettingsButton
|
|
||||||
showSyncStatus
|
|
||||||
showEnableCloudButton
|
|
||||||
/>
|
|
||||||
) : (
|
) : (
|
||||||
<FallbackHeaderSkeleton />
|
<FallbackHeaderSkeleton />
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -35,7 +35,8 @@ export type { ServerConfig } from './types';
|
|||||||
|
|
||||||
import { type Framework } from '@toeverything/infra';
|
import { type Framework } from '@toeverything/infra';
|
||||||
|
|
||||||
import { DocScope, DocService } from '../doc';
|
import { DocScope } from '../doc/scopes/doc';
|
||||||
|
import { DocService } from '../doc/services/doc';
|
||||||
import { GlobalCache, GlobalState, GlobalStateService } from '../storage';
|
import { GlobalCache, GlobalState, GlobalStateService } from '../storage';
|
||||||
import { UrlService } from '../url';
|
import { UrlService } from '../url';
|
||||||
import { WorkspaceScope, WorkspaceService } from '../workspace';
|
import { WorkspaceScope, WorkspaceService } from '../workspace';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { Framework } from '@toeverything/infra';
|
import type { Framework } from '@toeverything/infra';
|
||||||
|
|
||||||
import { WorkspaceServerService } from '../cloud';
|
import { WorkspaceServerService } from '../cloud/services/workspace-server';
|
||||||
import { WorkspaceScope, WorkspaceService } from '../workspace';
|
import { WorkspaceScope, WorkspaceService } from '../workspace';
|
||||||
import { WorkspaceDB } from './entities/db';
|
import { WorkspaceDB } from './entities/db';
|
||||||
import { WorkspaceDBTable } from './entities/table';
|
import { WorkspaceDBTable } from './entities/table';
|
||||||
|
|||||||
@@ -26,11 +26,7 @@ export type GLOBAL_DIALOG_SCHEMA = {
|
|||||||
templateMode: DocMode;
|
templateMode: DocMode;
|
||||||
snapshotUrl: string;
|
snapshotUrl: string;
|
||||||
}) => void;
|
}) => void;
|
||||||
setting: (props: {
|
setting: (props: { activeTab?: SettingTab; scrollAnchor?: string }) => void;
|
||||||
activeTab?: SettingTab;
|
|
||||||
workspaceMetadata?: WorkspaceMetadata | null;
|
|
||||||
scrollAnchor?: string;
|
|
||||||
}) => void;
|
|
||||||
'sign-in': (props: { server?: string; step?: string }) => void;
|
'sign-in': (props: { server?: string; step?: string }) => void;
|
||||||
'change-password': (props: { server?: string }) => void;
|
'change-password': (props: { server?: string }) => void;
|
||||||
'verify-email': (props: { server?: string; changeEmail?: boolean }) => void;
|
'verify-email': (props: { server?: string; changeEmail?: boolean }) => void;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export { DocsService } from './services/docs';
|
|||||||
|
|
||||||
import type { Framework } from '@toeverything/infra';
|
import type { Framework } from '@toeverything/infra';
|
||||||
|
|
||||||
import { WorkspaceDBService } from '../db';
|
import { WorkspaceDBService } from '../db/services/db';
|
||||||
import { WorkspaceScope, WorkspaceService } from '../workspace';
|
import { WorkspaceScope, WorkspaceService } from '../workspace';
|
||||||
import { Doc } from './entities/doc';
|
import { Doc } from './entities/doc';
|
||||||
import { DocPropertyList } from './entities/property-list';
|
import { DocPropertyList } from './entities/property-list';
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ test('should have pagination in member list', async ({ page }) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
await openSettingModal(page);
|
await openSettingModal(page);
|
||||||
await openWorkspaceSettingPanel(page, 'test');
|
await openWorkspaceSettingPanel(page);
|
||||||
|
|
||||||
await page.waitForTimeout(1000);
|
await page.waitForTimeout(1000);
|
||||||
|
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ test('delete workspace', async ({ page }) => {
|
|||||||
// });
|
// });
|
||||||
await page.waitForTimeout(1000);
|
await page.waitForTimeout(1000);
|
||||||
await clickSideBarSettingButton(page);
|
await clickSideBarSettingButton(page);
|
||||||
await page.getByTestId('current-workspace-label').click();
|
await page.getByTestId('workspace-list-item-workspace:preference').click();
|
||||||
await expect(page.getByTestId('workspace-name-input')).toHaveValue(
|
await expect(page.getByTestId('workspace-name-input')).toHaveValue(
|
||||||
'Delete Me'
|
'Delete Me'
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ test('export then add', async ({ page, appInfo, workspace }) => {
|
|||||||
const newWorkspaceName = 'new-test-name';
|
const newWorkspaceName = 'new-test-name';
|
||||||
|
|
||||||
// goto workspace setting
|
// goto workspace setting
|
||||||
await page.getByTestId('workspace-list-item').click();
|
await page.getByTestId('workspace-list-item-workspace:preference').click();
|
||||||
const input = page.getByTestId('workspace-name-input');
|
const input = page.getByTestId('workspace-name-input');
|
||||||
await expect(input).toBeVisible();
|
await expect(input).toBeVisible();
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ test('should create a page with a local first avatar and remove it', async ({
|
|||||||
.nth(1)
|
.nth(1)
|
||||||
.click({ position: { x: 10, y: 10 } });
|
.click({ position: { x: 10, y: 10 } });
|
||||||
await page.getByTestId('settings-modal-trigger').click();
|
await page.getByTestId('settings-modal-trigger').click();
|
||||||
await page.getByTestId('current-workspace-label').click();
|
await page.getByTestId('workspace-list-item-workspace:preference').click();
|
||||||
await page
|
await page
|
||||||
.getByTestId('upload-avatar')
|
.getByTestId('upload-avatar')
|
||||||
.setInputFiles(ProjectRoot.join('tests', 'fixtures', 'blue.png').value);
|
.setInputFiles(ProjectRoot.join('tests', 'fixtures', 'blue.png').value);
|
||||||
@@ -61,7 +61,7 @@ test('should create a page with a local first avatar and remove it', async ({
|
|||||||
|
|
||||||
// Click remove button to remove workspace avatar
|
// Click remove button to remove workspace avatar
|
||||||
await page.getByTestId('settings-modal-trigger').click();
|
await page.getByTestId('settings-modal-trigger').click();
|
||||||
await page.getByTestId('current-workspace-label').click();
|
await page.getByTestId('workspace-list-item-workspace:preference').click();
|
||||||
await page.getByTestId('workspace-setting-avatar').hover();
|
await page.getByTestId('workspace-setting-avatar').hover();
|
||||||
await page.getByTestId('workspace-setting-remove-avatar-button').click();
|
await page.getByTestId('workspace-setting-remove-avatar-button').click();
|
||||||
await page.mouse.click(0, 0);
|
await page.mouse.click(0, 0);
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ test('Create new workspace, then delete it', async ({ page, workspace }) => {
|
|||||||
'Test Workspace'
|
'Test Workspace'
|
||||||
);
|
);
|
||||||
await openSettingModal(page);
|
await openSettingModal(page);
|
||||||
await openWorkspaceSettingPanel(page, 'Test Workspace');
|
await openWorkspaceSettingPanel(page);
|
||||||
await page.getByTestId('delete-workspace-button').click();
|
await page.getByTestId('delete-workspace-button').click();
|
||||||
await expect(
|
await expect(
|
||||||
page.locator('.affine-notification-center').first()
|
page.locator('.affine-notification-center').first()
|
||||||
@@ -64,7 +64,7 @@ test('Delete last workspace', async ({ page }) => {
|
|||||||
node => node.textContent
|
node => node.textContent
|
||||||
);
|
);
|
||||||
await openSettingModal(page);
|
await openSettingModal(page);
|
||||||
await openWorkspaceSettingPanel(page, currentWorkspaceName as string);
|
await openWorkspaceSettingPanel(page);
|
||||||
await page.getByTestId('delete-workspace-button').click();
|
await page.getByTestId('delete-workspace-button').click();
|
||||||
await page
|
await page
|
||||||
.getByTestId('delete-workspace-input')
|
.getByTestId('delete-workspace-input')
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import {
|
|||||||
openSettingModal,
|
openSettingModal,
|
||||||
openShortcutsPanel,
|
openShortcutsPanel,
|
||||||
} from '@affine-test/kit/utils/setting';
|
} from '@affine-test/kit/utils/setting';
|
||||||
import { createLocalWorkspace } from '@affine-test/kit/utils/workspace';
|
|
||||||
import { expect } from '@playwright/test';
|
import { expect } from '@playwright/test';
|
||||||
|
|
||||||
test('Open settings modal', async ({ page }) => {
|
test('Open settings modal', async ({ page }) => {
|
||||||
@@ -104,21 +103,3 @@ test('Open experimental features panel', async ({ page }) => {
|
|||||||
const settings = page.getByTestId('experimental-settings');
|
const settings = page.getByTestId('experimental-settings');
|
||||||
await expect(settings).toBeVisible();
|
await expect(settings).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Different workspace should have different name in the setting panel', async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
await openHomePage(page);
|
|
||||||
await waitForEditorLoad(page);
|
|
||||||
await createLocalWorkspace({ name: 'New Workspace 2' }, page);
|
|
||||||
await createLocalWorkspace({ name: 'New Workspace 3' }, page);
|
|
||||||
await openSettingModal(page);
|
|
||||||
await page.getByTestId('current-workspace-label').click();
|
|
||||||
await expect(page.getByTestId('workspace-name-input')).toHaveValue(
|
|
||||||
'New Workspace 3'
|
|
||||||
);
|
|
||||||
await page.getByText('New Workspace 2').click();
|
|
||||||
await expect(page.getByTestId('workspace-name-input')).toHaveValue(
|
|
||||||
'New Workspace 2'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ export async function loginUserDirectly(
|
|||||||
|
|
||||||
export async function enableCloudWorkspace(page: Page) {
|
export async function enableCloudWorkspace(page: Page) {
|
||||||
await clickSideBarSettingButton(page);
|
await clickSideBarSettingButton(page);
|
||||||
await page.getByTestId('current-workspace-label').click();
|
await page.getByTestId('workspace-list-item-workspace:preference').click();
|
||||||
await page.getByTestId('publish-enable-affine-cloud-button').click();
|
await page.getByTestId('publish-enable-affine-cloud-button').click();
|
||||||
await page.getByTestId('confirm-enable-affine-cloud-button').click();
|
await page.getByTestId('confirm-enable-affine-cloud-button').click();
|
||||||
// wait for upload and delete local workspace
|
// wait for upload and delete local workspace
|
||||||
|
|||||||
@@ -149,9 +149,6 @@ export const expectPropertyOrdering = async (
|
|||||||
|
|
||||||
export const openWorkspaceProperties = async (page: Page) => {
|
export const openWorkspaceProperties = async (page: Page) => {
|
||||||
await page.getByTestId('slider-bar-workspace-setting-button').click();
|
await page.getByTestId('slider-bar-workspace-setting-button').click();
|
||||||
await page
|
|
||||||
.locator('[data-testid="workspace-list-item"] .setting-name')
|
|
||||||
.click();
|
|
||||||
await page.getByTestId('workspace-list-item-workspace:properties').click();
|
await page.getByTestId('workspace-list-item-workspace:properties').click();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -38,11 +38,11 @@ export async function confirmExperimentalPrompt(page: Page) {
|
|||||||
await page.getByTestId('experimental-confirm-button').click();
|
await page.getByTestId('experimental-confirm-button').click();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function openWorkspaceSettingPanel(
|
export async function openWorkspaceSettingPanel(page: Page) {
|
||||||
page: Page,
|
await page
|
||||||
workspaceName: string
|
.getByTestId('settings-sidebar')
|
||||||
) {
|
.getByTestId('workspace-list-item-workspace:preference')
|
||||||
await page.getByTestId('settings-sidebar').getByText(workspaceName).click();
|
.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function clickUserInfoCard(page: Page) {
|
export async function clickUserInfoCard(page: Page) {
|
||||||
|
|||||||
Reference in New Issue
Block a user