mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-25 18:26:05 +08:00
refactor(editor): file size limit service (#12026)
Closes: [BS-3359](https://linear.app/affine-design/issue/BS-3359/重构-filesizelimitservice-支持-handle-文件超出限制) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added an "Upgrade" button to attachment blocks that appears when file size limits are exceeded, enabling users to view storage plans and upgrade. - **Refactor** - Unified file size limit handling across attachments and images for consistency. - Redesigned file size limit service with improved integration and dependency injection. - **Chores** - Updated service registrations and dependency management for file size limit enforcement. - Integrated a new file size limit extension that triggers storage plan dialogs and tracking events on limit exceedance. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -11,11 +11,16 @@ import {
|
|||||||
AttachmentBlockStyles,
|
AttachmentBlockStyles,
|
||||||
} from '@blocksuite/affine-model';
|
} from '@blocksuite/affine-model';
|
||||||
import {
|
import {
|
||||||
FileSizeLimitService,
|
FileSizeLimitProvider,
|
||||||
ThemeProvider,
|
ThemeProvider,
|
||||||
} from '@blocksuite/affine-shared/services';
|
} from '@blocksuite/affine-shared/services';
|
||||||
import { humanFileSize } from '@blocksuite/affine-shared/utils';
|
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 { BlockSelection } from '@blocksuite/std';
|
||||||
import { Slice } from '@blocksuite/store';
|
import { Slice } from '@blocksuite/store';
|
||||||
import { type BlobState } from '@blocksuite/sync';
|
import { type BlobState } from '@blocksuite/sync';
|
||||||
@@ -50,7 +55,7 @@ export class AttachmentBlockComponent extends CaptionedBlockComponent<Attachment
|
|||||||
});
|
});
|
||||||
|
|
||||||
private get _maxFileSize() {
|
private get _maxFileSize() {
|
||||||
return this.std.store.get(FileSizeLimitService).maxFileSize;
|
return this.std.get(FileSizeLimitProvider).maxFileSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
get isCitation() {
|
get isCitation() {
|
||||||
@@ -185,7 +190,24 @@ export class AttachmentBlockComponent extends CaptionedBlockComponent<Attachment
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected renderUpgradeButton = () => {
|
protected renderUpgradeButton = () => {
|
||||||
return null;
|
if (this.std.store.readonly) return null;
|
||||||
|
|
||||||
|
const onOverFileSize = this.std.get(FileSizeLimitProvider).onOverFileSize;
|
||||||
|
|
||||||
|
return when(
|
||||||
|
onOverFileSize,
|
||||||
|
() => html`
|
||||||
|
<button
|
||||||
|
class="affine-attachment-content-button"
|
||||||
|
@click=${(event: MouseEvent) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
onOverFileSize?.();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
${UpgradeIcon()} Upgrade
|
||||||
|
</button>
|
||||||
|
`
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
protected renderReloadButton = () => {
|
protected renderReloadButton = () => {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import {
|
|||||||
type ImageBlockProps,
|
type ImageBlockProps,
|
||||||
MAX_IMAGE_WIDTH,
|
MAX_IMAGE_WIDTH,
|
||||||
} from '@blocksuite/affine-model';
|
} from '@blocksuite/affine-model';
|
||||||
import { FileSizeLimitService } from '@blocksuite/affine-shared/services';
|
import { FileSizeLimitProvider } from '@blocksuite/affine-shared/services';
|
||||||
import {
|
import {
|
||||||
readImageSize,
|
readImageSize,
|
||||||
transformModel,
|
transformModel,
|
||||||
@@ -68,7 +68,7 @@ export const AttachmentEmbedProvider = createIdentifier<AttachmentEmbedService>(
|
|||||||
|
|
||||||
export class AttachmentEmbedService extends Extension {
|
export class AttachmentEmbedService extends Extension {
|
||||||
private get _maxFileSize() {
|
private get _maxFileSize() {
|
||||||
return this.std.store.get(FileSizeLimitService).maxFileSize;
|
return this.std.get(FileSizeLimitProvider).maxFileSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
get keys() {
|
get keys() {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
} from '@blocksuite/affine-shared/consts';
|
} from '@blocksuite/affine-shared/consts';
|
||||||
import {
|
import {
|
||||||
type AttachmentUploadedEvent,
|
type AttachmentUploadedEvent,
|
||||||
FileSizeLimitService,
|
FileSizeLimitProvider,
|
||||||
TelemetryProvider,
|
TelemetryProvider,
|
||||||
} from '@blocksuite/affine-shared/services';
|
} from '@blocksuite/affine-shared/services';
|
||||||
import { humanFileSize } from '@blocksuite/affine-shared/utils';
|
import { humanFileSize } from '@blocksuite/affine-shared/utils';
|
||||||
@@ -110,7 +110,7 @@ export async function getFileType(file: File) {
|
|||||||
function hasExceeded(
|
function hasExceeded(
|
||||||
std: BlockStdScope,
|
std: BlockStdScope,
|
||||||
files: File[],
|
files: File[],
|
||||||
maxFileSize = std.store.get(FileSizeLimitService).maxFileSize
|
maxFileSize = std.get(FileSizeLimitProvider).maxFileSize
|
||||||
) {
|
) {
|
||||||
const exceeded = files.some(file => file.size > maxFileSize);
|
const exceeded = files.some(file => file.size > maxFileSize);
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
ImageBlockSchema,
|
ImageBlockSchema,
|
||||||
} from '@blocksuite/affine-model';
|
} from '@blocksuite/affine-model';
|
||||||
import {
|
import {
|
||||||
FileSizeLimitService,
|
FileSizeLimitProvider,
|
||||||
NativeClipboardProvider,
|
NativeClipboardProvider,
|
||||||
} from '@blocksuite/affine-shared/services';
|
} from '@blocksuite/affine-shared/services';
|
||||||
import {
|
import {
|
||||||
@@ -362,7 +362,7 @@ export function shouldResizeImage(node: Node, target: EventTarget | null) {
|
|||||||
function hasExceeded(
|
function hasExceeded(
|
||||||
std: BlockStdScope,
|
std: BlockStdScope,
|
||||||
files: File[],
|
files: File[],
|
||||||
maxFileSize = std.store.get(FileSizeLimitService).maxFileSize
|
maxFileSize = std.get(FileSizeLimitProvider).maxFileSize
|
||||||
) {
|
) {
|
||||||
const exceeded = files.some(file => file.size > maxFileSize);
|
const exceeded = files.some(file => file.size > maxFileSize);
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import { HighlightSelectionExtension } from '@blocksuite/affine-shared/selection
|
|||||||
import {
|
import {
|
||||||
BlockMetaService,
|
BlockMetaService,
|
||||||
FeatureFlagService,
|
FeatureFlagService,
|
||||||
FileSizeLimitService,
|
|
||||||
LinkPreviewerService,
|
LinkPreviewerService,
|
||||||
} from '@blocksuite/affine-shared/services';
|
} from '@blocksuite/affine-shared/services';
|
||||||
import {
|
import {
|
||||||
@@ -51,7 +50,6 @@ export class FoundationStoreExtension extends StoreExtensionProvider {
|
|||||||
BlockMetaService,
|
BlockMetaService,
|
||||||
// TODO(@mirone): maybe merge these services into a file setting service
|
// TODO(@mirone): maybe merge these services into a file setting service
|
||||||
LinkPreviewerService,
|
LinkPreviewerService,
|
||||||
FileSizeLimitService,
|
|
||||||
ImageProxyService,
|
ImageProxyService,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import {
|
|||||||
DocModeService,
|
DocModeService,
|
||||||
EditPropsStore,
|
EditPropsStore,
|
||||||
EmbedOptionService,
|
EmbedOptionService,
|
||||||
|
FileSizeLimitService,
|
||||||
FontLoaderService,
|
FontLoaderService,
|
||||||
PageViewportServiceExtension,
|
PageViewportServiceExtension,
|
||||||
ThemeService,
|
ThemeService,
|
||||||
@@ -109,6 +110,7 @@ export class FoundationViewExtension extends ViewExtensionProvider {
|
|||||||
FileDropExtension,
|
FileDropExtension,
|
||||||
ToolbarRegistryExtension,
|
ToolbarRegistryExtension,
|
||||||
AutoClearSelectionService,
|
AutoClearSelectionService,
|
||||||
|
FileSizeLimitService,
|
||||||
]);
|
]);
|
||||||
context.register(clipboardConfigs);
|
context.register(clipboardConfigs);
|
||||||
if (this.isEdgeless(context.scope)) {
|
if (this.isEdgeless(context.scope)) {
|
||||||
|
|||||||
@@ -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')
|
export interface IFileSizeLimitService {
|
||||||
const maxFileSize = 2 * 1024 * 1024 * 1024;
|
maxFileSize: number;
|
||||||
|
onOverFileSize?: () => void;
|
||||||
export class FileSizeLimitService extends StoreExtension {
|
}
|
||||||
static override key = 'file-size-limit';
|
|
||||||
|
export const FileSizeLimitProvider = createIdentifier<IFileSizeLimitService>(
|
||||||
maxFileSize = maxFileSize;
|
'FileSizeLimitService'
|
||||||
|
);
|
||||||
|
|
||||||
|
export class FileSizeLimitService
|
||||||
|
extends Extension
|
||||||
|
implements IFileSizeLimitService
|
||||||
|
{
|
||||||
|
// 2GB
|
||||||
|
maxFileSize = 2 * 1024 * 1024 * 1024;
|
||||||
|
|
||||||
|
static override setup(di: Container) {
|
||||||
|
di.addImpl(FileSizeLimitProvider, FileSizeLimitService);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -26,6 +26,7 @@ import { edgelessCopilotWidget } from '../ai/widgets/edgeless-copilot';
|
|||||||
import { buildDocDisplayMetaExtension } from '../extensions/display-meta';
|
import { buildDocDisplayMetaExtension } from '../extensions/display-meta';
|
||||||
import { getEditorConfigExtension } from '../extensions/editor-config';
|
import { getEditorConfigExtension } from '../extensions/editor-config';
|
||||||
import { getPagePreviewThemeExtension } from '../extensions/entry/enable-preview';
|
import { getPagePreviewThemeExtension } from '../extensions/entry/enable-preview';
|
||||||
|
import { patchFileSizeLimitExtension } from '../extensions/file-size-limit';
|
||||||
import { getFontConfigExtension } from '../extensions/font-config';
|
import { getFontConfigExtension } from '../extensions/font-config';
|
||||||
import { patchPeekViewService } from '../extensions/peek-view-service';
|
import { patchPeekViewService } from '../extensions/peek-view-service';
|
||||||
import { getTelemetryExtension } from '../extensions/telemetry';
|
import { getTelemetryExtension } from '../extensions/telemetry';
|
||||||
@@ -58,6 +59,7 @@ class MigratingAffineViewExtension extends ViewExtensionProvider<
|
|||||||
if (context.scope === 'page' || context.scope === 'edgeless') {
|
if (context.scope === 'page' || context.scope === 'edgeless') {
|
||||||
context.register(getTelemetryExtension());
|
context.register(getTelemetryExtension());
|
||||||
context.register(getEditorConfigExtension(framework));
|
context.register(getEditorConfigExtension(framework));
|
||||||
|
context.register(patchFileSizeLimitExtension(framework));
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
context.scope === 'preview-page' ||
|
context.scope === 'preview-page' ||
|
||||||
|
|||||||
Reference in New Issue
Block a user