mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-13 21:05:19 +00:00
@@ -1,5 +1,5 @@
|
||||
import type { SettingTab } from '@affine/core/modules/dialogs/constant';
|
||||
import type { ReactNode } from 'react';
|
||||
import type { ReactElement } from 'react';
|
||||
|
||||
export interface SettingState {
|
||||
activeTab: SettingTab;
|
||||
@@ -9,6 +9,6 @@ export interface SettingState {
|
||||
export interface SettingSidebarItem {
|
||||
key: SettingTab;
|
||||
title: string;
|
||||
icon: ReactNode;
|
||||
icon: ReactElement;
|
||||
testId: string;
|
||||
}
|
||||
|
||||
@@ -2,14 +2,22 @@ import { useWorkspaceInfo } from '@affine/core/components/hooks/use-workspace-in
|
||||
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 {
|
||||
CollaborationIcon,
|
||||
PaymentIcon,
|
||||
PropertyIcon,
|
||||
SaveIcon,
|
||||
SettingsIcon,
|
||||
} from '@blocksuite/icons/rc';
|
||||
import { useService } from '@toeverything/infra';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import type { SettingSidebarItem, SettingState } from '../types';
|
||||
import { WorkspaceSettingBilling } from './billing';
|
||||
import { WorkspaceSettingDetail } from './new-workspace-setting-detail';
|
||||
import { MembersPanel } from './members';
|
||||
import { WorkspaceSettingDetail } from './preference';
|
||||
import { WorkspaceSettingProperties } from './properties';
|
||||
import { WorkspaceSettingStorage } from './storage';
|
||||
|
||||
export const WorkspaceSetting = ({
|
||||
activeTab,
|
||||
@@ -22,16 +30,20 @@ export const WorkspaceSetting = ({
|
||||
}) => {
|
||||
switch (activeTab) {
|
||||
case 'workspace:preference':
|
||||
return <WorkspaceSettingDetail onCloseSetting={onCloseSetting} />;
|
||||
case 'workspace:properties':
|
||||
return <WorkspaceSettingProperties />;
|
||||
case 'workspace:members':
|
||||
return (
|
||||
<WorkspaceSettingDetail
|
||||
<MembersPanel
|
||||
onCloseSetting={onCloseSetting}
|
||||
onChangeSettingState={onChangeSettingState}
|
||||
/>
|
||||
);
|
||||
case 'workspace:properties':
|
||||
return <WorkspaceSettingProperties />;
|
||||
case 'workspace:billing':
|
||||
return <WorkspaceSettingBilling />;
|
||||
case 'workspace:storage':
|
||||
return <WorkspaceSettingStorage />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@@ -58,17 +70,27 @@ export const useWorkspaceSettingList = (): SettingSidebarItem[] => {
|
||||
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',
|
||||
},
|
||||
]
|
||||
: []),
|
||||
];
|
||||
{
|
||||
key: 'workspace:members',
|
||||
title: t['Members'](),
|
||||
icon: <CollaborationIcon />,
|
||||
testId: 'workspace-setting:members',
|
||||
},
|
||||
{
|
||||
key: 'workspace:storage',
|
||||
title: t['Storage'](),
|
||||
icon: <SaveIcon />,
|
||||
testId: 'workspace-setting:storage',
|
||||
},
|
||||
showBilling && {
|
||||
key: 'workspace:billing' as SettingTab,
|
||||
title: t['com.affine.settings.workspace.billing'](),
|
||||
icon: <PaymentIcon />,
|
||||
testId: 'workspace-setting:billing',
|
||||
},
|
||||
|
||||
// todo(@pengx17): add selfhost's team license
|
||||
].filter((item): item is SettingSidebarItem => !!item);
|
||||
}, [showBilling, t]);
|
||||
|
||||
return items;
|
||||
|
||||
@@ -24,7 +24,7 @@ import { ExportIcon } from '@blocksuite/icons/rc';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import type { SettingState } from '../../../types';
|
||||
import type { SettingState } from '../../types';
|
||||
import { MemberList } from './member-list';
|
||||
import * as styles from './styles.css';
|
||||
|
||||
@@ -7,19 +7,22 @@ import { useI18n } from '@affine/i18n';
|
||||
import { useService } from '@toeverything/infra';
|
||||
import type { ReactElement } from 'react';
|
||||
|
||||
import type { SettingState } from '../../../types';
|
||||
import type { SettingState } from '../../types';
|
||||
import { EnableCloudPanel } from '../preference/enable-cloud';
|
||||
import { CloudWorkspaceMembersPanel } from './cloud-members-panel';
|
||||
import * as styles from './styles.css';
|
||||
|
||||
export const MembersPanel = ({
|
||||
onChangeSettingState,
|
||||
onCloseSetting,
|
||||
}: {
|
||||
onChangeSettingState: (settingState: SettingState) => void;
|
||||
onCloseSetting: () => void;
|
||||
}): ReactElement | null => {
|
||||
const workspace = useService(WorkspaceService).workspace;
|
||||
const isTeam = useWorkspaceInfo(workspace.meta)?.isTeam;
|
||||
if (workspace.flavour === 'local') {
|
||||
return <MembersPanelLocal />;
|
||||
return <MembersPanelLocal onCloseSetting={onCloseSetting} />;
|
||||
}
|
||||
return (
|
||||
<AffineErrorBoundary>
|
||||
@@ -31,15 +34,22 @@ export const MembersPanel = ({
|
||||
);
|
||||
};
|
||||
|
||||
const MembersPanelLocal = () => {
|
||||
const MembersPanelLocal = ({
|
||||
onCloseSetting,
|
||||
}: {
|
||||
onCloseSetting: () => void;
|
||||
}) => {
|
||||
const t = useI18n();
|
||||
return (
|
||||
<Tooltip content={t['com.affine.settings.member-tooltip']()}>
|
||||
<div className={styles.fakeWrapper}>
|
||||
<SettingRow name={`${t['Members']()} (0)`} desc={t['Members hint']()}>
|
||||
<Button>{t['Invite Members']()}</Button>
|
||||
</SettingRow>
|
||||
</div>
|
||||
</Tooltip>
|
||||
<div className={styles.localMembersPanel}>
|
||||
<Tooltip content={t['com.affine.settings.member-tooltip']()}>
|
||||
<div className={styles.fakeWrapper}>
|
||||
<SettingRow name={`${t['Members']()} (0)`} desc={t['Members hint']()}>
|
||||
<Button>{t['Invite Members']()}</Button>
|
||||
</SettingRow>
|
||||
</div>
|
||||
</Tooltip>
|
||||
<EnableCloudPanel onCloseSetting={onCloseSetting} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -29,6 +29,12 @@ export const membersPanel = style({
|
||||
justifyContent: 'space-between',
|
||||
});
|
||||
|
||||
export const localMembersPanel = style({
|
||||
gap: '24px',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
});
|
||||
|
||||
export const goUpgradeWrapper = style({
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
@@ -1,78 +0,0 @@
|
||||
import {
|
||||
SettingHeader,
|
||||
SettingRow,
|
||||
SettingWrapper,
|
||||
} from '@affine/component/setting-components';
|
||||
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 { FrameworkScope, useService } from '@toeverything/infra';
|
||||
|
||||
import { DeleteLeaveWorkspace } from './delete-leave-workspace';
|
||||
import { EnableCloudPanel } from './enable-cloud';
|
||||
import { DesktopExportPanel } from './export';
|
||||
import { LabelsPanel } from './labels';
|
||||
import { MembersPanel } from './members';
|
||||
import { ProfilePanel } from './profile';
|
||||
import { SharingPanel } from './sharing';
|
||||
import { TemplateDocSetting } from './template';
|
||||
import type { WorkspaceSettingDetailProps } from './types';
|
||||
import { WorkspaceQuotaPanel } from './workspace-quota';
|
||||
|
||||
export const WorkspaceSettingDetail = ({
|
||||
onCloseSetting,
|
||||
onChangeSettingState,
|
||||
}: WorkspaceSettingDetailProps) => {
|
||||
const t = useI18n();
|
||||
|
||||
const workspace = useService(WorkspaceService).workspace;
|
||||
const server = workspace?.scope.get(WorkspaceServerService).server;
|
||||
|
||||
const workspaceInfo = useWorkspaceInfo(workspace);
|
||||
|
||||
if (!workspace) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<FrameworkScope scope={server?.scope}>
|
||||
<FrameworkScope scope={workspace.scope}>
|
||||
<SettingHeader
|
||||
title={t[`Workspace Settings with name`]({
|
||||
name: workspaceInfo?.name ?? UNTITLED_WORKSPACE_NAME,
|
||||
})}
|
||||
subtitle={t['com.affine.settings.workspace.description']()}
|
||||
/>
|
||||
<SettingWrapper title={t['Info']()}>
|
||||
<SettingRow
|
||||
name={t['Workspace Profile']()}
|
||||
desc={t['com.affine.settings.workspace.not-owner']()}
|
||||
spreadCol={false}
|
||||
>
|
||||
<ProfilePanel />
|
||||
<LabelsPanel />
|
||||
</SettingRow>
|
||||
</SettingWrapper>
|
||||
<TemplateDocSetting />
|
||||
<SettingWrapper title={t['com.affine.brand.affineCloud']()}>
|
||||
<EnableCloudPanel onCloseSetting={onCloseSetting} />
|
||||
{workspace.flavour !== 'local' && <WorkspaceQuotaPanel />}
|
||||
{workspace.flavour !== 'local' && (
|
||||
<MembersPanel onChangeSettingState={onChangeSettingState} />
|
||||
)}
|
||||
</SettingWrapper>
|
||||
<SharingPanel />
|
||||
{BUILD_CONFIG.isElectron && (
|
||||
<SettingWrapper title={t['Storage and Export']()}>
|
||||
<DesktopExportPanel workspace={workspace} />
|
||||
</SettingWrapper>
|
||||
)}
|
||||
<SettingWrapper>
|
||||
<DeleteLeaveWorkspace onCloseSetting={onCloseSetting} />
|
||||
</SettingWrapper>
|
||||
</FrameworkScope>
|
||||
</FrameworkScope>
|
||||
);
|
||||
};
|
||||
@@ -1,6 +0,0 @@
|
||||
import type { SettingState } from '../../types';
|
||||
|
||||
export interface WorkspaceSettingDetailProps {
|
||||
onCloseSetting: () => void;
|
||||
onChangeSettingState: (settingState: SettingState) => void;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import {
|
||||
SettingHeader,
|
||||
SettingRow,
|
||||
SettingWrapper,
|
||||
} from '@affine/component/setting-components';
|
||||
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 { FrameworkScope, useService } from '@toeverything/infra';
|
||||
|
||||
import { DeleteLeaveWorkspace } from './delete-leave-workspace';
|
||||
import { EnableCloudPanel } from './enable-cloud';
|
||||
import { LabelsPanel } from './labels';
|
||||
import { ProfilePanel } from './profile';
|
||||
import { SharingPanel } from './sharing';
|
||||
import { TemplateDocSetting } from './template';
|
||||
import type { WorkspaceSettingDetailProps } from './types';
|
||||
|
||||
export const WorkspaceSettingDetail = ({
|
||||
onCloseSetting,
|
||||
}: WorkspaceSettingDetailProps) => {
|
||||
const t = useI18n();
|
||||
|
||||
const workspace = useService(WorkspaceService).workspace;
|
||||
const server = workspace?.scope.get(WorkspaceServerService).server;
|
||||
|
||||
const workspaceInfo = useWorkspaceInfo(workspace);
|
||||
|
||||
return (
|
||||
<FrameworkScope scope={server?.scope}>
|
||||
<SettingHeader
|
||||
title={t[`Workspace Settings with name`]({
|
||||
name: workspaceInfo?.name ?? UNTITLED_WORKSPACE_NAME,
|
||||
})}
|
||||
subtitle={t['com.affine.settings.workspace.description']()}
|
||||
/>
|
||||
<SettingWrapper title={t['Info']()}>
|
||||
<SettingRow
|
||||
name={t['Workspace Profile']()}
|
||||
desc={t['com.affine.settings.workspace.not-owner']()}
|
||||
spreadCol={false}
|
||||
>
|
||||
<ProfilePanel />
|
||||
<LabelsPanel />
|
||||
{workspace.flavour === 'local' && (
|
||||
<EnableCloudPanel onCloseSetting={onCloseSetting} />
|
||||
)}
|
||||
</SettingRow>
|
||||
</SettingWrapper>
|
||||
<TemplateDocSetting />
|
||||
<SharingPanel />
|
||||
<SettingWrapper>
|
||||
<DeleteLeaveWorkspace onCloseSetting={onCloseSetting} />
|
||||
</SettingWrapper>
|
||||
</FrameworkScope>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
export interface WorkspaceSettingDetailProps {
|
||||
onCloseSetting: () => void;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import {
|
||||
SettingHeader,
|
||||
SettingWrapper,
|
||||
} from '@affine/component/setting-components';
|
||||
import { WorkspaceService } from '@affine/core/modules/workspace';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { useService } from '@toeverything/infra';
|
||||
|
||||
import { DesktopExportPanel } from './export';
|
||||
import { WorkspaceQuotaPanel } from './workspace-quota';
|
||||
|
||||
export const WorkspaceSettingStorage = () => {
|
||||
const t = useI18n();
|
||||
const workspace = useService(WorkspaceService).workspace;
|
||||
return (
|
||||
<>
|
||||
<SettingHeader
|
||||
title={t['Storage']()}
|
||||
subtitle={t['com.affine.settings.workspace.storage.subtitle']()}
|
||||
/>
|
||||
{workspace.flavour !== 'local' && (
|
||||
<SettingWrapper>
|
||||
<WorkspaceQuotaPanel />
|
||||
</SettingWrapper>
|
||||
)}
|
||||
{BUILD_CONFIG.isElectron && (
|
||||
<SettingWrapper>
|
||||
<DesktopExportPanel workspace={workspace} />
|
||||
</SettingWrapper>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import { cssVarV2 } from '@toeverything/theme/v2';
|
||||
import { globalStyle, style } from '@vanilla-extract/css';
|
||||
|
||||
export const storageProgressContainer = style({
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
});
|
||||
export const storageProgressWrapper = style({
|
||||
flexGrow: 1,
|
||||
});
|
||||
globalStyle(`${storageProgressWrapper} .storage-progress-desc`, {
|
||||
fontSize: cssVar('fontXs'),
|
||||
color: cssVarV2('text/secondary'),
|
||||
height: '20px',
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: 2,
|
||||
});
|
||||
globalStyle(`${storageProgressWrapper} .storage-progress-bar-wrapper`, {
|
||||
height: '8px',
|
||||
borderRadius: '4px',
|
||||
backgroundColor: cssVarV2('layer/background/hoverOverlay'),
|
||||
overflow: 'hidden',
|
||||
});
|
||||
export const storageProgressBar = style({
|
||||
height: '100%',
|
||||
});
|
||||
@@ -11,7 +11,7 @@ export type SettingTab =
|
||||
| 'experimental-features'
|
||||
| 'editor'
|
||||
| 'account'
|
||||
| `workspace:${'preference' | 'properties' | 'billing' | 'license'}`;
|
||||
| `workspace:${'preference' | 'properties' | 'members' | 'storage' | 'billing' | 'license'}`;
|
||||
|
||||
export type GLOBAL_DIALOG_SCHEMA = {
|
||||
'create-workspace': (props: { serverId?: string; forcedCloud?: boolean }) => {
|
||||
|
||||
Reference in New Issue
Block a user