mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
allow import of multiple files at the same time
This commit is contained in:
parent
936f85c09e
commit
886ea6c68c
@ -43,27 +43,45 @@ $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) {
|
||||||
url: baseApiUrl + 'notes/' + importNoteId + '/import/' + importId + '/safe/' + safeImport,
|
const formData = new FormData();
|
||||||
headers: server.getHeaders(),
|
formData.append('upload', file);
|
||||||
data: formData,
|
|
||||||
dataType: 'json',
|
noteId = await $.ajax({
|
||||||
type: 'POST',
|
url: baseApiUrl + 'notes/' + importNoteId + '/import/' + importId + '/safe/' + safeImport,
|
||||||
contentType: false, // NEEDED, DON'T REMOVE THIS
|
headers: server.getHeaders(),
|
||||||
processData: false, // NEEDED, DON'T REMOVE THIS
|
data: formData,
|
||||||
})
|
dataType: 'json',
|
||||||
|
type: 'POST',
|
||||||
|
timeout: 60 * 60 * 1000,
|
||||||
|
contentType: false, // NEEDED, DON'T REMOVE THIS
|
||||||
|
processData: false, // NEEDED, DON'T REMOVE THIS
|
||||||
|
})
|
||||||
// we actually ignore the error since it can be caused by HTTP timeout and use WS messages instead.
|
// we actually ignore the error since it can be caused by HTTP timeout and use WS messages instead.
|
||||||
.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 => {
|
||||||
@ -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