feat(infra): page infra (#5618)

This commit is contained in:
EYHN 2024-01-30 06:31:26 +00:00
parent 2e71c980cf
commit 1e3499c323
No known key found for this signature in database
GPG Key ID: 46C9E26A75AB276C
8 changed files with 173 additions and 0 deletions

View File

@ -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) {

View File

@ -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);
});
});

View File

@ -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<BlockSuitePage>(
'BlockSuitePageContext'
);
export const PageMetaContext = createIdentifier<PageMeta>('PageMetaContext');
export function configurePageContext(
services: ServiceCollection,
blockSuitePage: BlockSuitePage,
pageMeta: PageMeta
) {
services
.scope(PageScope)
.addImpl(PageMetaContext, pageMeta)
.addImpl(BlockSuitePageContext, blockSuitePage);
}

View File

@ -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]);
}

View File

@ -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<PageMeta[]>(
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();
};
}),
[]
);
}

View File

@ -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<string, Page>({});
constructor(
private readonly workspace: Workspace,
private readonly serviceProvider: ServiceProvider
) {}
open(pageMeta: PageMeta): RcRef<Page> {
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);
}
}

View File

@ -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
) {}
}

View File

@ -0,0 +1,4 @@
import { createScope, type ServiceScope } from '../di';
import { WorkspaceScope } from '../workspace';
export const PageScope: ServiceScope = createScope('page', WorkspaceScope);