diff --git a/packages/frontend/apps/electron/src/helper/index.ts b/packages/frontend/apps/electron/src/helper/index.ts index 2d8cff050..7fe622259 100644 --- a/packages/frontend/apps/electron/src/helper/index.ts +++ b/packages/frontend/apps/electron/src/helper/index.ts @@ -12,7 +12,7 @@ function setupRendererConnection(rendererPort: Electron.MessagePortMain) { try { const start = performance.now(); const result = await handler(...args); - logger.debug( + logger.info( '[async-api]', `${namespace}.${name}`, args.filter( diff --git a/packages/frontend/core/src/commands/affine-help.tsx b/packages/frontend/core/src/commands/affine-help.tsx index fcb67bdd8..d0136ca67 100644 --- a/packages/frontend/core/src/commands/affine-help.tsx +++ b/packages/frontend/core/src/commands/affine-help.tsx @@ -38,7 +38,6 @@ export function registerAffineHelpCommands({ track.$.cmdk.help.contactUs(); globalDialogService.open('setting', { activeTab: 'about', - workspaceMetadata: null, }); }, }) diff --git a/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-page.tsx b/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-page.tsx index 7108cfe11..d1467ff7f 100644 --- a/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-page.tsx +++ b/packages/frontend/core/src/components/affine/share-page-modal/share-menu/share-page.tsx @@ -86,9 +86,8 @@ export const AFFiNESharePage = (props: ShareMenuProps) => { const onOpenWorkspaceSettings = useCallback(() => { globalDialogService.open('setting', { activeTab: 'workspace:preference', - workspaceMetadata: props.workspaceMetadata, }); - }, [globalDialogService, props.workspaceMetadata]); + }, [globalDialogService]); const onClickAnyoneReadOnlyShare = useAsyncCallback(async () => { if (isSharedPage) { diff --git a/packages/frontend/core/src/components/providers/current-workspace-scope.tsx b/packages/frontend/core/src/components/providers/current-workspace-scope.tsx new file mode 100644 index 000000000..2477eabc3 --- /dev/null +++ b/packages/frontend/core/src/components/providers/current-workspace-scope.tsx @@ -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 {children}; +}; diff --git a/packages/frontend/core/src/components/root-app-sidebar/index.tsx b/packages/frontend/core/src/components/root-app-sidebar/index.tsx index 77ad4a406..458320f7d 100644 --- a/packages/frontend/core/src/components/root-app-sidebar/index.tsx +++ b/packages/frontend/core/src/components/root-app-sidebar/index.tsx @@ -148,11 +148,7 @@ export const RootAppSidebar = memo((): ReactElement => {
- +
diff --git a/packages/frontend/core/src/components/workspace-selector/index.tsx b/packages/frontend/core/src/components/workspace-selector/index.tsx index 099fd3124..3da157a68 100644 --- a/packages/frontend/core/src/components/workspace-selector/index.tsx +++ b/packages/frontend/core/src/components/workspace-selector/index.tsx @@ -25,7 +25,6 @@ interface WorkspaceSelectorProps { metadata: WorkspaceMetadata; defaultDocId?: string; }) => void; - showSettingsButton?: boolean; showEnableCloudButton?: boolean; showArrowDownIcon?: boolean; showSyncStatus?: boolean; @@ -38,7 +37,6 @@ export const WorkspaceSelector = ({ workspaceMetadata: outerWorkspaceMetadata, onSelectWorkspace, onCreatedWorkspace, - showSettingsButton, showArrowDownIcon, disable, open: outerOpen, @@ -89,7 +87,6 @@ export const WorkspaceSelector = ({ onClickWorkspace={onSelectWorkspace} onCreatedWorkspace={onCreatedWorkspace} showEnableCloudButton={showEnableCloudButton} - showSettingsButton={showSettingsButton} /> } contentOptions={{ diff --git a/packages/frontend/core/src/components/workspace-selector/user-with-workspace-list/index.tsx b/packages/frontend/core/src/components/workspace-selector/user-with-workspace-list/index.tsx index 0089be0e3..a9e38825d 100644 --- a/packages/frontend/core/src/components/workspace-selector/user-with-workspace-list/index.tsx +++ b/packages/frontend/core/src/components/workspace-selector/user-with-workspace-list/index.tsx @@ -55,7 +55,6 @@ interface UserWithWorkspaceListProps { metadata: WorkspaceMetadata; defaultDocId?: string; }) => void; - showSettingsButton?: boolean; showEnableCloudButton?: boolean; } @@ -63,7 +62,6 @@ const UserWithWorkspaceListInner = ({ onEventEnd, onClickWorkspace, onCreatedWorkspace, - showSettingsButton, showEnableCloudButton, }: UserWithWorkspaceListProps) => { const globalDialogService = useService(GlobalDialogService); @@ -121,7 +119,6 @@ const UserWithWorkspaceListInner = ({ onEventEnd={onEventEnd} onClickWorkspace={onClickWorkspace} showEnableCloudButton={showEnableCloudButton} - showSettingsButton={showSettingsButton} /> void; - onClickWorkspaceSetting?: (workspaceMetadata: WorkspaceMetadata) => void; onClickEnableCloud?: (meta: WorkspaceMetadata) => void; }) => { const t = useI18n(); @@ -161,7 +159,6 @@ const CloudWorkSpaceList = ({ void; onEventEnd?: () => void; - showSettingsButton?: boolean; showEnableCloudButton?: boolean; }) => { const workspacesService = useService(WorkspacesService); const workspaces = useLiveData(workspacesService.list.workspaces$); - const globalDialogService = useService(GlobalDialogService); const confirmEnableCloud = useEnableCloud(); @@ -247,17 +241,6 @@ export const AFFiNEWorkspaceList = ({ [workspaces] ); - const onClickWorkspaceSetting = useCallback( - (workspaceMetadata: WorkspaceMetadata) => { - globalDialogService.open('setting', { - activeTab: 'workspace:preference', - workspaceMetadata, - }); - onEventEnd?.(); - }, - [globalDialogService, onEventEnd] - ); - const onClickEnableCloud = useCallback( (meta: WorkspaceMetadata) => { const { workspace, dispose } = workspacesService.open({ metadata: meta }); @@ -292,9 +275,6 @@ export const AFFiNEWorkspaceList = ({ ({ flavour }) => flavour === server.id )} onClickWorkspace={handleClickWorkspace} - onClickWorkspaceSetting={ - showSettingsButton ? onClickWorkspaceSetting : undefined - } /> @@ -303,9 +283,6 @@ export const AFFiNEWorkspaceList = ({ ) => ReactElement; + icon: ReactNode; testId: string; } @@ -58,19 +58,19 @@ export const useGeneralSettingList = (): GeneralSettingList => { { key: 'appearance', title: t['com.affine.settings.appearance'](), - icon: AppearanceIcon, + icon: , testId: 'appearance-panel-trigger', }, { key: 'shortcuts', title: t['com.affine.keyboardShortcuts.title'](), - icon: KeyboardIcon, + icon: , testId: 'shortcuts-panel-trigger', }, { key: 'about', title: t['com.affine.aboutAFFiNE.title'](), - icon: InformationIcon, + icon: , testId: 'about-panel-trigger', }, ]; @@ -79,7 +79,7 @@ export const useGeneralSettingList = (): GeneralSettingList => { settings.splice(1, 0, { key: 'editor', title: t['com.affine.settings.editorSettings'](), - icon: PenIcon, + icon: , testId: 'editor-panel-trigger', }); } @@ -88,14 +88,14 @@ export const useGeneralSettingList = (): GeneralSettingList => { settings.splice(3, 0, { key: 'plans', title: t['com.affine.payment.title'](), - icon: UpgradeIcon, + icon: , testId: 'plans-panel-trigger', }); if (status === 'authenticated') { settings.splice(3, 0, { key: 'billing', title: t['com.affine.payment.billing-setting.title'](), - icon: PaymentIcon, + icon: , testId: 'billing-panel-trigger', }); } @@ -104,7 +104,7 @@ export const useGeneralSettingList = (): GeneralSettingList => { settings.push({ key: 'experimental-features', title: t['com.affine.settings.workspace.experimental-features'](), - icon: ExperimentIcon, + icon: , testId: 'experimental-features-trigger', }); diff --git a/packages/frontend/core/src/desktop/dialogs/setting/index.tsx b/packages/frontend/core/src/desktop/dialogs/setting/index.tsx index 80a29076c..6545a5216 100644 --- a/packages/frontend/core/src/desktop/dialogs/setting/index.tsx +++ b/packages/frontend/core/src/desktop/dialogs/setting/index.tsx @@ -13,7 +13,6 @@ import type { } from '@affine/core/modules/dialogs'; import type { SettingTab } from '@affine/core/modules/dialogs/constant'; import { GlobalContextService } from '@affine/core/modules/global-context'; -import type { WorkspaceMetadata } from '@affine/core/modules/workspace'; import { Trans } from '@affine/i18n'; import { ContactWithUsIcon } from '@blocksuite/icons/rc'; import { FrameworkScope, useLiveData, useService } from '@toeverything/infra'; @@ -37,7 +36,6 @@ import { WorkspaceSetting } from './workspace-setting'; interface SettingProps extends ModalProps { activeTab?: SettingTab; - workspaceMetadata?: WorkspaceMetadata | null; onCloseSetting: () => void; } @@ -54,12 +52,10 @@ const CenteredLoading = () => { const SettingModalInner = ({ activeTab: initialActiveTab = 'appearance', - workspaceMetadata: initialWorkspaceMetadata = null, onCloseSetting, }: SettingProps) => { const [settingState, setSettingState] = useState({ activeTab: initialActiveTab, - activeWorkspaceMetadata: initialWorkspaceMetadata, scrollAnchor: undefined, }); const globalContextService = useService(GlobalContextService); @@ -122,8 +118,8 @@ const SettingModalInner = ({ }, []); const onTabChange = useCallback( - (key: SettingTab, meta: WorkspaceMetadata | null) => { - setSettingState({ activeTab: key, activeWorkspaceMetadata: meta }); + (key: SettingTab) => { + setSettingState({ activeTab: key }); }, [setSettingState] ); @@ -143,7 +139,6 @@ const SettingModalInner = ({ - ) : isWorkspaceSetting(settingState.activeTab) && - settingState.activeWorkspaceMetadata ? ( + ) : isWorkspaceSetting(settingState.activeTab) ? ( @@ -214,7 +207,6 @@ const SettingModalInner = ({ export const SettingDialog = ({ close, activeTab, - workspaceMetadata, }: DialogComponentProps) => { return ( close()} > }> - + ); diff --git a/packages/frontend/core/src/desktop/dialogs/setting/setting-sidebar/index.tsx b/packages/frontend/core/src/desktop/dialogs/setting/setting-sidebar/index.tsx index c66430c97..64729440a 100644 --- a/packages/frontend/core/src/desktop/dialogs/setting/setting-sidebar/index.tsx +++ b/packages/frontend/core/src/desktop/dialogs/setting/setting-sidebar/index.tsx @@ -1,30 +1,31 @@ -import { - WorkspaceListItemSkeleton, - WorkspaceListSkeleton, -} from '@affine/component/setting-components'; +import { WorkspaceListSkeleton } from '@affine/component/setting-components'; 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 { useCatchEventCallback } from '@affine/core/components/hooks/use-catch-event-hook'; 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 { UserFeatureService } from '@affine/core/modules/cloud/services/user-feature'; import { GlobalDialogService } from '@affine/core/modules/dialogs'; import type { SettingTab } from '@affine/core/modules/dialogs/constant'; -import { GlobalContextService } from '@affine/core/modules/global-context'; import { type WorkspaceMetadata, - WorkspacesService, + WorkspaceService, } from '@affine/core/modules/workspace'; -import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant'; import { useI18n } from '@affine/i18n'; 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 clsx from 'clsx'; import { + type HTMLAttributes, type MouseEvent, + type ReactNode, Suspense, useCallback, useEffect, @@ -117,17 +118,36 @@ export const SignInButton = () => { ); }; +const SettingSidebarItem = ({ + isActive, + icon, + label, + ...props +}: { + isActive: boolean; + label: string; + icon: ReactNode; +} & HTMLAttributes) => { + return ( +
+
{icon}
+
{label}
+
+ ); +}; + export const SettingSidebar = ({ activeTab, onTabChange, - selectedWorkspaceId, }: { activeTab: SettingTab; - onTabChange: ( - key: SettingTab, - workspaceMetadata: WorkspaceMetadata | null - ) => void; - selectedWorkspaceId: string | null; + onTabChange: (key: SettingTab) => void; }) => { const t = useI18n(); const loginStatus = useLiveData(useService(AuthService).session.status$); @@ -137,21 +157,21 @@ export const SettingSidebar = ({ const tab = e.currentTarget.dataset.eventArg; if (!tab) return; track.$.settingsPanel.menu.openSettings({ to: tab }); - onTabChange(tab as SettingTab, null); + onTabChange(tab as SettingTab); }, [onTabChange] ); const onAccountSettingClick = useCallback(() => { track.$.settingsPanel.menu.openSettings({ to: 'account' }); - onTabChange('account', null); + onTabChange('account'); }, [onTabChange]); const onWorkspaceSettingClick = useCallback( - (tab: SettingTab, workspaceMetadata: WorkspaceMetadata) => { + (tab: SettingTab) => { track.$.settingsPanel.menu.openSettings({ to: 'workspace', control: tab, }); - onTabChange(tab, workspaceMetadata); + onTabChange(tab); }, [onTabChange] ); @@ -161,195 +181,129 @@ export const SettingSidebar = ({
{t['com.affine.settingSidebar.title']()}
-
- {t['com.affine.settingSidebar.settings.general']()} -
-
- {generalList.map(({ title, icon, key, testId }) => { - return ( -
- {icon({ className: 'icon' })} - {title} -
- ); - })} -
-
- {t['com.affine.settingSidebar.settings.workspace']()} -
-
- }> - : null} + {loginStatus === 'authenticated' ? ( + + + ) : null} + +
+
+ {t['com.affine.settingSidebar.settings.general']()} +
+
+ {generalList.map(({ title, icon, key, testId }) => { + return ( + + ); + })} +
-
- {loginStatus === 'unauthenticated' ? : null} - {loginStatus === 'authenticated' ? ( - - +
+
+ {t['com.affine.settingSidebar.settings.workspace']()} +
+
+ }> + + + - ) : null} +
); }; -export const WorkspaceList = ({ +const WorkspaceSettingItems = ({ onWorkspaceSettingClick, - selectedWorkspaceId, activeTab, }: { - onWorkspaceSettingClick: ( - activeTab: SettingTab, - workspaceMetadata: WorkspaceMetadata - ) => void; - selectedWorkspaceId: string | null; + onWorkspaceSettingClick: (activeTab: SettingTab) => void; activeTab: SettingTab; }) => { - const workspaces = useLiveData( - useService(WorkspacesService).list.workspaces$ - ); - return ( - <> - {workspaces.map(workspace => { - return ( - }> - { - onWorkspaceSettingClick(subTab, workspace); - }} - activeTab={ - workspace.id === selectedWorkspaceId ? activeTab : undefined - } - /> - - ); - })} - - ); -}; - -const WorkspaceListItem = ({ - activeTab, - meta, - onClick, -}: { - meta: WorkspaceMetadata; - activeTab?: SettingTab; - onClick: (activeTab: SettingTab) => void; -}) => { - const { globalContextService, userFeatureService } = useServices({ - GlobalContextService, + const { userFeatureService } = useServices({ UserFeatureService, }); - const information = useWorkspaceInfo(meta); - const name = information?.name ?? UNTITLED_WORKSPACE_NAME; - const currentWorkspaceId = useLiveData( - globalContextService.globalContext.workspaceId.$ - ); - const isCurrent = currentWorkspaceId === meta.id; + + const workspaceService = useService(WorkspaceService); + const information = useWorkspaceInfo(workspaceService.workspace); + const t = useI18n(); useEffect(() => { userFeatureService.userFeature.revalidate(); }, [userFeatureService]); - const onClickPreference = useCallback(() => { - onClick('workspace:preference'); - }, [onClick]); - const showBilling = information?.isTeam && information?.isOwner; const subTabs = useMemo(() => { const subTabConfigs = [ { key: 'workspace:preference', title: 'com.affine.settings.workspace.preferences', + icon: , }, { key: 'workspace:properties', title: 'com.affine.settings.workspace.properties', + icon: , }, ...(showBilling ? [ { key: 'workspace:billing' as SettingTab, title: 'com.affine.settings.workspace.billing', + icon: , }, ] : []), ] satisfies { key: SettingTab; title: keyof ReturnType; + icon: ReactNode; }[]; - return subTabConfigs.map(({ key, title }) => { + return subTabConfigs.map(({ key, title, icon }) => { return ( -
{ - onClick(key); + onWorkspaceSettingClick(key); }} - className={clsx(style.sidebarSelectSubItem, { + className={clsx(style.sidebarSelectItem, { active: activeTab === key, })} key={key} - > - {t[title]()} -
+ /> ); }); - }, [activeTab, onClick, showBilling, t]); + }, [activeTab, onWorkspaceSettingClick, showBilling, t]); return ( - <> -
- - {name} - {isCurrent ? ( - -
-
- ) : null} -
- {activeTab && subTabs.length > 1 ? subTabs : null} - +
+ {/* TODO: remove the suspense? */} + }>{subTabs} +
); }; diff --git a/packages/frontend/core/src/desktop/dialogs/setting/setting-sidebar/style.css.ts b/packages/frontend/core/src/desktop/dialogs/setting/setting-sidebar/style.css.ts index de91df305..78bd807cb 100644 --- a/packages/frontend/core/src/desktop/dialogs/setting/setting-sidebar/style.css.ts +++ b/packages/frontend/core/src/desktop/dialogs/setting/setting-sidebar/style.css.ts @@ -1,28 +1,29 @@ import { cssVar } from '@toeverything/theme'; +import { cssVarV2 } from '@toeverything/theme/v2'; import { globalStyle, style } from '@vanilla-extract/css'; export const settingSlideBar = style({ width: '25%', maxWidth: '242px', background: cssVar('backgroundSecondaryColor'), - padding: '20px 0px', + padding: '20px 12px', height: '100%', flexShrink: 0, display: 'flex', flexDirection: 'column', + gap: '16px', + overflowY: 'auto', }); export const sidebarTitle = style({ fontSize: cssVar('fontH6'), fontWeight: '600', lineHeight: cssVar('lineHeight'), - padding: '0px 16px 0px 24px', + padding: '0 8px', }); export const sidebarSubtitle = style({ fontSize: cssVar('fontSm'), lineHeight: cssVar('lineHeight'), color: cssVar('textSecondaryColor'), - padding: '0px 16px 0px 24px', - marginTop: '20px', - marginBottom: '4px', + padding: '4px 8px', display: 'flex', justifyContent: 'space-between', alignItems: 'center', @@ -31,18 +32,11 @@ export const sidebarItemsWrapper = style({ display: 'flex', flexDirection: 'column', gap: 4, - selectors: { - '&.scroll': { - flexGrow: 1, - overflowY: 'auto', - }, - }, }); export const sidebarSelectItem = style({ display: 'flex', alignItems: 'center', - margin: '0px 16px', - padding: '0px 8px', + padding: '4px 8px', height: '30px', flexShrink: 0, fontSize: cssVar('fontSm'), @@ -76,19 +70,23 @@ export const sidebarSelectSubItem = style({ }, }, }); -globalStyle(`${settingSlideBar} .icon`, { + +export const sidebarSelectItemIcon = style({ width: '16px', height: '16px', marginRight: '10px', flexShrink: 0, + color: cssVarV2('icon/primary'), }); -globalStyle(`${settingSlideBar} .setting-name`, { + +export const sidebarSelectItemName = style({ minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', flexGrow: 1, }); + export const currentWorkspaceLabel = style({ width: '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({ padding: '4px 8px', borderRadius: '8px', diff --git a/packages/frontend/core/src/desktop/dialogs/setting/types.ts b/packages/frontend/core/src/desktop/dialogs/setting/types.ts index 8d4e56076..41d352760 100644 --- a/packages/frontend/core/src/desktop/dialogs/setting/types.ts +++ b/packages/frontend/core/src/desktop/dialogs/setting/types.ts @@ -1,8 +1,6 @@ import type { SettingTab } from '@affine/core/modules/dialogs/constant'; -import type { WorkspaceMetadata } from '@affine/core/modules/workspace'; export interface SettingState { activeTab: SettingTab; - activeWorkspaceMetadata?: WorkspaceMetadata | null; scrollAnchor?: string; } diff --git a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/billing/index.tsx b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/billing/index.tsx index ace01bd9d..e9cce2bfb 100644 --- a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/billing/index.tsx +++ b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/billing/index.tsx @@ -8,7 +8,6 @@ import { import { getUpgradeQuestionnaireLink } from '@affine/core/components/hooks/affine/use-subscription-notify'; import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks'; import { useMutation } from '@affine/core/components/hooks/use-mutation'; -import { useWorkspace } from '@affine/core/components/hooks/use-workspace'; import { AuthService, SubscriptionService, @@ -17,7 +16,7 @@ import { } from '@affine/core/modules/cloud'; import { WorkspaceQuotaService } from '@affine/core/modules/quota'; import { UrlService } from '@affine/core/modules/url'; -import type { WorkspaceMetadata } from '@affine/core/modules/workspace'; +import { WorkspaceService } from '@affine/core/modules/workspace'; import { createCustomerPortalMutation, type InvoicesQuery, @@ -27,7 +26,7 @@ import { UserFriendlyError, } from '@affine/graphql'; import { useI18n } from '@affine/i18n'; -import { FrameworkScope, useLiveData, useService } from '@toeverything/infra'; +import { useLiveData, useService } from '@toeverything/infra'; import { cssVar } from '@toeverything/theme'; import { useCallback, useEffect, useMemo, useState } from 'react'; @@ -37,14 +36,8 @@ import { } from '../../general-setting/plans/actions'; import * as styles from './styles.css'; -export const WorkspaceSettingBilling = ({ - workspaceMetadata, -}: { - 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); +export const WorkspaceSettingBilling = () => { + const workspace = useService(WorkspaceService).workspace; const t = useI18n(); @@ -68,7 +61,7 @@ export const WorkspaceSettingBilling = ({ } return ( - + <> - + ); }; diff --git a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/index.tsx b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/index.tsx index 1b89588a2..b0cd5a358 100644 --- a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/index.tsx +++ b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/index.tsx @@ -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 { WorkspaceMetadata } from '@affine/core/modules/workspace'; +import { useMemo } from 'react'; import type { SettingState } from '../types'; import { WorkspaceSettingBilling } from './billing'; @@ -7,31 +8,32 @@ import { WorkspaceSettingDetail } from './new-workspace-setting-detail'; import { WorkspaceSettingProperties } from './properties'; export const WorkspaceSetting = ({ - workspaceMetadata, activeTab, onCloseSetting, onChangeSettingState, }: { - workspaceMetadata: WorkspaceMetadata; activeTab: SettingTab; onCloseSetting: () => void; onChangeSettingState: (settingState: SettingState) => void; }) => { - switch (activeTab) { - case 'workspace:preference': - return ( - - ); - case 'workspace:properties': - return ( - - ); - case 'workspace:billing': - return ; - } - return null; + const element = useMemo(() => { + switch (activeTab) { + case 'workspace:preference': + return ( + + ); + case 'workspace:properties': + return ; + case 'workspace:billing': + return ; + default: + return null; + } + }, [activeTab, onCloseSetting, onChangeSettingState]); + return ( + {element} + ); }; diff --git a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/new-workspace-setting-detail/export.tsx b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/new-workspace-setting-detail/export.tsx index 03170ff60..8006e5b8a 100644 --- a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/new-workspace-setting-detail/export.tsx +++ b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/new-workspace-setting-detail/export.tsx @@ -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 { DesktopApiService } from '@affine/core/modules/desktop-api'; import { WorkspacePermissionService } from '@affine/core/modules/permissions'; -import type { - Workspace, - WorkspaceMetadata, -} from '@affine/core/modules/workspace'; +import type { Workspace } from '@affine/core/modules/workspace'; import { useI18n } from '@affine/i18n'; import track from '@affine/track'; import { useLiveData, useService } from '@toeverything/infra'; import { useState } from 'react'; interface ExportPanelProps { - workspaceMetadata: WorkspaceMetadata; - workspace: Workspace | null; + workspace: Workspace; } -export const DesktopExportPanel = ({ - workspaceMetadata, - workspace, -}: ExportPanelProps) => { - const workspaceId = workspaceMetadata.id; +export const DesktopExportPanel = ({ workspace }: ExportPanelProps) => { + const workspaceId = workspace.id; const workspacePermissionService = useService( WorkspacePermissionService ).permission; diff --git a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/new-workspace-setting-detail/index.tsx b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/new-workspace-setting-detail/index.tsx index e397474c8..6d99d56e4 100644 --- a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/new-workspace-setting-detail/index.tsx +++ b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/new-workspace-setting-detail/index.tsx @@ -3,13 +3,13 @@ import { SettingRow, SettingWrapper, } 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 { WorkspaceServerService } from '@affine/core/modules/cloud'; +import { WorkspaceService } from '@affine/core/modules/workspace'; import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant'; import { useI18n } from '@affine/i18n'; import { ArrowRightSmallIcon } from '@blocksuite/icons/rc'; -import { FrameworkScope } from '@toeverything/infra'; +import { FrameworkScope, useService } from '@toeverything/infra'; import { useCallback } from 'react'; import { DeleteLeaveWorkspace } from './delete-leave-workspace'; @@ -24,18 +24,15 @@ import type { WorkspaceSettingDetailProps } from './types'; import { WorkspaceQuotaPanel } from './workspace-quota'; export const WorkspaceSettingDetail = ({ - workspaceMetadata, onCloseSetting, onChangeSettingState, }: WorkspaceSettingDetailProps) => { const t = useI18n(); - // 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 workspace = useService(WorkspaceService).workspace; const server = workspace?.scope.get(WorkspaceServerService).server; - const workspaceInfo = useWorkspaceInfo(workspaceMetadata); + const workspaceInfo = useWorkspaceInfo(workspace); const handleResetSyncStatus = useCallback(() => { workspace?.engine.doc @@ -80,10 +77,7 @@ export const WorkspaceSettingDetail = ({ {BUILD_CONFIG.isElectron && ( - + )} diff --git a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/new-workspace-setting-detail/types.ts b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/new-workspace-setting-detail/types.ts index 6604851b7..d5856e744 100644 --- a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/new-workspace-setting-detail/types.ts +++ b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/new-workspace-setting-detail/types.ts @@ -1,9 +1,6 @@ -import type { WorkspaceMetadata } from '@affine/core/modules/workspace'; - import type { SettingState } from '../../types'; export interface WorkspaceSettingDetailProps { - workspaceMetadata: WorkspaceMetadata; onCloseSetting: () => void; onChangeSettingState: (settingState: SettingState) => void; } diff --git a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/properties/index.tsx b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/properties/index.tsx index 04ceb3334..c1601fe3b 100644 --- a/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/properties/index.tsx +++ b/packages/frontend/core/src/desktop/dialogs/setting/workspace-setting/properties/index.tsx @@ -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 { useWorkspaceInfo } from '@affine/core/components/hooks/use-workspace-info'; 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 track from '@affine/track'; -import { FrameworkScope } from '@toeverything/infra'; +import { FrameworkScope, useService } from '@toeverything/infra'; import { useCallback } from 'react'; -import { useWorkspace } from '../../../../../components/hooks/use-workspace'; import * as styles from './styles.css'; const WorkspaceSettingPropertiesMain = () => { @@ -47,14 +46,10 @@ const WorkspaceSettingPropertiesMain = () => { ); }; -export const WorkspaceSettingProperties = ({ - workspaceMetadata, -}: { - workspaceMetadata: WorkspaceMetadata; -}) => { +export const WorkspaceSettingProperties = () => { const t = useI18n(); - const workspace = useWorkspace(workspaceMetadata); - const workspaceInfo = useWorkspaceInfo(workspaceMetadata); + const workspace = useService(WorkspaceService).workspace; + const workspaceInfo = useWorkspaceInfo(workspace); const title = workspaceInfo?.name || 'untitled'; if (workspace === null) { diff --git a/packages/frontend/core/src/modules/app-sidebar/views/index.tsx b/packages/frontend/core/src/modules/app-sidebar/views/index.tsx index f7953a994..12d6d78c5 100644 --- a/packages/frontend/core/src/modules/app-sidebar/views/index.tsx +++ b/packages/frontend/core/src/modules/app-sidebar/views/index.tsx @@ -265,11 +265,7 @@ export function FallbackHeaderWithWorkspaceNavigator() { return (
{currentWorkspace && navigate ? ( - + ) : ( )} diff --git a/packages/frontend/core/src/modules/cloud/index.ts b/packages/frontend/core/src/modules/cloud/index.ts index a6cc96b44..9d6604ec4 100644 --- a/packages/frontend/core/src/modules/cloud/index.ts +++ b/packages/frontend/core/src/modules/cloud/index.ts @@ -35,7 +35,8 @@ export type { ServerConfig } from './types'; 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 { UrlService } from '../url'; import { WorkspaceScope, WorkspaceService } from '../workspace'; diff --git a/packages/frontend/core/src/modules/db/index.ts b/packages/frontend/core/src/modules/db/index.ts index 203fff902..5e8a13bc5 100644 --- a/packages/frontend/core/src/modules/db/index.ts +++ b/packages/frontend/core/src/modules/db/index.ts @@ -1,6 +1,6 @@ import type { Framework } from '@toeverything/infra'; -import { WorkspaceServerService } from '../cloud'; +import { WorkspaceServerService } from '../cloud/services/workspace-server'; import { WorkspaceScope, WorkspaceService } from '../workspace'; import { WorkspaceDB } from './entities/db'; import { WorkspaceDBTable } from './entities/table'; diff --git a/packages/frontend/core/src/modules/dialogs/constant.ts b/packages/frontend/core/src/modules/dialogs/constant.ts index 9bb6503bc..caa3365e5 100644 --- a/packages/frontend/core/src/modules/dialogs/constant.ts +++ b/packages/frontend/core/src/modules/dialogs/constant.ts @@ -26,11 +26,7 @@ export type GLOBAL_DIALOG_SCHEMA = { templateMode: DocMode; snapshotUrl: string; }) => void; - setting: (props: { - activeTab?: SettingTab; - workspaceMetadata?: WorkspaceMetadata | null; - scrollAnchor?: string; - }) => void; + setting: (props: { activeTab?: SettingTab; scrollAnchor?: string }) => void; 'sign-in': (props: { server?: string; step?: string }) => void; 'change-password': (props: { server?: string }) => void; 'verify-email': (props: { server?: string; changeEmail?: boolean }) => void; diff --git a/packages/frontend/core/src/modules/doc/index.ts b/packages/frontend/core/src/modules/doc/index.ts index 27405acca..d1182d3da 100644 --- a/packages/frontend/core/src/modules/doc/index.ts +++ b/packages/frontend/core/src/modules/doc/index.ts @@ -8,7 +8,7 @@ export { DocsService } from './services/docs'; import type { Framework } from '@toeverything/infra'; -import { WorkspaceDBService } from '../db'; +import { WorkspaceDBService } from '../db/services/db'; import { WorkspaceScope, WorkspaceService } from '../workspace'; import { Doc } from './entities/doc'; import { DocPropertyList } from './entities/property-list'; diff --git a/tests/affine-cloud/e2e/workspace.spec.ts b/tests/affine-cloud/e2e/workspace.spec.ts index b577cf629..86883e920 100644 --- a/tests/affine-cloud/e2e/workspace.spec.ts +++ b/tests/affine-cloud/e2e/workspace.spec.ts @@ -58,7 +58,7 @@ test('should have pagination in member list', async ({ page }) => { ); await openSettingModal(page); - await openWorkspaceSettingPanel(page, 'test'); + await openWorkspaceSettingPanel(page); await page.waitForTimeout(1000); diff --git a/tests/affine-desktop/e2e/basic.spec.ts b/tests/affine-desktop/e2e/basic.spec.ts index cf356925a..c0554a99a 100644 --- a/tests/affine-desktop/e2e/basic.spec.ts +++ b/tests/affine-desktop/e2e/basic.spec.ts @@ -121,7 +121,7 @@ test('delete workspace', async ({ page }) => { // }); await page.waitForTimeout(1000); 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( 'Delete Me' ); diff --git a/tests/affine-desktop/e2e/workspace.spec.ts b/tests/affine-desktop/e2e/workspace.spec.ts index 3820c360c..36a8f596a 100644 --- a/tests/affine-desktop/e2e/workspace.spec.ts +++ b/tests/affine-desktop/e2e/workspace.spec.ts @@ -42,7 +42,7 @@ test('export then add', async ({ page, appInfo, workspace }) => { const newWorkspaceName = 'new-test-name'; // 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'); await expect(input).toBeVisible(); diff --git a/tests/affine-local/e2e/local-first-avatar.spec.ts b/tests/affine-local/e2e/local-first-avatar.spec.ts index 587ab051f..152355fa1 100644 --- a/tests/affine-local/e2e/local-first-avatar.spec.ts +++ b/tests/affine-local/e2e/local-first-avatar.spec.ts @@ -24,7 +24,7 @@ test('should create a page with a local first avatar and remove it', async ({ .nth(1) .click({ position: { x: 10, y: 10 } }); 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('upload-avatar') .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 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-remove-avatar-button').click(); await page.mouse.click(0, 0); diff --git a/tests/affine-local/e2e/local-first-delete-workspace.spec.ts b/tests/affine-local/e2e/local-first-delete-workspace.spec.ts index bf3e0c4bc..fffc79b0b 100644 --- a/tests/affine-local/e2e/local-first-delete-workspace.spec.ts +++ b/tests/affine-local/e2e/local-first-delete-workspace.spec.ts @@ -26,7 +26,7 @@ test('Create new workspace, then delete it', async ({ page, workspace }) => { 'Test Workspace' ); await openSettingModal(page); - await openWorkspaceSettingPanel(page, 'Test Workspace'); + await openWorkspaceSettingPanel(page); await page.getByTestId('delete-workspace-button').click(); await expect( page.locator('.affine-notification-center').first() @@ -64,7 +64,7 @@ test('Delete last workspace', async ({ page }) => { node => node.textContent ); await openSettingModal(page); - await openWorkspaceSettingPanel(page, currentWorkspaceName as string); + await openWorkspaceSettingPanel(page); await page.getByTestId('delete-workspace-button').click(); await page .getByTestId('delete-workspace-input') diff --git a/tests/affine-local/e2e/settings.spec.ts b/tests/affine-local/e2e/settings.spec.ts index b381098d9..82645a4e2 100644 --- a/tests/affine-local/e2e/settings.spec.ts +++ b/tests/affine-local/e2e/settings.spec.ts @@ -10,7 +10,6 @@ import { openSettingModal, openShortcutsPanel, } from '@affine-test/kit/utils/setting'; -import { createLocalWorkspace } from '@affine-test/kit/utils/workspace'; import { expect } from '@playwright/test'; test('Open settings modal', async ({ page }) => { @@ -104,21 +103,3 @@ test('Open experimental features panel', async ({ page }) => { const settings = page.getByTestId('experimental-settings'); 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' - ); -}); diff --git a/tests/kit/src/utils/cloud.ts b/tests/kit/src/utils/cloud.ts index fea3a19bf..7c7992b9f 100644 --- a/tests/kit/src/utils/cloud.ts +++ b/tests/kit/src/utils/cloud.ts @@ -282,7 +282,7 @@ export async function loginUserDirectly( export async function enableCloudWorkspace(page: 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('confirm-enable-affine-cloud-button').click(); // wait for upload and delete local workspace diff --git a/tests/kit/src/utils/properties.ts b/tests/kit/src/utils/properties.ts index 33cc05843..f5c76a8ca 100644 --- a/tests/kit/src/utils/properties.ts +++ b/tests/kit/src/utils/properties.ts @@ -149,9 +149,6 @@ export const expectPropertyOrdering = async ( export const openWorkspaceProperties = async (page: Page) => { 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(); }; diff --git a/tests/kit/src/utils/setting.ts b/tests/kit/src/utils/setting.ts index b3d4a254c..2fa9301b0 100644 --- a/tests/kit/src/utils/setting.ts +++ b/tests/kit/src/utils/setting.ts @@ -38,11 +38,11 @@ export async function confirmExperimentalPrompt(page: Page) { await page.getByTestId('experimental-confirm-button').click(); } -export async function openWorkspaceSettingPanel( - page: Page, - workspaceName: string -) { - await page.getByTestId('settings-sidebar').getByText(workspaceName).click(); +export async function openWorkspaceSettingPanel(page: Page) { + await page + .getByTestId('settings-sidebar') + .getByTestId('workspace-list-item-workspace:preference') + .click(); } export async function clickUserInfoCard(page: Page) {