diff --git a/apps/electron/e2e/workspace.spec.ts b/apps/electron/e2e/workspace.spec.ts index 9886fd219b..0cdd365871 100644 --- a/apps/electron/e2e/workspace.spec.ts +++ b/apps/electron/e2e/workspace.spec.ts @@ -17,7 +17,7 @@ test('check workspace has a DB file', async ({ appInfo, workspace }) => { expect(await fs.exists(dbPath)).toBe(true); }); -test('move workspace db file', async ({ page, appInfo, workspace }) => { +test.skip('move workspace db file', async ({ page, appInfo, workspace }) => { const w = await workspace.current(); await page.getByTestId('slider-bar-workspace-setting-button').click(); await expect(page.getByTestId('setting-modal')).toBeVisible(); diff --git a/apps/electron/src/helper/db/secondary-db.ts b/apps/electron/src/helper/db/secondary-db.ts index 753acc93ec..7c0be42e62 100644 --- a/apps/electron/src/helper/db/secondary-db.ts +++ b/apps/electron/src/helper/db/secondary-db.ts @@ -115,19 +115,43 @@ export class SecondaryWorkspaceSQLiteDB extends BaseSQLiteAdapter { } setupListener(docId?: string) { + logger.debug( + 'SecondaryWorkspaceSQLiteDB:setupListener', + this.workspaceId, + docId + ); const doc = this.getDoc(docId); - if (!doc) { + const upstreamDoc = this.upstream.getDoc(docId); + if (!doc || !upstreamDoc) { + logger.warn( + '[SecondaryWorkspaceSQLiteDB] setupListener: doc not found', + docId + ); return; } const onUpstreamUpdate = (update: Uint8Array, origin: YOrigin) => { - if (origin === 'renderer') { + logger.debug( + 'SecondaryWorkspaceSQLiteDB:onUpstreamUpdate', + origin, + this.workspaceId, + docId, + update.length + ); + if (origin === 'renderer' || origin === 'self') { // update to upstream yDoc should be replicated to self yDoc this.applyUpdate(update, 'upstream', docId); } }; const onSelfUpdate = async (update: Uint8Array, origin: YOrigin) => { + logger.debug( + 'SecondaryWorkspaceSQLiteDB:onSelfUpdate', + origin, + this.workspaceId, + docId, + update.length + ); // for self update from upstream, we need to push it to external DB if (origin === 'upstream') { await this.addUpdateToUpdateQueue({ @@ -147,15 +171,19 @@ export class SecondaryWorkspaceSQLiteDB extends BaseSQLiteAdapter { }); }; + doc.subdocs.forEach(subdoc => { + this.setupListener(subdoc.guid); + }); + // listen to upstream update this.upstream.yDoc.on('update', onUpstreamUpdate); - this.yDoc.on('update', onSelfUpdate); - this.yDoc.on('subdocs', onSubdocs); + doc.on('update', onSelfUpdate); + doc.on('subdocs', onSubdocs); this.unsubscribers.add(() => { this.upstream.yDoc.off('update', onUpstreamUpdate); - this.yDoc.off('update', onSelfUpdate); - this.yDoc.off('subdocs', onSubdocs); + doc.off('update', onSelfUpdate); + doc.off('subdocs', onSubdocs); }); } @@ -188,7 +216,10 @@ export class SecondaryWorkspaceSQLiteDB extends BaseSQLiteAdapter { if (doc) { Y.applyUpdate(this.yDoc, data, origin); } else { - logger.warn('applyUpdate: doc not found', docId); + logger.warn( + '[SecondaryWorkspaceSQLiteDB] applyUpdate: doc not found', + docId + ); } }; diff --git a/apps/electron/src/helper/db/workspace-db-adapter.ts b/apps/electron/src/helper/db/workspace-db-adapter.ts index dfdb455fec..18d929cdd2 100644 --- a/apps/electron/src/helper/db/workspace-db-adapter.ts +++ b/apps/electron/src/helper/db/workspace-db-adapter.ts @@ -151,7 +151,7 @@ export class WorkspaceSQLiteDB extends BaseSQLiteAdapter { if (doc) { Y.applyUpdate(doc, data, origin); } else { - logger.warn('applyUpdate: doc not found', docId); + logger.warn('[WorkspaceSQLiteDB] applyUpdate: doc not found', docId); } }; diff --git a/apps/electron/src/helper/dialog/dialog.ts b/apps/electron/src/helper/dialog/dialog.ts index 6a6fd756ba..d58bd4a4a9 100644 --- a/apps/electron/src/helper/dialog/dialog.ts +++ b/apps/electron/src/helper/dialog/dialog.ts @@ -227,7 +227,6 @@ export async function loadDBFile(): Promise { await storeWorkspaceMeta(workspaceId, { id: workspaceId, mainDBPath: internalFilePath, - secondaryDBPath: filePath, }); return { workspaceId }; diff --git a/apps/web/preset.config.mjs b/apps/web/preset.config.mjs index f7af4cc4bf..8964a26511 100644 --- a/apps/web/preset.config.mjs +++ b/apps/web/preset.config.mjs @@ -28,6 +28,7 @@ const buildPreset = { enableNewSettingModal: true, enableNewSettingUnstableApi: false, enableSQLiteProvider: true, + enableMoveDatabase: false, enableNotificationCenter: false, enableCloud: false, }, @@ -44,6 +45,7 @@ const buildPreset = { enableNewSettingModal: true, enableNewSettingUnstableApi: false, enableSQLiteProvider: true, + enableMoveDatabase: false, enableNotificationCenter: true, enableCloud: false, }, @@ -90,6 +92,9 @@ const environmentPreset = { enableCloud: process.env.ENABLE_CLOUD ? process.env.ENABLE_CLOUD === 'true' : currentBuildPreset.enableCloud, + enableMoveDatabase: process.env.ENABLE_MOVE_DATABASE + ? process.env.ENABLE_MOVE_DATABASE === 'true' + : currentBuildPreset.enableMoveDatabase, }; /** diff --git a/apps/web/src/components/affine/new-workspace-setting-detail/index.tsx b/apps/web/src/components/affine/new-workspace-setting-detail/index.tsx index 82b1860ebd..e16450af39 100644 --- a/apps/web/src/components/affine/new-workspace-setting-detail/index.tsx +++ b/apps/web/src/components/affine/new-workspace-setting-detail/index.tsx @@ -9,7 +9,7 @@ import type { } from '@affine/env/workspace'; import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name'; -import type { FC } from 'react'; +import { type FC, useMemo } from 'react'; import { useWorkspace } from '../../../hooks/use-workspace'; import { DeleteLeaveWorkspace } from './delete-leave-workspace'; @@ -40,6 +40,21 @@ export const WorkspaceSettingDetail: FC = ({ const workspace = useWorkspace(workspaceId); const [name] = useBlockSuiteWorkspaceName(workspace.blockSuiteWorkspace); + const storageAndExportSetting = useMemo(() => { + if (environment.isDesktop) { + return ( + + {runtimeConfig.enableMoveDatabase ? ( + + ) : null} + + + ); + } else { + return null; + } + }, [t, workspace]); + return ( <> = ({ {...props} /> - {environment.isDesktop ? ( - - - - - ) : null} - + {storageAndExportSetting}