diff --git a/apps/web/src/hooks/__tests__/use-blocksuite-workspace-helper.spec.ts b/apps/web/src/hooks/__tests__/use-blocksuite-workspace-helper.spec.ts index 2ad145c5b1..0e92057448 100644 --- a/apps/web/src/hooks/__tests__/use-blocksuite-workspace-helper.spec.ts +++ b/apps/web/src/hooks/__tests__/use-blocksuite-workspace-helper.spec.ts @@ -14,21 +14,21 @@ import { usePageMeta } from '../use-page-meta'; let blockSuiteWorkspace: BlockSuiteWorkspace; +function handleNewPage(page: Page) { + const pageBlockId = page.addBlock('affine:page', { title: '' }); + const frameId = page.addBlock('affine:frame', {}, pageBlockId); + page.addBlock('affine:paragraph', {}, frameId); +} + beforeEach(() => { blockSuiteWorkspace = new BlockSuiteWorkspace({ id: 'test', }) .register(AffineSchemas) .register(__unstableSchemas); - blockSuiteWorkspace.slots.pageAdded.on(pageId => { - const page = blockSuiteWorkspace.getPage(pageId) as Page; - const pageBlockId = page.addBlock('affine:page', { title: '' }); - const frameId = page.addBlock('affine:frame', {}, pageBlockId); - page.addBlock('affine:paragraph', {}, frameId); - }); - blockSuiteWorkspace.createPage('page0'); - blockSuiteWorkspace.createPage('page1'); - blockSuiteWorkspace.createPage('page2'); + handleNewPage(blockSuiteWorkspace.createPage('page0')); + handleNewPage(blockSuiteWorkspace.createPage('page1')); + handleNewPage(blockSuiteWorkspace.createPage('page2')); }); describe('useBlockSuiteWorkspaceHelper', () => { @@ -46,4 +46,20 @@ describe('useBlockSuiteWorkspaceHelper', () => { pageMetaHook.rerender(); expect(pageMetaHook.result.current.length).toBe(4); }); + + test('milestone', async () => { + expect(blockSuiteWorkspace.meta.pageMetas.length).toBe(3); + const helperHook = renderHook(() => + useBlockSuiteWorkspaceHelper(blockSuiteWorkspace) + ); + await helperHook.result.current.markMilestone('test'); + expect(blockSuiteWorkspace.meta.pageMetas.length).toBe(3); + handleNewPage(helperHook.result.current.createPage('page4')); + expect(blockSuiteWorkspace.meta.pageMetas.length).toBe(4); + expect(await helperHook.result.current.listMilestone()).toHaveProperty( + 'test' + ); + await helperHook.result.current.revertMilestone('test'); + expect(blockSuiteWorkspace.meta.pageMetas.length).toBe(3); + }); }); diff --git a/apps/web/src/hooks/use-blocksuite-workspace-helper.ts b/apps/web/src/hooks/use-blocksuite-workspace-helper.ts index 1c9646ac84..489032f0d3 100644 --- a/apps/web/src/hooks/use-blocksuite-workspace-helper.ts +++ b/apps/web/src/hooks/use-blocksuite-workspace-helper.ts @@ -1,5 +1,10 @@ import type { Page } from '@blocksuite/store'; import { assertExists } from '@blocksuite/store'; +import { + getMilestones, + markMilestone, + revertUpdate, +} from '@toeverything/y-indexeddb'; import { useMemo } from 'react'; import type { BlockSuiteWorkspace } from '../shared'; @@ -13,6 +18,27 @@ export function useBlockSuiteWorkspaceHelper( assertExists(blockSuiteWorkspace); return blockSuiteWorkspace.createPage(pageId, parentId); }, + markMilestone: async (name: string) => { + assertExists(blockSuiteWorkspace); + const doc = blockSuiteWorkspace.doc; + await markMilestone(blockSuiteWorkspace.id, doc, name); + }, + revertMilestone: async (name: string) => { + assertExists(blockSuiteWorkspace); + const doc = blockSuiteWorkspace.doc; + const list = await getMilestones(blockSuiteWorkspace.id); + if (!list) { + throw new Error('no milestone'); + } + const milestone = list[name]; + if (milestone) { + revertUpdate(doc, milestone, () => 'Map'); + } + }, + listMilestone: async () => { + assertExists(blockSuiteWorkspace); + return await getMilestones(blockSuiteWorkspace.id); + }, }), [blockSuiteWorkspace] ); diff --git a/apps/web/src/shared/apis.ts b/apps/web/src/shared/apis.ts index d7a3b5cc8d..0d8c05cbf6 100644 --- a/apps/web/src/shared/apis.ts +++ b/apps/web/src/shared/apis.ts @@ -1,3 +1,4 @@ +import { DebugLogger } from '@affine/debug'; import { config } from '@affine/env'; import { createUserApis, @@ -30,6 +31,8 @@ const affineApis = {} as ReturnType & Object.assign(affineApis, createUserApis(prefixUrl)); Object.assign(affineApis, createWorkspaceApis(prefixUrl)); +const debugLogger = new DebugLogger('affine-debug-apis'); + if (!globalThis.AFFINE_APIS) { globalThis.AFFINE_APIS = affineApis; globalThis.setLogin = (response: LoginResponse) => { diff --git a/packages/y-indexeddb/src/__tests__/index.spec.ts b/packages/y-indexeddb/src/__tests__/index.spec.ts index d92ad54841..b040797dc4 100644 --- a/packages/y-indexeddb/src/__tests__/index.spec.ts +++ b/packages/y-indexeddb/src/__tests__/index.spec.ts @@ -179,10 +179,9 @@ describe('milestone', () => { const map = snapshot.getMap('map'); expect(map.get('1')).toBe(1); } - revertUpdate(doc, milestones.test1, { - map: 'Map', - array: 'Array', - }); + revertUpdate(doc, milestones.test1, key => + key === 'map' ? 'Map' : 'Array' + ); { const map = doc.getMap('map'); expect(map.get('1')).toBe(1); @@ -207,10 +206,9 @@ describe('milestone', () => { const doc2 = new Doc(); applyUpdate(doc2, encodeStateAsUpdate(doc)); - revertUpdate(doc2, milestones.test1, { - map: 'Map', - array: 'Array', - }); + revertUpdate(doc2, milestones.test1, key => + key === 'map' ? 'Map' : 'Array' + ); { const map = doc2.getMap('map'); expect(map.get('1')).toBe(1); diff --git a/packages/y-indexeddb/src/index.ts b/packages/y-indexeddb/src/index.ts index 078e129d34..23f6698a18 100644 --- a/packages/y-indexeddb/src/index.ts +++ b/packages/y-indexeddb/src/index.ts @@ -15,12 +15,10 @@ const snapshotOrigin = Symbol('snapshot-origin'); let mergeCount = 500; -type Metadata = Record; - export function revertUpdate( doc: Doc, snapshotUpdate: Uint8Array, - metadata: Metadata + getMetadata: (key: string) => 'Text' | 'Map' | 'Array' ) { const snapshotDoc = new Doc(); applyUpdate(snapshotDoc, snapshotUpdate, snapshotOrigin); @@ -34,11 +32,12 @@ export function revertUpdate( ); const undoManager = new UndoManager( [...snapshotDoc.share.keys()].map(key => { - if (metadata[key] === 'Text') { + const type = getMetadata(key); + if (type === 'Text') { return snapshotDoc.getText(key); - } else if (metadata[key] === 'Map') { + } else if (type === 'Map') { return snapshotDoc.getMap(key); - } else if (metadata[key] === 'Array') { + } else if (type === 'Array') { return snapshotDoc.getArray(key); } throw new Error('Unknown type');