diff --git a/blocksuite/affine/block-database/src/data-source.ts b/blocksuite/affine/block-database/src/data-source.ts index 79e2f50f28..405b81a8f1 100644 --- a/blocksuite/affine/block-database/src/data-source.ts +++ b/blocksuite/affine/block-database/src/data-source.ts @@ -1,4 +1,5 @@ import type { DatabaseBlockModel } from '@blocksuite/affine-model'; +import { FeatureFlagService } from '@blocksuite/affine-shared/services'; import { insertPositionToIndex, type InsertToPosition, @@ -57,10 +58,12 @@ export class DatabaseBlockDataSource extends DataSourceBase { private readonly _model: DatabaseBlockModel; override featureFlags$: ReadonlySignal = computed(() => { + const featureFlagService = this.doc.get(FeatureFlagService); + const flag = featureFlagService.getFlag( + 'enable_database_number_formatting' + ); return { - enable_number_formatting: - this.doc.awarenessStore.getFlag('enable_database_number_formatting') ?? - false, + enable_number_formatting: flag ?? false, }; }); diff --git a/blocksuite/affine/block-embed/src/embed-linked-doc-block/embed-edgeless-linked-doc-block.ts b/blocksuite/affine/block-embed/src/embed-linked-doc-block/embed-edgeless-linked-doc-block.ts index b07a78c901..154b17fd27 100644 --- a/blocksuite/affine/block-embed/src/embed-linked-doc-block/embed-edgeless-linked-doc-block.ts +++ b/blocksuite/affine/block-embed/src/embed-linked-doc-block/embed-edgeless-linked-doc-block.ts @@ -3,6 +3,7 @@ import { EMBED_CARD_HEIGHT, EMBED_CARD_WIDTH, } from '@blocksuite/affine-shared/consts'; +import { FeatureFlagService } from '@blocksuite/affine-shared/services'; import { cloneReferenceInfoWithoutAliases } from '@blocksuite/affine-shared/utils'; import { Bound } from '@blocksuite/global/utils'; @@ -15,10 +16,10 @@ export class EmbedEdgelessLinkedDocBlockComponent extends toEdgelessEmbedBlock( override convertToEmbed = () => { const { id, doc, caption, xywh } = this.model; - // synced doc entry controlled by awareness flag - const isSyncedDocEnabled = doc.awarenessStore.getFlag( - 'enable_synced_doc_block' - ); + // synced doc entry controlled by flag + const isSyncedDocEnabled = doc + .get(FeatureFlagService) + .getFlag('enable_synced_doc_block'); if (!isSyncedDocEnabled) { return; } diff --git a/blocksuite/affine/block-embed/src/embed-linked-doc-block/embed-linked-doc-block.ts b/blocksuite/affine/block-embed/src/embed-linked-doc-block/embed-linked-doc-block.ts index 32e68e88d3..9c4a178671 100644 --- a/blocksuite/affine/block-embed/src/embed-linked-doc-block/embed-linked-doc-block.ts +++ b/blocksuite/affine/block-embed/src/embed-linked-doc-block/embed-linked-doc-block.ts @@ -13,6 +13,7 @@ import { import { DocDisplayMetaProvider, DocModeProvider, + FeatureFlagService, ThemeProvider, } from '@blocksuite/affine-shared/services'; import { @@ -129,10 +130,10 @@ export class EmbedLinkedDocBlockComponent extends EmbedBlockComponent = signal({ + enable_synced_doc_block: true, + enable_pie_menu: false, + enable_database_number_formatting: false, + enable_database_attachment_note: false, + enable_database_full_width: false, + enable_block_query: false, + enable_lasso_tool: false, + enable_edgeless_text: true, + enable_ai_onboarding: true, + enable_ai_chat_block: true, + enable_color_picker: true, + enable_mind_map_import: true, + enable_advanced_block_visibility: false, + enable_shape_shadow_blur: false, + enable_mobile_keyboard_toolbar: false, + enable_mobile_linked_doc_menu: false, + }); + + setFlag(key: keyof BlockSuiteFlags, value: boolean) { + this._flags.value = { + ...this._flags.value, + [key]: value, + }; + } + + getFlag(key: keyof BlockSuiteFlags) { + return this._flags.value[key]; + } + + constructor(store: Store) { + super(store); + } +} diff --git a/blocksuite/affine/shared/src/services/index.ts b/blocksuite/affine/shared/src/services/index.ts index ae5a0d51f8..84e69b2e3f 100644 --- a/blocksuite/affine/shared/src/services/index.ts +++ b/blocksuite/affine/shared/src/services/index.ts @@ -4,6 +4,7 @@ export * from './drag-handle-config'; export * from './edit-props-store'; export * from './editor-setting-service'; export * from './embed-option-service'; +export * from './feature-flag-service'; export * from './font-loader'; export * from './generate-url-service'; export * from './native-clipboard-service'; diff --git a/blocksuite/blocks/src/__tests__/utils/create-job.ts b/blocksuite/blocks/src/__tests__/utils/create-job.ts index 669180b5c6..f7d1a8ad45 100644 --- a/blocksuite/blocks/src/__tests__/utils/create-job.ts +++ b/blocksuite/blocks/src/__tests__/utils/create-job.ts @@ -1,3 +1,4 @@ +import { FeatureFlagService } from '@blocksuite/affine-shared/services'; import { Job, type JobMiddleware, Schema } from '@blocksuite/store'; import { TestWorkspace } from '@blocksuite/store/test'; @@ -22,6 +23,7 @@ export function createJob(middlewares?: JobMiddleware[]) { testMiddlewares.push(defaultImageProxyMiddleware); const schema = new Schema().register(AffineSchemas); const docCollection = new TestWorkspace({ schema }); + docCollection.storeExtensions = [FeatureFlagService]; docCollection.meta.initialize(); return new Job({ schema, diff --git a/blocksuite/blocks/src/_specs/common.ts b/blocksuite/blocks/src/_specs/common.ts index bf196ceb06..c278de58d8 100644 --- a/blocksuite/blocks/src/_specs/common.ts +++ b/blocksuite/blocks/src/_specs/common.ts @@ -30,6 +30,7 @@ import { import { DocDisplayMetaService, EditPropsStore, + FeatureFlagService, FontLoaderService, } from '@blocksuite/affine-shared/services'; import type { ExtensionType } from '@blocksuite/store'; @@ -73,3 +74,5 @@ export const EdgelessFirstPartyBlockSpecs: ExtensionType[] = [ EdgelessTextBlockSpec, FontLoaderService, ].flat(); + +export const StoreExtensions: ExtensionType[] = [FeatureFlagService]; diff --git a/blocksuite/blocks/src/_specs/index.ts b/blocksuite/blocks/src/_specs/index.ts index 4721e64cb7..6d8620705d 100644 --- a/blocksuite/blocks/src/_specs/index.ts +++ b/blocksuite/blocks/src/_specs/index.ts @@ -1,3 +1,4 @@ +export * from './common.js'; export * from './preset/edgeless-specs.js'; export * from './preset/mobile-patch.js'; export * from './preset/page-specs.js'; diff --git a/blocksuite/blocks/src/_specs/preset/mobile-patch.ts b/blocksuite/blocks/src/_specs/preset/mobile-patch.ts index 985e792ede..ae06814210 100644 --- a/blocksuite/blocks/src/_specs/preset/mobile-patch.ts +++ b/blocksuite/blocks/src/_specs/preset/mobile-patch.ts @@ -3,6 +3,7 @@ import { type ReferenceNodeConfig, ReferenceNodeConfigIdentifier, } from '@blocksuite/affine-components/rich-text'; +import { FeatureFlagService } from '@blocksuite/affine-shared/services'; import { type BlockStdScope, ConfigIdentifier, @@ -21,9 +22,10 @@ export class MobileSpecsPatches extends LifeCycleWatcher { constructor(std: BlockStdScope) { super(std); + const featureFlagService = std.get(FeatureFlagService); - std.doc.awarenessStore.setFlag('enable_mobile_keyboard_toolbar', true); - std.doc.awarenessStore.setFlag('enable_mobile_linked_doc_menu', true); + featureFlagService.setFlag('enable_mobile_keyboard_toolbar', true); + featureFlagService.setFlag('enable_mobile_linked_doc_menu', true); } static override setup(di: Container) { diff --git a/blocksuite/blocks/src/_specs/register-specs.ts b/blocksuite/blocks/src/_specs/register-specs.ts index c24a2ff11e..8595d747b3 100644 --- a/blocksuite/blocks/src/_specs/register-specs.ts +++ b/blocksuite/blocks/src/_specs/register-specs.ts @@ -1,6 +1,6 @@ import { SpecProvider } from '@blocksuite/affine-shared/utils'; -import { CommonBlockSpecs } from './common.js'; +import { CommonBlockSpecs, StoreExtensions } from './common.js'; import { EdgelessEditorBlockSpecs } from './preset/edgeless-specs.js'; import { PageEditorBlockSpecs } from './preset/page-specs.js'; import { @@ -9,6 +9,7 @@ import { } from './preset/preview-specs.js'; export function registerSpecs() { + SpecProvider.getInstance().addSpec('store', StoreExtensions); SpecProvider.getInstance().addSpec('common', CommonBlockSpecs); SpecProvider.getInstance().addSpec('page', PageEditorBlockSpecs); SpecProvider.getInstance().addSpec('edgeless', EdgelessEditorBlockSpecs); diff --git a/blocksuite/blocks/src/root-block/edgeless/components/auto-complete/auto-complete-panel.ts b/blocksuite/blocks/src/root-block/edgeless/components/auto-complete/auto-complete-panel.ts index 305670eb88..64fabef494 100644 --- a/blocksuite/blocks/src/root-block/edgeless/components/auto-complete/auto-complete-panel.ts +++ b/blocksuite/blocks/src/root-block/edgeless/components/auto-complete/auto-complete-panel.ts @@ -26,6 +26,7 @@ import { } from '@blocksuite/affine-model'; import { EditPropsStore, + FeatureFlagService, ThemeProvider, } from '@blocksuite/affine-shared/services'; import { captureEventTarget } from '@blocksuite/affine-shared/utils'; @@ -249,9 +250,9 @@ export class EdgelessAutoCompletePanel extends WithDisposable(LitElement) { const { xywh, position } = target; const bound = Bound.fromXYWH(xywh); - const textFlag = this.edgeless.doc.awarenessStore.getFlag( - 'enable_edgeless_text' - ); + const textFlag = this.edgeless.doc + .get(FeatureFlagService) + .getFlag('enable_edgeless_text'); if (textFlag) { const { textId } = this.edgeless.std.command.exec('insertEdgelessText', { x: bound.x, diff --git a/blocksuite/blocks/src/root-block/edgeless/components/toolbar/brush/brush-menu.ts b/blocksuite/blocks/src/root-block/edgeless/components/toolbar/brush/brush-menu.ts index 0ab04a116b..07db89be49 100644 --- a/blocksuite/blocks/src/root-block/edgeless/components/toolbar/brush/brush-menu.ts +++ b/blocksuite/blocks/src/root-block/edgeless/components/toolbar/brush/brush-menu.ts @@ -1,6 +1,7 @@ import { DefaultTheme } from '@blocksuite/affine-model'; import { EditPropsStore, + FeatureFlagService, ThemeProvider, } from '@blocksuite/affine-shared/services'; import type { ColorEvent } from '@blocksuite/affine-shared/utils'; @@ -65,9 +66,9 @@ export class EdgelessBrushMenu extends EdgelessToolbarToolMixin( .value=${this._props$.value.color} .theme=${this._theme$.value} .palettes=${DefaultTheme.StrokeColorPalettes} - .hasTransparent=${!this.edgeless.doc.awarenessStore.getFlag( - 'enable_color_picker' - )} + .hasTransparent=${!this.edgeless.doc + .get(FeatureFlagService) + .getFlag('enable_color_picker')} @select=${(e: ColorEvent) => this.onChange({ color: e.detail.value })} > diff --git a/blocksuite/blocks/src/root-block/edgeless/components/toolbar/connector/connector-menu.ts b/blocksuite/blocks/src/root-block/edgeless/components/toolbar/connector/connector-menu.ts index c01bbdb572..cb3f85d7d4 100644 --- a/blocksuite/blocks/src/root-block/edgeless/components/toolbar/connector/connector-menu.ts +++ b/blocksuite/blocks/src/root-block/edgeless/components/toolbar/connector/connector-menu.ts @@ -6,6 +6,7 @@ import { import { ConnectorMode, DefaultTheme } from '@blocksuite/affine-model'; import { EditPropsStore, + FeatureFlagService, ThemeProvider, } from '@blocksuite/affine-shared/services'; import type { ColorEvent } from '@blocksuite/affine-shared/utils'; @@ -130,9 +131,9 @@ export class EdgelessConnectorMenu extends EdgelessToolbarToolMixin( .value=${stroke} .theme=${this._theme$.value} .palettes=${DefaultTheme.StrokeColorPalettes} - .hasTransparent=${!this.edgeless.doc.awarenessStore.getFlag( - 'enable_color_picker' - )} + .hasTransparent=${!this.edgeless.doc + .get(FeatureFlagService) + .getFlag('enable_color_picker')} @select=${(e: ColorEvent) => this.onChange({ stroke: e.detail.value })} > diff --git a/blocksuite/blocks/src/root-block/edgeless/components/toolbar/mindmap/basket-elements.ts b/blocksuite/blocks/src/root-block/edgeless/components/toolbar/mindmap/basket-elements.ts index 4842c1c8d4..2cd1de6d43 100644 --- a/blocksuite/blocks/src/root-block/edgeless/components/toolbar/mindmap/basket-elements.ts +++ b/blocksuite/blocks/src/root-block/edgeless/components/toolbar/mindmap/basket-elements.ts @@ -1,6 +1,9 @@ import { CanvasElementType } from '@blocksuite/affine-block-surface'; import { type MindmapStyle, TextElementModel } from '@blocksuite/affine-model'; -import { TelemetryProvider } from '@blocksuite/affine-shared/services'; +import { + FeatureFlagService, + TelemetryProvider, +} from '@blocksuite/affine-shared/services'; import { assertInstanceOf, Bound } from '@blocksuite/global/utils'; import type { TemplateResult } from 'lit'; import * as Y from 'yjs'; @@ -103,7 +106,9 @@ export const textRender: DraggableTool['render'] = ( const w = 100; const h = 32; - const flag = edgeless.doc.awarenessStore.getFlag('enable_edgeless_text'); + const flag = edgeless.doc + .get(FeatureFlagService) + .getFlag('enable_edgeless_text'); let id: string; if (flag) { const { textId } = edgeless.std.command.exec('insertEdgelessText', { diff --git a/blocksuite/blocks/src/root-block/edgeless/components/toolbar/mindmap/mindmap-menu.ts b/blocksuite/blocks/src/root-block/edgeless/components/toolbar/mindmap/mindmap-menu.ts index a63c4cd5e6..9486e01943 100644 --- a/blocksuite/blocks/src/root-block/edgeless/components/toolbar/mindmap/mindmap-menu.ts +++ b/blocksuite/blocks/src/root-block/edgeless/components/toolbar/mindmap/mindmap-menu.ts @@ -2,6 +2,7 @@ import { toast } from '@blocksuite/affine-components/toast'; import type { MindmapStyle } from '@blocksuite/affine-model'; import { EditPropsStore, + FeatureFlagService, TelemetryProvider, } from '@blocksuite/affine-shared/services'; import type { BlockStdScope } from '@blocksuite/block-std'; @@ -316,7 +317,7 @@ export class EdgelessMindmapMenu extends EdgelessToolbarToolMixin( `; })} - ${this.std.doc.awarenessStore.getFlag('enable_mind_map_import') + ${this.std.doc.get(FeatureFlagService).getFlag('enable_mind_map_import') ? this._importMindMapEntry() : nothing} diff --git a/blocksuite/blocks/src/root-block/edgeless/components/toolbar/shape/shape-menu.ts b/blocksuite/blocks/src/root-block/edgeless/components/toolbar/shape/shape-menu.ts index 93d6df368e..269ad7fc04 100644 --- a/blocksuite/blocks/src/root-block/edgeless/components/toolbar/shape/shape-menu.ts +++ b/blocksuite/blocks/src/root-block/edgeless/components/toolbar/shape/shape-menu.ts @@ -12,6 +12,7 @@ import { } from '@blocksuite/affine-model'; import { EditPropsStore, + FeatureFlagService, ThemeProvider, } from '@blocksuite/affine-shared/services'; import type { ColorEvent } from '@blocksuite/affine-shared/utils'; @@ -173,9 +174,9 @@ export class EdgelessShapeMenu extends SignalWatcher( .value=${fillColor} .theme=${this._theme$.value} .palettes=${DefaultTheme.FillColorPalettes} - .hasTransparent=${!this.edgeless.doc.awarenessStore.getFlag( - 'enable_color_picker' - )} + .hasTransparent=${!this.edgeless.doc + .get(FeatureFlagService) + .getFlag('enable_color_picker')} @select=${(e: ColorEvent) => this._setFillColor(e.detail)} > diff --git a/blocksuite/blocks/src/root-block/edgeless/edgeless-keyboard.ts b/blocksuite/blocks/src/root-block/edgeless/edgeless-keyboard.ts index 59395525ca..2e76b78ae2 100644 --- a/blocksuite/blocks/src/root-block/edgeless/edgeless-keyboard.ts +++ b/blocksuite/blocks/src/root-block/edgeless/edgeless-keyboard.ts @@ -12,6 +12,7 @@ import { } from '@blocksuite/affine-model'; import { EditPropsStore, + FeatureFlagService, TelemetryProvider, } from '@blocksuite/affine-shared/services'; import { LassoMode } from '@blocksuite/affine-shared/types'; @@ -72,7 +73,11 @@ export class EdgelessPageKeyboardManager extends PageKeyboardManager { this._setEdgelessTool('connector', { mode }); }, l: () => { - if (!rootComponent.doc.awarenessStore.getFlag('enable_lasso_tool')) { + if ( + !rootComponent.doc + .get(FeatureFlagService) + .getFlag('enable_lasso_tool') + ) { return; } @@ -81,7 +86,11 @@ export class EdgelessPageKeyboardManager extends PageKeyboardManager { }); }, 'Shift-l': () => { - if (!rootComponent.doc.awarenessStore.getFlag('enable_lasso_tool')) { + if ( + !rootComponent.doc + .get(FeatureFlagService) + .getFlag('enable_lasso_tool') + ) { return; } // toggle between lasso modes diff --git a/blocksuite/blocks/src/root-block/edgeless/gfx-tool/default-tool.ts b/blocksuite/blocks/src/root-block/edgeless/gfx-tool/default-tool.ts index c871aa4a4d..e3abd898b1 100644 --- a/blocksuite/blocks/src/root-block/edgeless/gfx-tool/default-tool.ts +++ b/blocksuite/blocks/src/root-block/edgeless/gfx-tool/default-tool.ts @@ -15,7 +15,10 @@ import { ShapeElementModel, TextElementModel, } from '@blocksuite/affine-model'; -import { TelemetryProvider } from '@blocksuite/affine-shared/services'; +import { + FeatureFlagService, + TelemetryProvider, +} from '@blocksuite/affine-shared/services'; import { clamp, handleNativeRangeAtPoint, @@ -783,7 +786,9 @@ export class DefaultTool extends BaseTool { } if (!selected) { - const textFlag = this.doc.awarenessStore.getFlag('enable_edgeless_text'); + const textFlag = this.doc + .get(FeatureFlagService) + .getFlag('enable_edgeless_text'); if (textFlag) { const [x, y] = this.gfx.viewport.toModelCoord(e.x, e.y); diff --git a/blocksuite/blocks/src/root-block/edgeless/gfx-tool/text-tool.ts b/blocksuite/blocks/src/root-block/edgeless/gfx-tool/text-tool.ts index c750c7ee24..3fe8ee6f80 100644 --- a/blocksuite/blocks/src/root-block/edgeless/gfx-tool/text-tool.ts +++ b/blocksuite/blocks/src/root-block/edgeless/gfx-tool/text-tool.ts @@ -1,5 +1,8 @@ import type { TextElementModel } from '@blocksuite/affine-model'; -import { TelemetryProvider } from '@blocksuite/affine-shared/services'; +import { + FeatureFlagService, + TelemetryProvider, +} from '@blocksuite/affine-shared/services'; import type { PointerEventState } from '@blocksuite/block-std'; import { BaseTool, type GfxController } from '@blocksuite/block-std/gfx'; import { Bound } from '@blocksuite/global/utils'; @@ -38,9 +41,9 @@ export class TextTool extends BaseTool { static override toolName: string = 'text'; override click(e: PointerEventState): void { - const textFlag = this.gfx.doc.awarenessStore.getFlag( - 'enable_edgeless_text' - ); + const textFlag = this.gfx.doc + .get(FeatureFlagService) + .getFlag('enable_edgeless_text'); if (textFlag) { const [x, y] = this.gfx.viewport.toModelCoord(e.x, e.y); diff --git a/blocksuite/blocks/src/root-block/widgets/edgeless-auto-connect/edgeless-auto-connect.ts b/blocksuite/blocks/src/root-block/widgets/edgeless-auto-connect/edgeless-auto-connect.ts index 115db07dfe..407476e2b9 100644 --- a/blocksuite/blocks/src/root-block/widgets/edgeless-auto-connect/edgeless-auto-connect.ts +++ b/blocksuite/blocks/src/root-block/widgets/edgeless-auto-connect/edgeless-auto-connect.ts @@ -12,6 +12,7 @@ import { type RootBlockModel, type SurfaceRefBlockModel, } from '@blocksuite/affine-model'; +import { FeatureFlagService } from '@blocksuite/affine-shared/services'; import { matchFlavours, stopPropagation, @@ -555,9 +556,9 @@ export class EdgelessAutoConnectWidget extends WidgetComponent< } override render() { - const advancedVisibilityEnabled = this.doc.awarenessStore.getFlag( - 'enable_advanced_block_visibility' - ); + const advancedVisibilityEnabled = this.doc + .get(FeatureFlagService) + .getFlag('enable_advanced_block_visibility'); if (!this._show || this._dragging || !advancedVisibilityEnabled) { return nothing; diff --git a/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-brush-button.ts b/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-brush-button.ts index 261ec8f3a5..04c35c9169 100644 --- a/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-brush-button.ts +++ b/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-brush-button.ts @@ -17,6 +17,7 @@ import { LineWidth, resolveColor, } from '@blocksuite/affine-model'; +import { FeatureFlagService } from '@blocksuite/affine-shared/services'; import type { ColorEvent } from '@blocksuite/affine-shared/utils'; import { countBy, maxBy, WithDisposable } from '@blocksuite/global/utils'; import { html, LitElement, nothing } from 'lit'; @@ -120,7 +121,9 @@ export class EdgelessChangeBrushButton extends WithDisposable(LitElement) { ${when( - this.edgeless.doc.awarenessStore.getFlag('enable_color_picker'), + this.edgeless.doc + .get(FeatureFlagService) + .getFlag('enable_color_picker'), () => { const { type, colors } = packColorsWithColorScheme( colorScheme, diff --git a/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-connector-button.ts b/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-connector-button.ts index ea9c4a138f..bbbf7dfcde 100644 --- a/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-connector-button.ts +++ b/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-connector-button.ts @@ -42,6 +42,7 @@ import { resolveColor, StrokeStyle, } from '@blocksuite/affine-model'; +import { FeatureFlagService } from '@blocksuite/affine-shared/services'; import type { ColorEvent } from '@blocksuite/affine-shared/utils'; import { countBy, maxBy, WithDisposable } from '@blocksuite/global/utils'; import { html, LitElement, nothing, type TemplateResult } from 'lit'; @@ -361,7 +362,9 @@ export class EdgelessChangeConnectorButton extends WithDisposable(LitElement) { return join( [ when( - this.edgeless.doc.awarenessStore.getFlag('enable_color_picker'), + this.edgeless.doc + .get(FeatureFlagService) + .getFlag('enable_color_picker'), () => { const { type, colors } = packColorsWithColorScheme( colorScheme, diff --git a/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-embed-card-button.ts b/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-embed-card-button.ts index 15b633d1f8..a6d42f4a45 100644 --- a/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-embed-card-button.ts +++ b/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-embed-card-button.ts @@ -40,6 +40,7 @@ import { import { EmbedOptionProvider, type EmbedOptions, + FeatureFlagService, GenerateDocUrlProvider, type GenerateDocUrlService, type LinkEventType, @@ -390,9 +391,9 @@ export class EdgelessChangeEmbedCardButton extends WithDisposable(LitElement) { // synced doc entry controlled by awareness flag if (!!block && isEmbedLinkedDocBlock(block.model)) { - const isSyncedDocEnabled = block.doc.awarenessStore.getFlag( - 'enable_synced_doc_block' - ); + const isSyncedDocEnabled = block.doc + .get(FeatureFlagService) + .getFlag('enable_synced_doc_block'); if (!isSyncedDocEnabled) { return false; } diff --git a/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-frame-button.ts b/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-frame-button.ts index ac846721d9..bd594cd1a3 100644 --- a/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-frame-button.ts +++ b/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-frame-button.ts @@ -22,6 +22,7 @@ import { NoteDisplayMode, resolveColor, } from '@blocksuite/affine-model'; +import { FeatureFlagService } from '@blocksuite/affine-shared/services'; import type { ColorEvent } from '@blocksuite/affine-shared/utils'; import { matchFlavours } from '@blocksuite/affine-shared/utils'; import { GfxExtensionIdentifier } from '@blocksuite/block-std/gfx'; @@ -190,7 +191,9 @@ export class EdgelessChangeFrameButton extends WithDisposable(LitElement) { `, when( - this.edgeless.doc.awarenessStore.getFlag('enable_color_picker'), + this.edgeless.doc + .get(FeatureFlagService) + .getFlag('enable_color_picker'), () => { const { type, colors } = packColorsWithColorScheme( colorScheme, diff --git a/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-note-button.ts b/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-note-button.ts index 5a9468e0c3..21c60fa8ae 100644 --- a/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-note-button.ts +++ b/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-note-button.ts @@ -28,7 +28,10 @@ import { resolveColor, type StrokeStyle, } from '@blocksuite/affine-model'; -import { ThemeProvider } from '@blocksuite/affine-shared/services'; +import { + FeatureFlagService, + ThemeProvider, +} from '@blocksuite/affine-shared/services'; import { matchFlavours } from '@blocksuite/affine-shared/utils'; import { assertExists, @@ -133,7 +136,9 @@ export class EdgelessChangeNoteButton extends WithDisposable(LitElement) { }; private get _advancedVisibilityEnabled() { - return this.doc.awarenessStore.getFlag('enable_advanced_block_visibility'); + return this.doc + .get(FeatureFlagService) + .getFlag('enable_advanced_block_visibility'); } private get doc() { @@ -301,7 +306,9 @@ export class EdgelessChangeNoteButton extends WithDisposable(LitElement) { isDocOnly ? nothing : when( - this.edgeless.doc.awarenessStore.getFlag('enable_color_picker'), + this.edgeless.doc + .get(FeatureFlagService) + .getFlag('enable_color_picker'), () => { const { type, colors } = packColorsWithColorScheme( colorScheme, diff --git a/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-shape-button.ts b/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-shape-button.ts index bd3e2b6ad4..16a10e8594 100644 --- a/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-shape-button.ts +++ b/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-shape-button.ts @@ -34,6 +34,7 @@ import { ShapeStyle, StrokeStyle, } from '@blocksuite/affine-model'; +import { FeatureFlagService } from '@blocksuite/affine-shared/services'; import type { ColorEvent } from '@blocksuite/affine-shared/utils'; import { countBy, maxBy, WithDisposable } from '@blocksuite/global/utils'; import { css, html, LitElement, nothing, type TemplateResult } from 'lit'; @@ -317,7 +318,9 @@ export class EdgelessChangeShapeButton extends WithDisposable(LitElement) { `, when( - this.edgeless.doc.awarenessStore.getFlag('enable_color_picker'), + this.edgeless.doc + .get(FeatureFlagService) + .getFlag('enable_color_picker'), () => { const { type, colors } = packColorsWithColorScheme( colorScheme, @@ -367,7 +370,9 @@ export class EdgelessChangeShapeButton extends WithDisposable(LitElement) { ), when( - this.edgeless.doc.awarenessStore.getFlag('enable_color_picker'), + this.edgeless.doc + .get(FeatureFlagService) + .getFlag('enable_color_picker'), () => { const { type, colors } = packColorsWithColorScheme( colorScheme, diff --git a/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-text-menu.ts b/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-text-menu.ts index d78a9ccffa..f0f941a266 100644 --- a/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-text-menu.ts +++ b/blocksuite/blocks/src/root-block/widgets/element-toolbar/change-text-menu.ts @@ -33,6 +33,7 @@ import { TextElementModel, type TextStyleProps, } from '@blocksuite/affine-model'; +import { FeatureFlagService } from '@blocksuite/affine-shared/services'; import type { ColorEvent } from '@blocksuite/affine-shared/utils'; import { Bound, @@ -372,7 +373,9 @@ export class EdgelessChangeTextMenu extends WithDisposable(LitElement) { `, when( - this.edgeless.doc.awarenessStore.getFlag('enable_color_picker'), + this.edgeless.doc + .get(FeatureFlagService) + .getFlag('enable_color_picker'), () => { const { type, colors } = packColorsWithColorScheme( colorScheme, diff --git a/blocksuite/blocks/src/root-block/widgets/embed-card-toolbar/embed-card-toolbar.ts b/blocksuite/blocks/src/root-block/widgets/embed-card-toolbar/embed-card-toolbar.ts index d4657c6687..b4c8c5dc95 100644 --- a/blocksuite/blocks/src/root-block/widgets/embed-card-toolbar/embed-card-toolbar.ts +++ b/blocksuite/blocks/src/root-block/widgets/embed-card-toolbar/embed-card-toolbar.ts @@ -44,6 +44,7 @@ import { import { EmbedOptionProvider, type EmbedOptions, + FeatureFlagService, GenerateDocUrlProvider, type GenerateDocUrlService, type LinkEventType, @@ -203,9 +204,9 @@ export class EmbedCardToolbar extends WidgetComponent< private get _canConvertToEmbedView() { // synced doc entry controlled by awareness flag if (this.focusModel && isEmbedLinkedDocBlock(this.focusModel)) { - const isSyncedDocEnabled = this.doc.awarenessStore.getFlag( - 'enable_synced_doc_block' - ); + const isSyncedDocEnabled = this.doc + .get(FeatureFlagService) + .getFlag('enable_synced_doc_block'); if (!isSyncedDocEnabled) { return false; } diff --git a/blocksuite/blocks/src/root-block/widgets/keyboard-toolbar/index.ts b/blocksuite/blocks/src/root-block/widgets/keyboard-toolbar/index.ts index 610bd7422d..c251dd2698 100644 --- a/blocksuite/blocks/src/root-block/widgets/keyboard-toolbar/index.ts +++ b/blocksuite/blocks/src/root-block/widgets/keyboard-toolbar/index.ts @@ -1,4 +1,5 @@ import type { RootBlockModel } from '@blocksuite/affine-model'; +import { FeatureFlagService } from '@blocksuite/affine-shared/services'; import { WidgetComponent } from '@blocksuite/block-std'; import { IS_MOBILE } from '@blocksuite/global/env'; import { assertType } from '@blocksuite/global/utils'; @@ -71,7 +72,9 @@ export class AffineKeyboardToolbarWidget extends WidgetComponent< if ( this.doc.readonly || !IS_MOBILE || - !this.doc.awarenessStore.getFlag('enable_mobile_keyboard_toolbar') + !this.doc + .get(FeatureFlagService) + .getFlag('enable_mobile_keyboard_toolbar') ) return nothing; diff --git a/blocksuite/blocks/src/root-block/widgets/linked-doc/index.ts b/blocksuite/blocks/src/root-block/widgets/linked-doc/index.ts index 7740174c0c..7d77b04436 100644 --- a/blocksuite/blocks/src/root-block/widgets/linked-doc/index.ts +++ b/blocksuite/blocks/src/root-block/widgets/linked-doc/index.ts @@ -3,6 +3,7 @@ import { getRangeRects, type SelectionRect, } from '@blocksuite/affine-shared/commands'; +import { FeatureFlagService } from '@blocksuite/affine-shared/services'; import { getViewportElement } from '@blocksuite/affine-shared/utils'; import type { BlockComponent } from '@blocksuite/block-std'; import { BLOCK_ID_ATTR, WidgetComponent } from '@blocksuite/block-std'; @@ -256,9 +257,9 @@ export class AffineLinkedDocWidget extends WidgetComponent< }, }; - const enableMobile = this.doc.awarenessStore.getFlag( - 'enable_mobile_linked_doc_menu' - ); + const enableMobile = this.doc + .get(FeatureFlagService) + .getFlag('enable_mobile_linked_doc_menu'); this._mode$.value = enableMobile ? mode : 'desktop'; } diff --git a/blocksuite/blocks/src/root-block/widgets/slash-menu/config.ts b/blocksuite/blocks/src/root-block/widgets/slash-menu/config.ts index 36f7f1fc40..c4803109ed 100644 --- a/blocksuite/blocks/src/root-block/widgets/slash-menu/config.ts +++ b/blocksuite/blocks/src/root-block/widgets/slash-menu/config.ts @@ -39,7 +39,10 @@ import type { ParagraphBlockModel, } from '@blocksuite/affine-model'; import { REFERENCE_NODE } from '@blocksuite/affine-shared/consts'; -import { TelemetryProvider } from '@blocksuite/affine-shared/services'; +import { + FeatureFlagService, + TelemetryProvider, +} from '@blocksuite/affine-shared/services'; import { createDefaultDoc, openFileOrFiles, @@ -574,7 +577,7 @@ export const defaultSlashMenuConfig: SlashMenuConfig = { showWhen: ({ model }) => model.doc.schema.flavourSchemaMap.has('affine:database') && !insideEdgelessText(model) && - !!model.doc.awarenessStore.getFlag('enable_block_query'), + !!model.doc.get(FeatureFlagService).getFlag('enable_block_query'), action: ({ model, rootComponent }) => { const parent = rootComponent.doc.getParent(model); diff --git a/blocksuite/framework/global/src/types/index.ts b/blocksuite/framework/global/src/types/index.ts index 18a4434456..2a095904fe 100644 --- a/blocksuite/framework/global/src/types/index.ts +++ b/blocksuite/framework/global/src/types/index.ts @@ -1,20 +1,4 @@ export interface BlockSuiteFlags { - enable_synced_doc_block: boolean; - enable_pie_menu: boolean; - enable_database_number_formatting: boolean; - enable_database_attachment_note: boolean; - enable_database_full_width: boolean; - enable_block_query: boolean; - enable_lasso_tool: boolean; - enable_edgeless_text: boolean; - enable_ai_onboarding: boolean; - enable_ai_chat_block: boolean; - enable_color_picker: boolean; - enable_mind_map_import: boolean; - enable_advanced_block_visibility: boolean; - enable_shape_shadow_blur: boolean; - enable_mobile_keyboard_toolbar: boolean; - enable_mobile_linked_doc_menu: boolean; readonly: Record; } export * from './virtual-keyboard.js'; diff --git a/blocksuite/framework/store/src/__tests__/collection.unit.spec.ts b/blocksuite/framework/store/src/__tests__/collection.unit.spec.ts index 5a106b56b8..8341d563b2 100644 --- a/blocksuite/framework/store/src/__tests__/collection.unit.spec.ts +++ b/blocksuite/framework/store/src/__tests__/collection.unit.spec.ts @@ -860,22 +860,6 @@ describe('getBlock', () => { }); }); -describe('flags', () => { - it('update flags', () => { - const options = createTestOptions(); - const collection = new TestWorkspace(options); - collection.meta.initialize(); - - const awareness = collection.awarenessStore; - - awareness.setFlag('enable_lasso_tool', false); - expect(awareness.getFlag('enable_lasso_tool')).toBe(false); - - awareness.setFlag('enable_lasso_tool', true); - expect(awareness.getFlag('enable_lasso_tool')).toBe(true); - }); -}); - declare global { namespace BlockSuite { interface BlockModels { diff --git a/blocksuite/framework/store/src/model/store/store.ts b/blocksuite/framework/store/src/model/store/store.ts index 2036842e5e..f71b883978 100644 --- a/blocksuite/framework/store/src/model/store/store.ts +++ b/blocksuite/framework/store/src/model/store/store.ts @@ -688,4 +688,12 @@ export class Store { ); }); } + + get get() { + return this.provider.get.bind(this.provider); + } + + get getOptional() { + return this.provider.getOptional.bind(this.provider); + } } diff --git a/blocksuite/framework/store/src/test/test-doc.ts b/blocksuite/framework/store/src/test/test-doc.ts index b9042583df..b687dcb725 100644 --- a/blocksuite/framework/store/src/test/test-doc.ts +++ b/blocksuite/framework/store/src/test/test-doc.ts @@ -7,6 +7,7 @@ import type { Doc, GetBlocksOptions, Workspace } from '../model/index.js'; import type { Query } from '../model/store/query.js'; import { Store } from '../model/store/store.js'; import type { AwarenessStore } from '../yjs/index.js'; +import type { TestWorkspace } from './test-workspace.js'; type DocOptions = { id: string; @@ -294,7 +295,9 @@ export class TestDoc implements Doc { readonly, query, provider, - extensions, + extensions: (this.workspace as TestWorkspace).storeExtensions.concat( + extensions ?? [] + ), }); this._docMap[readonlyKey].set(key, doc); diff --git a/blocksuite/framework/store/src/test/test-workspace.ts b/blocksuite/framework/store/src/test/test-workspace.ts index aadd5b39ac..a9eab3dbef 100644 --- a/blocksuite/framework/store/src/test/test-workspace.ts +++ b/blocksuite/framework/store/src/test/test-workspace.ts @@ -16,6 +16,7 @@ import merge from 'lodash.merge'; import { Awareness } from 'y-protocols/awareness.js'; import * as Y from 'yjs'; +import type { ExtensionType } from '../extension/extension.js'; import type { CreateBlocksOptions, GetBlocksOptions, @@ -46,22 +47,6 @@ export type DocCollectionOptions = { }; const FLAGS_PRESET = { - enable_synced_doc_block: false, - enable_pie_menu: false, - enable_database_number_formatting: false, - enable_database_attachment_note: false, - enable_database_full_width: false, - enable_block_query: false, - enable_lasso_tool: false, - enable_edgeless_text: true, - enable_ai_onboarding: false, - enable_ai_chat_block: false, - enable_color_picker: false, - enable_mind_map_import: false, - enable_advanced_block_visibility: false, - enable_shape_shadow_blur: false, - enable_mobile_keyboard_toolbar: false, - enable_mobile_linked_doc_menu: false, readonly: {}, } satisfies BlockSuiteFlags; @@ -72,6 +57,8 @@ const FLAGS_PRESET = { export class TestWorkspace implements Workspace { protected readonly _schema: Schema; + storeExtensions: ExtensionType[] = []; + readonly awarenessStore: AwarenessStore; readonly awarenessSync: AwarenessEngine; diff --git a/blocksuite/playground/apps/_common/helper.ts b/blocksuite/playground/apps/_common/helper.ts index cffe9a4466..132775c9a5 100644 --- a/blocksuite/playground/apps/_common/helper.ts +++ b/blocksuite/playground/apps/_common/helper.ts @@ -1,10 +1,12 @@ -import { AffineSchemas } from '@blocksuite/blocks'; +import { AffineSchemas, SpecProvider } from '@blocksuite/blocks'; import { Schema } from '@blocksuite/store'; import { TestWorkspace } from '@blocksuite/store/test'; export function createEmptyDoc() { const schema = new Schema().register(AffineSchemas); const collection = new TestWorkspace({ schema }); + collection.storeExtensions = + SpecProvider.getInstance().getSpec('store').value; collection.meta.initialize(); const doc = collection.createDoc(); diff --git a/blocksuite/playground/apps/starter/data/database.ts b/blocksuite/playground/apps/starter/data/database.ts index 69b1bfeaa4..5b676f3ba0 100644 --- a/blocksuite/playground/apps/starter/data/database.ts +++ b/blocksuite/playground/apps/starter/data/database.ts @@ -7,18 +7,14 @@ import { } from '@blocksuite/blocks'; import { viewPresets } from '@blocksuite/data-view/view-presets'; import { assertExists } from '@blocksuite/global/utils'; -import { type DocCollection, Text } from '@blocksuite/store'; +import { Text, type Workspace } from '@blocksuite/store'; // eslint-disable-next-line @typescript-eslint/no-restricted-imports import { propertyPresets } from '../../../../affine/data-view/src/property-presets'; import type { InitFn } from './utils.js'; -export const database: InitFn = (collection: DocCollection, id: string) => { +export const database: InitFn = (collection: Workspace, id: string) => { const doc = collection.createDoc({ id }); - doc.awarenessStore.setFlag('enable_database_number_formatting', true); - doc.awarenessStore.setFlag('enable_database_attachment_note', true); - doc.awarenessStore.setFlag('enable_database_full_width', true); - doc.awarenessStore.setFlag('enable_block_query', true); doc.load(() => { // Add root block and surface block at root level diff --git a/blocksuite/playground/apps/starter/utils/collection.ts b/blocksuite/playground/apps/starter/utils/collection.ts index d55a40f791..f96e1352e3 100644 --- a/blocksuite/playground/apps/starter/utils/collection.ts +++ b/blocksuite/playground/apps/starter/utils/collection.ts @@ -1,4 +1,4 @@ -import { AffineSchemas, TestUtils } from '@blocksuite/blocks'; +import { AffineSchemas, SpecProvider, TestUtils } from '@blocksuite/blocks'; import type { BlockSuiteFlags } from '@blocksuite/global/types'; import { assertExists } from '@blocksuite/global/utils'; import { type BlockCollection, Job, nanoid, Schema } from '@blocksuite/store'; @@ -75,6 +75,8 @@ export function createStarterDocCollection() { blobSources, }; const collection = new TestWorkspace(options); + collection.storeExtensions = + SpecProvider.getInstance().getSpec('store').value; collection.start(); // debug info diff --git a/blocksuite/presets/src/__tests__/utils/setup.ts b/blocksuite/presets/src/__tests__/utils/setup.ts index e184d91587..bee73f382f 100644 --- a/blocksuite/presets/src/__tests__/utils/setup.ts +++ b/blocksuite/presets/src/__tests__/utils/setup.ts @@ -9,6 +9,7 @@ effects(); import { CommunityCanvasTextFonts, type DocMode, + FeatureFlagService, FontConfigExtension, } from '@blocksuite/blocks'; import { AffineSchemas } from '@blocksuite/blocks/schemas'; @@ -84,6 +85,7 @@ async function createEditor(collection: TestWorkspace, mode: DocMode = 'page') { export async function setupEditor(mode: DocMode = 'page') { const collection = new TestWorkspace(createCollectionOptions()); + collection.storeExtensions = [FeatureFlagService]; collection.meta.initialize(); window.collection = collection; diff --git a/blocksuite/tests-legacy/edgeless/auto-complete.spec.ts b/blocksuite/tests-legacy/edgeless/auto-complete.spec.ts index 315e3dd3bd..e4aa9ce9e1 100644 --- a/blocksuite/tests-legacy/edgeless/auto-complete.spec.ts +++ b/blocksuite/tests-legacy/edgeless/auto-complete.spec.ts @@ -108,10 +108,11 @@ test.describe('auto-complete', () => { test('drag on right auto-complete button to add canvas text', async ({ page, }) => { - await enterPlaygroundRoom(page, { - flags: { - enable_edgeless_text: false, - }, + await enterPlaygroundRoom(page); + await page.evaluate(() => { + window.doc + .get(window.$blocksuite.blocks.FeatureFlagService) + .setFlag('enable_edgeless_text', false); }); await initEmptyEdgelessState(page); await switchEditorMode(page); diff --git a/blocksuite/tests-legacy/edgeless/edgeless-text.spec.ts b/blocksuite/tests-legacy/edgeless/edgeless-text.spec.ts index 75a5713bc2..e97323d2b4 100644 --- a/blocksuite/tests-legacy/edgeless/edgeless-text.spec.ts +++ b/blocksuite/tests-legacy/edgeless/edgeless-text.spec.ts @@ -54,11 +54,7 @@ async function assertEdgelessTextModelRect( test.describe('edgeless text block', () => { test.beforeEach(async ({ page }) => { - await enterPlaygroundRoom(page, { - flags: { - enable_edgeless_text: true, - }, - }); + await enterPlaygroundRoom(page); await initEmptyEdgelessState(page); await switchEditorMode(page); }); @@ -546,11 +542,7 @@ test.describe('edgeless text block', () => { test('press backspace at the start of first line when edgeless text exist', async ({ page, }, testInfo) => { - await enterPlaygroundRoom(page, { - flags: { - enable_edgeless_text: true, - }, - }); + await enterPlaygroundRoom(page); await page.evaluate(() => { const { doc } = window; const rootId = doc.addBlock('affine:page', { diff --git a/blocksuite/tests-legacy/edgeless/paste-block.spec.ts b/blocksuite/tests-legacy/edgeless/paste-block.spec.ts index 280ba69540..1813e62f97 100644 --- a/blocksuite/tests-legacy/edgeless/paste-block.spec.ts +++ b/blocksuite/tests-legacy/edgeless/paste-block.spec.ts @@ -66,11 +66,7 @@ test.describe('pasting blocks', () => { await expect(blocks.nth(3)).toContainText('code'); }); test('pasting a edgeless block', async ({ page }) => { - await enterPlaygroundRoom(page, { - flags: { - enable_edgeless_text: true, - }, - }); + await enterPlaygroundRoom(page); await initEmptyEdgelessState(page); await switchEditorMode(page); await setEdgelessTool(page, 'default'); diff --git a/blocksuite/tests-legacy/edgeless/shape.spec.ts b/blocksuite/tests-legacy/edgeless/shape.spec.ts index 8ccb9cd224..b10d6689b1 100644 --- a/blocksuite/tests-legacy/edgeless/shape.spec.ts +++ b/blocksuite/tests-legacy/edgeless/shape.spec.ts @@ -641,10 +641,11 @@ test.describe('shape hit test', () => { } test.beforeEach(async ({ page }) => { - await enterPlaygroundRoom(page, { - flags: { - enable_edgeless_text: false, - }, + await enterPlaygroundRoom(page); + await page.evaluate(() => { + window.doc + .get(window.$blocksuite.blocks.FeatureFlagService) + .setFlag('enable_edgeless_text', false); }); await initEmptyEdgelessState(page); await switchEditorMode(page); diff --git a/blocksuite/tests-legacy/edgeless/text.spec.ts b/blocksuite/tests-legacy/edgeless/text.spec.ts index a0197659ad..734c263c38 100644 --- a/blocksuite/tests-legacy/edgeless/text.spec.ts +++ b/blocksuite/tests-legacy/edgeless/text.spec.ts @@ -38,10 +38,11 @@ async function assertTextFont(page: Page, font: string) { test.describe('edgeless canvas text', () => { test.beforeEach(async ({ page }) => { - await enterPlaygroundRoom(page, { - flags: { - enable_edgeless_text: false, - }, + await enterPlaygroundRoom(page); + await page.evaluate(() => { + window.doc + .get(window.$blocksuite.blocks.FeatureFlagService) + .setFlag('enable_edgeless_text', false); }); await initEmptyEdgelessState(page); await switchEditorMode(page); diff --git a/blocksuite/tests-legacy/utils/actions/misc.ts b/blocksuite/tests-legacy/utils/actions/misc.ts index 7597a56a94..e33d0b7bd1 100644 --- a/blocksuite/tests-legacy/utils/actions/misc.ts +++ b/blocksuite/tests-legacy/utils/actions/misc.ts @@ -95,6 +95,9 @@ async function initEmptyEditor({ } const createEditor = () => { const editor = document.createElement('affine-editor-container'); + doc + .get(window.$blocksuite.blocks.FeatureFlagService) + .setFlag('enable_advanced_block_visibility', true); editor.doc = doc; editor.autofocus = true; const defaultExtensions: ExtensionType[] = [ diff --git a/packages/frontend/core/src/blocksuite/presets/ai/chat-panel/chat-panel-messages.ts b/packages/frontend/core/src/blocksuite/presets/ai/chat-panel/chat-panel-messages.ts index 1c2e62bf30..b2b578f098 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/chat-panel/chat-panel-messages.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/chat-panel/chat-panel-messages.ts @@ -3,6 +3,7 @@ import { ShadowlessElement } from '@blocksuite/affine/block-std'; import { type AIError, DocModeProvider, + FeatureFlagService, isInsidePageEditor, PaymentRequiredError, UnauthorizedError, @@ -141,7 +142,7 @@ export class ChatPanelMessages extends WithDisposable(ShadowlessElement) { private _renderAIOnboarding() { return this.isLoading || - !this.host?.doc.awarenessStore.getFlag('enable_ai_onboarding') + !this.host?.doc.get(FeatureFlagService).getFlag('enable_ai_onboarding') ? nothing : html`
void)[] = []; @@ -325,9 +329,24 @@ 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 workspaceService: WorkspaceService, + private readonly featureFlagService: FeatureFlagService ) { super(); } diff --git a/packages/frontend/core/src/modules/editor/index.ts b/packages/frontend/core/src/modules/editor/index.ts index edd9ec6630..da3f9b72d6 100644 --- a/packages/frontend/core/src/modules/editor/index.ts +++ b/packages/frontend/core/src/modules/editor/index.ts @@ -1,6 +1,7 @@ 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'; @@ -18,7 +19,7 @@ export function configureEditorModule(framework: Framework) { .scope(WorkspaceScope) .scope(DocScope) .service(EditorsService) - .entity(Editor, [DocService, WorkspaceService]) + .entity(Editor, [DocService, WorkspaceService, FeatureFlagService]) .scope(EditorScope) .service(EditorService, [EditorScope]); } diff --git a/packages/frontend/core/src/modules/feature-flag/services/feature-flag.ts b/packages/frontend/core/src/modules/feature-flag/services/feature-flag.ts index cc0ee7a127..e8dc075c5a 100644 --- a/packages/frontend/core/src/modules/feature-flag/services/feature-flag.ts +++ b/packages/frontend/core/src/modules/feature-flag/services/feature-flag.ts @@ -2,27 +2,12 @@ import { OnEvent, Service } from '@toeverything/infra'; import { distinctUntilChanged, skip } from 'rxjs'; import { ApplicationStarted } from '../../lifecycle'; -import type { Workspace } from '../../workspace'; -import { WorkspaceInitialized } from '../../workspace/events'; -import { AFFINE_FLAGS } from '../constant'; import { Flags, type FlagsExt } from '../entities/flags'; -@OnEvent(WorkspaceInitialized, e => e.setupBlocksuiteEditorFlags) @OnEvent(ApplicationStarted, e => e.setupRestartListener) export class FeatureFlagService extends Service { flags = this.framework.createEntity(Flags) as FlagsExt; - setupBlocksuiteEditorFlags(workspace: Workspace) { - for (const [key, flag] of Object.entries(AFFINE_FLAGS)) { - if (flag.category === 'blocksuite') { - const value = this.flags[key as keyof AFFINE_FLAGS].value; - if (value !== undefined) { - workspace.docCollection.awarenessStore.setFlag(flag.bsFlag, value); - } - } - } - } - setupRestartListener() { this.flags.enable_ai.$.pipe(distinctUntilChanged(), skip(1)).subscribe( () => { diff --git a/packages/frontend/core/src/modules/feature-flag/types.ts b/packages/frontend/core/src/modules/feature-flag/types.ts index 665377bcd9..783847a739 100644 --- a/packages/frontend/core/src/modules/feature-flag/types.ts +++ b/packages/frontend/core/src/modules/feature-flag/types.ts @@ -1,4 +1,4 @@ -import type { BlockSuiteFlags } from '@blocksuite/affine/global/types'; +import type { BlockSuiteFlags } from '@blocksuite/affine/blocks'; type FeedbackType = 'discord' | 'email' | 'github'; diff --git a/packages/frontend/core/src/modules/workspace/impls/doc.ts b/packages/frontend/core/src/modules/workspace/impls/doc.ts index 1d4291d1a3..a906774df5 100644 --- a/packages/frontend/core/src/modules/workspace/impls/doc.ts +++ b/packages/frontend/core/src/modules/workspace/impls/doc.ts @@ -1,3 +1,4 @@ +import { SpecProvider } from '@blocksuite/affine/blocks'; import { type Disposable, Slot } from '@blocksuite/affine/global/utils'; import { type AwarenessStore, @@ -283,13 +284,18 @@ export class DocImpl implements Doc { return this._docMap[readonlyKey].get(key) as Store; } + const storeExtensions = SpecProvider.getInstance().getSpec('store'); + const extensionSet = new Set( + storeExtensions.value.concat(extensions ?? []) + ); + const doc = new Store({ doc: this, schema: this.workspace.schema, readonly, query, provider, - extensions, + extensions: Array.from(extensionSet), }); this._docMap[readonlyKey].set(key, doc); diff --git a/packages/frontend/core/src/modules/workspace/impls/workspace.ts b/packages/frontend/core/src/modules/workspace/impls/workspace.ts index a124939d1e..2797fc8c0d 100644 --- a/packages/frontend/core/src/modules/workspace/impls/workspace.ts +++ b/packages/frontend/core/src/modules/workspace/impls/workspace.ts @@ -34,22 +34,6 @@ type WorkspaceOptions = { }; const FLAGS_PRESET = { - enable_synced_doc_block: false, - enable_pie_menu: false, - enable_database_number_formatting: false, - enable_database_attachment_note: false, - enable_database_full_width: false, - enable_block_query: false, - enable_lasso_tool: false, - enable_edgeless_text: true, - enable_ai_onboarding: false, - enable_ai_chat_block: false, - enable_color_picker: false, - enable_mind_map_import: false, - enable_advanced_block_visibility: false, - enable_shape_shadow_blur: false, - enable_mobile_keyboard_toolbar: false, - enable_mobile_linked_doc_menu: false, readonly: {}, } satisfies BlockSuiteFlags;