fix: Fixed issue where non-image inlined files would not correctly be imported from a Markdown file

This commit is contained in:
Aman Harwara
2023-11-07 12:11:21 +05:30
parent a1317b2bfd
commit 894167520d
5 changed files with 46 additions and 7 deletions

View File

@@ -164,6 +164,10 @@ export class Importer {
return this.mutator.insertItem(note) return this.mutator.insertItem(note)
}), }),
) )
return insertedItems
}
async uploadAndReplaceInlineFilesInInsertedItems(insertedItems: DecryptedItemInterface<ItemContent>[]) {
for (const item of insertedItems) { for (const item of insertedItems) {
if (!isNote(item)) { if (!isNote(item)) {
continue continue
@@ -185,6 +189,5 @@ export class Importer {
console.error(error) console.error(error)
} }
} }
return insertedItems
} }
} }

View File

@@ -21,6 +21,7 @@ export type ImportModalFile = (
| { status: 'ready'; payloads?: DecryptedTransferPayload[] } | { status: 'ready'; payloads?: DecryptedTransferPayload[] }
| { status: 'parsing' } | { status: 'parsing' }
| { status: 'importing' } | { status: 'importing' }
| { status: 'uploading-files' }
| { status: 'success'; successMessage: string } | { status: 'success'; successMessage: string }
| { status: 'error'; error: Error } | { status: 'error'; error: Error }
) & ) &
@@ -105,7 +106,14 @@ export class ImportModalController {
}) })
try { try {
await this.importer.importFromTransferPayloads(payloads) const insertedItems = await this.importer.importFromTransferPayloads(payloads)
this.updateFile({
...file,
status: 'uploading-files',
})
await this.importer.uploadAndReplaceInlineFilesInInsertedItems(insertedItems)
const notesImported = payloads.filter((payload) => payload.content_type === ContentType.TYPES.Note) const notesImported = payloads.filter((payload) => payload.content_type === ContentType.TYPES.Note)
const tagsImported = payloads.filter((payload) => payload.content_type === ContentType.TYPES.Tag) const tagsImported = payloads.filter((payload) => payload.content_type === ContentType.TYPES.Tag)

View File

@@ -103,6 +103,7 @@ const ImportModalFileItem = ({
{file.status === 'pending' && 'Could not auto-detect service. Please select manually.'} {file.status === 'pending' && 'Could not auto-detect service. Please select manually.'}
{file.status === 'parsing' && 'Parsing...'} {file.status === 'parsing' && 'Parsing...'}
{file.status === 'importing' && 'Importing...'} {file.status === 'importing' && 'Importing...'}
{file.status === 'uploading-files' && 'Uploading and embedding files...'}
{file.status === 'error' && JSON.stringify(file.error)} {file.status === 'error' && JSON.stringify(file.error)}
{file.status === 'success' && file.successMessage} {file.status === 'success' && file.successMessage}
</div> </div>

View File

@@ -31,6 +31,7 @@ import {
$isRemoteImageNode, $isRemoteImageNode,
RemoteImageNode, RemoteImageNode,
} from './Plugins/RemoteImagePlugin/RemoteImageNode' } from './Plugins/RemoteImagePlugin/RemoteImageNode'
import { $createInlineFileNode, $isInlineFileNode, InlineFileNode } from './Plugins/InlineFilePlugin/InlineFileNode'
const HorizontalRule: ElementTransformer = { const HorizontalRule: ElementTransformer = {
dependencies: [HorizontalRuleNode], dependencies: [HorizontalRuleNode],
@@ -72,6 +73,26 @@ const IMAGE: TextMatchTransformer = {
type: 'text-match', type: 'text-match',
} }
const INLINE_FILE: TextMatchTransformer = {
dependencies: [InlineFileNode],
export: (node) => {
if (!$isInlineFileNode(node)) {
return null
}
return node.getTextContent()
},
importRegExp: /(?:\[([^[]*)\])(?:\((data:(.*);[^(]+)\))/,
regExp: /(?:\[([^[]*)\])(?:\((data:(.*);[^(]+)\))$/,
replace: (textNode, match) => {
const [, name, src, mimeType] = match
const inlineFileNode = $createInlineFileNode(src, mimeType, name)
textNode.replace(inlineFileNode)
},
trigger: ')',
type: 'text-match',
}
// Table transformer, taken from Lexical Playground // Table transformer, taken from Lexical Playground
const TABLE_ROW_REG_EXP = /^(?:\|)(.+)(?:\|)\s?$/ const TABLE_ROW_REG_EXP = /^(?:\|)(.+)(?:\|)\s?$/
const TABLE_ROW_DIVIDER_REG_EXP = /^(\| ?:?-*:? ?)+\|\s?$/ const TABLE_ROW_DIVIDER_REG_EXP = /^(\| ?:?-*:? ?)+\|\s?$/
@@ -224,6 +245,7 @@ export const MarkdownTransformers = [
TABLE, TABLE,
CHECK_LIST, CHECK_LIST,
IMAGE, IMAGE,
INLINE_FILE,
...ELEMENT_TRANSFORMERS, ...ELEMENT_TRANSFORMERS,
...TEXT_FORMAT_TRANSFORMERS, ...TEXT_FORMAT_TRANSFORMERS,
...TEXT_MATCH_TRANSFORMERS, ...TEXT_MATCH_TRANSFORMERS,

View File

@@ -16,8 +16,9 @@ import { MarkdownTransformers } from '../MarkdownTransformers'
import { $generateHtmlFromNodes, $generateNodesFromDOM } from '@lexical/html' import { $generateHtmlFromNodes, $generateNodesFromDOM } from '@lexical/html'
import { FileNode } from '../Plugins/EncryptedFilePlugin/Nodes/FileNode' import { FileNode } from '../Plugins/EncryptedFilePlugin/Nodes/FileNode'
import { $createFileExportNode } from '../Lexical/Nodes/FileExportNode' import { $createFileExportNode } from '../Lexical/Nodes/FileExportNode'
import { $createInlineFileNode, InlineFileNode } from '../Plugins/InlineFilePlugin/InlineFileNode' import { $createInlineFileNode, $isInlineFileNode, InlineFileNode } from '../Plugins/InlineFilePlugin/InlineFileNode'
import { $createFileNode } from '../Plugins/EncryptedFilePlugin/Nodes/FileUtils' import { $createFileNode } from '../Plugins/EncryptedFilePlugin/Nodes/FileUtils'
import { RemoteImageNode } from '../Plugins/RemoteImagePlugin/RemoteImageNode'
export class HeadlessSuperConverter implements SuperConverterServiceInterface { export class HeadlessSuperConverter implements SuperConverterServiceInterface {
private importEditor: LexicalEditor private importEditor: LexicalEditor
private exportEditor: LexicalEditor private exportEditor: LexicalEditor
@@ -271,15 +272,19 @@ export class HeadlessSuperConverter implements SuperConverterServiceInterface {
this.importEditor.update( this.importEditor.update(
() => { () => {
const inlineFileNodes = $nodesOfType(InlineFileNode) const inlineFileNodes = $nodesOfType(InlineFileNode)
if (inlineFileNodes.length === 0) { const remoteImageNodes = $nodesOfType(RemoteImageNode).filter((node) => node.__src.startsWith('data:'))
const concatenatedNodes = [...inlineFileNodes, ...remoteImageNodes]
if (concatenatedNodes.length === 0) {
resolve() resolve()
return return
} }
Promise.all( Promise.all(
inlineFileNodes.map(async (node) => { concatenatedNodes.map(async (node) => {
const blob = await fetch(node.__src).then((response) => response.blob()) const blob = await fetch(node.__src).then((response) => response.blob())
const file = new File([blob], node.__fileName || generateUuid.execute().getValue(), { const name = $isInlineFileNode(node) ? node.__fileName : node.__alt
type: node.__mimeType, const mimeType = $isInlineFileNode(node) ? node.__mimeType : node.__src.split(';')[0].split(':')[1]
const file = new File([blob], name || generateUuid.execute().getValue(), {
type: mimeType,
}) })
const uploadedFile = await uploadFile(file) const uploadedFile = await uploadFile(file)