refactor(core): move setting dialog to workspace scope (#9706)

This commit is contained in:
pengx17
2025-01-15 13:00:06 +00:00
parent 9df338274d
commit b1896746f9
32 changed files with 248 additions and 277 deletions

View File

@@ -9,7 +9,7 @@ import {
configureDesktopApiModule, configureDesktopApiModule,
DesktopApiService, DesktopApiService,
} from '@affine/core/modules/desktop-api'; } from '@affine/core/modules/desktop-api';
import { GlobalDialogService } from '@affine/core/modules/dialogs'; import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
import { DocsService } from '@affine/core/modules/doc'; import { DocsService } from '@affine/core/modules/doc';
import { import {
configureSpellCheckSettingModule, configureSpellCheckSettingModule,
@@ -124,7 +124,7 @@ window.addEventListener('unload', () => {
}); });
events?.applicationMenu.openAboutPageInSettingModal(() => events?.applicationMenu.openAboutPageInSettingModal(() =>
frameworkProvider.get(GlobalDialogService).open('setting', { frameworkProvider.get(WorkspaceDialogService).open('setting', {
activeTab: 'about', activeTab: 'about',
}) })
); );

View File

@@ -2,18 +2,18 @@ import type { useI18n } from '@affine/i18n';
import { track } from '@affine/track'; import { track } from '@affine/track';
import { ContactWithUsIcon, NewIcon } from '@blocksuite/icons/rc'; import { ContactWithUsIcon, NewIcon } from '@blocksuite/icons/rc';
import type { GlobalDialogService } from '../modules/dialogs'; import type { WorkspaceDialogService } from '../modules/dialogs';
import type { UrlService } from '../modules/url'; import type { UrlService } from '../modules/url';
import { registerAffineCommand } from './registry'; import { registerAffineCommand } from './registry';
export function registerAffineHelpCommands({ export function registerAffineHelpCommands({
t, t,
urlService, urlService,
globalDialogService, workspaceDialogService,
}: { }: {
t: ReturnType<typeof useI18n>; t: ReturnType<typeof useI18n>;
urlService: UrlService; urlService: UrlService;
globalDialogService: GlobalDialogService; workspaceDialogService: WorkspaceDialogService;
}) { }) {
const unsubs: Array<() => void> = []; const unsubs: Array<() => void> = [];
unsubs.push( unsubs.push(
@@ -36,7 +36,7 @@ export function registerAffineHelpCommands({
label: t['com.affine.cmdk.affine.contact-us'](), label: t['com.affine.cmdk.affine.contact-us'](),
run() { run() {
track.$.cmdk.help.contactUs(); track.$.cmdk.help.contactUs();
globalDialogService.open('setting', { workspaceDialogService.open('setting', {
activeTab: 'about', activeTab: 'about',
}); });
}, },

View File

@@ -6,7 +6,7 @@ import type { createStore } from 'jotai';
import { openWorkspaceListModalAtom } from '../components/atoms'; import { openWorkspaceListModalAtom } from '../components/atoms';
import type { useNavigateHelper } from '../components/hooks/use-navigate-helper'; import type { useNavigateHelper } from '../components/hooks/use-navigate-helper';
import type { GlobalDialogService } from '../modules/dialogs'; import type { WorkspaceDialogService } from '../modules/dialogs';
import { registerAffineCommand } from './registry'; import { registerAffineCommand } from './registry';
export function registerAffineNavigationCommands({ export function registerAffineNavigationCommands({
@@ -14,13 +14,13 @@ export function registerAffineNavigationCommands({
store, store,
docCollection, docCollection,
navigationHelper, navigationHelper,
globalDialogService, workspaceDialogService,
}: { }: {
t: ReturnType<typeof useI18n>; t: ReturnType<typeof useI18n>;
store: ReturnType<typeof createStore>; store: ReturnType<typeof createStore>;
navigationHelper: ReturnType<typeof useNavigateHelper>; navigationHelper: ReturnType<typeof useNavigateHelper>;
docCollection: Workspace; docCollection: Workspace;
globalDialogService: GlobalDialogService; workspaceDialogService: WorkspaceDialogService;
}) { }) {
const unsubs: Array<() => void> = []; const unsubs: Array<() => void> = [];
unsubs.push( unsubs.push(
@@ -96,7 +96,7 @@ export function registerAffineNavigationCommands({
keyBinding: '$mod+,', keyBinding: '$mod+,',
run() { run() {
track.$.cmdk.settings.openSettings(); track.$.cmdk.settings.openSettings();
globalDialogService.open('setting', { workspaceDialogService.open('setting', {
activeTab: 'appearance', activeTab: 'appearance',
}); });
}, },
@@ -111,7 +111,7 @@ export function registerAffineNavigationCommands({
label: t['com.affine.cmdk.affine.navigation.open-account-settings'](), label: t['com.affine.cmdk.affine.navigation.open-account-settings'](),
run() { run() {
track.$.cmdk.settings.openSettings({ to: 'account' }); track.$.cmdk.settings.openSettings({ to: 'account' });
globalDialogService.open('setting', { workspaceDialogService.open('setting', {
activeTab: 'account', activeTab: 'account',
}); });
}, },

View File

@@ -1,6 +1,6 @@
import { Button, FlexWrapper, notify } from '@affine/component'; import { Button, FlexWrapper, notify } from '@affine/component';
import { SubscriptionService } from '@affine/core/modules/cloud'; import { SubscriptionService } from '@affine/core/modules/cloud';
import { GlobalDialogService } from '@affine/core/modules/dialogs'; import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
import { EditorService } from '@affine/core/modules/editor'; import { EditorService } from '@affine/core/modules/editor';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { track } from '@affine/track'; import { track } from '@affine/track';
@@ -50,18 +50,18 @@ export const AIOnboardingEdgeless = () => {
const notifyId = useLiveData(edgelessNotifyId$); const notifyId = useLiveData(edgelessNotifyId$);
const generalAIOnboardingOpened = useLiveData(showAIOnboardingGeneral$); const generalAIOnboardingOpened = useLiveData(showAIOnboardingGeneral$);
const aiSubscription = useLiveData(subscriptionService.subscription.ai$); const aiSubscription = useLiveData(subscriptionService.subscription.ai$);
const globalDialogService = useService(GlobalDialogService); const workspaceDialogService = useService(WorkspaceDialogService);
const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null); const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const mode = useLiveData(editorService.editor.mode$); const mode = useLiveData(editorService.editor.mode$);
const goToPricingPlans = useCallback(() => { const goToPricingPlans = useCallback(() => {
track.$.aiOnboarding.dialog.viewPlans(); track.$.aiOnboarding.dialog.viewPlans();
globalDialogService.open('setting', { workspaceDialogService.open('setting', {
activeTab: 'plans', activeTab: 'plans',
scrollAnchor: 'aiPricingPlan', scrollAnchor: 'aiPricingPlan',
}); });
}, [globalDialogService]); }, [workspaceDialogService]);
useEffect(() => { useEffect(() => {
if (generalAIOnboardingOpened) return; if (generalAIOnboardingOpened) return;

View File

@@ -1,7 +1,7 @@
import { Button, IconButton, Modal } from '@affine/component'; import { Button, IconButton, Modal } from '@affine/component';
import { useBlurRoot } from '@affine/core/components/hooks/use-blur-root'; import { useBlurRoot } from '@affine/core/components/hooks/use-blur-root';
import { AuthService, SubscriptionService } from '@affine/core/modules/cloud'; import { AuthService, SubscriptionService } from '@affine/core/modules/cloud';
import { GlobalDialogService } from '@affine/core/modules/dialogs'; import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
import { Trans, useI18n } from '@affine/i18n'; import { Trans, useI18n } from '@affine/i18n';
import { track } from '@affine/track'; import { track } from '@affine/track';
import { ArrowLeftSmallIcon } from '@blocksuite/icons/rc'; import { ArrowLeftSmallIcon } from '@blocksuite/icons/rc';
@@ -95,7 +95,7 @@ export const AIOnboardingGeneral = () => {
const aiSubscription = useLiveData(subscriptionService.subscription.ai$); const aiSubscription = useLiveData(subscriptionService.subscription.ai$);
const [index, setIndex] = useState(0); const [index, setIndex] = useState(0);
const list = useMemo(() => getPlayList(t), [t]); const list = useMemo(() => getPlayList(t), [t]);
const globalDialogService = useService(GlobalDialogService); const workspaceDialogService = useService(WorkspaceDialogService);
const readyToOpen = isLoggedIn; const readyToOpen = isLoggedIn;
useBlurRoot(open && readyToOpen); useBlurRoot(open && readyToOpen);
@@ -110,13 +110,13 @@ export const AIOnboardingGeneral = () => {
toggleGeneralAIOnboarding(false); toggleGeneralAIOnboarding(false);
}, []); }, []);
const goToPricingPlans = useCallback(() => { const goToPricingPlans = useCallback(() => {
globalDialogService.open('setting', { workspaceDialogService.open('setting', {
activeTab: 'plans', activeTab: 'plans',
scrollAnchor: 'aiPricingPlan', scrollAnchor: 'aiPricingPlan',
}); });
track.$.aiOnboarding.dialog.viewPlans(); track.$.aiOnboarding.dialog.viewPlans();
closeAndDismiss(); closeAndDismiss();
}, [closeAndDismiss, globalDialogService]); }, [closeAndDismiss, workspaceDialogService]);
const onPrev = useCallback(() => { const onPrev = useCallback(() => {
setIndex(i => Math.max(0, i - 1)); setIndex(i => Math.max(0, i - 1));
}, []); }, []);

View File

@@ -2,7 +2,7 @@ import { Loading, Scrollable } from '@affine/component';
import { EditorLoading } from '@affine/component/page-detail-skeleton'; import { EditorLoading } from '@affine/component/page-detail-skeleton';
import { Button, IconButton } from '@affine/component/ui/button'; import { Button, IconButton } from '@affine/component/ui/button';
import { Modal, useConfirmModal } from '@affine/component/ui/modal'; import { Modal, useConfirmModal } from '@affine/component/ui/modal';
import { GlobalDialogService } from '@affine/core/modules/dialogs'; import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
import { DocDisplayMetaService } from '@affine/core/modules/doc-display-meta'; import { DocDisplayMetaService } from '@affine/core/modules/doc-display-meta';
import { EditorService } from '@affine/core/modules/editor'; import { EditorService } from '@affine/core/modules/editor';
import { WorkspacePermissionService } from '@affine/core/modules/permissions'; import { WorkspacePermissionService } from '@affine/core/modules/permissions';
@@ -187,18 +187,18 @@ const PlanPrompt = () => {
}, [permissionService]); }, [permissionService]);
const [planPromptClosed, setPlanPromptClosed] = useAtom(planPromptClosedAtom); const [planPromptClosed, setPlanPromptClosed] = useAtom(planPromptClosedAtom);
const globalDialogService = useService(GlobalDialogService); const workspaceDialogService = useService(WorkspaceDialogService);
const closeFreePlanPrompt = useCallback(() => { const closeFreePlanPrompt = useCallback(() => {
setPlanPromptClosed(true); setPlanPromptClosed(true);
}, [setPlanPromptClosed]); }, [setPlanPromptClosed]);
const onClickUpgrade = useCallback(() => { const onClickUpgrade = useCallback(() => {
globalDialogService.open('setting', { workspaceDialogService.open('setting', {
activeTab: 'plans', activeTab: 'plans',
scrollAnchor: 'cloudPricingPlan', scrollAnchor: 'cloudPricingPlan',
}); });
track.$.docHistory.$.viewPlans(); track.$.docHistory.$.viewPlans();
}, [globalDialogService]); }, [workspaceDialogService]);
const t = useI18n(); const t = useI18n();

View File

@@ -1,7 +1,7 @@
import { ConfirmModal } from '@affine/component/ui/modal'; import { ConfirmModal } from '@affine/component/ui/modal';
import { openQuotaModalAtom } from '@affine/core/components/atoms'; import { openQuotaModalAtom } from '@affine/core/components/atoms';
import { UserQuotaService } from '@affine/core/modules/cloud'; import { UserQuotaService } from '@affine/core/modules/cloud';
import { GlobalDialogService } from '@affine/core/modules/dialogs'; import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
import { WorkspacePermissionService } from '@affine/core/modules/permissions'; import { WorkspacePermissionService } from '@affine/core/modules/permissions';
import { WorkspaceQuotaService } from '@affine/core/modules/quota'; import { WorkspaceQuotaService } from '@affine/core/modules/quota';
import { WorkspaceService } from '@affine/core/modules/workspace'; import { WorkspaceService } from '@affine/core/modules/workspace';
@@ -42,16 +42,16 @@ export const CloudQuotaModal = () => {
) )
); );
const globalDialogService = useService(GlobalDialogService); const workspaceDialogService = useService(WorkspaceDialogService);
const handleUpgradeConfirm = useCallback(() => { const handleUpgradeConfirm = useCallback(() => {
globalDialogService.open('setting', { workspaceDialogService.open('setting', {
activeTab: 'plans', activeTab: 'plans',
scrollAnchor: 'cloudPricingPlan', scrollAnchor: 'cloudPricingPlan',
}); });
track.$.paywall.storage.viewPlans(); track.$.paywall.storage.viewPlans();
setOpen(false); setOpen(false);
}, [globalDialogService, setOpen]); }, [workspaceDialogService, setOpen]);
const description = useMemo(() => { const description = useMemo(() => {
if (userQuota && isOwner) { if (userQuota && isOwner) {

View File

@@ -7,7 +7,7 @@ import {
} from '@affine/core/components/hooks/affine/use-share-url'; } from '@affine/core/components/hooks/affine/use-share-url';
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks'; import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
import { ServerService } from '@affine/core/modules/cloud'; import { ServerService } from '@affine/core/modules/cloud';
import { GlobalDialogService } from '@affine/core/modules/dialogs'; import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
import { EditorService } from '@affine/core/modules/editor'; import { EditorService } from '@affine/core/modules/editor';
import { WorkspacePermissionService } from '@affine/core/modules/permissions'; import { WorkspacePermissionService } from '@affine/core/modules/permissions';
import { ShareInfoService } from '@affine/core/modules/share-doc'; import { ShareInfoService } from '@affine/core/modules/share-doc';
@@ -81,13 +81,13 @@ export const AFFiNESharePage = (props: ShareMenuProps) => {
const permissionService = useService(WorkspacePermissionService); const permissionService = useService(WorkspacePermissionService);
const isOwner = useLiveData(permissionService.permission.isOwner$); const isOwner = useLiveData(permissionService.permission.isOwner$);
const globalDialogService = useService(GlobalDialogService); const workspaceDialogService = useService(WorkspaceDialogService);
const onOpenWorkspaceSettings = useCallback(() => { const onOpenWorkspaceSettings = useCallback(() => {
globalDialogService.open('setting', { workspaceDialogService.open('setting', {
activeTab: 'workspace:preference', activeTab: 'workspace:preference',
}); });
}, [globalDialogService]); }, [workspaceDialogService]);
const onClickAnyoneReadOnlyShare = useAsyncCallback(async () => { const onClickAnyoneReadOnlyShare = useAsyncCallback(async () => {
if (isSharedPage) { if (isSharedPage) {

View File

@@ -1,6 +1,9 @@
import { AppSidebarService } from '@affine/core/modules/app-sidebar'; import { AppSidebarService } from '@affine/core/modules/app-sidebar';
import { DesktopApiService } from '@affine/core/modules/desktop-api'; import { DesktopApiService } from '@affine/core/modules/desktop-api';
import { GlobalDialogService } from '@affine/core/modules/dialogs'; import {
GlobalDialogService,
WorkspaceDialogService,
} from '@affine/core/modules/dialogs';
import { I18nService } from '@affine/core/modules/i18n'; import { I18nService } from '@affine/core/modules/i18n';
import { UrlService } from '@affine/core/modules/url'; import { UrlService } from '@affine/core/modules/url';
import { WorkspaceService } from '@affine/core/modules/workspace'; import { WorkspaceService } from '@affine/core/modules/workspace';
@@ -76,6 +79,7 @@ export function useRegisterWorkspaceCommands() {
const [editor] = useActiveBlocksuiteEditor(); const [editor] = useActiveBlocksuiteEditor();
const cmdkQuickSearchService = useService(CMDKQuickSearchService); const cmdkQuickSearchService = useService(CMDKQuickSearchService);
const editorSettingService = useService(EditorSettingService); const editorSettingService = useService(EditorSettingService);
const workspaceDialogService = useService(WorkspaceDialogService);
const globalDialogService = useService(GlobalDialogService); const globalDialogService = useService(GlobalDialogService);
const appSidebarService = useService(AppSidebarService); const appSidebarService = useService(AppSidebarService);
const i18n = useService(I18nService).i18n; const i18n = useService(I18nService).i18n;
@@ -115,7 +119,7 @@ export function useRegisterWorkspaceCommands() {
t, t,
docCollection: currentWorkspace.docCollection, docCollection: currentWorkspace.docCollection,
navigationHelper, navigationHelper,
globalDialogService, workspaceDialogService,
}); });
return () => { return () => {
@@ -127,6 +131,7 @@ export function useRegisterWorkspaceCommands() {
currentWorkspace.docCollection, currentWorkspace.docCollection,
navigationHelper, navigationHelper,
globalDialogService, globalDialogService,
workspaceDialogService,
]); ]);
// register AffineSettingsCommands // register AffineSettingsCommands
@@ -182,11 +187,11 @@ export function useRegisterWorkspaceCommands() {
const unsub = registerAffineHelpCommands({ const unsub = registerAffineHelpCommands({
t, t,
urlService, urlService,
globalDialogService, workspaceDialogService,
}); });
return () => { return () => {
unsub(); unsub();
}; };
}, [t, globalDialogService, urlService]); }, [t, globalDialogService, urlService, workspaceDialogService]);
} }

View File

@@ -1,5 +1,5 @@
import { notify } from '@affine/component'; import { notify } from '@affine/component';
import { GlobalDialogService } from '@affine/core/modules/dialogs'; import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
import { WorkspacePermissionService } from '@affine/core/modules/permissions'; import { WorkspacePermissionService } from '@affine/core/modules/permissions';
import { WorkspaceService } from '@affine/core/modules/workspace'; import { WorkspaceService } from '@affine/core/modules/workspace';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
@@ -20,13 +20,13 @@ export const OverCapacityNotification = () => {
permissionService.permission.revalidate(); permissionService.permission.revalidate();
}, [permissionService]); }, [permissionService]);
const globalDialogService = useService(GlobalDialogService); const workspaceDialogService = useService(WorkspaceDialogService);
const jumpToPricePlan = useCallback(() => { const jumpToPricePlan = useCallback(() => {
globalDialogService.open('setting', { workspaceDialogService.open('setting', {
activeTab: 'plans', activeTab: 'plans',
scrollAnchor: 'cloudPricingPlan', scrollAnchor: 'cloudPricingPlan',
}); });
}, [globalDialogService]); }, [workspaceDialogService]);
// debounce sync engine status // debounce sync engine status
useEffect(() => { useEffect(() => {

View File

@@ -14,7 +14,10 @@ import {
FetchService, FetchService,
GraphQLService, GraphQLService,
} from '@affine/core/modules/cloud'; } from '@affine/core/modules/cloud';
import { GlobalDialogService } from '@affine/core/modules/dialogs'; import {
GlobalDialogService,
WorkspaceDialogService,
} from '@affine/core/modules/dialogs';
import { DocsService } from '@affine/core/modules/doc'; import { DocsService } from '@affine/core/modules/doc';
import { EditorSettingService } from '@affine/core/modules/editor-setting'; import { EditorSettingService } from '@affine/core/modules/editor-setting';
import { useRegisterNavigationCommands } from '@affine/core/modules/navigation/view/use-register-navigation-commands'; import { useRegisterNavigationCommands } from '@affine/core/modules/navigation/view/use-register-navigation-commands';
@@ -123,11 +126,12 @@ export const WorkspaceSideEffects = () => {
workbench, workbench,
]); ]);
const workspaceDialogService = useService(WorkspaceDialogService);
const globalDialogService = useService(GlobalDialogService); const globalDialogService = useService(GlobalDialogService);
useEffect(() => { useEffect(() => {
const disposable = AIProvider.slots.requestUpgradePlan.on(() => { const disposable = AIProvider.slots.requestUpgradePlan.on(() => {
globalDialogService.open('setting', { workspaceDialogService.open('setting', {
activeTab: 'billing', activeTab: 'billing',
}); });
track.$.paywall.aiAction.viewPlans(); track.$.paywall.aiAction.viewPlans();
@@ -135,7 +139,7 @@ export const WorkspaceSideEffects = () => {
return () => { return () => {
disposable.dispose(); disposable.dispose();
}; };
}, [globalDialogService]); }, [workspaceDialogService]);
const graphqlService = useService(GraphQLService); const graphqlService = useService(GraphQLService);
const eventSourceService = useService(EventSourceService); const eventSourceService = useService(EventSourceService);
@@ -158,9 +162,10 @@ export const WorkspaceSideEffects = () => {
}, [ }, [
eventSourceService, eventSourceService,
fetchService, fetchService,
globalDialogService, workspaceDialogService,
graphqlService, graphqlService,
networkSearchService, networkSearchService,
globalDialogService,
]); ]);
useRegisterWorkspaceCommands(); useRegisterWorkspaceCommands();

View File

@@ -1,5 +1,5 @@
import { Tooltip } from '@affine/component/ui/tooltip'; import { Tooltip } from '@affine/component/ui/tooltip';
import { GlobalDialogService } from '@affine/core/modules/dialogs'; import { WorkspaceDialogService } 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 { UrlService } from '@affine/core/modules/url'; import { UrlService } from '@affine/core/modules/url';
@@ -36,18 +36,18 @@ export const HelpIsland = () => {
}); });
const docId = useLiveData(globalContextService.globalContext.docId.$); const docId = useLiveData(globalContextService.globalContext.docId.$);
const docMode = useLiveData(globalContextService.globalContext.docMode.$); const docMode = useLiveData(globalContextService.globalContext.docMode.$);
const globalDialogService = useService(GlobalDialogService); const workspaceDialogService = useService(WorkspaceDialogService);
const [spread, setShowSpread] = useState(false); const [spread, setShowSpread] = useState(false);
const t = useI18n(); const t = useI18n();
const openSettingModal = useCallback( const openSettingModal = useCallback(
(tab: SettingTab) => { (tab: SettingTab) => {
setShowSpread(false); setShowSpread(false);
globalDialogService.open('setting', { workspaceDialogService.open('setting', {
activeTab: tab, activeTab: tab,
}); });
}, },
[globalDialogService] [workspaceDialogService]
); );
const openAbout = useCallback( const openAbout = useCallback(
() => openSettingModal('about'), () => openSettingModal('about'),

View File

@@ -1,3 +1,4 @@
// Import is already correct, no changes needed
import { import {
AddPageButton, AddPageButton,
AppDownloadButton, AppDownloadButton,
@@ -10,10 +11,7 @@ import {
SidebarScrollableContainer, SidebarScrollableContainer,
} from '@affine/core/modules/app-sidebar/views'; } from '@affine/core/modules/app-sidebar/views';
import { ExternalMenuLinkItem } from '@affine/core/modules/app-sidebar/views/menu-item/external-menu-link-item'; import { ExternalMenuLinkItem } from '@affine/core/modules/app-sidebar/views/menu-item/external-menu-link-item';
import { import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
GlobalDialogService,
WorkspaceDialogService,
} from '@affine/core/modules/dialogs';
import { import {
ExplorerCollections, ExplorerCollections,
ExplorerFavorites, ExplorerFavorites,
@@ -95,7 +93,6 @@ export const RootAppSidebar = memo((): ReactElement => {
CMDKQuickSearchService, CMDKQuickSearchService,
}); });
const t = useI18n(); const t = useI18n();
const globalDialogService = useService(GlobalDialogService);
const workspaceDialogService = useService(WorkspaceDialogService); const workspaceDialogService = useService(WorkspaceDialogService);
const workbench = workbenchService.workbench; const workbench = workbenchService.workbench;
const onOpenQuickSearchModal = useCallback(() => { const onOpenQuickSearchModal = useCallback(() => {
@@ -103,11 +100,11 @@ export const RootAppSidebar = memo((): ReactElement => {
}, [cMDKQuickSearchService]); }, [cMDKQuickSearchService]);
const onOpenSettingModal = useCallback(() => { const onOpenSettingModal = useCallback(() => {
globalDialogService.open('setting', { workspaceDialogService.open('setting', {
activeTab: 'appearance', activeTab: 'appearance',
}); });
track.$.navigationPanel.$.openSettings(); track.$.navigationPanel.$.openSettings();
}, [globalDialogService]); }, [workspaceDialogService]);
const handleOpenDocs = useCallback( const handleOpenDocs = useCallback(
(result: { (result: {

View File

@@ -8,7 +8,10 @@ import {
type MenuProps, type MenuProps,
Skeleton, Skeleton,
} from '@affine/component'; } from '@affine/component';
import { GlobalDialogService } from '@affine/core/modules/dialogs'; import {
GlobalDialogService,
WorkspaceDialogService,
} from '@affine/core/modules/dialogs';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { track } from '@affine/track'; import { track } from '@affine/track';
import { AccountIcon, SignOutIcon } from '@blocksuite/icons/rc'; import { AccountIcon, SignOutIcon } from '@blocksuite/icons/rc';
@@ -75,15 +78,15 @@ const UnauthorizedUserInfo = () => {
}; };
const AccountMenu = () => { const AccountMenu = () => {
const globalDialogService = useService(GlobalDialogService); const workspaceDialogService = useService(WorkspaceDialogService);
const openSignOutModal = useSignOut(); const openSignOutModal = useSignOut();
const onOpenAccountSetting = useCallback(() => { const onOpenAccountSetting = useCallback(() => {
track.$.navigationPanel.profileAndBadge.openSettings({ to: 'account' }); track.$.navigationPanel.profileAndBadge.openSettings({ to: 'account' });
globalDialogService.open('setting', { workspaceDialogService.open('setting', {
activeTab: 'account', activeTab: 'account',
}); });
}, [globalDialogService]); }, [workspaceDialogService]);
const t = useI18n(); const t = useI18n();
@@ -112,13 +115,13 @@ const CloudUsage = () => {
const quota = useService(UserQuotaService).quota; const quota = useService(UserQuotaService).quota;
const quotaError = useLiveData(quota.error$); const quotaError = useLiveData(quota.error$);
const globalDialogService = useService(GlobalDialogService); const workspaceDialogService = useService(WorkspaceDialogService);
const handleClick = useCatchEventCallback(() => { const handleClick = useCatchEventCallback(() => {
globalDialogService.open('setting', { workspaceDialogService.open('setting', {
activeTab: 'plans', activeTab: 'plans',
scrollAnchor: 'cloudPricingPlan', scrollAnchor: 'cloudPricingPlan',
}); });
}, [globalDialogService]); }, [workspaceDialogService]);
useEffect(() => { useEffect(() => {
// revalidate quota to get the latest status // revalidate quota to get the latest status
@@ -192,20 +195,20 @@ const AIUsage = () => {
const loading = copilotActionLimit === null || copilotActionUsed === null; const loading = copilotActionLimit === null || copilotActionUsed === null;
const loadError = useLiveData(copilotQuotaService.copilotQuota.error$); const loadError = useLiveData(copilotQuotaService.copilotQuota.error$);
const globalDialogService = useService(GlobalDialogService); const workspaceDialogService = useService(WorkspaceDialogService);
const goToAIPlanPage = useCallback(() => { const goToAIPlanPage = useCallback(() => {
globalDialogService.open('setting', { workspaceDialogService.open('setting', {
activeTab: 'plans', activeTab: 'plans',
scrollAnchor: 'aiPricingPlan', scrollAnchor: 'aiPricingPlan',
}); });
}, [globalDialogService]); }, [workspaceDialogService]);
const goToAccountSetting = useCallback(() => { const goToAccountSetting = useCallback(() => {
globalDialogService.open('setting', { workspaceDialogService.open('setting', {
activeTab: 'account', activeTab: 'account',
}); });
}, [globalDialogService]); }, [workspaceDialogService]);
if (loading) { if (loading) {
if (loadError) console.error(loadError); if (loadError) console.error(loadError);

View File

@@ -27,7 +27,6 @@ const GLOBAL_DIALOGS = {
'create-workspace': CreateWorkspaceDialog, 'create-workspace': CreateWorkspaceDialog,
'import-workspace': ImportWorkspaceDialog, 'import-workspace': ImportWorkspaceDialog,
'import-template': ImportTemplateDialog, 'import-template': ImportTemplateDialog,
setting: SettingDialog,
'sign-in': SignInDialog, 'sign-in': SignInDialog,
'change-password': ChangePasswordDialog, 'change-password': ChangePasswordDialog,
'verify-email': VerifyEmailDialog, 'verify-email': VerifyEmailDialog,
@@ -45,6 +44,7 @@ const WORKSPACE_DIALOGS = {
'doc-selector': DocSelectorDialog, 'doc-selector': DocSelectorDialog,
'collection-selector': CollectionSelectorDialog, 'collection-selector': CollectionSelectorDialog,
'date-selector': DateSelectorDialog, 'date-selector': DateSelectorDialog,
setting: SettingDialog,
import: ImportDialog, import: ImportDialog,
} satisfies { } satisfies {
[key in keyof WORKSPACE_DIALOG_SCHEMA]?: React.FC< [key in keyof WORKSPACE_DIALOG_SCHEMA]?: React.FC<

View File

@@ -10,11 +10,10 @@ 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 { ReactNode } from 'react';
import { useEffect } from 'react'; import { useEffect } from 'react';
import { AuthService, ServerService } from '../../../../modules/cloud'; import { AuthService, ServerService } from '../../../../modules/cloud';
import type { SettingState } from '../types'; import type { SettingSidebarItem, SettingState } from '../types';
import { AboutAffine } from './about'; import { AboutAffine } from './about';
import { AppearanceSettings } from './appearance'; import { AppearanceSettings } from './appearance';
import { BillingSettings } from './billing'; import { BillingSettings } from './billing';
@@ -24,14 +23,7 @@ import { PaymentIcon, UpgradeIcon } from './icons';
import { AFFiNEPricingPlans } from './plans'; import { AFFiNEPricingPlans } from './plans';
import { Shortcuts } from './shortcuts'; import { Shortcuts } from './shortcuts';
interface GeneralSettingListItem { export type GeneralSettingList = SettingSidebarItem[];
key: SettingTab;
title: string;
icon: ReactNode;
testId: string;
}
export type GeneralSettingList = GeneralSettingListItem[];
export const useGeneralSettingList = (): GeneralSettingList => { export const useGeneralSettingList = (): GeneralSettingList => {
const t = useI18n(); const t = useI18n();
@@ -54,7 +46,7 @@ export const useGeneralSettingList = (): GeneralSettingList => {
userFeatureService.userFeature.revalidate(); userFeatureService.userFeature.revalidate();
}, [userFeatureService]); }, [userFeatureService]);
const settings: GeneralSettingListItem[] = [ const settings: GeneralSettingList = [
{ {
key: 'appearance', key: 'appearance',
title: t['com.affine.settings.appearance'](), title: t['com.affine.settings.appearance'](),

View File

@@ -7,11 +7,11 @@ import {
DefaultServerService, DefaultServerService,
ServersService, ServersService,
} from '@affine/core/modules/cloud'; } from '@affine/core/modules/cloud';
import type { DialogComponentProps } from '@affine/core/modules/dialogs';
import type { import type {
DialogComponentProps, SettingTab,
GLOBAL_DIALOG_SCHEMA, WORKSPACE_DIALOG_SCHEMA,
} from '@affine/core/modules/dialogs'; } 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 { Trans } from '@affine/i18n'; import { Trans } from '@affine/i18n';
import { ContactWithUsIcon } from '@blocksuite/icons/rc'; import { ContactWithUsIcon } from '@blocksuite/icons/rc';
@@ -207,7 +207,7 @@ const SettingModalInner = ({
export const SettingDialog = ({ export const SettingDialog = ({
close, close,
activeTab, activeTab,
}: DialogComponentProps<GLOBAL_DIALOG_SCHEMA['setting']>) => { }: DialogComponentProps<WORKSPACE_DIALOG_SCHEMA['setting']>) => {
return ( return (
<Modal <Modal
width={1280} width={1280}

View File

@@ -1,38 +1,25 @@
import { WorkspaceListSkeleton } from '@affine/component/setting-components';
import { Avatar } from '@affine/component/ui/avatar'; import { Avatar } from '@affine/component/ui/avatar';
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 { 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 { 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 { import { type WorkspaceMetadata } from '@affine/core/modules/workspace';
type WorkspaceMetadata,
WorkspaceService,
} 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 { import { Logo1Icon } from '@blocksuite/icons/rc';
Logo1Icon, import { useLiveData, useService } from '@toeverything/infra';
PaymentIcon,
PropertyIcon,
SettingsIcon,
} from '@blocksuite/icons/rc';
import { useLiveData, useService, useServices } from '@toeverything/infra';
import clsx from 'clsx'; import clsx from 'clsx';
import { import {
type HTMLAttributes, type HTMLAttributes,
type MouseEvent,
type ReactNode, type ReactNode,
Suspense, Suspense,
useCallback, useCallback,
useEffect,
useMemo, useMemo,
} from 'react'; } from 'react';
import { useGeneralSettingList } from '../general-setting'; import { useGeneralSettingList } from '../general-setting';
import { useWorkspaceSettingList } from '../workspace-setting';
import * as style from './style.css'; import * as style from './style.css';
export type UserInfoProps = { export type UserInfoProps = {
@@ -118,26 +105,51 @@ export const SignInButton = () => {
); );
}; };
type SettingSidebarItemProps = {
isActive: boolean;
icon: ReactNode;
title: string;
key: string;
testId?: string;
} & HTMLAttributes<HTMLDivElement>;
const SettingSidebarItem = ({ const SettingSidebarItem = ({
isActive, isActive,
icon, icon,
label, title,
testId,
...props ...props
}: { }: SettingSidebarItemProps) => {
isActive: boolean;
label: string;
icon: ReactNode;
} & HTMLAttributes<HTMLDivElement>) => {
return ( return (
<div <div
{...props} {...props}
title={label} title={title}
data-testid={testId}
className={clsx(style.sidebarSelectItem, { className={clsx(style.sidebarSelectItem, {
active: isActive, active: isActive,
})} })}
> >
<div className={style.sidebarSelectItemIcon}>{icon}</div> <div className={style.sidebarSelectItemIcon}>{icon}</div>
<div className={style.sidebarSelectItemName}>{label}</div> <div className={style.sidebarSelectItemName}>{title}</div>
</div>
);
};
const SettingSidebarGroup = ({
title,
items,
}: {
title: string;
items: SettingSidebarItemProps[];
}) => {
return (
<div className={style.sidebarGroup}>
<div className={style.sidebarSubtitle}>{title}</div>
<div className={style.sidebarItemsWrapper}>
{items.map(({ key, ...props }) => (
<SettingSidebarItem key={key} {...props} />
))}
</div>
</div> </div>
); );
}; };
@@ -152,12 +164,11 @@ export const SettingSidebar = ({
const t = useI18n(); const t = useI18n();
const loginStatus = useLiveData(useService(AuthService).session.status$); const loginStatus = useLiveData(useService(AuthService).session.status$);
const generalList = useGeneralSettingList(); const generalList = useGeneralSettingList();
const workspaceSettingList = useWorkspaceSettingList();
const gotoTab = useCallback( const gotoTab = useCallback(
(e: MouseEvent<HTMLDivElement>) => { (tab: SettingTab) => {
const tab = e.currentTarget.dataset.eventArg;
if (!tab) return;
track.$.settingsPanel.menu.openSettings({ to: tab }); track.$.settingsPanel.menu.openSettings({ to: tab });
onTabChange(tab as SettingTab); onTabChange(tab);
}, },
[onTabChange] [onTabChange]
); );
@@ -165,16 +176,34 @@ export const SettingSidebar = ({
track.$.settingsPanel.menu.openSettings({ to: 'account' }); track.$.settingsPanel.menu.openSettings({ to: 'account' });
onTabChange('account'); onTabChange('account');
}, [onTabChange]); }, [onTabChange]);
const onWorkspaceSettingClick = useCallback(
(tab: SettingTab) => { const groups = useMemo(() => {
track.$.settingsPanel.menu.openSettings({ const res = [
to: 'workspace', {
control: tab, key: 'setting:general',
}); title: t['com.affine.settingSidebar.settings.general'](),
onTabChange(tab); items: generalList,
}, },
[onTabChange] {
); key: 'setting:workspace',
title: t['com.affine.settingSidebar.settings.workspace'](),
items: workspaceSettingList,
},
].map(group => {
return {
...group,
items: group.items.map(item => {
return {
...item,
isActive: item.key === activeTab,
'data-event-arg': item.key,
onClick: () => gotoTab(item.key),
};
}),
};
});
return res;
}, [activeTab, generalList, gotoTab, t, workspaceSettingList]);
return ( return (
<div className={style.settingSlideBar} data-testid="settings-sidebar"> <div className={style.settingSlideBar} data-testid="settings-sidebar">
@@ -193,117 +222,13 @@ export const SettingSidebar = ({
</Suspense> </Suspense>
) : null} ) : null}
<div className={style.sidebarGroup}> {groups.map(group => (
<div className={style.sidebarSubtitle}> <SettingSidebarGroup
{t['com.affine.settingSidebar.settings.general']()} key={group.key}
</div> title={group.title}
<div className={style.sidebarItemsWrapper}> items={group.items}
{generalList.map(({ title, icon, key, testId }) => {
return (
<SettingSidebarItem
isActive={key === activeTab}
key={key}
label={title}
data-event-arg={key}
onClick={gotoTab}
data-testid={testId}
icon={icon}
/>
);
})}
</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 WorkspaceSettingItems = ({
onWorkspaceSettingClick,
activeTab,
}: {
onWorkspaceSettingClick: (activeTab: SettingTab) => void;
activeTab: SettingTab;
}) => {
const { userFeatureService } = useServices({
UserFeatureService,
});
const workspaceService = useService(WorkspaceService);
const information = useWorkspaceInfo(workspaceService.workspace);
const t = useI18n();
useEffect(() => {
userFeatureService.userFeature.revalidate();
}, [userFeatureService]);
const showBilling = information?.isTeam && information?.isOwner;
const subTabs = useMemo(() => {
const subTabConfigs = [
{
key: 'workspace:preference',
title: 'com.affine.settings.workspace.preferences',
icon: <SettingsIcon />,
},
{
key: 'workspace:properties',
title: 'com.affine.settings.workspace.properties',
icon: <PropertyIcon />,
},
...(showBilling
? [
{
key: 'workspace:billing' as SettingTab,
title: 'com.affine.settings.workspace.billing',
icon: <PaymentIcon />,
},
]
: []),
] satisfies {
key: SettingTab;
title: keyof ReturnType<typeof useI18n>;
icon: ReactNode;
}[];
return subTabConfigs.map(({ key, title, icon }) => {
return (
<SettingSidebarItem
isActive={activeTab === key}
label={t[title]()}
icon={icon}
data-testid={`workspace-list-item-${key}`}
onClick={() => {
onWorkspaceSettingClick(key);
}}
className={clsx(style.sidebarSelectItem, {
active: activeTab === key,
})}
key={key}
/> />
); ))}
});
}, [activeTab, onWorkspaceSettingClick, showBilling, t]);
return (
<div className={style.sidebarItemsWrapper}>
{/* TODO: remove the suspense? */}
<Suspense fallback={<WorkspaceListSkeleton />}>{subTabs}</Suspense>
</div> </div>
); );
}; };

View File

@@ -1,6 +1,14 @@
import type { SettingTab } from '@affine/core/modules/dialogs/constant'; import type { SettingTab } from '@affine/core/modules/dialogs/constant';
import type { ReactNode } from 'react';
export interface SettingState { export interface SettingState {
activeTab: SettingTab; activeTab: SettingTab;
scrollAnchor?: string; scrollAnchor?: string;
} }
export interface SettingSidebarItem {
key: SettingTab;
title: string;
icon: ReactNode;
testId: string;
}

View File

@@ -1,8 +1,12 @@
import { CurrentWorkspaceScopeProvider } from '@affine/core/components/providers/current-workspace-scope'; import { useWorkspaceInfo } from '@affine/core/components/hooks/use-workspace-info';
import type { SettingTab } from '@affine/core/modules/dialogs/constant'; import type { SettingTab } from '@affine/core/modules/dialogs/constant';
import { WorkspaceService } from '@affine/core/modules/workspace';
import { useI18n } from '@affine/i18n';
import { PaymentIcon, PropertyIcon, SettingsIcon } from '@blocksuite/icons/rc';
import { useService } from '@toeverything/infra';
import { useMemo } from 'react'; import { useMemo } from 'react';
import type { SettingState } from '../types'; import type { SettingSidebarItem, SettingState } from '../types';
import { WorkspaceSettingBilling } from './billing'; import { WorkspaceSettingBilling } from './billing';
import { WorkspaceSettingDetail } from './new-workspace-setting-detail'; import { WorkspaceSettingDetail } from './new-workspace-setting-detail';
import { WorkspaceSettingProperties } from './properties'; import { WorkspaceSettingProperties } from './properties';
@@ -16,24 +20,56 @@ export const WorkspaceSetting = ({
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} />
/> );
); case 'workspace:properties':
case 'workspace:properties': return <WorkspaceSettingProperties />;
return <WorkspaceSettingProperties />; case 'workspace:billing':
case 'workspace:billing': return <WorkspaceSettingBilling />;
return <WorkspaceSettingBilling />; default:
default: return null;
return null; }
} };
}, [activeTab, onCloseSetting, onChangeSettingState]);
return ( export const useWorkspaceSettingList = (): SettingSidebarItem[] => {
<CurrentWorkspaceScopeProvider>{element}</CurrentWorkspaceScopeProvider> const workspaceService = useService(WorkspaceService);
); const information = useWorkspaceInfo(workspaceService.workspace);
const t = useI18n();
const showBilling = information?.isTeam && information?.isOwner;
const items = useMemo<SettingSidebarItem[]>(() => {
return [
{
key: 'workspace:preference',
title: t['com.affine.settings.workspace.preferences'](),
icon: <SettingsIcon />,
testId: 'workspace-setting:preference',
},
{
key: 'workspace:properties',
title: t['com.affine.settings.workspace.properties'](),
icon: <PropertyIcon />,
testId: 'workspace-setting:properties',
},
...(showBilling
? [
{
key: 'workspace:billing' as SettingTab,
title: t['com.affine.settings.workspace.billing'](),
icon: <PaymentIcon />,
testId: 'workspace-setting:billing',
},
]
: []),
];
}, [showBilling, t]);
return items;
}; };

View File

@@ -18,7 +18,6 @@ const GLOBAL_DIALOGS = {
// 'create-workspace': CreateWorkspaceDialog, // 'create-workspace': CreateWorkspaceDialog,
// 'import-workspace': ImportWorkspaceDialog, // 'import-workspace': ImportWorkspaceDialog,
// 'import-template': ImportTemplateDialog, // 'import-template': ImportTemplateDialog,
setting: SettingDialog,
// import: ImportDialog, // import: ImportDialog,
'sign-in': SignInDialog, 'sign-in': SignInDialog,
} satisfies { } satisfies {
@@ -34,6 +33,7 @@ const WORKSPACE_DIALOGS = {
'doc-selector': DocSelectorDialog, 'doc-selector': DocSelectorDialog,
'collection-selector': CollectionSelectorDialog, 'collection-selector': CollectionSelectorDialog,
'date-selector': DateSelectorDialog, 'date-selector': DateSelectorDialog,
setting: SettingDialog,
} satisfies { } satisfies {
[key in keyof WORKSPACE_DIALOG_SCHEMA]?: React.FC< [key in keyof WORKSPACE_DIALOG_SCHEMA]?: React.FC<
DialogComponentProps<WORKSPACE_DIALOG_SCHEMA[key]> DialogComponentProps<WORKSPACE_DIALOG_SCHEMA[key]>

View File

@@ -1,7 +1,7 @@
import { AuthService } from '@affine/core/modules/cloud'; import { AuthService } from '@affine/core/modules/cloud';
import type { import type {
DialogComponentProps, DialogComponentProps,
GLOBAL_DIALOG_SCHEMA, WORKSPACE_DIALOG_SCHEMA,
} from '@affine/core/modules/dialogs'; } from '@affine/core/modules/dialogs';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { useService } from '@toeverything/infra'; import { useService } from '@toeverything/infra';
@@ -34,7 +34,7 @@ const MobileSetting = () => {
export const SettingDialog = ({ export const SettingDialog = ({
close, close,
}: DialogComponentProps<GLOBAL_DIALOG_SCHEMA['setting']>) => { }: DialogComponentProps<WORKSPACE_DIALOG_SCHEMA['setting']>) => {
const t = useI18n(); const t = useI18n();
return ( return (

View File

@@ -3,7 +3,7 @@ import {
SafeArea, SafeArea,
startScopedViewTransition, startScopedViewTransition,
} from '@affine/component'; } from '@affine/component';
import { GlobalDialogService } from '@affine/core/modules/dialogs'; import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
import { WorkbenchService } from '@affine/core/modules/workbench'; import { WorkbenchService } from '@affine/core/modules/workbench';
import { useI18n } from '@affine/i18n'; import { useI18n } from '@affine/i18n';
import { SettingsIcon } from '@blocksuite/icons/rc'; import { SettingsIcon } from '@blocksuite/icons/rc';
@@ -23,7 +23,7 @@ import * as styles from './styles.css';
* - hide Search * - hide Search
*/ */
export const HomeHeader = () => { export const HomeHeader = () => {
const globalDialogService = useService(GlobalDialogService); const workspaceDialogService = useService(WorkspaceDialogService);
const workspaceCardRef = useRef<HTMLDivElement>(null); const workspaceCardRef = useRef<HTMLDivElement>(null);
const floatWorkspaceCardRef = useRef<HTMLDivElement>(null); const floatWorkspaceCardRef = useRef<HTMLDivElement>(null);
@@ -50,10 +50,10 @@ export const HomeHeader = () => {
); );
const openSetting = useCallback(() => { const openSetting = useCallback(() => {
globalDialogService.open('setting', { workspaceDialogService.open('setting', {
activeTab: 'appearance', activeTab: 'appearance',
}); });
}, [globalDialogService]); }, [workspaceDialogService]);
return ( return (
<> <>

View File

@@ -26,7 +26,6 @@ export type GLOBAL_DIALOG_SCHEMA = {
templateMode: DocMode; templateMode: DocMode;
snapshotUrl: string; snapshotUrl: string;
}) => void; }) => void;
setting: (props: { activeTab?: SettingTab; 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;
@@ -38,6 +37,7 @@ export type GLOBAL_DIALOG_SCHEMA = {
}; };
export type WORKSPACE_DIALOG_SCHEMA = { export type WORKSPACE_DIALOG_SCHEMA = {
setting: (props: { activeTab?: SettingTab; scrollAnchor?: string }) => void;
'doc-info': (props: { docId: string }) => void; 'doc-info': (props: { docId: string }) => void;
'doc-selector': (props: { 'doc-selector': (props: {
init: string[]; init: string[];

View File

@@ -1,4 +1,5 @@
import { Button } from '@affine/component/ui/button'; import { Button } from '@affine/component/ui/button';
import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
import { appIconMap, appNames } from '@affine/core/utils/channel'; import { appIconMap, appNames } from '@affine/core/utils/channel';
import { Trans, useI18n } from '@affine/i18n'; import { Trans, useI18n } from '@affine/i18n';
import { LocalWorkspaceIcon, Logo1Icon } from '@blocksuite/icons/rc'; import { LocalWorkspaceIcon, Logo1Icon } from '@blocksuite/icons/rc';
@@ -6,7 +7,6 @@ import { useService } from '@toeverything/infra';
import type { MouseEvent } from 'react'; import type { MouseEvent } from 'react';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { GlobalDialogService } from '../../dialogs';
import { getOpenUrlInDesktopAppLink } from '../utils'; import { getOpenUrlInDesktopAppLink } from '../utils';
import * as styles from './open-in-app-page.css'; import * as styles from './open-in-app-page.css';
@@ -28,7 +28,7 @@ export const OpenInAppPage = ({
}: OpenAppProps) => { }: OpenAppProps) => {
// default to open the current page in desktop app // default to open the current page in desktop app
urlToOpen ??= getOpenUrlInDesktopAppLink(window.location.href, true); urlToOpen ??= getOpenUrlInDesktopAppLink(window.location.href, true);
const globalDialogService = useService(GlobalDialogService); const workspaceDialogService = useService(WorkspaceDialogService);
const t = useI18n(); const t = useI18n();
const openDownloadLink = useCallback(() => { const openDownloadLink = useCallback(() => {
@@ -41,11 +41,11 @@ export const OpenInAppPage = ({
const goToAppearanceSetting = useCallback( const goToAppearanceSetting = useCallback(
(e: MouseEvent) => { (e: MouseEvent) => {
openHereClicked?.(e); openHereClicked?.(e);
globalDialogService.open('setting', { workspaceDialogService.open('setting', {
activeTab: 'appearance', activeTab: 'appearance',
}); });
}, },
[globalDialogService, openHereClicked] [workspaceDialogService, openHereClicked]
); );
if (urlToOpen && lastOpened !== urlToOpen) { if (urlToOpen && lastOpened !== urlToOpen) {

View File

@@ -1,5 +1,5 @@
import { useConfirmModal } from '@affine/component'; import { useConfirmModal } from '@affine/component';
import { GlobalDialogService } from '@affine/core/modules/dialogs'; import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
import { type I18nString, useI18n } from '@affine/i18n'; import { type I18nString, useI18n } from '@affine/i18n';
import { InformationFillDuotoneIcon } from '@blocksuite/icons/rc'; import { InformationFillDuotoneIcon } from '@blocksuite/icons/rc';
import { useLiveData, useService } from '@toeverything/infra'; import { useLiveData, useService } from '@toeverything/infra';
@@ -36,18 +36,18 @@ export const QuotaCheck = ({
const profile = useLiveData(workspaceProfile.profile$); const profile = useLiveData(workspaceProfile.profile$);
const isOwner = profile?.isOwner; const isOwner = profile?.isOwner;
const isTeam = profile?.isTeam; const isTeam = profile?.isTeam;
const globalDialogService = useService(GlobalDialogService); const workspaceDialogService = useService(WorkspaceDialogService);
const t = useI18n(); const t = useI18n();
const onConfirm = useCallback(() => { const onConfirm = useCallback(() => {
if (!isOwner) { if (!isOwner) {
return; return;
} }
globalDialogService.open('setting', { workspaceDialogService.open('setting', {
activeTab: 'plans', activeTab: 'plans',
scrollAnchor: 'cloudPricingPlan', scrollAnchor: 'cloudPricingPlan',
}); });
}, [globalDialogService, isOwner]); }, [workspaceDialogService, isOwner]);
useEffect(() => { useEffect(() => {
workspaceQuota?.revalidate(); workspaceQuota?.revalidate();

View File

@@ -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('workspace-list-item-workspace:preference').click(); await page.getByTestId('workspace-setting:preference').click();
await expect(page.getByTestId('workspace-name-input')).toHaveValue( await expect(page.getByTestId('workspace-name-input')).toHaveValue(
'Delete Me' 'Delete Me'
); );

View File

@@ -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-workspace:preference').click(); await page.getByTestId('workspace-setting:preference').click();
const input = page.getByTestId('workspace-name-input'); const input = page.getByTestId('workspace-name-input');
await expect(input).toBeVisible(); await expect(input).toBeVisible();

View File

@@ -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('workspace-list-item-workspace:preference').click(); await page.getByTestId('workspace-setting: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('workspace-list-item-workspace:preference').click(); await page.getByTestId('workspace-setting: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);

View File

@@ -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('workspace-list-item-workspace:preference').click(); await page.getByTestId('workspace-setting: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

View File

@@ -149,7 +149,7 @@ 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.getByTestId('workspace-list-item-workspace:properties').click(); await page.getByTestId('workspace-setting:properties').click();
}; };
export const selectVisibilitySelector = async ( export const selectVisibilitySelector = async (

View File

@@ -41,7 +41,7 @@ export async function confirmExperimentalPrompt(page: Page) {
export async function openWorkspaceSettingPanel(page: Page) { export async function openWorkspaceSettingPanel(page: Page) {
await page await page
.getByTestId('settings-sidebar') .getByTestId('settings-sidebar')
.getByTestId('workspace-list-item-workspace:preference') .getByTestId('workspace-setting:preference')
.click(); .click();
} }