mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-14 21:27:20 +00:00
feat(editor): feature flag store extension builder (#12235)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced feature flag synchronization for enhanced control over feature availability. - Added new configuration options for store management, allowing initialization and feature flag setup. - **Improvements** - Updated how store extensions are accessed throughout the app for more robust initialization and configuration. - Enhanced workspace entities to support feature flag services, improving flexibility for workspace-specific features. - Centralized configuration of storage implementations for Electron environments. - **Refactor** - Simplified editor module by removing direct feature flag synchronization logic. - Streamlined imports and configuration for storage modules, especially in Electron-based apps. - **Bug Fixes** - Ensured consistent retrieval of store extensions across various modules and platforms. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -5,10 +5,7 @@ import { DefaultTool } from '@blocksuite/affine/blocks/surface';
|
||||
import type { DocTitle } from '@blocksuite/affine/fragments/doc-title';
|
||||
import type { DocMode, ReferenceParams } from '@blocksuite/affine/model';
|
||||
import { HighlightSelection } from '@blocksuite/affine/shared/selection';
|
||||
import {
|
||||
DocModeProvider,
|
||||
FeatureFlagService as BSFeatureFlagService,
|
||||
} from '@blocksuite/affine/shared/services';
|
||||
import { DocModeProvider } from '@blocksuite/affine/shared/services';
|
||||
import { GfxControllerIdentifier } from '@blocksuite/affine/std/gfx';
|
||||
import type { InlineEditor } from '@blocksuite/std/inline';
|
||||
import { effect } from '@preact/signals-core';
|
||||
@@ -17,7 +14,6 @@ import { defaults, isEqual, omit } from 'lodash-es';
|
||||
import { skip } from 'rxjs';
|
||||
|
||||
import type { DocService } from '../../doc';
|
||||
import { AFFINE_FLAGS, type FeatureFlagService } from '../../feature-flag';
|
||||
import { paramsParseOptions, preprocessParams } from '../../navigation/utils';
|
||||
import type { WorkbenchView } from '../../workbench';
|
||||
import type { WorkspaceService } from '../../workspace';
|
||||
@@ -196,7 +192,6 @@ export class Editor extends Entity {
|
||||
throw new Error('already bound');
|
||||
}
|
||||
|
||||
this._setupBlocksuiteEditorFlags(editorContainer);
|
||||
this.editorContainer$.next(editorContainer);
|
||||
const unsubs: (() => void)[] = [];
|
||||
|
||||
@@ -325,24 +320,9 @@ export class Editor extends Entity {
|
||||
};
|
||||
}
|
||||
|
||||
private _setupBlocksuiteEditorFlags(editorContainer: AffineEditorContainer) {
|
||||
const affineFeatureFlagService = this.featureFlagService;
|
||||
const bsFeatureFlagService = editorContainer.doc.get(BSFeatureFlagService);
|
||||
Object.entries(AFFINE_FLAGS).forEach(([key, flag]) => {
|
||||
if (flag.category === 'blocksuite') {
|
||||
const value =
|
||||
affineFeatureFlagService.flags[key as keyof AFFINE_FLAGS].value;
|
||||
if (value !== undefined) {
|
||||
bsFeatureFlagService.setFlag(flag.bsFlag, value);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly docService: DocService,
|
||||
private readonly workspaceService: WorkspaceService,
|
||||
private readonly featureFlagService: FeatureFlagService
|
||||
private readonly workspaceService: WorkspaceService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { type Framework } from '@toeverything/infra';
|
||||
|
||||
import { DocScope, DocService } from '../doc';
|
||||
import { FeatureFlagService } from '../feature-flag';
|
||||
import { WorkspaceScope, WorkspaceService } from '../workspace';
|
||||
import { Editor } from './entities/editor';
|
||||
import { EditorScope } from './scopes/editor';
|
||||
@@ -19,7 +18,7 @@ export function configureEditorModule(framework: Framework) {
|
||||
.scope(WorkspaceScope)
|
||||
.scope(DocScope)
|
||||
.service(EditorsService)
|
||||
.entity(Editor, [DocService, WorkspaceService, FeatureFlagService])
|
||||
.entity(Editor, [DocService, WorkspaceService])
|
||||
.scope(EditorScope)
|
||||
.service(EditorService, [EditorScope]);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ export class ImportClipperService extends Service {
|
||||
collection: workspace.docCollection,
|
||||
schema: getAFFiNEWorkspaceSchema(),
|
||||
markdown: clipperInput.contentMarkdown,
|
||||
extensions: getStoreManager().get('store'),
|
||||
extensions: getStoreManager().config.init().value.get('store'),
|
||||
});
|
||||
const docsService = workspace.scope.get(DocsService);
|
||||
if (docId) {
|
||||
@@ -69,7 +69,7 @@ export class ImportClipperService extends Service {
|
||||
collection: docCollection,
|
||||
schema: getAFFiNEWorkspaceSchema(),
|
||||
markdown: clipperInput.contentMarkdown,
|
||||
extensions: getStoreManager().get('store'),
|
||||
extensions: getStoreManager().config.init().value.get('store'),
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -61,7 +61,7 @@ export class IntegrationWriter extends Entity {
|
||||
schema: getAFFiNEWorkspaceSchema(),
|
||||
markdown,
|
||||
fileName: title,
|
||||
extensions: getStoreManager().get('store'),
|
||||
extensions: getStoreManager().config.init().value.get('store'),
|
||||
});
|
||||
|
||||
if (!newDocId) throw new Error('Failed to create a new doc');
|
||||
@@ -85,7 +85,7 @@ export class IntegrationWriter extends Entity {
|
||||
doc,
|
||||
blockId: noteBlockId,
|
||||
markdown,
|
||||
extensions: getStoreManager().get('store'),
|
||||
extensions: getStoreManager().config.init().value.get('store'),
|
||||
});
|
||||
} else if (updateStrategy === 'append') {
|
||||
const pageBlockId = doc.getBlocksByFlavour('affine:page')[0]?.id;
|
||||
@@ -94,7 +94,7 @@ export class IntegrationWriter extends Entity {
|
||||
doc,
|
||||
blockId,
|
||||
markdown: `---\n${markdown}`,
|
||||
extensions: getStoreManager().get('store'),
|
||||
extensions: getStoreManager().config.init().value.get('store'),
|
||||
});
|
||||
} else {
|
||||
throw new Error('Invalid update strategy');
|
||||
|
||||
@@ -14,8 +14,6 @@ export { NbstoreService } from './services/nbstore';
|
||||
|
||||
import { type Framework } from '@toeverything/infra';
|
||||
|
||||
import { DesktopApiService } from '../desktop-api';
|
||||
import { ElectronGlobalCache, ElectronGlobalState } from './impls/electron';
|
||||
import {
|
||||
IDBGlobalState,
|
||||
LocalStorageGlobalCache,
|
||||
@@ -49,12 +47,6 @@ export function configureLocalStorageStateStorageImpls(framework: Framework) {
|
||||
framework.impl(CacheStorage, IDBGlobalState);
|
||||
}
|
||||
|
||||
export function configureElectronStateStorageImpls(framework: Framework) {
|
||||
framework.impl(GlobalCache, ElectronGlobalCache, [DesktopApiService]);
|
||||
framework.impl(GlobalState, ElectronGlobalState, [DesktopApiService]);
|
||||
framework.impl(CacheStorage, IDBGlobalState);
|
||||
}
|
||||
|
||||
export function configureCommonGlobalStorageImpls(framework: Framework) {
|
||||
framework.impl(GlobalSessionState, SessionStorageGlobalSessionState);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
||||
import type { Workspace as WorkspaceInterface } from '@blocksuite/affine/store';
|
||||
import { Entity, LiveData, yjsGetPath } from '@toeverything/infra';
|
||||
import type { Observable } from 'rxjs';
|
||||
@@ -9,7 +10,10 @@ import type { WorkspaceScope } from '../scopes/workspace';
|
||||
import { WorkspaceEngineService } from '../services/engine';
|
||||
|
||||
export class Workspace extends Entity {
|
||||
constructor(public readonly scope: WorkspaceScope) {
|
||||
constructor(
|
||||
public readonly scope: WorkspaceScope,
|
||||
public readonly featureFlagService: FeatureFlagService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
@@ -30,6 +34,7 @@ export class Workspace extends Entity {
|
||||
this._docCollection = new WorkspaceImpl({
|
||||
id: this.openOptions.metadata.id,
|
||||
rootDoc: this.rootYDoc,
|
||||
featureFlagService: this.featureFlagService,
|
||||
blobSource: {
|
||||
get: async key => {
|
||||
const record = await this.engine.blob.get(key);
|
||||
|
||||
@@ -5,20 +5,21 @@ import {
|
||||
type ExtensionType,
|
||||
type GetStoreOptions,
|
||||
StoreContainer,
|
||||
type Workspace,
|
||||
type YBlock,
|
||||
} from '@blocksuite/affine/store';
|
||||
import { Awareness } from 'y-protocols/awareness.js';
|
||||
import * as Y from 'yjs';
|
||||
|
||||
import type { WorkspaceImpl } from './workspace';
|
||||
|
||||
type DocOptions = {
|
||||
id: string;
|
||||
collection: Workspace;
|
||||
collection: WorkspaceImpl;
|
||||
doc: Y.Doc;
|
||||
};
|
||||
|
||||
export class DocImpl implements Doc {
|
||||
private readonly _collection: Workspace;
|
||||
private readonly _collection: WorkspaceImpl;
|
||||
|
||||
private readonly _storeContainer: StoreContainer;
|
||||
|
||||
@@ -136,7 +137,10 @@ export class DocImpl implements Doc {
|
||||
extensions,
|
||||
id,
|
||||
}: GetStoreOptions = {}) {
|
||||
const storeExtensions = getStoreManager().get('store');
|
||||
const storeExtensions = getStoreManager()
|
||||
.config.init()
|
||||
.featureFlag(this.workspace.featureFlagService)
|
||||
.value.get('store');
|
||||
const exts = storeExtensions
|
||||
.concat(extensions ?? [])
|
||||
.concat(this.storeExtensions);
|
||||
|
||||
@@ -19,6 +19,7 @@ import { Subject } from 'rxjs';
|
||||
import type { Awareness } from 'y-protocols/awareness.js';
|
||||
import type { Doc as YDoc } from 'yjs';
|
||||
|
||||
import type { FeatureFlagService } from '../../feature-flag';
|
||||
import { DocImpl } from './doc';
|
||||
import { WorkspaceMetaImpl } from './meta';
|
||||
|
||||
@@ -29,6 +30,7 @@ type WorkspaceOptions = {
|
||||
onLoadDoc?: (doc: YDoc) => void;
|
||||
onLoadAwareness?: (awareness: Awareness) => void;
|
||||
onCreateDoc?: (docId?: string) => string;
|
||||
featureFlagService?: FeatureFlagService;
|
||||
};
|
||||
|
||||
export class WorkspaceImpl implements Workspace {
|
||||
@@ -57,6 +59,7 @@ export class WorkspaceImpl implements Workspace {
|
||||
readonly onLoadDoc?: (doc: YDoc) => void;
|
||||
readonly onLoadAwareness?: (awareness: Awareness) => void;
|
||||
readonly onCreateDoc?: (docId?: string) => string;
|
||||
readonly featureFlagService?: FeatureFlagService;
|
||||
|
||||
constructor({
|
||||
id,
|
||||
@@ -65,8 +68,10 @@ export class WorkspaceImpl implements Workspace {
|
||||
onLoadDoc,
|
||||
onLoadAwareness,
|
||||
onCreateDoc,
|
||||
featureFlagService,
|
||||
}: WorkspaceOptions) {
|
||||
this.id = id || '';
|
||||
this.featureFlagService = featureFlagService;
|
||||
this.doc = rootDoc;
|
||||
this.onLoadDoc = onLoadDoc;
|
||||
this.onLoadDoc?.(this.doc);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
||||
|
||||
export type { WorkspaceProfileInfo } from './entities/profile';
|
||||
export { Workspace } from './entities/workspace';
|
||||
export { WorkspaceEngineBeforeStart, WorkspaceInitialized } from './events';
|
||||
@@ -70,7 +72,7 @@ export function configureWorkspaceModule(framework: Framework) {
|
||||
])
|
||||
.scope(WorkspaceScope)
|
||||
.service(WorkspaceService)
|
||||
.entity(Workspace, [WorkspaceScope])
|
||||
.entity(Workspace, [WorkspaceScope, FeatureFlagService])
|
||||
.service(WorkspaceEngineService, [WorkspaceScope])
|
||||
.entity(WorkspaceEngine, [WorkspaceService, NbstoreService])
|
||||
.impl(WorkspaceLocalState, WorkspaceLocalStateImpl, [
|
||||
|
||||
Reference in New Issue
Block a user