From 8e4585495f033f89ba794f3c89e4bbc24b039c28 Mon Sep 17 00:00:00 2001 From: alt0 Date: Wed, 11 Jan 2023 23:14:13 +0800 Subject: [PATCH 01/20] refactor: create and load workspace will return workspaceUnit --- packages/data-center/src/datacenter.ts | 61 ++---- .../data-center/src/provider/affine/affine.ts | 201 +++++++----------- .../data-center/src/provider/affine/utils.ts | 95 +++++++++ packages/data-center/src/provider/base.ts | 37 ++-- .../src/provider/local/indexeddb/utils.ts | 29 ++- .../src/provider/local/local.spec.ts | 6 +- .../data-center/src/provider/local/local.ts | 73 ++----- .../data-center/src/provider/local/utils.ts | 34 +++ .../src/workspace-unit-collection.spec.ts | 5 +- .../src/workspace-unit-collection.ts | 37 ++-- packages/data-center/src/workspace-unit.ts | 29 ++- 11 files changed, 327 insertions(+), 280 deletions(-) create mode 100644 packages/data-center/src/provider/affine/utils.ts create mode 100644 packages/data-center/src/provider/local/utils.ts diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index c15861223..d9269f988 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -96,12 +96,7 @@ export class DataCenter { 'There is no provider. You should add provider first.' ); - const workspaceMeta = await this._mainProvider.createWorkspaceInfo(params); - - const workspace = createBlocksuiteWorkspace(workspaceMeta.id); - - await this._mainProvider.createWorkspace(workspace, workspaceMeta); - const workspaceUnit = this._workspaceUnitCollection.find(workspaceMeta.id); + const workspaceUnit = await this._mainProvider.createWorkspace(params); return workspaceUnit; } @@ -322,55 +317,33 @@ export class DataCenter { } } - private async _transWorkspaceProvider( - workspace: BlocksuiteWorkspace, - providerId: string + public async enableProvider( + workspaceUnit: WorkspaceUnit, + providerId = 'affine' ) { - assert(workspace.room, 'No workspace id'); - const workspaceInfo = this._workspaceUnitCollection.find(workspace.room); - assert(workspaceInfo, 'Workspace not found'); - if (workspaceInfo.provider === providerId) { + if (workspaceUnit.provider === providerId) { this._logger('Workspace provider is same'); return; } - const currentProvider = this.providerMap.get(workspaceInfo.provider); - assert(currentProvider, 'Provider not found'); - const newProvider = this.providerMap.get(providerId); - assert(newProvider, `provide '${providerId}' is not registered`); - this._logger(`create ${providerId} workspace: `, workspaceInfo.name); - const newWorkspaceInfo = await newProvider.createWorkspaceInfo({ - name: workspaceInfo.name, - // avatar: workspaceInfo.avatar, - }); - const newWorkspace = createBlocksuiteWorkspace(newWorkspaceInfo.id); - // TODO optimize this function - await newProvider.createWorkspace(newWorkspace, { - ...newWorkspaceInfo, - name: workspaceInfo.name, - avatar: workspaceInfo.avatar, - }); + const provider = this.providerMap.get(providerId); + assert(provider); + const newWorkspaceUnit = await provider.extendWorkspace(workspaceUnit); - assert(newWorkspace, 'Create workspace failed'); - this._logger( - `update workspace data from ${workspaceInfo.provider} to ${providerId}` - ); - await newProvider.assign(newWorkspace, workspace); - assert(newWorkspace, 'Create workspace failed'); - await currentProvider.deleteWorkspace(workspace.room); - return newWorkspace.room; + // Currently we only allow enable one provider, so after enable new provider, + // delete the old workspace from its provider. + const oldProvider = this.providerMap.get(workspaceUnit.provider); + assert(oldProvider); + await oldProvider.deleteWorkspace(workspaceUnit.id); + + return newWorkspaceUnit; } /** * Enable workspace cloud * @param {string} id ID of workspace. */ - public async enableWorkspaceCloud(workspace: WorkspaceUnit) { - assert(workspace?.id, 'No workspace to enable cloud'); - assert(workspace.blocksuiteWorkspace); - return await this._transWorkspaceProvider( - workspace.blocksuiteWorkspace, - 'affine' - ); + public async enableWorkspaceCloud(workspaceUnit: WorkspaceUnit) { + return this.enableProvider(workspaceUnit); } /** diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index a3142b74a..572c05b72 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -6,7 +6,6 @@ import type { } from '../base'; import type { User } from '../../types'; import { Workspace as BlocksuiteWorkspace } from '@blocksuite/store'; -import { BlockSchema } from '@blocksuite/blocks/models'; import { storage } from './storage.js'; import assert from 'assert'; import { WebsocketProvider } from './sync.js'; @@ -14,9 +13,16 @@ import { WebsocketProvider } from './sync.js'; import { getApis } from './apis/index.js'; import type { Apis, WorkspaceDetail, Callback } from './apis'; import { setDefaultAvatar } from '../utils.js'; -import { MessageCode } from '../../message'; +import { MessageCode } from '../../message/index.js'; import { token } from './apis/token.js'; import { WebsocketClient } from './channel'; +import { + loadWorkspaceUnit, + createWorkspaceUnit, + syncToCloud, +} from './utils.js'; +import { WorkspaceUnit } from '../../workspace-unit.js'; +import { createBlocksuiteWorkspace } from '../../utils/index.js'; export interface AffineProviderConstructorParams extends ProviderConstructorParams { @@ -153,78 +159,25 @@ export class AffineProvider extends BaseProvider { return []; } const workspacesList = await this._apis.getWorkspaces(); - const workspaces: WorkspaceMeta0[] = workspacesList.map(w => { - return { - ...w, - memberCount: 0, - name: '', - provider: 'affine', - syncMode: 'core', - }; - }); - const workspaceInstances = workspaces.map(({ id }) => { - const workspace = - this._workspacesCache.get(id) || - new BlocksuiteWorkspace({ - room: id, - }).register(BlockSchema); - this._workspacesCache.set(id, workspace); - if (workspace) { - return new Promise(resolve => { - this._apis.downloadWorkspace(id).then(data => { - applyUpdate(workspace.doc, new Uint8Array(data)); - resolve(workspace); - }); - }); - } else { - return Promise.resolve(null); - } - }); - - (await Promise.all(workspaceInstances)).forEach((workspace, i) => { - if (workspace) { - workspaces[i] = { - ...workspaces[i], - name: workspace.meta.name, - avatar: workspace.meta.avatar, - }; - } - }); - const getDetailList = workspacesList.map(w => { - const { id } = w; - return new Promise<{ id: string; detail: WorkspaceDetail | null }>( - resolve => { - this._apis.getWorkspaceDetail({ id }).then(data => { - resolve({ id, detail: data || null }); - }); - } - ); - }); - const ownerList = await Promise.all(getDetailList); - (await Promise.all(ownerList)).forEach(detail => { - if (detail) { - const { id, detail: workspaceDetail } = detail; - if (workspaceDetail) { - const { owner, member_count } = workspaceDetail; - const currentWorkspace = workspaces.find(w => w.id === id); - if (currentWorkspace) { - currentWorkspace.owner = { - id: owner.id, - name: owner.name, - avatar: owner.avatar_url, - email: owner.email, - }; - currentWorkspace.memberCount = member_count; - } - } - } - }); - - workspaces.forEach(workspace => { - this._workspaces.add(workspace); - }); - - return workspaces; + const workspaceUnits = await Promise.all( + workspacesList.map(w => { + return loadWorkspaceUnit( + { + id: w.id, + name: '', + avatar: undefined, + owner: undefined, + published: w.public, + memberCount: 1, + provider: 'affine', + syncMode: 'core', + }, + this._apis + ); + }) + ); + this._workspaces.add(workspaceUnits); + return workspaceUnits; } override async auth() { @@ -310,52 +263,29 @@ export class AffineProvider extends BaseProvider { // return workspace; } - public override async createWorkspaceInfo( + public override async createWorkspace( meta: CreateWorkspaceInfoParams - ): Promise { + ): Promise { const { id } = await this._apis.createWorkspace(meta); - const workspaceInfo: WorkspaceMeta0 = { + const workspaceUnit = await createWorkspaceUnit({ + id, name: meta.name, - id: id, - published: false, - avatar: '', + avatar: undefined, owner: await this.getUserInfo(), - syncMode: 'core', - memberCount: 1, - provider: 'affine', - }; - return workspaceInfo; - } - - public override async createWorkspace( - blocksuiteWorkspace: BlocksuiteWorkspace, - meta: WorkspaceMeta0 - ): Promise { - const workspaceId = blocksuiteWorkspace.room; - assert(workspaceId, 'Blocksuite Workspace without room(workspaceId).'); - this._logger('Creating affine workspace'); - - this._applyCloudUpdates(blocksuiteWorkspace); - this.linkLocal(blocksuiteWorkspace); - - const workspaceInfo: WorkspaceMeta0 = { - name: meta.name, - id: workspaceId, published: false, - avatar: '', - owner: undefined, - syncMode: 'core', memberCount: 1, provider: 'affine', - }; + syncMode: 'core', + }); - if (!blocksuiteWorkspace.meta.avatar) { - await setDefaultAvatar(blocksuiteWorkspace); - workspaceInfo.avatar = blocksuiteWorkspace.meta.avatar; - } - this._workspaces.add(workspaceInfo); - return blocksuiteWorkspace; + await syncToCloud( + workspaceUnit.blocksuiteWorkspace!, + this._apis.token.refresh + ); + this._workspaces.add(workspaceUnit); + + return workspaceUnit; } public override async publish(id: string, isPublish: boolean): Promise { @@ -377,22 +307,41 @@ 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)); - // TODO: upload blobs and make sure doc is synced - await new Promise((resolve, reject) => { - ws.once('synced', () => { - setTimeout(() => resolve(), 1000); - }); - ws.once('lost-connection', () => reject()); - ws.once('connection-error', () => reject()); + public override async extendWorkspace( + workspaceUnit: WorkspaceUnit + ): Promise { + const { id } = await this._apis.createWorkspace({ + name: workspaceUnit.name, }); - return to; + const newWorkspaceUnit = new WorkspaceUnit({ + id, + name: workspaceUnit.name, + avatar: undefined, + owner: await this.getUserInfo(), + published: false, + memberCount: 1, + provider: 'affine', + syncMode: 'core', + }); + + const blocksuiteWorkspace = createBlocksuiteWorkspace(id); + + await new Promise(resolve => { + assert(workspaceUnit.blocksuiteWorkspace); + const doc = blocksuiteWorkspace.doc; + doc.once('update', resolve); + applyUpdate( + doc, + encodeStateAsUpdate(workspaceUnit.blocksuiteWorkspace.doc) + ); + }); + + await syncToCloud(blocksuiteWorkspace, this._apis.token.refresh); + + newWorkspaceUnit.setBlocksuiteWorkspace(blocksuiteWorkspace); + + this._workspaces.add(newWorkspaceUnit); + return newWorkspaceUnit; } public override async logout(): Promise { diff --git a/packages/data-center/src/provider/affine/utils.ts b/packages/data-center/src/provider/affine/utils.ts new file mode 100644 index 000000000..7fb62e171 --- /dev/null +++ b/packages/data-center/src/provider/affine/utils.ts @@ -0,0 +1,95 @@ +import assert from 'assert'; +import { Workspace as BlocksuiteWorkspace } from '@blocksuite/store'; +import { WorkspaceUnit } from '../../workspace-unit.js'; +import type { WorkspaceUnitCtorParams } from '../../workspace-unit'; +import { createBlocksuiteWorkspace } from '../../utils/index.js'; +import type { Apis } from './apis'; +import { WebsocketProvider } from './sync.js'; +import { setDefaultAvatar } from '../utils.js'; + +export const loadWorkspaceUnit = async ( + params: WorkspaceUnitCtorParams, + apis: Apis +) => { + const workspaceUnit = new WorkspaceUnit(params); + const blocksuiteWorkspace = createBlocksuiteWorkspace(workspaceUnit.id); + + const updates = await apis.downloadWorkspace( + workspaceUnit.id, + params.published + ); + if (updates && updates.byteLength) { + await new Promise(resolve => { + const doc = blocksuiteWorkspace.doc; + doc.once('update', resolve); + BlocksuiteWorkspace.Y.applyUpdate(doc, new Uint8Array(updates)); + }); + } + + const details = await apis.getWorkspaceDetail({ id: workspaceUnit.id }); + const owner = details?.owner; + + workspaceUnit.setBlocksuiteWorkspace(blocksuiteWorkspace); + workspaceUnit.update({ + name: blocksuiteWorkspace.meta.name, + avatar: blocksuiteWorkspace.meta.avatar, + memberCount: details?.member_count || 1, + owner: owner + ? { + id: owner.id, + name: owner.name, + avatar: owner.avatar_url, + email: owner.email, + } + : undefined, + }); + + return workspaceUnit; +}; + +export const syncToCloud = async ( + blocksuiteWorkspace: BlocksuiteWorkspace, + refreshToken: string +) => { + const workspaceId = blocksuiteWorkspace.room; + assert(workspaceId, 'Blocksuite workspace without room(workspaceId).'); + + const wsUrl = `${window.location.protocol === 'https:' ? 'wss' : 'ws'}://${ + window.location.host + }/api/sync/`; + + const ws = new WebsocketProvider( + wsUrl, + workspaceId, + blocksuiteWorkspace.doc, + { + params: { token: refreshToken }, + } + ); + + await new Promise((resolve, reject) => { + ws.once('synced', () => { + // FIXME: we don't when send local data to cloud successfully, so hack to wait 1s. + // Server will support this by add a new api. + setTimeout(resolve, 1000); + }); + ws.once('lost-connection', () => reject()); + ws.once('connection-error', () => reject()); + }); +}; + +export const createWorkspaceUnit = async (params: WorkspaceUnitCtorParams) => { + const workspaceUnit = new WorkspaceUnit(params); + + const blocksuiteWorkspace = createBlocksuiteWorkspace(workspaceUnit.id); + + blocksuiteWorkspace.meta.setName(workspaceUnit.name); + if (!workspaceUnit.avatar) { + await setDefaultAvatar(blocksuiteWorkspace); + workspaceUnit.update({ avatar: blocksuiteWorkspace.meta.avatar }); + } + + workspaceUnit.setBlocksuiteWorkspace(blocksuiteWorkspace); + + return workspaceUnit; +}; diff --git a/packages/data-center/src/provider/base.ts b/packages/data-center/src/provider/base.ts index fed862681..c2e0d61ca 100644 --- a/packages/data-center/src/provider/base.ts +++ b/packages/data-center/src/provider/base.ts @@ -1,8 +1,8 @@ -import { Workspace as BlocksuiteWorkspace, uuidv4 } from '@blocksuite/store'; +import { Workspace as BlocksuiteWorkspace } from '@blocksuite/store'; import { MessageCenter } from '../message'; import { Logger, User } from '../types'; import type { WorkspaceUnitCollectionScope } from '../workspace-unit-collection'; -import type { WorkspaceUnitCtorParams } from '../workspace-unit'; +import type { WorkspaceUnitCtorParams, WorkspaceUnit } from '../workspace-unit'; import { Member } from './affine/apis'; const defaultLogger = () => { @@ -44,12 +44,6 @@ export class BaseProvider { return; } - public async createWorkspaceInfo( - params: CreateWorkspaceInfoParams - ): Promise { - throw new Error(`provider: ${this.id} createWorkspaceInfo Not implemented`); - } - /** * auth provider */ @@ -87,7 +81,7 @@ export class BaseProvider { /** * load workspaces **/ - public async loadWorkspaces(): Promise { + public async loadWorkspaces(): Promise { throw new Error(`provider: ${this.id} loadWorkSpace Not implemented`); } @@ -183,13 +177,18 @@ export class BaseProvider { /** * create workspace by workspace meta - * @param {WorkspaceMeta} meta + * @param {CreateWorkspaceInfoParams} meta */ public async createWorkspace( - blocksuiteWorkspace: BlocksuiteWorkspace, - meta: WorkspaceMeta0 - ): Promise { - return blocksuiteWorkspace; + meta: CreateWorkspaceInfoParams + ): Promise { + throw new Error(`provider: ${this.id} createWorkspace not implemented`); + } + + public async extendWorkspace( + workspaceUnit: WorkspaceUnit + ): Promise { + throw new Error(`provider: ${this.id} extendWorkspace not implemented`); } /** @@ -214,16 +213,6 @@ export class BaseProvider { return workspace; } - /** - * merge one workspaces to another - * @param workspace - * @returns - */ - public async assign(to: BlocksuiteWorkspace, from: BlocksuiteWorkspace) { - from; - return to; - } - /** * get workspace members * @param {string} workspaceId diff --git a/packages/data-center/src/provider/local/indexeddb/utils.ts b/packages/data-center/src/provider/local/indexeddb/utils.ts index 8ca5c9b46..10406673f 100644 --- a/packages/data-center/src/provider/local/indexeddb/utils.ts +++ b/packages/data-center/src/provider/local/indexeddb/utils.ts @@ -2,9 +2,12 @@ import assert from 'assert'; import * as idb from 'lib0/indexeddb.js'; import { Workspace as BlocksuiteWorkspace } from '@blocksuite/store'; -const { encodeStateAsUpdate } = BlocksuiteWorkspace.Y; +const { applyUpdate, encodeStateAsUpdate, mergeUpdates } = + BlocksuiteWorkspace.Y; -export const initStore = async (blocksuiteWorkspace: BlocksuiteWorkspace) => { +export const writeUpdatesToLocal = async ( + blocksuiteWorkspace: BlocksuiteWorkspace +) => { const workspaceId = blocksuiteWorkspace.room; assert(workspaceId); await idb.deleteDB(workspaceId); @@ -18,3 +21,25 @@ export const initStore = async (blocksuiteWorkspace: BlocksuiteWorkspace) => { await idb.addAutoKey(updatesStore, currState); } }; + +export const applyLocalUpdates = async ( + blocksuiteWorkspace: BlocksuiteWorkspace +) => { + const workspaceId = blocksuiteWorkspace.room; + assert(workspaceId, 'Blocksuite workspace without room(workspaceId).'); + const db = await idb.openDB(workspaceId, db => + idb.createStores(db, [['updates', { autoIncrement: true }], ['custom']]) + ); + + const [updatesStore] = idb.transact(db, ['updates']); // , 'readonly') + if (updatesStore) { + const updates = await idb.getAll(updatesStore); + const doc = blocksuiteWorkspace.doc; + await new Promise(resolve => { + const mergedUpdates = mergeUpdates(updates); + doc.once('update', resolve); + applyUpdate(doc, mergedUpdates); + }); + } + 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 e60ce31aa..ba9cb8b66 100644 --- a/packages/data-center/src/provider/local/local.spec.ts +++ b/packages/data-center/src/provider/local/local.spec.ts @@ -16,12 +16,10 @@ test.describe.serial('local provider', () => { let workspaceId: string | undefined; test('create workspace', async () => { - const workspaceInfo = await provider.createWorkspaceInfo({ + const workspaceUnit = await provider.createWorkspace({ name: workspaceName, }); - workspaceId = workspaceInfo.id; - const blocksuiteWorkspace = createBlocksuiteWorkspace(workspaceId); - await provider.createWorkspace(blocksuiteWorkspace, workspaceInfo); + workspaceId = workspaceUnit?.id; expect(workspaceMetaCollection.workspaces.length).toEqual(1); expect(workspaceMetaCollection.workspaces[0].name).toEqual(workspaceName); diff --git a/packages/data-center/src/provider/local/local.ts b/packages/data-center/src/provider/local/local.ts index ec07ef568..ad7194306 100644 --- a/packages/data-center/src/provider/local/local.ts +++ b/packages/data-center/src/provider/local/local.ts @@ -8,9 +8,9 @@ import type { import { varStorage as storage } from 'lib0/storage'; import { Workspace as BlocksuiteWorkspace, uuidv4 } from '@blocksuite/store'; import { IndexedDBProvider } from './indexeddb/indexeddb.js'; -import { initStore } from './indexeddb/utils.js'; import assert from 'assert'; -import { setDefaultAvatar } from '../utils.js'; +import { loadWorkspaceUnit, createWorkspaceUnit } from './utils.js'; +import type { WorkspaceUnit } from '../../workspace-unit'; const WORKSPACE_KEY = 'workspaces'; @@ -22,21 +22,12 @@ export class LocalProvider extends BaseProvider { super(params); } - private _storeWorkspaces(workspaces: WorkspaceMeta0[]) { + private _storeWorkspaces(workspaceUnits: WorkspaceUnit[]) { storage.setItem( WORKSPACE_KEY, JSON.stringify( - workspaces.map(w => { - return { - id: w.id, - name: w.name, - avatar: w.avatar, - owner: w.owner, - published: w.published, - memberCount: w.memberCount, - provider: w.provider, - syncMode: w.syncMode, - }; + workspaceUnits.map(w => { + return w.toJSON(); }) ) ); @@ -60,20 +51,23 @@ export class LocalProvider extends BaseProvider { return workspace; } - override loadWorkspaces(): Promise { + override async loadWorkspaces(): Promise { const workspaceStr = storage.getItem(WORKSPACE_KEY); - let workspaces: WorkspaceMeta0[] = []; if (workspaceStr) { try { - workspaces = JSON.parse(workspaceStr) as WorkspaceMeta0[]; - workspaces.forEach(workspace => { - this._workspaces.add(workspace); - }); + const workspaceMetas = JSON.parse(workspaceStr) as WorkspaceMeta0[]; + const workspaceUnits = await Promise.all( + workspaceMetas.map(meta => { + return loadWorkspaceUnit(meta); + }) + ); + this._workspaces.add(workspaceUnits); + return workspaceUnits; } catch (error) { this._logger(`Failed to parse workspaces from storage`); } } - return Promise.resolve(workspaces); + return []; } public override async deleteWorkspace(id: string): Promise { @@ -95,10 +89,10 @@ export class LocalProvider extends BaseProvider { this._storeWorkspaces(this._workspaces.list()); } - public override async createWorkspaceInfo( + public override async createWorkspace( meta: CreateWorkspaceInfoParams - ): Promise { - const workspaceInfo: WorkspaceMeta0 = { + ): Promise { + const workspaceUnit = await createWorkspaceUnit({ name: meta.name, id: uuidv4(), published: false, @@ -107,35 +101,10 @@ export class LocalProvider extends BaseProvider { syncMode: 'core', memberCount: 1, provider: 'local', - }; - return Promise.resolve(workspaceInfo); - } - - public override async createWorkspace( - blocksuiteWorkspace: BlocksuiteWorkspace, - meta: WorkspaceMeta0 - ): Promise { - const workspaceId = blocksuiteWorkspace.room; - assert(workspaceId, 'Blocksuite Workspace without room(workspaceId).'); - this._logger('Creating affine workspace'); - - const workspaceInfo: WorkspaceMeta0 = { - ...meta, - }; - - blocksuiteWorkspace.meta.setName(meta.name); - - if (!meta.avatar) { - await setDefaultAvatar(blocksuiteWorkspace); - workspaceInfo.avatar = blocksuiteWorkspace.meta.avatar; - } - - await initStore(blocksuiteWorkspace); - - this._workspaces.add(workspaceInfo); + }); + this._workspaces.add(workspaceUnit); this._storeWorkspaces(this._workspaces.list()); - - return blocksuiteWorkspace; + return workspaceUnit; } public override async clear(): Promise { diff --git a/packages/data-center/src/provider/local/utils.ts b/packages/data-center/src/provider/local/utils.ts new file mode 100644 index 000000000..bd5654c51 --- /dev/null +++ b/packages/data-center/src/provider/local/utils.ts @@ -0,0 +1,34 @@ +import { WorkspaceUnit } from '../../workspace-unit.js'; +import type { WorkspaceUnitCtorParams } from '../../workspace-unit'; +import { createBlocksuiteWorkspace } from '../../utils/index.js'; +import { applyLocalUpdates, writeUpdatesToLocal } from './indexeddb/utils.js'; +import { setDefaultAvatar } from '../utils.js'; + +export const loadWorkspaceUnit = async (params: WorkspaceUnitCtorParams) => { + const workspaceUnit = new WorkspaceUnit(params); + + const blocksuiteWorkspace = createBlocksuiteWorkspace(workspaceUnit.id); + + await applyLocalUpdates(blocksuiteWorkspace); + + workspaceUnit.setBlocksuiteWorkspace(blocksuiteWorkspace); + + return workspaceUnit; +}; + +export const createWorkspaceUnit = async (params: WorkspaceUnitCtorParams) => { + const workspaceUnit = new WorkspaceUnit(params); + + const blocksuiteWorkspace = createBlocksuiteWorkspace(workspaceUnit.id); + blocksuiteWorkspace.meta.setName(workspaceUnit.name); + if (!workspaceUnit.avatar) { + await setDefaultAvatar(blocksuiteWorkspace); + workspaceUnit.update({ avatar: blocksuiteWorkspace.meta.avatar }); + } + + await writeUpdatesToLocal(blocksuiteWorkspace); + + workspaceUnit.setBlocksuiteWorkspace(blocksuiteWorkspace); + + return workspaceUnit; +}; diff --git a/packages/data-center/src/workspace-unit-collection.spec.ts b/packages/data-center/src/workspace-unit-collection.spec.ts index f010c31d1..405fc8237 100644 --- a/packages/data-center/src/workspace-unit-collection.spec.ts +++ b/packages/data-center/src/workspace-unit-collection.spec.ts @@ -1,6 +1,7 @@ import { test, expect } from '@playwright/test'; import { WorkspaceUnitCollection } from './workspace-unit-collection.js'; import type { WorkspaceUnitCollectionChangeEvent } from './workspace-unit-collection'; +import { WorkspaceUnit } from './workspace-unit.js'; test.describe.serial('workspace meta collection observable', () => { const workspaceUnitCollection = new WorkspaceUnitCollection(); @@ -14,13 +15,15 @@ test.describe.serial('workspace meta collection observable', () => { expect(event.added?.[0]?.id).toEqual('123'); } ); - scope.add({ + const workspaceUnit = new WorkspaceUnit({ id: '123', name: 'test', + avatar: undefined, memberCount: 1, provider: '', syncMode: 'core', }); + scope.add(workspaceUnit); }); test('list workspace', () => { diff --git a/packages/data-center/src/workspace-unit-collection.ts b/packages/data-center/src/workspace-unit-collection.ts index f385cecdc..7d5576256 100644 --- a/packages/data-center/src/workspace-unit-collection.ts +++ b/packages/data-center/src/workspace-unit-collection.ts @@ -1,19 +1,18 @@ import { Observable } from 'lib0/observable'; -import { WorkspaceUnit } from './workspace-unit.js'; import type { - WorkspaceUnitCtorParams, + WorkspaceUnit, UpdateWorkspaceUnitParams, } from './workspace-unit'; export interface WorkspaceUnitCollectionScope { get: (workspaceId: string) => WorkspaceUnit | undefined; list: () => WorkspaceUnit[]; - add: (workspace: WorkspaceUnitCtorParams) => void; + add: (workspace: WorkspaceUnit | WorkspaceUnit[]) => void; remove: (workspaceId: string) => boolean; clear: () => void; update: ( workspaceId: string, - workspaceMeta: UpdateWorkspaceUnitParams + workspaceUnit: UpdateWorkspaceUnitParams ) => void; } @@ -59,20 +58,23 @@ export class WorkspaceUnitCollection { return this._workspaceUnitMap.get(workspaceId); }; - const add = (workspace: WorkspaceUnitCtorParams) => { - if (this._workspaceUnitMap.has(workspace.id)) { - // FIXME: multiple add same workspace - return; - } + const add = (workspaceUnit: WorkspaceUnit | WorkspaceUnit[]) => { + const workspaceUnits = Array.isArray(workspaceUnit) + ? workspaceUnit + : [workspaceUnit]; - const workspaceUnit = new WorkspaceUnit(workspace); - this._workspaceUnitMap.set(workspace.id, workspaceUnit); - - scopedWorkspaceIds.add(workspace.id); + workspaceUnits.forEach(workspaceUnit => { + if (this._workspaceUnitMap.has(workspaceUnit.id)) { + // FIXME: multiple add same workspace + return; + } + this._workspaceUnitMap.set(workspaceUnit.id, workspaceUnit); + scopedWorkspaceIds.add(workspaceUnit.id); + }); this._events.emit('change', [ { - added: [workspaceUnit], + added: workspaceUnits, } as WorkspaceUnitCollectionChangeEvent, ]); }; @@ -107,10 +109,7 @@ export class WorkspaceUnitCollection { }); }; - const update = ( - workspaceId: string, - workspaceMeta: UpdateWorkspaceUnitParams - ) => { + const update = (workspaceId: string, meta: UpdateWorkspaceUnitParams) => { if (!scopedWorkspaceIds.has(workspaceId)) { return true; } @@ -120,7 +119,7 @@ export class WorkspaceUnitCollection { return true; } - workspaceUnit.update(workspaceMeta); + workspaceUnit.update(meta); this._events.emit('change', [ { diff --git a/packages/data-center/src/workspace-unit.ts b/packages/data-center/src/workspace-unit.ts index b7244c0b5..5bc4bf8ae 100644 --- a/packages/data-center/src/workspace-unit.ts +++ b/packages/data-center/src/workspace-unit.ts @@ -37,6 +37,16 @@ export class WorkspaceUnit { this.update(params); } + get isPublish() { + console.error('Suggest changing to published'); + return this.published; + } + + get isLocal() { + console.error('Suggest changing to syncMode'); + return this.syncMode === 'all'; + } + get blocksuiteWorkspace() { return this._blocksuiteWorkspace; } @@ -52,13 +62,16 @@ export class WorkspaceUnit { 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'; + toJSON(): Omit { + return { + id: this.id, + name: this.name, + avatar: this.avatar, + owner: this.owner, + published: this.published, + memberCount: this.memberCount, + provider: this.provider, + syncMode: this.syncMode, + }; } } From 48d355ee72d21fef7746ce58cd79d647c816ffea Mon Sep 17 00:00:00 2001 From: alt0 Date: Thu, 12 Jan 2023 10:01:09 +0800 Subject: [PATCH 02/20] fix: after load workspace, we need to close other workspace, not detory. --- packages/data-center/src/datacenter.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index cce3f8a30..0e6dee827 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -164,7 +164,9 @@ export class DataCenter { this._workspaceInstances.set(workspaceId, workspace); await provider.warpWorkspace(workspace); this._workspaceUnitCollection.workspaces.forEach(workspaceUnit => { - workspaceUnit.setBlocksuiteWorkspace(null); + const provider = this.providerMap.get(workspaceUnit.provider); + assert(provider); + provider.closeWorkspace(workspaceUnit.id); }); workspaceUnit.setBlocksuiteWorkspace(workspace); return workspaceUnit; From 1b544463c2bd3e98753a5c7457823fafdbf80523 Mon Sep 17 00:00:00 2001 From: DiamondThree <857159145@qq.com> Date: Thu, 12 Jan 2023 11:50:49 +0800 Subject: [PATCH 03/20] fix: login when no user. enabled on member --- .../workspace-setting/member/MembersPage.tsx | 23 ++++--------------- .../app/src/hooks/use-workspace-helper.ts | 2 +- 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/packages/app/src/components/workspace-setting/member/MembersPage.tsx b/packages/app/src/components/workspace-setting/member/MembersPage.tsx index 45ab2c30d..2971e5a13 100644 --- a/packages/app/src/components/workspace-setting/member/MembersPage.tsx +++ b/packages/app/src/components/workspace-setting/member/MembersPage.tsx @@ -26,13 +26,12 @@ import { toast } from '@/ui/toast'; import useMembers from '@/hooks/use-members'; import Loading from '@/components/loading'; import { Wrapper } from '@/ui/layout'; +import { useWorkspaceHelper } from '@/hooks/use-workspace-helper'; export const MembersPage = ({ workspace }: { workspace: WorkspaceUnit }) => { const [isInviteModalShow, setIsInviteModalShow] = useState(false); const { members, removeMember, loaded } = useMembers(); - - // FIXME: DELETE THIS - const { user, login, updateWorkspaceMeta } = useTemporaryHelper(); + const { enableWorkspace } = useWorkspaceHelper(); const { confirm } = useConfirm(); if (workspace.provider === 'affine') { @@ -163,22 +162,8 @@ export const MembersPage = ({ workspace }: { workspace: WorkspaceUnit }) => { { + setShowDelete(false); + }} workspace={workspace} /> ) : ( <> - { + setShowLeave(false); + }} /> )} diff --git a/packages/app/src/components/workspace-setting/general/leave/Leave.tsx b/packages/app/src/components/workspace-setting/general/leave/Leave.tsx index e34b4ac25..aed3617ab 100644 --- a/packages/app/src/components/workspace-setting/general/leave/Leave.tsx +++ b/packages/app/src/components/workspace-setting/general/leave/Leave.tsx @@ -7,29 +7,19 @@ import { } from './style'; import { ModalCloseButton } from '@/ui/modal'; import { Button } from '@/ui/button'; +import { useWorkspaceHelper } from '@/hooks/use-workspace-helper'; // import { getDataCenter } from '@affine/datacenter'; // import { useAppState } from '@/providers/app-state-provider'; interface WorkspaceDeleteProps { open: boolean; onClose: () => void; - workspaceName: string; - workspaceId: string; } -export const WorkspaceLeave = ({ - open, - onClose, - workspaceId, -}: WorkspaceDeleteProps) => { - console.log('workspaceId: ', workspaceId); - // const router = useRouter(); - // const { refreshWorkspacesMeta } = useAppState(); +export const WorkspaceLeave = ({ open, onClose }: WorkspaceDeleteProps) => { + const { leaveWorkSpace } = useWorkspaceHelper(); const handleLeave = async () => { - // const dc = await getDataCenter(); - // await dc.apis.leaveWorkspace({ id: workspaceId }); - // // router.push(`/workspace/${nextWorkSpaceId}`); - // refreshWorkspacesMeta(); + await leaveWorkSpace(); onClose(); }; diff --git a/packages/app/src/hooks/use-workspace-helper.ts b/packages/app/src/hooks/use-workspace-helper.ts index c8e05d6e2..f1dee901d 100644 --- a/packages/app/src/hooks/use-workspace-helper.ts +++ b/packages/app/src/hooks/use-workspace-helper.ts @@ -47,10 +47,10 @@ export const useWorkspaceHelper = () => { if (!user) { await login(); } - const newWorkspaceId = await dataCenter.enableWorkspaceCloud( + const workspace = await dataCenter.enableWorkspaceCloud( currentWorkspace ); - router.push(`/workspace/${newWorkspaceId}/setting`); + workspace && router.push(`/workspace/${workspace.id}/setting`); toast('Enabled success'); } }); @@ -60,6 +60,9 @@ export const useWorkspaceHelper = () => { currentWorkspace && (await dataCenter.deleteWorkspace(currentWorkspace?.id)); }; + const leaveWorkSpace = async () => { + currentWorkspace && (await dataCenter.leaveWorkspace(currentWorkspace?.id)); + }; return { createWorkspace, @@ -67,5 +70,6 @@ export const useWorkspaceHelper = () => { updateWorkspace, enableWorkspace, deleteWorkSpace, + leaveWorkSpace, }; }; From 4fe2febda347030e33fe38ea4c12dcbde91a58b3 Mon Sep 17 00:00:00 2001 From: DiamondThree <857159145@qq.com> Date: Thu, 12 Jan 2023 17:06:54 +0800 Subject: [PATCH 11/20] feat:add isOwner --- .../workspace-setting/general/General.tsx | 22 +++++---- .../app/src/pages/new-workspace/index.tsx | 47 ------------------- .../pages/workspace/[workspaceId]/setting.tsx | 19 ++++++-- .../providers/app-state-provider/Provider.tsx | 11 ++++- .../providers/app-state-provider/interface.ts | 1 + 5 files changed, 39 insertions(+), 61 deletions(-) delete mode 100644 packages/app/src/pages/new-workspace/index.tsx diff --git a/packages/app/src/components/workspace-setting/general/General.tsx b/packages/app/src/components/workspace-setting/general/General.tsx index b3f5af88a..0ced889c6 100644 --- a/packages/app/src/components/workspace-setting/general/General.tsx +++ b/packages/app/src/components/workspace-setting/general/General.tsx @@ -21,9 +21,8 @@ export const GeneralPage = ({ workspace }: { workspace: WorkspaceUnit }) => { const [showLeave, setShowLeave] = useState(false); const [uploading, setUploading] = useState(false); const [workspaceName, setWorkspaceName] = useState(workspace.name); - const { currentWorkspace } = useAppState(); + const { currentWorkspace, isOwner } = useAppState(); const { updateWorkspace } = useWorkspaceHelper(); - const isOwner = true; const handleChangeWorkSpaceName = (newName: string) => { setWorkspaceName(newName); }; @@ -72,16 +71,19 @@ export const GeneralPage = ({ workspace }: { workspace: WorkspaceUnit }) => { placeholder="Workspace Name" maxLength={14} minLength={1} + disabled={!isOwner} onChange={handleChangeWorkSpaceName} > - { - handleUpdateWorkspaceName(); - }} - style={{ marginLeft: '0px' }} - > - ✔️ - + {isOwner ? ( + { + handleUpdateWorkspaceName(); + }} + style={{ marginLeft: '0px' }} + > + ✔️ + + ) : null} Workspace Type diff --git a/packages/app/src/pages/new-workspace/index.tsx b/packages/app/src/pages/new-workspace/index.tsx deleted file mode 100644 index 1a1d9e1a4..000000000 --- a/packages/app/src/pages/new-workspace/index.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { WorkspaceModal } from '@/components/workspace-modal'; -import { getWorkspaces } from '@/hooks/mock-data/mock'; -import { useEffect, useState } from 'react'; -import { styled } from '@/styles'; -import Button from '@/ui/button/Button'; - -const Page = () => { - const [open, setOpen] = useState(false); - - useEffect(() => { - const data = getWorkspaces(); - if (!data.length) { - setOpen(true); - } - }, []); - return ( - -

workspace

-
- -
- { - setOpen(false); - }} - > -
- ); -}; -export default Page; - -const Workspace = styled.div(({ theme }) => { - return { - height: '100vh', - background: theme.colors.pageBackground, - color: '#FFFFFF', - fontSize: '18px', - fontWeight: 500, - }; -}); diff --git a/packages/app/src/pages/workspace/[workspaceId]/setting.tsx b/packages/app/src/pages/workspace/[workspaceId]/setting.tsx index e8c40aacf..e39a42416 100644 --- a/packages/app/src/pages/workspace/[workspaceId]/setting.tsx +++ b/packages/app/src/pages/workspace/[workspaceId]/setting.tsx @@ -60,7 +60,7 @@ const tabMap: { ]; const WorkspaceSetting = () => { - const { currentWorkspace } = useAppState(); + const { currentWorkspace, isOwner } = useAppState(); const [activeTab, setActiveTab] = useState(tabMap[0].name); const handleTabChange = (tab: TabNames) => { @@ -70,7 +70,20 @@ const WorkspaceSetting = () => { const activeTabPanelRender = tabMap.find( tab => tab.name === activeTab )?.panelRender; - + let tableArr: { + name: TabNames; + icon: ReactNode; + panelRender: (workspace: WorkspaceUnit) => ReactNode; + }[] = tabMap; + if (!isOwner) { + tableArr = [ + { + name: 'general', + icon: , + panelRender: workspace => , + }, + ]; + } return ( @@ -78,7 +91,7 @@ const WorkspaceSetting = () => { Workspace Settings - {tabMap.map(({ icon, name }) => { + {tableArr.map(({ icon, name }) => { return ( (); loadWorkspace.current = async (workspaceId: string) => { - const { dataCenter, workspaceList, currentWorkspace } = appState; + const { dataCenter, workspaceList, currentWorkspace, user } = appState; if (!workspaceList.find(v => v.id.toString() === workspaceId)) { return null; } @@ -99,6 +100,13 @@ export const AppStateProvider = ({ return currentWorkspace; } const workspace = (await dataCenter.loadWorkspace(workspaceId)) ?? null; + let isOwner; + if (workspace.provider === 'local') { + // isOwner is useful only in the cloud + isOwner = true; + } else { + isOwner = workspace?.owner && user?.id === workspace?.owner?.id; + } const pageList = (workspace?.blocksuiteWorkspace?.meta.pageMetas as PageMeta[]) ?? []; setAppState({ @@ -107,6 +115,7 @@ export const AppStateProvider = ({ pageList: pageList, currentPage: null, editor: null, + isOwner, }); return workspace; diff --git a/packages/app/src/providers/app-state-provider/interface.ts b/packages/app/src/providers/app-state-provider/interface.ts index 6cb5f5551..c76b2993c 100644 --- a/packages/app/src/providers/app-state-provider/interface.ts +++ b/packages/app/src/providers/app-state-provider/interface.ts @@ -23,6 +23,7 @@ export type AppStateValue = { currentPage: StorePage | null; editor?: EditorContainer | null; synced: boolean; + isOwner?: boolean; }; export type AppStateFunction = { From 251cfc2340d850ad7d3eac2ddfd36b41f63109e6 Mon Sep 17 00:00:00 2001 From: DiamondThree <857159145@qq.com> Date: Thu, 12 Jan 2023 17:16:44 +0800 Subject: [PATCH 12/20] fix: message in affine --- packages/data-center/src/provider/affine/affine.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index 309af9570..944d19c7f 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -21,7 +21,7 @@ import { import { WorkspaceUnit } from '../../workspace-unit.js'; import { createBlocksuiteWorkspace, applyUpdate } from '../../utils/index.js'; import type { SyncMode } from '../../workspace-unit'; -import { MessageCenter } from 'src/message/message.js'; +import { MessageCenter } from '../../message/index.js'; type ChannelMessage = { ws_list: Workspace[]; From 11edef1bbdc893045ecf8c0d99756db121055878 Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Thu, 12 Jan 2023 17:18:40 +0800 Subject: [PATCH 13/20] feat: add new workspaces by arrays --- .../data-center/src/provider/affine/affine.ts | 30 +++++++++++++++---- .../src/provider/affine/apis/workspace.ts | 2 +- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index d4c402777..c389363ab 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -21,7 +21,7 @@ import { import { WorkspaceUnit } from '../../workspace-unit.js'; import { createBlocksuiteWorkspace, applyUpdate } from '../../utils/index.js'; import type { SyncMode } from '../../workspace-unit'; -import { MessageCenter } from 'src/message/message.js'; +import { MessageCenter } from '../../message/index.js'; type ChannelMessage = { ws_list: Workspace[]; @@ -102,10 +102,19 @@ export class AffineProvider extends BaseProvider { }); } - private _handlerAffineListMessage({ ws_details, metadata }: ChannelMessage) { + private async _handlerAffineListMessage({ + ws_details, + metadata, + }: ChannelMessage) { this._logger('receive server message'); - Object.entries(ws_details).forEach(async ([id, detail]) => { + const addedWorkspaces: WorkspaceUnit[] = []; + const removeWorkspaceList = this._workspaces.list().map(w => w.id); + for (const [id, detail] of Object.entries(ws_details)) { const { name, avatar } = metadata[id]; + const index = removeWorkspaceList.indexOf(id); + if (index !== -1) { + removeWorkspaceList.splice(index, 1); + } assert(name); const workspace = { name: name, @@ -122,15 +131,26 @@ export class AffineProvider extends BaseProvider { syncMode: 'core' as SyncMode, }; if (this._workspaces.get(id)) { + // update workspaces this._workspaces.update(id, workspace); } else { const workspaceUnit = await loadWorkspaceUnit( { id, ...workspace }, this._apis ); - this._workspaces.add(workspaceUnit); + addedWorkspaces.push(workspaceUnit); } - }); + } + if (addedWorkspaces.length) { + // add workspaces + this._workspaces.add(addedWorkspaces); + } + if (removeWorkspaceList.length) { + // remove workspaces + removeWorkspaceList.forEach(id => { + this._workspaces.remove(id); + }); + } } private _getWebsocketProvider(workspace: BlocksuiteWorkspace) { diff --git a/packages/data-center/src/provider/affine/apis/workspace.ts b/packages/data-center/src/provider/affine/apis/workspace.ts index 0101832d2..f2455810e 100644 --- a/packages/data-center/src/provider/affine/apis/workspace.ts +++ b/packages/data-center/src/provider/affine/apis/workspace.ts @@ -1,4 +1,4 @@ -import { MessageCenter } from 'src/message/message.js'; +import { MessageCenter } from '../../../message/index.js'; import { bareClient, client } from './request.js'; import type { User } from './user'; From a0c9f9a49c25668cc85df6e7cd1de7232b0cad59 Mon Sep 17 00:00:00 2001 From: DiamondThree <857159145@qq.com> Date: Thu, 12 Jan 2023 17:33:12 +0800 Subject: [PATCH 14/20] feat: add backhome --- packages/app/src/components/404/index.tsx | 16 +++++++++++++++- packages/app/src/pages/404.tsx | 4 ---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/packages/app/src/components/404/index.tsx b/packages/app/src/components/404/index.tsx index 8ed423280..36f1b90a3 100644 --- a/packages/app/src/components/404/index.tsx +++ b/packages/app/src/components/404/index.tsx @@ -1,10 +1,24 @@ import { NotFoundTitle, PageContainer } from './styles'; import { useTranslation } from '@affine/i18n'; +import { Button } from '@/ui/button'; +import { useRouter } from 'next/router'; export const NotfoundPage = () => { const { t } = useTranslation(); + const router = useRouter(); return ( - {t('404 - Page Not Found')} + + {t('404 - Page Not Found')} +

+ +

+
); }; diff --git a/packages/app/src/pages/404.tsx b/packages/app/src/pages/404.tsx index 74f25f07e..0eef5261e 100644 --- a/packages/app/src/pages/404.tsx +++ b/packages/app/src/pages/404.tsx @@ -1,9 +1,5 @@ import NotfoundPage from '@/components/404'; -import { useAppState } from '@/providers/app-state-provider'; export default function Custom404() { - const { workspaceList } = useAppState(); - console.log('workspaceList: ', workspaceList); - return ; } From 0b623a522b828f8bab1922671fa37d1bf634f515 Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Thu, 12 Jan 2023 17:38:18 +0800 Subject: [PATCH 15/20] feat: add remove workspace by ids --- .../data-center/src/provider/affine/affine.ts | 16 ++---- .../src/workspace-unit-collection.ts | 54 ++++++++++++------- 2 files changed, 41 insertions(+), 29 deletions(-) diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index c389363ab..88dab8485 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -141,16 +141,10 @@ export class AffineProvider extends BaseProvider { addedWorkspaces.push(workspaceUnit); } } - if (addedWorkspaces.length) { - // add workspaces - this._workspaces.add(addedWorkspaces); - } - if (removeWorkspaceList.length) { - // remove workspaces - removeWorkspaceList.forEach(id => { - this._workspaces.remove(id); - }); - } + // add workspaces + this._workspaces.add(addedWorkspaces); + // remove workspaces + this._workspaces.remove(removeWorkspaceList); } private _getWebsocketProvider(workspace: BlocksuiteWorkspace) { @@ -174,7 +168,7 @@ export class AffineProvider extends BaseProvider { blocksuiteWorkspace: BlocksuiteWorkspace, published = false ) { - const { doc, room: workspaceId } = blocksuiteWorkspace; + const { room: workspaceId } = blocksuiteWorkspace; assert(workspaceId, 'Blocksuite Workspace without room(workspaceId).'); const updates = await this._apis.downloadWorkspace(workspaceId, published); await applyUpdate(blocksuiteWorkspace, new Uint8Array(updates)); diff --git a/packages/data-center/src/workspace-unit-collection.ts b/packages/data-center/src/workspace-unit-collection.ts index 7d5576256..b51f5d160 100644 --- a/packages/data-center/src/workspace-unit-collection.ts +++ b/packages/data-center/src/workspace-unit-collection.ts @@ -8,7 +8,7 @@ export interface WorkspaceUnitCollectionScope { get: (workspaceId: string) => WorkspaceUnit | undefined; list: () => WorkspaceUnit[]; add: (workspace: WorkspaceUnit | WorkspaceUnit[]) => void; - remove: (workspaceId: string) => boolean; + remove: (workspaceId: string | string[]) => boolean; clear: () => void; update: ( workspaceId: string, @@ -18,7 +18,7 @@ export interface WorkspaceUnitCollectionScope { export interface WorkspaceUnitCollectionChangeEvent { added?: WorkspaceUnit[]; - deleted?: WorkspaceUnit; + deleted?: WorkspaceUnit[]; updated?: WorkspaceUnit; } @@ -62,16 +62,22 @@ export class WorkspaceUnitCollection { const workspaceUnits = Array.isArray(workspaceUnit) ? workspaceUnit : [workspaceUnit]; + let added = false; workspaceUnits.forEach(workspaceUnit => { if (this._workspaceUnitMap.has(workspaceUnit.id)) { // FIXME: multiple add same workspace return; } + added = true; this._workspaceUnitMap.set(workspaceUnit.id, workspaceUnit); scopedWorkspaceIds.add(workspaceUnit.id); }); + if (!added) { + return; + } + this._events.emit('change', [ { added: workspaceUnits, @@ -79,27 +85,39 @@ export class WorkspaceUnitCollection { ]); }; - const remove = (workspaceId: string) => { - if (!scopedWorkspaceIds.has(workspaceId)) { - return true; - } + const remove = (workspaceId: string | string[]) => { + const workspaceIds = Array.isArray(workspaceId) + ? workspaceId + : [workspaceId]; + const workspaceUnits: WorkspaceUnit[] = []; - const workspaceUnit = this._workspaceUnitMap.get(workspaceId); - if (workspaceUnit) { - const ret = this._workspaceUnitMap.delete(workspaceId); - // If deletion failed, return. - if (!ret) { - return ret; + workspaceIds.forEach(workspaceId => { + if (!scopedWorkspaceIds.has(workspaceId)) { + return; } + const workspaceUnit = this._workspaceUnitMap.get(workspaceId); + if (workspaceUnit) { + const ret = this._workspaceUnitMap.delete(workspaceId); + // If deletion failed, return. + if (!ret) { + return; + } - scopedWorkspaceIds.delete(workspaceId); + workspaceUnits.push(workspaceUnit); + scopedWorkspaceIds.delete(workspaceId); + } + }); - this._events.emit('change', [ - { - deleted: workspaceUnit, - } as WorkspaceUnitCollectionChangeEvent, - ]); + if (!workspaceUnits.length) { + return false; } + + this._events.emit('change', [ + { + deleted: workspaceUnits, + } as WorkspaceUnitCollectionChangeEvent, + ]); + return true; }; From cf47098631db5134d66ea78e153ea2b75380ce01 Mon Sep 17 00:00:00 2001 From: MingLiang Wang Date: Thu, 12 Jan 2023 18:13:44 +0800 Subject: [PATCH 16/20] feat: fix access permission api --- packages/data-center/src/datacenter.ts | 3 ++- packages/data-center/src/provider/affine/affine.ts | 4 ++-- .../src/provider/affine/apis/workspace.ts | 14 +++++++------- packages/data-center/src/provider/base.ts | 7 +++++-- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/packages/data-center/src/datacenter.ts b/packages/data-center/src/datacenter.ts index 551fa009c..e8876ac2d 100644 --- a/packages/data-center/src/datacenter.ts +++ b/packages/data-center/src/datacenter.ts @@ -416,13 +416,14 @@ export class DataCenter { /** * accept invitation * @param {string} inviteCode + * @returns {Promise} permission */ async acceptInvitation(inviteCode: string, providerStr = 'affine') { const provider = this.providerMap.get(providerStr); if (provider) { return await provider.acceptInvitation(inviteCode); } - return []; + return null; } onMessage(cb: (message: Message) => void) { diff --git a/packages/data-center/src/provider/affine/affine.ts b/packages/data-center/src/provider/affine/affine.ts index 88dab8485..6e14e8251 100644 --- a/packages/data-center/src/provider/affine/affine.ts +++ b/packages/data-center/src/provider/affine/affine.ts @@ -399,7 +399,7 @@ export class AffineProvider extends BaseProvider { return this._apis.getWorkspaceMembers({ id }); } - public override async acceptInvitation(invitingCode: string): Promise { - await this._apis.acceptInviting({ invitingCode }); + public override async acceptInvitation(invitingCode: string) { + return await this._apis.acceptInviting({ invitingCode }); } } diff --git a/packages/data-center/src/provider/affine/apis/workspace.ts b/packages/data-center/src/provider/affine/apis/workspace.ts index f2455810e..09574b3e8 100644 --- a/packages/data-center/src/provider/affine/apis/workspace.ts +++ b/packages/data-center/src/provider/affine/apis/workspace.ts @@ -197,13 +197,13 @@ export interface AcceptInvitingParams { export async function acceptInviting( params: AcceptInvitingParams -): Promise { - await bareClient - .post(`api/invitation/${params.invitingCode}`) - .catch(error => { - sendMessage(messageCode.acceptInvitingFailed); - throw new RequestError('accept inviting failed', error); - }); +): Promise { + try { + return bareClient.post(`api/invitation/${params.invitingCode}`).json(); + } catch (error) { + sendMessage(messageCode.acceptInvitingFailed); + throw new RequestError('accept inviting failed', error); + } } export async function uploadBlob(params: { blob: Blob }): Promise { diff --git a/packages/data-center/src/provider/base.ts b/packages/data-center/src/provider/base.ts index 0f0a23ead..eb9a68d74 100644 --- a/packages/data-center/src/provider/base.ts +++ b/packages/data-center/src/provider/base.ts @@ -4,6 +4,7 @@ import { Logger, User } from '../types'; import type { WorkspaceUnitCollectionScope } from '../workspace-unit-collection'; import type { WorkspaceUnitCtorParams, WorkspaceUnit } from '../workspace-unit'; import { Member } from './affine/apis'; +import { Permission } from './affine/apis/workspace.js'; const defaultLogger = () => { return; @@ -233,8 +234,10 @@ export class BaseProvider { * @param {string} inviteCode * @returns */ - public async acceptInvitation(inviteCode: string): Promise { + public async acceptInvitation( + inviteCode: string + ): Promise { inviteCode; - return; + return null; } } From 32a5788504ac9c78ffef66a27d0c6670ccde491f Mon Sep 17 00:00:00 2001 From: DiamondThree <857159145@qq.com> Date: Thu, 12 Jan 2023 18:36:57 +0800 Subject: [PATCH 17/20] feat: add invite info --- .../app/src/hooks/use-workspace-helper.ts | 9 +++ .../app/src/pages/invite/[invite_code].tsx | 63 +++++++++---------- 2 files changed, 37 insertions(+), 35 deletions(-) diff --git a/packages/app/src/hooks/use-workspace-helper.ts b/packages/app/src/hooks/use-workspace-helper.ts index f1dee901d..480ba409c 100644 --- a/packages/app/src/hooks/use-workspace-helper.ts +++ b/packages/app/src/hooks/use-workspace-helper.ts @@ -64,6 +64,14 @@ export const useWorkspaceHelper = () => { currentWorkspace && (await dataCenter.leaveWorkspace(currentWorkspace?.id)); }; + const acceptInvite = async (inviteCode: string) => { + let inviteInfo; + if (inviteCode) { + inviteInfo = await dataCenter.acceptInvitation(inviteCode); + } + return inviteInfo; + }; + return { createWorkspace, publishWorkspace, @@ -71,5 +79,6 @@ export const useWorkspaceHelper = () => { enableWorkspace, deleteWorkSpace, leaveWorkSpace, + acceptInvite, }; }; diff --git a/packages/app/src/pages/invite/[invite_code].tsx b/packages/app/src/pages/invite/[invite_code].tsx index e007a6cd2..22122db13 100644 --- a/packages/app/src/pages/invite/[invite_code].tsx +++ b/packages/app/src/pages/invite/[invite_code].tsx @@ -1,44 +1,36 @@ +import { useWorkspaceHelper } from '@/hooks/use-workspace-helper'; +import { useAppState } from '@/providers/app-state-provider'; import { styled } from '@/styles'; import { Empty } from '@/ui/empty'; -import { Avatar } from '@mui/material'; -// import { getDataCenter } from '@affine/datacenter'; +// import { Avatar } from '@mui/material'; import { useRouter } from 'next/router'; import { useEffect, useState } from 'react'; -const User = ({ name, avatar }: { name: string; avatar?: string }) => { - return ( - - {avatar ? ( - - ) : ( - {name.slice(0, 1)} - )} - {name} - - ); -}; +// const User = ({ name, avatar }: { name: string; avatar?: string }) => { +// return ( +// +// {avatar ? ( +// +// ) : ( +// {name.slice(0, 1)} +// )} +// {name} +// +// ); +// }; export default function DevPage() { const router = useRouter(); const [successInvited, setSuccessInvited] = useState(false); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const [inviteData, setInviteData] = useState(null); + const { acceptInvite } = useWorkspaceHelper(); + const { user } = useAppState(); useEffect(() => { - // getDataCenter() - // .then(dc => - // dc.apis.acceptInviting({ - // invitingCode: router.query.invite_code as string, - // }) - // ) - // .then(data => { - // setSuccessInvited(true); - // setInviteData(data); - // }) - // .catch(err => { - // console.log('err: ', err); - // }); - setSuccessInvited(true); - setInviteData(null); + acceptInvite(router.query.invite_code as string).then(data => { + if (data && data.accepted) { + setSuccessInvited(true); + user && router.push(`/workspace/${data.workspace_id}`); + } + }); }, [router.query.invite_code]); return ( @@ -47,11 +39,12 @@ export default function DevPage() { - invited - you to join - invited */} + {/* you to join */} + {/* + > */} {successInvited ? ( Date: Thu, 12 Jan 2023 18:37:43 +0800 Subject: [PATCH 18/20] fix: add error catch --- packages/app/src/pages/invite/[invite_code].tsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/app/src/pages/invite/[invite_code].tsx b/packages/app/src/pages/invite/[invite_code].tsx index 22122db13..342fa7c48 100644 --- a/packages/app/src/pages/invite/[invite_code].tsx +++ b/packages/app/src/pages/invite/[invite_code].tsx @@ -25,12 +25,13 @@ export default function DevPage() { const { acceptInvite } = useWorkspaceHelper(); const { user } = useAppState(); useEffect(() => { - acceptInvite(router.query.invite_code as string).then(data => { - if (data && data.accepted) { - setSuccessInvited(true); - user && router.push(`/workspace/${data.workspace_id}`); - } - }); + router.query.invite_code && + acceptInvite(router.query.invite_code as string).then(data => { + if (data && data.accepted) { + setSuccessInvited(true); + user && router.push(`/workspace/${data.workspace_id}`); + } + }); }, [router.query.invite_code]); return ( From cea3d13805663b3b467d3d8aca3e14f7a299b08c Mon Sep 17 00:00:00 2001 From: alt0 Date: Thu, 12 Jan 2023 19:50:26 +0800 Subject: [PATCH 19/20] fix: workspace avatar --- .../{index.tsx => Avatar.tsx} | 6 ++- .../workspace-avatar/WorkspaceUnitAvatar.tsx | 39 +++++++++++++++++++ .../src/components/workspace-avatar/index.ts | 2 + .../src/components/workspace-modal/index.tsx | 8 +--- .../WorkspaceSelector/WorkspaceSelector.tsx | 8 ++-- .../src/provider/local/indexeddb/utils.ts | 1 + .../data-center/src/provider/local/local.ts | 2 + pnpm-lock.yaml | 24 ------------ 8 files changed, 55 insertions(+), 35 deletions(-) rename packages/app/src/components/workspace-avatar/{index.tsx => Avatar.tsx} (88%) create mode 100644 packages/app/src/components/workspace-avatar/WorkspaceUnitAvatar.tsx create mode 100644 packages/app/src/components/workspace-avatar/index.ts diff --git a/packages/app/src/components/workspace-avatar/index.tsx b/packages/app/src/components/workspace-avatar/Avatar.tsx similarity index 88% rename from packages/app/src/components/workspace-avatar/index.tsx rename to packages/app/src/components/workspace-avatar/Avatar.tsx index 22f5fdd04..c01808e68 100644 --- a/packages/app/src/components/workspace-avatar/index.tsx +++ b/packages/app/src/components/workspace-avatar/Avatar.tsx @@ -23,7 +23,11 @@ export const WorkspaceAvatar = (props: IWorkspaceAvatar) => { }} > - + ) : ( diff --git a/packages/app/src/components/workspace-avatar/WorkspaceUnitAvatar.tsx b/packages/app/src/components/workspace-avatar/WorkspaceUnitAvatar.tsx new file mode 100644 index 000000000..8a390bddd --- /dev/null +++ b/packages/app/src/components/workspace-avatar/WorkspaceUnitAvatar.tsx @@ -0,0 +1,39 @@ +import { useState, useEffect } from 'react'; +import type { WorkspaceUnit } from '@affine/datacenter'; +import { WorkspaceAvatar as Avatar } from './Avatar'; + +const useAvatar = (workspaceUnit?: WorkspaceUnit) => { + const [avatarUrl, setAvatarUrl] = useState(''); + const avatarId = + workspaceUnit?.avatar || workspaceUnit?.blocksuiteWorkspace?.meta.avatar; + useEffect(() => { + if (avatarId && workspaceUnit?.blocksuiteWorkspace?.blobs) { + workspaceUnit.blocksuiteWorkspace.blobs.then(blobs => { + blobs?.get(avatarId).then(url => setAvatarUrl(url || '')); + }); + } else { + setAvatarUrl(''); + } + }, [avatarId]); + + return avatarUrl; +}; + +export const WorkspaceUnitAvatar = ({ + size = 20, + name, + workspaceUnit, +}: { + size?: number; + name?: string; + workspaceUnit?: WorkspaceUnit | null; +}) => { + const avatarUrl = useAvatar(workspaceUnit || undefined); + return ( + + ); +}; diff --git a/packages/app/src/components/workspace-avatar/index.ts b/packages/app/src/components/workspace-avatar/index.ts new file mode 100644 index 000000000..8d6dfe17b --- /dev/null +++ b/packages/app/src/components/workspace-avatar/index.ts @@ -0,0 +1,2 @@ +export { WorkspaceAvatar } from './Avatar'; +export { WorkspaceUnitAvatar } from './WorkspaceUnitAvatar'; diff --git a/packages/app/src/components/workspace-modal/index.tsx b/packages/app/src/components/workspace-modal/index.tsx index 4328224d8..a34abdb87 100644 --- a/packages/app/src/components/workspace-modal/index.tsx +++ b/packages/app/src/components/workspace-modal/index.tsx @@ -10,7 +10,7 @@ import { AddIcon, } from '@blocksuite/icons'; import { toast } from '@/ui/toast'; -import { WorkspaceAvatar } from '@/components/workspace-avatar'; +import { WorkspaceUnitAvatar } from '@/components/workspace-avatar'; import { useAppState } from '@/providers/app-state-provider'; import { useRouter } from 'next/router'; import { useConfirm } from '@/providers/ConfirmProvider'; @@ -65,11 +65,7 @@ export const WorkspaceModal = ({ open, onClose }: WorkspaceModalProps) => { marginRight: '10px', }} > - + { const [workspaceListShow, setWorkspaceListShow] = useState(false); @@ -23,17 +23,17 @@ export const WorkspaceSelector = () => {
-
diff --git a/packages/data-center/src/provider/local/indexeddb/utils.ts b/packages/data-center/src/provider/local/indexeddb/utils.ts index 0a83282a6..68a4172eb 100644 --- a/packages/data-center/src/provider/local/indexeddb/utils.ts +++ b/packages/data-center/src/provider/local/indexeddb/utils.ts @@ -20,6 +20,7 @@ export const writeUpdatesToLocal = async ( if (updatesStore) { await idb.addAutoKey(updatesStore, currState); } + db.close(); }; export const applyLocalUpdates = async ( diff --git a/packages/data-center/src/provider/local/local.ts b/packages/data-center/src/provider/local/local.ts index 7388c4b2a..f9b819ea4 100644 --- a/packages/data-center/src/provider/local/local.ts +++ b/packages/data-center/src/provider/local/local.ts @@ -8,6 +8,7 @@ import type { import { varStorage as storage } from 'lib0/storage'; import { Workspace as BlocksuiteWorkspace, uuidv4 } from '@blocksuite/store'; import { IndexedDBProvider } from './indexeddb/indexeddb.js'; +import { applyLocalUpdates } from './indexeddb/utils.js'; import assert from 'assert'; import { loadWorkspaceUnit, createWorkspaceUnit } from './utils.js'; import type { WorkspaceUnit } from '../../workspace-unit'; @@ -48,6 +49,7 @@ export class LocalProvider extends BaseProvider { workspace: BlocksuiteWorkspace ): Promise { assert(workspace.room); + await applyLocalUpdates(workspace); await this.linkLocal(workspace); return workspace; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4844bc6a2..f608cb2fa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3011,7 +3011,6 @@ packages: /@next/env/13.1.0: resolution: {integrity: sha512-6iNixFzCndH+Bl4FetQzOMjxCJqg8fs0LAlZviig1K6mIjOWH2m2oPcHcOg1Ta5VCe7Bx5KG1Hs+NrWDUkBt9A==} - dev: false /@next/eslint-plugin-next/12.3.1: resolution: {integrity: sha512-sw+lTf6r6P0j+g/n9y4qdWWI2syPqZx+uc0+B/fRENqfR3KpSid6MIKqc9gNwGhJASazEQ5b3w8h4cAET213jw==} @@ -3034,7 +3033,6 @@ packages: cpu: [arm] os: [android] requiresBuild: true - dev: false optional: true /@next/swc-android-arm64/12.3.1: @@ -3052,7 +3050,6 @@ packages: cpu: [arm64] os: [android] requiresBuild: true - dev: false optional: true /@next/swc-darwin-arm64/12.3.1: @@ -3070,7 +3067,6 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true - dev: false optional: true /@next/swc-darwin-x64/12.3.1: @@ -3088,7 +3084,6 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true - dev: false optional: true /@next/swc-freebsd-x64/12.3.1: @@ -3106,7 +3101,6 @@ packages: cpu: [x64] os: [freebsd] requiresBuild: true - dev: false optional: true /@next/swc-linux-arm-gnueabihf/12.3.1: @@ -3124,7 +3118,6 @@ packages: cpu: [arm] os: [linux] requiresBuild: true - dev: false optional: true /@next/swc-linux-arm64-gnu/12.3.1: @@ -3142,7 +3135,6 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - dev: false optional: true /@next/swc-linux-arm64-musl/12.3.1: @@ -3160,7 +3152,6 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - dev: false optional: true /@next/swc-linux-x64-gnu/12.3.1: @@ -3178,7 +3169,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: false optional: true /@next/swc-linux-x64-musl/12.3.1: @@ -3196,7 +3186,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: false optional: true /@next/swc-win32-arm64-msvc/12.3.1: @@ -3214,7 +3203,6 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true - dev: false optional: true /@next/swc-win32-ia32-msvc/12.3.1: @@ -3232,7 +3220,6 @@ packages: cpu: [ia32] os: [win32] requiresBuild: true - dev: false optional: true /@next/swc-win32-x64-msvc/12.3.1: @@ -3250,7 +3237,6 @@ packages: cpu: [x64] os: [win32] requiresBuild: true - dev: false optional: true /@nodelib/fs.scandir/2.1.5: @@ -3613,7 +3599,6 @@ packages: resolution: {integrity: sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==} dependencies: tslib: 2.4.0 - dev: false /@szmarczak/http-timer/5.0.1: resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==} @@ -4580,7 +4565,6 @@ packages: /client-only/0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} - dev: false /cliui/6.0.0: resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} @@ -7512,7 +7496,6 @@ packages: resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - dev: false /natural-compare-lite/1.4.0: resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} @@ -7635,7 +7618,6 @@ packages: transitivePeerDependencies: - '@babel/core' - babel-plugin-macros - dev: false /node-domexception/1.0.0: resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} @@ -7986,7 +7968,6 @@ packages: nanoid: 3.3.4 picocolors: 1.0.0 source-map-js: 1.0.2 - dev: false /preferred-pm/3.0.3: resolution: {integrity: sha512-+wZgbxNES/KlJs9q40F/1sfOd/j7f1O9JaHcW5Dsn3aUUOZg3L2bjpVUcKV2jvtElYfoTuQiNeMfQJ4kwUAhCQ==} @@ -8156,7 +8137,6 @@ packages: loose-envify: 1.4.0 react: 18.2.0 scheduler: 0.23.0 - dev: false /react-i18next/11.18.6_i18next@21.10.0: resolution: {integrity: sha512-yHb2F9BiT0lqoQDt8loZ5gWP331GwctHz9tYQ8A2EIEUu+CcEdjBLQWli1USG3RdWQt3W+jqQLg/d4rrQR96LA==} @@ -8253,7 +8233,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: loose-envify: 1.4.0 - dev: false /read-pkg-up/7.0.1: resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} @@ -8531,7 +8510,6 @@ packages: resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} dependencies: loose-envify: 1.4.0 - dev: false /schema-utils/2.7.1: resolution: {integrity: sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==} @@ -8690,7 +8668,6 @@ packages: /source-map-js/1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} - dev: false /source-map-support/0.5.13: resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} @@ -8939,7 +8916,6 @@ packages: dependencies: client-only: 0.0.1 react: 18.2.0 - dev: false /stylis/4.0.13: resolution: {integrity: sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==} From f892af6dcd548a6b3f765adbbf830913550c30e0 Mon Sep 17 00:00:00 2001 From: DiamondThree <857159145@qq.com> Date: Fri, 13 Jan 2023 09:59:44 +0800 Subject: [PATCH 20/20] fix:workspace avatar --- .../src/components/workspace-setting/general/General.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/app/src/components/workspace-setting/general/General.tsx b/packages/app/src/components/workspace-setting/general/General.tsx index 0ced889c6..6921282d7 100644 --- a/packages/app/src/components/workspace-setting/general/General.tsx +++ b/packages/app/src/components/workspace-setting/general/General.tsx @@ -13,7 +13,10 @@ import { useAppState } from '@/providers/app-state-provider'; import { WorkspaceDelete } from './delete'; import { WorkspaceLeave } from './leave'; import { Upload } from '@/components/file-upload'; -import { WorkspaceAvatar } from '@/components/workspace-avatar'; +import { + WorkspaceAvatar, + WorkspaceUnitAvatar, +} from '@/components/workspace-avatar'; import { WorkspaceUnit } from '@affine/datacenter'; import { useWorkspaceHelper } from '@/hooks/use-workspace-helper'; export const GeneralPage = ({ workspace }: { workspace: WorkspaceUnit }) => { @@ -49,10 +52,10 @@ export const GeneralPage = ({ workspace }: { workspace: WorkspaceUnit }) => { marginRight: '20px', }} > -