feat!: upgrade blocksuite version (#2833)

This commit is contained in:
Alex Yang
2023-06-25 01:16:46 +08:00
committed by GitHub
parent aa86d3a2ee
commit 7fcc5e599e
59 changed files with 564 additions and 1064 deletions

View File

@@ -2,7 +2,6 @@ import { Unreachable } from '@affine/env/constant';
import type { AffineLegacyCloudWorkspace } from '@affine/env/workspace';
import { WorkspaceFlavour } from '@affine/env/workspace';
import { affineApis } from '@affine/workspace/affine/shared';
import { createAffineProviders } from '@affine/workspace/providers';
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
import { assertExists } from '@blocksuite/store';
import { rootStore } from '@toeverything/plugin-infra/manager';
@@ -74,7 +73,6 @@ export const fetcher = async (
...workspace,
flavour: WorkspaceFlavour.AFFINE,
blockSuiteWorkspace,
providers: [...createAffineProviders(blockSuiteWorkspace)],
};
return remWorkspace;
});

View File

@@ -5,7 +5,11 @@
import { AFFINE_STORAGE_KEY, config } from '@affine/env';
import { initEmptyPage } from '@affine/env/blocksuite';
import { PageNotFoundError } from '@affine/env/constant';
import type { AffineLegacyCloudWorkspace } from '@affine/env/workspace';
import type {
AffineDownloadProvider,
AffineLegacyCloudWorkspace,
LocalIndexedDBDownloadProvider,
} from '@affine/env/workspace';
import {
LoadPriority,
ReleaseType,
@@ -22,10 +26,7 @@ import {
} from '@affine/workspace/affine/login';
import { affineApis, affineAuth } from '@affine/workspace/affine/shared';
import { rootWorkspacesMetadataAtom } from '@affine/workspace/atom';
import {
createAffineProviders,
createIndexedDBBackgroundProvider,
} from '@affine/workspace/providers';
import { createIndexedDBDownloadProvider } from '@affine/workspace/providers';
import { createAffineDownloadProvider } from '@affine/workspace/providers';
import {
cleanupWorkspace,
@@ -80,7 +81,6 @@ const getPersistenceAllWorkspace = () => {
...item,
flavour: WorkspaceFlavour.AFFINE,
blockSuiteWorkspace,
providers: [...createAffineProviders(blockSuiteWorkspace)],
};
return affineWorkspace;
})
@@ -165,19 +165,19 @@ export const AffineAdapter: WorkspaceAdapter<WorkspaceFlavour.AFFINE> = {
// fixme:
// force to download workspace binary
// to make sure the workspace is synced
const provider = createAffineDownloadProvider(bs);
const indexedDBProvider = createIndexedDBBackgroundProvider(bs);
await new Promise<void>(resolve => {
indexedDBProvider.callbacks.add(() => {
resolve();
});
provider.callbacks.add(() => {
indexedDBProvider.connect();
});
provider.connect();
});
const provider = createAffineDownloadProvider(bs.id, bs.doc, {
awareness: bs.awarenessStore.awareness,
}) as AffineDownloadProvider;
const indexedDBProvider = createIndexedDBDownloadProvider(
bs.id,
bs.doc,
{
awareness: bs.awarenessStore.awareness,
}
) as LocalIndexedDBDownloadProvider;
indexedDBProvider.sync();
await indexedDBProvider.whenReady;
provider.disconnect();
indexedDBProvider.disconnect();
}
await mutate(matcher => matcher === QueryKey.getWorkspaces);
@@ -280,7 +280,6 @@ export const AffineAdapter: WorkspaceAdapter<WorkspaceFlavour.AFFINE> = {
...workspace,
flavour: WorkspaceFlavour.AFFINE,
blockSuiteWorkspace,
providers: [...createAffineProviders(blockSuiteWorkspace)],
};
return affineWorkspace;
});

View File

@@ -6,6 +6,7 @@ import {
} from '@affine/env';
import { initEmptyPage, initPageWithPreloading } from '@affine/env/blocksuite';
import { PageNotFoundError } from '@affine/env/constant';
import type { LocalIndexedDBDownloadProvider } from '@affine/env/workspace';
import {
LoadPriority,
ReleaseType,
@@ -15,7 +16,7 @@ import {
CRUD,
saveWorkspaceToLocalStorage,
} from '@affine/workspace/local/crud';
import { createIndexedDBBackgroundProvider } from '@affine/workspace/providers';
import { createIndexedDBDownloadProvider } from '@affine/workspace/providers';
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
import { nanoid } from '@blocksuite/store';
@@ -49,16 +50,22 @@ export const LocalAdapter: WorkspaceAdapter<WorkspaceFlavour.LOCAL> = {
logger.error('init page with preloading failed', err);
});
} else {
initEmptyPage(page);
initEmptyPage(page).catch(error => {
logger.error('init page with empty failed', error);
});
}
blockSuiteWorkspace.setPageMeta(page.id, {
jumpOnce: true,
});
const provider = createIndexedDBBackgroundProvider(blockSuiteWorkspace);
provider.connect();
provider.callbacks.add(() => {
provider.disconnect();
});
const provider = createIndexedDBDownloadProvider(
blockSuiteWorkspace.id,
blockSuiteWorkspace.doc,
{
awareness: blockSuiteWorkspace.awarenessStore.awareness,
}
) as LocalIndexedDBDownloadProvider;
provider.sync();
provider.whenReady.catch(console.error);
saveWorkspaceToLocalStorage(blockSuiteWorkspace.id);
logger.debug('create first workspace');
return [blockSuiteWorkspace.id];

View File

@@ -4,12 +4,13 @@
import 'fake-indexeddb/auto';
import { initEmptyPage } from '@affine/env/blocksuite';
import type { LocalIndexedDBBackgroundProvider } from '@affine/env/workspace';
import { WorkspaceFlavour } from '@affine/env/workspace';
import {
rootCurrentWorkspaceIdAtom,
rootWorkspacesMetadataAtom,
} from '@affine/workspace/atom';
import { createIndexedDBDownloadProvider } from '@affine/workspace/providers';
import { createIndexedDBBackgroundProvider } from '@affine/workspace/providers';
import {
_cleanupBlockSuiteWorkspaceCache,
createEmptyBlockSuiteWorkspace,
@@ -69,9 +70,8 @@ describe('currentWorkspace atom', () => {
WorkspaceFlavour.LOCAL
);
const page = workspace.createPage({ id: 'page0' });
initEmptyPage(page);
const frameId = page.getBlockByFlavour('affine:frame').at(0)
?.id as string;
await initEmptyPage(page);
const frameId = page.getBlockByFlavour('affine:note').at(0)?.id as string;
id = page.addBlock(
'affine:paragraph',
{
@@ -79,9 +79,16 @@ describe('currentWorkspace atom', () => {
},
frameId
);
const provider = createIndexedDBDownloadProvider(workspace);
provider.sync();
await provider.whenReady;
const provider = createIndexedDBBackgroundProvider(
workspace.id,
workspace.doc,
{
awareness: workspace.awarenessStore.awareness,
}
) as LocalIndexedDBBackgroundProvider;
provider.connect();
await new Promise(resolve => setTimeout(resolve, 1000));
provider.disconnect();
const workspaceId = await WorkspaceAdapters[
WorkspaceFlavour.LOCAL
].CRUD.create(workspace);
@@ -100,6 +107,7 @@ describe('currentWorkspace atom', () => {
const workspace = await store.get(rootCurrentWorkspaceAtom);
expect(workspace).toBeDefined();
const page = workspace.blockSuiteWorkspace.getPage('page0') as Page;
await page.waitForLoaded();
expect(page).not.toBeNull();
const paragraphBlock = page.getBlockById(id) as ParagraphBlockModel;
expect(paragraphBlock).not.toBeNull();

View File

@@ -38,8 +38,6 @@ function createPublicWorkspace(
flavour: WorkspaceFlavour.PUBLIC,
id: workspaceId,
blockSuiteWorkspace,
// maybe we can add some sync providers here
providers: [],
};
}

View File

@@ -1,15 +1,13 @@
//#region async atoms that to load the real workspace data
import { DebugLogger } from '@affine/debug';
import { config } from '@affine/env';
import type {
NecessaryProvider,
WorkspaceRegistry,
} from '@affine/env/workspace';
import type { WorkspaceRegistry } from '@affine/env/workspace';
import { WorkspaceFlavour } from '@affine/env/workspace';
import {
rootCurrentWorkspaceIdAtom,
rootWorkspacesMetadataAtom,
} from '@affine/workspace/atom';
import type { ActiveDocProvider } from '@blocksuite/store';
import { assertExists } from '@blocksuite/store';
import { atom } from 'jotai';
@@ -57,9 +55,9 @@ export const workspacesAtom = atom<Promise<AllWorkspace[]>>(async get => {
)
);
const workspaceProviders = workspaces.map(workspace =>
workspace.providers.filter(
(provider): provider is NecessaryProvider =>
'necessary' in provider && provider.necessary
workspace.blockSuiteWorkspace.providers.filter(
(provider): provider is ActiveDocProvider =>
'active' in provider && provider.active
)
);
const promises: Promise<void>[] = [];
@@ -102,9 +100,10 @@ export const rootCurrentWorkspaceAtom = atom<Promise<AllWorkspace>>(
`cannot find the workspace with id ${targetId} in the plugin ${targetWorkspace.flavour}.`
);
}
const providers = workspace.providers.filter(
(provider): provider is NecessaryProvider =>
'necessary' in provider && provider.necessary === true
const providers = workspace.blockSuiteWorkspace.providers.filter(
(provider): provider is ActiveDocProvider =>
'active' in provider && provider.active === true
);
for (const provider of providers) {
provider.sync();

View File

@@ -37,11 +37,11 @@ export const Footer: React.FC<FooterProps> = ({
return (
<Command.Item
data-testid="quick-search-add-new-page"
onSelect={useCallback(() => {
onSelect={useCallback(async () => {
const id = nanoid();
const page = createPage(id);
assertEquals(page.id, id);
initEmptyPage(page);
await initEmptyPage(page);
const block = page.getBlockByFlavour(
'affine:page'
)[0] as PageBlockModel;

View File

@@ -39,9 +39,10 @@ export const Results: FC<ResultsProps> = ({
const recentPageSetting = useAtomValue(recentPageSettingsAtom);
const t = useAFFiNEI18N();
const { jumpToPage } = useRouterHelper(router);
const results = blockSuiteWorkspace.search(query);
const results = blockSuiteWorkspace.search({ query });
const pageIds = [...results.values()];
// remove `space:` prefix
const pageIds = [...results.values()].map(id => id.slice(6));
const resultsPageMeta = pageList.filter(
page => pageIds.indexOf(page.id) > -1 && !page.trash

View File

@@ -70,22 +70,23 @@ beforeEach(async () => {
blockSuiteWorkspace = new BlockSuiteWorkspace({ id: 'test' })
.register(AffineSchemas)
.register(__unstableSchemas);
const initPage = (page: Page) => {
const initPage = async (page: Page) => {
await page.waitForLoaded()
expect(page).not.toBeNull();
assertExists(page);
const pageBlockId = page.addBlock('affine:page', {
title: new page.Text(''),
});
const frameId = page.addBlock('affine:frame', {}, pageBlockId);
const frameId = page.addBlock('affine:note', {}, pageBlockId);
page.addBlock('affine:paragraph', {}, frameId);
};
initPage(
await initPage(
blockSuiteWorkspace.createPage({
id: 'page0',
})
);
initPage(blockSuiteWorkspace.createPage({ id: 'page1' }));
initPage(blockSuiteWorkspace.createPage({ id: 'page2' }));
await initPage(blockSuiteWorkspace.createPage({ id: 'page1' }));
await initPage(blockSuiteWorkspace.createPage({ id: 'page2' }));
});
describe('usePageMetas', async () => {

View File

@@ -11,8 +11,7 @@ export function useBlockSuiteMetaHelper(
blockSuiteWorkspace: BlockSuiteWorkspace
) {
const { setPageMeta, getPageMeta } = usePageMetaHelper(blockSuiteWorkspace);
const { addReferenceLink, removeReferenceLink } =
useReferenceLinkHelper(blockSuiteWorkspace);
const { addReferenceLink } = useReferenceLinkHelper(blockSuiteWorkspace);
const metas = useBlockSuitePageMeta(blockSuiteWorkspace);
const addToFavorite = useCallback(
@@ -57,13 +56,8 @@ export function useBlockSuiteMetaHelper(
trashDate: +new Date(),
trashRelate: isRoot ? parentMeta?.id : undefined,
});
// Just the trash root need delete its id from parent
if (parentMeta && isRoot) {
removeReferenceLink(pageId);
}
},
[getPageMeta, metas, removeReferenceLink, setPageMeta]
[getPageMeta, metas, setPageMeta]
);
const restoreFromTrash = useCallback(

View File

@@ -22,24 +22,14 @@ export function useReferenceLinkHelper(
},
},
]);
const [frame] = page.getBlockByFlavour('affine:frame');
const [frame] = page.getBlockByFlavour('affine:note');
frame && page.addBlock('affine:paragraph', { text }, frame.id);
},
[blockSuiteWorkspace]
);
const removeReferenceLink = useCallback(
(deleteId: string) => {
blockSuiteWorkspace.indexer.backlink.removeSubpageNode(
blockSuiteWorkspace,
deleteId
);
},
[blockSuiteWorkspace]
);
return {
addReferenceLink,
removeReferenceLink,
};
}

View File

@@ -1,5 +1,4 @@
import { DebugLogger } from '@affine/debug';
import type { LocalWorkspace } from '@affine/env/workspace';
import { WorkspaceFlavour } from '@affine/env/workspace';
import { rootWorkspacesMetadataAtom } from '@affine/workspace/atom';
import { saveWorkspaceToLocalStorage } from '@affine/workspace/local/crud';
@@ -27,19 +26,6 @@ export function useAppHelper() {
const jotaiWorkspaces = useAtomValue(rootWorkspacesMetadataAtom);
const set = useSetAtom(rootWorkspacesMetadataAtom);
return {
createWorkspacePage: useCallback(
(workspaceId: string, pageId: string) => {
const workspace = workspaces.find(
ws => ws.id === workspaceId
) as LocalWorkspace;
if (workspace && 'blockSuiteWorkspace' in workspace) {
workspace.blockSuiteWorkspace.createPage({ id: pageId });
} else {
throw new Error('cannot create page. blockSuiteWorkspace not found');
}
},
[workspaces]
),
addLocalWorkspace: useCallback(
async (workspaceId: string): Promise<string> => {
saveWorkspaceToLocalStorage(workspaceId);

View File

@@ -11,7 +11,6 @@ import {
import { DebugLogger } from '@affine/debug';
import { config, DEFAULT_HELLO_WORLD_PAGE_ID, env } from '@affine/env';
import { initEmptyPage, initPageWithPreloading } from '@affine/env/blocksuite';
import type { BackgroundProvider } from '@affine/env/workspace';
import { WorkspaceFlavour } from '@affine/env/workspace';
import { setUpLanguage, useI18N } from '@affine/i18n';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
@@ -21,6 +20,7 @@ import {
rootCurrentWorkspaceIdAtom,
rootWorkspacesMetadataAtom,
} from '@affine/workspace/atom';
import type { PassiveDocProvider } from '@blocksuite/store';
import { assertEquals, assertExists, nanoid } from '@blocksuite/store';
import type { DragEndEvent } from '@dnd-kit/core';
import {
@@ -164,9 +164,9 @@ export const AllWorkspaceContext = ({
// ignore current workspace
.filter(workspace => workspace.id !== currentWorkspaceId)
.flatMap(workspace =>
workspace.providers.filter(
(provider): provider is BackgroundProvider =>
'background' in provider && provider.background
workspace.blockSuiteWorkspace.providers.filter(
(provider): provider is PassiveDocProvider =>
'passive' in provider && provider.passive
)
);
providers.forEach(provider => {
@@ -333,6 +333,9 @@ export const WorkspaceLayoutInner: FC<PropsWithChildren> = ({ children }) => {
const router = useRouter();
const { jumpToPage } = useRouterHelper(router);
// fixme(himself65):
// we should move the page into jotai atom since it's an async value
//#region init workspace
if (currentWorkspace.blockSuiteWorkspace.isEmpty) {
// this is a new workspace, so we should redirect to the new page
@@ -346,7 +349,9 @@ export const WorkspaceLayoutInner: FC<PropsWithChildren> = ({ children }) => {
console.error('import error:', error);
});
} else {
initEmptyPage(page);
initEmptyPage(page).catch(error => {
console.error('init empty page error', error);
});
}
if (!router.query.pageId) {
setCurrentPageId(pageId);
@@ -358,9 +363,11 @@ export const WorkspaceLayoutInner: FC<PropsWithChildren> = ({ children }) => {
//#endregion
useEffect(() => {
const backgroundProviders = currentWorkspace.providers.filter(
(provider): provider is BackgroundProvider => 'background' in provider
);
const backgroundProviders =
currentWorkspace.blockSuiteWorkspace.providers.filter(
(provider): provider is PassiveDocProvider =>
'passive' in provider && provider.passive
);
backgroundProviders.forEach(provider => {
provider.connect();
});

View File

@@ -1,73 +0,0 @@
import { Button } from '@affine/component';
import { MainContainer } from '@affine/component/workspace';
import { DebugLogger } from '@affine/debug';
import type { BroadCastChannelProvider } from '@affine/env/workspace';
import { WorkspaceFlavour } from '@affine/env/workspace';
import { createBroadCastChannelProvider } from '@affine/workspace/providers';
import { createEmptyBlockSuiteWorkspace } from '@affine/workspace/utils';
import { nanoid } from '@blocksuite/store';
import { Typography } from '@mui/material';
import type React from 'react';
import { useEffect, useMemo, useState } from 'react';
import { AppContainer } from '../../components/affine/app-container';
import { BlockSuitePageList } from '../../components/blocksuite/block-suite-page-list';
import { toast } from '../../utils';
const logger = new DebugLogger('broadcast');
declare global {
// eslint-disable-next-line no-var
var currentBroadCastChannel: BroadCastChannelProvider | undefined;
}
const BroadcastPage: React.FC = () => {
const blockSuiteWorkspace = useMemo(
() =>
createEmptyBlockSuiteWorkspace('broadcast-test', WorkspaceFlavour.LOCAL),
[]
);
const [provider, setProvider] = useState<BroadCastChannelProvider | null>(
null
);
useEffect(() => {
const provider = createBroadCastChannelProvider(blockSuiteWorkspace);
setProvider(provider);
globalThis.currentBroadCastChannel = provider;
provider.connect();
return () => {
provider.disconnect();
globalThis.currentBroadCastChannel = undefined;
setProvider(null);
};
}, [blockSuiteWorkspace]);
if (!provider) {
return null;
}
return (
<AppContainer>
<MainContainer>
<Typography variant="h5">Broadcast Provider Test</Typography>
<Button
type="primary"
data-testid="create-page"
onClick={() => {
logger.info('create page');
blockSuiteWorkspace.createPage({ id: nanoid() });
}}
>
Create Page
</Button>
<BlockSuitePageList
blockSuiteWorkspace={blockSuiteWorkspace}
listType="all"
onOpenPage={() => {
toast('do nothing');
}}
/>
</MainContainer>
</AppContainer>
);
};
export default BroadcastPage;