From c28407f77dd30c194edb9b84fec14cd00b40600d Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Tue, 10 Jan 2023 18:19:40 +0800 Subject: [PATCH 1/5] feat: synced socket upload --- packages/data-center/src/datacenter.ts | 2 +- .../data-center/src/provider/affine/affine.ts | 50 ++++++++++++++----- packages/data-center/src/provider/base.ts | 10 ++++ 3 files changed, 48 insertions(+), 14 deletions(-) diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index 8350013952..06c2a8dbab 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -306,7 +306,7 @@ export class DataCenter { this._logger( `update workspace data from ${workspaceInfo.provider} to ${providerId}` ); - applyUpdate(newWorkspace.doc, encodeStateAsUpdate(workspace.doc)); + await newProvider.assign(newWorkspace, workspace); assert(newWorkspace, 'Create workspace failed'); await currentProvider.deleteWorkspace(workspace.room); return newWorkspace.room; diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index 478aa583d5..0a3599c22c 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -3,7 +3,7 @@ import type { ProviderConstructorParams } from '../base'; import type { User, WorkspaceInfo, WorkspaceMeta } from '../../types'; import { Workspace as BlocksuiteWorkspace } from '@blocksuite/store'; import { BlockSchema } from '@blocksuite/blocks/models'; -import { applyUpdate } from 'yjs'; +import { applyUpdate, encodeStateAsUpdate } from 'yjs'; import { storage } from './storage.js'; import assert from 'assert'; import { WebsocketProvider } from './sync.js'; @@ -64,6 +64,23 @@ export class AffineProvider extends BaseProvider { } } + private _getWebsocketProvider(workspace: BlocksuiteWorkspace) { + const { doc, room } = workspace; + assert(room); + assert(doc); + let ws = this._wsMap.get(room); + if (!ws) { + const wsUrl = `${ + window.location.protocol === 'https:' ? 'wss' : 'ws' + }://${window.location.host}/api/sync/`; + ws = new WebsocketProvider(wsUrl, room, doc, { + params: { token: this._apis.token.refresh }, + }); + this._wsMap.set(room, ws); + } + return ws; + } + private async _applyCloudUpdates(blocksuiteWorkspace: BlocksuiteWorkspace) { const { doc, room: workspaceId } = blocksuiteWorkspace; assert(workspaceId, 'Blocksuite Workspace without room(workspaceId).'); @@ -78,20 +95,10 @@ export class AffineProvider extends BaseProvider { override async warpWorkspace(workspace: BlocksuiteWorkspace) { await this._applyCloudUpdates(workspace); - const { doc, room } = workspace; + const { room } = workspace; assert(room); this.linkLocal(workspace); - - let ws = this._wsMap.get(room); - if (!ws) { - const wsUrl = `${ - window.location.protocol === 'https:' ? 'wss' : 'ws' - }://${window.location.host}/api/sync/`; - ws = new WebsocketProvider(wsUrl, room, doc, { - params: { token: this._apis.token.refresh }, - }); - this._wsMap.set(room, ws); - } + const ws = this._getWebsocketProvider(workspace); // close all websocket links Array.from(this._wsMap.entries()).forEach(([id, ws]) => { if (id !== room) { @@ -335,4 +342,21 @@ export class AffineProvider extends BaseProvider { } : null; } + + public override async assign( + to: BlocksuiteWorkspace, + from: BlocksuiteWorkspace + ): Promise { + assert(to.room, 'Blocksuite Workspace without room(workspaceId).'); + const ws = this._getWebsocketProvider(to); + applyUpdate(to.doc, encodeStateAsUpdate(from.doc)); + await new Promise((resolve, reject) => { + ws.once('synced', () => { + resolve(); + }); + ws.once('lost-connection', () => reject()); + ws.once('connection-error', () => reject()); + }); + return to; + } } diff --git a/packages/data-center/src/provider/base.ts b/packages/data-center/src/provider/base.ts index f9851098df..8a6668edd5 100644 --- a/packages/data-center/src/provider/base.ts +++ b/packages/data-center/src/provider/base.ts @@ -196,4 +196,14 @@ export class BaseProvider { ): Promise { return workspace; } + + /** + * merge one workspaces to another + * @param workspace + * @returns + */ + public async assign(to: BlocksuiteWorkspace, from: BlocksuiteWorkspace) { + from; + return to; + } } From 22606966759cc5ca806fe44ba65c56cb1dd1e947 Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Tue, 10 Jan 2023 18:32:06 +0800 Subject: [PATCH 2/5] feat: remove not used --- packages/data-center/src/datacenter.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index 06c2a8dbab..349dab9e17 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -7,7 +7,6 @@ import { AffineProvider } from './provider'; import type { Message, WorkspaceMeta } from './types'; import assert from 'assert'; import { getLogger } from './logger'; -import { applyUpdate, encodeStateAsUpdate } from 'yjs'; import { createBlocksuiteWorkspace } from './utils/index.js'; import { MessageCenter } from './message'; From e13d27ad9c31fdccdbbe1e4023630fe14fd26623 Mon Sep 17 00:00:00 2001 From: alt0 Date: Tue, 10 Jan 2023 18:37:24 +0800 Subject: [PATCH 3/5] refactor: add workspace unit --- packages/data-center/src/datacenter.ts | 55 ++++--- packages/data-center/src/index.ts | 2 +- packages/data-center/src/message/index.ts | 4 +- packages/data-center/src/message/message.ts | 2 +- .../data-center/src/provider/affine/affine.ts | 34 ++-- .../src/provider/affine/apis/workspace.ts | 1 - packages/data-center/src/provider/base.ts | 27 ++-- .../src/provider/local/local.spec.ts | 15 +- .../data-center/src/provider/local/local.ts | 36 +++-- packages/data-center/src/provider/utils.ts | 3 + packages/data-center/src/types/index.ts | 22 +-- .../src/workspace-meta-collection.spec.ts | 50 ------ .../src/workspace-meta-collection.ts | 127 --------------- .../src/workspace-unit-collection.spec.ts | 60 +++++++ .../src/workspace-unit-collection.ts | 152 ++++++++++++++++++ packages/data-center/src/workspace-unit.ts | 64 ++++++++ 16 files changed, 386 insertions(+), 268 deletions(-) delete mode 100644 packages/data-center/src/workspace-meta-collection.spec.ts delete mode 100644 packages/data-center/src/workspace-meta-collection.ts create mode 100644 packages/data-center/src/workspace-unit-collection.spec.ts create mode 100644 packages/data-center/src/workspace-unit-collection.ts create mode 100644 packages/data-center/src/workspace-unit.ts diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index 8350013952..d65ddc3be4 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -1,10 +1,14 @@ -import { WorkspaceMetaCollection } from './workspace-meta-collection.js'; -import type { WorkspaceMetaCollectionChangeEvent } from './workspace-meta-collection'; +import { WorkspaceUnitCollection } from './workspace-unit-collection.js'; +import type { WorkspaceUnitCollectionChangeEvent } from './workspace-unit-collection'; import { Workspace as BlocksuiteWorkspace } from '@blocksuite/store'; -import { BaseProvider } from './provider/base'; +import type { + BaseProvider, + CreateWorkspaceInfoParams, + UpdateWorkspaceMetaParams, +} from './provider/base'; import { LocalProvider } from './provider/local/local'; import { AffineProvider } from './provider'; -import type { Message, WorkspaceMeta } from './types'; +import type { Message } from './types'; import assert from 'assert'; import { getLogger } from './logger'; import { applyUpdate, encodeStateAsUpdate } from 'yjs'; @@ -16,7 +20,7 @@ import { MessageCenter } from './message'; * @classdesc Data center is made for managing different providers for business */ export class DataCenter { - private readonly _workspaceMetaCollection = new WorkspaceMetaCollection(); + private readonly _workspaceUnitCollection = new WorkspaceUnitCollection(); private readonly _logger = getLogger('dc'); private _workspaceInstances: Map = new Map(); private _messageCenter = new MessageCenter(); @@ -35,7 +39,7 @@ export class DataCenter { const getInitParams = () => { return { logger: dc._logger, - workspaces: dc._workspaceMetaCollection.createScope(), + workspaces: dc._workspaceUnitCollection.createScope(), messageCenter: dc._messageCenter, }; }; @@ -68,7 +72,7 @@ export class DataCenter { } public get workspaces() { - return this._workspaceMetaCollection.workspaces; + return this._workspaceUnitCollection.workspaces; } public async refreshWorkspaces() { @@ -82,17 +86,15 @@ export class DataCenter { * @param {string} name workspace name * @returns {Promise} */ - public async createWorkspace(workspaceMeta: WorkspaceMeta) { + public async createWorkspace(params: CreateWorkspaceInfoParams) { assert( this._mainProvider, 'There is no provider. You should add provider first.' ); - const workspaceInfo = await this._mainProvider.createWorkspaceInfo( - workspaceMeta - ); + const workspaceMeta = await this._mainProvider.createWorkspaceInfo(params); - const workspace = createBlocksuiteWorkspace(workspaceInfo.id); + const workspace = createBlocksuiteWorkspace(workspaceMeta.id); await this._mainProvider.createWorkspace(workspace, workspaceMeta); return workspace; @@ -103,7 +105,7 @@ export class DataCenter { * @param {string} workspaceId workspace id */ public async deleteWorkspace(workspaceId: string) { - const workspaceInfo = this._workspaceMetaCollection.find(workspaceId); + const workspaceInfo = this._workspaceUnitCollection.find(workspaceId); assert(workspaceInfo, 'Workspace not found'); const provider = this.providerMap.get(workspaceInfo.provider); assert(provider, `Workspace exists, but we couldn't find its provider.`); @@ -115,7 +117,7 @@ export class DataCenter { * @param {string} workspaceId workspace id */ private _getBlocksuiteWorkspace(workspaceId: string) { - const workspaceInfo = this._workspaceMetaCollection.find(workspaceId); + const workspaceInfo = this._workspaceUnitCollection.find(workspaceId); assert(workspaceInfo, 'Workspace not found'); return ( this._workspaceInstances.get(workspaceId) || @@ -149,7 +151,7 @@ export class DataCenter { * @returns {Promise} */ public async loadWorkspace(workspaceId: string) { - const workspaceInfo = this._workspaceMetaCollection.find(workspaceId); + const workspaceInfo = this._workspaceUnitCollection.find(workspaceId); assert(workspaceInfo, 'Workspace not found'); const currentProvider = this.providerMap.get(workspaceInfo.provider); if (currentProvider) { @@ -180,9 +182,9 @@ export class DataCenter { * @param {Function} callback callback function */ public async onWorkspacesChange( - callback: (workspaces: WorkspaceMetaCollectionChangeEvent) => void + callback: (workspaces: WorkspaceUnitCollectionChangeEvent) => void ) { - this._workspaceMetaCollection.on('change', callback); + this._workspaceUnitCollection.on('change', callback); } /** @@ -191,11 +193,11 @@ export class DataCenter { * @param {BlocksuiteWorkspace} workspace workspace instance */ public async updateWorkspaceMeta( - { name, avatar }: Partial, + { name, avatar }: UpdateWorkspaceMetaParams, workspace: BlocksuiteWorkspace ) { assert(workspace?.room, 'No workspace to set meta'); - const update: Partial = {}; + const update: Partial = {}; if (name) { workspace.meta.setName(name); update.name = name; @@ -205,7 +207,7 @@ export class DataCenter { update.avatar = avatar; } // may run for change workspace meta - const workspaceInfo = this._workspaceMetaCollection.find(workspace.room); + const workspaceInfo = this._workspaceUnitCollection.find(workspace.room); assert(workspaceInfo, 'Workspace not found'); const provider = this.providerMap.get(workspaceInfo.provider); provider?.updateWorkspaceMeta(workspace.room, update); @@ -217,7 +219,7 @@ export class DataCenter { * @param id workspace id */ public async leaveWorkspace(workspaceId: string) { - const workspaceInfo = this._workspaceMetaCollection.find(workspaceId); + const workspaceInfo = this._workspaceUnitCollection.find(workspaceId); assert(workspaceInfo, 'Workspace not found'); const provider = this.providerMap.get(workspaceInfo.provider); if (provider) { @@ -227,7 +229,7 @@ export class DataCenter { } public async setWorkspacePublish(workspaceId: string, isPublish: boolean) { - const workspaceInfo = this._workspaceMetaCollection.find(workspaceId); + const workspaceInfo = this._workspaceUnitCollection.find(workspaceId); assert(workspaceInfo, 'Workspace not found'); const provider = this.providerMap.get(workspaceInfo.provider); if (provider) { @@ -236,7 +238,7 @@ export class DataCenter { } public async inviteMember(id: string, email: string) { - const workspaceInfo = this._workspaceMetaCollection.find(id); + const workspaceInfo = this._workspaceUnitCollection.find(id); assert(workspaceInfo, 'Workspace not found'); const provider = this.providerMap.get(workspaceInfo.provider); if (provider) { @@ -249,7 +251,7 @@ export class DataCenter { * @param {number} permissionId permission id */ public async removeMember(workspaceId: string, permissionId: number) { - const workspaceInfo = this._workspaceMetaCollection.find(workspaceId); + const workspaceInfo = this._workspaceUnitCollection.find(workspaceId); assert(workspaceInfo, 'Workspace not found'); const provider = this.providerMap.get(workspaceInfo.provider); if (provider) { @@ -280,7 +282,7 @@ export class DataCenter { providerId: string ) { assert(workspace.room, 'No workspace id'); - const workspaceInfo = this._workspaceMetaCollection.find(workspace.room); + const workspaceInfo = this._workspaceUnitCollection.find(workspace.room); assert(workspaceInfo, 'Workspace not found'); if (workspaceInfo.provider === providerId) { this._logger('Workspace provider is same'); @@ -293,11 +295,12 @@ export class DataCenter { this._logger(`create ${providerId} workspace: `, workspaceInfo.name); const newWorkspaceInfo = await newProvider.createWorkspaceInfo({ name: workspaceInfo.name, - avatar: workspaceInfo.avatar, + // avatar: workspaceInfo.avatar, }); const newWorkspace = createBlocksuiteWorkspace(newWorkspaceInfo.id); // TODO optimize this function await newProvider.createWorkspace(newWorkspace, { + ...newWorkspaceInfo, name: workspaceInfo.name, avatar: workspaceInfo.avatar, }); diff --git a/packages/data-center/src/index.ts b/packages/data-center/src/index.ts index f758d9c336..029dffd7ea 100644 --- a/packages/data-center/src/index.ts +++ b/packages/data-center/src/index.ts @@ -26,6 +26,6 @@ const _initializeDataCenter = () => { export const getDataCenter = _initializeDataCenter(); export type { AccessTokenMessage } from './provider/affine/apis'; -export type { WorkspaceInfo } from './types'; +export { WorkspaceUnit } from './workspace-unit'; export { getLogger } from './logger'; export * from './message'; diff --git a/packages/data-center/src/message/index.ts b/packages/data-center/src/message/index.ts index b04581df15..7d42b90d8b 100644 --- a/packages/data-center/src/message/index.ts +++ b/packages/data-center/src/message/index.ts @@ -1,2 +1,2 @@ -export { MessageCenter } from './message'; -export { MessageCode } from './code'; +export { MessageCenter } from './message.js'; +export { MessageCode } from './code.js'; diff --git a/packages/data-center/src/message/message.ts b/packages/data-center/src/message/message.ts index 34d6870211..6de9c75795 100644 --- a/packages/data-center/src/message/message.ts +++ b/packages/data-center/src/message/message.ts @@ -1,6 +1,6 @@ import { Observable } from 'lib0/observable'; import { Message } from '../types'; -import { MessageCode } from './code'; +import { MessageCode } from './code.js'; export class MessageCenter extends Observable { constructor() { diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index 478aa583d5..52a14a60a0 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -1,6 +1,11 @@ import { BaseProvider } from '../base.js'; -import type { ProviderConstructorParams } from '../base'; -import type { User, WorkspaceInfo, WorkspaceMeta } from '../../types'; +import type { + ProviderConstructorParams, + CreateWorkspaceInfoParams, + UpdateWorkspaceMetaParams, + WorkspaceMeta0, +} from '../base'; +import type { User } from '../../types'; import { Workspace as BlocksuiteWorkspace } from '@blocksuite/store'; import { BlockSchema } from '@blocksuite/blocks/models'; import { applyUpdate } from 'yjs'; @@ -115,12 +120,13 @@ export class AffineProvider extends BaseProvider { return []; } const workspacesList = await this._apis.getWorkspaces(); - const workspaces: WorkspaceInfo[] = workspacesList.map(w => { + const workspaces: WorkspaceMeta0[] = workspacesList.map(w => { return { ...w, memberCount: 0, name: '', provider: 'affine', + syncMode: 'core', }; }); const workspaceInstances = workspaces.map(({ id }) => { @@ -268,19 +274,17 @@ export class AffineProvider extends BaseProvider { } public override async createWorkspaceInfo( - meta: WorkspaceMeta - ): Promise { - const { id } = await this._apis.createWorkspace( - meta as Required - ); + meta: CreateWorkspaceInfoParams + ): Promise { + const { id } = await this._apis.createWorkspace(meta); - const workspaceInfo: WorkspaceInfo = { + const workspaceInfo: WorkspaceMeta0 = { name: meta.name, id: id, - isPublish: false, + published: false, avatar: '', owner: await this.getUserInfo(), - isLocal: true, + syncMode: 'core', memberCount: 1, provider: 'affine', }; @@ -289,7 +293,7 @@ export class AffineProvider extends BaseProvider { public override async createWorkspace( blocksuiteWorkspace: BlocksuiteWorkspace, - meta: WorkspaceMeta + meta: WorkspaceMeta0 ): Promise { const workspaceId = blocksuiteWorkspace.room; assert(workspaceId, 'Blocksuite Workspace without room(workspaceId).'); @@ -298,13 +302,13 @@ export class AffineProvider extends BaseProvider { this._applyCloudUpdates(blocksuiteWorkspace); this.linkLocal(blocksuiteWorkspace); - const workspaceInfo: WorkspaceInfo = { + const workspaceInfo: WorkspaceMeta0 = { name: meta.name, id: workspaceId, - isPublish: false, + published: false, avatar: '', owner: undefined, - isLocal: true, + syncMode: 'core', memberCount: 1, provider: 'affine', }; diff --git a/packages/data-center/src/provider/affine/apis/workspace.ts b/packages/data-center/src/provider/affine/apis/workspace.ts index 0c145928d5..8bdc25b21f 100644 --- a/packages/data-center/src/provider/affine/apis/workspace.ts +++ b/packages/data-center/src/provider/affine/apis/workspace.ts @@ -79,7 +79,6 @@ export async function getWorkspaceMembers( export interface CreateWorkspaceParams { name: string; - avatar: string; } export async function createWorkspace( diff --git a/packages/data-center/src/provider/base.ts b/packages/data-center/src/provider/base.ts index f9851098df..0f6a968a69 100644 --- a/packages/data-center/src/provider/base.ts +++ b/packages/data-center/src/provider/base.ts @@ -1,7 +1,8 @@ import { Workspace as BlocksuiteWorkspace, uuidv4 } from '@blocksuite/store'; import { MessageCenter } from '../message'; -import { Logger, User, WorkspaceInfo, WorkspaceMeta } from '../types'; -import type { WorkspaceMetaCollectionScope } from '../workspace-meta-collection'; +import { Logger, User } from '../types'; +import type { WorkspaceUnitCollectionScope } from '../workspace-unit-collection'; +import type { WorkspaceUnitCtorParams } from '../workspace-unit'; const defaultLogger = () => { return; @@ -9,13 +10,19 @@ const defaultLogger = () => { export interface ProviderConstructorParams { logger?: Logger; - workspaces: WorkspaceMetaCollectionScope; + workspaces: WorkspaceUnitCollectionScope; messageCenter: MessageCenter; } +export type WorkspaceMeta0 = WorkspaceUnitCtorParams; +export type CreateWorkspaceInfoParams = Pick; +export type UpdateWorkspaceMetaParams = Partial< + Pick +>; + export class BaseProvider { public readonly id: string = 'base'; - protected _workspaces!: WorkspaceMetaCollectionScope; + protected _workspaces!: WorkspaceUnitCollectionScope; protected _logger!: Logger; protected _messageCenter!: MessageCenter; @@ -37,8 +44,8 @@ export class BaseProvider { } public async createWorkspaceInfo( - meta: WorkspaceMeta - ): Promise { + params: CreateWorkspaceInfoParams + ): Promise { throw new Error(`provider: ${this.id} createWorkspaceInfo Not implemented`); } @@ -70,7 +77,7 @@ export class BaseProvider { /** * load workspaces **/ - public async loadWorkspaces(): Promise { + public async loadWorkspaces(): Promise { throw new Error(`provider: ${this.id} loadWorkSpace Not implemented`); } @@ -157,10 +164,10 @@ export class BaseProvider { */ public async updateWorkspaceMeta( id: string, - meta: Partial + params: UpdateWorkspaceMetaParams ): Promise { id; - meta; + params; return; } @@ -170,7 +177,7 @@ export class BaseProvider { */ public async createWorkspace( blocksuiteWorkspace: BlocksuiteWorkspace, - meta: WorkspaceMeta + meta: WorkspaceMeta0 ): Promise { return blocksuiteWorkspace; } diff --git a/packages/data-center/src/provider/local/local.spec.ts b/packages/data-center/src/provider/local/local.spec.ts index eff462ef86..e60ce31aae 100644 --- a/packages/data-center/src/provider/local/local.spec.ts +++ b/packages/data-center/src/provider/local/local.spec.ts @@ -1,13 +1,15 @@ import { test, expect } from '@playwright/test'; -import { WorkspaceMetaCollection } from '../../workspace-meta-collection.js'; +import { WorkspaceUnitCollection } from '../../workspace-unit-collection.js'; import { LocalProvider } from './local.js'; import { createBlocksuiteWorkspace } from '../../utils/index.js'; +import { MessageCenter } from '../../message/index.js'; import 'fake-indexeddb/auto'; test.describe.serial('local provider', () => { - const workspaceMetaCollection = new WorkspaceMetaCollection(); + const workspaceMetaCollection = new WorkspaceUnitCollection(); const provider = new LocalProvider({ workspaces: workspaceMetaCollection.createScope(), + messageCenter: new MessageCenter(), }); const workspaceName = 'workspace-test'; @@ -16,23 +18,20 @@ test.describe.serial('local provider', () => { test('create workspace', async () => { const workspaceInfo = await provider.createWorkspaceInfo({ name: workspaceName, - avatar: 'avatar-url-test', }); workspaceId = workspaceInfo.id; const blocksuiteWorkspace = createBlocksuiteWorkspace(workspaceId); - await provider.createWorkspace(blocksuiteWorkspace, { - name: workspaceName, - avatar: 'avatar-url-test', - }); + await provider.createWorkspace(blocksuiteWorkspace, workspaceInfo); expect(workspaceMetaCollection.workspaces.length).toEqual(1); expect(workspaceMetaCollection.workspaces[0].name).toEqual(workspaceName); }); test('workspace list cache', async () => { - const workspacesMetaCollection1 = new WorkspaceMetaCollection(); + const workspacesMetaCollection1 = new WorkspaceUnitCollection(); const provider1 = new LocalProvider({ workspaces: workspacesMetaCollection1.createScope(), + messageCenter: new MessageCenter(), }); await provider1.loadWorkspaces(); expect(workspacesMetaCollection1.workspaces.length).toEqual(1); diff --git a/packages/data-center/src/provider/local/local.ts b/packages/data-center/src/provider/local/local.ts index bf8aa31941..f87d7c95fb 100644 --- a/packages/data-center/src/provider/local/local.ts +++ b/packages/data-center/src/provider/local/local.ts @@ -1,7 +1,11 @@ import { BaseProvider } from '../base.js'; -import type { ProviderConstructorParams } from '../base'; +import type { + ProviderConstructorParams, + WorkspaceMeta0, + UpdateWorkspaceMetaParams, + CreateWorkspaceInfoParams, +} from '../base'; import { varStorage as storage } from 'lib0/storage'; -import { WorkspaceInfo, WorkspaceMeta } from '../../types'; import { Workspace as BlocksuiteWorkspace, uuidv4 } from '@blocksuite/store'; import { IndexedDBProvider } from './indexeddb.js'; import assert from 'assert'; @@ -18,7 +22,7 @@ export class LocalProvider extends BaseProvider { this.loadWorkspaces(); } - private _storeWorkspaces(workspaces: WorkspaceInfo[]) { + private _storeWorkspaces(workspaces: WorkspaceMeta0[]) { storage.setItem(WORKSPACE_KEY, JSON.stringify(workspaces)); } @@ -40,12 +44,12 @@ export class LocalProvider extends BaseProvider { return workspace; } - override loadWorkspaces(): Promise { + override loadWorkspaces(): Promise { const workspaceStr = storage.getItem(WORKSPACE_KEY); - let workspaces: WorkspaceInfo[] = []; + let workspaces: WorkspaceMeta0[] = []; if (workspaceStr) { try { - workspaces = JSON.parse(workspaceStr) as WorkspaceInfo[]; + workspaces = JSON.parse(workspaceStr) as WorkspaceMeta0[]; workspaces.forEach(workspace => { this._workspaces.add(workspace); }); @@ -69,22 +73,22 @@ export class LocalProvider extends BaseProvider { public override async updateWorkspaceMeta( id: string, - meta: Partial + meta: UpdateWorkspaceMetaParams ) { this._workspaces.update(id, meta); this._storeWorkspaces(this._workspaces.list()); } public override async createWorkspaceInfo( - meta: WorkspaceMeta - ): Promise { - const workspaceInfo: WorkspaceInfo = { + meta: CreateWorkspaceInfoParams + ): Promise { + const workspaceInfo: WorkspaceMeta0 = { name: meta.name, id: uuidv4(), - isPublish: false, + published: false, avatar: '', owner: undefined, - isLocal: true, + syncMode: 'core', memberCount: 1, provider: 'local', }; @@ -93,20 +97,20 @@ export class LocalProvider extends BaseProvider { public override async createWorkspace( blocksuiteWorkspace: BlocksuiteWorkspace, - meta: WorkspaceMeta + meta: WorkspaceMeta0 ): Promise { const workspaceId = blocksuiteWorkspace.room; assert(workspaceId, 'Blocksuite Workspace without room(workspaceId).'); assert(meta.name, 'Workspace name is required'); this._logger('Creating affine workspace'); - const workspaceInfo: WorkspaceInfo = { + const workspaceInfo: WorkspaceMeta0 = { name: meta.name, id: workspaceId, - isPublish: false, + published: false, avatar: '', owner: undefined, - isLocal: true, + syncMode: 'core', memberCount: 1, provider: 'local', }; diff --git a/packages/data-center/src/provider/utils.ts b/packages/data-center/src/provider/utils.ts index d8e5f6d058..c193719cc2 100644 --- a/packages/data-center/src/provider/utils.ts +++ b/packages/data-center/src/provider/utils.ts @@ -5,6 +5,9 @@ import { getDefaultHeadImgBlob } from '../utils/index.js'; export const setDefaultAvatar = async ( blocksuiteWorkspace: BlocksuiteWorkspace ) => { + if (typeof document === 'undefined') { + return; + } const blob = await getDefaultHeadImgBlob(blocksuiteWorkspace.meta.name); const blobStorage = await blocksuiteWorkspace.blobs; assert(blobStorage, 'No blob storage'); diff --git a/packages/data-center/src/types/index.ts b/packages/data-center/src/types/index.ts index 29e3a2f255..ea85ded82f 100644 --- a/packages/data-center/src/types/index.ts +++ b/packages/data-center/src/types/index.ts @@ -1,15 +1,15 @@ import { getLogger } from '../logger'; -export type WorkspaceInfo = { - name: string; - id: string; - isPublish?: boolean; - avatar?: string; - owner?: User; - isLocal?: boolean; - memberCount: number; - provider: string; -}; +// export type WorkspaceInfo = { +// name: string; +// id: string; +// isPublish?: boolean; +// avatar?: string; +// owner?: User; +// isLocal?: boolean; +// memberCount: number; +// provider: string; +// }; export type User = { name: string; @@ -18,7 +18,7 @@ export type User = { avatar: string; }; -export type WorkspaceMeta = Pick; +// export type WorkspaceMeta = Pick; export type Logger = ReturnType; diff --git a/packages/data-center/src/workspace-meta-collection.spec.ts b/packages/data-center/src/workspace-meta-collection.spec.ts deleted file mode 100644 index afb3eb65f5..0000000000 --- a/packages/data-center/src/workspace-meta-collection.spec.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { test, expect } from '@playwright/test'; -import { WorkspaceMetaCollection } from './workspace-meta-collection.js'; -import type { WorkspaceMetaCollectionChangeEvent } from './workspace-meta-collection'; - -test.describe.serial('workspace meta collection observable', () => { - const workspaces = new WorkspaceMetaCollection(); - - const scope = workspaces.createScope(); - - test('add workspace', () => { - workspaces.once('change', (event: WorkspaceMetaCollectionChangeEvent) => { - expect(event.added?.id).toEqual('123'); - }); - scope.add({ - id: '123', - name: 'test', - memberCount: 1, - provider: '', - }); - }); - - test('list workspace', () => { - const list = scope.list(); - expect(list.length).toEqual(1); - expect(list[0].id).toEqual('123'); - }); - - test('get workspace', () => { - expect(scope.get('123')?.id).toEqual('123'); - }); - - test('update workspace', () => { - workspaces.once('change', (event: WorkspaceMetaCollectionChangeEvent) => { - expect(event.updated?.name).toEqual('demo'); - }); - scope.update('123', { name: 'demo' }); - }); - - test('get workspace form other scope', () => { - const scope1 = workspaces.createScope(); - expect(scope1.get('123')).toBeFalsy(); - }); - - test('delete workspace', () => { - workspaces.once('change', (event: WorkspaceMetaCollectionChangeEvent) => { - expect(event.deleted?.id).toEqual('123'); - }); - scope.remove('123'); - }); -}); diff --git a/packages/data-center/src/workspace-meta-collection.ts b/packages/data-center/src/workspace-meta-collection.ts deleted file mode 100644 index 6b7ce4a350..0000000000 --- a/packages/data-center/src/workspace-meta-collection.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { Observable } from 'lib0/observable'; -import type { WorkspaceInfo, WorkspaceMeta } from './types'; - -export interface WorkspaceMetaCollectionScope { - get: (workspaceId: string) => WorkspaceInfo | undefined; - list: () => WorkspaceInfo[]; - add: (workspace: WorkspaceInfo) => void; - remove: (workspaceId: string) => boolean; - clear: () => void; - update: (workspaceId: string, workspaceMeta: Partial) => void; -} - -export interface WorkspaceMetaCollectionChangeEvent { - added?: WorkspaceInfo; - deleted?: WorkspaceInfo; - updated?: WorkspaceInfo; -} - -export class WorkspaceMetaCollection extends Observable<'change'> { - private _workspacesMap = new Map(); - - get workspaces(): WorkspaceInfo[] { - return Array.from(this._workspacesMap.values()); - } - - find(workspaceId: string) { - return this._workspacesMap.get(workspaceId); - } - - createScope(): WorkspaceMetaCollectionScope { - const scopedWorkspaceIds = new Set(); - - const get = (workspaceId: string) => { - if (!scopedWorkspaceIds.has(workspaceId)) { - return; - } - return this._workspacesMap.get(workspaceId); - }; - - const add = (workspace: WorkspaceInfo) => { - if (this._workspacesMap.has(workspace.id)) { - throw new Error(`Duplicate workspace id.`); - } - this._workspacesMap.set(workspace.id, workspace); - scopedWorkspaceIds.add(workspace.id); - - this.emit('change', [ - { - added: workspace, - } as WorkspaceMetaCollectionChangeEvent, - ]); - }; - - const remove = (workspaceId: string) => { - if (!scopedWorkspaceIds.has(workspaceId)) { - return true; - } - - const workspace = this._workspacesMap.get(workspaceId); - if (workspace) { - const ret = this._workspacesMap.delete(workspaceId); - // If deletion failed, return. - if (!ret) { - return ret; - } - - scopedWorkspaceIds.delete(workspaceId); - - this.emit('change', [ - { - deleted: workspace, - } as WorkspaceMetaCollectionChangeEvent, - ]); - } - return true; - }; - - const clear = () => { - scopedWorkspaceIds.forEach(id => { - remove(id); - }); - }; - - const update = ( - workspaceId: string, - workspaceMeta: Partial - ) => { - if (!scopedWorkspaceIds.has(workspaceId)) { - return true; - } - - const workspace = this._workspacesMap.get(workspaceId); - if (!workspace) { - return true; - } - - this._workspacesMap.set(workspaceId, { ...workspace, ...workspaceMeta }); - - this.emit('change', [ - { - updated: this._workspacesMap.get(workspaceId), - } as WorkspaceMetaCollectionChangeEvent, - ]); - }; - - // TODO: need to optimize - const list = () => { - const workspaces: WorkspaceInfo[] = []; - scopedWorkspaceIds.forEach(id => { - const workspace = this._workspacesMap.get(id); - if (workspace) { - workspaces.push(workspace); - } - }); - return workspaces; - }; - - return { - get, - list, - add, - remove, - clear, - update, - }; - } -} diff --git a/packages/data-center/src/workspace-unit-collection.spec.ts b/packages/data-center/src/workspace-unit-collection.spec.ts new file mode 100644 index 0000000000..06eee95bd0 --- /dev/null +++ b/packages/data-center/src/workspace-unit-collection.spec.ts @@ -0,0 +1,60 @@ +import { test, expect } from '@playwright/test'; +import { WorkspaceUnitCollection } from './workspace-unit-collection.js'; +import type { WorkspaceUnitCollectionChangeEvent } from './workspace-unit-collection'; + +test.describe.serial('workspace meta collection observable', () => { + const workspaceUnitCollection = new WorkspaceUnitCollection(); + + const scope = workspaceUnitCollection.createScope(); + + test('add workspace', () => { + workspaceUnitCollection.once( + 'change', + (event: WorkspaceUnitCollectionChangeEvent) => { + expect(event.added?.id).toEqual('123'); + } + ); + scope.add({ + id: '123', + name: 'test', + memberCount: 1, + provider: '', + syncMode: 'core', + }); + }); + + test('list workspace', () => { + const list = scope.list(); + expect(list.length).toEqual(1); + expect(list[0].id).toEqual('123'); + }); + + test('get workspace', () => { + expect(scope.get('123')?.id).toEqual('123'); + }); + + test('update workspace', () => { + workspaceUnitCollection.once( + 'change', + (event: WorkspaceUnitCollectionChangeEvent) => { + expect(event.updated?.name).toEqual('demo'); + } + ); + scope.update('123', { name: 'demo' }); + }); + + test('get workspace form other scope', () => { + const scope1 = workspaceUnitCollection.createScope(); + expect(scope1.get('123')).toBeFalsy(); + }); + + test('delete workspace', () => { + workspaceUnitCollection.once( + 'change', + (event: WorkspaceUnitCollectionChangeEvent) => { + expect(event.deleted?.id).toEqual('123'); + } + ); + scope.remove('123'); + }); +}); diff --git a/packages/data-center/src/workspace-unit-collection.ts b/packages/data-center/src/workspace-unit-collection.ts new file mode 100644 index 0000000000..e4dedad8c7 --- /dev/null +++ b/packages/data-center/src/workspace-unit-collection.ts @@ -0,0 +1,152 @@ +import { Observable } from 'lib0/observable'; +import { WorkspaceUnit } from './workspace-unit.js'; +import type { + WorkspaceUnitCtorParams, + UpdateWorkspaceUnitParams, +} from './workspace-unit'; + +export interface WorkspaceUnitCollectionScope { + get: (workspaceId: string) => WorkspaceUnit | undefined; + list: () => WorkspaceUnit[]; + add: (workspace: WorkspaceUnitCtorParams) => void; + remove: (workspaceId: string) => boolean; + clear: () => void; + update: ( + workspaceId: string, + workspaceMeta: UpdateWorkspaceUnitParams + ) => void; +} + +export interface WorkspaceUnitCollectionChangeEvent { + added?: WorkspaceUnit; + deleted?: WorkspaceUnit; + updated?: WorkspaceUnit; +} + +export class WorkspaceUnitCollection { + private _events = new Observable(); + private _workspaceUnitMap = new Map(); + + get workspaces(): WorkspaceUnit[] { + return Array.from(this._workspaceUnitMap.values()); + } + + public on( + type: 'change', + callback: (event: WorkspaceUnitCollectionChangeEvent) => void + ) { + this._events.on(type, callback); + } + + public once( + type: 'change', + callback: (event: WorkspaceUnitCollectionChangeEvent) => void + ) { + this._events.once(type, callback); + } + + find(workspaceId: string) { + return this._workspaceUnitMap.get(workspaceId); + } + + createScope(): WorkspaceUnitCollectionScope { + const scopedWorkspaceIds = new Set(); + + const get = (workspaceId: string) => { + if (!scopedWorkspaceIds.has(workspaceId)) { + return; + } + return this._workspaceUnitMap.get(workspaceId); + }; + + const add = (workspace: WorkspaceUnitCtorParams) => { + if (this._workspaceUnitMap.has(workspace.id)) { + throw new Error(`Duplicate workspace id.`); + } + + const workspaceUnit = new WorkspaceUnit(workspace); + this._workspaceUnitMap.set(workspace.id, workspaceUnit); + + scopedWorkspaceIds.add(workspace.id); + + this._events.emit('change', [ + { + added: workspaceUnit, + } as WorkspaceUnitCollectionChangeEvent, + ]); + }; + + const remove = (workspaceId: string) => { + if (!scopedWorkspaceIds.has(workspaceId)) { + return true; + } + + const workspaceUnit = this._workspaceUnitMap.get(workspaceId); + if (workspaceUnit) { + const ret = this._workspaceUnitMap.delete(workspaceId); + // If deletion failed, return. + if (!ret) { + return ret; + } + + scopedWorkspaceIds.delete(workspaceId); + + this._events.emit('change', [ + { + deleted: workspaceUnit, + } as WorkspaceUnitCollectionChangeEvent, + ]); + } + return true; + }; + + const clear = () => { + scopedWorkspaceIds.forEach(id => { + remove(id); + }); + }; + + const update = ( + workspaceId: string, + workspaceMeta: UpdateWorkspaceUnitParams + ) => { + if (!scopedWorkspaceIds.has(workspaceId)) { + return true; + } + + const workspaceUnit = this._workspaceUnitMap.get(workspaceId); + if (!workspaceUnit) { + return true; + } + + workspaceUnit.update(workspaceMeta); + + this._events.emit('change', [ + { + updated: workspaceUnit, + } as WorkspaceUnitCollectionChangeEvent, + ]); + }; + + // TODO: need to optimize + const list = () => { + const workspaceUnits: WorkspaceUnit[] = []; + scopedWorkspaceIds.forEach(id => { + const workspaceUnit = this._workspaceUnitMap.get(id); + if (workspaceUnit) { + workspaceUnits.push(workspaceUnit); + } + }); + return workspaceUnits; + }; + + return { + get, + list, + add, + remove, + clear, + update, + }; + } +} diff --git a/packages/data-center/src/workspace-unit.ts b/packages/data-center/src/workspace-unit.ts new file mode 100644 index 0000000000..527e8647ef --- /dev/null +++ b/packages/data-center/src/workspace-unit.ts @@ -0,0 +1,64 @@ +import { Workspace as BlocksuiteWorkspace } from '@blocksuite/store'; +import type { User } from './types'; + +export type SyncMode = 'all' | 'core'; + +export interface WorkspaceUnitCtorParams { + id: string; + name: string; + avatar?: string; + owner?: User; + published?: boolean; + memberCount: number; + provider: string; + syncMode: SyncMode; + + blocksuiteWorkspace?: BlocksuiteWorkspace; +} + +export type UpdateWorkspaceUnitParams = Partial< + Omit +>; + +export class WorkspaceUnit { + public readonly id: string; + public name!: string; + public avatar?: string; + public owner?: User; + public published?: boolean; + public memberCount!: number; + public provider!: string; + public syncMode: 'all' | 'core' = 'core'; + + private _blocksuiteWorkspace?: BlocksuiteWorkspace; + + constructor(params: WorkspaceUnitCtorParams) { + this.id = params.id; + this.update(params); + } + + get blocksuiteWorkspace() { + return this._blocksuiteWorkspace; + } + + setBlocksuiteWorkspace(blocksuiteWorkspace: BlocksuiteWorkspace) { + if (blocksuiteWorkspace?.room !== this.id) { + throw new Error('Workspace id inconsistent.'); + } + this._blocksuiteWorkspace = blocksuiteWorkspace; + } + + update(params: UpdateWorkspaceUnitParams) { + Object.assign(this, params); + } + + get isPublish() { + console.error('Suggest changing to published'); + return this.published; + } + + get isLocal() { + console.error('Suggest changing to syncMode'); + return this.syncMode === 'all'; + } +} From 104693916f7c4706b2362ceba5a1ce0f46f4a797 Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Tue, 10 Jan 2023 20:11:46 +0800 Subject: [PATCH 4/5] feat: change the order of load workspaces --- packages/data-center/src/datacenter.ts | 12 +++++++++++- packages/data-center/src/provider/affine/affine.ts | 6 ------ packages/data-center/src/provider/local/local.ts | 1 - .../data-center/src/workspace-unit-collection.ts | 4 ++-- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index 487e82cd5f..e4fe394c71 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -46,6 +46,10 @@ export class DataCenter { dc.registerProvider(new LocalProvider(getInitParams())); dc.registerProvider(new AffineProvider(getInitParams())); + for (const provider of dc.providerMap.values()) { + await provider.loadWorkspaces(); + } + return dc; } @@ -181,8 +185,14 @@ export class DataCenter { * @param {Function} callback callback function */ public async onWorkspacesChange( - callback: (workspaces: WorkspaceUnitCollectionChangeEvent) => void + callback: (workspaces: WorkspaceUnitCollectionChangeEvent) => void, + { immediate = true }: { immediate?: boolean } ) { + if (immediate) { + callback({ + added: this._workspaceUnitCollection.workspaces, + }); + } this._workspaceUnitCollection.on('change', callback); } diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index b98a08cf25..cbe5adef18 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -2,7 +2,6 @@ import { BaseProvider } from '../base.js'; import type { ProviderConstructorParams, CreateWorkspaceInfoParams, - UpdateWorkspaceMetaParams, WorkspaceMeta0, } from '../base'; import type { User } from '../../types'; @@ -34,11 +33,6 @@ export class AffineProvider extends BaseProvider { constructor({ apis, ...params }: AffineProviderConstructorParams) { super(params); this._apis = apis || getApis(); - this.init().then(() => { - if (this._apis.token.isLogin) { - this.loadWorkspaces(); - } - }); } override async init() { diff --git a/packages/data-center/src/provider/local/local.ts b/packages/data-center/src/provider/local/local.ts index f87d7c95fb..2bc6bae718 100644 --- a/packages/data-center/src/provider/local/local.ts +++ b/packages/data-center/src/provider/local/local.ts @@ -19,7 +19,6 @@ export class LocalProvider extends BaseProvider { constructor(params: ProviderConstructorParams) { super(params); - this.loadWorkspaces(); } private _storeWorkspaces(workspaces: WorkspaceMeta0[]) { diff --git a/packages/data-center/src/workspace-unit-collection.ts b/packages/data-center/src/workspace-unit-collection.ts index e4dedad8c7..58770e2122 100644 --- a/packages/data-center/src/workspace-unit-collection.ts +++ b/packages/data-center/src/workspace-unit-collection.ts @@ -18,7 +18,7 @@ export interface WorkspaceUnitCollectionScope { } export interface WorkspaceUnitCollectionChangeEvent { - added?: WorkspaceUnit; + added?: WorkspaceUnit[]; deleted?: WorkspaceUnit; updated?: WorkspaceUnit; } @@ -71,7 +71,7 @@ export class WorkspaceUnitCollection { this._events.emit('change', [ { - added: workspaceUnit, + added: [workspaceUnit], } as WorkspaceUnitCollectionChangeEvent, ]); }; From b111c411bd0414f67550b87ff842d9950bf51b3a Mon Sep 17 00:00:00 2001 From: alt0 Date: Tue, 10 Jan 2023 20:22:14 +0800 Subject: [PATCH 5/5] fix: local provider create workspace should wait sync to idb --- .../local/{ => indexeddb}/indexeddb.ts | 0 .../src/provider/local/indexeddb/utils.ts | 20 +++++++++++++++++++ .../data-center/src/provider/local/local.ts | 16 +++++---------- 3 files changed, 25 insertions(+), 11 deletions(-) rename packages/data-center/src/provider/local/{ => indexeddb}/indexeddb.ts (100%) create mode 100644 packages/data-center/src/provider/local/indexeddb/utils.ts diff --git a/packages/data-center/src/provider/local/indexeddb.ts b/packages/data-center/src/provider/local/indexeddb/indexeddb.ts similarity index 100% rename from packages/data-center/src/provider/local/indexeddb.ts rename to packages/data-center/src/provider/local/indexeddb/indexeddb.ts diff --git a/packages/data-center/src/provider/local/indexeddb/utils.ts b/packages/data-center/src/provider/local/indexeddb/utils.ts new file mode 100644 index 0000000000..8ca5c9b46d --- /dev/null +++ b/packages/data-center/src/provider/local/indexeddb/utils.ts @@ -0,0 +1,20 @@ +import assert from 'assert'; +import * as idb from 'lib0/indexeddb.js'; +import { Workspace as BlocksuiteWorkspace } from '@blocksuite/store'; + +const { encodeStateAsUpdate } = BlocksuiteWorkspace.Y; + +export const initStore = async (blocksuiteWorkspace: BlocksuiteWorkspace) => { + const workspaceId = blocksuiteWorkspace.room; + assert(workspaceId); + await idb.deleteDB(workspaceId); + const db = await idb.openDB(workspaceId, db => + idb.createStores(db, [['updates', { autoIncrement: true }], ['custom']]) + ); + const currState = encodeStateAsUpdate(blocksuiteWorkspace.doc); + const [updatesStore] = idb.transact(db, ['updates']); // , 'readonly') + + if (updatesStore) { + await idb.addAutoKey(updatesStore, currState); + } +}; diff --git a/packages/data-center/src/provider/local/local.ts b/packages/data-center/src/provider/local/local.ts index f87d7c95fb..e662320b64 100644 --- a/packages/data-center/src/provider/local/local.ts +++ b/packages/data-center/src/provider/local/local.ts @@ -7,7 +7,8 @@ import type { } from '../base'; import { varStorage as storage } from 'lib0/storage'; import { Workspace as BlocksuiteWorkspace, uuidv4 } from '@blocksuite/store'; -import { IndexedDBProvider } from './indexeddb.js'; +import { IndexedDBProvider } from './indexeddb/indexeddb.js'; +import { initStore } from './indexeddb/utils.js'; import assert from 'assert'; import { setDefaultAvatar } from '../utils.js'; @@ -101,21 +102,12 @@ export class LocalProvider extends BaseProvider { ): Promise { const workspaceId = blocksuiteWorkspace.room; assert(workspaceId, 'Blocksuite Workspace without room(workspaceId).'); - assert(meta.name, 'Workspace name is required'); this._logger('Creating affine workspace'); const workspaceInfo: WorkspaceMeta0 = { - name: meta.name, - id: workspaceId, - published: false, - avatar: '', - owner: undefined, - syncMode: 'core', - memberCount: 1, - provider: 'local', + ...meta, }; - this.linkLocal(blocksuiteWorkspace); blocksuiteWorkspace.meta.setName(meta.name); if (!meta.avatar) { @@ -123,6 +115,8 @@ export class LocalProvider extends BaseProvider { workspaceInfo.avatar = blocksuiteWorkspace.meta.avatar; } + await initStore(blocksuiteWorkspace); + this._workspaces.add(workspaceInfo); this._storeWorkspaces(this._workspaces.list());