diff --git a/blocksuite/affine/blocks/attachment/src/attachment-block.ts b/blocksuite/affine/blocks/attachment/src/attachment-block.ts index 7e5302b87a..951144a732 100644 --- a/blocksuite/affine/blocks/attachment/src/attachment-block.ts +++ b/blocksuite/affine/blocks/attachment/src/attachment-block.ts @@ -11,11 +11,16 @@ import { AttachmentBlockStyles, } from '@blocksuite/affine-model'; import { - FileSizeLimitService, + FileSizeLimitProvider, ThemeProvider, } from '@blocksuite/affine-shared/services'; import { humanFileSize } from '@blocksuite/affine-shared/utils'; -import { AttachmentIcon, ResetIcon, WarningIcon } from '@blocksuite/icons/lit'; +import { + AttachmentIcon, + ResetIcon, + UpgradeIcon, + WarningIcon, +} from '@blocksuite/icons/lit'; import { BlockSelection } from '@blocksuite/std'; import { Slice } from '@blocksuite/store'; import { type BlobState } from '@blocksuite/sync'; @@ -50,7 +55,7 @@ export class AttachmentBlockComponent extends CaptionedBlockComponent { - return null; + if (this.std.store.readonly) return null; + + const onOverFileSize = this.std.get(FileSizeLimitProvider).onOverFileSize; + + return when( + onOverFileSize, + () => html` + + ` + ); }; protected renderReloadButton = () => { diff --git a/blocksuite/affine/blocks/attachment/src/embed.ts b/blocksuite/affine/blocks/attachment/src/embed.ts index 93727441c4..e9dc7a2f45 100644 --- a/blocksuite/affine/blocks/attachment/src/embed.ts +++ b/blocksuite/affine/blocks/attachment/src/embed.ts @@ -3,7 +3,7 @@ import { type ImageBlockProps, MAX_IMAGE_WIDTH, } from '@blocksuite/affine-model'; -import { FileSizeLimitService } from '@blocksuite/affine-shared/services'; +import { FileSizeLimitProvider } from '@blocksuite/affine-shared/services'; import { readImageSize, transformModel, @@ -68,7 +68,7 @@ export const AttachmentEmbedProvider = createIdentifier( export class AttachmentEmbedService extends Extension { private get _maxFileSize() { - return this.std.store.get(FileSizeLimitService).maxFileSize; + return this.std.get(FileSizeLimitProvider).maxFileSize; } get keys() { diff --git a/blocksuite/affine/blocks/attachment/src/utils.ts b/blocksuite/affine/blocks/attachment/src/utils.ts index eabc76f91f..901b3f4424 100644 --- a/blocksuite/affine/blocks/attachment/src/utils.ts +++ b/blocksuite/affine/blocks/attachment/src/utils.ts @@ -10,7 +10,7 @@ import { } from '@blocksuite/affine-shared/consts'; import { type AttachmentUploadedEvent, - FileSizeLimitService, + FileSizeLimitProvider, TelemetryProvider, } from '@blocksuite/affine-shared/services'; import { humanFileSize } from '@blocksuite/affine-shared/utils'; @@ -110,7 +110,7 @@ export async function getFileType(file: File) { function hasExceeded( std: BlockStdScope, files: File[], - maxFileSize = std.store.get(FileSizeLimitService).maxFileSize + maxFileSize = std.get(FileSizeLimitProvider).maxFileSize ) { const exceeded = files.some(file => file.size > maxFileSize); diff --git a/blocksuite/affine/blocks/image/src/utils.ts b/blocksuite/affine/blocks/image/src/utils.ts index 6e610dbb53..a1bcef9cdf 100644 --- a/blocksuite/affine/blocks/image/src/utils.ts +++ b/blocksuite/affine/blocks/image/src/utils.ts @@ -7,7 +7,7 @@ import { ImageBlockSchema, } from '@blocksuite/affine-model'; import { - FileSizeLimitService, + FileSizeLimitProvider, NativeClipboardProvider, } from '@blocksuite/affine-shared/services'; import { @@ -362,7 +362,7 @@ export function shouldResizeImage(node: Node, target: EventTarget | null) { function hasExceeded( std: BlockStdScope, files: File[], - maxFileSize = std.store.get(FileSizeLimitService).maxFileSize + maxFileSize = std.get(FileSizeLimitProvider).maxFileSize ) { const exceeded = files.some(file => file.size > maxFileSize); diff --git a/blocksuite/affine/foundation/src/store.ts b/blocksuite/affine/foundation/src/store.ts index 14ffac00e3..c5499721d3 100644 --- a/blocksuite/affine/foundation/src/store.ts +++ b/blocksuite/affine/foundation/src/store.ts @@ -15,7 +15,6 @@ import { HighlightSelectionExtension } from '@blocksuite/affine-shared/selection import { BlockMetaService, FeatureFlagService, - FileSizeLimitService, LinkPreviewerService, } from '@blocksuite/affine-shared/services'; import { @@ -51,7 +50,6 @@ export class FoundationStoreExtension extends StoreExtensionProvider { BlockMetaService, // TODO(@mirone): maybe merge these services into a file setting service LinkPreviewerService, - FileSizeLimitService, ImageProxyService, ]); } diff --git a/blocksuite/affine/foundation/src/view.ts b/blocksuite/affine/foundation/src/view.ts index e7de06f296..517257b415 100644 --- a/blocksuite/affine/foundation/src/view.ts +++ b/blocksuite/affine/foundation/src/view.ts @@ -19,6 +19,7 @@ import { DocModeService, EditPropsStore, EmbedOptionService, + FileSizeLimitService, FontLoaderService, PageViewportServiceExtension, ThemeService, @@ -109,6 +110,7 @@ export class FoundationViewExtension extends ViewExtensionProvider { FileDropExtension, ToolbarRegistryExtension, AutoClearSelectionService, + FileSizeLimitService, ]); context.register(clipboardConfigs); if (this.isEdgeless(context.scope)) { diff --git a/blocksuite/affine/shared/src/services/file-size-limit-service.ts b/blocksuite/affine/shared/src/services/file-size-limit-service.ts index dcab5d9e32..8d7c009d52 100644 --- a/blocksuite/affine/shared/src/services/file-size-limit-service.ts +++ b/blocksuite/affine/shared/src/services/file-size-limit-service.ts @@ -1,10 +1,23 @@ -import { StoreExtension } from '@blocksuite/store'; +import { type Container, createIdentifier } from '@blocksuite/global/di'; +import { Extension } from '@blocksuite/store'; -// bytes.parse('2GB') -const maxFileSize = 2 * 1024 * 1024 * 1024; - -export class FileSizeLimitService extends StoreExtension { - static override key = 'file-size-limit'; - - maxFileSize = maxFileSize; +export interface IFileSizeLimitService { + maxFileSize: number; + onOverFileSize?: () => void; +} + +export const FileSizeLimitProvider = createIdentifier( + 'FileSizeLimitService' +); + +export class FileSizeLimitService + extends Extension + implements IFileSizeLimitService +{ + // 2GB + maxFileSize = 2 * 1024 * 1024 * 1024; + + static override setup(di: Container) { + di.addImpl(FileSizeLimitProvider, FileSizeLimitService); + } } diff --git a/packages/frontend/core/src/blocksuite/extensions/file-size-limit.ts b/packages/frontend/core/src/blocksuite/extensions/file-size-limit.ts new file mode 100644 index 0000000000..a948c2e2b9 --- /dev/null +++ b/packages/frontend/core/src/blocksuite/extensions/file-size-limit.ts @@ -0,0 +1,35 @@ +import { WorkspaceDialogService } from '@affine/core/modules/dialogs'; +import track from '@affine/track'; +import type { Container } from '@blocksuite/affine/global/di'; +import { + FileSizeLimitProvider, + type IFileSizeLimitService, +} from '@blocksuite/affine/shared/services'; +import { Extension } from '@blocksuite/affine/store'; +import type { FrameworkProvider } from '@toeverything/infra'; + +export function patchFileSizeLimitExtension(framework: FrameworkProvider) { + const workspaceDialogService = framework.get(WorkspaceDialogService); + + class AffineFileSizeLimitService + extends Extension + implements IFileSizeLimitService + { + // 2GB + maxFileSize = 2 * 1024 * 1024 * 1024; + + onOverFileSize() { + workspaceDialogService.open('setting', { + activeTab: 'plans', + scrollAnchor: 'cloudPricingPlan', + }); + track.$.paywall.storage.viewPlans(); + } + + static override setup(di: Container) { + di.override(FileSizeLimitProvider, AffineFileSizeLimitService); + } + } + + return AffineFileSizeLimitService; +} diff --git a/packages/frontend/core/src/blocksuite/manager/migrating-view.ts b/packages/frontend/core/src/blocksuite/manager/migrating-view.ts index 3b7a0838c8..fee547b8eb 100644 --- a/packages/frontend/core/src/blocksuite/manager/migrating-view.ts +++ b/packages/frontend/core/src/blocksuite/manager/migrating-view.ts @@ -26,6 +26,7 @@ import { edgelessCopilotWidget } from '../ai/widgets/edgeless-copilot'; import { buildDocDisplayMetaExtension } from '../extensions/display-meta'; import { getEditorConfigExtension } from '../extensions/editor-config'; import { getPagePreviewThemeExtension } from '../extensions/entry/enable-preview'; +import { patchFileSizeLimitExtension } from '../extensions/file-size-limit'; import { getFontConfigExtension } from '../extensions/font-config'; import { patchPeekViewService } from '../extensions/peek-view-service'; import { getTelemetryExtension } from '../extensions/telemetry'; @@ -58,6 +59,7 @@ class MigratingAffineViewExtension extends ViewExtensionProvider< if (context.scope === 'page' || context.scope === 'edgeless') { context.register(getTelemetryExtension()); context.register(getEditorConfigExtension(framework)); + context.register(patchFileSizeLimitExtension(framework)); } if ( context.scope === 'preview-page' ||