mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-27 10:52:40 +08:00
refactor(core): refactor atom to use di (#5831)
To support multiple instances, this PR removes some atoms and implements them using the new DI system. removed atom - `pageSettingsAtom` - `currentPageIdAtom` - `currentModeAtom`
This commit is contained in:
@@ -1,31 +0,0 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
@@ -1,21 +1,23 @@
|
||||
import type { Page as BlockSuitePage, PageMeta } from '@blocksuite/store';
|
||||
import type { Page as BlockSuitePage } from '@blocksuite/store';
|
||||
|
||||
import { createIdentifier, type ServiceCollection } from '../di';
|
||||
import type { PageRecord } from './record';
|
||||
import { PageScope } from './service-scope';
|
||||
|
||||
export const BlockSuitePageContext = createIdentifier<BlockSuitePage>(
|
||||
'BlockSuitePageContext'
|
||||
);
|
||||
|
||||
export const PageMetaContext = createIdentifier<PageMeta>('PageMetaContext');
|
||||
export const PageRecordContext =
|
||||
createIdentifier<PageRecord>('PageRecordContext');
|
||||
|
||||
export function configurePageContext(
|
||||
services: ServiceCollection,
|
||||
blockSuitePage: BlockSuitePage,
|
||||
pageMeta: PageMeta
|
||||
pageRecord: PageRecord
|
||||
) {
|
||||
services
|
||||
.scope(PageScope)
|
||||
.addImpl(PageMetaContext, pageMeta)
|
||||
.addImpl(PageRecordContext, pageRecord)
|
||||
.addImpl(BlockSuitePageContext, blockSuitePage);
|
||||
}
|
||||
|
||||
@@ -1,25 +1,26 @@
|
||||
export * from './context';
|
||||
export * from './list';
|
||||
export * from './manager';
|
||||
export * from './page';
|
||||
export * from './record';
|
||||
export * from './record-list';
|
||||
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 { Workspace, WorkspaceLocalState, WorkspaceScope } from '../workspace';
|
||||
import { BlockSuitePageContext, PageRecordContext } from './context';
|
||||
import { PageManager } from './manager';
|
||||
import { Page } from './page';
|
||||
import { PageRecordList } from './record-list';
|
||||
import { PageScope } from './service-scope';
|
||||
|
||||
export function configurePageServices(services: ServiceCollection) {
|
||||
services
|
||||
.scope(WorkspaceScope)
|
||||
.add(PageListService, [Workspace])
|
||||
.add(PageManager, [Workspace, PageListService, ServiceProvider]);
|
||||
.add(PageManager, [Workspace, PageRecordList, ServiceProvider])
|
||||
.add(PageRecordList, [Workspace, WorkspaceLocalState]);
|
||||
|
||||
services
|
||||
.scope(PageScope)
|
||||
.add(CleanupService)
|
||||
.add(Page, [PageMetaContext, BlockSuitePageContext, ServiceProvider]);
|
||||
.add(Page, [PageRecordContext, BlockSuitePageContext, ServiceProvider]);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import type { PageMeta } from '@blocksuite/store';
|
||||
|
||||
import type { ServiceProvider } from '../di';
|
||||
import { ObjectPool } from '../utils/object-pool';
|
||||
import type { Workspace } from '../workspace';
|
||||
import type { PageRecordList } from '.';
|
||||
import { configurePageContext } from './context';
|
||||
import type { PageListService } from './list';
|
||||
import { Page } from './page';
|
||||
import { PageScope } from './service-scope';
|
||||
|
||||
@@ -13,28 +11,21 @@ export class PageManager {
|
||||
|
||||
constructor(
|
||||
private readonly workspace: Workspace,
|
||||
private readonly pageList: PageListService,
|
||||
private readonly pageRecordList: PageRecordList,
|
||||
private readonly serviceProvider: ServiceProvider
|
||||
) {}
|
||||
|
||||
openByPageId(pageId: string) {
|
||||
const pageMeta = this.pageList.getPageMetaById(pageId);
|
||||
if (!pageMeta) {
|
||||
throw new Error('Page not found');
|
||||
open(pageId: string) {
|
||||
const pageRecord = this.pageRecordList.record(pageId).value;
|
||||
if (!pageRecord) {
|
||||
throw new Error('Page record not found');
|
||||
}
|
||||
|
||||
return this.open(pageMeta);
|
||||
}
|
||||
|
||||
open(pageMeta: PageMeta) {
|
||||
const blockSuitePage = this.workspace.blockSuiteWorkspace.getPage(
|
||||
pageMeta.id
|
||||
);
|
||||
const blockSuitePage = this.workspace.blockSuiteWorkspace.getPage(pageId);
|
||||
if (!blockSuitePage) {
|
||||
throw new Error('Page not found');
|
||||
}
|
||||
|
||||
const exists = this.pool.get(pageMeta.id);
|
||||
const exists = this.pool.get(pageId);
|
||||
if (exists) {
|
||||
return { page: exists.obj, release: exists.release };
|
||||
}
|
||||
@@ -43,7 +34,7 @@ export class PageManager {
|
||||
// avoid to modify the original service collection
|
||||
.clone();
|
||||
|
||||
configurePageContext(serviceCollection, blockSuitePage, pageMeta);
|
||||
configurePageContext(serviceCollection, blockSuitePage, pageRecord);
|
||||
|
||||
const provider = serviceCollection.provider(
|
||||
PageScope,
|
||||
@@ -52,7 +43,7 @@ export class PageManager {
|
||||
|
||||
const page = provider.get(Page);
|
||||
|
||||
const { obj, release } = this.pool.put(pageMeta.id, page);
|
||||
const { obj, release } = this.pool.put(pageId, page);
|
||||
|
||||
return { page: obj, release };
|
||||
}
|
||||
|
||||
@@ -1,15 +1,28 @@
|
||||
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;
|
||||
}
|
||||
import type { PageMode, PageRecord } from './record';
|
||||
|
||||
export class Page {
|
||||
constructor(
|
||||
public readonly meta: PageMeta,
|
||||
public readonly record: PageRecord,
|
||||
public readonly blockSuitePage: BlockSuitePage,
|
||||
public readonly services: ServiceProvider
|
||||
) {}
|
||||
|
||||
get id() {
|
||||
return this.record.id;
|
||||
}
|
||||
|
||||
readonly mete = this.record.meta;
|
||||
readonly mode = this.record.mode;
|
||||
readonly title = this.record.title;
|
||||
|
||||
setMode(mode: PageMode) {
|
||||
this.record.setMode(mode);
|
||||
}
|
||||
|
||||
toggleMode() {
|
||||
this.record.toggleMode();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,35 @@
|
||||
import type { PageMeta } from '@blocksuite/store';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { LiveData } from '../livedata';
|
||||
import { SyncEngineStep, type Workspace } from '../workspace';
|
||||
import {
|
||||
SyncEngineStep,
|
||||
type Workspace,
|
||||
type WorkspaceLocalState,
|
||||
} from '../workspace';
|
||||
import { PageRecord } from './record';
|
||||
|
||||
export class PageListService {
|
||||
constructor(private readonly workspace: Workspace) {}
|
||||
export class PageRecordList {
|
||||
constructor(
|
||||
private readonly workspace: Workspace,
|
||||
private readonly localState: WorkspaceLocalState
|
||||
) {}
|
||||
|
||||
public readonly pages = LiveData.from<PageMeta[]>(
|
||||
public readonly records = LiveData.from<PageRecord[]>(
|
||||
new Observable(subscriber => {
|
||||
subscriber.next(
|
||||
Array.from(this.workspace.blockSuiteWorkspace.meta.pageMetas)
|
||||
);
|
||||
const emit = () => {
|
||||
subscriber.next(
|
||||
this.workspace.blockSuiteWorkspace.meta.pageMetas.map(
|
||||
v => new PageRecord(v.id, this.workspace, this.localState)
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
emit();
|
||||
|
||||
const dispose =
|
||||
this.workspace.blockSuiteWorkspace.meta.pageMetasUpdated.on(() => {
|
||||
subscriber.next(
|
||||
Array.from(this.workspace.blockSuiteWorkspace.meta.pageMetas)
|
||||
);
|
||||
}).dispose;
|
||||
this.workspace.blockSuiteWorkspace.meta.pageMetasUpdated.on(
|
||||
emit
|
||||
).dispose;
|
||||
return () => {
|
||||
dispose();
|
||||
};
|
||||
@@ -44,7 +55,7 @@ export class PageListService {
|
||||
false
|
||||
);
|
||||
|
||||
public getPageMetaById(id: string) {
|
||||
return this.pages.value.find(page => page.id === id);
|
||||
public record(id: string) {
|
||||
return this.records.map(record => record.find(record => record.id === id));
|
||||
}
|
||||
}
|
||||
65
packages/common/infra/src/page/record.ts
Normal file
65
packages/common/infra/src/page/record.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import type { PageMeta } from '@blocksuite/store';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { LiveData } from '../livedata';
|
||||
import type { Workspace, WorkspaceLocalState } from '../workspace';
|
||||
|
||||
export type PageMode = 'edgeless' | 'page';
|
||||
|
||||
export class PageRecord {
|
||||
constructor(
|
||||
public readonly id: string,
|
||||
private readonly workspace: Workspace,
|
||||
private readonly localState: WorkspaceLocalState
|
||||
) {}
|
||||
|
||||
meta = LiveData.from<PageMeta>(
|
||||
new Observable(subscriber => {
|
||||
const emit = () => {
|
||||
const meta = this.workspace.blockSuiteWorkspace.meta.pageMetas.find(
|
||||
page => page.id === this.id
|
||||
);
|
||||
if (meta === undefined) {
|
||||
return;
|
||||
}
|
||||
subscriber.next(meta);
|
||||
};
|
||||
|
||||
emit();
|
||||
|
||||
const dispose =
|
||||
this.workspace.blockSuiteWorkspace.meta.pageMetasUpdated.on(
|
||||
emit
|
||||
).dispose;
|
||||
return () => {
|
||||
dispose();
|
||||
};
|
||||
}),
|
||||
{
|
||||
id: this.id,
|
||||
title: '',
|
||||
tags: [],
|
||||
createDate: 0,
|
||||
}
|
||||
);
|
||||
|
||||
setMeta(meta: Partial<PageMeta>): void {
|
||||
this.workspace.blockSuiteWorkspace.setPageMeta(this.id, meta);
|
||||
}
|
||||
|
||||
mode: LiveData<PageMode> = LiveData.from(
|
||||
this.localState.watch<PageMode>(`page:${this.id}:mode`),
|
||||
'page'
|
||||
).map(mode => (mode === 'edgeless' ? 'edgeless' : 'page'));
|
||||
|
||||
setMode(mode: PageMode) {
|
||||
this.localState.set(`page:${this.id}:mode`, mode);
|
||||
}
|
||||
|
||||
toggleMode() {
|
||||
this.setMode(this.mode.value === 'edgeless' ? 'page' : 'edgeless');
|
||||
return this.mode.value;
|
||||
}
|
||||
|
||||
title = this.meta.map(meta => meta.title);
|
||||
}
|
||||
Reference in New Issue
Block a user