feat: seperate createDoc and createStore (#11182)

This commit is contained in:
Saul-Mirone
2025-03-26 11:03:47 +00:00
parent d6093e1d66
commit 0a8d8e0a6b
70 changed files with 337 additions and 312 deletions
@@ -41,9 +41,9 @@ function createTestDoc(docId = 'doc0') {
const options = createTestOptions();
const collection = new TestWorkspace(options);
collection.meta.initialize();
const doc = collection.createDoc({ id: docId, extensions });
const doc = collection.createDoc(docId);
doc.load();
return doc;
return doc.getStore({ extensions });
}
describe('DatabaseManager', () => {
@@ -34,8 +34,8 @@ export function createJob(middlewares?: TransformerMiddleware[]) {
blobCRUD: docCollection.blobSync,
middlewares: testMiddlewares,
docCRUD: {
create: (id: string) => docCollection.createDoc({ id }),
get: (id: string) => docCollection.getDoc(id),
create: (id: string) => docCollection.createDoc(id).getStore({ id }),
get: (id: string) => docCollection.getDoc(id)?.getStore({ id }) ?? null,
delete: (id: string) => docCollection.removeDoc(id),
},
});
@@ -86,7 +86,7 @@ export class BlockQueryDataSource extends DataSourceBase {
this.workspace.slots.docCreated.subscribe(id => {
const doc = this.workspace.getDoc(id);
if (doc) {
this.listenToDoc(doc);
this.listenToDoc(doc.getStore());
}
});
this.workspace.slots.docRemoved.subscribe(id => {
@@ -412,7 +412,8 @@ export function createLinkedDocFromSlice(
snapshots: BlockSnapshot[],
docTitle?: string
) {
const linkedDoc = doc.workspace.createDoc({});
const _doc = doc.workspace.createDoc();
const linkedDoc = _doc.getStore();
linkedDoc.load(() => {
const rootId = linkedDoc.addBlock('affine:page', {
title: new Text(docTitle),
@@ -239,9 +239,8 @@ export class EmbedLinkedDocBlockComponent extends EmbedBlockComponent<EmbedLinke
}
get linkedDoc() {
return this.std.workspace.getDoc(this.model.props.pageId, {
id: this.model.props.pageId,
});
const doc = this.std.workspace.getDoc(this.model.props.pageId);
return doc?.getStore({ id: this.model.props.pageId });
}
private _handleDoubleClick(event: MouseEvent) {
@@ -409,7 +409,8 @@ export class EmbedSyncedDocBlockComponent extends EmbedBlockComponent<EmbedSynce
get syncedDoc() {
const options: GetBlocksOptions = { readonly: true };
if (this.isPageMode) options.query = this._pageFilter;
return this.std.workspace.getDoc(this.model.props.pageId, options);
const doc = this.std.workspace.getDoc(this.model.props.pageId);
return doc?.getStore(options) ?? null;
}
private _checkCycle() {
@@ -32,7 +32,8 @@ export function createLinkedDocFromNote(
note: NoteBlockModel,
docTitle?: string
) {
const linkedDoc = doc.workspace.createDoc({});
const _doc = doc.workspace.createDoc();
const linkedDoc = _doc.getStore();
linkedDoc.load(() => {
const rootId = linkedDoc.addBlock('affine:page', {
title: new Text(docTitle),
@@ -63,7 +64,8 @@ export function createLinkedDocFromEdgelessElements(
elements: GfxModel[],
docTitle?: string
) {
const linkedDoc = host.doc.workspace.createDoc({});
const _doc = host.doc.workspace.createDoc();
const linkedDoc = _doc.getStore();
linkedDoc.load(() => {
const rootId = linkedDoc.addBlock('affine:page', {
title: new Text(docTitle),
@@ -96,8 +96,8 @@ async function importHTMLToDoc({
schema,
blobCRUD: collection.blobSync,
docCRUD: {
create: (id: string) => collection.createDoc({ id }),
get: (id: string) => collection.getDoc(id),
create: (id: string) => collection.createDoc(id).getStore({ id }),
get: (id: string) => collection.getDoc(id)?.getStore({ id }) ?? null,
delete: (id: string) => collection.removeDoc(id),
},
middlewares: [
@@ -164,8 +164,8 @@ async function importHTMLZip({
schema,
blobCRUD: collection.blobSync,
docCRUD: {
create: (id: string) => collection.createDoc({ id }),
get: (id: string) => collection.getDoc(id),
create: (id: string) => collection.createDoc(id).getStore({ id }),
get: (id: string) => collection.getDoc(id)?.getStore({ id }) ?? null,
delete: (id: string) => collection.removeDoc(id),
},
middlewares: [
@@ -148,8 +148,8 @@ async function importMarkdownToDoc({
schema,
blobCRUD: collection.blobSync,
docCRUD: {
create: (id: string) => collection.createDoc({ id }),
get: (id: string) => collection.getDoc(id),
create: (id: string) => collection.createDoc(id).getStore({ id }),
get: (id: string) => collection.getDoc(id)?.getStore({ id }) ?? null,
delete: (id: string) => collection.removeDoc(id),
},
middlewares: [
@@ -215,8 +215,8 @@ async function importMarkdownZip({
schema,
blobCRUD: collection.blobSync,
docCRUD: {
create: (id: string) => collection.createDoc({ id }),
get: (id: string) => collection.getDoc(id),
create: (id: string) => collection.createDoc(id).getStore({ id }),
get: (id: string) => collection.getDoc(id)?.getStore({ id }) ?? null,
delete: (id: string) => collection.removeDoc(id),
},
middlewares: [
@@ -128,8 +128,8 @@ async function importNotionZip({
schema,
blobCRUD: collection.blobSync,
docCRUD: {
create: (id: string) => collection.createDoc({ id }),
get: (id: string) => collection.getDoc(id),
create: (id: string) => collection.createDoc(id).getStore({ id }),
get: (id: string) => collection.getDoc(id)?.getStore({ id }) ?? null,
delete: (id: string) => collection.removeDoc(id),
},
middlewares: [defaultImageProxyMiddleware],
@@ -18,8 +18,8 @@ async function exportDocs(
schema,
blobCRUD: collection.blobSync,
docCRUD: {
create: (id: string) => collection.createDoc({ id }),
get: (id: string) => collection.getDoc(id),
create: (id: string) => collection.createDoc(id).getStore({ id }),
get: (id: string) => collection.getDoc(id)?.getStore({ id }) ?? null,
delete: (id: string) => collection.removeDoc(id),
},
middlewares: [
@@ -109,8 +109,8 @@ async function importDocs(
schema,
blobCRUD: collection.blobSync,
docCRUD: {
create: (id: string) => collection.createDoc({ id }),
get: (id: string) => collection.getDoc(id),
create: (id: string) => collection.createDoc(id).getStore({ id }),
get: (id: string) => collection.getDoc(id)?.getStore({ id }) ?? null,
delete: (id: string) => collection.removeDoc(id),
},
middlewares: [
@@ -289,9 +289,8 @@ export class SurfaceRefBlockComponent extends BlockComponent<SurfaceRefBlockMode
this._referencedModel =
referencedModel && referencedModel.xywh ? referencedModel : null;
// TODO(@L-Sun): clear query cache
this._previewDoc = this.doc.workspace.getDoc(docId, {
readonly: true,
});
const doc = this.doc.workspace.getDoc(docId);
this._previewDoc = doc?.getStore({ readonly: true }) ?? null;
};
init();
@@ -102,13 +102,9 @@ export class FramePreview extends WithDisposable(ShadowlessElement) {
}
private _initPreviewDoc() {
this._previewDoc = this._originalDoc.workspace.getDoc(
this._originalDoc.id,
{
query: this._docFilter,
readonly: true,
}
);
const doc = this._originalDoc.workspace.getDoc(this._originalDoc.id);
this._previewDoc =
doc?.getStore({ readonly: true, query: this._docFilter }) ?? null;
this.disposables.add(() => {
this._originalDoc.doc.clearQuery(this._docFilter);
});
@@ -60,7 +60,8 @@ export function affine(strings: TemplateStringsArray, ...values: any[]) {
// Create a new doc
const workspace = new TestWorkspace({});
workspace.meta.initialize();
const doc = workspace.createDoc({ id: 'test-doc', extensions });
const doc = workspace.createDoc('test-doc');
const store = doc.getStore({ extensions });
// Use DOMParser to parse HTML string
doc.load(() => {
@@ -72,11 +73,11 @@ export function affine(strings: TemplateStringsArray, ...values: any[]) {
throw new Error('Template must contain a root element');
}
buildDocFromElement(doc, root, null);
buildDocFromElement(store, root, null);
});
// Create and return a host object with the document
return createTestHost(doc);
return createTestHost(store);
}
/**
@@ -103,7 +104,8 @@ export function block(
// Create a temporary doc to hold the block
const workspace = new TestWorkspace({});
workspace.meta.initialize();
const doc = workspace.createDoc({ id: 'temp-doc', extensions });
const doc = workspace.createDoc('temp-doc');
const store = doc.getStore({ extensions });
let blockId: string | null = null;
@@ -117,11 +119,11 @@ export function block(
throw new Error('Template must contain a root element');
}
blockId = buildDocFromElement(doc, root, null);
blockId = buildDocFromElement(store, root, null);
});
// Return the created block
return blockId ? (doc.getBlock(blockId) ?? null) : null;
return blockId ? (store.getBlock(blockId) ?? null) : null;
}
/**
@@ -100,7 +100,9 @@ export class DocDisplayMetaService
return signal(DocDisplayMetaService.icons.deleted);
}
let icon$ = this.iconMap.get(doc);
const store = doc.getStore();
let icon$ = this.iconMap.get(store);
if (!icon$) {
icon$ = signal(
@@ -128,11 +130,11 @@ export class DocDisplayMetaService
this.disposables.splice(index, 1);
disposable.unsubscribe();
}
this.iconMap.delete(doc);
this.iconMap.delete(store);
}
});
this.disposables.push(docRemovedSubscription);
this.iconMap.set(doc, icon$);
this.iconMap.set(store, icon$);
}
return computed(() => {
@@ -165,7 +167,9 @@ export class DocDisplayMetaService
return signal(title || 'Deleted doc');
}
let title$ = this.titleMap.get(doc);
const store = doc.getStore();
let title$ = this.titleMap.get(store);
if (!title$) {
title$ = signal(doc.meta?.title || 'Untitled');
@@ -185,11 +189,11 @@ export class DocDisplayMetaService
this.disposables.splice(index, 1);
disposable.unsubscribe();
}
this.iconMap.delete(doc);
this.iconMap.delete(store);
}
});
this.disposables.push(docRemovedSubscription);
this.titleMap.set(doc, title$);
this.titleMap.set(store, title$);
}
return computed(() => {
@@ -9,29 +9,30 @@ export function createDefaultDoc(
collection: Workspace,
options: { id?: string; title?: string } = {}
) {
const doc = collection.createDoc({ id: options.id });
const doc = collection.createDoc(options.id);
doc.load();
const store = doc.getStore();
const title = options.title ?? '';
const rootId = doc.addBlock('affine:page', {
const rootId = store.addBlock('affine:page', {
title: new Text(title),
});
collection.meta.setDocMeta(doc.id, {
title,
});
doc.addBlock('affine:surface', {}, rootId);
const noteId = doc.addBlock(
store.addBlock('affine:surface', {}, rootId);
const noteId = store.addBlock(
'affine:note',
{
xywh: `[0, 0, ${DEFAULT_PAGE_BLOCK_WIDTH}, ${DEFAULT_PAGE_BLOCK_HEIGHT}]`,
},
rootId
);
doc.addBlock('affine:paragraph', {}, noteId);
store.addBlock('affine:paragraph', {}, noteId);
// To make sure the content of new doc would not be clear
// By undo operation for the first time
doc.resetHistory();
return doc;
return store;
}
@@ -36,15 +36,16 @@ describe('editor host', () => {
const collection = new TestWorkspace(createTestOptions());
collection.meta.initialize();
const doc = collection.createDoc({ id: 'home', extensions });
const doc = collection.createDoc('home');
const store = doc.getStore({ extensions });
doc.load();
const rootId = doc.addBlock('test:page');
const noteId = doc.addBlock('test:note', {}, rootId);
const headingId = doc.addBlock('test:heading', { type: 'h1' }, noteId);
const headingBlock = doc.getBlock(headingId)!;
const rootId = store.addBlock('test:page');
const noteId = store.addBlock('test:note', {}, rootId);
const headingId = store.addBlock('test:heading', { type: 'h1' }, noteId);
const headingBlock = store.getBlock(headingId)!;
const editorContainer = new TestEditorContainer();
editorContainer.doc = doc;
editorContainer.doc = store;
editorContainer.specs = testSpecs;
document.body.append(editorContainer);
@@ -80,16 +80,16 @@ function createTestDoc(docId = defaultDocId) {
const options = createTestOptions();
const collection = new TestWorkspace(options);
collection.meta.initialize();
const doc = collection.createDoc({
id: docId,
const doc = collection.createDoc(docId);
doc.load();
const store = doc.getStore({
extensions: [
pageSchemaExtension,
tableSchemaExtension,
flatTableSchemaExtension,
],
});
doc.load();
return doc;
return store;
}
test('init block without props should add default props', () => {
@@ -61,12 +61,12 @@ function createTestDoc(docId = defaultDocId) {
const options = createTestOptions();
const collection = new TestWorkspace(options);
collection.meta.initialize();
const doc = collection.createDoc({
id: docId,
const doc = collection.createDoc(docId);
const store = doc.getStore({
extensions,
});
doc.load();
return doc;
return store;
}
function requestIdleCallbackPolyfill(
@@ -97,7 +97,7 @@ describe('basic', () => {
const collection = new TestWorkspace(options);
collection.meta.initialize();
const doc = collection.createDoc({ id: 'doc:home' });
const doc = collection.createDoc('doc:home');
doc.load();
const actual = serializCollection(collection.doc);
const actualDoc = actual[spaceMetaId].pages[0] as DocMeta;
@@ -148,23 +148,23 @@ describe('basic', () => {
const options = createTestOptions();
const collection = new TestWorkspace(options);
collection.meta.initialize();
const doc = collection.createDoc({
id: 'space:0',
const doc = collection.createDoc('space:0');
const store = doc.getStore({
extensions,
});
const readyCallback = vi.fn();
const rootAddedCallback = vi.fn();
doc.slots.ready.subscribe(readyCallback);
doc.slots.rootAdded.subscribe(rootAddedCallback);
store.slots.ready.subscribe(readyCallback);
store.slots.rootAdded.subscribe(rootAddedCallback);
doc.load(() => {
const rootId = doc.addBlock('affine:page', {
store.load(() => {
const rootId = store.addBlock('affine:page', {
title: new Text(),
});
expect(rootAddedCallback).toBeCalledTimes(1);
doc.addBlock('affine:note', {}, rootId);
store.addBlock('affine:note', {}, rootId);
});
expect(readyCallback).toBeCalledTimes(1);
@@ -175,12 +175,12 @@ describe('basic', () => {
const collection = new TestWorkspace(options);
collection.meta.initialize();
const collection2 = new TestWorkspace(options);
const doc = collection.createDoc({
id: 'space:0',
const doc = collection.createDoc('space:0');
const store = doc.getStore({
extensions,
});
doc.load(() => {
doc.addBlock('affine:page', {
store.addBlock('affine:page', {
title: new Text(),
});
});
@@ -206,9 +206,7 @@ describe('basic', () => {
// apply doc update
const update = encodeStateAsUpdate(doc.spaceDoc);
expect(collection2.docs.size).toBe(1);
const doc2 = collection2.getDoc('space:0', {
extensions,
});
const doc2 = collection2.getDoc('space:0');
if (!doc2) {
throw new Error('doc2 is not found');
}
@@ -382,12 +380,15 @@ describe('addBlock', () => {
const collection = new TestWorkspace(options);
collection.meta.initialize();
const doc0 = collection.createDoc({ id: 'doc:home' });
const doc1 = collection.createDoc({ id: 'space:doc1' });
const doc0 = collection.createDoc('doc:home');
const doc1 = collection.createDoc('space:doc1');
await Promise.all([doc0.load(), doc1.load()]);
assert.equal(collection.docs.size, 2);
const store0 = doc0.getStore({
extensions,
});
doc0.addBlock('affine:page', {
store0.addBlock('affine:page', {
title: new Text(),
});
collection.removeDoc(doc0.id);
@@ -407,8 +408,7 @@ describe('addBlock', () => {
const collection = new TestWorkspace(options);
collection.meta.initialize();
const doc0 = collection.createDoc({ id: 'doc:home' });
const doc0 = collection.createDoc('doc:home');
collection.removeDoc(doc0.id);
assert.equal(collection.docs.size, 0);
});
@@ -417,7 +417,7 @@ describe('addBlock', () => {
const options = createTestOptions();
const collection = new TestWorkspace(options);
collection.meta.initialize();
collection.createDoc({ id: 'doc:home' });
collection.createDoc('doc:home');
assert.deepEqual(
collection.meta.docMetas.map(({ id, title }) => ({
@@ -31,12 +31,15 @@ test('trigger props updated', () => {
const collection = new TestWorkspace(options);
collection.meta.initialize();
const doc = collection.createDoc({ id: 'home', extensions });
const doc = collection.createDoc('home');
doc.load();
const store = doc.getStore({
extensions,
});
doc.addBlock('affine:page');
store.addBlock('affine:page');
const rootModel = doc.root as RootBlockModel;
const rootModel = store.root as RootBlockModel;
expect(rootModel).not.toBeNull();
@@ -91,12 +94,15 @@ test('stash and pop', () => {
const collection = new TestWorkspace(options);
collection.meta.initialize();
const doc = collection.createDoc({ id: 'home', extensions });
const doc = collection.createDoc('home');
doc.load();
const store = doc.getStore({
extensions,
});
doc.addBlock('affine:page');
store.addBlock('affine:page');
const rootModel = doc.root as RootBlockModel;
const rootModel = store.root as RootBlockModel;
expect(rootModel).not.toBeNull();
@@ -161,12 +167,15 @@ test('always get latest value in onChange', () => {
const collection = new TestWorkspace(options);
collection.meta.initialize();
const doc = collection.createDoc({ id: 'home', extensions });
const doc = collection.createDoc('home');
doc.load();
const store = doc.getStore({
extensions,
});
doc.addBlock('affine:page');
store.addBlock('affine:page');
const rootModel = doc.root as RootBlockModel;
const rootModel = store.root as RootBlockModel;
expect(rootModel).not.toBeNull();
@@ -207,11 +216,15 @@ test('query', () => {
const options = createTestOptions();
const collection = new TestWorkspace(options);
collection.meta.initialize();
const doc1 = collection.createDoc({ id: 'home', extensions });
doc1.load();
const doc2 = collection.getDoc('home', { extensions });
const doc3 = collection.getDoc('home', {
const doc = collection.createDoc('home');
doc.load();
const store1 = doc.getStore({
extensions,
});
const store2 = doc.getStore({
extensions,
});
const store3 = doc.getStore({
extensions,
query: {
mode: 'loose',
@@ -223,48 +236,53 @@ test('query', () => {
],
},
});
expect(doc1).toBe(doc2);
expect(doc1).not.toBe(doc3);
expect(store1).toBe(store2);
expect(store1).not.toBe(store3);
const page = doc1.addBlock('affine:page');
const note = doc1.addBlock('affine:note', {}, page);
const paragraph1 = doc1.addBlock('affine:paragraph', {}, note);
const list1 = doc1.addBlock('affine:list' as never, {}, note);
const page = store1.addBlock('affine:page');
const note = store1.addBlock('affine:note', {}, page);
const paragraph1 = store1.addBlock('affine:paragraph', {}, note);
const list1 = store1.addBlock('affine:list' as never, {}, note);
expect(doc2?.getBlock(paragraph1)?.blockViewType).toBe('display');
expect(doc2?.getBlock(list1)?.blockViewType).toBe('display');
expect(doc3?.getBlock(list1)?.blockViewType).toBe('hidden');
expect(store2?.getBlock(paragraph1)?.blockViewType).toBe('display');
expect(store2?.getBlock(list1)?.blockViewType).toBe('display');
expect(store3?.getBlock(list1)?.blockViewType).toBe('hidden');
const list2 = doc1.addBlock('affine:list' as never, {}, note);
const list2 = store1.addBlock('affine:list' as never, {}, note);
expect(doc2?.getBlock(list2)?.blockViewType).toBe('display');
expect(doc3?.getBlock(list2)?.blockViewType).toBe('hidden');
expect(store2?.getBlock(list2)?.blockViewType).toBe('display');
expect(store3?.getBlock(list2)?.blockViewType).toBe('hidden');
});
test('local readonly', () => {
const options = createTestOptions();
const collection = new TestWorkspace(options);
collection.meta.initialize();
const doc1 = collection.createDoc({ id: 'home', extensions });
doc1.load();
const doc2 = collection.getDoc('home', { readonly: true, extensions });
const doc3 = collection.getDoc('home', { readonly: false, extensions });
const doc = collection.createDoc('home');
const store1 = doc.getStore({
extensions,
});
const store2 = doc.getStore({
readonly: true,
extensions,
});
const store3 = doc.getStore({ readonly: false, extensions });
expect(doc1.readonly).toBeFalsy();
expect(doc2?.readonly).toBeTruthy();
expect(doc3?.readonly).toBeFalsy();
expect(store1.readonly).toBeFalsy();
expect(store2.readonly).toBeTruthy();
expect(store3.readonly).toBeFalsy();
doc1.readonly = true;
store1.readonly = true;
expect(doc1.readonly).toBeTruthy();
expect(doc2?.readonly).toBeTruthy();
expect(doc3?.readonly).toBeFalsy();
expect(store1.readonly).toBeTruthy();
expect(store2.readonly).toBeTruthy();
expect(store3.readonly).toBeFalsy();
doc1.readonly = false;
store1.readonly = false;
expect(doc1.readonly).toBeFalsy();
expect(doc2?.readonly).toBeTruthy();
expect(doc3?.readonly).toBeFalsy();
expect(store1.readonly).toBeFalsy();
expect(store2.readonly).toBeTruthy();
expect(store3.readonly).toBeFalsy();
});
describe('move blocks', () => {
@@ -274,21 +292,22 @@ describe('move blocks', () => {
const collection = new TestWorkspace(options);
collection.meta.initialize();
const doc = collection.createDoc({ id: 'home', extensions });
const doc = collection.createDoc('home');
doc.load();
const pageId = doc.addBlock('affine:page');
const page = doc.getBlock(pageId)!.model;
const store = doc.getStore({ extensions });
const pageId = store.addBlock('affine:page');
const page = store.getBlock(pageId)!.model;
const noteIds = doc.addBlocks(
const noteIds = store.addBlocks(
[1, 2, 3].map(i => ({
flavour: 'affine:note',
blockProps: { id: `${i}` },
})),
page
);
const notes = noteIds.map(id => doc.getBlock(id)!.model);
const notes = noteIds.map(id => store.getBlock(id)!.model);
context.doc = doc;
context.doc = store;
context.page = page;
context.notes = notes;
});
@@ -99,9 +99,10 @@ function createTestDoc(docId = defaultDocId) {
const options = createTestOptions();
const collection = new TestWorkspace(options);
collection.meta.initialize();
const doc = collection.createDoc({ id: docId, extensions });
const doc = collection.createDoc(docId);
doc.load();
return doc;
const store = doc.getStore({ extensions });
return store;
}
describe('schema', () => {
@@ -59,10 +59,11 @@ test('model to snapshot', () => {
const options = createTestOptions();
const collection = new TestWorkspace(options);
collection.meta.initialize();
const doc = collection.createDoc({ id: 'home', extensions });
const doc = collection.createDoc('home');
const store = doc.getStore({ extensions });
doc.load();
doc.addBlock('page');
const rootModel = doc.root as RootBlockModel;
store.addBlock('page');
const rootModel = store.root as RootBlockModel;
expect(rootModel).not.toBeNull();
const snapshot = transformer.toSnapshot({
@@ -76,10 +77,11 @@ test('snapshot to model', async () => {
const options = createTestOptions();
const collection = new TestWorkspace(options);
collection.meta.initialize();
const doc = collection.createDoc({ id: 'home', extensions });
const doc = collection.createDoc('home');
const store = doc.getStore({ extensions });
doc.load();
doc.addBlock('page');
const rootModel = doc.root as RootBlockModel;
store.addBlock('page');
const rootModel = store.root as RootBlockModel;
const tempDoc = new Y.Doc();
const map = tempDoc.getMap('temp');
@@ -1127,8 +1127,9 @@ export class Store {
schema: this.schema,
blobCRUD: this.workspace.blobSync,
docCRUD: {
create: (id: string) => this.workspace.createDoc({ id }),
get: (id: string) => this.workspace.getDoc(id),
create: (id: string) => this.workspace.createDoc(id).getStore({ id }),
get: (id: string) =>
this.workspace.getDoc(id)?.getStore({ id }) ?? null,
delete: (id: string) => this.workspace.removeDoc(id),
},
middlewares,
@@ -4,8 +4,7 @@ import type { Awareness } from 'y-protocols/awareness.js';
import type * as Y from 'yjs';
import type { IdGenerator } from '../utils/id-generator.js';
import type { CreateBlocksOptions, Doc, GetBlocksOptions } from './doc.js';
import type { Store } from './store/store.js';
import type { Doc } from './doc.js';
import type { WorkspaceMeta } from './workspace-meta.js';
export interface Workspace {
@@ -25,8 +24,8 @@ export interface Workspace {
docRemoved: Subject<string>;
};
createDoc(options?: CreateBlocksOptions): Store;
getDoc(docId: string, options?: GetBlocksOptions): Store | null;
createDoc(docId?: string): Doc;
getDoc(docId: string): Doc | null;
removeDoc(docId: string): void;
dispose(): void;
@@ -15,13 +15,7 @@ import { Awareness } from 'y-protocols/awareness.js';
import * as Y from 'yjs';
import type { ExtensionType } from '../extension/extension.js';
import type {
CreateBlocksOptions,
GetBlocksOptions,
Store,
Workspace,
WorkspaceMeta,
} from '../model/index.js';
import type { Doc, Workspace, WorkspaceMeta } from '../model/index.js';
import { type IdGenerator, nanoid } from '../utils/id-generator.js';
import { AwarenessStore } from '../yjs/index.js';
import { TestDoc } from './test-doc.js';
@@ -155,14 +149,9 @@ export class TestWorkspace implements Workspace {
* If the `init` parameter is passed, a `surface`, `note`, and `paragraph` block
* will be created in the doc simultaneously.
*/
createDoc(options: CreateBlocksOptions = {}) {
const {
id: docId = this.idGenerator(),
query,
readonly,
extensions,
} = options;
if (this._hasDoc(docId)) {
createDoc(docId?: string): Doc {
const id = docId ?? this.idGenerator();
if (this._hasDoc(id)) {
throw new BlockSuiteError(
ErrorCode.DocCollectionError,
'doc already exists'
@@ -170,18 +159,13 @@ export class TestWorkspace implements Workspace {
}
this.meta.addDocMeta({
id: docId,
id,
title: '',
createDate: Date.now(),
tags: [],
});
this.slots.docCreated.next(docId);
return this.getDoc(docId, {
id: docId,
query,
readonly,
extensions,
}) as Store;
this.slots.docCreated.next(id);
return this.getDoc(id) as Doc;
}
dispose() {
@@ -203,12 +187,9 @@ export class TestWorkspace implements Workspace {
return space ?? null;
}
getDoc(
docId: string,
options: GetBlocksOptions = { id: docId }
): Store | null {
getDoc(docId: string): Doc | null {
const collection = this.getBlockCollection(docId);
return collection?.getStore(options) ?? null;
return collection;
}
removeDoc(docId: string) {
@@ -1,6 +1,6 @@
import { z } from 'zod';
import type { Store } from '../model/store/store';
import type { Store } from '../model';
import type { DocMeta, DocsPropertiesMeta } from '../model/workspace-meta';
export type BlockSnapshot = {
@@ -15,8 +15,8 @@ export async function importFromSnapshot(
schema: new Schema().register(AffineSchemas),
blobCRUD: collection.blobSync,
docCRUD: {
create: (id: string) => collection.createDoc({ id }),
get: (id: string) => collection.getDoc(id),
create: (id: string) => collection.createDoc(id).getStore({ id }),
get: (id: string) => collection.getDoc(id)?.getStore({ id }) ?? null,
delete: (id: string) => collection.removeDoc(id),
},
middlewares: [replaceIdMiddleware(collection.idGenerator)],
@@ -50,7 +50,7 @@ function createCollectionOptions() {
}
function initCollection(collection: TestWorkspace) {
const doc = collection.createDoc({ id: 'doc:home' });
const doc = collection.createDoc('doc:home').getStore();
doc.load(() => {
const rootId = doc.addBlock('affine:page', {
+6 -5
View File
@@ -6,16 +6,17 @@ export function createEmptyDoc() {
collection.storeExtensions = SpecProvider._.getSpec('store').value;
collection.meta.initialize();
const doc = collection.createDoc();
const store = doc.getStore();
return {
doc,
init() {
doc.load();
const rootId = doc.addBlock('affine:page', {});
doc.addBlock('affine:surface', {}, rootId);
const noteId = doc.addBlock('affine:note', {}, rootId);
doc.addBlock('affine:paragraph', {}, noteId);
return doc;
const rootId = store.addBlock('affine:page', {});
store.addBlock('affine:surface', {}, rootId);
const noteId = store.addBlock('affine:note', {}, rootId);
store.addBlock('affine:paragraph', {}, noteId);
return store;
},
};
}
@@ -8,7 +8,7 @@ export function getDocFromUrlParams(collection: Workspace, url: URL) {
const docId = decodeURIComponent(url.hash.slice(1));
if (docId) {
doc = collection.getDoc(docId);
doc = collection.getDoc(docId)?.getStore() ?? null;
}
if (!doc) {
const blockCollection = collection.docs.values().next().value as Doc;
@@ -2,13 +2,14 @@ import { ZipTransformer } from '@blocksuite/affine/blocks/root';
import { AffineSchemas } from '@blocksuite/affine/schemas';
import { Schema, Text, type Workspace } from '@blocksuite/affine/store';
export async function affineSnapshot(collection: Workspace, id: string) {
const doc = collection.createDoc({ id });
const doc = collection.createDoc(id);
doc.load();
const store = doc.getStore();
// Add root block and surface block at root level
const rootId = doc.addBlock('affine:page', {
const rootId = store.addBlock('affine:page', {
title: new Text('Affine Snapshot Test'),
});
doc.addBlock('affine:surface', {}, rootId);
store.addBlock('affine:surface', {}, rootId);
const path = '/apps/starter/data/snapshots/affine-default.zip';
const response = await fetch(path);
@@ -15,24 +15,25 @@ import { viewPresets } from '@blocksuite/data-view/view-presets';
import type { InitFn } from './utils.js';
export const database: InitFn = (collection: Workspace, id: string) => {
const doc = collection.createDoc({ id });
const doc = collection.createDoc(id);
const store = doc.getStore();
doc.load(() => {
// Add root block and surface block at root level
const rootId = doc.addBlock('affine:page', {
const rootId = store.addBlock('affine:page', {
title: new Text('BlockSuite Playground'),
});
doc.addBlock('affine:surface', {}, rootId);
store.addBlock('affine:surface', {}, rootId);
// Add note block inside root block
const noteId = doc.addBlock('affine:note', {}, rootId);
const pId = doc.addBlock('affine:paragraph', {}, noteId);
const model = doc.getModelById(pId);
const noteId = store.addBlock('affine:note', {}, rootId);
const pId = store.addBlock('affine:paragraph', {}, noteId);
const model = store.getModelById(pId);
if (!model) {
throw new Error('model is not found');
}
const addDatabase = (title: string, group = true) => {
const databaseId = doc.addBlock(
const databaseId = store.addBlock(
'affine:database',
{
columns: [],
@@ -40,7 +41,7 @@ export const database: InitFn = (collection: Workspace, id: string) => {
},
noteId
);
const database = doc.getModelById(databaseId) as DatabaseBlockModel;
const database = store.getModelById(databaseId) as DatabaseBlockModel;
const datasource = new DatabaseBlockDataSource(database);
datasource.viewManager.viewAdd('table');
database.props.title = new Text(title);
@@ -74,7 +75,7 @@ export const database: InitFn = (collection: Workspace, id: string) => {
'h6',
];
paragraphTypes.forEach(type => {
const id = doc.addBlock(
const id = store.addBlock(
'affine:paragraph',
{ type: type, text: new Text(`Paragraph type ${type}`) },
databaseId
@@ -90,7 +91,7 @@ export const database: InitFn = (collection: Workspace, id: string) => {
const listTypes: ListType[] = ['numbered', 'bulleted', 'todo', 'toggle'];
listTypes.forEach(type => {
const id = doc.addBlock(
const id = store.addBlock(
'affine:list',
{ type: type, text: new Text(`List type ${type}`) },
databaseId
@@ -104,11 +105,11 @@ export const database: InitFn = (collection: Workspace, id: string) => {
}
});
// Add a paragraph after database
doc.addBlock('affine:paragraph', {}, noteId);
doc.addBlock('affine:paragraph', {}, noteId);
doc.addBlock('affine:paragraph', {}, noteId);
doc.addBlock('affine:paragraph', {}, noteId);
doc.addBlock('affine:paragraph', {}, noteId);
store.addBlock('affine:paragraph', {}, noteId);
store.addBlock('affine:paragraph', {}, noteId);
store.addBlock('affine:paragraph', {}, noteId);
store.addBlock('affine:paragraph', {}, noteId);
store.addBlock('affine:paragraph', {}, noteId);
datasource.viewManager.viewAdd(viewPresets.kanbanViewMeta.type);
doc.resetHistory();
@@ -3,30 +3,31 @@ import { Text, type Workspace } from '@blocksuite/affine/store';
import type { InitFn } from './utils.js';
export const embed: InitFn = (collection: Workspace, id: string) => {
const doc = collection.getDoc(id) ?? collection.createDoc({ id });
doc.doc.clear();
const doc = collection.getDoc(id) ?? collection.createDoc(id);
const store = doc.getStore();
doc.clear();
doc.load(() => {
// Add root block and surface block at root level
const rootId = doc.addBlock('affine:page', {
const rootId = store.addBlock('affine:page', {
title: new Text(),
});
const surfaceId = doc.addBlock('affine:surface', {}, rootId);
const surfaceId = store.addBlock('affine:surface', {}, rootId);
// Add note block inside root block
const noteId = doc.addBlock('affine:note', {}, rootId);
const noteId = store.addBlock('affine:note', {}, rootId);
// Add paragraph block inside note block
doc.addBlock('affine:paragraph', {}, noteId);
store.addBlock('affine:paragraph', {}, noteId);
doc.addBlock(
store.addBlock(
'affine:embed-github',
{
url: 'https://github.com/toeverything/AFFiNE/pull/5453',
},
noteId
);
doc.addBlock(
store.addBlock(
'affine:embed-github',
{
url: 'https://www.github.com/toeverything/blocksuite/pull/5927',
@@ -35,7 +36,7 @@ export const embed: InitFn = (collection: Workspace, id: string) => {
},
surfaceId
);
doc.addBlock(
store.addBlock(
'affine:embed-github',
{
url: 'https://github.com/Milkdown/milkdown/pull/1215',
@@ -43,7 +44,7 @@ export const embed: InitFn = (collection: Workspace, id: string) => {
},
surfaceId
);
doc.addBlock('affine:paragraph', {}, noteId);
store.addBlock('affine:paragraph', {}, noteId);
});
doc.resetHistory();
@@ -3,21 +3,22 @@ import { Text, type Workspace } from '@blocksuite/affine/store';
import type { InitFn } from './utils.js';
export const empty: InitFn = (collection: Workspace, id: string) => {
const doc = collection.getDoc(id) ?? collection.createDoc({ id });
doc.doc.clear();
const doc = collection.getDoc(id) ?? collection.createDoc(id);
const store = doc.getStore();
doc.clear();
doc.load(() => {
// Add root block and surface block at root level
const rootId = doc.addBlock('affine:page', {
const rootId = store.addBlock('affine:page', {
title: new Text(),
});
doc.addBlock('affine:surface', {}, rootId);
store.addBlock('affine:surface', {}, rootId);
// Add note block inside root block
const noteId = doc.addBlock('affine:note', {}, rootId);
const noteId = store.addBlock('affine:note', {}, rootId);
// Add paragraph block inside note block
doc.addBlock('affine:paragraph', {}, noteId);
store.addBlock('affine:paragraph', {}, noteId);
});
doc.resetHistory();
@@ -50,16 +50,17 @@ export const heavyWhiteboard: InitFn = (collection: Workspace, id: string) => {
const count = Number(params.get('count')) || SHAPES_COUNT;
const enableShapes = !!params.get('shapes');
const doc = collection.createDoc({ id });
const doc = collection.createDoc(id);
const store = doc.getStore();
doc.load(() => {
// Add root block and surface block at root level
const rootId = doc.addBlock('affine:page', {
const rootId = store.addBlock('affine:page', {
title: new Text(),
});
const surfaceBlocks = enableShapes ? createShapes(count) : {};
doc.addBlock(
store.addBlock(
'affine:surface',
{
elements: new Boxed(native2Y(surfaceBlocks, { deep: false })) as Boxed<
@@ -74,7 +75,7 @@ export const heavyWhiteboard: InitFn = (collection: Workspace, id: string) => {
for (i = 0; i < count; i++) {
const x = Math.random() * RANGE - RANGE / 2;
const y = Math.random() * RANGE - RANGE / 2;
const noteId = doc.addBlock(
const noteId = store.addBlock(
'affine:note',
{
xywh: `[${x}, ${y}, 100, 50]` as SerializedXYWH,
@@ -82,7 +83,7 @@ export const heavyWhiteboard: InitFn = (collection: Workspace, id: string) => {
rootId
);
// Add paragraph block inside note block
doc.addBlock(
store.addBlock(
'affine:paragraph',
{
text: new Text('Note #' + i),
@@ -7,19 +7,20 @@ const params = new URLSearchParams(location.search);
export const heavy: InitFn = (collection: Workspace, docId: string) => {
const count = Number(params.get('count')) || 1000;
const doc = collection.createDoc({ id: docId });
const doc = collection.createDoc(docId);
const store = doc.getStore();
doc.load(() => {
// Add root block and surface block at root level
const rootId = doc.addBlock('affine:page', {
const rootId = store.addBlock('affine:page', {
title: new Text(),
});
doc.addBlock('affine:surface', {}, rootId);
store.addBlock('affine:surface', {}, rootId);
// Add note block inside root block
const noteId = doc.addBlock('affine:note', {}, rootId);
const noteId = store.addBlock('affine:note', {}, rootId);
for (let i = 0; i < count; i++) {
// Add paragraph block inside note block
doc.addBlock(
store.addBlock(
'affine:paragraph',
{
text: new Text('Hello, world! ' + i),
@@ -3,13 +3,15 @@ import { Text, type Workspace } from '@blocksuite/affine/store';
import type { InitFn } from './utils.js';
export const linked: InitFn = (collection: Workspace, id: string) => {
const docA = collection.getDoc(id) ?? collection.createDoc({ id });
const docA =
collection.getDoc(id)?.getStore({ id }) ??
collection.createDoc(id).getStore({ id });
const docBId = 'doc:linked-page';
const docB = collection.createDoc({ id: docBId });
const docB = collection.createDoc(docBId).getStore();
const docCId = 'doc:linked-edgeless';
const docC = collection.createDoc({ id: docCId });
const docC = collection.createDoc(docCId).getStore();
docA.doc.clear();
docB.doc.clear();
@@ -4,7 +4,7 @@ import { createTestEditor } from '../utils/extensions.js';
import type { InitFn } from './utils.js';
export const multiEditor: InitFn = (collection: Workspace, id: string) => {
const doc = collection.createDoc({ id });
const doc = collection.createDoc(id).getStore({ id });
doc.load(() => {
// Add root block and surface block at root level
const rootId = doc.addBlock('affine:page', {
@@ -39,7 +39,7 @@ export const multiEditorVertical: InitFn = (
collection: Workspace,
docId: string
) => {
const doc = collection.createDoc({ id: docId });
const doc = collection.createDoc(docId).getStore();
doc.load(() => {
// Add root block and surface block at root level
const rootId = doc.addBlock('affine:page', {
@@ -4,8 +4,8 @@ import * as Y from 'yjs';
import type { InitFn } from './utils.js';
export const pendingStructs: InitFn = (collection: Workspace, id: string) => {
const doc = collection.createDoc({ id });
const tempDoc = collection.createDoc({ id: 'tempDoc' });
const doc = collection.createDoc(id).getStore({ id });
const tempDoc = collection.createDoc('tempDoc').getStore();
doc.load();
tempDoc.load(() => {
const rootId = tempDoc.addBlock('affine:page', {
@@ -6,7 +6,7 @@ import type { InitFn } from './utils.js';
const presetMarkdown = `Click the 🔁 button to switch between editors dynamically - they are fully compatible!`;
export const preset: InitFn = async (collection: Workspace, id: string) => {
const doc = collection.createDoc({ id });
const doc = collection.createDoc(id).getStore({ id });
doc.load();
// Add root block and surface block at root level
const rootId = doc.addBlock('affine:page', {
@@ -12,13 +12,17 @@ This article has also been published [in PDF format](https://www.inkandswitch.co
We welcome your feedback: [@inkandswitch](https://twitter.com/inkandswitch) or hello@inkandswitch.com.`;
export const synced: InitFn = (collection: Workspace, id: string) => {
const docMain = collection.getDoc(id) ?? collection.createDoc({ id });
const docMain =
collection.getDoc(id)?.getStore({ id }) ??
collection.createDoc(id).getStore({ id });
const docSyncedPageId = 'doc:synced-page';
const docSyncedPage = collection.createDoc({ id: docSyncedPageId });
const docSyncedPage = collection.createDoc(docSyncedPageId).getStore();
const docSyncedEdgelessId = 'doc:synced-edgeless';
const docSyncedEdgeless = collection.createDoc({ id: docSyncedEdgelessId });
const docSyncedEdgeless = collection
.createDoc(docSyncedEdgelessId)
.getStore();
docMain.doc.clear();
docSyncedPage.doc.clear();
@@ -4,8 +4,8 @@ import * as Y from 'yjs';
import type { InitFn } from './utils.js';
export const versionMismatch: InitFn = (collection: Workspace, id: string) => {
const doc = collection.createDoc({ id });
const tempDoc = collection.createDoc({ id: 'tempDoc' });
const doc = collection.createDoc(id).getStore({ id });
const tempDoc = collection.createDoc('tempDoc').getStore();
doc.load();
tempDoc.load(() => {
@@ -66,8 +66,8 @@ export function createStarterDocCollection() {
schema,
blobCRUD: collection.blobSync,
docCRUD: {
create: (id: string) => collection.createDoc({ id }),
get: (id: string) => collection.getDoc(id),
create: (id: string) => collection.createDoc(id).getStore({ id }),
get: (id: string) => collection.getDoc(id)?.getStore({ id }) ?? null,
delete: (id: string) => collection.removeDoc(id),
},
});
@@ -52,7 +52,7 @@ export function createTestEditor(store: Store, workspace: Workspace) {
editor.std
.get(RefNodeSlotsProvider)
.docLinkClicked.subscribe(({ pageId: docId }) => {
const target = workspace.getDoc(docId);
const target = workspace.getDoc(docId)?.getStore();
if (!target) {
throw new Error(`Failed to jump to doc ${docId}`);
}
@@ -26,7 +26,7 @@ async function getStore(
): Promise<Store> {
if (!noInit) {
collection.meta.initialize();
const doc = collection.createDoc({ id: 'doc:home' });
const doc = collection.createDoc('doc:home').getStore();
window.doc = doc;
return doc;
}
@@ -477,7 +477,8 @@ const SAVE_AS_DOC = {
toast: 'New doc created',
handler: (host: EditorHost, content: string) => {
reportResponse('result:add-page');
const newDoc = host.doc.workspace.createDoc();
const doc = host.doc.workspace.createDoc();
const newDoc = doc.getStore();
newDoc.load();
const rootId = newDoc.addBlock('affine:page');
newDoc.addBlock('affine:surface', {}, rootId);
@@ -533,7 +534,7 @@ const CREATE_AS_LINKED_DOC = {
}
// Create a new doc and add the content to it
const newDoc = host.doc.workspace.createDoc();
const newDoc = host.doc.workspace.createDoc().getStore();
newDoc.load();
const rootId = newDoc.addBlock('affine:page');
newDoc.addBlock('affine:surface', {}, rootId);
@@ -219,7 +219,7 @@ export class AISlidesRenderer extends WithDisposable(LitElement) {
id: 'SLIDES_PREVIEW',
});
collection.meta.initialize();
const doc = collection.createDoc();
const doc = collection.createDoc().getStore();
doc.load(() => {
const pageBlockId = doc.addBlock('affine:page', {});
@@ -30,7 +30,7 @@ describe('markdownToMindmap: convert markdown list to a mind map tree', () => {
`;
const collection = new TestWorkspace();
collection.meta.initialize();
const doc = collection.createDoc();
const doc = collection.createDoc().getStore();
const nodes = markdownToMindmap(markdown, doc, provider);
expect(nodes).toEqual({
@@ -68,7 +68,7 @@ describe('markdownToMindmap: convert markdown list to a mind map tree', () => {
`;
const collection = new TestWorkspace();
collection.meta.initialize();
const doc = collection.createDoc();
const doc = collection.createDoc().getStore();
const nodes = markdownToMindmap(markdown, doc, provider);
expect(nodes).toEqual({
@@ -100,7 +100,7 @@ describe('markdownToMindmap: convert markdown list to a mind map tree', () => {
const markdown = '';
const collection = new TestWorkspace();
collection.meta.initialize();
const doc = collection.createDoc();
const doc = collection.createDoc().getStore();
const nodes = markdownToMindmap(markdown, doc, provider);
expect(nodes).toEqual(null);
@@ -103,7 +103,8 @@ export class MiniMindmapPreview extends WithDisposable(LitElement) {
id: 'MINI_MINDMAP_TEMPORARY',
});
collection.meta.initialize();
const doc = collection.createDoc({ id: 'doc:home' }).load();
const doc = collection.createDoc('doc:home').getStore();
doc.load();
const rootId = doc.addBlock('affine:page', {});
const surfaceId = doc.addBlock('affine:surface', {}, rootId);
const surface = doc.getModelById(surfaceId) as SurfaceBlockModel;
@@ -684,7 +684,7 @@ const embedLinkedDocToolbarConfig = {
ctx.hide();
const model = block.model;
const doc = ctx.workspace.getDoc(model.props.pageId);
const doc = ctx.workspace.getDoc(model.props.pageId)?.getStore();
const abortController = new AbortController();
abortController.signal.onabort = () => ctx.show();
@@ -165,8 +165,8 @@ export async function markDownToDoc(
schema,
blobCRUD: collection.blobSync,
docCRUD: {
create: (id: string) => collection.createDoc({ id }),
get: (id: string) => collection.getDoc(id),
create: (id: string) => collection.createDoc(id).getStore({ id }),
get: (id: string) => collection.getDoc(id)?.getStore({ id }) ?? null,
delete: (id: string) => collection.removeDoc(id),
},
middlewares,
@@ -174,11 +174,9 @@ export const useSnapshotPage = (
docCollection.id,
workspacesService.getWorkspaceFlavourProvider(affineWorkspace.meta)
);
let page = historyShellWorkspace.getDoc(pageId);
let page = historyShellWorkspace.getDoc(pageId)?.getStore();
if (!page && snapshot) {
page = historyShellWorkspace.createDoc({
id: pageId,
});
page = historyShellWorkspace.createDoc(pageId).getStore();
page.readonly = true;
const spaceDoc = page.spaceDoc;
page.load(() => {
@@ -65,8 +65,8 @@ async function exportDoc(
schema: getAFFiNEWorkspaceSchema(),
blobCRUD: doc.workspace.blobSync,
docCRUD: {
create: (id: string) => doc.workspace.createDoc({ id }),
get: (id: string) => doc.workspace.getDoc(id),
create: (id: string) => doc.workspace.createDoc(id).getStore({ id }),
get: (id: string) => doc.workspace.getDoc(id)?.getStore({ id }) ?? null,
delete: (id: string) => doc.workspace.removeDoc(id),
},
middlewares: [
@@ -9,7 +9,7 @@ import { useCallback } from 'react';
export function useReferenceLinkHelper(docCollection: Workspace) {
const addReferenceLink = useCallback(
(pageId: string, referenceId: string) => {
const page = docCollection?.getDoc(pageId);
const page = docCollection?.getDoc(pageId)?.getStore();
if (!page) {
return;
}
@@ -5,7 +5,7 @@ export function useDocCollectionHelper(docCollection: Workspace) {
return useMemo(
() => ({
createDoc: (pageId?: string): Store => {
return docCollection.createDoc({ id: pageId });
return docCollection.createDoc(pageId).getStore();
},
}),
[docCollection]
@@ -9,8 +9,8 @@ export function useDocCollectionPage(
docCollection: Workspace,
pageId: string | null
): Store | null {
const [page, setPage] = useState(
pageId ? docCollection.getDoc(pageId) : null
const [page, setPage] = useState<Store | null>(
pageId ? (docCollection.getDoc(pageId)?.getStore() ?? null) : null
);
useEffect(() => {
@@ -18,7 +18,7 @@ export function useDocCollectionPage(
group.add(
docCollection.slots.docCreated.subscribe(id => {
if (pageId === id) {
setPage(docCollection.getDoc(id));
setPage(docCollection.getDoc(id)?.getStore() ?? null);
}
})
);
@@ -33,12 +33,16 @@ beforeEach(async () => {
const frameId = page.addBlock('affine:note', {}, pageBlockId);
page.addBlock('affine:paragraph', {}, frameId);
};
await initPage(docCollection.createDoc({ id: 'page0', extensions }));
const store = docCollection.createDoc('page0').getStore({ extensions });
await initPage(store);
});
describe('useBlockSuitePagePreview', () => {
test('basic', async () => {
const page = docCollection.getDoc('page0') as Store;
const page = docCollection.getDoc('page0')?.getStore();
if (!page) {
throw new Error('Page not found');
}
const id = page.addBlock(
'affine:paragraph',
{
@@ -9,8 +9,8 @@ export function useDocCollectionPage(
docCollection: Workspace,
pageId: string | null
): Store | null {
const [page, setPage] = useState(
pageId ? docCollection.getDoc(pageId) : null
const [page, setPage] = useState<Store | null>(
pageId ? (docCollection.getDoc(pageId)?.getStore() ?? null) : null
);
useEffect(() => {
@@ -18,7 +18,7 @@ export function useDocCollectionPage(
group.add(
docCollection.slots.docCreated.subscribe(id => {
if (pageId === id) {
setPage(docCollection.getDoc(id));
setPage(docCollection.getDoc(id)?.getStore() ?? null);
}
})
);
@@ -46,7 +46,9 @@ export function useDocCollectionPage(
useEffect(() => {
if (page?.id !== pageId) {
setPage(pageId ? docCollection.getDoc(pageId) : null);
setPage(
pageId ? (docCollection.getDoc(pageId)?.getStore() ?? null) : null
);
}
}, [docCollection, page?.id, pageId]);
@@ -87,8 +87,8 @@ async function initDoc(name: DocName) {
schema: getAFFiNEWorkspaceSchema(),
blobCRUD: collection.blobSync,
docCRUD: {
create: (id: string) => collection.createDoc({ id }),
get: (id: string) => collection.getDoc(id),
create: (id: string) => collection.createDoc(id).getStore({ id }),
get: (id: string) => collection.getDoc(id)?.getStore({ id }) ?? null,
delete: (id: string) => collection.removeDoc(id),
},
middlewares: [],
@@ -96,7 +96,7 @@ export const EditorChatPanel = forwardRef(function EditorChatPanel(
},
getDoc: (docId: string) => {
const doc = workspaceService.workspace.docCollection.getDoc(docId);
return doc;
return doc?.getStore() ?? null;
},
getReferenceDocs: (docIds: string[]) => {
const docs$ = docsSearchService.watchRefsFrom(docIds);
@@ -155,7 +155,7 @@ export class DndService extends Service {
getBlocksuiteDndAPI(sourceDocId?: string) {
const collection = this.workspaceService.workspace.docCollection;
sourceDocId ??= collection.docs.keys().next().value;
const doc = sourceDocId ? collection.getDoc(sourceDocId) : null;
const doc = sourceDocId ? collection.getDoc(sourceDocId)?.getStore() : null;
if (!doc) {
return null;
@@ -206,8 +206,8 @@ export class DocsService extends Service {
schema: getAFFiNEWorkspaceSchema(),
blobCRUD: collection.blobSync,
docCRUD: {
create: (id: string) => collection.createDoc({ id }),
get: (id: string) => collection.getDoc(id),
create: (id: string) => collection.createDoc(id).getStore({ id }),
get: (id: string) => collection.getDoc(id)?.getStore({ id }) ?? null,
delete: (id: string) => collection.removeDoc(id),
},
middlewares: [replaceIdMiddleware(collection.idGenerator)],
@@ -21,7 +21,11 @@ export class DocsStore extends Store {
}
getBlockSuiteDoc(id: string) {
return this.workspaceService.workspace.docCollection.getDoc(id);
return (
this.workspaceService.workspace.docCollection
.getDoc(id)
?.getStore({ id }) ?? null
);
}
getBlocksuiteCollection() {
@@ -29,7 +33,8 @@ export class DocsStore extends Store {
}
createBlockSuiteDoc() {
return this.workspaceService.workspace.docCollection.createDoc();
const doc = this.workspaceService.workspace.docCollection.createDoc();
return doc.getStore({ id: doc.id });
}
watchDocIds() {
@@ -192,8 +192,10 @@ function generateMarkdownPreviewBuilder(
schema: getAFFiNEWorkspaceSchema(),
blobCRUD: markdownPreviewDocCollection.blobSync,
docCRUD: {
create: (id: string) => markdownPreviewDocCollection.createDoc({ id }),
get: (id: string) => markdownPreviewDocCollection.getDoc(id),
create: (id: string) =>
markdownPreviewDocCollection.createDoc(id).getStore({ id }),
get: (id: string) =>
markdownPreviewDocCollection.getDoc(id)?.getStore({ id }) ?? null,
delete: (id: string) => markdownPreviewDocCollection.removeDoc(id),
},
middlewares: [docLinkBaseURLMiddleware, titleMiddleware],
@@ -67,7 +67,7 @@ export class IntegrationWriter extends Entity {
} else {
const collection = workspace.docCollection;
const doc = collection.getDoc(docId);
const doc = collection.getDoc(docId)?.getStore();
if (!doc) throw new Error('Doc not found');
doc.workspace.meta.setDocMeta(docId, {
@@ -69,7 +69,7 @@ function useImageBlob(
['workspace', 'image', docId, blockId],
{
fetcher: async ([_, __, pageId, blockId]) => {
const page = docCollection.getDoc(pageId);
const page = docCollection.getDoc(pageId)?.getStore();
const block = page?.getBlock(blockId);
if (!block) {
return null;
@@ -4,12 +4,9 @@ import {
} from '@blocksuite/affine/global/exceptions';
import { NoopLogger } from '@blocksuite/affine/global/utils';
import {
type CreateBlocksOptions,
type Doc,
type GetBlocksOptions,
type IdGenerator,
nanoid,
type Store,
type Workspace,
type WorkspaceMeta,
} from '@blocksuite/affine/store';
@@ -113,9 +110,9 @@ export class WorkspaceImpl implements Workspace {
* If the `init` parameter is passed, a `surface`, `note`, and `paragraph` block
* will be created in the doc simultaneously.
*/
createDoc(options: CreateBlocksOptions = {}) {
const { id: docId = this.idGenerator(), query, readonly } = options;
if (this._hasDoc(docId)) {
createDoc(docId?: string): Doc {
const id = docId ?? this.idGenerator();
if (this._hasDoc(id)) {
throw new BlockSuiteError(
ErrorCode.DocCollectionError,
'doc already exists'
@@ -123,17 +120,13 @@ export class WorkspaceImpl implements Workspace {
}
this.meta.addDocMeta({
id: docId,
id,
title: '',
createDate: Date.now(),
tags: [],
});
this.slots.docCreated.next(docId);
return this.getDoc(docId, {
id: docId,
query,
readonly,
}) as Store;
this.slots.docCreated.next(id);
return this.getDoc(id) as Doc;
}
private _getDoc(docId: string): Doc | null {
@@ -141,12 +134,9 @@ export class WorkspaceImpl implements Workspace {
return space ?? null;
}
getDoc(
docId: string,
options: GetBlocksOptions = { id: docId }
): Store | null {
const collection = this._getDoc(docId);
return collection?.getStore(options) ?? null;
getDoc(docId: string): Doc | null {
const doc = this._getDoc(docId);
return doc;
}
removeDoc(docId: string) {
@@ -159,7 +159,7 @@ test.describe('Embed synced doc', () => {
const noteId = doc.addBlock('affine:note', {}, rootId);
doc.addBlock('affine:paragraph', {}, noteId);
const doc2 = collection.createDoc({ id: 'doc2' });
const doc2 = collection.createDoc('doc2').getStore();
doc2.load();
const rootId2 = doc2.addBlock('affine:page', {
title: new window.$blocksuite.store.Text('Doc 2'),
@@ -174,7 +174,7 @@ test.describe('Embed synced doc', () => {
noteId2
);
const doc3 = collection.createDoc({ id: 'doc3' });
const doc3 = collection.createDoc('doc3').getStore();
doc3.load();
const rootId3 = doc3.addBlock('affine:page', {
title: new window.$blocksuite.store.Text('Doc 3'),
@@ -260,7 +260,7 @@ test.describe('Embed synced doc', () => {
// go back to previous doc
await page.evaluate(() => {
const { collection, editor } = window;
editor.doc = collection.getDoc('doc:home')!;
editor.doc = collection.getDoc('doc:home')!.getStore();
});
const databaseFirstCell = page.locator(
+1 -1
View File
@@ -92,7 +92,7 @@ export async function switchToPage(page: Page, docId?: string) {
docId = docMetas[0].id;
}
const doc = collection.getDoc(docId);
const doc = collection.getDoc(docId)?.getStore();
if (!doc) return;
editor.doc = doc;
}, docId);
@@ -66,7 +66,7 @@ export enum ConnectorMode {
export async function getNoteRect(page: Page, noteId: string) {
const xywh: string | null = await page.evaluate(
([noteId]) => {
const doc = window.collection.getDoc('doc:home');
const doc = window.collection.getDoc('doc:home')?.getStore();
const block = doc?.getModelById(noteId);
if (block?.flavour === 'affine:note') {
return (block as NoteBlockModel).xywh;
@@ -84,7 +84,7 @@ export async function getNoteRect(page: Page, noteId: string) {
export async function getNoteProps(page: Page, noteId: string) {
const props = await page.evaluate(
([id]) => {
const doc = window.collection.getDoc('doc:home');
const doc = window.collection.getDoc('doc:home')?.getStore();
const block = doc?.getModelById(id);
if (block?.flavour === 'affine:note') {
return (block as NoteBlockModel).keys.reduce(