mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-10-31 21:11:30 +08: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
	 zadam
						zadam