feat(core): add clipper import interface (#10619)

This commit is contained in:
EYHN
2025-03-05 04:22:02 +00:00
parent 4daa763c95
commit 61635aa77a
11 changed files with 373 additions and 25 deletions

View File

@@ -0,0 +1,10 @@
import { type Framework } from '@toeverything/infra';
import { WorkspacesService } from '../workspace';
import { ImportClipperService } from './services/import';
export { type ClipperInput, ImportClipperService } from './services/import';
export function configureImportClipperModule(framework: Framework) {
framework.service(ImportClipperService, [WorkspacesService]);
}

View File

@@ -0,0 +1,76 @@
import { MarkdownTransformer } from '@blocksuite/affine/blocks';
import { Service } from '@toeverything/infra';
import { DocsService } from '../../doc';
import {
getAFFiNEWorkspaceSchema,
type WorkspaceMetadata,
type WorkspacesService,
} from '../../workspace';
export interface ClipperInput {
title: string;
contentMarkdown: string;
contentHtml: string;
attachments: Record<string, Blob>;
}
export class ImportClipperService extends Service {
constructor(private readonly workspacesService: WorkspacesService) {
super();
}
async importToWorkspace(
workspaceMetadata: WorkspaceMetadata,
clipperInput: ClipperInput
) {
const { workspace, dispose: disposeWorkspace } =
this.workspacesService.open({
metadata: workspaceMetadata,
});
await workspace.engine.doc.waitForDocReady(workspace.id); // wait for root doc ready
const docId = await MarkdownTransformer.importMarkdownToDoc({
collection: workspace.docCollection,
schema: getAFFiNEWorkspaceSchema(),
markdown: clipperInput.contentMarkdown,
});
const docsService = workspace.scope.get(DocsService);
if (docId) {
// only support page mode for now
docsService.list.setPrimaryMode(docId, 'page');
workspace.engine.doc.addPriority(workspace.id, 100);
workspace.engine.doc.addPriority(docId, 100);
await workspace.engine.doc.waitForDocSynced(workspace.id);
await workspace.engine.doc.waitForDocSynced(docId);
disposeWorkspace();
return docId;
} else {
throw new Error('Failed to import doc');
}
}
async importToNewWorkspace(
flavour: string,
workspaceName: string,
clipperInput: ClipperInput
) {
// oxlint-disable-next-line @typescript-eslint/no-non-null-assertion
let docId: string | undefined;
const { id: workspaceId } = await this.workspacesService.create(
flavour,
async docCollection => {
docCollection.meta.initialize();
docCollection.meta.setName(workspaceName);
docId = await MarkdownTransformer.importMarkdownToDoc({
collection: docCollection,
schema: getAFFiNEWorkspaceSchema(),
markdown: clipperInput.contentMarkdown,
});
}
);
if (!docId) {
throw new Error('Failed to import doc');
}
return { workspaceId, docId };
}
}

View File

@@ -1,22 +0,0 @@
import type { DocMode } from '@blocksuite/affine/blocks';
import { Entity, LiveData } from '@toeverything/infra';
interface TemplateOptions {
templateName: string;
snapshotUrl: string;
templateMode: DocMode;
}
export class ImportTemplateDialog extends Entity {
readonly isOpen$ = new LiveData(false);
readonly template$ = new LiveData<TemplateOptions | null>(null);
open(options: TemplateOptions) {
this.template$.next(options);
this.isOpen$.next(true);
}
close() {
this.isOpen$.next(false);
}
}

View File

@@ -1,7 +1,6 @@
import { type Framework } from '@toeverything/infra';
import { WorkspacesService } from '../workspace';
import { ImportTemplateDialog } from './entities/dialog';
import { TemplateDownloader } from './entities/downloader';
import { TemplateDownloaderService } from './services/downloader';
import { ImportTemplateService } from './services/import';
@@ -12,7 +11,6 @@ export { ImportTemplateService } from './services/import';
export function configureImportTemplateModule(framework: Framework) {
framework
.entity(ImportTemplateDialog)
.service(TemplateDownloaderService)
.entity(TemplateDownloader, [TemplateDownloaderStore])
.store(TemplateDownloaderStore)

View File

@@ -26,6 +26,7 @@ import { configureFavoriteModule } from './favorite';
import { configureFeatureFlagModule } from './feature-flag';
import { configureGlobalContextModule } from './global-context';
import { configureI18nModule } from './i18n';
import { configureImportClipperModule } from './import-clipper';
import { configureImportTemplateModule } from './import-template';
import { configureJournalModule } from './journal';
import { configureLifecycleModule } from './lifecycle';
@@ -100,4 +101,5 @@ export function configureCommonModules(framework: Framework) {
configureAIButtonModule(framework);
configureTemplateDocModule(framework);
configureBlobManagementModule(framework);
configureImportClipperModule(framework);
}