mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-22 08:47:10 +08:00
refactor(editor): split openFileOrFiles into openSingleFileWith and openFilesWith (#12523)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Improved file selection dialogs for attachments, imports, and uploads, allowing for more consistent and streamlined file picking across the app. - **Bug Fixes** - Resolved inconsistencies when selecting single or multiple files, ensuring a smoother user experience during file import and upload. - **Refactor** - Unified and simplified file selection logic throughout the app for better reliability and maintainability. - Standardized import functions to uniformly handle arrays of files, enhancing consistency in file processing. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { openFileOrFiles } from '@blocksuite/affine-shared/utils';
|
import { openSingleFileWith } from '@blocksuite/affine-shared/utils';
|
||||||
import { type SlashMenuConfig } from '@blocksuite/affine-widget-slash-menu';
|
import { type SlashMenuConfig } from '@blocksuite/affine-widget-slash-menu';
|
||||||
import { ExportToPdfIcon, FileIcon } from '@blocksuite/icons/lit';
|
import { ExportToPdfIcon, FileIcon } from '@blocksuite/icons/lit';
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ export const attachmentSlashMenuConfig: SlashMenuConfig = {
|
|||||||
model.store.schema.flavourSchemaMap.has('affine:attachment'),
|
model.store.schema.flavourSchemaMap.has('affine:attachment'),
|
||||||
action: ({ std, model }) => {
|
action: ({ std, model }) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const file = await openFileOrFiles();
|
const file = await openSingleFileWith();
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
|
||||||
await addSiblingAttachmentBlocks(std, [file], model);
|
await addSiblingAttachmentBlocks(std, [file], model);
|
||||||
@@ -44,7 +44,7 @@ export const attachmentSlashMenuConfig: SlashMenuConfig = {
|
|||||||
model.store.schema.flavourSchemaMap.has('affine:attachment'),
|
model.store.schema.flavourSchemaMap.has('affine:attachment'),
|
||||||
action: ({ std, model }) => {
|
action: ({ std, model }) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
const file = await openFileOrFiles();
|
const file = await openSingleFileWith();
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
|
||||||
await addSiblingAttachmentBlocks(std, [file], model);
|
await addSiblingAttachmentBlocks(std, [file], model);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import {
|
|||||||
FeatureFlagService,
|
FeatureFlagService,
|
||||||
TelemetryProvider,
|
TelemetryProvider,
|
||||||
} from '@blocksuite/affine-shared/services';
|
} from '@blocksuite/affine-shared/services';
|
||||||
import { openFileOrFiles } from '@blocksuite/affine-shared/utils';
|
import { openSingleFileWith } from '@blocksuite/affine-shared/utils';
|
||||||
import { Bound, type IVec } from '@blocksuite/global/gfx';
|
import { Bound, type IVec } from '@blocksuite/global/gfx';
|
||||||
import type { BlockComponent } from '@blocksuite/std';
|
import type { BlockComponent } from '@blocksuite/std';
|
||||||
import type { TemplateResult } from 'lit';
|
import type { TemplateResult } from 'lit';
|
||||||
@@ -158,7 +158,7 @@ export const textRender: DraggableTool['render'] = async (bound, edgeless) => {
|
|||||||
export const mediaRender: DraggableTool['render'] = async (bound, edgeless) => {
|
export const mediaRender: DraggableTool['render'] = async (bound, edgeless) => {
|
||||||
let file: File | null = null;
|
let file: File | null = null;
|
||||||
try {
|
try {
|
||||||
file = await openFileOrFiles();
|
file = await openSingleFileWith();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { openFileOrFiles } from '@blocksuite/affine-shared/utils';
|
import { openSingleFileWith } from '@blocksuite/affine-shared/utils';
|
||||||
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
import { BlockSuiteError, ErrorCode } from '@blocksuite/global/exceptions';
|
||||||
import type { Bound } from '@blocksuite/global/gfx';
|
import type { Bound } from '@blocksuite/global/gfx';
|
||||||
import c from 'simple-xml-to-json';
|
import c from 'simple-xml-to-json';
|
||||||
@@ -12,9 +12,7 @@ type MindMapNode = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export async function importMindmap(bound: Bound): Promise<MindMapNode> {
|
export async function importMindmap(bound: Bound): Promise<MindMapNode> {
|
||||||
const file = await openFileOrFiles({
|
const file = await openSingleFileWith('MindMap');
|
||||||
acceptType: 'MindMap',
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!file) {
|
if (!file) {
|
||||||
throw new BlockSuiteError(ErrorCode.UserAbortError, 'Aborted by user');
|
throw new BlockSuiteError(ErrorCode.UserAbortError, 'Aborted by user');
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { TelemetryProvider } from '@blocksuite/affine-shared/services';
|
|||||||
import type { NoteChildrenFlavour } from '@blocksuite/affine-shared/types';
|
import type { NoteChildrenFlavour } from '@blocksuite/affine-shared/types';
|
||||||
import {
|
import {
|
||||||
getImageFilesFromLocal,
|
getImageFilesFromLocal,
|
||||||
openFileOrFiles,
|
openSingleFileWith,
|
||||||
} from '@blocksuite/affine-shared/utils';
|
} from '@blocksuite/affine-shared/utils';
|
||||||
import { EdgelessToolbarToolMixin } from '@blocksuite/affine-widget-edgeless-toolbar';
|
import { EdgelessToolbarToolMixin } from '@blocksuite/affine-widget-edgeless-toolbar';
|
||||||
import { AttachmentIcon, ImageIcon, LinkIcon } from '@blocksuite/icons/lit';
|
import { AttachmentIcon, ImageIcon, LinkIcon } from '@blocksuite/icons/lit';
|
||||||
@@ -139,7 +139,7 @@ export class EdgelessNoteMenu extends EdgelessToolbarToolMixin(LitElement) {
|
|||||||
.activeMode=${'background'}
|
.activeMode=${'background'}
|
||||||
.tooltip=${'File'}
|
.tooltip=${'File'}
|
||||||
@click=${async () => {
|
@click=${async () => {
|
||||||
const file = await openFileOrFiles();
|
const file = await openSingleFileWith();
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
await addAttachments(this.edgeless.std, [file]);
|
await addAttachments(this.edgeless.std, [file]);
|
||||||
this.gfx.tool.setTool(DefaultTool);
|
this.gfx.tool.setTool(DefaultTool);
|
||||||
|
|||||||
@@ -112,21 +112,11 @@ type AcceptTypes =
|
|||||||
| 'Html'
|
| 'Html'
|
||||||
| 'Zip'
|
| 'Zip'
|
||||||
| 'MindMap';
|
| 'MindMap';
|
||||||
export function openFileOrFiles(options?: {
|
|
||||||
acceptType?: AcceptTypes;
|
export async function openFilesWith(
|
||||||
}): Promise<File | null>;
|
acceptType: AcceptTypes = 'Any',
|
||||||
export function openFileOrFiles(options: {
|
multiple: boolean = true
|
||||||
acceptType?: AcceptTypes;
|
): Promise<File[] | null> {
|
||||||
multiple: false;
|
|
||||||
}): Promise<File | null>;
|
|
||||||
export function openFileOrFiles(options: {
|
|
||||||
acceptType?: AcceptTypes;
|
|
||||||
multiple: true;
|
|
||||||
}): Promise<File[] | null>;
|
|
||||||
export async function openFileOrFiles({
|
|
||||||
acceptType = 'Any',
|
|
||||||
multiple = false,
|
|
||||||
} = {}) {
|
|
||||||
// Feature detection. The API needs to be supported
|
// Feature detection. The API needs to be supported
|
||||||
// and the app not run in an iframe.
|
// and the app not run in an iframe.
|
||||||
const supportsFileSystemAccess =
|
const supportsFileSystemAccess =
|
||||||
@@ -138,6 +128,7 @@ export async function openFileOrFiles({
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
// If the File System Access API is supported…
|
// If the File System Access API is supported…
|
||||||
if (supportsFileSystemAccess && window.showOpenFilePicker) {
|
if (supportsFileSystemAccess && window.showOpenFilePicker) {
|
||||||
try {
|
try {
|
||||||
@@ -153,30 +144,14 @@ export async function openFileOrFiles({
|
|||||||
} satisfies OpenFilePickerOptions;
|
} satisfies OpenFilePickerOptions;
|
||||||
// Show the file picker, optionally allowing multiple files.
|
// Show the file picker, optionally allowing multiple files.
|
||||||
const handles = await window.showOpenFilePicker(pickerOpts);
|
const handles = await window.showOpenFilePicker(pickerOpts);
|
||||||
// Only one file is requested.
|
|
||||||
if (!multiple) {
|
return await Promise.all(handles.map(handle => handle.getFile()));
|
||||||
// Add the `FileSystemFileHandle` as `.handle`.
|
|
||||||
const file = await handles[0].getFile();
|
|
||||||
// Add the `FileSystemFileHandle` as `.handle`.
|
|
||||||
// file.handle = handles[0];
|
|
||||||
return file;
|
|
||||||
} else {
|
|
||||||
const files = await Promise.all(
|
|
||||||
handles.map(async handle => {
|
|
||||||
const file = await handle.getFile();
|
|
||||||
// Add the `FileSystemFileHandle` as `.handle`.
|
|
||||||
// file.handle = handles[0];
|
|
||||||
return file;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
return files;
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Error opening file');
|
|
||||||
console.error(err);
|
console.error(err);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback if the File System Access API is not supported.
|
// Fallback if the File System Access API is not supported.
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
// Append a new `<input type="file" multiple? />` and hide it.
|
// Append a new `<input type="file" multiple? />` and hide it.
|
||||||
@@ -184,9 +159,8 @@ export async function openFileOrFiles({
|
|||||||
input.classList.add('affine-upload-input');
|
input.classList.add('affine-upload-input');
|
||||||
input.style.display = 'none';
|
input.style.display = 'none';
|
||||||
input.type = 'file';
|
input.type = 'file';
|
||||||
if (multiple) {
|
input.multiple = multiple;
|
||||||
input.multiple = true;
|
|
||||||
}
|
|
||||||
if (acceptType !== 'Any') {
|
if (acceptType !== 'Any') {
|
||||||
// For example, `accept="image/*"` or `accept="video/*,audio/*"`.
|
// For example, `accept="image/*"` or `accept="video/*,audio/*"`.
|
||||||
input.accept = Object.keys(
|
input.accept = Object.keys(
|
||||||
@@ -198,17 +172,8 @@ export async function openFileOrFiles({
|
|||||||
input.addEventListener('change', () => {
|
input.addEventListener('change', () => {
|
||||||
// Remove the `<input type="file" multiple? />` again from the DOM.
|
// Remove the `<input type="file" multiple? />` again from the DOM.
|
||||||
input.remove();
|
input.remove();
|
||||||
// If no files were selected, return.
|
|
||||||
if (!input.files) {
|
resolve(input.files ? Array.from(input.files) : null);
|
||||||
resolve(null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Return all files or just one file.
|
|
||||||
if (multiple) {
|
|
||||||
resolve(Array.from(input.files));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resolve(input.files[0]);
|
|
||||||
});
|
});
|
||||||
// The `cancel` event fires when the user cancels the dialog.
|
// The `cancel` event fires when the user cancels the dialog.
|
||||||
input.addEventListener('cancel', () => {
|
input.addEventListener('cancel', () => {
|
||||||
@@ -223,11 +188,14 @@ export async function openFileOrFiles({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function openSingleFileWith(
|
||||||
|
acceptType?: AcceptTypes
|
||||||
|
): Promise<File | null> {
|
||||||
|
return openFilesWith(acceptType, false).then(files => files?.at(0) ?? null);
|
||||||
|
}
|
||||||
|
|
||||||
export async function getImageFilesFromLocal() {
|
export async function getImageFilesFromLocal() {
|
||||||
const imageFiles = await openFileOrFiles({
|
const imageFiles = await openFilesWith('Images');
|
||||||
acceptType: 'Images',
|
|
||||||
multiple: true,
|
|
||||||
});
|
|
||||||
if (!imageFiles) return [];
|
if (!imageFiles) return [];
|
||||||
return imageFiles;
|
return imageFiles;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ import { REFERENCE_NODE } from '@blocksuite/affine-shared/consts';
|
|||||||
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
|
import type { AffineTextAttributes } from '@blocksuite/affine-shared/types';
|
||||||
import {
|
import {
|
||||||
createDefaultDoc,
|
createDefaultDoc,
|
||||||
openFileOrFiles,
|
openSingleFileWith,
|
||||||
type Signal,
|
type Signal,
|
||||||
} from '@blocksuite/affine-shared/utils';
|
} from '@blocksuite/affine-shared/utils';
|
||||||
import type { AffineLinkedDocWidget } from '@blocksuite/affine-widget-linked-doc';
|
import type { AffineLinkedDocWidget } from '@blocksuite/affine-widget-linked-doc';
|
||||||
@@ -418,7 +418,7 @@ const contentMediaToolGroup: KeyboardToolPanelGroup = {
|
|||||||
const model = selectedModels?.[0];
|
const model = selectedModels?.[0];
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
const file = await openFileOrFiles();
|
const file = await openSingleFileWith();
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
|
||||||
await addSiblingAttachmentBlocks(std, [file], model);
|
await addSiblingAttachmentBlocks(std, [file], model);
|
||||||
@@ -1040,7 +1040,7 @@ export const defaultKeyboardToolbarConfig: KeyboardToolbarConfig = {
|
|||||||
const model = selectedModels?.[0];
|
const model = selectedModels?.[0];
|
||||||
if (!model) return;
|
if (!model) return;
|
||||||
|
|
||||||
const file = await openFileOrFiles();
|
const file = await openSingleFileWith();
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
|
||||||
await addSiblingAttachmentBlocks(std, [file], model);
|
await addSiblingAttachmentBlocks(std, [file], model);
|
||||||
|
|||||||
@@ -6,7 +6,10 @@ import {
|
|||||||
NewIcon,
|
NewIcon,
|
||||||
NotionIcon,
|
NotionIcon,
|
||||||
} from '@blocksuite/affine-components/icons';
|
} from '@blocksuite/affine-components/icons';
|
||||||
import { openFileOrFiles } from '@blocksuite/affine-shared/utils';
|
import {
|
||||||
|
openFilesWith,
|
||||||
|
openSingleFileWith,
|
||||||
|
} from '@blocksuite/affine-shared/utils';
|
||||||
import { WithDisposable } from '@blocksuite/global/lit';
|
import { WithDisposable } from '@blocksuite/global/lit';
|
||||||
import type { ExtensionType, Schema, Workspace } from '@blocksuite/store';
|
import type { ExtensionType, Schema, Workspace } from '@blocksuite/store';
|
||||||
import { html, LitElement, type PropertyValues } from 'lit';
|
import { html, LitElement, type PropertyValues } from 'lit';
|
||||||
@@ -50,7 +53,7 @@ export class ImportDoc extends WithDisposable(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _importHtml() {
|
private async _importHtml() {
|
||||||
const files = await openFileOrFiles({ acceptType: 'Html', multiple: true });
|
const files = await openFilesWith('Html');
|
||||||
if (!files) return;
|
if (!files) return;
|
||||||
const pageIds: string[] = [];
|
const pageIds: string[] = [];
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
@@ -79,10 +82,7 @@ export class ImportDoc extends WithDisposable(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _importMarkDown() {
|
private async _importMarkDown() {
|
||||||
const files = await openFileOrFiles({
|
const files = await openFilesWith('Markdown');
|
||||||
acceptType: 'Markdown',
|
|
||||||
multiple: true,
|
|
||||||
});
|
|
||||||
if (!files) return;
|
if (!files) return;
|
||||||
const pageIds: string[] = [];
|
const pageIds: string[] = [];
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
@@ -111,7 +111,7 @@ export class ImportDoc extends WithDisposable(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async _importNotion() {
|
private async _importNotion() {
|
||||||
const file = await openFileOrFiles({ acceptType: 'Zip' });
|
const file = await openSingleFileWith('Zip');
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
const needLoading = file.size > SHOW_LOADING_SIZE;
|
const needLoading = file.size > SHOW_LOADING_SIZE;
|
||||||
if (needLoading) {
|
if (needLoading) {
|
||||||
|
|||||||
@@ -41,7 +41,11 @@ import {
|
|||||||
SizeVariables,
|
SizeVariables,
|
||||||
StyleVariables,
|
StyleVariables,
|
||||||
} from '@blocksuite/affine/shared/theme';
|
} from '@blocksuite/affine/shared/theme';
|
||||||
import { openFileOrFiles, printToPdf } from '@blocksuite/affine/shared/utils';
|
import {
|
||||||
|
openFilesWith,
|
||||||
|
openSingleFileWith,
|
||||||
|
printToPdf,
|
||||||
|
} from '@blocksuite/affine/shared/utils';
|
||||||
import { ShadowlessElement } from '@blocksuite/affine/std';
|
import { ShadowlessElement } from '@blocksuite/affine/std';
|
||||||
import { GfxControllerIdentifier } from '@blocksuite/affine/std/gfx';
|
import { GfxControllerIdentifier } from '@blocksuite/affine/std/gfx';
|
||||||
import {
|
import {
|
||||||
@@ -339,10 +343,7 @@ export class StarterDebugMenu extends ShadowlessElement {
|
|||||||
|
|
||||||
private async _importHTML() {
|
private async _importHTML() {
|
||||||
try {
|
try {
|
||||||
const files = await openFileOrFiles({
|
const files = await openFilesWith('Html');
|
||||||
acceptType: 'Html',
|
|
||||||
multiple: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!files) return;
|
if (!files) return;
|
||||||
|
|
||||||
@@ -373,7 +374,7 @@ export class StarterDebugMenu extends ShadowlessElement {
|
|||||||
|
|
||||||
private async _importHTMLZip() {
|
private async _importHTMLZip() {
|
||||||
try {
|
try {
|
||||||
const file = await openFileOrFiles({ acceptType: 'Zip' });
|
const file = await openSingleFileWith('Zip');
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
const result = await HtmlTransformer.importHTMLZip({
|
const result = await HtmlTransformer.importHTMLZip({
|
||||||
collection: this.collection,
|
collection: this.collection,
|
||||||
@@ -393,10 +394,7 @@ export class StarterDebugMenu extends ShadowlessElement {
|
|||||||
|
|
||||||
private async _importMarkdown() {
|
private async _importMarkdown() {
|
||||||
try {
|
try {
|
||||||
const files = await openFileOrFiles({
|
const files = await openFilesWith('Markdown');
|
||||||
acceptType: 'Markdown',
|
|
||||||
multiple: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!files) return;
|
if (!files) return;
|
||||||
|
|
||||||
@@ -427,7 +425,7 @@ export class StarterDebugMenu extends ShadowlessElement {
|
|||||||
|
|
||||||
private async _importMarkdownZip() {
|
private async _importMarkdownZip() {
|
||||||
try {
|
try {
|
||||||
const file = await openFileOrFiles({ acceptType: 'Zip' });
|
const file = await openSingleFileWith('Zip');
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
const result = await MarkdownTransformer.importMarkdownZip({
|
const result = await MarkdownTransformer.importMarkdownZip({
|
||||||
collection: this.collection,
|
collection: this.collection,
|
||||||
@@ -447,10 +445,7 @@ export class StarterDebugMenu extends ShadowlessElement {
|
|||||||
|
|
||||||
private async _importNotionHTML() {
|
private async _importNotionHTML() {
|
||||||
try {
|
try {
|
||||||
const file = await openFileOrFiles({
|
const file = await openSingleFileWith('Html');
|
||||||
acceptType: 'Html',
|
|
||||||
multiple: false,
|
|
||||||
});
|
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
const doc = this.editor.doc;
|
const doc = this.editor.doc;
|
||||||
const job = doc.getTransformer([defaultImageProxyMiddleware]);
|
const job = doc.getTransformer([defaultImageProxyMiddleware]);
|
||||||
@@ -467,7 +462,7 @@ export class StarterDebugMenu extends ShadowlessElement {
|
|||||||
|
|
||||||
private async _importNotionHTMLZip() {
|
private async _importNotionHTMLZip() {
|
||||||
try {
|
try {
|
||||||
const file = await openFileOrFiles({ acceptType: 'Zip' });
|
const file = await openSingleFileWith('Zip');
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
const result = await NotionHtmlTransformer.importNotionZip({
|
const result = await NotionHtmlTransformer.importNotionZip({
|
||||||
collection: this.collection,
|
collection: this.collection,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import track from '@affine/track';
|
|||||||
import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/lit';
|
import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/lit';
|
||||||
import { scrollbarStyle } from '@blocksuite/affine/shared/styles';
|
import { scrollbarStyle } from '@blocksuite/affine/shared/styles';
|
||||||
import { unsafeCSSVar, unsafeCSSVarV2 } from '@blocksuite/affine/shared/theme';
|
import { unsafeCSSVar, unsafeCSSVarV2 } from '@blocksuite/affine/shared/theme';
|
||||||
import { openFileOrFiles } from '@blocksuite/affine/shared/utils';
|
import { openFilesWith } from '@blocksuite/affine/shared/utils';
|
||||||
import { ShadowlessElement } from '@blocksuite/affine/std';
|
import { ShadowlessElement } from '@blocksuite/affine/std';
|
||||||
import type { DocMeta } from '@blocksuite/affine/store';
|
import type { DocMeta } from '@blocksuite/affine/store';
|
||||||
import {
|
import {
|
||||||
@@ -159,9 +159,7 @@ export class ChatPanelAddPopover extends SignalWatcher(
|
|||||||
};
|
};
|
||||||
|
|
||||||
private readonly _addFileChip = async () => {
|
private readonly _addFileChip = async () => {
|
||||||
const files = await openFileOrFiles({
|
const files = await openFilesWith();
|
||||||
multiple: true,
|
|
||||||
});
|
|
||||||
if (!files || files.length === 0) return;
|
if (!files || files.length === 0) return;
|
||||||
|
|
||||||
const images = files.filter(file => file.type.startsWith('image/'));
|
const images = files.filter(file => file.type.startsWith('image/'));
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { stopPropagation } from '@affine/core/utils';
|
|||||||
import type { CopilotSessionType } from '@affine/graphql';
|
import type { CopilotSessionType } from '@affine/graphql';
|
||||||
import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/lit';
|
import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/lit';
|
||||||
import { unsafeCSSVar, unsafeCSSVarV2 } from '@blocksuite/affine/shared/theme';
|
import { unsafeCSSVar, unsafeCSSVarV2 } from '@blocksuite/affine/shared/theme';
|
||||||
import { openFileOrFiles } from '@blocksuite/affine/shared/utils';
|
import { openFilesWith } from '@blocksuite/affine/shared/utils';
|
||||||
import type { EditorHost } from '@blocksuite/affine/std';
|
import type { EditorHost } from '@blocksuite/affine/std';
|
||||||
import {
|
import {
|
||||||
CloseIcon,
|
CloseIcon,
|
||||||
@@ -533,10 +533,7 @@ export class AIChatInput extends SignalWatcher(WithDisposable(LitElement)) {
|
|||||||
private readonly _uploadImageFiles = async (_e: MouseEvent) => {
|
private readonly _uploadImageFiles = async (_e: MouseEvent) => {
|
||||||
if (this._isImageUploadDisabled) return;
|
if (this._isImageUploadDisabled) return;
|
||||||
|
|
||||||
const images = await openFileOrFiles({
|
const images = await openFilesWith('Images');
|
||||||
acceptType: 'Images',
|
|
||||||
multiple: true,
|
|
||||||
});
|
|
||||||
if (!images) return;
|
if (!images) return;
|
||||||
if (this.chatContextValue.images.length + images.length > MAX_IMAGE_COUNT) {
|
if (this.chatContextValue.images.length + images.length > MAX_IMAGE_COUNT) {
|
||||||
toast(`You can only upload up to ${MAX_IMAGE_COUNT} images`);
|
toast(`You can only upload up to ${MAX_IMAGE_COUNT} images`);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
type DataViewCellLifeCycle,
|
type DataViewCellLifeCycle,
|
||||||
EditorHostKey,
|
EditorHostKey,
|
||||||
} from '@blocksuite/affine/blocks/database';
|
} from '@blocksuite/affine/blocks/database';
|
||||||
import { openFileOrFiles } from '@blocksuite/affine/shared/utils';
|
import { openFilesWith } from '@blocksuite/affine/shared/utils';
|
||||||
import type { BlobEngine } from '@blocksuite/affine/sync';
|
import type { BlobEngine } from '@blocksuite/affine/sync';
|
||||||
import {
|
import {
|
||||||
DeleteIcon,
|
DeleteIcon,
|
||||||
@@ -402,7 +402,7 @@ const FileCellComponent: ForwardRefRenderFunction<
|
|||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
openFileOrFiles({ multiple: true })
|
openFilesWith()
|
||||||
.then(files => {
|
.then(files => {
|
||||||
files?.forEach(file => {
|
files?.forEach(file => {
|
||||||
manager.uploadFile(file);
|
manager.uploadFile(file);
|
||||||
@@ -447,7 +447,7 @@ const FileCellComponent: ForwardRefRenderFunction<
|
|||||||
<div className={styles.uploadContainer}>
|
<div className={styles.uploadContainer}>
|
||||||
<div
|
<div
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
openFileOrFiles({ multiple: true })
|
openFilesWith()
|
||||||
.then(files => {
|
.then(files => {
|
||||||
files?.forEach(file => {
|
files?.forEach(file => {
|
||||||
manager.uploadFile(file);
|
manager.uploadFile(file);
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
import { DebugLogger } from '@affine/debug';
|
import { DebugLogger } from '@affine/debug';
|
||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
import track from '@affine/track';
|
import track from '@affine/track';
|
||||||
import { openFileOrFiles } from '@blocksuite/affine/shared/utils';
|
import { openFilesWith } from '@blocksuite/affine/shared/utils';
|
||||||
import type { Workspace } from '@blocksuite/affine/store';
|
import type { Workspace } from '@blocksuite/affine/store';
|
||||||
import {
|
import {
|
||||||
HtmlTransformer,
|
HtmlTransformer,
|
||||||
@@ -56,7 +56,7 @@ type ImportConfig = {
|
|||||||
fileOptions: { acceptType: AcceptType; multiple: boolean };
|
fileOptions: { acceptType: AcceptType; multiple: boolean };
|
||||||
importFunction: (
|
importFunction: (
|
||||||
docCollection: Workspace,
|
docCollection: Workspace,
|
||||||
file: File | File[]
|
files: File[]
|
||||||
) => Promise<ImportResult>;
|
) => Promise<ImportResult>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -134,9 +134,6 @@ const importConfigs: Record<ImportType, ImportConfig> = {
|
|||||||
markdown: {
|
markdown: {
|
||||||
fileOptions: { acceptType: 'Markdown', multiple: true },
|
fileOptions: { acceptType: 'Markdown', multiple: true },
|
||||||
importFunction: async (docCollection, files) => {
|
importFunction: async (docCollection, files) => {
|
||||||
if (!Array.isArray(files)) {
|
|
||||||
throw new Error('Expected an array of files for markdown files import');
|
|
||||||
}
|
|
||||||
const docIds: string[] = [];
|
const docIds: string[] = [];
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
const text = await file.text();
|
const text = await file.text();
|
||||||
@@ -157,8 +154,9 @@ const importConfigs: Record<ImportType, ImportConfig> = {
|
|||||||
},
|
},
|
||||||
markdownZip: {
|
markdownZip: {
|
||||||
fileOptions: { acceptType: 'Zip', multiple: false },
|
fileOptions: { acceptType: 'Zip', multiple: false },
|
||||||
importFunction: async (docCollection, file) => {
|
importFunction: async (docCollection, files) => {
|
||||||
if (Array.isArray(file)) {
|
const file = files.length === 1 ? files[0] : null;
|
||||||
|
if (!file) {
|
||||||
throw new Error('Expected a single zip file for markdownZip import');
|
throw new Error('Expected a single zip file for markdownZip import');
|
||||||
}
|
}
|
||||||
const docIds = await MarkdownTransformer.importMarkdownZip({
|
const docIds = await MarkdownTransformer.importMarkdownZip({
|
||||||
@@ -175,9 +173,6 @@ const importConfigs: Record<ImportType, ImportConfig> = {
|
|||||||
html: {
|
html: {
|
||||||
fileOptions: { acceptType: 'Html', multiple: true },
|
fileOptions: { acceptType: 'Html', multiple: true },
|
||||||
importFunction: async (docCollection, files) => {
|
importFunction: async (docCollection, files) => {
|
||||||
if (!Array.isArray(files)) {
|
|
||||||
throw new Error('Expected an array of files for html files import');
|
|
||||||
}
|
|
||||||
const docIds: string[] = [];
|
const docIds: string[] = [];
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
const text = await file.text();
|
const text = await file.text();
|
||||||
@@ -198,8 +193,9 @@ const importConfigs: Record<ImportType, ImportConfig> = {
|
|||||||
},
|
},
|
||||||
notion: {
|
notion: {
|
||||||
fileOptions: { acceptType: 'Zip', multiple: false },
|
fileOptions: { acceptType: 'Zip', multiple: false },
|
||||||
importFunction: async (docCollection, file) => {
|
importFunction: async (docCollection, files) => {
|
||||||
if (Array.isArray(file)) {
|
const file = files.length === 1 ? files[0] : null;
|
||||||
|
if (!file) {
|
||||||
throw new Error('Expected a single zip file for notion import');
|
throw new Error('Expected a single zip file for notion import');
|
||||||
}
|
}
|
||||||
const { entryId, pageIds, isWorkspaceFile } =
|
const { entryId, pageIds, isWorkspaceFile } =
|
||||||
@@ -218,8 +214,9 @@ const importConfigs: Record<ImportType, ImportConfig> = {
|
|||||||
},
|
},
|
||||||
snapshot: {
|
snapshot: {
|
||||||
fileOptions: { acceptType: 'Zip', multiple: false },
|
fileOptions: { acceptType: 'Zip', multiple: false },
|
||||||
importFunction: async (docCollection, file) => {
|
importFunction: async (docCollection, files) => {
|
||||||
if (Array.isArray(file)) {
|
const file = files.length === 1 ? files[0] : null;
|
||||||
|
if (!file) {
|
||||||
throw new Error('Expected a single zip file for snapshot import');
|
throw new Error('Expected a single zip file for snapshot import');
|
||||||
}
|
}
|
||||||
const docIds = (
|
const docIds = (
|
||||||
@@ -412,9 +409,10 @@ export const ImportDialog = ({
|
|||||||
setImportError(null);
|
setImportError(null);
|
||||||
try {
|
try {
|
||||||
const importConfig = importConfigs[type];
|
const importConfig = importConfigs[type];
|
||||||
const file = await openFileOrFiles(importConfig.fileOptions);
|
const { acceptType, multiple } = importConfig.fileOptions;
|
||||||
|
const files = await openFilesWith(acceptType, multiple);
|
||||||
|
|
||||||
if (!file || (Array.isArray(file) && file.length === 0)) {
|
if (!files || files.length === 0) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
t['com.affine.import.status.failed.message.no-file-selected']()
|
t['com.affine.import.status.failed.message.no-file-selected']()
|
||||||
);
|
);
|
||||||
@@ -427,7 +425,7 @@ export const ImportDialog = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const { docIds, entryId, isWorkspaceFile } =
|
const { docIds, entryId, isWorkspaceFile } =
|
||||||
await importConfig.importFunction(docCollection, file);
|
await importConfig.importFunction(docCollection, files);
|
||||||
|
|
||||||
setImportResult({ docIds, entryId, isWorkspaceFile });
|
setImportResult({ docIds, entryId, isWorkspaceFile });
|
||||||
setStatus('success');
|
setStatus('success');
|
||||||
|
|||||||
Reference in New Issue
Block a user