refactor: workspace crud
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import { Workspaces } from './workspaces';
|
import { Workspaces } from './workspaces';
|
||||||
|
import type { WorkspacesChangeEvent } from './workspaces';
|
||||||
import { Workspace } from '@blocksuite/store';
|
import { Workspace } from '@blocksuite/store';
|
||||||
import { BaseProvider } from './provider/base';
|
import { BaseProvider } from './provider/base';
|
||||||
import { LocalProvider } from './provider/local/local';
|
import { LocalProvider } from './provider/local/local';
|
||||||
@@ -14,9 +15,10 @@ import { applyUpdate, encodeStateAsUpdate } from 'yjs';
|
|||||||
* @classdesc DataCenter is a data center, it can manage different providers for business
|
* @classdesc DataCenter is a data center, it can manage different providers for business
|
||||||
*/
|
*/
|
||||||
export class DataCenter {
|
export class DataCenter {
|
||||||
private readonly workspaces = new Workspaces(this);
|
private readonly _workspaces = new Workspaces();
|
||||||
private currentWorkspace: Workspace | null = null;
|
private currentWorkspace: Workspace | null = null;
|
||||||
private readonly _logger = getLogger('dc');
|
private readonly _logger = getLogger('dc');
|
||||||
|
private _defaultProvider?: BaseProvider;
|
||||||
providerMap: Map<string, BaseProvider> = new Map();
|
providerMap: Map<string, BaseProvider> = new Map();
|
||||||
|
|
||||||
constructor(debug: boolean) {
|
constructor(debug: boolean) {
|
||||||
@@ -28,32 +30,43 @@ export class DataCenter {
|
|||||||
// TODO: switch different provider
|
// TODO: switch different provider
|
||||||
dc.registerProvider(new LocalProvider());
|
dc.registerProvider(new LocalProvider());
|
||||||
dc.registerProvider(new AffineProvider());
|
dc.registerProvider(new AffineProvider());
|
||||||
dc.workspaces.init();
|
|
||||||
|
|
||||||
return dc;
|
return dc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register provider.
|
||||||
|
* We will automatically set the first provider to default provider.
|
||||||
|
*/
|
||||||
registerProvider(provider: BaseProvider) {
|
registerProvider(provider: BaseProvider) {
|
||||||
|
if (!this._defaultProvider) {
|
||||||
|
this._defaultProvider = provider;
|
||||||
|
}
|
||||||
// inject data in provider
|
// inject data in provider
|
||||||
provider.inject({ logger: this._logger, workspaces: this.workspaces });
|
provider.inject({
|
||||||
|
logger: this._logger,
|
||||||
|
workspaces: this._workspaces.createScope(),
|
||||||
|
});
|
||||||
provider.init();
|
provider.init();
|
||||||
this.providerMap.set(provider.id, provider);
|
this.providerMap.set(provider.id, provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setDefaultProvider(providerId: string) {
|
||||||
|
this._defaultProvider = this.providerMap.get(providerId);
|
||||||
|
}
|
||||||
|
|
||||||
get providers() {
|
get providers() {
|
||||||
return Array.from(this.providerMap.values());
|
return Array.from(this.providerMap.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public get workspaces() {
|
||||||
* get workspaces list if focusUpdate is true, it will refresh workspaces
|
return this._workspaces.workspaces;
|
||||||
* @param {string} name workspace name
|
}
|
||||||
* @returns {Promise<WS[]>}
|
|
||||||
*/
|
public async refreshWorkspaces() {
|
||||||
public async getWorkspaces(focusUpdate = false) {
|
return Promise.allSettled(
|
||||||
if (focusUpdate) {
|
Object.values(this.providerMap).map(provider => provider.loadWorkspaces())
|
||||||
this.workspaces.refreshWorkspaces();
|
);
|
||||||
}
|
|
||||||
return this.workspaces.workspaces;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -61,11 +74,16 @@ export class DataCenter {
|
|||||||
* @param {string} name workspace name
|
* @param {string} name workspace name
|
||||||
* @returns {Promise<WS>}
|
* @returns {Promise<WS>}
|
||||||
*/
|
*/
|
||||||
public async createWorkspace(name: string) {
|
public async createWorkspace(workspaceMeta: WorkspaceMeta) {
|
||||||
const workspaceInfo = this.workspaces.addLocalWorkspace(name);
|
assert(
|
||||||
// IMP: create workspace in local provider
|
this._defaultProvider,
|
||||||
this.providerMap.get('local')?.createWorkspace({ name });
|
'There is no provider. You should add provider first.'
|
||||||
return workspaceInfo;
|
);
|
||||||
|
|
||||||
|
const workspace = await this._defaultProvider.createWorkspace(
|
||||||
|
workspaceMeta
|
||||||
|
);
|
||||||
|
return workspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -73,14 +91,11 @@ export class DataCenter {
|
|||||||
* @param {string} workspaceId workspace id
|
* @param {string} workspaceId workspace id
|
||||||
*/
|
*/
|
||||||
public async deleteWorkspace(workspaceId: string) {
|
public async deleteWorkspace(workspaceId: string) {
|
||||||
const workspaceInfo = this.workspaces.getWorkspace(workspaceId);
|
const workspaceInfo = this._workspaces.find(workspaceId);
|
||||||
assert(workspaceInfo, 'Workspace not found');
|
assert(workspaceInfo, 'Workspace not found');
|
||||||
const provider = this.providerMap.get(workspaceInfo.provider);
|
const provider = this.providerMap.get(workspaceInfo.provider);
|
||||||
if (provider && this.workspaces.hasWorkspace(workspaceId)) {
|
assert(provider, `Workspace exists, but we couldn't find its provider.`);
|
||||||
await provider.delete(workspaceId);
|
await provider.deleteWorkspace(workspaceId);
|
||||||
// may be refresh all workspaces
|
|
||||||
this.workspaces.delete(workspaceId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -119,11 +134,11 @@ export class DataCenter {
|
|||||||
* @returns {Promise<Workspace>}
|
* @returns {Promise<Workspace>}
|
||||||
*/
|
*/
|
||||||
public async loadWorkspace(workspaceId: string) {
|
public async loadWorkspace(workspaceId: string) {
|
||||||
const workspaceInfo = this.workspaces.getWorkspace(workspaceId);
|
const workspaceInfo = this._workspaces.find(workspaceId);
|
||||||
assert(workspaceInfo, 'Workspace not found');
|
assert(workspaceInfo, 'Workspace not found');
|
||||||
const currentProvider = this.providerMap.get(workspaceInfo.provider);
|
const currentProvider = this.providerMap.get(workspaceInfo.provider);
|
||||||
if (currentProvider) {
|
if (currentProvider) {
|
||||||
currentProvider.close(workspaceId);
|
currentProvider.closeWorkspace(workspaceId);
|
||||||
}
|
}
|
||||||
const provider = this.providerMap.get(workspaceInfo.provider);
|
const provider = this.providerMap.get(workspaceInfo.provider);
|
||||||
assert(provider, `provide '${workspaceInfo.provider}' is not registered`);
|
assert(provider, `provide '${workspaceInfo.provider}' is not registered`);
|
||||||
@@ -149,8 +164,10 @@ export class DataCenter {
|
|||||||
* listen workspaces list change
|
* listen workspaces list change
|
||||||
* @param {Function} callback callback function
|
* @param {Function} callback callback function
|
||||||
*/
|
*/
|
||||||
public async onWorkspacesChange(callback: (workspaces: WS[]) => void) {
|
public async onWorkspacesChange(
|
||||||
this.workspaces.onWorkspacesChange(callback);
|
callback: (workspaces: WorkspacesChangeEvent) => void
|
||||||
|
) {
|
||||||
|
this._workspaces.on('change', callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -166,20 +183,18 @@ export class DataCenter {
|
|||||||
assert(w?.room, 'No workspace to set meta');
|
assert(w?.room, 'No workspace to set meta');
|
||||||
const update: Partial<WorkspaceMeta> = {};
|
const update: Partial<WorkspaceMeta> = {};
|
||||||
if (name) {
|
if (name) {
|
||||||
w.doc.meta.setName(name);
|
w.meta.setName(name);
|
||||||
update.name = name;
|
update.name = name;
|
||||||
}
|
}
|
||||||
if (avatar) {
|
if (avatar) {
|
||||||
w.doc.meta.setAvatar(avatar);
|
w.meta.setAvatar(avatar);
|
||||||
update.avatar = avatar;
|
update.avatar = avatar;
|
||||||
}
|
}
|
||||||
// may run for change workspace meta
|
// may run for change workspace meta
|
||||||
const workspaceInfo = this.workspaces.getWorkspace(w.room);
|
const workspaceInfo = this._workspaces.find(w.room);
|
||||||
assert(workspaceInfo, 'Workspace not found');
|
assert(workspaceInfo, 'Workspace not found');
|
||||||
const provider = this.providerMap.get(workspaceInfo.provider);
|
const provider = this.providerMap.get(workspaceInfo.provider);
|
||||||
provider?.updateWorkspaceMeta(w.room, update);
|
provider?.updateWorkspaceMeta(w.room, update);
|
||||||
// update workspace list directly
|
|
||||||
this.workspaces.updateWorkspaceInfo(w.room, update);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -188,27 +203,26 @@ export class DataCenter {
|
|||||||
* @param id workspace id
|
* @param id workspace id
|
||||||
*/
|
*/
|
||||||
public async leaveWorkspace(workspaceId: string) {
|
public async leaveWorkspace(workspaceId: string) {
|
||||||
const workspaceInfo = this.workspaces.getWorkspace(workspaceId);
|
const workspaceInfo = this._workspaces.find(workspaceId);
|
||||||
assert(workspaceInfo, 'Workspace not found');
|
assert(workspaceInfo, 'Workspace not found');
|
||||||
const provider = this.providerMap.get(workspaceInfo.provider);
|
const provider = this.providerMap.get(workspaceInfo.provider);
|
||||||
if (provider) {
|
if (provider) {
|
||||||
await provider.close(workspaceId);
|
await provider.closeWorkspace(workspaceId);
|
||||||
await provider.leave(workspaceId);
|
await provider.leaveWorkspace(workspaceId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async setWorkspacePublish(workspaceId: string, isPublish: boolean) {
|
public async setWorkspacePublish(workspaceId: string, isPublish: boolean) {
|
||||||
const workspaceInfo = this.workspaces.getWorkspace(workspaceId);
|
const workspaceInfo = this._workspaces.find(workspaceId);
|
||||||
assert(workspaceInfo, 'Workspace not found');
|
assert(workspaceInfo, 'Workspace not found');
|
||||||
const provider = this.providerMap.get(workspaceInfo.provider);
|
const provider = this.providerMap.get(workspaceInfo.provider);
|
||||||
if (provider) {
|
if (provider) {
|
||||||
await provider.publish(workspaceId, isPublish);
|
await provider.publish(workspaceId, isPublish);
|
||||||
this.workspaces.updateWorkspaceInfo(workspaceId, { isPublish });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async inviteMember(id: string, email: string) {
|
public async inviteMember(id: string, email: string) {
|
||||||
const workspaceInfo = this.workspaces.getWorkspace(id);
|
const workspaceInfo = this._workspaces.find(id);
|
||||||
assert(workspaceInfo, 'Workspace not found');
|
assert(workspaceInfo, 'Workspace not found');
|
||||||
const provider = this.providerMap.get(workspaceInfo.provider);
|
const provider = this.providerMap.get(workspaceInfo.provider);
|
||||||
if (provider) {
|
if (provider) {
|
||||||
@@ -221,7 +235,7 @@ export class DataCenter {
|
|||||||
* @param {number} permissionId permission id
|
* @param {number} permissionId permission id
|
||||||
*/
|
*/
|
||||||
public async removeMember(workspaceId: string, permissionId: number) {
|
public async removeMember(workspaceId: string, permissionId: number) {
|
||||||
const workspaceInfo = this.workspaces.getWorkspace(workspaceId);
|
const workspaceInfo = this._workspaces.find(workspaceId);
|
||||||
assert(workspaceInfo, 'Workspace not found');
|
assert(workspaceInfo, 'Workspace not found');
|
||||||
const provider = this.providerMap.get(workspaceInfo.provider);
|
const provider = this.providerMap.get(workspaceInfo.provider);
|
||||||
if (provider) {
|
if (provider) {
|
||||||
@@ -235,13 +249,11 @@ export class DataCenter {
|
|||||||
*/
|
*/
|
||||||
public async closeCurrentWorkspace() {
|
public async closeCurrentWorkspace() {
|
||||||
assert(this.currentWorkspace?.room, 'No workspace to close');
|
assert(this.currentWorkspace?.room, 'No workspace to close');
|
||||||
const currentWorkspace = this.workspaces.getWorkspace(
|
const currentWorkspace = this._workspaces.find(this.currentWorkspace.room);
|
||||||
this.currentWorkspace.room
|
|
||||||
);
|
|
||||||
assert(currentWorkspace, 'Workspace not found');
|
assert(currentWorkspace, 'Workspace not found');
|
||||||
const provider = this.providerMap.get(currentWorkspace.provider);
|
const provider = this.providerMap.get(currentWorkspace.provider);
|
||||||
assert(provider, 'Provider not found');
|
assert(provider, 'Provider not found');
|
||||||
await provider.close(currentWorkspace.id);
|
await provider.closeWorkspace(currentWorkspace.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async _transWorkspaceProvider(
|
private async _transWorkspaceProvider(
|
||||||
@@ -249,7 +261,7 @@ export class DataCenter {
|
|||||||
providerId: string
|
providerId: string
|
||||||
) {
|
) {
|
||||||
assert(workspace.room, 'No workspace id');
|
assert(workspace.room, 'No workspace id');
|
||||||
const workspaceInfo = this.workspaces.getWorkspace(workspace.room);
|
const workspaceInfo = this._workspaces.find(workspace.room);
|
||||||
assert(workspaceInfo, 'Workspace not found');
|
assert(workspaceInfo, 'Workspace not found');
|
||||||
if (workspaceInfo.provider === providerId) {
|
if (workspaceInfo.provider === providerId) {
|
||||||
this._logger('Workspace provider is same');
|
this._logger('Workspace provider is same');
|
||||||
@@ -270,8 +282,7 @@ export class DataCenter {
|
|||||||
);
|
);
|
||||||
applyUpdate(newWorkspace.doc, encodeStateAsUpdate(workspace.doc));
|
applyUpdate(newWorkspace.doc, encodeStateAsUpdate(workspace.doc));
|
||||||
assert(newWorkspace, 'Create workspace failed');
|
assert(newWorkspace, 'Create workspace failed');
|
||||||
await currentProvider.delete(workspace.room);
|
await currentProvider.deleteWorkspace(workspace.room);
|
||||||
this.workspaces.refreshWorkspaces();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -119,9 +119,8 @@ export class AffineProvider extends BaseProvider {
|
|||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
await (
|
|
||||||
await Promise.all(workspaceInstances)
|
(await Promise.all(workspaceInstances)).forEach((workspace, i) => {
|
||||||
).forEach((workspace, i) => {
|
|
||||||
if (workspace) {
|
if (workspace) {
|
||||||
workspaces[i] = {
|
workspaces[i] = {
|
||||||
...workspaces[i],
|
...workspaces[i],
|
||||||
@@ -159,6 +158,11 @@ export class AffineProvider extends BaseProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
workspaces.forEach(workspace => {
|
||||||
|
this._workspaces.add(workspace);
|
||||||
|
});
|
||||||
|
|
||||||
return workspaces;
|
return workspaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,17 +189,19 @@ export class AffineProvider extends BaseProvider {
|
|||||||
return this._user;
|
return this._user;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async delete(id: string): Promise<void> {
|
public override async deleteWorkspace(id: string): Promise<void> {
|
||||||
await this.close(id);
|
await this.closeWorkspace(id);
|
||||||
IndexedDBProvider.delete(id);
|
IndexedDBProvider.delete(id);
|
||||||
await deleteWorkspace({ id });
|
await deleteWorkspace({ id });
|
||||||
|
this._workspaces.remove(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async clear(): Promise<void> {
|
public override async clear(): Promise<void> {
|
||||||
for (const w of this._workspacesCache.values()) {
|
for (const w of this._workspacesCache.values()) {
|
||||||
if (w.room) {
|
if (w.room) {
|
||||||
try {
|
try {
|
||||||
await this.delete(w.room);
|
await this.deleteWorkspace(w.room);
|
||||||
|
this._workspaces.remove(w.room);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this._logger('has a problem of delete workspace ', e);
|
this._logger('has a problem of delete workspace ', e);
|
||||||
}
|
}
|
||||||
@@ -204,14 +210,14 @@ export class AffineProvider extends BaseProvider {
|
|||||||
this._workspacesCache.clear();
|
this._workspacesCache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async close(id: string) {
|
public override async closeWorkspace(id: string) {
|
||||||
const idb = this._idbMap.get(id);
|
const idb = this._idbMap.get(id);
|
||||||
idb?.destroy();
|
idb?.destroy();
|
||||||
const ws = this._wsMap.get(id);
|
const ws = this._wsMap.get(id);
|
||||||
ws?.disconnect();
|
ws?.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async leave(id: string): Promise<void> {
|
public override async leaveWorkspace(id: string): Promise<void> {
|
||||||
await leaveWorkspace({ id });
|
await leaveWorkspace({ id });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,6 +257,19 @@ export class AffineProvider extends BaseProvider {
|
|||||||
nw.meta.setName(meta.name);
|
nw.meta.setName(meta.name);
|
||||||
nw.meta.setAvatar(meta.avatar);
|
nw.meta.setAvatar(meta.avatar);
|
||||||
this._initWorkspaceDb(nw);
|
this._initWorkspaceDb(nw);
|
||||||
|
|
||||||
|
const workspaceInfo: WS = {
|
||||||
|
name: meta.name,
|
||||||
|
id,
|
||||||
|
isPublish: false,
|
||||||
|
avatar: '',
|
||||||
|
owner: undefined,
|
||||||
|
isLocal: true,
|
||||||
|
memberCount: 1,
|
||||||
|
provider: 'local',
|
||||||
|
};
|
||||||
|
|
||||||
|
this._workspaces.add(workspaceInfo);
|
||||||
return nw;
|
return nw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { BlobStorage, Workspace } from '@blocksuite/store';
|
import { BlobStorage, Workspace } from '@blocksuite/store';
|
||||||
import { Logger, User, Workspace as WS, WorkspaceMeta } from '../types';
|
import { Logger, User, Workspace as WS, WorkspaceMeta } from '../types';
|
||||||
import { Workspaces } from '../workspaces';
|
import type { WorkspacesScope } from '../workspaces';
|
||||||
|
|
||||||
export class BaseProvider {
|
export class BaseProvider {
|
||||||
public readonly id: string = 'base';
|
public readonly id: string = 'base';
|
||||||
protected _workspaces!: Workspaces;
|
protected _workspaces!: WorkspacesScope;
|
||||||
protected _logger!: Logger;
|
protected _logger!: Logger;
|
||||||
protected _blobs!: BlobStorage;
|
protected _blobs!: BlobStorage;
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ export class BaseProvider {
|
|||||||
workspaces,
|
workspaces,
|
||||||
}: {
|
}: {
|
||||||
logger: Logger;
|
logger: Logger;
|
||||||
workspaces: Workspaces;
|
workspaces: WorkspacesScope;
|
||||||
}) {
|
}) {
|
||||||
this._logger = logger;
|
this._logger = logger;
|
||||||
this._workspaces = workspaces;
|
this._workspaces = workspaces;
|
||||||
@@ -83,7 +83,7 @@ export class BaseProvider {
|
|||||||
* delete workspace include all data
|
* delete workspace include all data
|
||||||
* @param id workspace id
|
* @param id workspace id
|
||||||
*/
|
*/
|
||||||
public async delete(id: string): Promise<void> {
|
public async deleteWorkspace(id: string): Promise<void> {
|
||||||
id;
|
id;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -92,7 +92,7 @@ export class BaseProvider {
|
|||||||
* leave workspace by workspace id
|
* leave workspace by workspace id
|
||||||
* @param id workspace id
|
* @param id workspace id
|
||||||
*/
|
*/
|
||||||
public async leave(id: string): Promise<void> {
|
public async leaveWorkspace(id: string): Promise<void> {
|
||||||
id;
|
id;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -101,7 +101,7 @@ export class BaseProvider {
|
|||||||
* close db link and websocket connection and other resources
|
* close db link and websocket connection and other resources
|
||||||
* @param id workspace id
|
* @param id workspace id
|
||||||
*/
|
*/
|
||||||
public async close(id: string) {
|
public async closeWorkspace(id: string) {
|
||||||
id;
|
id;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { BaseProvider } from '../base';
|
import { BaseProvider } from '../base';
|
||||||
import { varStorage as storage } from 'lib0/storage';
|
import { varStorage as storage } from 'lib0/storage';
|
||||||
import { Workspace as WS, WorkspaceMeta } from '../../types';
|
import { Workspace as WS, WorkspaceMeta } from '../../types';
|
||||||
import { Workspace } from '@blocksuite/store';
|
import { Workspace, uuidv4 } from '@blocksuite/store';
|
||||||
import { IndexedDBProvider } from '../indexeddb';
|
import { IndexedDBProvider } from '../indexeddb';
|
||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
import { getDefaultHeadImgBlob } from '../../utils';
|
import { getDefaultHeadImgBlob } from '../../utils';
|
||||||
@@ -11,11 +11,10 @@ const WORKSPACE_KEY = 'workspaces';
|
|||||||
export class LocalProvider extends BaseProvider {
|
export class LocalProvider extends BaseProvider {
|
||||||
public id = 'local';
|
public id = 'local';
|
||||||
private _idbMap: Map<string, IndexedDBProvider> = new Map();
|
private _idbMap: Map<string, IndexedDBProvider> = new Map();
|
||||||
private _workspacesList: WS[] = [];
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this._workspacesList = [];
|
this.loadWorkspaces();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _storeWorkspaces(workspaces: WS[]) {
|
private _storeWorkspaces(workspaces: WS[]) {
|
||||||
@@ -46,6 +45,9 @@ export class LocalProvider extends BaseProvider {
|
|||||||
if (workspaceStr) {
|
if (workspaceStr) {
|
||||||
try {
|
try {
|
||||||
workspaces = JSON.parse(workspaceStr) as WS[];
|
workspaces = JSON.parse(workspaceStr) as WS[];
|
||||||
|
workspaces.forEach(workspace => {
|
||||||
|
this._workspaces.add(workspace);
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this._logger(`Failed to parse workspaces from storage`);
|
this._logger(`Failed to parse workspaces from storage`);
|
||||||
}
|
}
|
||||||
@@ -53,12 +55,12 @@ export class LocalProvider extends BaseProvider {
|
|||||||
return Promise.resolve(workspaces);
|
return Promise.resolve(workspaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async delete(id: string): Promise<void> {
|
public override async deleteWorkspace(id: string): Promise<void> {
|
||||||
const index = this._workspacesList.findIndex(ws => ws.id === id);
|
const workspace = this._workspaces.get(id);
|
||||||
if (index !== -1) {
|
if (workspace) {
|
||||||
IndexedDBProvider.delete(id);
|
IndexedDBProvider.delete(id);
|
||||||
this._workspacesList.splice(index, 1);
|
this._workspaces.remove(id);
|
||||||
this._storeWorkspaces(this._workspacesList);
|
this._storeWorkspaces(this._workspaces.list());
|
||||||
} else {
|
} else {
|
||||||
this._logger(`Failed to delete workspace ${id}`);
|
this._logger(`Failed to delete workspace ${id}`);
|
||||||
}
|
}
|
||||||
@@ -68,15 +70,8 @@ export class LocalProvider extends BaseProvider {
|
|||||||
id: string,
|
id: string,
|
||||||
meta: Partial<WorkspaceMeta>
|
meta: Partial<WorkspaceMeta>
|
||||||
) {
|
) {
|
||||||
const index = this._workspacesList.findIndex(ws => ws.id === id);
|
this._workspaces.update(id, meta);
|
||||||
if (index !== -1) {
|
this._storeWorkspaces(this._workspaces.list());
|
||||||
const workspace = this._workspacesList[index];
|
|
||||||
meta.name && (workspace.name = meta.name);
|
|
||||||
meta.avatar && (workspace.avatar = meta.avatar);
|
|
||||||
this._storeWorkspaces(this._workspacesList);
|
|
||||||
} else {
|
|
||||||
this._logger(`Failed to update workspace ${id}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async createWorkspace(
|
public override async createWorkspace(
|
||||||
@@ -88,13 +83,27 @@ export class LocalProvider extends BaseProvider {
|
|||||||
const blob = await getDefaultHeadImgBlob(meta.name);
|
const blob = await getDefaultHeadImgBlob(meta.name);
|
||||||
meta.avatar = (await this.setBlob(blob)) || '';
|
meta.avatar = (await this.setBlob(blob)) || '';
|
||||||
}
|
}
|
||||||
const workspaceInfos = this._workspaces.addLocalWorkspace(meta.name);
|
|
||||||
this._logger('Creating affine workspace');
|
this._logger('Creating affine workspace');
|
||||||
const workspace = new Workspace({ room: workspaceInfos.id });
|
|
||||||
|
const workspaceInfo: WS = {
|
||||||
|
name: meta.name,
|
||||||
|
id: uuidv4(),
|
||||||
|
isPublish: false,
|
||||||
|
avatar: '',
|
||||||
|
owner: undefined,
|
||||||
|
isLocal: true,
|
||||||
|
memberCount: 1,
|
||||||
|
provider: 'local',
|
||||||
|
};
|
||||||
|
|
||||||
|
const workspace = new Workspace({ room: workspaceInfo.id });
|
||||||
|
this._initWorkspaceDb(workspace);
|
||||||
workspace.meta.setName(meta.name);
|
workspace.meta.setName(meta.name);
|
||||||
workspace.meta.setAvatar(meta.avatar);
|
workspace.meta.setAvatar(meta.avatar);
|
||||||
this._storeWorkspaces([...this._workspacesList, workspaceInfos]);
|
|
||||||
this._initWorkspaceDb(workspace);
|
this._workspaces.add(workspaceInfo);
|
||||||
|
this._storeWorkspaces(this._workspaces.list());
|
||||||
|
|
||||||
return workspace;
|
return workspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,5 +111,6 @@ export class LocalProvider extends BaseProvider {
|
|||||||
const workspaces = await this.loadWorkspaces();
|
const workspaces = await this.loadWorkspaces();
|
||||||
workspaces.forEach(ws => IndexedDBProvider.delete(ws.id));
|
workspaces.forEach(ws => IndexedDBProvider.delete(ws.id));
|
||||||
this._storeWorkspaces([]);
|
this._storeWorkspaces([]);
|
||||||
|
this._workspaces.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
export { Workspaces } from './workspaces';
|
export { Workspaces } from './workspaces';
|
||||||
|
export type { WorkspacesScope, WorkspacesChangeEvent } from './workspaces';
|
||||||
|
|||||||
@@ -1,101 +1,127 @@
|
|||||||
import { Workspace as WS } from '../types';
|
|
||||||
|
|
||||||
import { Observable } from 'lib0/observable';
|
import { Observable } from 'lib0/observable';
|
||||||
import { uuidv4 } from '@blocksuite/store';
|
import type { Workspace, WorkspaceMeta } from '../types';
|
||||||
import { DataCenter } from '../datacenter';
|
|
||||||
|
|
||||||
export class Workspaces extends Observable<string> {
|
export interface WorkspacesScope {
|
||||||
private _workspaces: WS[];
|
get: (workspaceId: string) => Workspace | undefined;
|
||||||
private readonly _dc: DataCenter;
|
list: () => Workspace[];
|
||||||
|
add: (workspace: Workspace) => void;
|
||||||
|
remove: (workspaceId: string) => boolean;
|
||||||
|
clear: () => void;
|
||||||
|
update: (workspaceId: string, workspaceMeta: Partial<WorkspaceMeta>) => void;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(dc: DataCenter) {
|
export interface WorkspacesChangeEvent {
|
||||||
super();
|
added?: Workspace;
|
||||||
this._workspaces = [];
|
deleted?: Workspace;
|
||||||
this._dc = dc;
|
updated?: Workspace;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Workspaces extends Observable<'change'> {
|
||||||
|
private _workspacesMap = new Map<string, Workspace>();
|
||||||
|
|
||||||
|
get workspaces(): Workspace[] {
|
||||||
|
return Object.values(this._workspacesMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
public init() {
|
find(workspaceId: string) {
|
||||||
this._loadWorkspaces();
|
return this._workspacesMap.get(workspaceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
get workspaces() {
|
createScope(): WorkspacesScope {
|
||||||
return this._workspaces;
|
const scopedWorkspaceIds = new Set<string>();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
const get = (workspaceId: string) => {
|
||||||
* emit when workspaces changed
|
if (!scopedWorkspaceIds.has(workspaceId)) {
|
||||||
* @param {(workspace: WS[]) => void} cb
|
return;
|
||||||
*/
|
}
|
||||||
onWorkspacesChange(cb: (workspace: WS[]) => void) {
|
return this._workspacesMap.get(workspaceId);
|
||||||
this.on('change', cb);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
private async _loadWorkspaces() {
|
const add = (workspace: Workspace) => {
|
||||||
const providers = this._dc.providers;
|
if (this._workspacesMap.has(workspace.id)) {
|
||||||
let workspaces: WS[] = [];
|
throw new Error(`Duplicate workspace id.`);
|
||||||
providers.forEach(async p => {
|
}
|
||||||
const pWorkspaces = await p.loadWorkspaces();
|
this._workspacesMap.set(workspace.id, workspace);
|
||||||
workspaces = [...workspaces, ...pWorkspaces];
|
scopedWorkspaceIds.add(workspace.id);
|
||||||
this._updateWorkspaces([...workspaces, ...pWorkspaces]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
this.emit('change', [
|
||||||
* focus load all workspaces list
|
{
|
||||||
*/
|
added: workspace,
|
||||||
public async refreshWorkspaces() {
|
} as WorkspacesChangeEvent,
|
||||||
this._loadWorkspaces();
|
]);
|
||||||
}
|
};
|
||||||
|
|
||||||
private _updateWorkspaces(workspaces: WS[]) {
|
const remove = (workspaceId: string) => {
|
||||||
this._workspaces = workspaces;
|
if (!scopedWorkspaceIds.has(workspaceId)) {
|
||||||
this.emit('change', this._workspaces);
|
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 WorkspacesChangeEvent,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const clear = () => {
|
||||||
|
scopedWorkspaceIds.forEach(id => {
|
||||||
|
remove(id);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const update = (
|
||||||
|
workspaceId: string,
|
||||||
|
workspaceMeta: Partial<WorkspaceMeta>
|
||||||
|
) => {
|
||||||
|
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 WorkspacesChangeEvent,
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: need to optimize
|
||||||
|
const list = () => {
|
||||||
|
const workspaces: Workspace[] = [];
|
||||||
|
scopedWorkspaceIds.forEach(id => {
|
||||||
|
const workspace = this._workspacesMap.get(id);
|
||||||
|
if (workspace) {
|
||||||
|
workspaces.push(workspace);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return workspaces;
|
||||||
|
};
|
||||||
|
|
||||||
private _getDefaultWorkspace(name: string): WS {
|
|
||||||
return {
|
return {
|
||||||
name,
|
get,
|
||||||
id: uuidv4(),
|
list,
|
||||||
isPublish: false,
|
add,
|
||||||
avatar: '',
|
remove,
|
||||||
owner: undefined,
|
clear,
|
||||||
isLocal: true,
|
update,
|
||||||
memberCount: 1,
|
|
||||||
provider: 'local',
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** add a local workspaces */
|
|
||||||
public addLocalWorkspace(name: string) {
|
|
||||||
const workspace = this._getDefaultWorkspace(name);
|
|
||||||
this._updateWorkspaces([...this._workspaces, workspace]);
|
|
||||||
return workspace;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** delete a workspaces by id */
|
|
||||||
public delete(id: string) {
|
|
||||||
const index = this._workspaces.findIndex(w => w.id === id);
|
|
||||||
if (index >= 0) {
|
|
||||||
this._workspaces.splice(index, 1);
|
|
||||||
this._updateWorkspaces(this._workspaces);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** get workspace info by id */
|
|
||||||
public getWorkspace(id: string) {
|
|
||||||
return this._workspaces.find(w => w.id === id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** check if workspace exists */
|
|
||||||
public hasWorkspace(id: string) {
|
|
||||||
return this._workspaces.some(w => w.id === id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public updateWorkspaceInfo(id: string, info: Partial<WS>) {
|
|
||||||
const index = this._workspaces.findIndex(w => w.id === id);
|
|
||||||
if (index >= 0) {
|
|
||||||
this._workspaces[index] = { ...this._workspaces[index], ...info };
|
|
||||||
this._updateWorkspaces(this._workspaces);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
101
packages/data-center/src/workspaces/workspaces.ts.bak
Normal file
101
packages/data-center/src/workspaces/workspaces.ts.bak
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
import { Workspace as WS } from '../types';
|
||||||
|
|
||||||
|
import { Observable } from 'lib0/observable';
|
||||||
|
import { uuidv4 } from '@blocksuite/store';
|
||||||
|
import { DataCenter } from '../datacenter';
|
||||||
|
|
||||||
|
export class Workspaces extends Observable<string> {
|
||||||
|
private _workspaces: WS[];
|
||||||
|
private readonly _dc: DataCenter;
|
||||||
|
|
||||||
|
constructor(dc: DataCenter) {
|
||||||
|
super();
|
||||||
|
this._workspaces = [];
|
||||||
|
this._dc = dc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public init() {
|
||||||
|
this._loadWorkspaces();
|
||||||
|
}
|
||||||
|
|
||||||
|
get workspaces() {
|
||||||
|
return this._workspaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* emit when workspaces changed
|
||||||
|
* @param {(workspace: WS[]) => void} cb
|
||||||
|
*/
|
||||||
|
onWorkspacesChange(cb: (workspace: WS[]) => void) {
|
||||||
|
this.on('change', cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _loadWorkspaces() {
|
||||||
|
const providers = this._dc.providers;
|
||||||
|
let workspaces: WS[] = [];
|
||||||
|
providers.forEach(async p => {
|
||||||
|
const pWorkspaces = await p.loadWorkspaces();
|
||||||
|
workspaces = [...workspaces, ...pWorkspaces];
|
||||||
|
this._updateWorkspaces([...workspaces, ...pWorkspaces]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* focus load all workspaces list
|
||||||
|
*/
|
||||||
|
public async refreshWorkspaces() {
|
||||||
|
this._loadWorkspaces();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _updateWorkspaces(workspaces: WS[]) {
|
||||||
|
this._workspaces = workspaces;
|
||||||
|
this.emit('change', this._workspaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getDefaultWorkspace(name: string): WS {
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
id: uuidv4(),
|
||||||
|
isPublish: false,
|
||||||
|
avatar: '',
|
||||||
|
owner: undefined,
|
||||||
|
isLocal: true,
|
||||||
|
memberCount: 1,
|
||||||
|
provider: 'local',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** add a local workspaces */
|
||||||
|
public addLocalWorkspace(name: string) {
|
||||||
|
const workspace = this._getDefaultWorkspace(name);
|
||||||
|
this._updateWorkspaces([...this._workspaces, workspace]);
|
||||||
|
return workspace;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** delete a workspaces by id */
|
||||||
|
public delete(id: string) {
|
||||||
|
const index = this._workspaces.findIndex(w => w.id === id);
|
||||||
|
if (index >= 0) {
|
||||||
|
this._workspaces.splice(index, 1);
|
||||||
|
this._updateWorkspaces(this._workspaces);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** get workspace info by id */
|
||||||
|
public getWorkspace(id: string) {
|
||||||
|
return this._workspaces.find(w => w.id === id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** check if workspace exists */
|
||||||
|
public hasWorkspace(id: string) {
|
||||||
|
return this._workspaces.some(w => w.id === id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateWorkspaceInfo(id: string, info: Partial<WS>) {
|
||||||
|
const index = this._workspaces.findIndex(w => w.id === id);
|
||||||
|
if (index >= 0) {
|
||||||
|
this._workspaces[index] = { ...this._workspaces[index], ...info };
|
||||||
|
this._updateWorkspaces(this._workspaces);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user