From 945e968e06b4f93940e1d04e03cf4ea14a474155 Mon Sep 17 00:00:00 2001 From: Matt Gibson Date: Wed, 2 Jun 2021 07:21:57 -0500 Subject: [PATCH] Export all events matching dates (#990) * Export eagerly pulls down all events Export does not add to rendered elements since that may cause slow down. Export is tied to the currently rendered list of events though `dirtyDates` bool * Use manual btn-submit class * Remove unnecessary method * Fix ExpressionChangedAfterItHasBeenCheckedError --- .../manage/events.component.html | 30 ++++--- .../organizations/manage/events.component.ts | 83 +++++++++++++------ src/app/send/add-edit.component.html | 6 +- 3 files changed, 80 insertions(+), 39 deletions(-) diff --git a/src/app/organizations/manage/events.component.html b/src/app/organizations/manage/events.component.html index ed09ca4561..c9dcd9f04b 100644 --- a/src/app/organizations/manage/events.component.html +++ b/src/app/organizations/manage/events.component.html @@ -4,21 +4,29 @@
+ placeholder="{{'startDate' | i18n}}" [(ngModel)]="start" placeholder="YYYY-MM-DDTHH:MM" + (change)="dirtyDates = true"> - + placeholder="{{'endDate' | i18n}}" [(ngModel)]="end" placeholder="YYYY-MM-DDTHH:MM" + (change)="dirtyDates = true">
- - +
+ +
+
+ +
diff --git a/src/app/organizations/manage/events.component.ts b/src/app/organizations/manage/events.component.ts index 3d4a62cf54..e42349af03 100644 --- a/src/app/organizations/manage/events.component.ts +++ b/src/app/organizations/manage/events.component.ts @@ -29,6 +29,7 @@ export class EventsComponent implements OnInit { events: EventView[]; start: string; end: string; + dirtyDates: boolean = true; continuationToken: string; refreshPromise: Promise; exportPromise: Promise; @@ -69,16 +70,20 @@ export class EventsComponent implements OnInit { } async exportEvents() { - if (this.appApiPromiseUnfulfilled()) { + if (this.appApiPromiseUnfulfilled() || this.dirtyDates) { return; } this.loading = true; - this.exportPromise = this.exportService.getEventExport(this.events).then(data => { - const fileName = this.exportService.getFileName('org-events', 'csv'); - this.platformUtilsService.saveFile(window, data, { type: 'text/plain' }, fileName); - }); + + const dates = this.parseDates(); + if (dates == null) { + return; + } + try { + this.exportPromise = this.export(dates[0], dates[1]); + await this.exportPromise; } catch { } @@ -91,29 +96,56 @@ export class EventsComponent implements OnInit { return; } - let dates: string[] = null; - try { - dates = this.eventService.formatDateFilters(this.start, this.end); - } catch (e) { - this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'), - this.i18nService.t('invalidDateRange')); + const dates = this.parseDates(); + if (dates == null) { return; } this.loading = true; - let response: ListResponse; + let events: EventView[] = []; try { - const promise = this.apiService.getEventsOrganization(this.organizationId, dates[0], dates[1], - clearExisting ? null : this.continuationToken); + const promise = this.loadAndParseEvents(dates[0], dates[1], clearExisting ? null : this.continuationToken); if (clearExisting) { this.refreshPromise = promise; } else { this.morePromise = promise; } - response = await promise; + const result = await promise; + this.continuationToken = result.continuationToken; + events = result.events; } catch { } - this.continuationToken = response.continuationToken; + if (!clearExisting && this.events != null && this.events.length > 0) { + this.events = this.events.concat(events); + } else { + this.events = events; + } + + this.dirtyDates = false; + this.loading = false; + this.morePromise = null; + this.refreshPromise = null; + } + + private async export(start: string, end: string) { + let continuationToken = this.continuationToken; + let events = [].concat(this.events); + + while (continuationToken != null) { + const result = await this.loadAndParseEvents(start, end, continuationToken); + continuationToken = result.continuationToken; + events = events.concat(result.events); + } + + const data = await this.exportService.getEventExport(events); + const fileName = this.exportService.getFileName('org-events', 'csv'); + this.platformUtilsService.saveFile(window, data, { type: 'text/plain' }, fileName); + } + + private async loadAndParseEvents(startDate: string, endDate: string, continuationToken: string) { + const response = await this.apiService.getEventsOrganization(this.organizationId, startDate, endDate, + continuationToken); + const events = await Promise.all(response.data.map(async r => { const userId = r.actingUserId == null ? r.userId : r.actingUserId; const eventInfo = await this.eventService.getEventInfo(r); @@ -132,16 +164,19 @@ export class EventsComponent implements OnInit { type: r.type, }); })); + return { continuationToken: response.continuationToken, events: events }; + } - if (!clearExisting && this.events != null && this.events.length > 0) { - this.events = this.events.concat(events); - } else { - this.events = events; + private parseDates() { + let dates: string[] = null; + try { + dates = this.eventService.formatDateFilters(this.start, this.end); + } catch (e) { + this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'), + this.i18nService.t('invalidDateRange')); + return null; } - - this.loading = false; - this.morePromise = null; - this.refreshPromise = null; + return dates; } private appApiPromiseUnfulfilled() { diff --git a/src/app/send/add-edit.component.html b/src/app/send/add-edit.component.html index 0c051a3e12..cceefa7a54 100644 --- a/src/app/send/add-edit.component.html +++ b/src/app/send/add-edit.component.html @@ -232,10 +232,8 @@