From 1e3499c323485d439db54fe733f33a25ee6443bb Mon Sep 17 00:00:00 2001 From: EYHN Date: Tue, 30 Jan 2024 06:31:26 +0000 Subject: [PATCH] feat(infra): page infra (#5618) --- packages/common/infra/src/index.ts | 3 ++ .../infra/src/page/__tests__/page.spec.ts | 31 +++++++++++++ packages/common/infra/src/page/context.ts | 21 +++++++++ packages/common/infra/src/page/index.ts | 25 ++++++++++ packages/common/infra/src/page/list.ts | 28 +++++++++++ packages/common/infra/src/page/manager.ts | 46 +++++++++++++++++++ packages/common/infra/src/page/page.ts | 15 ++++++ .../common/infra/src/page/service-scope.ts | 4 ++ 8 files changed, 173 insertions(+) create mode 100644 packages/common/infra/src/page/__tests__/page.spec.ts create mode 100644 packages/common/infra/src/page/context.ts create mode 100644 packages/common/infra/src/page/index.ts create mode 100644 packages/common/infra/src/page/list.ts create mode 100644 packages/common/infra/src/page/manager.ts create mode 100644 packages/common/infra/src/page/page.ts create mode 100644 packages/common/infra/src/page/service-scope.ts diff --git a/packages/common/infra/src/index.ts b/packages/common/infra/src/index.ts index d4d5815909..75538c5621 100644 --- a/packages/common/infra/src/index.ts +++ b/packages/common/infra/src/index.ts @@ -4,12 +4,14 @@ export * from './blocksuite'; export * from './command'; export * from './di'; export * from './livedata'; +export * from './page'; export * from './storage'; export * from './utils'; export * from './workspace'; import type { ServiceCollection } from './di'; import { CleanupService } from './lifecycle'; +import { configurePageServices } from './page'; import { GlobalCache, GlobalState, MemoryMemento } from './storage'; import { configureTestingWorkspaceServices, @@ -19,6 +21,7 @@ import { export function configureInfraServices(services: ServiceCollection) { services.add(CleanupService); configureWorkspaceServices(services); + configurePageServices(services); } export function configureTestingInfraServices(services: ServiceCollection) { diff --git a/packages/common/infra/src/page/__tests__/page.spec.ts b/packages/common/infra/src/page/__tests__/page.spec.ts new file mode 100644 index 0000000000..a8ce869346 --- /dev/null +++ b/packages/common/infra/src/page/__tests__/page.spec.ts @@ -0,0 +1,31 @@ +import { WorkspaceFlavour } from '@affine/env/workspace'; +import { describe, expect, test } from 'vitest'; + +import { configureInfraServices, configureTestingInfraServices } from '../..'; +import { ServiceCollection } from '../../di'; +import { WorkspaceManager } from '../../workspace'; +import { PageListService } from '..'; + +describe('Page System', () => { + test('basic', async () => { + const services = new ServiceCollection(); + configureInfraServices(services); + configureTestingInfraServices(services); + + const provider = services.provider(); + const workspaceManager = provider.get(WorkspaceManager); + + const { workspace } = workspaceManager.open( + await workspaceManager.createWorkspace(WorkspaceFlavour.LOCAL) + ); + + const pageListService = workspace.services.get(PageListService); + expect(pageListService.pages.value.length).toBe(0); + + workspace.blockSuiteWorkspace.createPage({ + id: 'page0', + }); + + expect(pageListService.pages.value.length).toBe(1); + }); +}); diff --git a/packages/common/infra/src/page/context.ts b/packages/common/infra/src/page/context.ts new file mode 100644 index 0000000000..2102cc78ca --- /dev/null +++ b/packages/common/infra/src/page/context.ts @@ -0,0 +1,21 @@ +import type { Page as BlockSuitePage, PageMeta } from '@blocksuite/store'; + +import { createIdentifier, type ServiceCollection } from '../di'; +import { PageScope } from './service-scope'; + +export const BlockSuitePageContext = createIdentifier( + 'BlockSuitePageContext' +); + +export const PageMetaContext = createIdentifier('PageMetaContext'); + +export function configurePageContext( + services: ServiceCollection, + blockSuitePage: BlockSuitePage, + pageMeta: PageMeta +) { + services + .scope(PageScope) + .addImpl(PageMetaContext, pageMeta) + .addImpl(BlockSuitePageContext, blockSuitePage); +} diff --git a/packages/common/infra/src/page/index.ts b/packages/common/infra/src/page/index.ts new file mode 100644 index 0000000000..f290f43b99 --- /dev/null +++ b/packages/common/infra/src/page/index.ts @@ -0,0 +1,25 @@ +export * from './context'; +export * from './list'; +export * from './manager'; +export * from './page'; +export * from './service-scope'; + +import { type ServiceCollection, ServiceProvider } from '../di'; +import { CleanupService } from '../lifecycle'; +import { Workspace, WorkspaceScope } from '../workspace'; +import { BlockSuitePageContext, PageMetaContext } from './context'; +import { PageListService } from './list'; +import { PageManager } from './manager'; +import { Page } from './page'; +import { PageScope } from './service-scope'; + +export function configurePageServices(services: ServiceCollection) { + services + .scope(WorkspaceScope) + .add(PageListService, [Workspace]) + .add(PageManager, [Workspace, ServiceProvider]); + services + .scope(PageScope) + .add(CleanupService) + .add(Page, [PageMetaContext, BlockSuitePageContext, ServiceProvider]); +} diff --git a/packages/common/infra/src/page/list.ts b/packages/common/infra/src/page/list.ts new file mode 100644 index 0000000000..834391da9f --- /dev/null +++ b/packages/common/infra/src/page/list.ts @@ -0,0 +1,28 @@ +import type { PageMeta } from '@blocksuite/store'; +import { Observable } from 'rxjs'; + +import { LiveData } from '../livedata'; +import type { Workspace } from '../workspace'; + +export class PageListService { + constructor(private readonly workspace: Workspace) {} + + public readonly pages = LiveData.from( + new Observable(subscriber => { + subscriber.next( + Array.from(this.workspace.blockSuiteWorkspace.meta.pageMetas) + ); + + const dispose = + this.workspace.blockSuiteWorkspace.meta.pageMetasUpdated.on(() => { + subscriber.next( + Array.from(this.workspace.blockSuiteWorkspace.meta.pageMetas) + ); + }).dispose; + return () => { + dispose(); + }; + }), + [] + ); +} diff --git a/packages/common/infra/src/page/manager.ts b/packages/common/infra/src/page/manager.ts new file mode 100644 index 0000000000..c3e56ddfb6 --- /dev/null +++ b/packages/common/infra/src/page/manager.ts @@ -0,0 +1,46 @@ +import type { PageMeta } from '@blocksuite/store'; + +import type { ServiceProvider } from '../di'; +import { ObjectPool, type RcRef } from '../utils/object-pool'; +import type { Workspace } from '../workspace'; +import { configurePageContext } from './context'; +import { Page } from './page'; +import { PageScope } from './service-scope'; + +export class PageManager { + pool = new ObjectPool({}); + + constructor( + private readonly workspace: Workspace, + private readonly serviceProvider: ServiceProvider + ) {} + + open(pageMeta: PageMeta): RcRef { + const blockSuitePage = this.workspace.blockSuiteWorkspace.getPage( + pageMeta.id + ); + if (!blockSuitePage) { + throw new Error('Page not found'); + } + + const exists = this.pool.get(pageMeta.id); + if (exists) { + return exists; + } + + const serviceCollection = this.serviceProvider.collection + // avoid to modify the original service collection + .clone(); + + configurePageContext(serviceCollection, blockSuitePage, pageMeta); + + const provider = serviceCollection.provider( + PageScope, + this.serviceProvider + ); + + const page = provider.get(Page); + + return this.pool.put(pageMeta.id, page); + } +} diff --git a/packages/common/infra/src/page/page.ts b/packages/common/infra/src/page/page.ts new file mode 100644 index 0000000000..bd330cf326 --- /dev/null +++ b/packages/common/infra/src/page/page.ts @@ -0,0 +1,15 @@ +import type { Page as BlockSuitePage } from '@blocksuite/store'; +import { type PageMeta } from '@blocksuite/store'; +import type { ServiceProvider } from '@toeverything/infra/di'; + +export class Page { + get id() { + return this.meta.id; + } + + constructor( + public readonly meta: PageMeta, + public readonly blockSuitePage: BlockSuitePage, + public readonly services: ServiceProvider + ) {} +} diff --git a/packages/common/infra/src/page/service-scope.ts b/packages/common/infra/src/page/service-scope.ts new file mode 100644 index 0000000000..31cdaca345 --- /dev/null +++ b/packages/common/infra/src/page/service-scope.ts @@ -0,0 +1,4 @@ +import { createScope, type ServiceScope } from '../di'; +import { WorkspaceScope } from '../workspace'; + +export const PageScope: ServiceScope = createScope('page', WorkspaceScope);