mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-11-04 15:11:31 +08:00 
			
		
		
		
	allow import of multiple files at the same time
This commit is contained in:
		
							parent
							
								
									936f85c09e
								
							
						
					
					
						commit
						886ea6c68c
					
				@ -43,22 +43,27 @@ $form.submit(() => {
 | 
				
			|||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function importIntoNote(importNoteId) {
 | 
					async function importIntoNote(importNoteId) {
 | 
				
			||||||
    const formData = new FormData();
 | 
					    const files = Array.from($fileUploadInput[0].files); // shallow copy since we're resetting the upload button below
 | 
				
			||||||
    formData.append('upload', $fileUploadInput[0].files[0]);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // we generate it here (and not on opening) for the case when you try to import multiple times from the same
 | 
					    // we generate it here (and not on opening) for the case when you try to import multiple times from the same
 | 
				
			||||||
    // dialog (which shouldn't happen, but still ...)
 | 
					    // dialog (which shouldn't happen, but still ...)
 | 
				
			||||||
    importId = utils.randomString(10);
 | 
					    importId = utils.randomString(10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const safeImport = $safeImport.is(":checked") ? 1 : 0;
 | 
					    const safeImport = $safeImport.is(":checked") ? 1 : 0;
 | 
				
			||||||
 | 
					    let noteId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    $.ajax({
 | 
					    for (const file of files) {
 | 
				
			||||||
 | 
					        const formData = new FormData();
 | 
				
			||||||
 | 
					        formData.append('upload', file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        noteId = await $.ajax({
 | 
				
			||||||
            url: baseApiUrl + 'notes/' + importNoteId + '/import/' + importId + '/safe/' + safeImport,
 | 
					            url: baseApiUrl + 'notes/' + importNoteId + '/import/' + importId + '/safe/' + safeImport,
 | 
				
			||||||
            headers: server.getHeaders(),
 | 
					            headers: server.getHeaders(),
 | 
				
			||||||
            data: formData,
 | 
					            data: formData,
 | 
				
			||||||
            dataType: 'json',
 | 
					            dataType: 'json',
 | 
				
			||||||
            type: 'POST',
 | 
					            type: 'POST',
 | 
				
			||||||
 | 
					            timeout: 60 * 60 * 1000,
 | 
				
			||||||
            contentType: false, // NEEDED, DON'T REMOVE THIS
 | 
					            contentType: false, // NEEDED, DON'T REMOVE THIS
 | 
				
			||||||
            processData: false, // NEEDED, DON'T REMOVE THIS
 | 
					            processData: false, // NEEDED, DON'T REMOVE THIS
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
@ -66,6 +71,19 @@ function importIntoNote(importNoteId) {
 | 
				
			|||||||
            .fail((xhr, status, error) => {});
 | 
					            .fail((xhr, status, error) => {});
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $dialog.modal('hide');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    infoService.showMessage("Import finished successfully.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await treeService.reload();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (noteId) {
 | 
				
			||||||
 | 
					        const node = await treeService.activateNote(noteId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        node.setExpanded(true);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
messagingService.subscribeToMessages(async message => {
 | 
					messagingService.subscribeToMessages(async message => {
 | 
				
			||||||
    if (message.type === 'import-error') {
 | 
					    if (message.type === 'import-error') {
 | 
				
			||||||
        infoService.showError(message.message);
 | 
					        infoService.showError(message.message);
 | 
				
			||||||
@ -83,19 +101,6 @@ messagingService.subscribeToMessages(async message => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        $importProgressCount.text(message.progressCount);
 | 
					        $importProgressCount.text(message.progressCount);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else if (message.type === 'import-finished') {
 | 
					 | 
				
			||||||
        $dialog.modal('hide');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        infoService.showMessage("Import finished successfully.");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        await treeService.reload();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (message.noteId) {
 | 
					 | 
				
			||||||
            const node = await treeService.activateNote(message.noteId);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            node.setExpanded(true);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$fileUploadInput.change(() => {
 | 
					$fileUploadInput.change(() => {
 | 
				
			||||||
 | 
				
			|||||||
@ -36,7 +36,7 @@ async function importToBranch(req) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    let note; // typically root of the import - client can show it after finishing the import
 | 
					    let note; // typically root of the import - client can show it after finishing the import
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const importContext = new ImportContext(importId, safeImport);
 | 
					    const importContext = ImportContext.getInstance(importId, safeImport);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
        if (extension === '.tar') {
 | 
					        if (extension === '.tar') {
 | 
				
			||||||
 | 
				
			|||||||
@ -298,12 +298,7 @@ async function importEnex(importContext, file, parentNote) {
 | 
				
			|||||||
    return new Promise((resolve, reject) =>
 | 
					    return new Promise((resolve, reject) =>
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        // resolve only when we parse the whole document AND saving of all notes have been finished
 | 
					        // resolve only when we parse the whole document AND saving of all notes have been finished
 | 
				
			||||||
        saxStream.on("end", () => { Promise.all(saveNotePromises).then(() => {
 | 
					        saxStream.on("end", () => { Promise.all(saveNotePromises).then(() => resolve(rootNote)) });
 | 
				
			||||||
                importContext.importFinished(rootNote.noteId);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                resolve(rootNote);
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const bufferStream = new stream.PassThrough();
 | 
					        const bufferStream = new stream.PassThrough();
 | 
				
			||||||
        bufferStream.end(file.buffer);
 | 
					        bufferStream.end(file.buffer);
 | 
				
			||||||
 | 
				
			|||||||
@ -64,8 +64,6 @@ async function importOpml(importContext, fileBuffer, parentNote) {
 | 
				
			|||||||
        returnNote = returnNote || note;
 | 
					        returnNote = returnNote || note;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    importContext.importFinished(returnNote.noteId);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return returnNote;
 | 
					    return returnNote;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -21,7 +21,6 @@ async function importMarkdown(importContext, file, parentNote) {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    importContext.increaseProgressCount();
 | 
					    importContext.increaseProgressCount();
 | 
				
			||||||
    importContext.importFinished(note.noteId);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return note;
 | 
					    return note;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -36,7 +35,6 @@ async function importHtml(importContext, file, parentNote) {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    importContext.increaseProgressCount();
 | 
					    importContext.increaseProgressCount();
 | 
				
			||||||
    importContext.importFinished(note.noteId);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return note;
 | 
					    return note;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -386,8 +386,6 @@ async function importTar(importContext, fileBuffer, importRootNote) {
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            importContext.importFinished();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            resolve(firstNote);
 | 
					            resolve(firstNote);
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const messagingService = require('./messaging');
 | 
					const messagingService = require('./messaging');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// importId => ImportContext
 | 
				
			||||||
 | 
					const importContexts = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ImportContext {
 | 
					class ImportContext {
 | 
				
			||||||
    constructor(importId, safeImport) {
 | 
					    constructor(importId, safeImport) {
 | 
				
			||||||
        // importId is to distinguish between different import events - it is possible (though not recommended)
 | 
					        // importId is to distinguish between different import events - it is possible (though not recommended)
 | 
				
			||||||
@ -15,6 +18,15 @@ class ImportContext {
 | 
				
			|||||||
        this.lastSentCountTs = Date.now();
 | 
					        this.lastSentCountTs = Date.now();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** @return {ImportContext} */
 | 
				
			||||||
 | 
					    static getInstance(importId, safeImport) {
 | 
				
			||||||
 | 
					        if (!importContexts[importId]) {
 | 
				
			||||||
 | 
					            importContexts[importId] = new ImportContext(importId, safeImport);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return importContexts[importId];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async increaseProgressCount() {
 | 
					    async increaseProgressCount() {
 | 
				
			||||||
        this.progressCount++;
 | 
					        this.progressCount++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -29,14 +41,6 @@ class ImportContext {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async importFinished(noteId) {
 | 
					 | 
				
			||||||
        await messagingService.sendMessageToAllClients({
 | 
					 | 
				
			||||||
            importId: this.importId,
 | 
					 | 
				
			||||||
            type: 'import-finished',
 | 
					 | 
				
			||||||
            noteId: noteId
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // must remaing non-static
 | 
					    // must remaing non-static
 | 
				
			||||||
    async reportError(message) {
 | 
					    async reportError(message) {
 | 
				
			||||||
        await messagingService.sendMessageToAllClients({
 | 
					        await messagingService.sendMessageToAllClients({
 | 
				
			||||||
 | 
				
			|||||||
@ -16,7 +16,7 @@
 | 
				
			|||||||
                    <div class="form-group">
 | 
					                    <div class="form-group">
 | 
				
			||||||
                        <label for="import-file-upload-input"><strong>Choose import file</strong></label>
 | 
					                        <label for="import-file-upload-input"><strong>Choose import file</strong></label>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        <input type="file" id="import-file-upload-input" class="form-control-file" />
 | 
					                        <input type="file" id="import-file-upload-input" class="form-control-file" multiple />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        <p>Content of the file will be imported as child note(s) into <strong class="note-title"></strong>. Import file must be of supported type and have correct extension - one of <code>.html</code>, <code>.md</code>, <code>.tar</code>, <code>.enex</code>.</p>
 | 
					                        <p>Content of the file will be imported as child note(s) into <strong class="note-title"></strong>. Import file must be of supported type and have correct extension - one of <code>.html</code>, <code>.md</code>, <code>.tar</code>, <code>.enex</code>.</p>
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user