Skip to content

Commit

Permalink
feat(core): support creating cloud workspaces to different servers (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
JimmFly committed Dec 4, 2024
1 parent dddefcf commit 1fa1a95
Show file tree
Hide file tree
Showing 24 changed files with 621 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@ export class WorkspaceTransformService extends Service {
*/
transformLocalToCloud = async (
local: Workspace,
accountId: string
accountId: string,
flavour: string
): Promise<WorkspaceMetadata> => {
assertEquals(local.flavour, 'local');

const localDocStorage = local.engine.doc.storage.behavior;

const newMetadata = await this.factory.create(
'affine-cloud',
flavour,
async (docCollection, blobStorage, docStorage) => {
const rootDocBinary = await localDocStorage.doc.get(
local.docCollection.doc.guid
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/core/src/commands/affine-creation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export function registerAffineCreationCommands({
run() {
track.$.cmdk.workspace.createWorkspace();

globalDialogService.open('create-workspace', undefined);
globalDialogService.open('create-workspace', {});
},
})
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { notify, useConfirmModal } from '@affine/component';
import { AuthService } from '@affine/core/modules/cloud';
import { AuthService, ServersService } from '@affine/core/modules/cloud';
import { GlobalDialogService } from '@affine/core/modules/dialogs';
import { useI18n } from '@affine/i18n';
import type { Workspace } from '@toeverything/infra';
Expand All @@ -22,6 +22,7 @@ interface ConfirmEnableCloudOptions {
*/
onFinished?: () => void;
openPageId?: string;
serverId?: string;
}
type ConfirmEnableArgs = [Workspace, ConfirmEnableCloudOptions | undefined];

Expand All @@ -33,6 +34,9 @@ export const useEnableCloud = () => {
const globalDialogService = useService(GlobalDialogService);
const { openConfirmModal, closeConfirmModal } = useConfirmModal();
const workspacesService = useService(WorkspacesService);
const serversService = useService(ServersService);
const serverList = useLiveData(serversService.servers$);

const { jumpToPage } = useNavigateHelper();

const enableCloud = useCallback(
Expand All @@ -42,7 +46,8 @@ export const useEnableCloud = () => {
if (!account) return;
const { id: newId } = await workspacesService.transformLocalToCloud(
ws,
account.id
account.id,
'affine-cloud'
);
jumpToPage(newId, options?.openPageId || 'all');
options?.onSuccess?.();
Expand All @@ -56,9 +61,13 @@ export const useEnableCloud = () => {
[account, jumpToPage, t, workspacesService]
);

const openSignIn = useCallback(() => {
globalDialogService.open('sign-in', {});
}, [globalDialogService]);
const openSignIn = useCallback(
() =>
globalDialogService.open('sign-in', {
step: 'signIn',
}),
[globalDialogService]
);

const signInOrEnableCloud = useCallback(
async (...args: ConfirmEnableArgs) => {
Expand All @@ -76,13 +85,22 @@ export const useEnableCloud = () => {

const confirmEnableCloud = useCallback(
(ws: Workspace, options?: ConfirmEnableCloudOptions) => {
const { onSuccess, onFinished } = options ?? {};
const { onSuccess, onFinished, serverId, openPageId } = options ?? {};

const closeOnSuccess = () => {
closeConfirmModal();
onSuccess?.();
};

if (serverList.length > 1) {
globalDialogService.open('enable-cloud', {
workspaceId: ws.id,
serverId,
openPageId,
});
return;
}

openConfirmModal(
{
title: t['Enable AFFiNE Cloud'](),
Expand Down Expand Up @@ -110,7 +128,15 @@ export const useEnableCloud = () => {
}
);
},
[closeConfirmModal, loginStatus, openConfirmModal, signInOrEnableCloud, t]
[
closeConfirmModal,
globalDialogService,
loginStatus,
openConfirmModal,
serverList.length,
signInOrEnableCloud,
t,
]
);

return confirmEnableCloud;
Expand Down
40 changes: 40 additions & 0 deletions packages/frontend/core/src/components/server-selector/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Menu, MenuItem, type MenuProps, MenuTrigger } from '@affine/component';
import type { Server } from '@affine/core/modules/cloud';
import { useMemo } from 'react';

import { triggerStyle } from './style.css';

export const ServerSelector = ({
servers,
selectedSeverName,
onSelect,
contentOptions,
}: {
servers: Server[];
selectedSeverName: string;
onSelect: (server: Server) => void;
contentOptions?: MenuProps['contentOptions'];
}) => {
const menuItems = useMemo(() => {
return servers.map(server => (
<MenuItem key={server.id} onSelect={() => onSelect(server)}>
{server.config$.value.serverName} ({server.baseUrl})
</MenuItem>
));
}, [servers, onSelect]);

return (
<Menu
items={menuItems}
contentOptions={{
...contentOptions,
style: {
...contentOptions?.style,
width: 'var(--radix-dropdown-menu-trigger-width)',
},
}}
>
<MenuTrigger className={triggerStyle}>{selectedSeverName}</MenuTrigger>
</Menu>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { style } from '@vanilla-extract/css';

export const triggerStyle = style({
width: '100%',
});
8 changes: 7 additions & 1 deletion packages/frontend/core/src/components/sign-in/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,18 @@ export interface SignInState {
export const SignInPanel = ({
onClose,
server: initialServerBaseUrl,
initStep,
}: {
onClose: () => void;
server?: string;
initStep?: SignInStep | undefined;
}) => {
const [state, setState] = useState<SignInState>({
step: initialServerBaseUrl ? 'addSelfhosted' : 'signIn',
step: initStep
? initStep
: initialServerBaseUrl
? 'addSelfhosted'
: 'signIn',
initialServerBaseUrl: initialServerBaseUrl,
});

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { cssVar } from '@toeverything/theme';
import { style } from '@vanilla-extract/css';

export const root = style({
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
width: '100%',
gap: '20px',
});

export const textContainer = style({
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
textAlign: 'center',
});

export const title = style({
fontSize: cssVar('fontH6'),
fontWeight: 600,
lineHeight: '26px',
});

export const description = style({
fontSize: cssVar('fontBase'),
fontWeight: 400,
lineHeight: '24px',
color: cssVar('textSecondaryColor'),
});

export const serverSelector = style({
width: '100%',
});

export const button = style({
width: '100%',
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import type { Server } from '@affine/core/modules/cloud';
import { CloudWorkspaceIcon } from '@blocksuite/icons/rc';

import { ServerSelector } from '../../server-selector';
import * as styles from './enable-cloud.css';

export const CustomServerEnableCloud = ({
serverList,
selectedServer,
setSelectedServer,
title,
description,
}: {
serverList: Server[];
selectedServer: Server;
title?: string;
description?: string;
setSelectedServer: (server: Server) => void;
}) => {
return (
<div className={styles.root}>
<CloudWorkspaceIcon width={'36px'} height={'36px'} />
<div className={styles.textContainer}>
{title ? <div className={styles.title}>{title}</div> : null}
{description ? (
<div className={styles.description}>{description}</div>
) : null}
</div>
<div className={styles.serverSelector}>
<ServerSelector
servers={serverList}
selectedSeverName={`${selectedServer.config$.value.serverName} (${selectedServer.baseUrl})`}
onSelect={setSelectedServer}
/>
</div>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './enable-cloud';
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { cssVar } from '@toeverything/theme';
import { style } from '@vanilla-extract/css';
export const ItemContainer = style({
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-start',
padding: '8px 14px',
gap: '14px',
cursor: 'pointer',
borderRadius: '8px',
transition: 'background-color 0.2s',
fontSize: '24px',
color: cssVar('iconSecondary'),
});
export const ItemText = style({
fontSize: cssVar('fontSm'),
lineHeight: '22px',
color: cssVar('textSecondaryColor'),
fontWeight: 400,
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { MenuItem } from '@affine/component/ui/menu';
import { useI18n } from '@affine/i18n';
import { PlusIcon } from '@blocksuite/icons/rc';
import {
FeatureFlagService,
useLiveData,
useService,
} from '@toeverything/infra';

import * as styles from './index.css';

export const AddServer = ({ onAddServer }: { onAddServer?: () => void }) => {
const t = useI18n();
const featureFlagService = useService(FeatureFlagService);
const enableMultipleServer = useLiveData(
featureFlagService.flags.enable_multiple_cloud_servers.$
);

if (!enableMultipleServer) {
return null;
}
return (
<div>
<MenuItem
block={true}
prefixIcon={<PlusIcon />}
onClick={onAddServer}
data-testid="new-server"
className={styles.ItemContainer}
>
<div className={styles.ItemText}>
{t['com.affine.workspaceList.addServer']()}
</div>
</MenuItem>
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@ import {
} from '@toeverything/infra';
import { useCallback } from 'react';

import { useCatchEventCallback } from '../../hooks/use-catch-event-hook';
import { AddServer } from './add-server';
import { AddWorkspace } from './add-workspace';
import * as styles from './index.css';
import { UserAccountItem } from './user-account';
import { AFFiNEWorkspaceList } from './workspace-list';

export const SignInItem = () => {
Expand Down Expand Up @@ -90,7 +89,7 @@ const UserWithWorkspaceListInner = ({
return openSignInModal();
}
track.$.navigationPanel.workspaceList.createWorkspace();
globalDialogService.open('create-workspace', undefined, payload => {
globalDialogService.open('create-workspace', {}, payload => {
if (payload) {
onCreatedWorkspace?.(payload);
}
Expand All @@ -117,28 +116,15 @@ const UserWithWorkspaceListInner = ({
onEventEnd?.();
}, [globalDialogService, onCreatedWorkspace, onEventEnd]);

const onAddServer = useCallback(() => {
globalDialogService.open('sign-in', { step: 'addSelfhosted' });
}, [globalDialogService]);

const workspaceManager = useService(WorkspacesService);
const workspaces = useLiveData(workspaceManager.list.workspaces$);

const onOpenPricingPlan = useCatchEventCallback(() => {
globalDialogService.open('setting', {
activeTab: 'plans',
scrollAnchor: 'cloudPricingPlan',
});
}, [globalDialogService]);

return (
<div className={styles.workspaceListWrapper}>
{isAuthenticated ? (
<UserAccountItem
email={session.session.account.email ?? 'Unknown User'}
onEventEnd={onEventEnd}
onClick={onOpenPricingPlan}
/>
) : (
<SignInItem />
)}
<Divider size="thinner" />
<AFFiNEWorkspaceList
onEventEnd={onEventEnd}
onClickWorkspace={onClickWorkspace}
Expand All @@ -150,6 +136,7 @@ const UserWithWorkspaceListInner = ({
onAddWorkspace={onAddWorkspace}
onNewWorkspace={onNewWorkspace}
/>
<AddServer onAddServer={onAddServer} />
</div>
);
};
Expand Down
Loading

0 comments on commit 1fa1a95

Please sign in to comment.