refactor(editor): split turbo renderer and cloud view builder (#12213)

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Introduced dedicated extensions for cloud features, turbo renderer, and PDF embed preview, enabling modular and configurable view options.
  - Added audio embed preview support for attachments, enhancing the audio file viewing experience.

- **Refactor**
  - Streamlined editor view configuration with modular extension registration.
  - Simplified extension setup by removing some feature flags and related services from core editor configuration.

- **Chores**
  - Updated internal worker configuration paths for improved organization.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Saul-Mirone
2025-05-12 01:36:41 +00:00
parent 4c8e11aa25
commit e91e0e1812
13 changed files with 180 additions and 58 deletions

View File

@@ -84,14 +84,13 @@ const usePatchSpecs = (mode: DocMode) => {
.theme(framework)
.editorConfig(framework)
.editorView({
isCloud,
isInPeekView,
enableTurboRenderer,
enablePDFEmbedPreview,
framework,
reactToLit,
confirmModal,
})
.cloud(framework, isCloud)
.turboRenderer(enableTurboRenderer)
.pdf(enablePDFEmbedPreview, reactToLit)
.edgelessBlockHeader({
framework,
isInPeekView,

View File

@@ -0,0 +1,19 @@
import type { ReactToLit } from '@affine/component';
import { AttachmentEmbedPreview } from '@affine/core/blocksuite/attachment-viewer/attachment-embed-preview';
import { AttachmentEmbedConfigIdentifier } from '@blocksuite/affine/blocks/attachment';
import type { ExtensionType } from '@blocksuite/store';
export function patchForAudioEmbedView(reactToLit: ReactToLit): ExtensionType {
return {
setup: di => {
di.override(AttachmentEmbedConfigIdentifier('audio'), () => ({
name: 'audio',
check: (model, maxFileSize) =>
model.props.type.startsWith('audio/') &&
model.props.size <= maxFileSize,
render: (model, _) =>
reactToLit(<AttachmentEmbedPreview model={model} />, false),
}));
},
};
}

View File

@@ -0,0 +1,40 @@
import { PublicUserService } from '@affine/core/modules/cloud';
import { MemberSearchService } from '@affine/core/modules/permissions';
import {
type ViewExtensionContext,
ViewExtensionProvider,
} from '@blocksuite/affine/ext-loader';
import { FrameworkProvider } from '@toeverything/infra';
import { z } from 'zod';
import { patchUserExtensions } from './user';
import { patchUserListExtensions } from './user-list';
const optionsSchema = z.object({
framework: z.instanceof(FrameworkProvider).optional(),
enableCloud: z.boolean().optional(),
});
type CloudViewOptions = z.infer<typeof optionsSchema>;
export class CloudViewExtension extends ViewExtensionProvider<CloudViewOptions> {
override name = 'affine-view-cloud';
override schema = optionsSchema;
override setup(context: ViewExtensionContext, options?: CloudViewOptions) {
super.setup(context, options);
const enableCloud = options?.enableCloud;
const framework = options?.framework;
if (!enableCloud || !framework) {
return;
}
const memberSearchService = framework.get(MemberSearchService);
const publicUserService = framework.get(PublicUserService);
context.register([
patchUserListExtensions(memberSearchService),
patchUserExtensions(publicUserService),
]);
}
}

View File

@@ -0,0 +1,38 @@
import type { ElementOrFactory } from '@affine/component';
import {
type ViewExtensionContext,
ViewExtensionProvider,
} from '@blocksuite/affine/ext-loader';
import type { TemplateResult } from 'lit';
import { z } from 'zod';
import { patchForPDFEmbedView } from './pdf-view';
const optionsSchema = z.object({
enablePDFEmbedPreview: z.boolean().optional(),
reactToLit: z.optional(
z
.function()
.args(z.custom<ElementOrFactory>(), z.boolean().optional())
.returns(z.custom<TemplateResult>())
),
});
type PdfViewOptions = z.infer<typeof optionsSchema>;
export class PdfViewExtension extends ViewExtensionProvider<PdfViewOptions> {
override name = 'affine-view-pdf';
override schema = optionsSchema;
override setup(context: ViewExtensionContext, options?: PdfViewOptions) {
super.setup(context, options);
const enablePDFEmbedPreview = options?.enablePDFEmbedPreview;
const reactToLit = options?.reactToLit;
if (!enablePDFEmbedPreview || !reactToLit) {
return;
}
context.register(patchForPDFEmbedView(reactToLit));
}
}

View File

@@ -33,18 +33,3 @@ export function patchForPDFEmbedView(reactToLit: ReactToLit): ExtensionType {
},
};
}
export function patchForAudioEmbedView(reactToLit: ReactToLit): ExtensionType {
return {
setup: di => {
di.override(AttachmentEmbedConfigIdentifier('audio'), () => ({
name: 'audio',
check: (model, maxFileSize) =>
model.props.type.startsWith('audio/') &&
model.props.size <= maxFileSize,
render: (model, _) =>
reactToLit(<AttachmentEmbedPreview model={model} />, false),
}));
},
};
}

View File

@@ -0,0 +1,34 @@
import {
type ViewExtensionContext,
ViewExtensionProvider,
} from '@blocksuite/affine/ext-loader';
import { z } from 'zod';
import { turboRendererExtension } from './turbo-renderer';
const optionsSchema = z.object({
enableTurboRenderer: z.boolean().optional(),
});
type TurboRendererViewOptions = z.infer<typeof optionsSchema>;
export class TurboRendererViewExtension extends ViewExtensionProvider<TurboRendererViewOptions> {
override name = 'affine-view-turbo-renderer';
override schema = optionsSchema;
override setup(
context: ViewExtensionContext,
options?: TurboRendererViewOptions
) {
super.setup(context, options);
const enableTurboRenderer = options?.enableTurboRenderer;
const isEdgeless = this.isEdgeless(context.scope);
if (!enableTurboRenderer || !isEdgeless) {
return;
}
context.register(turboRendererExtension);
}
}

View File

@@ -1,8 +1,5 @@
import type { ConfirmModalProps, ElementOrFactory } from '@affine/component';
import {
patchForAudioEmbedView,
patchForPDFEmbedView,
} from '@affine/core/blocksuite/extensions/attachment-embed-view';
import { patchForAudioEmbedView } from '@affine/core/blocksuite/extensions/audio/audio-view';
import { patchDatabaseBlockConfigService } from '@affine/core/blocksuite/extensions/database-block-config-service';
import { patchDocModeService } from '@affine/core/blocksuite/extensions/doc-mode-service';
import { patchDocUrlExtensions } from '@affine/core/blocksuite/extensions/doc-url';
@@ -16,18 +13,13 @@ import {
type ReferenceReactRenderer,
} from '@affine/core/blocksuite/extensions/reference-renderer';
import { patchSideBarService } from '@affine/core/blocksuite/extensions/side-bar-service';
import { turboRendererExtension } from '@affine/core/blocksuite/extensions/turbo-renderer';
import { patchUserExtensions } from '@affine/core/blocksuite/extensions/user';
import { patchUserListExtensions } from '@affine/core/blocksuite/extensions/user-list';
import {
AffinePageReference,
AffineSharedPageReference,
} from '@affine/core/components/affine/reference-link';
import { PublicUserService } from '@affine/core/modules/cloud';
import { DocService, DocsService } from '@affine/core/modules/doc';
import { EditorService } from '@affine/core/modules/editor';
import { toDocSearchParams } from '@affine/core/modules/navigation';
import { MemberSearchService } from '@affine/core/modules/permissions';
import { WorkspaceService } from '@affine/core/modules/workspace';
import {
type ViewExtensionContext,
@@ -45,14 +37,6 @@ import {
} from '../extensions/mobile-config';
const optionsSchema = z.object({
// env
isCloud: z.boolean(),
isInPeekView: z.boolean(),
// flags
enableTurboRenderer: z.boolean(),
enablePDFEmbedPreview: z.boolean(),
// services
framework: z.instanceof(FrameworkProvider),
@@ -117,25 +101,17 @@ export class AffineEditorViewExtension extends ViewExtensionProvider<AffineEdito
return;
}
const {
isCloud,
enableTurboRenderer,
enablePDFEmbedPreview,
framework,
reactToLit,
confirmModal,
} = options;
const isEdgeless = this.isEdgeless(context.scope);
const isMobileEdition = BUILD_CONFIG.isMobileEdition;
const isElectron = BUILD_CONFIG.isElectron;
const docService = framework.get(DocService);
const docsService = framework.get(DocsService);
const editorService = framework.get(EditorService);
const memberSearchService = framework.get(MemberSearchService);
const publicUserService = framework.get(PublicUserService);
const referenceRenderer = this._getCustomReferenceRenderer(framework);
@@ -153,18 +129,6 @@ export class AffineEditorViewExtension extends ViewExtensionProvider<AffineEdito
patchDatabaseBlockConfigService(),
patchForAudioEmbedView(reactToLit),
]);
if (isCloud) {
context.register([
patchUserListExtensions(memberSearchService),
patchUserExtensions(publicUserService),
]);
}
if (isEdgeless && enableTurboRenderer) {
context.register(turboRendererExtension);
}
if (enablePDFEmbedPreview) {
context.register(patchForPDFEmbedView(reactToLit));
}
if (isMobileEdition) {
context.register([
KeyboardToolbarExtension(framework),

View File

@@ -1,3 +1,5 @@
import type { ReactToLit } from '@affine/component';
import { CloudViewExtension } from '@affine/core/blocksuite/extensions/cloud';
import {
EdgelessBlockHeaderConfigViewExtension,
type EdgelessBlockHeaderViewOptions,
@@ -5,7 +7,9 @@ import {
import { AffineEditorConfigViewExtension } from '@affine/core/blocksuite/extensions/editor-config';
import { createDatabaseOptionsConfig } from '@affine/core/blocksuite/extensions/editor-config/database';
import { createLinkedWidgetConfig } from '@affine/core/blocksuite/extensions/editor-config/linked';
import { PdfViewExtension } from '@affine/core/blocksuite/extensions/pdf';
import { AffineThemeViewExtension } from '@affine/core/blocksuite/extensions/theme';
import { TurboRendererViewExtension } from '@affine/core/blocksuite/extensions/turbo-renderer';
import { AffineCommonViewExtension } from '@affine/core/blocksuite/manager/common-view';
import {
AffineEditorViewExtension,
@@ -41,6 +45,9 @@ class ViewProvider {
AffineEditorConfigViewExtension,
CodeBlockPreviewViewExtension,
EdgelessBlockHeaderConfigViewExtension,
TurboRendererViewExtension,
CloudViewExtension,
PdfViewExtension,
]);
}
@@ -59,6 +66,9 @@ class ViewProvider {
database: this._configureDatabase,
linkedDoc: this._configureLinkedDoc,
paragraph: this._configureParagraph,
cloud: this._configureCloud,
turboRenderer: this._configureTurboRenderer,
pdf: this._configurePdf,
value: this._manager,
};
}
@@ -72,7 +82,10 @@ class ViewProvider {
.edgelessBlockHeader()
.database()
.linkedDoc()
.paragraph();
.paragraph()
.cloud()
.turboRenderer()
.pdf();
return this.config;
};
@@ -152,6 +165,34 @@ class ViewProvider {
}
return this.config;
};
private readonly _configureCloud = (
framework?: FrameworkProvider,
enableCloud?: boolean
) => {
this._manager.configure(CloudViewExtension, { framework, enableCloud });
return this.config;
};
private readonly _configureTurboRenderer = (
enableTurboRenderer?: boolean
) => {
this._manager.configure(TurboRendererViewExtension, {
enableTurboRenderer,
});
return this.config;
};
private readonly _configurePdf = (
enablePDFEmbedPreview?: boolean,
reactToLit?: ReactToLit
) => {
this._manager.configure(PdfViewExtension, {
enablePDFEmbedPreview,
reactToLit,
});
return this.config;
};
}
export function getViewManager() {