diff --git a/src/components/views/dialogs/ExportDialog.tsx b/src/components/views/dialogs/ExportDialog.tsx index ff542bfbf4..d82bc1efd8 100644 --- a/src/components/views/dialogs/ExportDialog.tsx +++ b/src/components/views/dialogs/ExportDialog.tsx @@ -29,6 +29,7 @@ const ExportDialog: React.FC = ({ room, onFinished }) => { const [exportType, setExportType] = useState(exportTypes.TIMELINE); const [includeAttachments, setAttachments] = useState(false); const [isExporting, setExporting] = useState(false); + const [exportProgressText, setExportProgressText] = useState(""); const [numberOfMessages, setNumberOfMessages] = useState(100); const [sizeLimit, setSizeLimit] = useState(8); const sizeLimitRef = useRef(); @@ -58,6 +59,7 @@ const ExportDialog: React.FC = ({ room, onFinished }) => { room, exportTypes[exportType], exportOptions, + setExportProgressText, ), ); break; @@ -67,6 +69,7 @@ const ExportDialog: React.FC = ({ room, onFinished }) => { room, exportTypes[exportType], exportOptions, + setExportProgressText, ), ); break; @@ -76,6 +79,7 @@ const ExportDialog: React.FC = ({ room, onFinished }) => { room, exportTypes[exportType], exportOptions, + setExportProgressText, ), ); break; @@ -352,6 +356,7 @@ const ExportDialog: React.FC = ({ room, onFinished }) => { onFinished={onFinished} fixedWidth={true} > +

{ exportProgressText }

>, ) { this.cancelled = false; this.files = []; @@ -40,6 +41,11 @@ export default abstract class Exporter { return e.returnValue = "Are you sure you want to exit during this export?"; } + protected updateProgress(progress: string, log = true, show = true): void { + if (log) console.log(progress); + if (show) this.setProgressText(progress); + } + protected addFile(filePath: string, blob: Blob): void { const file = { name: filePath, @@ -57,7 +63,7 @@ export default abstract class Exporter { // Create a writable stream to the directory this.fileStream = streamSaver.createWriteStream(filename); - if (!this.cancelled) console.info("Generating a ZIP..."); + if (!this.cancelled) this.updateProgress("Generating a ZIP..."); else return this.cleanUp(); this.writer = this.fileStream.getWriter(); @@ -72,7 +78,7 @@ export default abstract class Exporter { if (this.cancelled) return this.cleanUp(); - console.info("Writing to the file system..."); + this.updateProgress("Writing to the file system..."); const reader = readableZipStream.getReader(); await this.pumpToFileStream(reader); @@ -172,7 +178,11 @@ export default abstract class Exporter { } events.push(mxEv); } - console.log("Fetched " + events.length + " events so far."); + this.updateProgress( + ("Fetched " + events.length + " events ") + (this.exportType === exportTypes.LAST_N_MESSAGES + ? `out of ${this.exportOptions.numberOfMessages}...` + : "so far..."), + ); prevToken = res.end; } // Reverse the events so that we preserve the order diff --git a/src/utils/exportUtils/HtmlExport.tsx b/src/utils/exportUtils/HtmlExport.tsx index 3c19c4280b..fc963a27b8 100644 --- a/src/utils/exportUtils/HtmlExport.tsx +++ b/src/utils/exportUtils/HtmlExport.tsx @@ -27,8 +27,13 @@ export default class HTMLExporter extends Exporter { protected totalSize: number; protected mediaOmitText: string; - constructor(room: Room, exportType: exportTypes, exportOptions: exportOptions) { - super(room, exportType, exportOptions); + constructor( + room: Room, + exportType: exportTypes, + exportOptions: exportOptions, + setProgressText: React.Dispatch>, + ) { + super(room, exportType, exportOptions, setProgressText); this.avatars = new Map(); this.permalinkCreator = new RoomPermalinkCreator(this.room); this.totalSize = 0; @@ -328,6 +333,7 @@ export default class HTMLExporter extends Exporter { let prevEvent = null; for (let i = 0; i < events.length; i++) { const event = events[i]; + if (i % 100 == 0) this.updateProgress(`Processing event ${i ? i : 1} out of ${events.length}`, false, true); if (this.cancelled) return this.cleanUp(); if (!haveTileForEvent(event)) continue; @@ -343,16 +349,16 @@ export default class HTMLExporter extends Exporter { } public async export() { - console.info("Starting export process..."); - console.info("Fetching events..."); + this.updateProgress("Starting export process...", true, false); + this.updateProgress("Fetching events..."); const fetchStart = performance.now(); const res = await this.getRequiredEvents(); const fetchEnd = performance.now(); - console.log(`Fetched ${res.length} events in ${(fetchEnd - fetchStart)/1000}s`); + this.updateProgress(`Fetched ${res.length} events in ${(fetchEnd - fetchStart)/1000}s`, true, false); - console.info("Creating HTML..."); + this.updateProgress("Creating HTML..."); const html = await this.createHTML(res); this.addFile("index.html", new Blob([html])); @@ -370,8 +376,8 @@ export default class HTMLExporter extends Exporter { if (this.cancelled) { console.info("Export cancelled successfully"); } else { - console.info("Export successful!"); - console.log(`Exported ${res.length} events in ${(exportEnd - fetchStart)/1000} seconds`); + this.updateProgress("Export successful!"); + this.updateProgress(`Exported ${res.length} events in ${(exportEnd - fetchStart)/1000} seconds`); } this.cleanUp(); diff --git a/src/utils/exportUtils/JSONExport.ts b/src/utils/exportUtils/JSONExport.ts index 37f5724289..7b2a4f57a9 100644 --- a/src/utils/exportUtils/JSONExport.ts +++ b/src/utils/exportUtils/JSONExport.ts @@ -11,8 +11,13 @@ export default class JSONExporter extends Exporter { protected totalSize: number; protected messages: any[]; - constructor(room: Room, exportType: exportTypes, exportOptions: exportOptions) { - super(room, exportType, exportOptions); + constructor( + room: Room, + exportType: exportTypes, + exportOptions: exportOptions, + setProgressText: React.Dispatch>, + ) { + super(room, exportType, exportOptions, setProgressText); this.totalSize = 0; this.messages = []; } @@ -55,7 +60,9 @@ export default class JSONExporter extends Exporter { } protected async createOutput(events: MatrixEvent[]) { - for (const event of events) { + for (let i = 0; i < events.length; i++) { + const event = events[i]; + if (i % 100 == 0) this.updateProgress(`Processing event ${i ? i : 1} out of ${events.length}`, false, true); if (this.cancelled) return this.cleanUp(); if (!haveTileForEvent(event)) continue; this.messages.push(await this.getJSONString(event)); diff --git a/src/utils/exportUtils/PlainTextExport.ts b/src/utils/exportUtils/PlainTextExport.ts index 0ab9407415..c437c52de9 100644 --- a/src/utils/exportUtils/PlainTextExport.ts +++ b/src/utils/exportUtils/PlainTextExport.ts @@ -12,8 +12,13 @@ export default class PlainTextExporter extends Exporter { protected totalSize: number; protected mediaOmitText: string; - constructor(room: Room, exportType: exportTypes, exportOptions: exportOptions) { - super(room, exportType, exportOptions); + constructor( + room: Room, + exportType: exportTypes, + exportOptions: exportOptions, + setProgressText: React.Dispatch>, + ) { + super(room, exportType, exportOptions, setProgressText); this.totalSize = 0; this.mediaOmitText = !this.exportOptions.attachmentsIncluded ? _t("Media omitted") @@ -79,7 +84,9 @@ export default class PlainTextExporter extends Exporter { protected async createOutput(events: MatrixEvent[]) { let content = ""; - for (const event of events) { + for (let i = 0; i < events.length; i++) { + const event = events[i]; + if (i % 100 == 0) this.updateProgress(`Processing event ${i ? i : 1} out of ${events.length}`, false, true); if (this.cancelled) return this.cleanUp(); if (!haveTileForEvent(event)) continue; const textForEvent = await this._textForEvent(event); @@ -89,8 +96,8 @@ export default class PlainTextExporter extends Exporter { } public async export() { - console.info("Starting export process..."); - console.info("Fetching events..."); + this.updateProgress("Starting export process..."); + this.updateProgress("Fetching events..."); const fetchStart = performance.now(); const res = await this.getRequiredEvents(); @@ -98,7 +105,7 @@ export default class PlainTextExporter extends Exporter { console.log(`Fetched ${res.length} events in ${(fetchEnd - fetchStart)/1000}s`); - console.info("Creating output..."); + this.updateProgress("Creating output..."); const text = await this.createOutput(res); if (this.files.length) {