refactor: init package @affine/workspace (#1661)

This commit is contained in:
Himself65
2023-03-23 11:17:38 -05:00
committed by GitHub
parent 84d27e939d
commit 69721f2a61
44 changed files with 952 additions and 236 deletions

View File

@@ -15,6 +15,7 @@
"@affine/env": "workspace:*",
"@affine/i18n": "workspace:*",
"@affine/templates": "workspace:*",
"@affine/workspace": "workspace:*",
"@blocksuite/blocks": "0.5.0-20230323085636-3110abb",
"@blocksuite/editor": "0.5.0-20230323085636-3110abb",
"@blocksuite/icons": "2.0.23",

View File

@@ -1,3 +1,4 @@
import type { WorkspaceFlavour } from '@affine/workspace/type';
import type { EditorContainer } from '@blocksuite/editor';
import type { Page } from '@blocksuite/store';
import { assertExists } from '@blocksuite/store';
@@ -6,7 +7,7 @@ import { atomWithStorage } from 'jotai/utils';
import { unstable_batchedUpdates } from 'react-dom';
import { WorkspacePlugins } from '../plugins';
import type { RemWorkspace, RemWorkspaceFlavour } from '../shared';
import type { RemWorkspace } from '../shared';
// workspace necessary atoms
export const currentWorkspaceIdAtom = atom<string | null>(null);
export const currentPageIdAtom = atom<string | null>(null);
@@ -37,7 +38,7 @@ export const jotaiStore = createStore();
type JotaiWorkspace = {
id: string;
flavour: RemWorkspaceFlavour;
flavour: WorkspaceFlavour;
};
export const jotaiWorkspacesAtom = atomWithStorage<JotaiWorkspace[]>(

View File

@@ -1,8 +1,8 @@
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
import { atom } from 'jotai/index';
import { BlockSuiteWorkspace } from '../../shared';
import { apis } from '../../shared/apis';
import { createEmptyBlockSuiteWorkspace } from '../../utils';
export const publicWorkspaceIdAtom = atom<string | null>(null);
export const publicBlockSuiteAtom = atom<Promise<BlockSuiteWorkspace>>(

View File

@@ -1,11 +1,11 @@
'use client';
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
import type { EditorContainer } from '@blocksuite/editor';
import type { Page } from '@blocksuite/store';
import { Generator } from '@blocksuite/store';
import type React from 'react';
import { useCallback, useRef } from 'react';
import { createEmptyBlockSuiteWorkspace } from '../../../utils';
import { BlockSuiteEditor } from '../../blocksuite/block-suite-editor';
const blockSuiteWorkspace = createEmptyBlockSuiteWorkspace(

View File

@@ -3,6 +3,7 @@
*/
import 'fake-indexeddb/auto';
import { WorkspaceFlavour } from '@affine/workspace/type';
import { assertExists } from '@blocksuite/store';
import { render, renderHook } from '@testing-library/react';
import { createStore, getDefaultStore, Provider } from 'jotai';
@@ -20,7 +21,7 @@ import {
import { useBlockSuiteWorkspaceHelper } from '../../hooks/use-blocksuite-workspace-helper';
import { useWorkspacesHelper } from '../../hooks/use-workspaces';
import { ThemeProvider } from '../../providers/ThemeProvider';
import { pathGenerator, RemWorkspaceFlavour } from '../../shared';
import { pathGenerator } from '../../shared';
import { WorkSpaceSliderBar } from '../pure/workspace-slider-bar';
vi.mock('../blocksuite/header/editor-mode-switch/CustomLottie', () => ({
@@ -92,7 +93,7 @@ describe('WorkSpaceSliderBar', () => {
currentWorkspaceHook.result.current[1](id);
const currentWorkspace = await store.get(currentWorkspaceAtom);
expect(currentWorkspace).toBeDefined();
expect(currentWorkspace?.flavour).toBe(RemWorkspaceFlavour.LOCAL);
expect(currentWorkspace?.flavour).toBe(WorkspaceFlavour.LOCAL);
expect(currentWorkspace?.id).toBe(id);
const app = render(<App />);
const card = await app.findByTestId('current-workspace');

View File

@@ -1,4 +1,6 @@
import { useTranslation } from '@affine/i18n';
import type { SettingPanel, WorkspaceRegistry } from '@affine/workspace/type';
import { settingPanel, WorkspaceFlavour } from '@affine/workspace/type';
import type { MouseEvent } from 'react';
import type React from 'react';
import { Suspense, useCallback, useEffect, useMemo, useRef } from 'react';
@@ -6,12 +8,7 @@ import { preload } from 'swr';
import { useIsWorkspaceOwner } from '../../../hooks/affine/use-is-workspace-owner';
import { fetcher, QueryKey } from '../../../plugins/affine/fetcher';
import type {
AffineOfficialWorkspace,
FlavourToWorkspace,
SettingPanel,
} from '../../../shared';
import { RemWorkspaceFlavour, settingPanel } from '../../../shared';
import type { AffineOfficialWorkspace } from '../../../shared';
import { CollaborationPanel } from './panel/collaboration';
import { ExportPanel } from './panel/export';
import { GeneralPanel } from './panel/general';
@@ -31,12 +28,12 @@ export type WorkspaceSettingDetailProps = {
onChangeTab: (tab: SettingPanel) => void;
onDeleteWorkspace: () => void;
onTransferWorkspace: <
From extends RemWorkspaceFlavour,
To extends RemWorkspaceFlavour
From extends WorkspaceFlavour,
To extends WorkspaceFlavour
>(
from: From,
to: To,
workspace: FlavourToWorkspace[From]
workspace: WorkspaceRegistry[From]
) => void;
};
@@ -49,8 +46,7 @@ const panelMap = {
},
[settingPanel.Sync]: {
name: 'Sync',
enable: (flavour: RemWorkspaceFlavour) =>
flavour === RemWorkspaceFlavour.AFFINE,
enable: (flavour: WorkspaceFlavour) => flavour === WorkspaceFlavour.AFFINE,
ui: SyncPanel,
},
[settingPanel.Collaboration]: {
@@ -68,7 +64,7 @@ const panelMap = {
} satisfies {
[Key in SettingPanel]: {
name: string;
enable?: (flavour: RemWorkspaceFlavour) => boolean;
enable?: (flavour: WorkspaceFlavour) => boolean;
ui: React.FC<PanelProps>;
};
};

View File

@@ -8,6 +8,7 @@ import {
} from '@affine/component';
import { PermissionType } from '@affine/datacenter';
import { useTranslation } from '@affine/i18n';
import { WorkspaceFlavour } from '@affine/workspace/type';
import {
DeleteTemporarilyIcon,
EmailIcon,
@@ -18,7 +19,6 @@ import { useCallback, useState } from 'react';
import { useMembers } from '../../../../../hooks/affine/use-members';
import type { AffineWorkspace, LocalWorkspace } from '../../../../../shared';
import { RemWorkspaceFlavour } from '../../../../../shared';
import { Unreachable } from '../../../affine-error-eoundary';
import { TransformWorkspaceToAffineModal } from '../../../transform-workspace-to-affine-modal';
import type { PanelProps } from '../../index';
@@ -194,8 +194,8 @@ const LocalCollaborationPanel: React.FC<
}}
onConform={() => {
onTransferWorkspace(
RemWorkspaceFlavour.LOCAL,
RemWorkspaceFlavour.AFFINE,
WorkspaceFlavour.LOCAL,
WorkspaceFlavour.AFFINE,
workspace
);
setOpen(false);
@@ -207,13 +207,13 @@ const LocalCollaborationPanel: React.FC<
export const CollaborationPanel: React.FC<PanelProps> = props => {
switch (props.workspace.flavour) {
case RemWorkspaceFlavour.AFFINE: {
case WorkspaceFlavour.AFFINE: {
const workspace = props.workspace as AffineWorkspace;
return (
<AffineRemoteCollaborationPanel {...props} workspace={workspace} />
);
}
case RemWorkspaceFlavour.LOCAL: {
case WorkspaceFlavour.LOCAL: {
const workspace = props.workspace as LocalWorkspace;
return <LocalCollaborationPanel {...props} workspace={workspace} />;
}

View File

@@ -1,10 +1,10 @@
import { Button, Input, Modal, ModalCloseButton } from '@affine/component';
import { Trans, useTranslation } from '@affine/i18n';
import { WorkspaceFlavour } from '@affine/workspace/type';
import { useCallback, useState } from 'react';
import { useBlockSuiteWorkspaceName } from '../../../../../../hooks/use-blocksuite-workspace-name';
import type { AffineOfficialWorkspace } from '../../../../../../shared';
import { RemWorkspaceFlavour } from '../../../../../../shared';
import {
StyledButtonContent,
StyledInputContent,
@@ -43,7 +43,7 @@ export const WorkspaceDeleteModal = ({
<StyledModalWrapper>
<ModalCloseButton onClick={onClose} />
<StyledModalHeader>{t('Delete Workspace')}?</StyledModalHeader>
{workspace.flavour === RemWorkspaceFlavour.LOCAL ? (
{workspace.flavour === WorkspaceFlavour.LOCAL ? (
<StyledTextContent>
<Trans i18nKey="Delete Workspace Description">
Deleting (

View File

@@ -1,12 +1,12 @@
import { Button, FlexWrapper, MuiFade } from '@affine/component';
import { useTranslation } from '@affine/i18n';
import { WorkspaceFlavour } from '@affine/workspace/type';
import type React from 'react';
import { useState } from 'react';
import { useIsWorkspaceOwner } from '../../../../../hooks/affine/use-is-workspace-owner';
import { useBlockSuiteWorkspaceAvatarUrl } from '../../../../../hooks/use-blocksuite-workspace-avatar-url';
import { useBlockSuiteWorkspaceName } from '../../../../../hooks/use-blocksuite-workspace-name';
import { RemWorkspaceFlavour } from '../../../../../shared';
import { Upload } from '../../../../pure/file-upload';
import {
CloudWorkspaceIcon,
@@ -161,7 +161,7 @@ export const GeneralPanel: React.FC<PanelProps> = ({
<StyledRow>
<StyledSettingKey>{t('Workspace Type')}</StyledSettingKey>
{isOwner ? (
workspace.flavour === RemWorkspaceFlavour.LOCAL ? (
workspace.flavour === WorkspaceFlavour.LOCAL ? (
<StyledWorkspaceInfo>
<LocalWorkspaceIcon />
<span>{t('Local Workspace')}</span>

View File

@@ -7,6 +7,7 @@ import {
Wrapper,
} from '@affine/component';
import { useTranslation } from '@affine/i18n';
import { WorkspaceFlavour } from '@affine/workspace/type';
import { Box } from '@mui/material';
import type React from 'react';
import { useCallback, useEffect, useState } from 'react';
@@ -17,7 +18,6 @@ import type {
AffineWorkspace,
LocalWorkspace,
} from '../../../../../shared';
import { RemWorkspaceFlavour } from '../../../../../shared';
import { Unreachable } from '../../../affine-error-eoundary';
import { EnableAffineCloudModal } from '../../../enable-affine-cloud-modal';
import type { WorkspaceSettingDetailProps } from '../../index';
@@ -133,8 +133,8 @@ const PublishPanelLocal: React.FC<PublishPanelLocalProps> = ({
}}
onConfirm={() => {
onTransferWorkspace(
RemWorkspaceFlavour.LOCAL,
RemWorkspaceFlavour.AFFINE,
WorkspaceFlavour.LOCAL,
WorkspaceFlavour.AFFINE,
workspace
);
setOpen(false);
@@ -145,9 +145,9 @@ const PublishPanelLocal: React.FC<PublishPanelLocalProps> = ({
};
export const PublishPanel: React.FC<PublishPanelProps> = props => {
if (props.workspace.flavour === RemWorkspaceFlavour.AFFINE) {
if (props.workspace.flavour === WorkspaceFlavour.AFFINE) {
return <PublishPanelAffine {...props} workspace={props.workspace} />;
} else if (props.workspace.flavour === RemWorkspaceFlavour.LOCAL) {
} else if (props.workspace.flavour === WorkspaceFlavour.LOCAL) {
return <PublishPanelLocal {...props} workspace={props.workspace} />;
}
throw new Unreachable();

View File

@@ -1,11 +1,11 @@
import { Content, FlexWrapper, styled } from '@affine/component';
import { Trans, useTranslation } from '@affine/i18n';
import { WorkspaceFlavour } from '@affine/workspace/type';
import type React from 'react';
import { useCurrentUser } from '../../../../../hooks/current/use-current-user';
import { useBlockSuiteWorkspaceAvatarUrl } from '../../../../../hooks/use-blocksuite-workspace-avatar-url';
import { useBlockSuiteWorkspaceName } from '../../../../../hooks/use-blocksuite-workspace-name';
import { RemWorkspaceFlavour } from '../../../../../shared';
import { WorkspaceAvatar } from '../../../../pure/footer';
import type { PanelProps } from '../../index';
@@ -17,7 +17,7 @@ export const StyledWorkspaceName = styled('span')(({ theme }) => {
});
export const SyncPanel: React.FC<PanelProps> = ({ workspace }) => {
if (workspace.flavour !== RemWorkspaceFlavour.AFFINE) {
if (workspace.flavour !== WorkspaceFlavour.AFFINE) {
throw new TypeError('SyncPanel can only be used with Affine workspace');
}
const [name] = useBlockSuiteWorkspaceName(workspace.blockSuiteWorkspace);

View File

@@ -1,5 +1,6 @@
import { displayFlex, IconButton, styled, Tooltip } from '@affine/component';
import { useTranslation } from '@affine/i18n';
import { WorkspaceFlavour } from '@affine/workspace/type';
import {
CloudWorkspaceIcon,
LocalWorkspaceIcon,
@@ -15,7 +16,6 @@ import type {
AffineOfficialWorkspace,
LocalWorkspace,
} from '../../../../shared';
import { RemWorkspaceFlavour } from '../../../../shared';
import { apis } from '../../../../shared/apis';
import { TransformWorkspaceToAffineModal } from '../../../affine/transform-workspace-to-affine-modal';
@@ -117,10 +117,10 @@ export const SyncUser = () => {
router.reload();
return;
}
assertEquals(workspace.flavour, RemWorkspaceFlavour.LOCAL);
assertEquals(workspace.flavour, WorkspaceFlavour.LOCAL);
const id = await transformWorkspace(
RemWorkspaceFlavour.LOCAL,
RemWorkspaceFlavour.AFFINE,
WorkspaceFlavour.LOCAL,
WorkspaceFlavour.AFFINE,
workspace as LocalWorkspace
);
// fixme(himself65): refactor this

View File

@@ -1,12 +1,12 @@
import { PermissionType } from '@affine/datacenter';
import { useTranslation } from '@affine/i18n';
import { WorkspaceFlavour } from '@affine/workspace/type';
import { SettingsIcon } from '@blocksuite/icons';
import type React from 'react';
import { useCallback } from 'react';
import { useBlockSuiteWorkspaceName } from '../../../hooks/use-blocksuite-workspace-name';
import type { RemWorkspace } from '../../../shared';
import { RemWorkspaceFlavour } from '../../../shared';
import {
CloudWorkspaceIcon,
JoinedWorkspaceIcon,
@@ -28,13 +28,13 @@ export type WorkspaceTypeProps = {
const WorkspaceType: React.FC<WorkspaceTypeProps> = ({ workspace }) => {
const { t } = useTranslation();
let isOwner = true;
if (workspace.flavour === RemWorkspaceFlavour.AFFINE) {
if (workspace.flavour === WorkspaceFlavour.AFFINE) {
isOwner = workspace.permission === PermissionType.Owner;
} else if (workspace.flavour === RemWorkspaceFlavour.LOCAL) {
} else if (workspace.flavour === WorkspaceFlavour.LOCAL) {
isOwner = true;
}
if (workspace.flavour === RemWorkspaceFlavour.LOCAL) {
if (workspace.flavour === WorkspaceFlavour.LOCAL) {
return (
<p title={t('Local Workspace')}>
<LocalWorkspaceIcon />
@@ -85,19 +85,18 @@ export const WorkspaceCard: React.FC<WorkspaceCardProps> = ({
<StyleWorkspaceInfo>
<StyleWorkspaceTitle>{name}</StyleWorkspaceTitle>
<WorkspaceType workspace={workspace} />
{workspace.flavour === RemWorkspaceFlavour.LOCAL && (
{workspace.flavour === WorkspaceFlavour.LOCAL && (
<p title={t('Available Offline')}>
<LocalDataIcon />
<span>{t('Available Offline')}</span>
</p>
)}
{workspace.flavour === RemWorkspaceFlavour.AFFINE &&
workspace.public && (
<p title={t('Published to Web')}>
<PublishIcon />
<span>{t('Published to Web')}</span>
</p>
)}
{workspace.flavour === WorkspaceFlavour.AFFINE && workspace.public && (
<p title={t('Published to Web')}>
<PublishIcon />
<span>{t('Published to Web')}</span>
</p>
)}
</StyleWorkspaceInfo>
<StyledSettingLink
className="setting-entry"

View File

@@ -5,6 +5,7 @@ import 'fake-indexeddb/auto';
import assert from 'node:assert';
import { WorkspaceFlavour } from '@affine/workspace/type';
import { __unstableSchemas, AffineSchemas } from '@blocksuite/blocks/models';
import type { Page } from '@blocksuite/store';
import { assertExists } from '@blocksuite/store';
@@ -23,7 +24,7 @@ import {
} from '../../atoms';
import { LocalPlugin } from '../../plugins/local';
import type { LocalWorkspace } from '../../shared';
import { BlockSuiteWorkspace, RemWorkspaceFlavour } from '../../shared';
import { BlockSuiteWorkspace } from '../../shared';
import { useIsFirstLoad, useOpenTips } from '../affine/use-is-first-load';
import {
useRecentlyViewed,
@@ -181,7 +182,7 @@ describe('useWorkspaces', () => {
expect(result2.current.length).toEqual(1);
const firstWorkspace = result2.current[0];
expect(firstWorkspace.flavour).toBe('local');
assert(firstWorkspace.flavour === RemWorkspaceFlavour.LOCAL);
assert(firstWorkspace.flavour === WorkspaceFlavour.LOCAL);
expect(firstWorkspace.blockSuiteWorkspace.meta.name).toBe('test');
});
});
@@ -266,12 +267,12 @@ describe('useRecentlyViewed', () => {
store.set(jotaiWorkspacesAtom, [
{
id: workspaceId,
flavour: RemWorkspaceFlavour.LOCAL,
flavour: WorkspaceFlavour.LOCAL,
},
]);
LocalPlugin.CRUD.get = vi.fn().mockResolvedValue({
id: workspaceId,
flavour: RemWorkspaceFlavour.LOCAL,
flavour: WorkspaceFlavour.LOCAL,
blockSuiteWorkspace,
providers: [],
} satisfies LocalWorkspace);

View File

@@ -1,12 +1,12 @@
import { DEFAULT_WORKSPACE_NAME } from '@affine/env';
import { WorkspaceFlavour } from '@affine/workspace/type';
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
import { assertEquals, assertExists, nanoid } from '@blocksuite/store';
import { useAtom } from 'jotai/index';
import { useAtom } from 'jotai';
import { useEffect } from 'react';
import { jotaiWorkspacesAtom } from '../atoms';
import { LocalPlugin } from '../plugins/local';
import { RemWorkspaceFlavour } from '../shared';
import { createEmptyBlockSuiteWorkspace } from '../utils';
export function useCreateFirstWorkspace() {
const [jotaiWorkspaces, set] = useAtom(jotaiWorkspacesAtom);
@@ -29,7 +29,7 @@ export function useCreateFirstWorkspace() {
set([
{
id: workspace.id,
flavour: RemWorkspaceFlavour.LOCAL,
flavour: WorkspaceFlavour.LOCAL,
},
]);
}

View File

@@ -1,9 +1,9 @@
import { WorkspaceFlavour } from '@affine/workspace/type';
import type { NextRouter } from 'next/router';
import { useEffect } from 'react';
import { currentPageIdAtom, jotaiStore } from '../atoms';
import type { RemWorkspace } from '../shared';
import { RemWorkspaceFlavour } from '../shared';
import { useCurrentPageId } from './current/use-current-page-id';
import { useCurrentWorkspace } from './current/use-current-workspace';
import { useWorkspaces } from './use-workspaces';
@@ -13,7 +13,7 @@ export function findSuitablePageId(
targetId: string
): string | null {
switch (workspace.flavour) {
case RemWorkspaceFlavour.AFFINE: {
case WorkspaceFlavour.AFFINE: {
return (
workspace.blockSuiteWorkspace.meta.pageMetas.find(
page => page.id === targetId
@@ -22,7 +22,7 @@ export function findSuitablePageId(
null
);
}
case RemWorkspaceFlavour.LOCAL: {
case WorkspaceFlavour.LOCAL: {
return (
workspace.blockSuiteWorkspace.meta.pageMetas.find(
page => page.id === targetId

View File

@@ -1,9 +1,10 @@
import type { WorkspaceFlavour } from '@affine/workspace/type';
import type { WorkspaceRegistry } from '@affine/workspace/type';
import { useSetAtom } from 'jotai';
import { useCallback } from 'react';
import { jotaiWorkspacesAtom } from '../atoms';
import { WorkspacePlugins } from '../plugins';
import type { FlavourToWorkspace, RemWorkspaceFlavour } from '../shared';
/**
* Transform workspace from one flavour to another
@@ -13,10 +14,10 @@ import type { FlavourToWorkspace, RemWorkspaceFlavour } from '../shared';
export function useTransformWorkspace() {
const set = useSetAtom(jotaiWorkspacesAtom);
return useCallback(
async <From extends RemWorkspaceFlavour, To extends RemWorkspaceFlavour>(
async <From extends WorkspaceFlavour, To extends WorkspaceFlavour>(
from: From,
to: To,
workspace: FlavourToWorkspace[From]
workspace: WorkspaceRegistry[From]
): Promise<string> => {
await WorkspacePlugins[from].CRUD.delete(workspace as any);
const newId = await WorkspacePlugins[to].CRUD.create(

View File

@@ -1,3 +1,5 @@
import { WorkspaceFlavour } from '@affine/workspace/type';
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
import { nanoid } from '@blocksuite/store';
import { useAtomValue, useSetAtom } from 'jotai';
import { useCallback, useEffect } from 'react';
@@ -6,8 +8,6 @@ import { jotaiWorkspacesAtom, workspacesAtom } from '../atoms';
import { WorkspacePlugins } from '../plugins';
import { LocalPlugin } from '../plugins/local';
import type { LocalWorkspace, RemWorkspace } from '../shared';
import { RemWorkspaceFlavour } from '../shared';
import { createEmptyBlockSuiteWorkspace } from '../utils';
export function useWorkspaces(): RemWorkspace[] {
return useAtomValue(workspacesAtom);
@@ -43,7 +43,7 @@ export function useWorkspacesHelper() {
...workspaces,
{
id,
flavour: RemWorkspaceFlavour.LOCAL,
flavour: WorkspaceFlavour.LOCAL,
},
]);
return id;

View File

@@ -1,5 +1,6 @@
import { Button, toast } from '@affine/component';
import { DebugLogger } from '@affine/debug';
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
import { nanoid } from '@blocksuite/store';
import { Typography } from '@mui/material';
import type React from 'react';
@@ -9,7 +10,6 @@ import { createBroadCastChannelProvider } from '../../blocksuite/providers';
import PageList from '../../components/blocksuite/block-suite-page-list/page-list';
import { StyledPage, StyledWrapper } from '../../layouts/styles';
import type { BroadCastChannelProvider } from '../../shared';
import { createEmptyBlockSuiteWorkspace } from '../../utils';
const logger = new DebugLogger('broadcast');

View File

@@ -0,0 +1,78 @@
import { Button, toast } from '@affine/component';
import { currentAffineUserAtom } from '@affine/workspace/affine/atom';
import {
clearLoginStorage,
createAffineAuth,
getLoginStorage,
isExpired,
parseIdToken,
setLoginStorage,
SignMethod,
} from '@affine/workspace/affine/login';
import { useAtom } from 'jotai';
import type { NextPage } from 'next';
import { useMemo } from 'react';
import { StyledPage, StyledWrapper } from '../../layouts/styles';
const LoginDevPage: NextPage = () => {
const [user, setUser] = useAtom(currentAffineUserAtom);
const auth = useMemo(() => createAffineAuth(), []);
return (
<StyledPage>
<StyledWrapper>
<h1>LoginDevPage</h1>
<Button
onClick={async () => {
const storage = getLoginStorage();
if (storage) {
const user = parseIdToken(storage.token);
if (isExpired(user)) {
await auth.refreshToken(storage);
}
}
const response = await auth.generateToken(SignMethod.Google);
if (response) {
setLoginStorage(response);
const user = parseIdToken(response.token);
setUser(user);
} else {
toast('Login failed');
}
}}
>
Login
</Button>
<Button
onClick={async () => {
const storage = getLoginStorage();
if (!storage) {
throw new Error('No storage');
}
const response = await auth.refreshToken(storage);
if (response) {
setLoginStorage(response);
const user = parseIdToken(response.token);
setUser(user);
} else {
toast('Login failed');
}
}}
>
Refresh Token
</Button>
<Button
onClick={() => {
clearLoginStorage();
setUser(null);
}}
>
Reset Storage
</Button>
{user && JSON.stringify(user)}
</StyledWrapper>
</StyledPage>
);
};
export default LoginDevPage;

View File

@@ -1,3 +1,4 @@
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
import { ContentParser } from '@blocksuite/blocks/content-parser';
import type {
GetStaticPaths,
@@ -16,7 +17,6 @@ import {
StyledWrapper,
} from '../../layouts/styles';
import type { BlockSuiteWorkspace } from '../../shared';
import { createEmptyBlockSuiteWorkspace } from '../../utils';
export type PreviewPageProps = {
text: string;

View File

@@ -1,3 +1,4 @@
import { WorkspaceFlavour } from '@affine/workspace/type';
import { useRouter } from 'next/router';
import type React from 'react';
import { useEffect } from 'react';
@@ -11,7 +12,6 @@ import { useSyncRouterWithCurrentWorkspaceAndPage } from '../../../hooks/use-syn
import { WorkspaceLayout } from '../../../layouts';
import { WorkspacePlugins } from '../../../plugins';
import type { BlockSuiteWorkspace, NextPageWithLayout } from '../../../shared';
import { RemWorkspaceFlavour } from '../../../shared';
function enableFullFlags(blockSuiteWorkspace: BlockSuiteWorkspace) {
blockSuiteWorkspace.awarenessStore.setFlag('enable_set_remote_flag', false);
@@ -38,12 +38,12 @@ const WorkspaceDetail: React.FC = () => {
if (!pageId) {
return <PageLoading />;
}
if (currentWorkspace.flavour === RemWorkspaceFlavour.AFFINE) {
if (currentWorkspace.flavour === WorkspaceFlavour.AFFINE) {
const PageDetail = WorkspacePlugins[currentWorkspace.flavour].UI.PageDetail;
return (
<PageDetail currentWorkspace={currentWorkspace} currentPageId={pageId} />
);
} else if (currentWorkspace.flavour === RemWorkspaceFlavour.LOCAL) {
} else if (currentWorkspace.flavour === WorkspaceFlavour.LOCAL) {
const PageDetail = WorkspacePlugins[currentWorkspace.flavour].UI.PageDetail;
return (
<PageDetail currentWorkspace={currentWorkspace} currentPageId={pageId} />

View File

@@ -1,4 +1,5 @@
import { useTranslation } from '@affine/i18n';
import { WorkspaceFlavour } from '@affine/workspace/type';
import { FolderIcon } from '@blocksuite/icons';
import { assertEquals, assertExists, nanoid } from '@blocksuite/store';
import Head from 'next/head';
@@ -20,7 +21,6 @@ import type {
LocalIndexedDBProvider,
NextPageWithLayout,
} from '../../../shared';
import { RemWorkspaceFlavour } from '../../../shared';
const AllPage: NextPageWithLayout = () => {
const router = useRouter();
@@ -78,7 +78,7 @@ const AllPage: NextPageWithLayout = () => {
if (currentWorkspace === null) {
return <PageLoading />;
}
if (currentWorkspace.flavour === RemWorkspaceFlavour.AFFINE) {
if (currentWorkspace.flavour === WorkspaceFlavour.AFFINE) {
const PageList = WorkspacePlugins[currentWorkspace.flavour].UI.PageList;
return (
<>
@@ -92,7 +92,7 @@ const AllPage: NextPageWithLayout = () => {
/>
</>
);
} else if (currentWorkspace.flavour === RemWorkspaceFlavour.LOCAL) {
} else if (currentWorkspace.flavour === WorkspaceFlavour.LOCAL) {
const PageList = WorkspacePlugins[currentWorkspace.flavour].UI.PageList;
return (
<>

View File

@@ -1,4 +1,10 @@
import { useTranslation } from '@affine/i18n';
import type { SettingPanel, WorkspaceRegistry } from '@affine/workspace/type';
import {
settingPanel,
settingPanelValues,
WorkspaceFlavour,
} from '@affine/workspace/type';
import { SettingsIcon } from '@blocksuite/icons';
import { assertExists } from '@blocksuite/store';
import { useAtom } from 'jotai';
@@ -16,16 +22,7 @@ import { useTransformWorkspace } from '../../../hooks/use-transform-workspace';
import { useWorkspacesHelper } from '../../../hooks/use-workspaces';
import { WorkspaceLayout } from '../../../layouts';
import { WorkspacePlugins } from '../../../plugins';
import type {
FlavourToWorkspace,
NextPageWithLayout,
SettingPanel,
} from '../../../shared';
import {
RemWorkspaceFlavour,
settingPanel,
settingPanelValues,
} from '../../../shared';
import type { NextPageWithLayout } from '../../../shared';
import { apis } from '../../../shared/apis';
const settingPanelAtom = atomWithStorage<SettingPanel>(
@@ -105,13 +102,12 @@ const SettingPage: NextPageWithLayout = () => {
}, [currentWorkspace, helper]);
const transformWorkspace = useTransformWorkspace();
const onTransformWorkspace = useCallback(
async <From extends RemWorkspaceFlavour, To extends RemWorkspaceFlavour>(
async <From extends WorkspaceFlavour, To extends WorkspaceFlavour>(
from: From,
to: To,
workspace: FlavourToWorkspace[From]
workspace: WorkspaceRegistry[From]
): Promise<void> => {
const needRefresh =
to === RemWorkspaceFlavour.AFFINE && !apis.auth.isLogin;
const needRefresh = to === WorkspaceFlavour.AFFINE && !apis.auth.isLogin;
if (needRefresh) {
await apis.signInWithGoogle();
}
@@ -135,7 +131,7 @@ const SettingPage: NextPageWithLayout = () => {
return <PageLoading />;
} else if (settingPanelValues.indexOf(currentTab as SettingPanel) === -1) {
return <PageLoading />;
} else if (currentWorkspace.flavour === RemWorkspaceFlavour.AFFINE) {
} else if (currentWorkspace.flavour === WorkspaceFlavour.AFFINE) {
const Setting =
WorkspacePlugins[currentWorkspace.flavour].UI.SettingsDetail;
return (
@@ -155,7 +151,7 @@ const SettingPage: NextPageWithLayout = () => {
/>
</>
);
} else if (currentWorkspace.flavour === RemWorkspaceFlavour.LOCAL) {
} else if (currentWorkspace.flavour === WorkspaceFlavour.LOCAL) {
const Setting =
WorkspacePlugins[currentWorkspace.flavour].UI.SettingsDetail;
return (

View File

@@ -1,12 +1,12 @@
import { WorkspaceFlavour } from '@affine/workspace/type';
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
import { assertExists } from '@blocksuite/store';
import { jotaiStore, workspacesAtom } from '../../atoms';
import { createAffineProviders } from '../../blocksuite';
import { Unreachable } from '../../components/affine/affine-error-eoundary';
import type { AffineWorkspace } from '../../shared';
import { RemWorkspaceFlavour } from '../../shared';
import { apis } from '../../shared/apis';
import { createEmptyBlockSuiteWorkspace } from '../../utils';
type Query = (typeof QueryKey)[keyof typeof QueryKey];
@@ -73,7 +73,7 @@ export const fetcher = async (
);
const remWorkspace: AffineWorkspace = {
...workspace,
flavour: RemWorkspaceFlavour.AFFINE,
flavour: WorkspaceFlavour.AFFINE,
blockSuiteWorkspace,
providers: [...createAffineProviders(blockSuiteWorkspace)],
};

View File

@@ -1,3 +1,5 @@
import { LoadPriority, WorkspaceFlavour } from '@affine/workspace/type';
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
import { createJSONStorage } from 'jotai/utils';
import React from 'react';
import { mutate } from 'swr';
@@ -9,13 +11,8 @@ import { WorkspaceSettingDetail } from '../../components/affine/workspace-settin
import { BlockSuitePageList } from '../../components/blocksuite/block-suite-page-list';
import { PageDetailEditor } from '../../components/page-detail-editor';
import type { AffineWorkspace } from '../../shared';
import {
BlockSuiteWorkspace,
LoadPriority,
RemWorkspaceFlavour,
} from '../../shared';
import { BlockSuiteWorkspace } from '../../shared';
import { apis, clientAuth } from '../../shared/apis';
import { createEmptyBlockSuiteWorkspace } from '../../utils';
import { initPage } from '../../utils/blocksuite';
import type { WorkspacePlugin } from '..';
import { QueryKey } from './fetcher';
@@ -46,7 +43,7 @@ const getPersistenceAllWorkspace = () => {
);
const affineWorkspace: AffineWorkspace = {
...item,
flavour: RemWorkspaceFlavour.AFFINE,
flavour: WorkspaceFlavour.AFFINE,
blockSuiteWorkspace,
providers: [...createAffineProviders(blockSuiteWorkspace)],
};
@@ -57,8 +54,8 @@ const getPersistenceAllWorkspace = () => {
return allWorkspaces;
};
export const AffinePlugin: WorkspacePlugin<RemWorkspaceFlavour.AFFINE> = {
flavour: RemWorkspaceFlavour.AFFINE,
export const AffinePlugin: WorkspacePlugin<WorkspaceFlavour.AFFINE> = {
flavour: WorkspaceFlavour.AFFINE,
loadPriority: LoadPriority.HIGH,
cleanup: () => {
storage.removeItem(kAffineLocal);
@@ -167,7 +164,7 @@ export const AffinePlugin: WorkspacePlugin<RemWorkspaceFlavour.AFFINE> = {
const affineWorkspace: AffineWorkspace = {
...workspace,
flavour: RemWorkspaceFlavour.AFFINE,
flavour: WorkspaceFlavour.AFFINE,
blockSuiteWorkspace,
providers: [...createAffineProviders(blockSuiteWorkspace)],
};

View File

@@ -1,74 +1,35 @@
import type React from 'react';
import type {
BlockSuiteWorkspace,
FlavourToWorkspace,
LoadPriority,
SettingPanel,
} from '../shared';
import { RemWorkspaceFlavour } from '../shared';
WorkspaceCRUD,
WorkspaceUISchema,
} from '@affine/workspace/type';
import { WorkspaceFlavour } from '@affine/workspace/type';
import type { AffineWorkspace, LocalWorkspace } from '../shared';
import { AffinePlugin } from './affine';
import { LocalPlugin } from './local';
type UIBaseProps<Flavour extends RemWorkspaceFlavour> = {
currentWorkspace: FlavourToWorkspace[Flavour];
};
declare module '@affine/workspace/type' {
interface WorkspaceRegistry {
[WorkspaceFlavour.AFFINE]: AffineWorkspace;
[WorkspaceFlavour.LOCAL]: LocalWorkspace;
}
}
type SettingProps<Flavour extends RemWorkspaceFlavour> =
UIBaseProps<Flavour> & {
currentTab: SettingPanel;
onChangeTab: (tab: SettingPanel) => void;
onDeleteWorkspace: () => void;
onTransformWorkspace: <
From extends RemWorkspaceFlavour,
To extends RemWorkspaceFlavour
>(
from: From,
to: To,
workspace: FlavourToWorkspace[From]
) => void;
};
type PageDetailProps<Flavour extends RemWorkspaceFlavour> =
UIBaseProps<Flavour> & {
currentPageId: string;
};
type PageListProps<Flavour extends RemWorkspaceFlavour> = {
blockSuiteWorkspace: BlockSuiteWorkspace;
onOpenPage: (pageId: string, newTab?: boolean) => void;
};
type SideBarMenuProps<Flavour extends RemWorkspaceFlavour> =
UIBaseProps<Flavour> & {
setSideBarOpen: (open: boolean) => void;
};
export interface WorkspacePlugin<Flavour extends RemWorkspaceFlavour> {
export interface WorkspacePlugin<Flavour extends WorkspaceFlavour> {
flavour: Flavour;
// Plugin will be loaded according to the priority
loadPriority: LoadPriority;
// fixme: this is a hack
cleanup?: () => void;
// Fetch necessary data for the first render
CRUD: {
create: (blockSuiteWorkspace: BlockSuiteWorkspace) => Promise<string>;
delete: (workspace: FlavourToWorkspace[Flavour]) => Promise<void>;
get: (workspaceId: string) => Promise<FlavourToWorkspace[Flavour] | null>;
// not supported yet
// update: (workspace: FlavourToWorkspace[Flavour]) => Promise<void>;
list: () => Promise<FlavourToWorkspace[Flavour][]>;
};
UI: {
PageDetail: React.FC<PageDetailProps<Flavour>>;
PageList: React.FC<PageListProps<Flavour>>;
SettingsDetail: React.FC<SettingProps<Flavour>>;
};
CRUD: WorkspaceCRUD<Flavour>;
UI: WorkspaceUISchema<Flavour>;
}
export const WorkspacePlugins = {
[RemWorkspaceFlavour.AFFINE]: AffinePlugin,
[RemWorkspaceFlavour.LOCAL]: LocalPlugin,
[WorkspaceFlavour.AFFINE]: AffinePlugin,
[WorkspaceFlavour.LOCAL]: LocalPlugin,
} satisfies {
[Key in RemWorkspaceFlavour]: WorkspacePlugin<Key>;
[Key in WorkspaceFlavour]: WorkspacePlugin<Key>;
};

View File

@@ -1,4 +1,6 @@
import { DEFAULT_WORKSPACE_NAME } from '@affine/env';
import { LoadPriority, WorkspaceFlavour } from '@affine/workspace/type';
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
import { nanoid } from '@blocksuite/store';
import { createJSONStorage } from 'jotai/utils';
import React from 'react';
@@ -11,12 +13,7 @@ import { WorkspaceSettingDetail } from '../../components/affine/workspace-settin
import { BlockSuitePageList } from '../../components/blocksuite/block-suite-page-list';
import { PageDetailEditor } from '../../components/page-detail-editor';
import type { LocalWorkspace } from '../../shared';
import {
BlockSuiteWorkspace,
LoadPriority,
RemWorkspaceFlavour,
} from '../../shared';
import { createEmptyBlockSuiteWorkspace } from '../../utils';
import { BlockSuiteWorkspace } from '../../shared';
import { initPage } from '../../utils/blocksuite';
import type { WorkspacePlugin } from '..';
@@ -25,8 +22,8 @@ const getStorage = () => createJSONStorage(() => localStorage);
export const kStoreKey = 'affine-local-workspace';
const schema = z.array(z.string());
export const LocalPlugin: WorkspacePlugin<RemWorkspaceFlavour.LOCAL> = {
flavour: RemWorkspaceFlavour.LOCAL,
export const LocalPlugin: WorkspacePlugin<WorkspaceFlavour.LOCAL> = {
flavour: WorkspaceFlavour.LOCAL,
loadPriority: LoadPriority.LOW,
CRUD: {
get: async workspaceId => {
@@ -44,7 +41,7 @@ export const LocalPlugin: WorkspacePlugin<RemWorkspaceFlavour.LOCAL> = {
);
const workspace: LocalWorkspace = {
id,
flavour: RemWorkspaceFlavour.LOCAL,
flavour: WorkspaceFlavour.LOCAL,
blockSuiteWorkspace: blockSuiteWorkspace,
providers: [...createLocalProviders(blockSuiteWorkspace)],
};

View File

@@ -12,7 +12,7 @@ let prefixUrl = '/';
if (typeof window === 'undefined') {
// SSR
const serverAPI = config.serverAPI;
if (isValidIPAddress(serverAPI)) {
if (isValidIPAddress(serverAPI.split(':')[0])) {
// This is for Server side rendering support
prefixUrl = new URL('http://' + config.serverAPI + '/').origin;
} else {

View File

@@ -1,4 +1,5 @@
import type { Workspace as RemoteWorkspace } from '@affine/datacenter';
import type { WorkspaceFlavour } from '@affine/workspace/type';
import { Workspace as BlockSuiteWorkspace } from '@blocksuite/store';
import type { NextPage } from 'next';
import type { ReactElement, ReactNode } from 'react';
@@ -11,25 +12,15 @@ declare global {
}
}
export const enum RemWorkspaceFlavour {
AFFINE = 'affine',
LOCAL = 'local',
}
export interface FlavourToWorkspace {
[RemWorkspaceFlavour.AFFINE]: AffineWorkspace;
[RemWorkspaceFlavour.LOCAL]: LocalWorkspace;
}
export interface AffineWorkspace extends RemoteWorkspace {
flavour: RemWorkspaceFlavour.AFFINE;
flavour: WorkspaceFlavour.AFFINE;
// empty
blockSuiteWorkspace: BlockSuiteWorkspace;
providers: Provider[];
}
export interface LocalWorkspace {
flavour: RemWorkspaceFlavour.LOCAL;
flavour: WorkspaceFlavour.LOCAL;
id: string;
blockSuiteWorkspace: BlockSuiteWorkspace;
providers: Provider[];
@@ -89,16 +80,6 @@ export const enum WorkspaceSubPath {
TRASH = 'trash',
}
export const settingPanel = {
General: 'general',
Collaboration: 'collaboration',
Publish: 'publish',
Export: 'export',
Sync: 'sync',
} as const;
export const settingPanelValues = [...Object.values(settingPanel)] as const;
export type SettingPanel = (typeof settingPanel)[keyof typeof settingPanel];
export const WorkspaceSubPathName = {
[WorkspaceSubPath.ALL]: 'All Pages',
[WorkspaceSubPath.FAVORITE]: 'Favorites',
@@ -125,9 +106,3 @@ export const publicPathGenerator = {
} satisfies {
[Path in WorkspaceSubPath]: (workspaceId: string) => string;
};
export const enum LoadPriority {
HIGH = 1,
MEDIUM = 2,
LOW = 3,
}

View File

@@ -1,8 +1,3 @@
import { __unstableSchemas, AffineSchemas } from '@blocksuite/blocks/models';
import type { BlobOptionsGetter, Generator } from '@blocksuite/store';
import { BlockSuiteWorkspace } from '../shared';
export function stringToColour(str: string) {
str = str || 'affine';
let colour = '#';
@@ -23,24 +18,3 @@ export function stringToColour(str: string) {
return colour;
}
const hashMap = new Map<string, BlockSuiteWorkspace>();
export const createEmptyBlockSuiteWorkspace = (
id: string,
blobOptionsGetter?: BlobOptionsGetter,
idGenerator?: Generator
): BlockSuiteWorkspace => {
if (hashMap.has(id)) {
return hashMap.get(id) as BlockSuiteWorkspace;
}
const workspace = new BlockSuiteWorkspace({
id,
isSSR: typeof window === 'undefined',
blobOptionsGetter,
idGenerator,
})
.register(AffineSchemas)
.register(__unstableSchemas);
hashMap.set(id, workspace);
return workspace;
};