From 757e2d1d21e0e88cb66975976adcaea3323c9b57 Mon Sep 17 00:00:00 2001 From: Abhinav-grd Date: Wed, 14 Jul 2021 11:22:27 +0530 Subject: [PATCH] handle export Resume with previous stats --- src/components/ExportInProgress.tsx | 4 +- src/components/ExportModal.tsx | 83 ++++++++++++++++++++++++----- src/services/exportService.ts | 21 ++++---- src/utils/storage/localStorage.ts | 2 +- 4 files changed, 84 insertions(+), 26 deletions(-) diff --git a/src/components/ExportInProgress.tsx b/src/components/ExportInProgress.tsx index 4a2bab053..9e8285f90 100644 --- a/src/components/ExportInProgress.tsx +++ b/src/components/ExportInProgress.tsx @@ -16,7 +16,7 @@ interface Props { exportSize: string exportStage: ExportStage exportStats: ExportStats - exportFiles: () => void; + resumeExport: () => void; cancelExport: () => void pauseExport: () => void; } @@ -36,7 +36,7 @@ export default function ExportInProgress(props: Props) {
{props.exportStage === ExportStage.PAUSED ? - : + : }
diff --git a/src/components/ExportModal.tsx b/src/components/ExportModal.tsx index 55c47355e..2e781604d 100644 --- a/src/components/ExportModal.tsx +++ b/src/components/ExportModal.tsx @@ -42,12 +42,12 @@ export default function ExportModal(props: Props) { if (!isElectron()) { return; } - setExportFolder(getData(LS_KEYS.EXPORT_FOLDER)); + setExportFolder(getData(LS_KEYS.EXPORT)?.folder); exportService.ElectronAPIs.registerStopExportListener(stopExport); exportService.ElectronAPIs.registerPauseExportListener(pauseExport); - exportService.ElectronAPIs.registerStartExportListener(startExport); - exportService.ElectronAPIs.registerRetryFailedExportListener(exportService.retryFailedFiles.bind(this, setExportStats)); + exportService.ElectronAPIs.registerResumeExportListener(resumeExport); + exportService.ElectronAPIs.registerRetryFailedExportListener(retryFailedExport); }, []); useEffect(() => { const main = async () => { @@ -67,26 +67,26 @@ export default function ExportModal(props: Props) { setExportSize(props.usage); }, [props.usage]); - const updateExportFolder = (newFolder) => { + const updateExportFolder = (newFolder: string) => { setExportFolder(newFolder); - setData(LS_KEYS.EXPORT_FOLDER, newFolder); + setData(LS_KEYS.EXPORT, { folder: newFolder }); }; - const updateExportStage = (newStage) => { + const updateExportStage = (newStage: ExportStage) => { setExportStage(newStage); exportService.updateExportRecord({ stage: newStage }); }; - const updateExportTime = (newTime) => { + const updateExportTime = (newTime: number) => { setLastExportTime(newTime); exportService.updateExportRecord({ time: newTime }); }; - const updateExportStats = (newStats) => { + const updateExportStats = (newStats: ExportStats) => { setExportStats(newStats); exportService.updateExportRecord({ stats: newStats }); }; const startExport = async () => { - const exportFolder = getData(LS_KEYS.EXPORT_FOLDER); + const exportFolder = getData(LS_KEYS.EXPORT)?.folder; if (!exportFolder) { const folderSelected = await selectExportDirectory(); if (!folderSelected) { @@ -96,10 +96,65 @@ export default function ExportModal(props: Props) { } updateExportStage(ExportStage.INPROGRESS); updateExportStats({ current: 0, total: 0, failed: 0 }); - await exportService.exportFiles(updateExportStats); - updateExportStage(ExportStage.FINISHED); - await sleep(100); - updateExportTime(Date.now()); + + const finished = await exportService.exportFiles(updateExportStats); + + if (finished) { + updateExportStage(ExportStage.FINISHED); + await sleep(100); + updateExportTime(Date.now()); + } + }; + const retryFailedExport = async () => { + const exportFolder = getData(LS_KEYS.EXPORT)?.folder; + if (!exportFolder) { + const folderSelected = await selectExportDirectory(); + if (!folderSelected) { + // no-op as select folder aborted + return; + } + } + updateExportStage(ExportStage.INPROGRESS); + updateExportStats({ current: 0, total: 0, failed: 0 }); + const finished = await exportService.retryFailedFiles(updateExportStats); + if (finished) { + updateExportStage(ExportStage.FINISHED); + await sleep(100); + updateExportTime(Date.now()); + } + }; + + const resumeExport = async () => { + const exportFolder = getData(LS_KEYS.EXPORT)?.folder; + if (!exportFolder) { + const folderSelected = await selectExportDirectory(); + if (!folderSelected) { + // no-op as select folder aborted + return; + } + } + const exportRecord = await exportService.getExportRecord(); + if (exportRecord.stage !== ExportStage.PAUSED) { + // export not paused + return; + } + const pausedStageStats = exportRecord.stats; + updateExportStage(ExportStage.INPROGRESS); + updateExportStats(pausedStageStats); + const updateExportStatsWithOffset = ((stats: ExportStats) => updateExportStats( + { + current: pausedStageStats.current + stats.current, + total: pausedStageStats.current + stats.total, + failed: pausedStageStats.failed + stats.failed, + }, + )); + const finished = await exportService.exportFiles(updateExportStatsWithOffset); + + if (finished) { + updateExportStage(ExportStage.FINISHED); + await sleep(100); + updateExportTime(Date.now()); + } }; const selectExportDirectory = async () => { @@ -163,7 +218,7 @@ export default function ExportModal(props: Props) { exportSize={exportSize} exportStage={exportStage} exportStats={exportStats} - exportFiles={startExport} + resumeExport={resumeExport} cancelExport={stopExport} pauseExport={pauseExport} /> diff --git a/src/services/exportService.ts b/src/services/exportService.ts index cb3d3d2de..83b59b732 100644 --- a/src/services/exportService.ts +++ b/src/services/exportService.ts @@ -68,16 +68,18 @@ class ExportService { return this.exportInProgress; } this.ElectronAPIs.showOnTray('starting export'); - const dir = getData(LS_KEYS.EXPORT_FOLDER); + const dir = getData(LS_KEYS.EXPORT)?.folder; if (!dir) { // no-export folder set return; } const exportRecord = await this.getExportRecord(dir); const exportedFiles = new Set(exportRecord?.exportedFiles); + const failedFiles = new Set(exportRecord?.failedFiles); console.log(dir, exportedFiles); const unExportedFiles = files.filter((file) => { - if (!exportedFiles.has(`${file.id}_${file.collectionID}`)) { + const fileUID = `${file.id}_${file.collectionID}`; + if (!exportedFiles.has(fileUID) && !failedFiles.has(fileUID)) { return files; } }); @@ -97,20 +99,21 @@ class ExportService { return this.exportInProgress; } this.ElectronAPIs.showOnTray('starting export'); - const dir = getData(LS_KEYS.EXPORT_FOLDER); + const dir = getData(LS_KEYS.EXPORT)?.folder; console.log(dir); if (!dir) { // no-export folder set return; } + const exportRecord = await this.getExportRecord(dir); + const failedFiles = new Set(exportRecord?.failedFiles); - const failedFilesIds = new Set((await this.getExportRecord()).failedFiles ?? []); - const failedFiles = files.filter((file) => { - if (failedFilesIds.has(`${file.id}_${file.collectionID}`)) { + const filesToExport = files.filter((file) => { + if (failedFiles.has(`${file.id}_${file.collectionID}`)) { return files; } }); - this.exportInProgress = this.fileExporter(failedFiles, collections, updateProgress, dir); + this.exportInProgress = this.fileExporter(filesToExport, collections, updateProgress, dir); return this.exportInProgress; } @@ -219,7 +222,7 @@ class ExportService { this.recordUpdateInProgress = (async () => { try { if (!folder) { - folder = getData(LS_KEYS.EXPORT_FOLDER); + folder = getData(LS_KEYS.EXPORT)?.folder; } const exportRecord = await this.getExportRecord(folder); const newRecord = { ...exportRecord, ...newData }; @@ -235,7 +238,7 @@ class ExportService { try { console.log(folder); if (!folder) { - folder = getData(LS_KEYS.EXPORT_FOLDER); + folder = getData(LS_KEYS.EXPORT)?.folder; } const recordFile = await this.ElectronAPIs.getExportRecord(folder); if (recordFile) { diff --git a/src/utils/storage/localStorage.ts b/src/utils/storage/localStorage.ts index 2350e79c4..669dfff08 100644 --- a/src/utils/storage/localStorage.ts +++ b/src/utils/storage/localStorage.ts @@ -10,7 +10,7 @@ export enum LS_KEYS { IS_FIRST_LOGIN = 'isFirstLogin', JUST_SIGNED_UP = 'justSignedUp', SHOW_BACK_BUTTON = 'showBackButton', - EXPORT_FOLDER = 'exportFolder' + EXPORT = 'export' } export const setData = (key: LS_KEYS, value: object) => {