diff --git a/imports/dashboard/files/fileManager.tsx b/imports/dashboard/files/fileManager.tsx index 254bcac..383dec6 100644 --- a/imports/dashboard/files/fileManager.tsx +++ b/imports/dashboard/files/fileManager.tsx @@ -218,8 +218,38 @@ const FileManager = (props: { setFetching(false) } } - const handleFilesDelete = (): void => { + const handleFilesDelete = async (): Promise => { setMassActionMenuOpen(null) + setOverlay(`Deleting ${filesSelected.length} files.`) + try { + const operations = filesSelected.map(file => ({ operation: 'rm', path: path + file })) + const res = await ky.patch(`server/${server}/files?path=..`, { json: { operations } }) + if (res.ok) { + setMessage('Deleted all files successfully!') + setOverlay('') + fetchFiles() + return + } else if (res.status !== 404) { + const errors = await res.json<{ errors?: Array<{ index: number, message: string }> }>() + if (errors.errors?.length === 1) { + setMessage(`Error deleting files: ${errors.errors[0].message}`) + setOverlay('') + } else { + setMessage('Critical error deleting files: Check browser console for info!') + setOverlay('') + fetchFiles() + console.error(errors.errors) + } + return + } + } catch (e) { + setMessage(`Error deleting files: ${e}`) + setOverlay('') + fetchFiles() + return + } + + // Fallback to non-transactional API let total = filesSelected.length setOverlay({ text: `Deleting ${total} out of ${filesSelected.length} files.`, progress: 0 }) const ops = [] @@ -532,7 +562,7 @@ const FileManager = (props: { setMassActionMenuOpen(null)}> setMassActionDialogOpen('move')} disabled={!!overlay}>Move setMassActionDialogOpen('copy')} disabled={!!overlay}>Copy - handleFilesDelete()} disabled={!!overlay}>Delete + { handleFilesDelete().catch(() => {}) }} disabled={!!overlay}>Delete setMassActionDialogOpen('compress')} disabled={!!overlay}>Compress )} diff --git a/imports/dashboard/files/massActionDialog.tsx b/imports/dashboard/files/massActionDialog.tsx index 7492830..90ecd70 100644 --- a/imports/dashboard/files/massActionDialog.tsx +++ b/imports/dashboard/files/massActionDialog.tsx @@ -79,7 +79,41 @@ const MassActionDialog = ({ }).catch(() => { setOverlay(''); setMessage('Failed to compress the files!') }) } - const handleMoveCopyOperation = (): void => { + const handleMoveCopyOperation = async (): Promise => { + setOverlay(`${moving} ${files.length} files.`) + const operations = files.map(file => ({ + operation: operation === 'move' ? 'mv' : 'cp', + src: path + file, + dest: newPath.endsWith('/') ? newPath + file : newPath + '/' + file + })) + try { + const res = await ky.patch(`server/${server}/files?path=..`, { json: { operations } }) + if (res.ok) { + reload() + setMessage(moved + ' all files successfully!') + setOverlay('') + return + } else if (res.status !== 404) { + const errors = await res.json<{ errors?: Array<{ index: number, message: string }> }>() + if (errors.errors?.length === 1) { + setMessage(`Error ${movingl} files: ${errors.errors[0].message}`) + setOverlay('') + } else { + reload() + setMessage(`Critical error ${movingl} files: Check browser console for info!`) + setOverlay('') + console.error(errors.errors) + } + return + } + } catch (e) { + reload() + setMessage(`Error ${movingl} files: ${e}`) + setOverlay('') + return + } + + // Fallback to non-transactional API let left = files.length setOverlay({ text: `${moving} ${left} out of ${files.length} files.`, progress: 0 }) const requests = [] @@ -111,7 +145,7 @@ const MassActionDialog = ({ if (operation === 'compress') { handleCompressOperation() } else { - handleMoveCopyOperation() + handleMoveCopyOperation().catch(console.error) // Should not be called, ideally. } } const prompt = operation === 'compress'