feat(editor): use store extension manager (#11891)

Closes: BS-3284
This commit is contained in:
Saul-Mirone
2025-04-22 15:51:22 +00:00
parent 99ad4e871e
commit 43966a6c6b
25 changed files with 160 additions and 54 deletions

View File

@@ -1,5 +1,4 @@
import { defaultImageProxyMiddleware } from '@blocksuite/affine-block-image';
import { SpecProvider } from '@blocksuite/affine-shared/utils';
import {
Schema,
Transformer,
@@ -8,6 +7,7 @@ import {
import { TestWorkspace } from '@blocksuite/store/test';
import { AffineSchemas } from '../../schemas.js';
import { testStoreExtensions } from './store.js';
declare global {
interface Window {
@@ -27,7 +27,7 @@ export function createJob(middlewares?: TransformerMiddleware[]) {
testMiddlewares.push(defaultImageProxyMiddleware);
const schema = new Schema().register(AffineSchemas);
const docCollection = new TestWorkspace();
docCollection.storeExtensions = SpecProvider._.getSpec('store').value;
docCollection.storeExtensions = testStoreExtensions;
docCollection.meta.initialize();
return new Transformer({
schema,

View File

@@ -1,17 +1,17 @@
import { SpecProvider } from '@blocksuite/affine-shared/utils';
import { Container } from '@blocksuite/global/di';
import {
registerBlockSpecs,
registerStoreSpecs,
} from '../../extensions/register';
import { testStoreExtensions } from './store';
registerStoreSpecs();
registerBlockSpecs();
export function getProvider() {
const container = new Container();
const exts = SpecProvider._.getSpec('store').value;
const exts = testStoreExtensions;
exts.forEach(ext => {
ext.setup(container);
});

View File

@@ -0,0 +1,40 @@
import { AttachmentStoreExtension } from '@blocksuite/affine-block-attachment/store';
import { BookmarkStoreExtension } from '@blocksuite/affine-block-bookmark/store';
import { CalloutStoreExtension } from '@blocksuite/affine-block-callout/store';
import { CodeStoreExtension } from '@blocksuite/affine-block-code/store';
import { DataViewStoreExtension } from '@blocksuite/affine-block-data-view/store';
import { DatabaseStoreExtension } from '@blocksuite/affine-block-database/store';
import { DividerStoreExtension } from '@blocksuite/affine-block-divider/store';
import { EdgelessTextStoreExtension } from '@blocksuite/affine-block-edgeless-text/store';
import { EmbedStoreExtension } from '@blocksuite/affine-block-embed/store';
import { FrameStoreExtension } from '@blocksuite/affine-block-frame/store';
import { ImageStoreExtension } from '@blocksuite/affine-block-image/store';
import { LatexStoreExtension } from '@blocksuite/affine-block-latex/store';
import { ListStoreExtension } from '@blocksuite/affine-block-list/store';
import { NoteStoreExtension } from '@blocksuite/affine-block-note/store';
import { ParagraphStoreExtension } from '@blocksuite/affine-block-paragraph/store';
import { StoreExtensionManager } from '@blocksuite/affine-ext-loader';
import { MigratingStoreExtension } from '../../extensions/store';
const manager = new StoreExtensionManager([
AttachmentStoreExtension,
BookmarkStoreExtension,
CalloutStoreExtension,
CodeStoreExtension,
DataViewStoreExtension,
DatabaseStoreExtension,
DividerStoreExtension,
EdgelessTextStoreExtension,
EmbedStoreExtension,
FrameStoreExtension,
ImageStoreExtension,
LatexStoreExtension,
ListStoreExtension,
NoteStoreExtension,
ParagraphStoreExtension,
MigratingStoreExtension,
]);
export const testStoreExtensions = manager.get('store');

View File

@@ -10,7 +10,7 @@ import {
} from '@blocksuite/affine-block-root';
import { SurfaceBlockSchemaExtension } from '@blocksuite/affine-block-surface';
import {
TableBlockHtmlAdapterExtension,
TableBlockAdapterExtensions,
TableSelectionExtension,
} from '@blocksuite/affine-block-table';
import {
@@ -66,10 +66,7 @@ function getAdapterFactoryExtensions(): ExtensionType[] {
];
}
const defaultBlockHtmlAdapterMatchers = [
RootBlockHtmlAdapterExtension,
TableBlockHtmlAdapterExtension,
];
const defaultBlockHtmlAdapterMatchers = [RootBlockHtmlAdapterExtension];
const defaultBlockMarkdownAdapterMatchers = [RootBlockMarkdownAdapterExtension];
@@ -130,6 +127,7 @@ const MigratingStoreExtensions: ExtensionType[] = [
DatabaseSelectionExtension,
TableSelectionExtension,
TableBlockAdapterExtensions,
getHtmlAdapterExtensions(),
getMarkdownAdapterExtensions(),
getNotionHtmlAdapterExtensions(),

View File

@@ -1,3 +1,4 @@
export * from './extension';
export * from './html';
export * from './markdown';
export * from './notion-html';

View File

@@ -12,6 +12,7 @@
"dependencies": {
"@blocksuite/affine-block-image": "workspace:*",
"@blocksuite/affine-components": "workspace:*",
"@blocksuite/affine-ext-loader": "workspace:*",
"@blocksuite/affine-inline-reference": "workspace:*",
"@blocksuite/affine-model": "workspace:*",
"@blocksuite/affine-rich-text": "workspace:*",

View File

@@ -5,6 +5,7 @@ import {
NewDocIcon,
} from '@blocksuite/affine-components/icons';
import { toast } from '@blocksuite/affine-components/toast';
import { StoreExtensionManagerIdentifier } from '@blocksuite/affine-ext-loader';
import { insertLinkedNode } from '@blocksuite/affine-inline-reference';
import {
DocModeProvider,
@@ -235,9 +236,13 @@ export function createNewDocMenuGroup(
const onFail = (message: string) => {
toast(editorHost, message);
};
const storeManager = editorHost.std.get(
StoreExtensionManagerIdentifier
);
showImportModal({
collection: doc.workspace,
schema: doc.schema,
extensions: storeManager.get('store'),
onSuccess,
onFail,
});

View File

@@ -8,7 +8,7 @@ import {
} from '@blocksuite/affine-components/icons';
import { openFileOrFiles } from '@blocksuite/affine-shared/utils';
import { WithDisposable } from '@blocksuite/global/lit';
import type { Schema, Workspace } from '@blocksuite/store';
import type { ExtensionType, Schema, Workspace } from '@blocksuite/store';
import { html, LitElement, type PropertyValues } from 'lit';
import { query, state } from 'lit/decorators.js';
@@ -32,6 +32,7 @@ export class ImportDoc extends WithDisposable(LitElement) {
constructor(
private readonly collection: Workspace,
private readonly schema: Schema,
private readonly extensions: ExtensionType[],
private readonly onSuccess?: OnSuccessHandler,
private readonly onFail?: OnFailHandler,
private readonly abortController = new AbortController()
@@ -65,6 +66,7 @@ export class ImportDoc extends WithDisposable(LitElement) {
const pageId = await HtmlTransformer.importHTMLToDoc({
collection: this.collection,
schema: this.schema,
extensions: this.extensions,
html: text,
fileName,
});
@@ -98,6 +100,7 @@ export class ImportDoc extends WithDisposable(LitElement) {
schema: this.schema,
markdown: text,
fileName,
extensions: this.extensions,
});
needLoading && this.abortController.abort();
if (pageId) {
@@ -122,6 +125,7 @@ export class ImportDoc extends WithDisposable(LitElement) {
collection: this.collection,
schema: this.schema,
imported: file,
extensions: this.extensions,
});
needLoading && this.abortController.abort();
if (hasMarkdown) {

View File

@@ -1,4 +1,4 @@
import type { Schema, Workspace } from '@blocksuite/store';
import type { ExtensionType, Schema, Workspace } from '@blocksuite/store';
import {
ImportDoc,
@@ -9,6 +9,7 @@ import {
export function showImportModal({
schema,
collection,
extensions,
onSuccess,
onFail,
container = document.body,
@@ -16,6 +17,7 @@ export function showImportModal({
}: {
schema: Schema;
collection: Workspace;
extensions: ExtensionType[];
onSuccess?: OnSuccessHandler;
onFail?: OnFailHandler;
multiple?: boolean;
@@ -25,6 +27,7 @@ export function showImportModal({
const importDoc = new ImportDoc(
collection,
schema,
extensions,
onSuccess,
onFail,
abortController

View File

@@ -5,10 +5,14 @@ import {
HtmlAdapter,
titleMiddleware,
} from '@blocksuite/affine-shared/adapters';
import { SpecProvider } from '@blocksuite/affine-shared/utils';
import { Container } from '@blocksuite/global/di';
import { sha } from '@blocksuite/global/utils';
import type { Schema, Store, Workspace } from '@blocksuite/store';
import type {
ExtensionType,
Schema,
Store,
Workspace,
} from '@blocksuite/store';
import { extMimeMap, Transformer } from '@blocksuite/store';
import { createAssetsArchive, download, Unzip } from './utils.js';
@@ -18,18 +22,19 @@ type ImportHTMLToDocOptions = {
schema: Schema;
html: string;
fileName?: string;
extensions: ExtensionType[];
};
type ImportHTMLZipOptions = {
collection: Workspace;
schema: Schema;
imported: Blob;
extensions: ExtensionType[];
};
function getProvider() {
function getProvider(extensions: ExtensionType[]) {
const container = new Container();
const exts = SpecProvider._.getSpec('store').value;
exts.forEach(ext => {
extensions.forEach(ext => {
ext.setup(container);
});
return container.provider();
@@ -42,7 +47,7 @@ function getProvider() {
* @returns A Promise that resolves when the export is complete.
*/
async function exportDoc(doc: Store) {
const provider = getProvider();
const provider = doc.provider;
const job = doc.getTransformer([
docLinkBaseURLMiddleware(doc.workspace.id),
titleMiddleware(doc.workspace.meta.docMetas),
@@ -90,8 +95,9 @@ async function importHTMLToDoc({
schema,
html,
fileName,
extensions,
}: ImportHTMLToDocOptions) {
const provider = getProvider();
const provider = getProvider(extensions);
const job = new Transformer({
schema,
blobCRUD: collection.blobSync,
@@ -130,8 +136,9 @@ async function importHTMLZip({
collection,
schema,
imported,
extensions,
}: ImportHTMLZipOptions) {
const provider = getProvider();
const provider = getProvider(extensions);
const unzip = new Unzip();
await unzip.load(imported);

View File

@@ -5,19 +5,22 @@ import {
MarkdownAdapter,
titleMiddleware,
} from '@blocksuite/affine-shared/adapters';
import { SpecProvider } from '@blocksuite/affine-shared/utils';
import { Container } from '@blocksuite/global/di';
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
import { sha } from '@blocksuite/global/utils';
import type { Schema, Store, Workspace } from '@blocksuite/store';
import type {
ExtensionType,
Schema,
Store,
Workspace,
} from '@blocksuite/store';
import { extMimeMap, Transformer } from '@blocksuite/store';
import { createAssetsArchive, download, Unzip } from './utils.js';
function getProvider() {
function getProvider(extensions: ExtensionType[]) {
const container = new Container();
const exts = SpecProvider._.getSpec('store').value;
exts.forEach(ext => {
extensions.forEach(ext => {
ext.setup(container);
});
return container.provider();
@@ -27,6 +30,7 @@ type ImportMarkdownToBlockOptions = {
doc: Store;
markdown: string;
blockId: string;
extensions: ExtensionType[];
};
type ImportMarkdownToDocOptions = {
@@ -34,12 +38,14 @@ type ImportMarkdownToDocOptions = {
schema: Schema;
markdown: string;
fileName?: string;
extensions: ExtensionType[];
};
type ImportMarkdownZipOptions = {
collection: Workspace;
schema: Schema;
imported: Blob;
extensions: ExtensionType[];
};
/**
@@ -48,7 +54,7 @@ type ImportMarkdownZipOptions = {
* @returns A Promise that resolves when the export is complete
*/
async function exportDoc(doc: Store) {
const provider = getProvider();
const provider = doc.provider;
const job = doc.getTransformer([
docLinkBaseURLMiddleware(doc.workspace.id),
titleMiddleware(doc.workspace.meta.docMetas),
@@ -98,8 +104,9 @@ async function importMarkdownToBlock({
doc,
markdown,
blockId,
extensions,
}: ImportMarkdownToBlockOptions) {
const provider = getProvider();
const provider = getProvider(extensions);
const job = doc.getTransformer([
defaultImageProxyMiddleware,
docLinkBaseURLMiddleware(doc.workspace.id),
@@ -142,8 +149,9 @@ async function importMarkdownToDoc({
schema,
markdown,
fileName,
extensions,
}: ImportMarkdownToDocOptions) {
const provider = getProvider();
const provider = getProvider(extensions);
const job = new Transformer({
schema,
blobCRUD: collection.blobSync,
@@ -181,8 +189,9 @@ async function importMarkdownZip({
collection,
schema,
imported,
extensions,
}: ImportMarkdownZipOptions) {
const provider = getProvider();
const provider = getProvider(extensions);
const unzip = new Unzip();
await unzip.load(imported);

View File

@@ -1,9 +1,9 @@
import { defaultImageProxyMiddleware } from '@blocksuite/affine-block-image';
import { NotionHtmlAdapter } from '@blocksuite/affine-shared/adapters';
import { SpecProvider } from '@blocksuite/affine-shared/utils';
import { Container } from '@blocksuite/global/di';
import { sha } from '@blocksuite/global/utils';
import {
type ExtensionType,
extMimeMap,
type Schema,
Transformer,
@@ -16,12 +16,12 @@ type ImportNotionZipOptions = {
collection: Workspace;
schema: Schema;
imported: Blob;
extensions: ExtensionType[];
};
function getProvider() {
function getProvider(extensions: ExtensionType[]) {
const container = new Container();
const exts = SpecProvider._.getSpec('store').value;
exts.forEach(ext => {
extensions.forEach(ext => {
ext.setup(container);
});
return container.provider();
@@ -45,8 +45,9 @@ async function importNotionZip({
collection,
schema,
imported,
extensions,
}: ImportNotionZipOptions) {
const provider = getProvider();
const provider = getProvider(extensions);
const pageIds: string[] = [];
let isWorkspaceFile = false;
let hasMarkdown = false;

View File

@@ -9,6 +9,7 @@
"references": [
{ "path": "../../blocks/image" },
{ "path": "../../components" },
{ "path": "../../ext-loader" },
{ "path": "../../inlines/reference" },
{ "path": "../../model" },
{ "path": "../../rich-text" },

View File

@@ -16,25 +16,26 @@ import { ParagraphStoreExtension } from '@blocksuite/affine/blocks/paragraph/sto
import { StoreExtensionManager } from '@blocksuite/affine/ext-loader';
import { MigratingStoreExtension } from '@blocksuite/affine/extensions/store';
export function getTestStoreManager() {
const manager = new StoreExtensionManager([
AttachmentStoreExtension,
BookmarkStoreExtension,
CalloutStoreExtension,
CodeStoreExtension,
DataViewStoreExtension,
DatabaseStoreExtension,
DividerStoreExtension,
EdgelessTextStoreExtension,
EmbedStoreExtension,
FrameStoreExtension,
ImageStoreExtension,
LatexStoreExtension,
ListStoreExtension,
NoteStoreExtension,
ParagraphStoreExtension,
const manager = new StoreExtensionManager([
AttachmentStoreExtension,
BookmarkStoreExtension,
CalloutStoreExtension,
CodeStoreExtension,
DataViewStoreExtension,
DatabaseStoreExtension,
DividerStoreExtension,
EdgelessTextStoreExtension,
EmbedStoreExtension,
FrameStoreExtension,
ImageStoreExtension,
LatexStoreExtension,
ListStoreExtension,
NoteStoreExtension,
ParagraphStoreExtension,
MigratingStoreExtension,
]);
MigratingStoreExtension,
]);
export function getTestStoreManager() {
return manager;
}

View File

@@ -19,6 +19,7 @@ import './left-side-panel.js';
import { defaultImageProxyMiddleware } from '@blocksuite/affine/blocks/image';
import { ExportManager } from '@blocksuite/affine/blocks/surface';
import { toast } from '@blocksuite/affine/components/toast';
import { StoreExtensionManagerIdentifier } from '@blocksuite/affine/ext-loader';
import {
BlockSuiteError,
ErrorCode,
@@ -331,6 +332,10 @@ export class StarterDebugMenu extends ShadowlessElement {
);
}
private _getStoreManager() {
return this.editor.std.get(StoreExtensionManagerIdentifier);
}
private async _importHTML() {
try {
const files = await openFileOrFiles({
@@ -349,6 +354,7 @@ export class StarterDebugMenu extends ShadowlessElement {
schema: this.editor.doc.schema,
html: text,
fileName,
extensions: this._getStoreManager().get('store'),
});
if (pageId) {
pageIds.push(pageId);
@@ -372,6 +378,7 @@ export class StarterDebugMenu extends ShadowlessElement {
collection: this.collection,
schema: this.editor.doc.schema,
imported: file,
extensions: this._getStoreManager().get('store'),
});
if (!this.editor.host) return;
toast(
@@ -401,6 +408,7 @@ export class StarterDebugMenu extends ShadowlessElement {
schema: this.editor.doc.schema,
markdown: text,
fileName,
extensions: this._getStoreManager().get('store'),
});
if (pageId) {
pageIds.push(pageId);
@@ -424,6 +432,7 @@ export class StarterDebugMenu extends ShadowlessElement {
collection: this.collection,
schema: this.editor.doc.schema,
imported: file,
extensions: this._getStoreManager().get('store'),
});
if (!this.editor.host) return;
toast(
@@ -463,6 +472,7 @@ export class StarterDebugMenu extends ShadowlessElement {
collection: this.collection,
schema: this.editor.doc.schema,
imported: file,
extensions: this._getStoreManager().get('store'),
});
if (!this.editor.host) return;
toast(

View File

@@ -1,9 +1,9 @@
import { SpecProvider } from '@blocksuite/affine/shared/utils';
import { TestWorkspace } from '@blocksuite/affine/store/test';
import { getTestStoreManager } from '@blocksuite/integration-test/store';
export function createEmptyDoc() {
const collection = new TestWorkspace();
collection.storeExtensions = SpecProvider._.getSpec('store').value;
collection.storeExtensions = getTestStoreManager().get('store');
collection.meta.initialize();
const doc = collection.createDoc();
const store = doc.getStore();

View File

@@ -1,5 +1,6 @@
import { Text, type Workspace } from '@blocksuite/affine/store';
import { MarkdownTransformer } from '@blocksuite/affine/widgets/linked-doc';
import { getTestStoreManager } from '@blocksuite/integration-test/store';
import type { InitFn } from './utils.js';
@@ -26,6 +27,7 @@ export const preset: InitFn = async (collection: Workspace, id: string) => {
doc,
blockId: noteId,
markdown: presetMarkdown,
extensions: getTestStoreManager().get('store'),
});
doc.resetHistory();

View File

@@ -1,5 +1,6 @@
import { Text, type Workspace } from '@blocksuite/affine/store';
import { MarkdownTransformer } from '@blocksuite/affine/widgets/linked-doc';
import { getTestStoreManager } from '@blocksuite/integration-test/store';
import type { InitFn } from './utils';
@@ -44,6 +45,7 @@ export const synced: InitFn = (collection: Workspace, id: string) => {
doc: docSyncedPage,
blockId: noteId,
markdown: syncedDocMarkdown,
extensions: getTestStoreManager().get('store'),
}).catch(console.error);
});
@@ -63,6 +65,7 @@ export const synced: InitFn = (collection: Workspace, id: string) => {
doc: docSyncedEdgeless,
blockId: noteId,
markdown: syncedDocMarkdown,
extensions: getTestStoreManager().get('store'),
}).catch(console.error);
});
@@ -80,6 +83,7 @@ export const synced: InitFn = (collection: Workspace, id: string) => {
doc: docMain,
blockId: noteId,
markdown: syncedDocMarkdown,
extensions: getTestStoreManager().get('store'),
})
.then(() => {
// Add synced block - self