@alimetry/edit-session-widget 0.0.0-stage → 1.0.0-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -2
- package/esm2020/alimetry-edit-session-widget.mjs +5 -0
- package/esm2020/lib/edit-session-widget.component.mjs +161 -0
- package/esm2020/lib/edit-session-widget.module.mjs +19 -0
- package/esm2020/lib/version.mjs +4 -0
- package/esm2020/public-api.mjs +7 -0
- package/fesm2015/alimetry-edit-session-widget.mjs +192 -0
- package/fesm2015/alimetry-edit-session-widget.mjs.map +1 -0
- package/fesm2020/alimetry-edit-session-widget.mjs +190 -0
- package/fesm2020/alimetry-edit-session-widget.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/edit-session-widget.component.d.ts +33 -0
- package/lib/edit-session-widget.module.d.ts +9 -0
- package/lib/version.d.ts +1 -0
- package/package.json +32 -3
- package/public-api.d.ts +3 -0
package/README.md
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
-
#
|
|
1
|
+
# EditSessionWidget
|
|
2
2
|
|
|
3
|
-
This
|
|
3
|
+
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 15.1.0.
|
|
4
|
+
|
|
5
|
+
## Code scaffolding
|
|
6
|
+
|
|
7
|
+
Run `ng generate component component-name --project edit-session-widget` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project edit-session-widget`.
|
|
8
|
+
> Note: Don't forget to add `--project edit-session-widget` or else it will be added to the default project in your `angular.json` file.
|
|
9
|
+
|
|
10
|
+
## Build
|
|
11
|
+
|
|
12
|
+
Run `ng build edit-session-widget` to build the project. The build artifacts will be stored in the `dist/` directory.
|
|
13
|
+
|
|
14
|
+
## Publishing
|
|
15
|
+
|
|
16
|
+
After building your library with `ng build edit-session-widget`, go to the dist folder `cd dist/edit-session-widget` and run `npm publish`.
|
|
17
|
+
|
|
18
|
+
## Running unit tests
|
|
19
|
+
|
|
20
|
+
Run `ng test edit-session-widget` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
|
21
|
+
|
|
22
|
+
## Further help
|
|
23
|
+
|
|
24
|
+
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated bundle index. Do not edit.
|
|
3
|
+
*/
|
|
4
|
+
export * from './public-api';
|
|
5
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWxpbWV0cnktZWRpdC1zZXNzaW9uLXdpZGdldC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3dpZGdldHMvZWRpdC1zZXNzaW9uLXdpZGdldC9zcmMvYWxpbWV0cnktZWRpdC1zZXNzaW9uLXdpZGdldC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILGNBQWMsY0FBYyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBHZW5lcmF0ZWQgYnVuZGxlIGluZGV4LiBEbyBub3QgZWRpdC5cbiAqL1xuXG5leHBvcnQgKiBmcm9tICcuL3B1YmxpYy1hcGknO1xuIl19
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { Component, Input, ViewChild } from '@angular/core';
|
|
2
|
+
import { ServicesConfigService, ServicesService, SessionSearchComponent, isReportGenerated, isReportGenerating, reportLinkOf, sessionNumberOf, statusOf, } from '@alimetry/widget-core';
|
|
3
|
+
import { catchError, EMPTY, exhaustMap, filter, interval, map, Subject, switchMap, take, takeUntil, timer, } from 'rxjs';
|
|
4
|
+
import { EDIT_SESSION_WIDGET_VERSION } from './version';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
import * as i1 from "@alimetry/widget-core";
|
|
7
|
+
import * as i2 from "@angular/common";
|
|
8
|
+
// how often the widget asks the cloud whether the report it is waiting on is ready
|
|
9
|
+
const REPORT_POLL_INTERVAL_MS = 30000;
|
|
10
|
+
// how often it then re-reads the report link and the file behind it, waiting for that file to be
|
|
11
|
+
// the newly generated one rather than the one it replaced
|
|
12
|
+
const REPORT_FILE_POLL_INTERVAL_MS = 5000;
|
|
13
|
+
export class EditSessionWidgetComponent {
|
|
14
|
+
constructor(servicesConfig, services) {
|
|
15
|
+
this.servicesConfig = servicesConfig;
|
|
16
|
+
this.services = services;
|
|
17
|
+
this.version = EDIT_SESSION_WIDGET_VERSION;
|
|
18
|
+
this.configError = null;
|
|
19
|
+
// set when a poll gave up because the record stopped short of a generated report
|
|
20
|
+
this.reportError = null;
|
|
21
|
+
this.reportBaseline = null;
|
|
22
|
+
// the generation of the report currently on screen, as the viewer last loaded it
|
|
23
|
+
this.reportLastModified = null;
|
|
24
|
+
// set while a poll is running that started before the viewer had read the report on screen, so
|
|
25
|
+
// the generation that poll is waiting to replace has still to be recorded
|
|
26
|
+
this.needsBaseline = false;
|
|
27
|
+
// ends the poll a save started: on the next one, on a new search, and on teardown
|
|
28
|
+
this.stopPolling$ = new Subject();
|
|
29
|
+
}
|
|
30
|
+
ngOnChanges() {
|
|
31
|
+
const deviceDataModelId = this.config?.deviceDataModelId?.trim() ?? '';
|
|
32
|
+
const apiUrl = this.config?.apiUrl?.trim() ?? '';
|
|
33
|
+
const appDataPropertySetId = this.config?.appDataPropertySetId?.trim() ?? '';
|
|
34
|
+
const devicePropertySetId = this.config?.devicePropertySetId?.trim() ?? '';
|
|
35
|
+
if (!deviceDataModelId || !apiUrl) {
|
|
36
|
+
this.configError =
|
|
37
|
+
'This widget is missing required configuration values. Please check the widget configuration.';
|
|
38
|
+
this.sessionData = undefined;
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
this.configError = null;
|
|
42
|
+
// hand the values the services layer needs to it through dependency injection
|
|
43
|
+
this.servicesConfig.setConfig({
|
|
44
|
+
deviceDataModelId,
|
|
45
|
+
apiUrl,
|
|
46
|
+
appDataPropertySetId,
|
|
47
|
+
devicePropertySetId,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
onSessionDataLoaded(sessionData) {
|
|
51
|
+
// whatever the last save was waiting on, it is not this session
|
|
52
|
+
this.stopPolling$.next();
|
|
53
|
+
this.sessionData = sessionData;
|
|
54
|
+
this.reportError = null;
|
|
55
|
+
this.reportBaseline = null;
|
|
56
|
+
this.reportLastModified = null;
|
|
57
|
+
this.needsBaseline = false;
|
|
58
|
+
// a session that is already regenerating when it is searched for is waited on the same way one
|
|
59
|
+
// this widget just regenerated is, so reloading the page picks the wait back up
|
|
60
|
+
if (isReportGenerating(statusOf(sessionData))) {
|
|
61
|
+
this.onRegenerateRequested(true);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// clears the search box and drops the session, which empties the form and the report with it
|
|
65
|
+
onCancelled() {
|
|
66
|
+
this.sessionSearch?.clear();
|
|
67
|
+
this.onSessionDataLoaded(undefined);
|
|
68
|
+
}
|
|
69
|
+
onReportLoaded(lastModified) {
|
|
70
|
+
this.reportLastModified = lastModified;
|
|
71
|
+
// the poll a reload started has no generation to wait past until this first read arrives
|
|
72
|
+
if (this.needsBaseline) {
|
|
73
|
+
this.reportBaseline = lastModified;
|
|
74
|
+
this.needsBaseline = false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
onRegenerateRequested(requested) {
|
|
78
|
+
if (!requested) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
this.reportError = null;
|
|
82
|
+
this.reportBaseline = this.reportLastModified;
|
|
83
|
+
this.needsBaseline = !this.reportBaseline;
|
|
84
|
+
this.pollForReport();
|
|
85
|
+
}
|
|
86
|
+
ngOnDestroy() {
|
|
87
|
+
this.stopPolling$.next();
|
|
88
|
+
this.stopPolling$.complete();
|
|
89
|
+
}
|
|
90
|
+
pollForReport() {
|
|
91
|
+
const sessionNumber = this.sessionNumber;
|
|
92
|
+
if (!sessionNumber) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
// whichever poll is already running is waiting on a report this save has superseded
|
|
96
|
+
this.stopPolling$.next();
|
|
97
|
+
interval(REPORT_POLL_INTERVAL_MS)
|
|
98
|
+
.pipe(exhaustMap(() => this.services.getSessionProperty(sessionNumber, 'Status').pipe(map((sessionData) => statusOf(sessionData)), catchError(() => EMPTY))),
|
|
99
|
+
// anything other than "generating report" is as far as this report is going to get, so the
|
|
100
|
+
// poll ends on it either way rather than waiting out a status that will never change
|
|
101
|
+
filter((status) => !isReportGenerating(status)), take(1), takeUntil(this.stopPolling$))
|
|
102
|
+
.subscribe((status) => {
|
|
103
|
+
if (isReportGenerated(status)) {
|
|
104
|
+
this.pollForNewReportFile(sessionNumber);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
this.onReportStopped(sessionNumber);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
pollForNewReportFile(sessionNumber) {
|
|
112
|
+
// with no generation to compare against there is nothing to wait for: whatever the link points
|
|
113
|
+
// at is the report to show, and reading it here only downloads a file the viewer downloads again
|
|
114
|
+
if (!this.reportBaseline) {
|
|
115
|
+
this.loadSession(sessionNumber);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
// poll to check if new report is ready
|
|
119
|
+
timer(0, REPORT_FILE_POLL_INTERVAL_MS)
|
|
120
|
+
.pipe(exhaustMap(() => this.services.getSessionProperty(sessionNumber, 'PdfReport').pipe(map((sessionData) => reportLinkOf(sessionData)), filter((link) => !!link), switchMap((link) => this.services.getReportLastModified(link)), catchError(() => EMPTY))), filter((lastModified) => this.isNewReport(lastModified)), take(1), takeUntil(this.stopPolling$))
|
|
121
|
+
.subscribe(() => this.loadSession(sessionNumber));
|
|
122
|
+
}
|
|
123
|
+
// the record settled on a status that is not a generated report: say so, and read the record back
|
|
124
|
+
// so the form unlocks rather than staying held by a regeneration that is over
|
|
125
|
+
onReportStopped(sessionNumber) {
|
|
126
|
+
this.reportError = 'Report regeneration failed. Please try again.';
|
|
127
|
+
this.loadSession(sessionNumber);
|
|
128
|
+
}
|
|
129
|
+
// the polls above read one property at a time, so the whole record is read back once, here, to
|
|
130
|
+
// show the session the regeneration has left behind
|
|
131
|
+
loadSession(sessionNumber) {
|
|
132
|
+
this.services
|
|
133
|
+
.getSessionData(sessionNumber)
|
|
134
|
+
.pipe(filter((sessionData) => !!sessionData), catchError(() => EMPTY), takeUntil(this.stopPolling$))
|
|
135
|
+
.subscribe((sessionData) => this.showSession(sessionData));
|
|
136
|
+
}
|
|
137
|
+
showSession(sessionData) {
|
|
138
|
+
this.needsBaseline = false;
|
|
139
|
+
this.sessionData = sessionData;
|
|
140
|
+
}
|
|
141
|
+
// check if report is new
|
|
142
|
+
isNewReport(lastModified) {
|
|
143
|
+
const baseline = this.reportBaseline;
|
|
144
|
+
return !!lastModified && !!baseline && lastModified.getTime() > baseline.getTime();
|
|
145
|
+
}
|
|
146
|
+
get sessionNumber() {
|
|
147
|
+
return sessionNumberOf(this.sessionData);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
EditSessionWidgetComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: EditSessionWidgetComponent, deps: [{ token: i1.ServicesConfigService }, { token: i1.ServicesService }], target: i0.ɵɵFactoryTarget.Component });
|
|
151
|
+
EditSessionWidgetComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: EditSessionWidgetComponent, selector: "lib-edit-session-widget", inputs: { config: "config" }, providers: [ServicesConfigService, ServicesService], viewQueries: [{ propertyName: "sessionSearch", first: true, predicate: SessionSearchComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<p *ngIf=\"configError; else sessionSearch\" class=\"edit-session-widget__error\" role=\"alert\">\n {{ configError }}\n</p>\n<ng-template #sessionSearch>\n <lib-session-search (sessionDataLoaded)=\"onSessionDataLoaded($event)\"></lib-session-search>\n <p *ngIf=\"!sessionData\" class=\"edit-session-widget__empty\">\n Search for a session to view its report.\n </p>\n <lib-detail-edit\n [sessionData]=\"sessionData\"\n (regenerateRequested)=\"onRegenerateRequested($event)\"\n (cancelled)=\"onCancelled()\"\n ></lib-detail-edit>\n <p *ngIf=\"reportError\" class=\"edit-session-widget__error\" role=\"alert\">\n {{ reportError }}\n </p>\n <lib-report-viewer\n [sessionData]=\"sessionData\"\n (reportLoaded)=\"onReportLoaded($event)\"\n ></lib-report-viewer>\n</ng-template>\n<lib-version-footer [version]=\"version\"></lib-version-footer>\n", styles: [".edit-session-widget__empty{margin:1rem 0 0;color:#6c757d;font-size:14px}.edit-session-widget__error{margin:0;color:#b02a37}\n"], dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i1.SessionSearchComponent, selector: "lib-session-search", outputs: ["sessionDataLoaded"] }, { kind: "component", type: i1.ReportViewerComponent, selector: "lib-report-viewer", inputs: ["sessionData"], outputs: ["reportLoaded"] }, { kind: "component", type: i1.DetailEditComponent, selector: "lib-detail-edit", inputs: ["sessionData"], outputs: ["regenerateRequested", "cancelled"] }, { kind: "component", type: i1.VersionFooterComponent, selector: "lib-version-footer", inputs: ["version"] }] });
|
|
152
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: EditSessionWidgetComponent, decorators: [{
|
|
153
|
+
type: Component,
|
|
154
|
+
args: [{ selector: 'lib-edit-session-widget', providers: [ServicesConfigService, ServicesService], template: "<p *ngIf=\"configError; else sessionSearch\" class=\"edit-session-widget__error\" role=\"alert\">\n {{ configError }}\n</p>\n<ng-template #sessionSearch>\n <lib-session-search (sessionDataLoaded)=\"onSessionDataLoaded($event)\"></lib-session-search>\n <p *ngIf=\"!sessionData\" class=\"edit-session-widget__empty\">\n Search for a session to view its report.\n </p>\n <lib-detail-edit\n [sessionData]=\"sessionData\"\n (regenerateRequested)=\"onRegenerateRequested($event)\"\n (cancelled)=\"onCancelled()\"\n ></lib-detail-edit>\n <p *ngIf=\"reportError\" class=\"edit-session-widget__error\" role=\"alert\">\n {{ reportError }}\n </p>\n <lib-report-viewer\n [sessionData]=\"sessionData\"\n (reportLoaded)=\"onReportLoaded($event)\"\n ></lib-report-viewer>\n</ng-template>\n<lib-version-footer [version]=\"version\"></lib-version-footer>\n", styles: [".edit-session-widget__empty{margin:1rem 0 0;color:#6c757d;font-size:14px}.edit-session-widget__error{margin:0;color:#b02a37}\n"] }]
|
|
155
|
+
}], ctorParameters: function () { return [{ type: i1.ServicesConfigService }, { type: i1.ServicesService }]; }, propDecorators: { config: [{
|
|
156
|
+
type: Input
|
|
157
|
+
}], sessionSearch: [{
|
|
158
|
+
type: ViewChild,
|
|
159
|
+
args: [SessionSearchComponent]
|
|
160
|
+
}] } });
|
|
161
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWRpdC1zZXNzaW9uLXdpZGdldC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi93aWRnZXRzL2VkaXQtc2Vzc2lvbi13aWRnZXQvc3JjL2xpYi9lZGl0LXNlc3Npb24td2lkZ2V0LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uL3dpZGdldHMvZWRpdC1zZXNzaW9uLXdpZGdldC9zcmMvbGliL2VkaXQtc2Vzc2lvbi13aWRnZXQuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQXdCLFNBQVMsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNsRixPQUFPLEVBRUwscUJBQXFCLEVBQ3JCLGVBQWUsRUFDZixzQkFBc0IsRUFDdEIsaUJBQWlCLEVBQ2pCLGtCQUFrQixFQUNsQixZQUFZLEVBQ1osZUFBZSxFQUNmLFFBQVEsR0FDVCxNQUFNLHVCQUF1QixDQUFDO0FBQy9CLE9BQU8sRUFDTCxVQUFVLEVBQ1YsS0FBSyxFQUNMLFVBQVUsRUFDVixNQUFNLEVBQ04sUUFBUSxFQUNSLEdBQUcsRUFDSCxPQUFPLEVBQ1AsU0FBUyxFQUNULElBQUksRUFDSixTQUFTLEVBQ1QsS0FBSyxHQUNOLE1BQU0sTUFBTSxDQUFDO0FBQ2QsT0FBTyxFQUFFLDJCQUEyQixFQUFFLE1BQU0sV0FBVyxDQUFDOzs7O0FBRXhELG1GQUFtRjtBQUNuRixNQUFNLHVCQUF1QixHQUFHLEtBQU0sQ0FBQztBQUV2QyxpR0FBaUc7QUFDakcsMERBQTBEO0FBQzFELE1BQU0sNEJBQTRCLEdBQUcsSUFBSyxDQUFDO0FBUzNDLE1BQU0sT0FBTywwQkFBMEI7SUEyQnJDLFlBQ1UsY0FBcUMsRUFDckMsUUFBeUI7UUFEekIsbUJBQWMsR0FBZCxjQUFjLENBQXVCO1FBQ3JDLGFBQVEsR0FBUixRQUFRLENBQWlCO1FBekIxQixZQUFPLEdBQUcsMkJBQTJCLENBQUM7UUFNL0MsZ0JBQVcsR0FBa0IsSUFBSSxDQUFDO1FBRWxDLGlGQUFpRjtRQUNqRixnQkFBVyxHQUFrQixJQUFJLENBQUM7UUFFbEMsbUJBQWMsR0FBZ0IsSUFBSSxDQUFDO1FBRW5DLGlGQUFpRjtRQUN6RSx1QkFBa0IsR0FBZ0IsSUFBSSxDQUFDO1FBRS9DLCtGQUErRjtRQUMvRiwwRUFBMEU7UUFDbEUsa0JBQWEsR0FBRyxLQUFLLENBQUM7UUFFOUIsa0ZBQWtGO1FBQ2pFLGlCQUFZLEdBQUcsSUFBSSxPQUFPLEVBQVEsQ0FBQztJQUtqRCxDQUFDO0lBRUosV0FBVztRQUNULE1BQU0saUJBQWlCLEdBQVcsSUFBSSxDQUFDLE1BQU0sRUFBRSxpQkFBaUIsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUM7UUFDL0UsTUFBTSxNQUFNLEdBQVcsSUFBSSxDQUFDLE1BQU0sRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxDQUFDO1FBQ3pELE1BQU0sb0JBQW9CLEdBQVcsSUFBSSxDQUFDLE1BQU0sRUFBRSxvQkFBb0IsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUM7UUFDckYsTUFBTSxtQkFBbUIsR0FBVyxJQUFJLENBQUMsTUFBTSxFQUFFLG1CQUFtQixFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsQ0FBQztRQUVuRixJQUFJLENBQUMsaUJBQWlCLElBQUksQ0FBQyxNQUFNLEVBQUU7WUFDakMsSUFBSSxDQUFDLFdBQVc7Z0JBQ2QsOEZBQThGLENBQUM7WUFDakcsSUFBSSxDQUFDLFdBQVcsR0FBRyxTQUFTLENBQUM7WUFDN0IsT0FBTztTQUNSO1FBRUQsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUM7UUFDeEIsOEVBQThFO1FBQzlFLElBQUksQ0FBQyxjQUFjLENBQUMsU0FBUyxDQUFDO1lBQzVCLGlCQUFpQjtZQUNqQixNQUFNO1lBQ04sb0JBQW9CO1lBQ3BCLG1CQUFtQjtTQUNwQixDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQsbUJBQW1CLENBQUMsV0FBbUM7UUFDckQsZ0VBQWdFO1FBQ2hFLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxFQUFFLENBQUM7UUFFekIsSUFBSSxDQUFDLFdBQVcsR0FBRyxXQUFXLENBQUM7UUFDL0IsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUM7UUFDeEIsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUM7UUFDM0IsSUFBSSxDQUFDLGtCQUFrQixHQUFHLElBQUksQ0FBQztRQUMvQixJQUFJLENBQUMsYUFBYSxHQUFHLEtBQUssQ0FBQztRQUUzQiwrRkFBK0Y7UUFDL0YsZ0ZBQWdGO1FBQ2hGLElBQUksa0JBQWtCLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxDQUFDLEVBQUU7WUFDN0MsSUFBSSxDQUFDLHFCQUFxQixDQUFDLElBQUksQ0FBQyxDQUFDO1NBQ2xDO0lBQ0gsQ0FBQztJQUVELDZGQUE2RjtJQUM3RixXQUFXO1FBQ1QsSUFBSSxDQUFDLGFBQWEsRUFBRSxLQUFLLEVBQUUsQ0FBQztRQUM1QixJQUFJLENBQUMsbUJBQW1CLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDdEMsQ0FBQztJQUVELGNBQWMsQ0FBQyxZQUF5QjtRQUN0QyxJQUFJLENBQUMsa0JBQWtCLEdBQUcsWUFBWSxDQUFDO1FBRXZDLHlGQUF5RjtRQUN6RixJQUFJLElBQUksQ0FBQyxhQUFhLEVBQUU7WUFDdEIsSUFBSSxDQUFDLGNBQWMsR0FBRyxZQUFZLENBQUM7WUFDbkMsSUFBSSxDQUFDLGFBQWEsR0FBRyxLQUFLLENBQUM7U0FDNUI7SUFDSCxDQUFDO0lBRUQscUJBQXFCLENBQUMsU0FBa0I7UUFDdEMsSUFBSSxDQUFDLFNBQVMsRUFBRTtZQUNkLE9BQU87U0FDUjtRQUVELElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxDQUFDO1FBQ3hCLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixDQUFDO1FBQzlDLElBQUksQ0FBQyxhQUFhLEdBQUcsQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDO1FBQzFDLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztJQUN2QixDQUFDO0lBRUQsV0FBVztRQUNULElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDekIsSUFBSSxDQUFDLFlBQVksQ0FBQyxRQUFRLEVBQUUsQ0FBQztJQUMvQixDQUFDO0lBRU8sYUFBYTtRQUNuQixNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDO1FBQ3pDLElBQUksQ0FBQyxhQUFhLEVBQUU7WUFDbEIsT0FBTztTQUNSO1FBRUQsb0ZBQW9GO1FBQ3BGLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxFQUFFLENBQUM7UUFFekIsUUFBUSxDQUFDLHVCQUF1QixDQUFDO2FBQzlCLElBQUksQ0FDSCxVQUFVLENBQUMsR0FBRyxFQUFFLENBQ2QsSUFBSSxDQUFDLFFBQVEsQ0FBQyxrQkFBa0IsQ0FBQyxhQUFhLEVBQUUsUUFBUSxDQUFDLENBQUMsSUFBSSxDQUM1RCxHQUFHLENBQUMsQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsQ0FBQyxFQUMzQyxVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQ3hCLENBQ0Y7UUFDRCwyRkFBMkY7UUFDM0YscUZBQXFGO1FBQ3JGLE1BQU0sQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQyxrQkFBa0IsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUMvQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQ1AsU0FBUyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FDN0I7YUFDQSxTQUFTLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRTtZQUNwQixJQUFJLGlCQUFpQixDQUFDLE1BQU0sQ0FBQyxFQUFFO2dCQUM3QixJQUFJLENBQUMsb0JBQW9CLENBQUMsYUFBYSxDQUFDLENBQUM7YUFDMUM7aUJBQU07Z0JBQ0wsSUFBSSxDQUFDLGVBQWUsQ0FBQyxhQUFhLENBQUMsQ0FBQzthQUNyQztRQUNILENBQUMsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztJQUVPLG9CQUFvQixDQUFDLGFBQXFCO1FBQ2hELCtGQUErRjtRQUMvRixpR0FBaUc7UUFDakcsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLEVBQUU7WUFDeEIsSUFBSSxDQUFDLFdBQVcsQ0FBQyxhQUFhLENBQUMsQ0FBQztZQUNoQyxPQUFPO1NBQ1I7UUFFRCx1Q0FBdUM7UUFDdkMsS0FBSyxDQUFDLENBQUMsRUFBRSw0QkFBNEIsQ0FBQzthQUNuQyxJQUFJLENBQ0gsVUFBVSxDQUFDLEdBQUcsRUFBRSxDQUNkLElBQUksQ0FBQyxRQUFRLENBQUMsa0JBQWtCLENBQUMsYUFBYSxFQUFFLFdBQVcsQ0FBQyxDQUFDLElBQUksQ0FDL0QsR0FBRyxDQUFDLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQyxZQUFZLENBQUMsV0FBVyxDQUFDLENBQUMsRUFDL0MsTUFBTSxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQ3hCLFNBQVMsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxxQkFBcUIsQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUM5RCxVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQ3hCLENBQ0YsRUFDRCxNQUFNLENBQUMsQ0FBQyxZQUFZLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsWUFBWSxDQUFDLENBQUMsRUFDeEQsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUNQLFNBQVMsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQzdCO2FBQ0EsU0FBUyxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQztJQUN0RCxDQUFDO0lBRUQsa0dBQWtHO0lBQ2xHLDhFQUE4RTtJQUN0RSxlQUFlLENBQUMsYUFBcUI7UUFDM0MsSUFBSSxDQUFDLFdBQVcsR0FBRywrQ0FBK0MsQ0FBQztRQUNuRSxJQUFJLENBQUMsV0FBVyxDQUFDLGFBQWEsQ0FBQyxDQUFDO0lBQ2xDLENBQUM7SUFFRCwrRkFBK0Y7SUFDL0Ysb0RBQW9EO0lBQzVDLFdBQVcsQ0FBQyxhQUFxQjtRQUN2QyxJQUFJLENBQUMsUUFBUTthQUNWLGNBQWMsQ0FBQyxhQUFhLENBQUM7YUFDN0IsSUFBSSxDQUNILE1BQU0sQ0FBQyxDQUFDLFdBQVcsRUFBNkIsRUFBRSxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsRUFDakUsVUFBVSxDQUFDLEdBQUcsRUFBRSxDQUFDLEtBQUssQ0FBQyxFQUN2QixTQUFTLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUM3QjthQUNBLFNBQVMsQ0FBQyxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDO0lBQy9ELENBQUM7SUFFTyxXQUFXLENBQUMsV0FBdUI7UUFDekMsSUFBSSxDQUFDLGFBQWEsR0FBRyxLQUFLLENBQUM7UUFDM0IsSUFBSSxDQUFDLFdBQVcsR0FBRyxXQUFXLENBQUM7SUFDakMsQ0FBQztJQUVELHlCQUF5QjtJQUNqQixXQUFXLENBQUMsWUFBeUI7UUFDM0MsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQztRQUNyQyxPQUFPLENBQUMsQ0FBQyxZQUFZLElBQUksQ0FBQyxDQUFDLFFBQVEsSUFBSSxZQUFZLENBQUMsT0FBTyxFQUFFLEdBQUcsUUFBUSxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBQ3JGLENBQUM7SUFFRCxJQUFZLGFBQWE7UUFDdkIsT0FBTyxlQUFlLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQzNDLENBQUM7O3dIQW5NVSwwQkFBMEI7NEdBQTFCLDBCQUEwQixnRkFGMUIsQ0FBQyxxQkFBcUIsRUFBRSxlQUFlLENBQUMseUVBU3hDLHNCQUFzQixxRUNoRG5DLHcyQkFzQkE7NEZEbUJhLDBCQUEwQjtrQkFQdEMsU0FBUzsrQkFDRSx5QkFBeUIsYUFJeEIsQ0FBQyxxQkFBcUIsRUFBRSxlQUFlLENBQUM7MElBSTFDLE1BQU07c0JBQWQsS0FBSztnQkFLcUMsYUFBYTtzQkFBdkQsU0FBUzt1QkFBQyxzQkFBc0IiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIElucHV0LCBPbkNoYW5nZXMsIE9uRGVzdHJveSwgVmlld0NoaWxkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge1xuICBEZXZpY2VEYXRhLFxuICBTZXJ2aWNlc0NvbmZpZ1NlcnZpY2UsXG4gIFNlcnZpY2VzU2VydmljZSxcbiAgU2Vzc2lvblNlYXJjaENvbXBvbmVudCxcbiAgaXNSZXBvcnRHZW5lcmF0ZWQsXG4gIGlzUmVwb3J0R2VuZXJhdGluZyxcbiAgcmVwb3J0TGlua09mLFxuICBzZXNzaW9uTnVtYmVyT2YsXG4gIHN0YXR1c09mLFxufSBmcm9tICdAYWxpbWV0cnkvd2lkZ2V0LWNvcmUnO1xuaW1wb3J0IHtcbiAgY2F0Y2hFcnJvcixcbiAgRU1QVFksXG4gIGV4aGF1c3RNYXAsXG4gIGZpbHRlcixcbiAgaW50ZXJ2YWwsXG4gIG1hcCxcbiAgU3ViamVjdCxcbiAgc3dpdGNoTWFwLFxuICB0YWtlLFxuICB0YWtlVW50aWwsXG4gIHRpbWVyLFxufSBmcm9tICdyeGpzJztcbmltcG9ydCB7IEVESVRfU0VTU0lPTl9XSURHRVRfVkVSU0lPTiB9IGZyb20gJy4vdmVyc2lvbic7XG5cbi8vIGhvdyBvZnRlbiB0aGUgd2lkZ2V0IGFza3MgdGhlIGNsb3VkIHdoZXRoZXIgdGhlIHJlcG9ydCBpdCBpcyB3YWl0aW5nIG9uIGlzIHJlYWR5XG5jb25zdCBSRVBPUlRfUE9MTF9JTlRFUlZBTF9NUyA9IDMwXzAwMDtcblxuLy8gaG93IG9mdGVuIGl0IHRoZW4gcmUtcmVhZHMgdGhlIHJlcG9ydCBsaW5rIGFuZCB0aGUgZmlsZSBiZWhpbmQgaXQsIHdhaXRpbmcgZm9yIHRoYXQgZmlsZSB0byBiZVxuLy8gdGhlIG5ld2x5IGdlbmVyYXRlZCBvbmUgcmF0aGVyIHRoYW4gdGhlIG9uZSBpdCByZXBsYWNlZFxuY29uc3QgUkVQT1JUX0ZJTEVfUE9MTF9JTlRFUlZBTF9NUyA9IDVfMDAwO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdsaWItZWRpdC1zZXNzaW9uLXdpZGdldCcsXG4gIHRlbXBsYXRlVXJsOiAnLi9lZGl0LXNlc3Npb24td2lkZ2V0LmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vZWRpdC1zZXNzaW9uLXdpZGdldC5jb21wb25lbnQuY3NzJ10sXG4gIC8vIHNjb3BlZCB0byB0aGlzIHdpZGdldCBzbyBlYWNoIGluc3RhbmNlIHJ1bnMgYWdhaW5zdCB0aGUgY29uZmlnIGl0IHdhcyBnaXZlblxuICBwcm92aWRlcnM6IFtTZXJ2aWNlc0NvbmZpZ1NlcnZpY2UsIFNlcnZpY2VzU2VydmljZV0sXG59KVxuZXhwb3J0IGNsYXNzIEVkaXRTZXNzaW9uV2lkZ2V0Q29tcG9uZW50IGltcGxlbWVudHMgT25DaGFuZ2VzLCBPbkRlc3Ryb3kge1xuICAvLyBUT0RPOiBjaGFuZ2UgdGhlIHR5cGUgb2YgdGhlIGlucHV0IHRvIG5vdCBiZSBhbnlcbiAgQElucHV0KCkgY29uZmlnOiBhbnk7XG5cbiAgcmVhZG9ubHkgdmVyc2lvbiA9IEVESVRfU0VTU0lPTl9XSURHRVRfVkVSU0lPTjtcblxuICAvLyBpbnNpZGUgdGhlIGNvbmZpZyBjaGVjaydzIHRlbXBsYXRlLCBzbyBpdCBpcyBvbmx5IHRoZXJlIG9uY2UgdGhlIGNvbmZpZyBpcyB2YWxpZFxuICBAVmlld0NoaWxkKFNlc3Npb25TZWFyY2hDb21wb25lbnQpIHByaXZhdGUgc2Vzc2lvblNlYXJjaD86IFNlc3Npb25TZWFyY2hDb21wb25lbnQ7XG5cbiAgc2Vzc2lvbkRhdGE/OiBEZXZpY2VEYXRhO1xuICBjb25maWdFcnJvcjogc3RyaW5nIHwgbnVsbCA9IG51bGw7XG5cbiAgLy8gc2V0IHdoZW4gYSBwb2xsIGdhdmUgdXAgYmVjYXVzZSB0aGUgcmVjb3JkIHN0b3BwZWQgc2hvcnQgb2YgYSBnZW5lcmF0ZWQgcmVwb3J0XG4gIHJlcG9ydEVycm9yOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcblxuICByZXBvcnRCYXNlbGluZTogRGF0ZSB8IG51bGwgPSBudWxsO1xuXG4gIC8vIHRoZSBnZW5lcmF0aW9uIG9mIHRoZSByZXBvcnQgY3VycmVudGx5IG9uIHNjcmVlbiwgYXMgdGhlIHZpZXdlciBsYXN0IGxvYWRlZCBpdFxuICBwcml2YXRlIHJlcG9ydExhc3RNb2RpZmllZDogRGF0ZSB8IG51bGwgPSBudWxsO1xuXG4gIC8vIHNldCB3aGlsZSBhIHBvbGwgaXMgcnVubmluZyB0aGF0IHN0YXJ0ZWQgYmVmb3JlIHRoZSB2aWV3ZXIgaGFkIHJlYWQgdGhlIHJlcG9ydCBvbiBzY3JlZW4sIHNvXG4gIC8vIHRoZSBnZW5lcmF0aW9uIHRoYXQgcG9sbCBpcyB3YWl0aW5nIHRvIHJlcGxhY2UgaGFzIHN0aWxsIHRvIGJlIHJlY29yZGVkXG4gIHByaXZhdGUgbmVlZHNCYXNlbGluZSA9IGZhbHNlO1xuXG4gIC8vIGVuZHMgdGhlIHBvbGwgYSBzYXZlIHN0YXJ0ZWQ6IG9uIHRoZSBuZXh0IG9uZSwgb24gYSBuZXcgc2VhcmNoLCBhbmQgb24gdGVhcmRvd25cbiAgcHJpdmF0ZSByZWFkb25seSBzdG9wUG9sbGluZyQgPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgc2VydmljZXNDb25maWc6IFNlcnZpY2VzQ29uZmlnU2VydmljZSxcbiAgICBwcml2YXRlIHNlcnZpY2VzOiBTZXJ2aWNlc1NlcnZpY2UsXG4gICkge31cblxuICBuZ09uQ2hhbmdlcygpOiB2b2lkIHtcbiAgICBjb25zdCBkZXZpY2VEYXRhTW9kZWxJZDogc3RyaW5nID0gdGhpcy5jb25maWc/LmRldmljZURhdGFNb2RlbElkPy50cmltKCkgPz8gJyc7XG4gICAgY29uc3QgYXBpVXJsOiBzdHJpbmcgPSB0aGlzLmNvbmZpZz8uYXBpVXJsPy50cmltKCkgPz8gJyc7XG4gICAgY29uc3QgYXBwRGF0YVByb3BlcnR5U2V0SWQ6IHN0cmluZyA9IHRoaXMuY29uZmlnPy5hcHBEYXRhUHJvcGVydHlTZXRJZD8udHJpbSgpID8/ICcnO1xuICAgIGNvbnN0IGRldmljZVByb3BlcnR5U2V0SWQ6IHN0cmluZyA9IHRoaXMuY29uZmlnPy5kZXZpY2VQcm9wZXJ0eVNldElkPy50cmltKCkgPz8gJyc7XG5cbiAgICBpZiAoIWRldmljZURhdGFNb2RlbElkIHx8ICFhcGlVcmwpIHtcbiAgICAgIHRoaXMuY29uZmlnRXJyb3IgPVxuICAgICAgICAnVGhpcyB3aWRnZXQgaXMgbWlzc2luZyByZXF1aXJlZCBjb25maWd1cmF0aW9uIHZhbHVlcy4gUGxlYXNlIGNoZWNrIHRoZSB3aWRnZXQgY29uZmlndXJhdGlvbi4nO1xuICAgICAgdGhpcy5zZXNzaW9uRGF0YSA9IHVuZGVmaW5lZDtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLmNvbmZpZ0Vycm9yID0gbnVsbDtcbiAgICAvLyBoYW5kIHRoZSB2YWx1ZXMgdGhlIHNlcnZpY2VzIGxheWVyIG5lZWRzIHRvIGl0IHRocm91Z2ggZGVwZW5kZW5jeSBpbmplY3Rpb25cbiAgICB0aGlzLnNlcnZpY2VzQ29uZmlnLnNldENvbmZpZyh7XG4gICAgICBkZXZpY2VEYXRhTW9kZWxJZCxcbiAgICAgIGFwaVVybCxcbiAgICAgIGFwcERhdGFQcm9wZXJ0eVNldElkLFxuICAgICAgZGV2aWNlUHJvcGVydHlTZXRJZCxcbiAgICB9KTtcbiAgfVxuXG4gIG9uU2Vzc2lvbkRhdGFMb2FkZWQoc2Vzc2lvbkRhdGE6IERldmljZURhdGEgfCB1bmRlZmluZWQpOiB2b2lkIHtcbiAgICAvLyB3aGF0ZXZlciB0aGUgbGFzdCBzYXZlIHdhcyB3YWl0aW5nIG9uLCBpdCBpcyBub3QgdGhpcyBzZXNzaW9uXG4gICAgdGhpcy5zdG9wUG9sbGluZyQubmV4dCgpO1xuXG4gICAgdGhpcy5zZXNzaW9uRGF0YSA9IHNlc3Npb25EYXRhO1xuICAgIHRoaXMucmVwb3J0RXJyb3IgPSBudWxsO1xuICAgIHRoaXMucmVwb3J0QmFzZWxpbmUgPSBudWxsO1xuICAgIHRoaXMucmVwb3J0TGFzdE1vZGlmaWVkID0gbnVsbDtcbiAgICB0aGlzLm5lZWRzQmFzZWxpbmUgPSBmYWxzZTtcblxuICAgIC8vIGEgc2Vzc2lvbiB0aGF0IGlzIGFscmVhZHkgcmVnZW5lcmF0aW5nIHdoZW4gaXQgaXMgc2VhcmNoZWQgZm9yIGlzIHdhaXRlZCBvbiB0aGUgc2FtZSB3YXkgb25lXG4gICAgLy8gdGhpcyB3aWRnZXQganVzdCByZWdlbmVyYXRlZCBpcywgc28gcmVsb2FkaW5nIHRoZSBwYWdlIHBpY2tzIHRoZSB3YWl0IGJhY2sgdXBcbiAgICBpZiAoaXNSZXBvcnRHZW5lcmF0aW5nKHN0YXR1c09mKHNlc3Npb25EYXRhKSkpIHtcbiAgICAgIHRoaXMub25SZWdlbmVyYXRlUmVxdWVzdGVkKHRydWUpO1xuICAgIH1cbiAgfVxuXG4gIC8vIGNsZWFycyB0aGUgc2VhcmNoIGJveCBhbmQgZHJvcHMgdGhlIHNlc3Npb24sIHdoaWNoIGVtcHRpZXMgdGhlIGZvcm0gYW5kIHRoZSByZXBvcnQgd2l0aCBpdFxuICBvbkNhbmNlbGxlZCgpOiB2b2lkIHtcbiAgICB0aGlzLnNlc3Npb25TZWFyY2g/LmNsZWFyKCk7XG4gICAgdGhpcy5vblNlc3Npb25EYXRhTG9hZGVkKHVuZGVmaW5lZCk7XG4gIH1cblxuICBvblJlcG9ydExvYWRlZChsYXN0TW9kaWZpZWQ6IERhdGUgfCBudWxsKTogdm9pZCB7XG4gICAgdGhpcy5yZXBvcnRMYXN0TW9kaWZpZWQgPSBsYXN0TW9kaWZpZWQ7XG5cbiAgICAvLyB0aGUgcG9sbCBhIHJlbG9hZCBzdGFydGVkIGhhcyBubyBnZW5lcmF0aW9uIHRvIHdhaXQgcGFzdCB1bnRpbCB0aGlzIGZpcnN0IHJlYWQgYXJyaXZlc1xuICAgIGlmICh0aGlzLm5lZWRzQmFzZWxpbmUpIHtcbiAgICAgIHRoaXMucmVwb3J0QmFzZWxpbmUgPSBsYXN0TW9kaWZpZWQ7XG4gICAgICB0aGlzLm5lZWRzQmFzZWxpbmUgPSBmYWxzZTtcbiAgICB9XG4gIH1cblxuICBvblJlZ2VuZXJhdGVSZXF1ZXN0ZWQocmVxdWVzdGVkOiBib29sZWFuKTogdm9pZCB7XG4gICAgaWYgKCFyZXF1ZXN0ZWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLnJlcG9ydEVycm9yID0gbnVsbDtcbiAgICB0aGlzLnJlcG9ydEJhc2VsaW5lID0gdGhpcy5yZXBvcnRMYXN0TW9kaWZpZWQ7XG4gICAgdGhpcy5uZWVkc0Jhc2VsaW5lID0gIXRoaXMucmVwb3J0QmFzZWxpbmU7XG4gICAgdGhpcy5wb2xsRm9yUmVwb3J0KCk7XG4gIH1cblxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLnN0b3BQb2xsaW5nJC5uZXh0KCk7XG4gICAgdGhpcy5zdG9wUG9sbGluZyQuY29tcGxldGUoKTtcbiAgfVxuXG4gIHByaXZhdGUgcG9sbEZvclJlcG9ydCgpOiB2b2lkIHtcbiAgICBjb25zdCBzZXNzaW9uTnVtYmVyID0gdGhpcy5zZXNzaW9uTnVtYmVyO1xuICAgIGlmICghc2Vzc2lvbk51bWJlcikge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIHdoaWNoZXZlciBwb2xsIGlzIGFscmVhZHkgcnVubmluZyBpcyB3YWl0aW5nIG9uIGEgcmVwb3J0IHRoaXMgc2F2ZSBoYXMgc3VwZXJzZWRlZFxuICAgIHRoaXMuc3RvcFBvbGxpbmckLm5leHQoKTtcblxuICAgIGludGVydmFsKFJFUE9SVF9QT0xMX0lOVEVSVkFMX01TKVxuICAgICAgLnBpcGUoXG4gICAgICAgIGV4aGF1c3RNYXAoKCkgPT5cbiAgICAgICAgICB0aGlzLnNlcnZpY2VzLmdldFNlc3Npb25Qcm9wZXJ0eShzZXNzaW9uTnVtYmVyLCAnU3RhdHVzJykucGlwZShcbiAgICAgICAgICAgIG1hcCgoc2Vzc2lvbkRhdGEpID0+IHN0YXR1c09mKHNlc3Npb25EYXRhKSksXG4gICAgICAgICAgICBjYXRjaEVycm9yKCgpID0+IEVNUFRZKSxcbiAgICAgICAgICApLFxuICAgICAgICApLFxuICAgICAgICAvLyBhbnl0aGluZyBvdGhlciB0aGFuIFwiZ2VuZXJhdGluZyByZXBvcnRcIiBpcyBhcyBmYXIgYXMgdGhpcyByZXBvcnQgaXMgZ29pbmcgdG8gZ2V0LCBzbyB0aGVcbiAgICAgICAgLy8gcG9sbCBlbmRzIG9uIGl0IGVpdGhlciB3YXkgcmF0aGVyIHRoYW4gd2FpdGluZyBvdXQgYSBzdGF0dXMgdGhhdCB3aWxsIG5ldmVyIGNoYW5nZVxuICAgICAgICBmaWx0ZXIoKHN0YXR1cykgPT4gIWlzUmVwb3J0R2VuZXJhdGluZyhzdGF0dXMpKSxcbiAgICAgICAgdGFrZSgxKSxcbiAgICAgICAgdGFrZVVudGlsKHRoaXMuc3RvcFBvbGxpbmckKSxcbiAgICAgIClcbiAgICAgIC5zdWJzY3JpYmUoKHN0YXR1cykgPT4ge1xuICAgICAgICBpZiAoaXNSZXBvcnRHZW5lcmF0ZWQoc3RhdHVzKSkge1xuICAgICAgICAgIHRoaXMucG9sbEZvck5ld1JlcG9ydEZpbGUoc2Vzc2lvbk51bWJlcik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5vblJlcG9ydFN0b3BwZWQoc2Vzc2lvbk51bWJlcik7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBwb2xsRm9yTmV3UmVwb3J0RmlsZShzZXNzaW9uTnVtYmVyOiBzdHJpbmcpOiB2b2lkIHtcbiAgICAvLyB3aXRoIG5vIGdlbmVyYXRpb24gdG8gY29tcGFyZSBhZ2FpbnN0IHRoZXJlIGlzIG5vdGhpbmcgdG8gd2FpdCBmb3I6IHdoYXRldmVyIHRoZSBsaW5rIHBvaW50c1xuICAgIC8vIGF0IGlzIHRoZSByZXBvcnQgdG8gc2hvdywgYW5kIHJlYWRpbmcgaXQgaGVyZSBvbmx5IGRvd25sb2FkcyBhIGZpbGUgdGhlIHZpZXdlciBkb3dubG9hZHMgYWdhaW5cbiAgICBpZiAoIXRoaXMucmVwb3J0QmFzZWxpbmUpIHtcbiAgICAgIHRoaXMubG9hZFNlc3Npb24oc2Vzc2lvbk51bWJlcik7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gcG9sbCB0byBjaGVjayBpZiBuZXcgcmVwb3J0IGlzIHJlYWR5XG4gICAgdGltZXIoMCwgUkVQT1JUX0ZJTEVfUE9MTF9JTlRFUlZBTF9NUylcbiAgICAgIC5waXBlKFxuICAgICAgICBleGhhdXN0TWFwKCgpID0+XG4gICAgICAgICAgdGhpcy5zZXJ2aWNlcy5nZXRTZXNzaW9uUHJvcGVydHkoc2Vzc2lvbk51bWJlciwgJ1BkZlJlcG9ydCcpLnBpcGUoXG4gICAgICAgICAgICBtYXAoKHNlc3Npb25EYXRhKSA9PiByZXBvcnRMaW5rT2Yoc2Vzc2lvbkRhdGEpKSxcbiAgICAgICAgICAgIGZpbHRlcigobGluaykgPT4gISFsaW5rKSxcbiAgICAgICAgICAgIHN3aXRjaE1hcCgobGluaykgPT4gdGhpcy5zZXJ2aWNlcy5nZXRSZXBvcnRMYXN0TW9kaWZpZWQobGluaykpLFxuICAgICAgICAgICAgY2F0Y2hFcnJvcigoKSA9PiBFTVBUWSksXG4gICAgICAgICAgKSxcbiAgICAgICAgKSxcbiAgICAgICAgZmlsdGVyKChsYXN0TW9kaWZpZWQpID0+IHRoaXMuaXNOZXdSZXBvcnQobGFzdE1vZGlmaWVkKSksXG4gICAgICAgIHRha2UoMSksXG4gICAgICAgIHRha2VVbnRpbCh0aGlzLnN0b3BQb2xsaW5nJCksXG4gICAgICApXG4gICAgICAuc3Vic2NyaWJlKCgpID0+IHRoaXMubG9hZFNlc3Npb24oc2Vzc2lvbk51bWJlcikpO1xuICB9XG5cbiAgLy8gdGhlIHJlY29yZCBzZXR0bGVkIG9uIGEgc3RhdHVzIHRoYXQgaXMgbm90IGEgZ2VuZXJhdGVkIHJlcG9ydDogc2F5IHNvLCBhbmQgcmVhZCB0aGUgcmVjb3JkIGJhY2tcbiAgLy8gc28gdGhlIGZvcm0gdW5sb2NrcyByYXRoZXIgdGhhbiBzdGF5aW5nIGhlbGQgYnkgYSByZWdlbmVyYXRpb24gdGhhdCBpcyBvdmVyXG4gIHByaXZhdGUgb25SZXBvcnRTdG9wcGVkKHNlc3Npb25OdW1iZXI6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMucmVwb3J0RXJyb3IgPSAnUmVwb3J0IHJlZ2VuZXJhdGlvbiBmYWlsZWQuIFBsZWFzZSB0cnkgYWdhaW4uJztcbiAgICB0aGlzLmxvYWRTZXNzaW9uKHNlc3Npb25OdW1iZXIpO1xuICB9XG5cbiAgLy8gdGhlIHBvbGxzIGFib3ZlIHJlYWQgb25lIHByb3BlcnR5IGF0IGEgdGltZSwgc28gdGhlIHdob2xlIHJlY29yZCBpcyByZWFkIGJhY2sgb25jZSwgaGVyZSwgdG9cbiAgLy8gc2hvdyB0aGUgc2Vzc2lvbiB0aGUgcmVnZW5lcmF0aW9uIGhhcyBsZWZ0IGJlaGluZFxuICBwcml2YXRlIGxvYWRTZXNzaW9uKHNlc3Npb25OdW1iZXI6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMuc2VydmljZXNcbiAgICAgIC5nZXRTZXNzaW9uRGF0YShzZXNzaW9uTnVtYmVyKVxuICAgICAgLnBpcGUoXG4gICAgICAgIGZpbHRlcigoc2Vzc2lvbkRhdGEpOiBzZXNzaW9uRGF0YSBpcyBEZXZpY2VEYXRhID0+ICEhc2Vzc2lvbkRhdGEpLFxuICAgICAgICBjYXRjaEVycm9yKCgpID0+IEVNUFRZKSxcbiAgICAgICAgdGFrZVVudGlsKHRoaXMuc3RvcFBvbGxpbmckKSxcbiAgICAgIClcbiAgICAgIC5zdWJzY3JpYmUoKHNlc3Npb25EYXRhKSA9PiB0aGlzLnNob3dTZXNzaW9uKHNlc3Npb25EYXRhKSk7XG4gIH1cblxuICBwcml2YXRlIHNob3dTZXNzaW9uKHNlc3Npb25EYXRhOiBEZXZpY2VEYXRhKTogdm9pZCB7XG4gICAgdGhpcy5uZWVkc0Jhc2VsaW5lID0gZmFsc2U7XG4gICAgdGhpcy5zZXNzaW9uRGF0YSA9IHNlc3Npb25EYXRhO1xuICB9XG5cbiAgLy8gY2hlY2sgaWYgcmVwb3J0IGlzIG5ld1xuICBwcml2YXRlIGlzTmV3UmVwb3J0KGxhc3RNb2RpZmllZDogRGF0ZSB8IG51bGwpOiBib29sZWFuIHtcbiAgICBjb25zdCBiYXNlbGluZSA9IHRoaXMucmVwb3J0QmFzZWxpbmU7XG4gICAgcmV0dXJuICEhbGFzdE1vZGlmaWVkICYmICEhYmFzZWxpbmUgJiYgbGFzdE1vZGlmaWVkLmdldFRpbWUoKSA+IGJhc2VsaW5lLmdldFRpbWUoKTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0IHNlc3Npb25OdW1iZXIoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gc2Vzc2lvbk51bWJlck9mKHRoaXMuc2Vzc2lvbkRhdGEpO1xuICB9XG59XG4iLCI8cCAqbmdJZj1cImNvbmZpZ0Vycm9yOyBlbHNlIHNlc3Npb25TZWFyY2hcIiBjbGFzcz1cImVkaXQtc2Vzc2lvbi13aWRnZXRfX2Vycm9yXCIgcm9sZT1cImFsZXJ0XCI+XG4gIHt7IGNvbmZpZ0Vycm9yIH19XG48L3A+XG48bmctdGVtcGxhdGUgI3Nlc3Npb25TZWFyY2g+XG4gIDxsaWItc2Vzc2lvbi1zZWFyY2ggKHNlc3Npb25EYXRhTG9hZGVkKT1cIm9uU2Vzc2lvbkRhdGFMb2FkZWQoJGV2ZW50KVwiPjwvbGliLXNlc3Npb24tc2VhcmNoPlxuICA8cCAqbmdJZj1cIiFzZXNzaW9uRGF0YVwiIGNsYXNzPVwiZWRpdC1zZXNzaW9uLXdpZGdldF9fZW1wdHlcIj5cbiAgICBTZWFyY2ggZm9yIGEgc2Vzc2lvbiB0byB2aWV3IGl0cyByZXBvcnQuXG4gIDwvcD5cbiAgPGxpYi1kZXRhaWwtZWRpdFxuICAgIFtzZXNzaW9uRGF0YV09XCJzZXNzaW9uRGF0YVwiXG4gICAgKHJlZ2VuZXJhdGVSZXF1ZXN0ZWQpPVwib25SZWdlbmVyYXRlUmVxdWVzdGVkKCRldmVudClcIlxuICAgIChjYW5jZWxsZWQpPVwib25DYW5jZWxsZWQoKVwiXG4gID48L2xpYi1kZXRhaWwtZWRpdD5cbiAgPHAgKm5nSWY9XCJyZXBvcnRFcnJvclwiIGNsYXNzPVwiZWRpdC1zZXNzaW9uLXdpZGdldF9fZXJyb3JcIiByb2xlPVwiYWxlcnRcIj5cbiAgICB7eyByZXBvcnRFcnJvciB9fVxuICA8L3A+XG4gIDxsaWItcmVwb3J0LXZpZXdlclxuICAgIFtzZXNzaW9uRGF0YV09XCJzZXNzaW9uRGF0YVwiXG4gICAgKHJlcG9ydExvYWRlZCk9XCJvblJlcG9ydExvYWRlZCgkZXZlbnQpXCJcbiAgPjwvbGliLXJlcG9ydC12aWV3ZXI+XG48L25nLXRlbXBsYXRlPlxuPGxpYi12ZXJzaW9uLWZvb3RlciBbdmVyc2lvbl09XCJ2ZXJzaW9uXCI+PC9saWItdmVyc2lvbi1mb290ZXI+XG4iXX0=
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { ComponentsModule } from '@alimetry/widget-core';
|
|
4
|
+
import { EditSessionWidgetComponent } from './edit-session-widget.component';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
export class EditSessionWidgetModule {
|
|
7
|
+
}
|
|
8
|
+
EditSessionWidgetModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: EditSessionWidgetModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
9
|
+
EditSessionWidgetModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: EditSessionWidgetModule, declarations: [EditSessionWidgetComponent], imports: [CommonModule, ComponentsModule], exports: [EditSessionWidgetComponent] });
|
|
10
|
+
EditSessionWidgetModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: EditSessionWidgetModule, imports: [CommonModule, ComponentsModule] });
|
|
11
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: EditSessionWidgetModule, decorators: [{
|
|
12
|
+
type: NgModule,
|
|
13
|
+
args: [{
|
|
14
|
+
declarations: [EditSessionWidgetComponent],
|
|
15
|
+
imports: [CommonModule, ComponentsModule],
|
|
16
|
+
exports: [EditSessionWidgetComponent],
|
|
17
|
+
}]
|
|
18
|
+
}] });
|
|
19
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWRpdC1zZXNzaW9uLXdpZGdldC5tb2R1bGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi93aWRnZXRzL2VkaXQtc2Vzc2lvbi13aWRnZXQvc3JjL2xpYi9lZGl0LXNlc3Npb24td2lkZ2V0Lm1vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsMEJBQTBCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQzs7QUFPN0UsTUFBTSxPQUFPLHVCQUF1Qjs7cUhBQXZCLHVCQUF1QjtzSEFBdkIsdUJBQXVCLGlCQUpuQiwwQkFBMEIsYUFDL0IsWUFBWSxFQUFFLGdCQUFnQixhQUM5QiwwQkFBMEI7c0hBRXpCLHVCQUF1QixZQUh4QixZQUFZLEVBQUUsZ0JBQWdCOzRGQUc3Qix1QkFBdUI7a0JBTG5DLFFBQVE7bUJBQUM7b0JBQ1IsWUFBWSxFQUFFLENBQUMsMEJBQTBCLENBQUM7b0JBQzFDLE9BQU8sRUFBRSxDQUFDLFlBQVksRUFBRSxnQkFBZ0IsQ0FBQztvQkFDekMsT0FBTyxFQUFFLENBQUMsMEJBQTBCLENBQUM7aUJBQ3RDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgTmdNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQgeyBDb21wb25lbnRzTW9kdWxlIH0gZnJvbSAnQGFsaW1ldHJ5L3dpZGdldC1jb3JlJztcbmltcG9ydCB7IEVkaXRTZXNzaW9uV2lkZ2V0Q29tcG9uZW50IH0gZnJvbSAnLi9lZGl0LXNlc3Npb24td2lkZ2V0LmNvbXBvbmVudCc7XG5cbkBOZ01vZHVsZSh7XG4gIGRlY2xhcmF0aW9uczogW0VkaXRTZXNzaW9uV2lkZ2V0Q29tcG9uZW50XSxcbiAgaW1wb3J0czogW0NvbW1vbk1vZHVsZSwgQ29tcG9uZW50c01vZHVsZV0sXG4gIGV4cG9ydHM6IFtFZGl0U2Vzc2lvbldpZGdldENvbXBvbmVudF0sXG59KVxuZXhwb3J0IGNsYXNzIEVkaXRTZXNzaW9uV2lkZ2V0TW9kdWxlIHt9XG4iXX0=
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// keep in step with "version" in widgets/edit-session-widget/package.json, which ng-packagr won't
|
|
2
|
+
// let src import
|
|
3
|
+
export const EDIT_SESSION_WIDGET_VERSION = '1.0.0-dev.0';
|
|
4
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmVyc2lvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3dpZGdldHMvZWRpdC1zZXNzaW9uLXdpZGdldC9zcmMvbGliL3ZlcnNpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsa0dBQWtHO0FBQ2xHLGlCQUFpQjtBQUNqQixNQUFNLENBQUMsTUFBTSwyQkFBMkIsR0FBRyxhQUFhLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBrZWVwIGluIHN0ZXAgd2l0aCBcInZlcnNpb25cIiBpbiB3aWRnZXRzL2VkaXQtc2Vzc2lvbi13aWRnZXQvcGFja2FnZS5qc29uLCB3aGljaCBuZy1wYWNrYWdyIHdvbid0XG4vLyBsZXQgc3JjIGltcG9ydFxuZXhwb3J0IGNvbnN0IEVESVRfU0VTU0lPTl9XSURHRVRfVkVSU0lPTiA9ICcxLjAuMC1kZXYuMCc7XG4iXX0=
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Public API Surface of edit-session-widget
|
|
3
|
+
*/
|
|
4
|
+
export * from './lib/edit-session-widget.component';
|
|
5
|
+
export * from './lib/edit-session-widget.module';
|
|
6
|
+
export * from './lib/version';
|
|
7
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3dpZGdldHMvZWRpdC1zZXNzaW9uLXdpZGdldC9zcmMvcHVibGljLWFwaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILGNBQWMscUNBQXFDLENBQUM7QUFDcEQsY0FBYyxrQ0FBa0MsQ0FBQztBQUNqRCxjQUFjLGVBQWUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qXG4gKiBQdWJsaWMgQVBJIFN1cmZhY2Ugb2YgZWRpdC1zZXNzaW9uLXdpZGdldFxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vbGliL2VkaXQtc2Vzc2lvbi13aWRnZXQuY29tcG9uZW50JztcbmV4cG9ydCAqIGZyb20gJy4vbGliL2VkaXQtc2Vzc2lvbi13aWRnZXQubW9kdWxlJztcbmV4cG9ydCAqIGZyb20gJy4vbGliL3ZlcnNpb24nO1xuIl19
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { Component, Input, ViewChild, NgModule } from '@angular/core';
|
|
3
|
+
import * as i1 from '@alimetry/widget-core';
|
|
4
|
+
import { isReportGenerating, statusOf, isReportGenerated, reportLinkOf, sessionNumberOf, ServicesConfigService, ServicesService, SessionSearchComponent, ComponentsModule } from '@alimetry/widget-core';
|
|
5
|
+
import { Subject, interval, exhaustMap, map, catchError, EMPTY, filter, take, takeUntil, timer, switchMap } from 'rxjs';
|
|
6
|
+
import * as i2 from '@angular/common';
|
|
7
|
+
import { CommonModule } from '@angular/common';
|
|
8
|
+
|
|
9
|
+
// keep in step with "version" in widgets/edit-session-widget/package.json, which ng-packagr won't
|
|
10
|
+
// let src import
|
|
11
|
+
const EDIT_SESSION_WIDGET_VERSION = '1.0.0-dev.0';
|
|
12
|
+
|
|
13
|
+
// how often the widget asks the cloud whether the report it is waiting on is ready
|
|
14
|
+
const REPORT_POLL_INTERVAL_MS = 30000;
|
|
15
|
+
// how often it then re-reads the report link and the file behind it, waiting for that file to be
|
|
16
|
+
// the newly generated one rather than the one it replaced
|
|
17
|
+
const REPORT_FILE_POLL_INTERVAL_MS = 5000;
|
|
18
|
+
class EditSessionWidgetComponent {
|
|
19
|
+
constructor(servicesConfig, services) {
|
|
20
|
+
this.servicesConfig = servicesConfig;
|
|
21
|
+
this.services = services;
|
|
22
|
+
this.version = EDIT_SESSION_WIDGET_VERSION;
|
|
23
|
+
this.configError = null;
|
|
24
|
+
// set when a poll gave up because the record stopped short of a generated report
|
|
25
|
+
this.reportError = null;
|
|
26
|
+
this.reportBaseline = null;
|
|
27
|
+
// the generation of the report currently on screen, as the viewer last loaded it
|
|
28
|
+
this.reportLastModified = null;
|
|
29
|
+
// set while a poll is running that started before the viewer had read the report on screen, so
|
|
30
|
+
// the generation that poll is waiting to replace has still to be recorded
|
|
31
|
+
this.needsBaseline = false;
|
|
32
|
+
// ends the poll a save started: on the next one, on a new search, and on teardown
|
|
33
|
+
this.stopPolling$ = new Subject();
|
|
34
|
+
}
|
|
35
|
+
ngOnChanges() {
|
|
36
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
37
|
+
const deviceDataModelId = (_c = (_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.deviceDataModelId) === null || _b === void 0 ? void 0 : _b.trim()) !== null && _c !== void 0 ? _c : '';
|
|
38
|
+
const apiUrl = (_f = (_e = (_d = this.config) === null || _d === void 0 ? void 0 : _d.apiUrl) === null || _e === void 0 ? void 0 : _e.trim()) !== null && _f !== void 0 ? _f : '';
|
|
39
|
+
const appDataPropertySetId = (_j = (_h = (_g = this.config) === null || _g === void 0 ? void 0 : _g.appDataPropertySetId) === null || _h === void 0 ? void 0 : _h.trim()) !== null && _j !== void 0 ? _j : '';
|
|
40
|
+
const devicePropertySetId = (_m = (_l = (_k = this.config) === null || _k === void 0 ? void 0 : _k.devicePropertySetId) === null || _l === void 0 ? void 0 : _l.trim()) !== null && _m !== void 0 ? _m : '';
|
|
41
|
+
if (!deviceDataModelId || !apiUrl) {
|
|
42
|
+
this.configError =
|
|
43
|
+
'This widget is missing required configuration values. Please check the widget configuration.';
|
|
44
|
+
this.sessionData = undefined;
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
this.configError = null;
|
|
48
|
+
// hand the values the services layer needs to it through dependency injection
|
|
49
|
+
this.servicesConfig.setConfig({
|
|
50
|
+
deviceDataModelId,
|
|
51
|
+
apiUrl,
|
|
52
|
+
appDataPropertySetId,
|
|
53
|
+
devicePropertySetId,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
onSessionDataLoaded(sessionData) {
|
|
57
|
+
// whatever the last save was waiting on, it is not this session
|
|
58
|
+
this.stopPolling$.next();
|
|
59
|
+
this.sessionData = sessionData;
|
|
60
|
+
this.reportError = null;
|
|
61
|
+
this.reportBaseline = null;
|
|
62
|
+
this.reportLastModified = null;
|
|
63
|
+
this.needsBaseline = false;
|
|
64
|
+
// a session that is already regenerating when it is searched for is waited on the same way one
|
|
65
|
+
// this widget just regenerated is, so reloading the page picks the wait back up
|
|
66
|
+
if (isReportGenerating(statusOf(sessionData))) {
|
|
67
|
+
this.onRegenerateRequested(true);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// clears the search box and drops the session, which empties the form and the report with it
|
|
71
|
+
onCancelled() {
|
|
72
|
+
var _a;
|
|
73
|
+
(_a = this.sessionSearch) === null || _a === void 0 ? void 0 : _a.clear();
|
|
74
|
+
this.onSessionDataLoaded(undefined);
|
|
75
|
+
}
|
|
76
|
+
onReportLoaded(lastModified) {
|
|
77
|
+
this.reportLastModified = lastModified;
|
|
78
|
+
// the poll a reload started has no generation to wait past until this first read arrives
|
|
79
|
+
if (this.needsBaseline) {
|
|
80
|
+
this.reportBaseline = lastModified;
|
|
81
|
+
this.needsBaseline = false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
onRegenerateRequested(requested) {
|
|
85
|
+
if (!requested) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
this.reportError = null;
|
|
89
|
+
this.reportBaseline = this.reportLastModified;
|
|
90
|
+
this.needsBaseline = !this.reportBaseline;
|
|
91
|
+
this.pollForReport();
|
|
92
|
+
}
|
|
93
|
+
ngOnDestroy() {
|
|
94
|
+
this.stopPolling$.next();
|
|
95
|
+
this.stopPolling$.complete();
|
|
96
|
+
}
|
|
97
|
+
pollForReport() {
|
|
98
|
+
const sessionNumber = this.sessionNumber;
|
|
99
|
+
if (!sessionNumber) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
// whichever poll is already running is waiting on a report this save has superseded
|
|
103
|
+
this.stopPolling$.next();
|
|
104
|
+
interval(REPORT_POLL_INTERVAL_MS)
|
|
105
|
+
.pipe(exhaustMap(() => this.services.getSessionProperty(sessionNumber, 'Status').pipe(map((sessionData) => statusOf(sessionData)), catchError(() => EMPTY))),
|
|
106
|
+
// anything other than "generating report" is as far as this report is going to get, so the
|
|
107
|
+
// poll ends on it either way rather than waiting out a status that will never change
|
|
108
|
+
filter((status) => !isReportGenerating(status)), take(1), takeUntil(this.stopPolling$))
|
|
109
|
+
.subscribe((status) => {
|
|
110
|
+
if (isReportGenerated(status)) {
|
|
111
|
+
this.pollForNewReportFile(sessionNumber);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
this.onReportStopped(sessionNumber);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
pollForNewReportFile(sessionNumber) {
|
|
119
|
+
// with no generation to compare against there is nothing to wait for: whatever the link points
|
|
120
|
+
// at is the report to show, and reading it here only downloads a file the viewer downloads again
|
|
121
|
+
if (!this.reportBaseline) {
|
|
122
|
+
this.loadSession(sessionNumber);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
// poll to check if new report is ready
|
|
126
|
+
timer(0, REPORT_FILE_POLL_INTERVAL_MS)
|
|
127
|
+
.pipe(exhaustMap(() => this.services.getSessionProperty(sessionNumber, 'PdfReport').pipe(map((sessionData) => reportLinkOf(sessionData)), filter((link) => !!link), switchMap((link) => this.services.getReportLastModified(link)), catchError(() => EMPTY))), filter((lastModified) => this.isNewReport(lastModified)), take(1), takeUntil(this.stopPolling$))
|
|
128
|
+
.subscribe(() => this.loadSession(sessionNumber));
|
|
129
|
+
}
|
|
130
|
+
// the record settled on a status that is not a generated report: say so, and read the record back
|
|
131
|
+
// so the form unlocks rather than staying held by a regeneration that is over
|
|
132
|
+
onReportStopped(sessionNumber) {
|
|
133
|
+
this.reportError = 'Report regeneration failed. Please try again.';
|
|
134
|
+
this.loadSession(sessionNumber);
|
|
135
|
+
}
|
|
136
|
+
// the polls above read one property at a time, so the whole record is read back once, here, to
|
|
137
|
+
// show the session the regeneration has left behind
|
|
138
|
+
loadSession(sessionNumber) {
|
|
139
|
+
this.services
|
|
140
|
+
.getSessionData(sessionNumber)
|
|
141
|
+
.pipe(filter((sessionData) => !!sessionData), catchError(() => EMPTY), takeUntil(this.stopPolling$))
|
|
142
|
+
.subscribe((sessionData) => this.showSession(sessionData));
|
|
143
|
+
}
|
|
144
|
+
showSession(sessionData) {
|
|
145
|
+
this.needsBaseline = false;
|
|
146
|
+
this.sessionData = sessionData;
|
|
147
|
+
}
|
|
148
|
+
// check if report is new
|
|
149
|
+
isNewReport(lastModified) {
|
|
150
|
+
const baseline = this.reportBaseline;
|
|
151
|
+
return !!lastModified && !!baseline && lastModified.getTime() > baseline.getTime();
|
|
152
|
+
}
|
|
153
|
+
get sessionNumber() {
|
|
154
|
+
return sessionNumberOf(this.sessionData);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
EditSessionWidgetComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: EditSessionWidgetComponent, deps: [{ token: i1.ServicesConfigService }, { token: i1.ServicesService }], target: i0.ɵɵFactoryTarget.Component });
|
|
158
|
+
EditSessionWidgetComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: EditSessionWidgetComponent, selector: "lib-edit-session-widget", inputs: { config: "config" }, providers: [ServicesConfigService, ServicesService], viewQueries: [{ propertyName: "sessionSearch", first: true, predicate: SessionSearchComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<p *ngIf=\"configError; else sessionSearch\" class=\"edit-session-widget__error\" role=\"alert\">\n {{ configError }}\n</p>\n<ng-template #sessionSearch>\n <lib-session-search (sessionDataLoaded)=\"onSessionDataLoaded($event)\"></lib-session-search>\n <p *ngIf=\"!sessionData\" class=\"edit-session-widget__empty\">\n Search for a session to view its report.\n </p>\n <lib-detail-edit\n [sessionData]=\"sessionData\"\n (regenerateRequested)=\"onRegenerateRequested($event)\"\n (cancelled)=\"onCancelled()\"\n ></lib-detail-edit>\n <p *ngIf=\"reportError\" class=\"edit-session-widget__error\" role=\"alert\">\n {{ reportError }}\n </p>\n <lib-report-viewer\n [sessionData]=\"sessionData\"\n (reportLoaded)=\"onReportLoaded($event)\"\n ></lib-report-viewer>\n</ng-template>\n<lib-version-footer [version]=\"version\"></lib-version-footer>\n", styles: [".edit-session-widget__empty{margin:1rem 0 0;color:#6c757d;font-size:14px}.edit-session-widget__error{margin:0;color:#b02a37}\n"], dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i1.SessionSearchComponent, selector: "lib-session-search", outputs: ["sessionDataLoaded"] }, { kind: "component", type: i1.ReportViewerComponent, selector: "lib-report-viewer", inputs: ["sessionData"], outputs: ["reportLoaded"] }, { kind: "component", type: i1.DetailEditComponent, selector: "lib-detail-edit", inputs: ["sessionData"], outputs: ["regenerateRequested", "cancelled"] }, { kind: "component", type: i1.VersionFooterComponent, selector: "lib-version-footer", inputs: ["version"] }] });
|
|
159
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: EditSessionWidgetComponent, decorators: [{
|
|
160
|
+
type: Component,
|
|
161
|
+
args: [{ selector: 'lib-edit-session-widget', providers: [ServicesConfigService, ServicesService], template: "<p *ngIf=\"configError; else sessionSearch\" class=\"edit-session-widget__error\" role=\"alert\">\n {{ configError }}\n</p>\n<ng-template #sessionSearch>\n <lib-session-search (sessionDataLoaded)=\"onSessionDataLoaded($event)\"></lib-session-search>\n <p *ngIf=\"!sessionData\" class=\"edit-session-widget__empty\">\n Search for a session to view its report.\n </p>\n <lib-detail-edit\n [sessionData]=\"sessionData\"\n (regenerateRequested)=\"onRegenerateRequested($event)\"\n (cancelled)=\"onCancelled()\"\n ></lib-detail-edit>\n <p *ngIf=\"reportError\" class=\"edit-session-widget__error\" role=\"alert\">\n {{ reportError }}\n </p>\n <lib-report-viewer\n [sessionData]=\"sessionData\"\n (reportLoaded)=\"onReportLoaded($event)\"\n ></lib-report-viewer>\n</ng-template>\n<lib-version-footer [version]=\"version\"></lib-version-footer>\n", styles: [".edit-session-widget__empty{margin:1rem 0 0;color:#6c757d;font-size:14px}.edit-session-widget__error{margin:0;color:#b02a37}\n"] }]
|
|
162
|
+
}], ctorParameters: function () { return [{ type: i1.ServicesConfigService }, { type: i1.ServicesService }]; }, propDecorators: { config: [{
|
|
163
|
+
type: Input
|
|
164
|
+
}], sessionSearch: [{
|
|
165
|
+
type: ViewChild,
|
|
166
|
+
args: [SessionSearchComponent]
|
|
167
|
+
}] } });
|
|
168
|
+
|
|
169
|
+
class EditSessionWidgetModule {
|
|
170
|
+
}
|
|
171
|
+
EditSessionWidgetModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: EditSessionWidgetModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
172
|
+
EditSessionWidgetModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: EditSessionWidgetModule, declarations: [EditSessionWidgetComponent], imports: [CommonModule, ComponentsModule], exports: [EditSessionWidgetComponent] });
|
|
173
|
+
EditSessionWidgetModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: EditSessionWidgetModule, imports: [CommonModule, ComponentsModule] });
|
|
174
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: EditSessionWidgetModule, decorators: [{
|
|
175
|
+
type: NgModule,
|
|
176
|
+
args: [{
|
|
177
|
+
declarations: [EditSessionWidgetComponent],
|
|
178
|
+
imports: [CommonModule, ComponentsModule],
|
|
179
|
+
exports: [EditSessionWidgetComponent],
|
|
180
|
+
}]
|
|
181
|
+
}] });
|
|
182
|
+
|
|
183
|
+
/*
|
|
184
|
+
* Public API Surface of edit-session-widget
|
|
185
|
+
*/
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Generated bundle index. Do not edit.
|
|
189
|
+
*/
|
|
190
|
+
|
|
191
|
+
export { EDIT_SESSION_WIDGET_VERSION, EditSessionWidgetComponent, EditSessionWidgetModule };
|
|
192
|
+
//# sourceMappingURL=alimetry-edit-session-widget.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alimetry-edit-session-widget.mjs","sources":["../../../widgets/edit-session-widget/src/lib/version.ts","../../../widgets/edit-session-widget/src/lib/edit-session-widget.component.ts","../../../widgets/edit-session-widget/src/lib/edit-session-widget.component.html","../../../widgets/edit-session-widget/src/lib/edit-session-widget.module.ts","../../../widgets/edit-session-widget/src/public-api.ts","../../../widgets/edit-session-widget/src/alimetry-edit-session-widget.ts"],"sourcesContent":["// keep in step with \"version\" in widgets/edit-session-widget/package.json, which ng-packagr won't\n// let src import\nexport const EDIT_SESSION_WIDGET_VERSION = '1.0.0-dev.0';\n","import { Component, Input, OnChanges, OnDestroy, ViewChild } from '@angular/core';\nimport {\n DeviceData,\n ServicesConfigService,\n ServicesService,\n SessionSearchComponent,\n isReportGenerated,\n isReportGenerating,\n reportLinkOf,\n sessionNumberOf,\n statusOf,\n} from '@alimetry/widget-core';\nimport {\n catchError,\n EMPTY,\n exhaustMap,\n filter,\n interval,\n map,\n Subject,\n switchMap,\n take,\n takeUntil,\n timer,\n} from 'rxjs';\nimport { EDIT_SESSION_WIDGET_VERSION } from './version';\n\n// how often the widget asks the cloud whether the report it is waiting on is ready\nconst REPORT_POLL_INTERVAL_MS = 30_000;\n\n// how often it then re-reads the report link and the file behind it, waiting for that file to be\n// the newly generated one rather than the one it replaced\nconst REPORT_FILE_POLL_INTERVAL_MS = 5_000;\n\n@Component({\n selector: 'lib-edit-session-widget',\n templateUrl: './edit-session-widget.component.html',\n styleUrls: ['./edit-session-widget.component.css'],\n // scoped to this widget so each instance runs against the config it was given\n providers: [ServicesConfigService, ServicesService],\n})\nexport class EditSessionWidgetComponent implements OnChanges, OnDestroy {\n // TODO: change the type of the input to not be any\n @Input() config: any;\n\n readonly version = EDIT_SESSION_WIDGET_VERSION;\n\n // inside the config check's template, so it is only there once the config is valid\n @ViewChild(SessionSearchComponent) private sessionSearch?: SessionSearchComponent;\n\n sessionData?: DeviceData;\n configError: string | null = null;\n\n // set when a poll gave up because the record stopped short of a generated report\n reportError: string | null = null;\n\n reportBaseline: Date | null = null;\n\n // the generation of the report currently on screen, as the viewer last loaded it\n private reportLastModified: Date | null = null;\n\n // set while a poll is running that started before the viewer had read the report on screen, so\n // the generation that poll is waiting to replace has still to be recorded\n private needsBaseline = false;\n\n // ends the poll a save started: on the next one, on a new search, and on teardown\n private readonly stopPolling$ = new Subject<void>();\n\n constructor(\n private servicesConfig: ServicesConfigService,\n private services: ServicesService,\n ) {}\n\n ngOnChanges(): void {\n const deviceDataModelId: string = this.config?.deviceDataModelId?.trim() ?? '';\n const apiUrl: string = this.config?.apiUrl?.trim() ?? '';\n const appDataPropertySetId: string = this.config?.appDataPropertySetId?.trim() ?? '';\n const devicePropertySetId: string = this.config?.devicePropertySetId?.trim() ?? '';\n\n if (!deviceDataModelId || !apiUrl) {\n this.configError =\n 'This widget is missing required configuration values. Please check the widget configuration.';\n this.sessionData = undefined;\n return;\n }\n\n this.configError = null;\n // hand the values the services layer needs to it through dependency injection\n this.servicesConfig.setConfig({\n deviceDataModelId,\n apiUrl,\n appDataPropertySetId,\n devicePropertySetId,\n });\n }\n\n onSessionDataLoaded(sessionData: DeviceData | undefined): void {\n // whatever the last save was waiting on, it is not this session\n this.stopPolling$.next();\n\n this.sessionData = sessionData;\n this.reportError = null;\n this.reportBaseline = null;\n this.reportLastModified = null;\n this.needsBaseline = false;\n\n // a session that is already regenerating when it is searched for is waited on the same way one\n // this widget just regenerated is, so reloading the page picks the wait back up\n if (isReportGenerating(statusOf(sessionData))) {\n this.onRegenerateRequested(true);\n }\n }\n\n // clears the search box and drops the session, which empties the form and the report with it\n onCancelled(): void {\n this.sessionSearch?.clear();\n this.onSessionDataLoaded(undefined);\n }\n\n onReportLoaded(lastModified: Date | null): void {\n this.reportLastModified = lastModified;\n\n // the poll a reload started has no generation to wait past until this first read arrives\n if (this.needsBaseline) {\n this.reportBaseline = lastModified;\n this.needsBaseline = false;\n }\n }\n\n onRegenerateRequested(requested: boolean): void {\n if (!requested) {\n return;\n }\n\n this.reportError = null;\n this.reportBaseline = this.reportLastModified;\n this.needsBaseline = !this.reportBaseline;\n this.pollForReport();\n }\n\n ngOnDestroy(): void {\n this.stopPolling$.next();\n this.stopPolling$.complete();\n }\n\n private pollForReport(): void {\n const sessionNumber = this.sessionNumber;\n if (!sessionNumber) {\n return;\n }\n\n // whichever poll is already running is waiting on a report this save has superseded\n this.stopPolling$.next();\n\n interval(REPORT_POLL_INTERVAL_MS)\n .pipe(\n exhaustMap(() =>\n this.services.getSessionProperty(sessionNumber, 'Status').pipe(\n map((sessionData) => statusOf(sessionData)),\n catchError(() => EMPTY),\n ),\n ),\n // anything other than \"generating report\" is as far as this report is going to get, so the\n // poll ends on it either way rather than waiting out a status that will never change\n filter((status) => !isReportGenerating(status)),\n take(1),\n takeUntil(this.stopPolling$),\n )\n .subscribe((status) => {\n if (isReportGenerated(status)) {\n this.pollForNewReportFile(sessionNumber);\n } else {\n this.onReportStopped(sessionNumber);\n }\n });\n }\n\n private pollForNewReportFile(sessionNumber: string): void {\n // with no generation to compare against there is nothing to wait for: whatever the link points\n // at is the report to show, and reading it here only downloads a file the viewer downloads again\n if (!this.reportBaseline) {\n this.loadSession(sessionNumber);\n return;\n }\n\n // poll to check if new report is ready\n timer(0, REPORT_FILE_POLL_INTERVAL_MS)\n .pipe(\n exhaustMap(() =>\n this.services.getSessionProperty(sessionNumber, 'PdfReport').pipe(\n map((sessionData) => reportLinkOf(sessionData)),\n filter((link) => !!link),\n switchMap((link) => this.services.getReportLastModified(link)),\n catchError(() => EMPTY),\n ),\n ),\n filter((lastModified) => this.isNewReport(lastModified)),\n take(1),\n takeUntil(this.stopPolling$),\n )\n .subscribe(() => this.loadSession(sessionNumber));\n }\n\n // the record settled on a status that is not a generated report: say so, and read the record back\n // so the form unlocks rather than staying held by a regeneration that is over\n private onReportStopped(sessionNumber: string): void {\n this.reportError = 'Report regeneration failed. Please try again.';\n this.loadSession(sessionNumber);\n }\n\n // the polls above read one property at a time, so the whole record is read back once, here, to\n // show the session the regeneration has left behind\n private loadSession(sessionNumber: string): void {\n this.services\n .getSessionData(sessionNumber)\n .pipe(\n filter((sessionData): sessionData is DeviceData => !!sessionData),\n catchError(() => EMPTY),\n takeUntil(this.stopPolling$),\n )\n .subscribe((sessionData) => this.showSession(sessionData));\n }\n\n private showSession(sessionData: DeviceData): void {\n this.needsBaseline = false;\n this.sessionData = sessionData;\n }\n\n // check if report is new\n private isNewReport(lastModified: Date | null): boolean {\n const baseline = this.reportBaseline;\n return !!lastModified && !!baseline && lastModified.getTime() > baseline.getTime();\n }\n\n private get sessionNumber(): string {\n return sessionNumberOf(this.sessionData);\n }\n}\n","<p *ngIf=\"configError; else sessionSearch\" class=\"edit-session-widget__error\" role=\"alert\">\n {{ configError }}\n</p>\n<ng-template #sessionSearch>\n <lib-session-search (sessionDataLoaded)=\"onSessionDataLoaded($event)\"></lib-session-search>\n <p *ngIf=\"!sessionData\" class=\"edit-session-widget__empty\">\n Search for a session to view its report.\n </p>\n <lib-detail-edit\n [sessionData]=\"sessionData\"\n (regenerateRequested)=\"onRegenerateRequested($event)\"\n (cancelled)=\"onCancelled()\"\n ></lib-detail-edit>\n <p *ngIf=\"reportError\" class=\"edit-session-widget__error\" role=\"alert\">\n {{ reportError }}\n </p>\n <lib-report-viewer\n [sessionData]=\"sessionData\"\n (reportLoaded)=\"onReportLoaded($event)\"\n ></lib-report-viewer>\n</ng-template>\n<lib-version-footer [version]=\"version\"></lib-version-footer>\n","import { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { ComponentsModule } from '@alimetry/widget-core';\nimport { EditSessionWidgetComponent } from './edit-session-widget.component';\n\n@NgModule({\n declarations: [EditSessionWidgetComponent],\n imports: [CommonModule, ComponentsModule],\n exports: [EditSessionWidgetComponent],\n})\nexport class EditSessionWidgetModule {}\n","/*\n * Public API Surface of edit-session-widget\n */\n\nexport * from './lib/edit-session-widget.component';\nexport * from './lib/edit-session-widget.module';\nexport * from './lib/version';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { Component, Input, ViewChild, NgModule } from '@angular/core';
|
|
3
|
+
import * as i1 from '@alimetry/widget-core';
|
|
4
|
+
import { isReportGenerating, statusOf, isReportGenerated, reportLinkOf, sessionNumberOf, ServicesConfigService, ServicesService, SessionSearchComponent, ComponentsModule } from '@alimetry/widget-core';
|
|
5
|
+
import { Subject, interval, exhaustMap, map, catchError, EMPTY, filter, take, takeUntil, timer, switchMap } from 'rxjs';
|
|
6
|
+
import * as i2 from '@angular/common';
|
|
7
|
+
import { CommonModule } from '@angular/common';
|
|
8
|
+
|
|
9
|
+
// keep in step with "version" in widgets/edit-session-widget/package.json, which ng-packagr won't
|
|
10
|
+
// let src import
|
|
11
|
+
const EDIT_SESSION_WIDGET_VERSION = '1.0.0-dev.0';
|
|
12
|
+
|
|
13
|
+
// how often the widget asks the cloud whether the report it is waiting on is ready
|
|
14
|
+
const REPORT_POLL_INTERVAL_MS = 30000;
|
|
15
|
+
// how often it then re-reads the report link and the file behind it, waiting for that file to be
|
|
16
|
+
// the newly generated one rather than the one it replaced
|
|
17
|
+
const REPORT_FILE_POLL_INTERVAL_MS = 5000;
|
|
18
|
+
class EditSessionWidgetComponent {
|
|
19
|
+
constructor(servicesConfig, services) {
|
|
20
|
+
this.servicesConfig = servicesConfig;
|
|
21
|
+
this.services = services;
|
|
22
|
+
this.version = EDIT_SESSION_WIDGET_VERSION;
|
|
23
|
+
this.configError = null;
|
|
24
|
+
// set when a poll gave up because the record stopped short of a generated report
|
|
25
|
+
this.reportError = null;
|
|
26
|
+
this.reportBaseline = null;
|
|
27
|
+
// the generation of the report currently on screen, as the viewer last loaded it
|
|
28
|
+
this.reportLastModified = null;
|
|
29
|
+
// set while a poll is running that started before the viewer had read the report on screen, so
|
|
30
|
+
// the generation that poll is waiting to replace has still to be recorded
|
|
31
|
+
this.needsBaseline = false;
|
|
32
|
+
// ends the poll a save started: on the next one, on a new search, and on teardown
|
|
33
|
+
this.stopPolling$ = new Subject();
|
|
34
|
+
}
|
|
35
|
+
ngOnChanges() {
|
|
36
|
+
const deviceDataModelId = this.config?.deviceDataModelId?.trim() ?? '';
|
|
37
|
+
const apiUrl = this.config?.apiUrl?.trim() ?? '';
|
|
38
|
+
const appDataPropertySetId = this.config?.appDataPropertySetId?.trim() ?? '';
|
|
39
|
+
const devicePropertySetId = this.config?.devicePropertySetId?.trim() ?? '';
|
|
40
|
+
if (!deviceDataModelId || !apiUrl) {
|
|
41
|
+
this.configError =
|
|
42
|
+
'This widget is missing required configuration values. Please check the widget configuration.';
|
|
43
|
+
this.sessionData = undefined;
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
this.configError = null;
|
|
47
|
+
// hand the values the services layer needs to it through dependency injection
|
|
48
|
+
this.servicesConfig.setConfig({
|
|
49
|
+
deviceDataModelId,
|
|
50
|
+
apiUrl,
|
|
51
|
+
appDataPropertySetId,
|
|
52
|
+
devicePropertySetId,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
onSessionDataLoaded(sessionData) {
|
|
56
|
+
// whatever the last save was waiting on, it is not this session
|
|
57
|
+
this.stopPolling$.next();
|
|
58
|
+
this.sessionData = sessionData;
|
|
59
|
+
this.reportError = null;
|
|
60
|
+
this.reportBaseline = null;
|
|
61
|
+
this.reportLastModified = null;
|
|
62
|
+
this.needsBaseline = false;
|
|
63
|
+
// a session that is already regenerating when it is searched for is waited on the same way one
|
|
64
|
+
// this widget just regenerated is, so reloading the page picks the wait back up
|
|
65
|
+
if (isReportGenerating(statusOf(sessionData))) {
|
|
66
|
+
this.onRegenerateRequested(true);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// clears the search box and drops the session, which empties the form and the report with it
|
|
70
|
+
onCancelled() {
|
|
71
|
+
this.sessionSearch?.clear();
|
|
72
|
+
this.onSessionDataLoaded(undefined);
|
|
73
|
+
}
|
|
74
|
+
onReportLoaded(lastModified) {
|
|
75
|
+
this.reportLastModified = lastModified;
|
|
76
|
+
// the poll a reload started has no generation to wait past until this first read arrives
|
|
77
|
+
if (this.needsBaseline) {
|
|
78
|
+
this.reportBaseline = lastModified;
|
|
79
|
+
this.needsBaseline = false;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
onRegenerateRequested(requested) {
|
|
83
|
+
if (!requested) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
this.reportError = null;
|
|
87
|
+
this.reportBaseline = this.reportLastModified;
|
|
88
|
+
this.needsBaseline = !this.reportBaseline;
|
|
89
|
+
this.pollForReport();
|
|
90
|
+
}
|
|
91
|
+
ngOnDestroy() {
|
|
92
|
+
this.stopPolling$.next();
|
|
93
|
+
this.stopPolling$.complete();
|
|
94
|
+
}
|
|
95
|
+
pollForReport() {
|
|
96
|
+
const sessionNumber = this.sessionNumber;
|
|
97
|
+
if (!sessionNumber) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
// whichever poll is already running is waiting on a report this save has superseded
|
|
101
|
+
this.stopPolling$.next();
|
|
102
|
+
interval(REPORT_POLL_INTERVAL_MS)
|
|
103
|
+
.pipe(exhaustMap(() => this.services.getSessionProperty(sessionNumber, 'Status').pipe(map((sessionData) => statusOf(sessionData)), catchError(() => EMPTY))),
|
|
104
|
+
// anything other than "generating report" is as far as this report is going to get, so the
|
|
105
|
+
// poll ends on it either way rather than waiting out a status that will never change
|
|
106
|
+
filter((status) => !isReportGenerating(status)), take(1), takeUntil(this.stopPolling$))
|
|
107
|
+
.subscribe((status) => {
|
|
108
|
+
if (isReportGenerated(status)) {
|
|
109
|
+
this.pollForNewReportFile(sessionNumber);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
this.onReportStopped(sessionNumber);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
pollForNewReportFile(sessionNumber) {
|
|
117
|
+
// with no generation to compare against there is nothing to wait for: whatever the link points
|
|
118
|
+
// at is the report to show, and reading it here only downloads a file the viewer downloads again
|
|
119
|
+
if (!this.reportBaseline) {
|
|
120
|
+
this.loadSession(sessionNumber);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
// poll to check if new report is ready
|
|
124
|
+
timer(0, REPORT_FILE_POLL_INTERVAL_MS)
|
|
125
|
+
.pipe(exhaustMap(() => this.services.getSessionProperty(sessionNumber, 'PdfReport').pipe(map((sessionData) => reportLinkOf(sessionData)), filter((link) => !!link), switchMap((link) => this.services.getReportLastModified(link)), catchError(() => EMPTY))), filter((lastModified) => this.isNewReport(lastModified)), take(1), takeUntil(this.stopPolling$))
|
|
126
|
+
.subscribe(() => this.loadSession(sessionNumber));
|
|
127
|
+
}
|
|
128
|
+
// the record settled on a status that is not a generated report: say so, and read the record back
|
|
129
|
+
// so the form unlocks rather than staying held by a regeneration that is over
|
|
130
|
+
onReportStopped(sessionNumber) {
|
|
131
|
+
this.reportError = 'Report regeneration failed. Please try again.';
|
|
132
|
+
this.loadSession(sessionNumber);
|
|
133
|
+
}
|
|
134
|
+
// the polls above read one property at a time, so the whole record is read back once, here, to
|
|
135
|
+
// show the session the regeneration has left behind
|
|
136
|
+
loadSession(sessionNumber) {
|
|
137
|
+
this.services
|
|
138
|
+
.getSessionData(sessionNumber)
|
|
139
|
+
.pipe(filter((sessionData) => !!sessionData), catchError(() => EMPTY), takeUntil(this.stopPolling$))
|
|
140
|
+
.subscribe((sessionData) => this.showSession(sessionData));
|
|
141
|
+
}
|
|
142
|
+
showSession(sessionData) {
|
|
143
|
+
this.needsBaseline = false;
|
|
144
|
+
this.sessionData = sessionData;
|
|
145
|
+
}
|
|
146
|
+
// check if report is new
|
|
147
|
+
isNewReport(lastModified) {
|
|
148
|
+
const baseline = this.reportBaseline;
|
|
149
|
+
return !!lastModified && !!baseline && lastModified.getTime() > baseline.getTime();
|
|
150
|
+
}
|
|
151
|
+
get sessionNumber() {
|
|
152
|
+
return sessionNumberOf(this.sessionData);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
EditSessionWidgetComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: EditSessionWidgetComponent, deps: [{ token: i1.ServicesConfigService }, { token: i1.ServicesService }], target: i0.ɵɵFactoryTarget.Component });
|
|
156
|
+
EditSessionWidgetComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: EditSessionWidgetComponent, selector: "lib-edit-session-widget", inputs: { config: "config" }, providers: [ServicesConfigService, ServicesService], viewQueries: [{ propertyName: "sessionSearch", first: true, predicate: SessionSearchComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<p *ngIf=\"configError; else sessionSearch\" class=\"edit-session-widget__error\" role=\"alert\">\n {{ configError }}\n</p>\n<ng-template #sessionSearch>\n <lib-session-search (sessionDataLoaded)=\"onSessionDataLoaded($event)\"></lib-session-search>\n <p *ngIf=\"!sessionData\" class=\"edit-session-widget__empty\">\n Search for a session to view its report.\n </p>\n <lib-detail-edit\n [sessionData]=\"sessionData\"\n (regenerateRequested)=\"onRegenerateRequested($event)\"\n (cancelled)=\"onCancelled()\"\n ></lib-detail-edit>\n <p *ngIf=\"reportError\" class=\"edit-session-widget__error\" role=\"alert\">\n {{ reportError }}\n </p>\n <lib-report-viewer\n [sessionData]=\"sessionData\"\n (reportLoaded)=\"onReportLoaded($event)\"\n ></lib-report-viewer>\n</ng-template>\n<lib-version-footer [version]=\"version\"></lib-version-footer>\n", styles: [".edit-session-widget__empty{margin:1rem 0 0;color:#6c757d;font-size:14px}.edit-session-widget__error{margin:0;color:#b02a37}\n"], dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i1.SessionSearchComponent, selector: "lib-session-search", outputs: ["sessionDataLoaded"] }, { kind: "component", type: i1.ReportViewerComponent, selector: "lib-report-viewer", inputs: ["sessionData"], outputs: ["reportLoaded"] }, { kind: "component", type: i1.DetailEditComponent, selector: "lib-detail-edit", inputs: ["sessionData"], outputs: ["regenerateRequested", "cancelled"] }, { kind: "component", type: i1.VersionFooterComponent, selector: "lib-version-footer", inputs: ["version"] }] });
|
|
157
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: EditSessionWidgetComponent, decorators: [{
|
|
158
|
+
type: Component,
|
|
159
|
+
args: [{ selector: 'lib-edit-session-widget', providers: [ServicesConfigService, ServicesService], template: "<p *ngIf=\"configError; else sessionSearch\" class=\"edit-session-widget__error\" role=\"alert\">\n {{ configError }}\n</p>\n<ng-template #sessionSearch>\n <lib-session-search (sessionDataLoaded)=\"onSessionDataLoaded($event)\"></lib-session-search>\n <p *ngIf=\"!sessionData\" class=\"edit-session-widget__empty\">\n Search for a session to view its report.\n </p>\n <lib-detail-edit\n [sessionData]=\"sessionData\"\n (regenerateRequested)=\"onRegenerateRequested($event)\"\n (cancelled)=\"onCancelled()\"\n ></lib-detail-edit>\n <p *ngIf=\"reportError\" class=\"edit-session-widget__error\" role=\"alert\">\n {{ reportError }}\n </p>\n <lib-report-viewer\n [sessionData]=\"sessionData\"\n (reportLoaded)=\"onReportLoaded($event)\"\n ></lib-report-viewer>\n</ng-template>\n<lib-version-footer [version]=\"version\"></lib-version-footer>\n", styles: [".edit-session-widget__empty{margin:1rem 0 0;color:#6c757d;font-size:14px}.edit-session-widget__error{margin:0;color:#b02a37}\n"] }]
|
|
160
|
+
}], ctorParameters: function () { return [{ type: i1.ServicesConfigService }, { type: i1.ServicesService }]; }, propDecorators: { config: [{
|
|
161
|
+
type: Input
|
|
162
|
+
}], sessionSearch: [{
|
|
163
|
+
type: ViewChild,
|
|
164
|
+
args: [SessionSearchComponent]
|
|
165
|
+
}] } });
|
|
166
|
+
|
|
167
|
+
class EditSessionWidgetModule {
|
|
168
|
+
}
|
|
169
|
+
EditSessionWidgetModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: EditSessionWidgetModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
170
|
+
EditSessionWidgetModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: EditSessionWidgetModule, declarations: [EditSessionWidgetComponent], imports: [CommonModule, ComponentsModule], exports: [EditSessionWidgetComponent] });
|
|
171
|
+
EditSessionWidgetModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: EditSessionWidgetModule, imports: [CommonModule, ComponentsModule] });
|
|
172
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: EditSessionWidgetModule, decorators: [{
|
|
173
|
+
type: NgModule,
|
|
174
|
+
args: [{
|
|
175
|
+
declarations: [EditSessionWidgetComponent],
|
|
176
|
+
imports: [CommonModule, ComponentsModule],
|
|
177
|
+
exports: [EditSessionWidgetComponent],
|
|
178
|
+
}]
|
|
179
|
+
}] });
|
|
180
|
+
|
|
181
|
+
/*
|
|
182
|
+
* Public API Surface of edit-session-widget
|
|
183
|
+
*/
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Generated bundle index. Do not edit.
|
|
187
|
+
*/
|
|
188
|
+
|
|
189
|
+
export { EDIT_SESSION_WIDGET_VERSION, EditSessionWidgetComponent, EditSessionWidgetModule };
|
|
190
|
+
//# sourceMappingURL=alimetry-edit-session-widget.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alimetry-edit-session-widget.mjs","sources":["../../../widgets/edit-session-widget/src/lib/version.ts","../../../widgets/edit-session-widget/src/lib/edit-session-widget.component.ts","../../../widgets/edit-session-widget/src/lib/edit-session-widget.component.html","../../../widgets/edit-session-widget/src/lib/edit-session-widget.module.ts","../../../widgets/edit-session-widget/src/public-api.ts","../../../widgets/edit-session-widget/src/alimetry-edit-session-widget.ts"],"sourcesContent":["// keep in step with \"version\" in widgets/edit-session-widget/package.json, which ng-packagr won't\n// let src import\nexport const EDIT_SESSION_WIDGET_VERSION = '1.0.0-dev.0';\n","import { Component, Input, OnChanges, OnDestroy, ViewChild } from '@angular/core';\nimport {\n DeviceData,\n ServicesConfigService,\n ServicesService,\n SessionSearchComponent,\n isReportGenerated,\n isReportGenerating,\n reportLinkOf,\n sessionNumberOf,\n statusOf,\n} from '@alimetry/widget-core';\nimport {\n catchError,\n EMPTY,\n exhaustMap,\n filter,\n interval,\n map,\n Subject,\n switchMap,\n take,\n takeUntil,\n timer,\n} from 'rxjs';\nimport { EDIT_SESSION_WIDGET_VERSION } from './version';\n\n// how often the widget asks the cloud whether the report it is waiting on is ready\nconst REPORT_POLL_INTERVAL_MS = 30_000;\n\n// how often it then re-reads the report link and the file behind it, waiting for that file to be\n// the newly generated one rather than the one it replaced\nconst REPORT_FILE_POLL_INTERVAL_MS = 5_000;\n\n@Component({\n selector: 'lib-edit-session-widget',\n templateUrl: './edit-session-widget.component.html',\n styleUrls: ['./edit-session-widget.component.css'],\n // scoped to this widget so each instance runs against the config it was given\n providers: [ServicesConfigService, ServicesService],\n})\nexport class EditSessionWidgetComponent implements OnChanges, OnDestroy {\n // TODO: change the type of the input to not be any\n @Input() config: any;\n\n readonly version = EDIT_SESSION_WIDGET_VERSION;\n\n // inside the config check's template, so it is only there once the config is valid\n @ViewChild(SessionSearchComponent) private sessionSearch?: SessionSearchComponent;\n\n sessionData?: DeviceData;\n configError: string | null = null;\n\n // set when a poll gave up because the record stopped short of a generated report\n reportError: string | null = null;\n\n reportBaseline: Date | null = null;\n\n // the generation of the report currently on screen, as the viewer last loaded it\n private reportLastModified: Date | null = null;\n\n // set while a poll is running that started before the viewer had read the report on screen, so\n // the generation that poll is waiting to replace has still to be recorded\n private needsBaseline = false;\n\n // ends the poll a save started: on the next one, on a new search, and on teardown\n private readonly stopPolling$ = new Subject<void>();\n\n constructor(\n private servicesConfig: ServicesConfigService,\n private services: ServicesService,\n ) {}\n\n ngOnChanges(): void {\n const deviceDataModelId: string = this.config?.deviceDataModelId?.trim() ?? '';\n const apiUrl: string = this.config?.apiUrl?.trim() ?? '';\n const appDataPropertySetId: string = this.config?.appDataPropertySetId?.trim() ?? '';\n const devicePropertySetId: string = this.config?.devicePropertySetId?.trim() ?? '';\n\n if (!deviceDataModelId || !apiUrl) {\n this.configError =\n 'This widget is missing required configuration values. Please check the widget configuration.';\n this.sessionData = undefined;\n return;\n }\n\n this.configError = null;\n // hand the values the services layer needs to it through dependency injection\n this.servicesConfig.setConfig({\n deviceDataModelId,\n apiUrl,\n appDataPropertySetId,\n devicePropertySetId,\n });\n }\n\n onSessionDataLoaded(sessionData: DeviceData | undefined): void {\n // whatever the last save was waiting on, it is not this session\n this.stopPolling$.next();\n\n this.sessionData = sessionData;\n this.reportError = null;\n this.reportBaseline = null;\n this.reportLastModified = null;\n this.needsBaseline = false;\n\n // a session that is already regenerating when it is searched for is waited on the same way one\n // this widget just regenerated is, so reloading the page picks the wait back up\n if (isReportGenerating(statusOf(sessionData))) {\n this.onRegenerateRequested(true);\n }\n }\n\n // clears the search box and drops the session, which empties the form and the report with it\n onCancelled(): void {\n this.sessionSearch?.clear();\n this.onSessionDataLoaded(undefined);\n }\n\n onReportLoaded(lastModified: Date | null): void {\n this.reportLastModified = lastModified;\n\n // the poll a reload started has no generation to wait past until this first read arrives\n if (this.needsBaseline) {\n this.reportBaseline = lastModified;\n this.needsBaseline = false;\n }\n }\n\n onRegenerateRequested(requested: boolean): void {\n if (!requested) {\n return;\n }\n\n this.reportError = null;\n this.reportBaseline = this.reportLastModified;\n this.needsBaseline = !this.reportBaseline;\n this.pollForReport();\n }\n\n ngOnDestroy(): void {\n this.stopPolling$.next();\n this.stopPolling$.complete();\n }\n\n private pollForReport(): void {\n const sessionNumber = this.sessionNumber;\n if (!sessionNumber) {\n return;\n }\n\n // whichever poll is already running is waiting on a report this save has superseded\n this.stopPolling$.next();\n\n interval(REPORT_POLL_INTERVAL_MS)\n .pipe(\n exhaustMap(() =>\n this.services.getSessionProperty(sessionNumber, 'Status').pipe(\n map((sessionData) => statusOf(sessionData)),\n catchError(() => EMPTY),\n ),\n ),\n // anything other than \"generating report\" is as far as this report is going to get, so the\n // poll ends on it either way rather than waiting out a status that will never change\n filter((status) => !isReportGenerating(status)),\n take(1),\n takeUntil(this.stopPolling$),\n )\n .subscribe((status) => {\n if (isReportGenerated(status)) {\n this.pollForNewReportFile(sessionNumber);\n } else {\n this.onReportStopped(sessionNumber);\n }\n });\n }\n\n private pollForNewReportFile(sessionNumber: string): void {\n // with no generation to compare against there is nothing to wait for: whatever the link points\n // at is the report to show, and reading it here only downloads a file the viewer downloads again\n if (!this.reportBaseline) {\n this.loadSession(sessionNumber);\n return;\n }\n\n // poll to check if new report is ready\n timer(0, REPORT_FILE_POLL_INTERVAL_MS)\n .pipe(\n exhaustMap(() =>\n this.services.getSessionProperty(sessionNumber, 'PdfReport').pipe(\n map((sessionData) => reportLinkOf(sessionData)),\n filter((link) => !!link),\n switchMap((link) => this.services.getReportLastModified(link)),\n catchError(() => EMPTY),\n ),\n ),\n filter((lastModified) => this.isNewReport(lastModified)),\n take(1),\n takeUntil(this.stopPolling$),\n )\n .subscribe(() => this.loadSession(sessionNumber));\n }\n\n // the record settled on a status that is not a generated report: say so, and read the record back\n // so the form unlocks rather than staying held by a regeneration that is over\n private onReportStopped(sessionNumber: string): void {\n this.reportError = 'Report regeneration failed. Please try again.';\n this.loadSession(sessionNumber);\n }\n\n // the polls above read one property at a time, so the whole record is read back once, here, to\n // show the session the regeneration has left behind\n private loadSession(sessionNumber: string): void {\n this.services\n .getSessionData(sessionNumber)\n .pipe(\n filter((sessionData): sessionData is DeviceData => !!sessionData),\n catchError(() => EMPTY),\n takeUntil(this.stopPolling$),\n )\n .subscribe((sessionData) => this.showSession(sessionData));\n }\n\n private showSession(sessionData: DeviceData): void {\n this.needsBaseline = false;\n this.sessionData = sessionData;\n }\n\n // check if report is new\n private isNewReport(lastModified: Date | null): boolean {\n const baseline = this.reportBaseline;\n return !!lastModified && !!baseline && lastModified.getTime() > baseline.getTime();\n }\n\n private get sessionNumber(): string {\n return sessionNumberOf(this.sessionData);\n }\n}\n","<p *ngIf=\"configError; else sessionSearch\" class=\"edit-session-widget__error\" role=\"alert\">\n {{ configError }}\n</p>\n<ng-template #sessionSearch>\n <lib-session-search (sessionDataLoaded)=\"onSessionDataLoaded($event)\"></lib-session-search>\n <p *ngIf=\"!sessionData\" class=\"edit-session-widget__empty\">\n Search for a session to view its report.\n </p>\n <lib-detail-edit\n [sessionData]=\"sessionData\"\n (regenerateRequested)=\"onRegenerateRequested($event)\"\n (cancelled)=\"onCancelled()\"\n ></lib-detail-edit>\n <p *ngIf=\"reportError\" class=\"edit-session-widget__error\" role=\"alert\">\n {{ reportError }}\n </p>\n <lib-report-viewer\n [sessionData]=\"sessionData\"\n (reportLoaded)=\"onReportLoaded($event)\"\n ></lib-report-viewer>\n</ng-template>\n<lib-version-footer [version]=\"version\"></lib-version-footer>\n","import { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { ComponentsModule } from '@alimetry/widget-core';\nimport { EditSessionWidgetComponent } from './edit-session-widget.component';\n\n@NgModule({\n declarations: [EditSessionWidgetComponent],\n imports: [CommonModule, ComponentsModule],\n exports: [EditSessionWidgetComponent],\n})\nexport class EditSessionWidgetModule {}\n","/*\n * Public API Surface of edit-session-widget\n */\n\nexport * from './lib/edit-session-widget.component';\nexport * from './lib/edit-session-widget.module';\nexport * from './lib/version';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { OnChanges, OnDestroy } from '@angular/core';
|
|
2
|
+
import { DeviceData, ServicesConfigService, ServicesService } from '@alimetry/widget-core';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export declare class EditSessionWidgetComponent implements OnChanges, OnDestroy {
|
|
5
|
+
private servicesConfig;
|
|
6
|
+
private services;
|
|
7
|
+
config: any;
|
|
8
|
+
readonly version = "1.0.0-dev.0";
|
|
9
|
+
private sessionSearch?;
|
|
10
|
+
sessionData?: DeviceData;
|
|
11
|
+
configError: string | null;
|
|
12
|
+
reportError: string | null;
|
|
13
|
+
reportBaseline: Date | null;
|
|
14
|
+
private reportLastModified;
|
|
15
|
+
private needsBaseline;
|
|
16
|
+
private readonly stopPolling$;
|
|
17
|
+
constructor(servicesConfig: ServicesConfigService, services: ServicesService);
|
|
18
|
+
ngOnChanges(): void;
|
|
19
|
+
onSessionDataLoaded(sessionData: DeviceData | undefined): void;
|
|
20
|
+
onCancelled(): void;
|
|
21
|
+
onReportLoaded(lastModified: Date | null): void;
|
|
22
|
+
onRegenerateRequested(requested: boolean): void;
|
|
23
|
+
ngOnDestroy(): void;
|
|
24
|
+
private pollForReport;
|
|
25
|
+
private pollForNewReportFile;
|
|
26
|
+
private onReportStopped;
|
|
27
|
+
private loadSession;
|
|
28
|
+
private showSession;
|
|
29
|
+
private isNewReport;
|
|
30
|
+
private get sessionNumber();
|
|
31
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<EditSessionWidgetComponent, never>;
|
|
32
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<EditSessionWidgetComponent, "lib-edit-session-widget", never, { "config": "config"; }, {}, never, never, false, never>;
|
|
33
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
import * as i1 from "./edit-session-widget.component";
|
|
3
|
+
import * as i2 from "@angular/common";
|
|
4
|
+
import * as i3 from "@alimetry/widget-core";
|
|
5
|
+
export declare class EditSessionWidgetModule {
|
|
6
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<EditSessionWidgetModule, never>;
|
|
7
|
+
static ɵmod: i0.ɵɵNgModuleDeclaration<EditSessionWidgetModule, [typeof i1.EditSessionWidgetComponent], [typeof i2.CommonModule, typeof i3.ComponentsModule], [typeof i1.EditSessionWidgetComponent]>;
|
|
8
|
+
static ɵinj: i0.ɵɵInjectorDeclaration<EditSessionWidgetModule>;
|
|
9
|
+
}
|
package/lib/version.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const EDIT_SESSION_WIDGET_VERSION = "1.0.0-dev.0";
|
package/package.json
CHANGED
|
@@ -1,6 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alimetry/edit-session-widget",
|
|
3
|
-
"version": "0.0.0
|
|
4
|
-
"
|
|
5
|
-
|
|
3
|
+
"version": "1.0.0-dev.0",
|
|
4
|
+
"peerDependencies": {
|
|
5
|
+
"@angular/common": "^15.1.0",
|
|
6
|
+
"@angular/core": "^15.1.0"
|
|
7
|
+
},
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"tslib": "^2.3.0",
|
|
10
|
+
"@alimetry/widget-core": "1.0.0-dev.0"
|
|
11
|
+
},
|
|
12
|
+
"sideEffects": false,
|
|
13
|
+
"publishConfig": {
|
|
14
|
+
"access": "public"
|
|
15
|
+
},
|
|
16
|
+
"module": "fesm2015/alimetry-edit-session-widget.mjs",
|
|
17
|
+
"es2020": "fesm2020/alimetry-edit-session-widget.mjs",
|
|
18
|
+
"esm2020": "esm2020/alimetry-edit-session-widget.mjs",
|
|
19
|
+
"fesm2020": "fesm2020/alimetry-edit-session-widget.mjs",
|
|
20
|
+
"fesm2015": "fesm2015/alimetry-edit-session-widget.mjs",
|
|
21
|
+
"typings": "index.d.ts",
|
|
22
|
+
"exports": {
|
|
23
|
+
"./package.json": {
|
|
24
|
+
"default": "./package.json"
|
|
25
|
+
},
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./index.d.ts",
|
|
28
|
+
"esm2020": "./esm2020/alimetry-edit-session-widget.mjs",
|
|
29
|
+
"es2020": "./fesm2020/alimetry-edit-session-widget.mjs",
|
|
30
|
+
"es2015": "./fesm2015/alimetry-edit-session-widget.mjs",
|
|
31
|
+
"node": "./fesm2015/alimetry-edit-session-widget.mjs",
|
|
32
|
+
"default": "./fesm2020/alimetry-edit-session-widget.mjs"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
6
35
|
}
|
package/public-api.d.ts
ADDED