alimetry-detail-edit 1.1.0 → 1.2.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.
@@ -12,8 +12,10 @@ const appDataPropertySetId = '34d46477-ad4b-47b4-b555-06358b92f60c';
12
12
  const deviceDataPropertySetId = '7a32d851-5e89-46a6-a4b6-cca162dace29';
13
13
  const propertyCodes = ['RecordingSession', 'Status', 'UserDetailChangeLog'];
14
14
  export class DetailEditComponent {
15
- constructor(shared) {
15
+ constructor(shared, kvDiffers, itDiffers) {
16
16
  this.shared = shared;
17
+ this.kvDiffers = kvDiffers;
18
+ this.itDiffers = itDiffers;
17
19
  this.status = 'loading';
18
20
  this.formGroup = new FormGroup({
19
21
  dob: new FormControl('', [Validators.required, withinNYears(120, 'before')]),
@@ -95,18 +97,30 @@ export class DetailEditComponent {
95
97
  this.detailChangeLog.push(entry);
96
98
  console.log(this.detailChangeLog);
97
99
  }
98
- // get the device data record and initialise the form
99
- loadDeviceData() {
100
- this.shared.getDeviceData(this.config.deviceDataModelId, this.config.owners[0], propertyCodes).subscribe({
101
- next: (res) => {
102
- this.deviceDataId = res.deviceDataId;
103
- this.recordingSession = JSON.parse(res.data['RecordingSession'].value);
100
+ regenReport() {
101
+ this.postDeviceData(deviceDataPropertySetId, { 'Algorithmhasrun': false, 'AlgorithmRun': true }).subscribe(() => {
102
+ this.status = 'generating'; // assume report starts generating immediately
103
+ });
104
+ }
105
+ resetModifications() {
106
+ this.formGroup.patchValue(this.initialFormState);
107
+ }
108
+ loadData(currentUserId, ownerId, deviceDataModelId) {
109
+ forkJoin([
110
+ this.shared.getUser(currentUserId),
111
+ this.shared.getUser(ownerId),
112
+ this.shared.getDeviceData(deviceDataModelId, ownerId, propertyCodes)
113
+ ]).subscribe({
114
+ next: ([currentUser, owner, { deviceDataId, data: deviceData }]) => {
115
+ this.currentUser = currentUser;
116
+ this.owner = owner;
117
+ this.deviceDataId = deviceDataId;
118
+ this.recordingSession = JSON.parse(deviceData['RecordingSession'].value);
104
119
  this.initialiseForm(this.extractFields(this.recordingSession));
105
120
  // data field uninitialised for unmodified record
106
- this.detailChangeLog = res.data['UserDetailChangeLog']?.value ?? [];
107
- this.status = res.data['Status']?.value === 'Generating Report' ?
108
- 'generating' :
109
- 'success';
121
+ this.detailChangeLog = deviceData['UserDetailChangeLog']?.value ?? [];
122
+ this.status = deviceData['Status']?.value === 'Generating Report' ?
123
+ 'generating' : 'success';
110
124
  },
111
125
  error: (err) => {
112
126
  console.error(err);
@@ -114,35 +128,42 @@ export class DetailEditComponent {
114
128
  }
115
129
  });
116
130
  }
117
- regenReport() {
118
- this.postDeviceData(deviceDataPropertySetId, { 'Algorithmhasrun': false, 'AlgorithmRun': true }).subscribe(() => {
119
- this.status = 'generating'; // assume report starts generating immediately
120
- });
121
- }
122
- resetModifications() {
123
- this.formGroup.patchValue(this.initialFormState);
124
- }
125
- ngOnInit() {
126
- if (!this.config?.owners?.[0]) {
131
+ init() {
132
+ if (!this.config?.currentUserId || !this.config.deviceDataModelId) {
133
+ this.status = 'cfgerror';
134
+ return;
135
+ }
136
+ else if (!this.config?.owners?.[0]) {
127
137
  this.status = 'nouser';
128
138
  return;
129
139
  }
130
- forkJoin([
131
- this.shared.getUser(this.config.currentUserId),
132
- this.shared.getUser(this.config.owners[0])
133
- ]).pipe(tap(([current, owner]) => {
134
- this.currentUser = current;
135
- this.owner = owner;
136
- })).subscribe();
137
- this.loadDeviceData();
140
+ this.status = 'loading';
141
+ this.loadData(this.config.currentUserId, this.config.owners[0], this.config.deviceDataModelId);
142
+ }
143
+ // this should be called from the parent using the ViewChild attr
144
+ refresh() {
145
+ this.init();
146
+ }
147
+ // NOTE: there could be something wrong / unusual here but it seems to work ok
148
+ ngOnInit() {
149
+ if (this.config && !this.configDiffer)
150
+ this.configDiffer = this.kvDiffers.find(this.config).create();
151
+ if (this.config?.owners && !this.ownersDiffer)
152
+ this.ownersDiffer = this.itDiffers.find(this.config.owners).create();
153
+ }
154
+ ngDoCheck() {
155
+ const configChanges = this.configDiffer?.diff(this.config);
156
+ const ownersChanges = this.ownersDiffer?.diff(this.config?.owners);
157
+ if (configChanges || ownersChanges)
158
+ this.init();
138
159
  }
139
160
  }
140
- DetailEditComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DetailEditComponent, deps: [{ token: i1.SharedService }], target: i0.ɵɵFactoryTarget.Component });
141
- DetailEditComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: DetailEditComponent, selector: "lib-detail-edit", inputs: { config: "config" }, ngImport: i0, template: "<div class=\"wrapper\">\n <div class=\"status\" *ngIf=\"status === 'error'\">\n An error occured while trying to get the details.\n </div>\n <div class=\"status\" *ngIf=\"status === 'nouser'\">\n There is no user specified as the data owner.\n </div>\n <form *ngIf=\"status !== 'error' && status !== 'nouser'\" [formGroup]=\"formGroup\" (ngSubmit)=\"saveModifications()\">\n <div class=\"inputs\">\n <div class=\"form-row\">\n <label for=\"dob\">Date of Birth:</label>\n <input id=\"dob\" type=\"date\" formControlName=\"dob\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"weight\">Patient Weight (kg):</label>\n <input id=\"weight\" type=\"number\" formControlName=\"weight\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"height\">Patient Height (cm):</label>\n <input id=\"height\" type=\"number\" formControlName=\"height\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealStart\">Meal Start Time:</label>\n <input id=\"mealStart\" type=\"datetime-local\" formControlName=\"mealStart\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealEnd\">Meal End Time:</label>\n <input id=\"mealEnd\" type=\"datetime-local\" formControlName=\"mealEnd\">\n </div>\n </div>\n\n <div *ngIf=\"!formGroup.valid && formGroup.dirty\" class=\"errors\">\n <div *ngFor=\"let control of formGroup.controls | entries\">\n {{ parseInputErrors(control[0], control[1]) }}\n </div>\n </div>\n\n <div *ngIf=\"status === 'generating'\" class=\"info\">\n <div>The report is generating at the moment, check back later if you need to modify this entry.</div>\n </div>\n\n <div class=\"buttons\">\n <button type=\"button\" (click)=\"regenReport()\" [disabled]=\"status === 'sending' || status === 'generating' || status === 'loading'\">Regenerate Report</button>\n <button type=\"button\" (click)=\"resetModifications()\" [disabled]=\"status === 'sending' || status === 'generating' || formGroup.pristine\">Cancel Modification</button>\n <button type=\"submit\" [disabled]=\"status === 'sending' || status === 'generating' || !formGroup.valid || formGroup.pristine\">Save Details</button>\n </div>\n </form>\n</div>\n", styles: [".wrapper{width:100%;height:100%}.status{font-size:2rem;margin:5rem auto;text-align:center}form{display:flex;flex-direction:column;padding:2rem;gap:2rem;font-size:.9rem;max-width:70rem;margin:0 auto}form .inputs{display:flex;flex-flow:row wrap;gap:1rem 3rem}form .inputs .form-row{display:flex;gap:1rem;align-items:center;flex:1 0 calc(50% - 3rem);min-width:400px}form .inputs .form-row label{min-width:9rem}form .inputs .form-row input{background:#f5f5f6;height:36px;border:none;padding-inline:10px;flex-grow:1}form.ng-dirty .form-row .ng-invalid{outline:1px auto red}form .buttons{display:flex;gap:1rem}form .buttons button{padding:.5rem 1rem;height:36px;border:none;font-size:inherit;background:#f5f5f6}form .buttons button:not([disabled]){cursor:pointer}form .buttons button[type=submit]{background:#242C69;color:#fff}form .buttons button[disabled]{background:#fafafa;cursor:not-allowed}form .buttons button[type=submit][disabled]{background:#444C89}form .buttons button:first-child{margin-right:auto}.errors{padding:1rem;background:#fee;border:2px solid red;border-radius:4px;color:red}.info{padding:1rem;background:#eef;border:2px solid #242C69;border-radius:4px;color:#242c69}\n"], dependencies: [{ kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i4.EntriesPipe, name: "entries" }] });
161
+ DetailEditComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DetailEditComponent, deps: [{ token: i1.SharedService }, { token: i0.KeyValueDiffers }, { token: i0.IterableDiffers }], target: i0.ɵɵFactoryTarget.Component });
162
+ DetailEditComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: DetailEditComponent, selector: "lib-detail-edit", inputs: { config: "config" }, ngImport: i0, template: "<div class=\"wrapper\">\n <div class=\"status\" *ngIf=\"status === 'error'\">\n An error occured while trying to get the details.\n </div>\n <div class=\"status\" *ngIf=\"status === 'cfgerror'\">\n The widget has not been configured correctly, or is missing configuration information.\n </div>\n <div class=\"status\" *ngIf=\"status === 'nouser'\">\n There is no user specified as the data owner.\n </div>\n <form *ngIf=\"!status.includes('error') && status !== 'nouser'\" [formGroup]=\"formGroup\" (ngSubmit)=\"saveModifications()\">\n <div class=\"inputs\">\n <div class=\"form-row\">\n <label for=\"dob\">Date of Birth:</label>\n <input id=\"dob\" type=\"date\" formControlName=\"dob\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"weight\">Patient Weight (kg):</label>\n <input id=\"weight\" type=\"number\" formControlName=\"weight\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"height\">Patient Height (cm):</label>\n <input id=\"height\" type=\"number\" formControlName=\"height\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealStart\">Meal Start Time:</label>\n <input id=\"mealStart\" type=\"datetime-local\" formControlName=\"mealStart\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealEnd\">Meal End Time:</label>\n <input id=\"mealEnd\" type=\"datetime-local\" formControlName=\"mealEnd\">\n </div>\n </div>\n\n <div *ngIf=\"!formGroup.valid && formGroup.dirty\" class=\"errors\">\n <div *ngFor=\"let control of formGroup.controls | entries\">\n {{ parseInputErrors(control[0], control[1]) }}\n </div>\n </div>\n\n <div *ngIf=\"status === 'generating'\" class=\"info\">\n <div>The report is generating at the moment, check back later if you need to modify this entry.</div>\n </div>\n\n <div class=\"buttons\">\n <button type=\"button\" (click)=\"regenReport()\" [disabled]=\"status === 'sending' || status === 'generating' || status === 'loading'\">Regenerate Report</button>\n <button type=\"button\" (click)=\"resetModifications()\" [disabled]=\"status === 'sending' || status === 'generating' || formGroup.pristine\">Cancel Modification</button>\n <button type=\"submit\" [disabled]=\"status === 'sending' || status === 'generating' || !formGroup.valid || formGroup.pristine\">Save Details</button>\n </div>\n </form>\n</div>\n", styles: [".wrapper{width:100%;height:100%}.status{font-size:2rem;margin:5rem auto;text-align:center}form{display:flex;flex-direction:column;padding:2rem;gap:2rem;font-size:.9rem;max-width:70rem;margin:0 auto}form .inputs{display:flex;flex-flow:row wrap;gap:1rem 3rem}form .inputs .form-row{display:flex;gap:1rem;align-items:center;flex:1 0 calc(50% - 3rem);min-width:400px}form .inputs .form-row label{min-width:9rem}form .inputs .form-row input{background:#f5f5f6;height:36px;border:none;padding-inline:10px;flex-grow:1}form.ng-dirty .form-row .ng-invalid{outline:1px auto red}form .buttons{display:flex;gap:1rem}form .buttons button{padding:.5rem 1rem;height:36px;border:none;font-size:inherit;background:#f5f5f6}form .buttons button:not([disabled]){cursor:pointer}form .buttons button[type=submit]{background:#242C69;color:#fff}form .buttons button[disabled]{background:#fafafa;cursor:not-allowed}form .buttons button[type=submit][disabled]{background:#444C89}form .buttons button:first-child{margin-right:auto}.errors{padding:1rem;background:#fee;border:2px solid red;border-radius:4px;color:red}.info{padding:1rem;background:#eef;border:2px solid #242C69;border-radius:4px;color:#242c69}\n"], dependencies: [{ kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i4.EntriesPipe, name: "entries" }] });
142
163
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DetailEditComponent, decorators: [{
143
164
  type: Component,
144
- args: [{ selector: 'lib-detail-edit', template: "<div class=\"wrapper\">\n <div class=\"status\" *ngIf=\"status === 'error'\">\n An error occured while trying to get the details.\n </div>\n <div class=\"status\" *ngIf=\"status === 'nouser'\">\n There is no user specified as the data owner.\n </div>\n <form *ngIf=\"status !== 'error' && status !== 'nouser'\" [formGroup]=\"formGroup\" (ngSubmit)=\"saveModifications()\">\n <div class=\"inputs\">\n <div class=\"form-row\">\n <label for=\"dob\">Date of Birth:</label>\n <input id=\"dob\" type=\"date\" formControlName=\"dob\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"weight\">Patient Weight (kg):</label>\n <input id=\"weight\" type=\"number\" formControlName=\"weight\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"height\">Patient Height (cm):</label>\n <input id=\"height\" type=\"number\" formControlName=\"height\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealStart\">Meal Start Time:</label>\n <input id=\"mealStart\" type=\"datetime-local\" formControlName=\"mealStart\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealEnd\">Meal End Time:</label>\n <input id=\"mealEnd\" type=\"datetime-local\" formControlName=\"mealEnd\">\n </div>\n </div>\n\n <div *ngIf=\"!formGroup.valid && formGroup.dirty\" class=\"errors\">\n <div *ngFor=\"let control of formGroup.controls | entries\">\n {{ parseInputErrors(control[0], control[1]) }}\n </div>\n </div>\n\n <div *ngIf=\"status === 'generating'\" class=\"info\">\n <div>The report is generating at the moment, check back later if you need to modify this entry.</div>\n </div>\n\n <div class=\"buttons\">\n <button type=\"button\" (click)=\"regenReport()\" [disabled]=\"status === 'sending' || status === 'generating' || status === 'loading'\">Regenerate Report</button>\n <button type=\"button\" (click)=\"resetModifications()\" [disabled]=\"status === 'sending' || status === 'generating' || formGroup.pristine\">Cancel Modification</button>\n <button type=\"submit\" [disabled]=\"status === 'sending' || status === 'generating' || !formGroup.valid || formGroup.pristine\">Save Details</button>\n </div>\n </form>\n</div>\n", styles: [".wrapper{width:100%;height:100%}.status{font-size:2rem;margin:5rem auto;text-align:center}form{display:flex;flex-direction:column;padding:2rem;gap:2rem;font-size:.9rem;max-width:70rem;margin:0 auto}form .inputs{display:flex;flex-flow:row wrap;gap:1rem 3rem}form .inputs .form-row{display:flex;gap:1rem;align-items:center;flex:1 0 calc(50% - 3rem);min-width:400px}form .inputs .form-row label{min-width:9rem}form .inputs .form-row input{background:#f5f5f6;height:36px;border:none;padding-inline:10px;flex-grow:1}form.ng-dirty .form-row .ng-invalid{outline:1px auto red}form .buttons{display:flex;gap:1rem}form .buttons button{padding:.5rem 1rem;height:36px;border:none;font-size:inherit;background:#f5f5f6}form .buttons button:not([disabled]){cursor:pointer}form .buttons button[type=submit]{background:#242C69;color:#fff}form .buttons button[disabled]{background:#fafafa;cursor:not-allowed}form .buttons button[type=submit][disabled]{background:#444C89}form .buttons button:first-child{margin-right:auto}.errors{padding:1rem;background:#fee;border:2px solid red;border-radius:4px;color:red}.info{padding:1rem;background:#eef;border:2px solid #242C69;border-radius:4px;color:#242c69}\n"] }]
145
- }], ctorParameters: function () { return [{ type: i1.SharedService }]; }, propDecorators: { config: [{
165
+ args: [{ selector: 'lib-detail-edit', template: "<div class=\"wrapper\">\n <div class=\"status\" *ngIf=\"status === 'error'\">\n An error occured while trying to get the details.\n </div>\n <div class=\"status\" *ngIf=\"status === 'cfgerror'\">\n The widget has not been configured correctly, or is missing configuration information.\n </div>\n <div class=\"status\" *ngIf=\"status === 'nouser'\">\n There is no user specified as the data owner.\n </div>\n <form *ngIf=\"!status.includes('error') && status !== 'nouser'\" [formGroup]=\"formGroup\" (ngSubmit)=\"saveModifications()\">\n <div class=\"inputs\">\n <div class=\"form-row\">\n <label for=\"dob\">Date of Birth:</label>\n <input id=\"dob\" type=\"date\" formControlName=\"dob\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"weight\">Patient Weight (kg):</label>\n <input id=\"weight\" type=\"number\" formControlName=\"weight\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"height\">Patient Height (cm):</label>\n <input id=\"height\" type=\"number\" formControlName=\"height\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealStart\">Meal Start Time:</label>\n <input id=\"mealStart\" type=\"datetime-local\" formControlName=\"mealStart\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealEnd\">Meal End Time:</label>\n <input id=\"mealEnd\" type=\"datetime-local\" formControlName=\"mealEnd\">\n </div>\n </div>\n\n <div *ngIf=\"!formGroup.valid && formGroup.dirty\" class=\"errors\">\n <div *ngFor=\"let control of formGroup.controls | entries\">\n {{ parseInputErrors(control[0], control[1]) }}\n </div>\n </div>\n\n <div *ngIf=\"status === 'generating'\" class=\"info\">\n <div>The report is generating at the moment, check back later if you need to modify this entry.</div>\n </div>\n\n <div class=\"buttons\">\n <button type=\"button\" (click)=\"regenReport()\" [disabled]=\"status === 'sending' || status === 'generating' || status === 'loading'\">Regenerate Report</button>\n <button type=\"button\" (click)=\"resetModifications()\" [disabled]=\"status === 'sending' || status === 'generating' || formGroup.pristine\">Cancel Modification</button>\n <button type=\"submit\" [disabled]=\"status === 'sending' || status === 'generating' || !formGroup.valid || formGroup.pristine\">Save Details</button>\n </div>\n </form>\n</div>\n", styles: [".wrapper{width:100%;height:100%}.status{font-size:2rem;margin:5rem auto;text-align:center}form{display:flex;flex-direction:column;padding:2rem;gap:2rem;font-size:.9rem;max-width:70rem;margin:0 auto}form .inputs{display:flex;flex-flow:row wrap;gap:1rem 3rem}form .inputs .form-row{display:flex;gap:1rem;align-items:center;flex:1 0 calc(50% - 3rem);min-width:400px}form .inputs .form-row label{min-width:9rem}form .inputs .form-row input{background:#f5f5f6;height:36px;border:none;padding-inline:10px;flex-grow:1}form.ng-dirty .form-row .ng-invalid{outline:1px auto red}form .buttons{display:flex;gap:1rem}form .buttons button{padding:.5rem 1rem;height:36px;border:none;font-size:inherit;background:#f5f5f6}form .buttons button:not([disabled]){cursor:pointer}form .buttons button[type=submit]{background:#242C69;color:#fff}form .buttons button[disabled]{background:#fafafa;cursor:not-allowed}form .buttons button[type=submit][disabled]{background:#444C89}form .buttons button:first-child{margin-right:auto}.errors{padding:1rem;background:#fee;border:2px solid red;border-radius:4px;color:red}.info{padding:1rem;background:#eef;border:2px solid #242C69;border-radius:4px;color:#242c69}\n"] }]
166
+ }], ctorParameters: function () { return [{ type: i1.SharedService }, { type: i0.KeyValueDiffers }, { type: i0.IterableDiffers }]; }, propDecorators: { config: [{
146
167
  type: Input
147
168
  }] } });
148
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGV0YWlsLWVkaXQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvZGV0YWlsLWVkaXQvc3JjL2xpYi9kZXRhaWwtZWRpdC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9wcm9qZWN0cy9kZXRhaWwtZWRpdC9zcmMvbGliL2RldGFpbC1lZGl0LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ2pELE9BQU8sRUFBbUIsV0FBVyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNyRixPQUFPLEVBQUUsUUFBUSxFQUFFLEdBQUcsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUVyQyxPQUFPLEVBQUUsTUFBTSxFQUFFLGlCQUFpQixFQUFFLGdCQUFnQixFQUFFLGNBQWMsRUFBRSxXQUFXLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDbkcsT0FBTyxFQUFFLGNBQWMsRUFBRSxZQUFZLEVBQUUsWUFBWSxFQUFFLGNBQWMsRUFBRSxNQUFNLGNBQWMsQ0FBQzs7Ozs7O0FBRTFGLE1BQU0sb0JBQW9CLEdBQUcsc0NBQXNDLENBQUM7QUFDcEUsTUFBTSx1QkFBdUIsR0FBRyxzQ0FBc0MsQ0FBQztBQUN2RSxNQUFNLGFBQWEsR0FBRyxDQUFDLGtCQUFrQixFQUFFLFFBQVEsRUFBRSxxQkFBcUIsQ0FBQyxDQUFDO0FBcUI1RSxNQUFNLE9BQU8sbUJBQW1CO0lBNEI5QixZQUFvQixNQUFxQjtRQUFyQixXQUFNLEdBQU4sTUFBTSxDQUFlO1FBekJ6QyxXQUFNLEdBQTBFLFNBQVMsQ0FBQztRQWMxRixjQUFTLEdBQUcsSUFBSSxTQUFTLENBQUM7WUFDeEIsR0FBRyxFQUFFLElBQUksV0FBVyxDQUFTLEVBQUUsRUFBRSxDQUFDLFVBQVUsQ0FBQyxRQUFRLEVBQUUsWUFBWSxDQUFD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SSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUU7WUFDN0IsSUFBSSxDQUFDLE1BQU0sR0FBRyxRQUFRLENBQUM7WUFDdkIsT0FBTztTQUNSO1FBRUQsUUFBUSxDQUFDO1lBQ1AsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUM7WUFDOUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7U0FDM0MsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLE9BQU8sRUFBRSxLQUFLLENBQUMsRUFBRSxFQUFFO1lBQy9CLElBQUksQ0FBQyxXQUFXLEdBQUcsT0FBTyxDQUFDO1lBQzNCLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1FBQ3JCLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxFQUFFLENBQUM7UUFFaEIsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO0lBQ3hCLENBQUM7O2lIQWxMVSxtQkFBbUI7cUdBQW5CLG1CQUFtQixxRkM5QmhDLDB3RUFvREE7NEZEdEJhLG1CQUFtQjtrQkFKL0IsU0FBUzsrQkFDRSxpQkFBaUI7b0dBSWxCLE1BQU07c0JBQWQsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgSW5wdXQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEFic3RyYWN0Q29udHJvbCwgRm9ybUNvbnRyb2wsIEZvcm1Hcm91cCwgVmFsaWRhdG9ycyB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IGZvcmtKb2luLCB0YXAgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IENvbmZpZywgU2hhcmVkU2VydmljZSwgVXNlciB9IGZyb20gJ2FsaW1ldHJ5LXNoYXJlZCc7XG5pbXBvcnQgeyBnZXRBZ2UsIGdsb2JhbGlzZURhdGVUaW1lLCBsb2NhbGlzZURhdGVUaW1lLCBzaGFsbG93Q29tcGFyZSwgc2hhbGxvd0RpZmYgfSBmcm9tICcuL3V0aWxzJztcbmltcG9ydCB7IGRhdGVDb21wYXJpc29uLCB3aXRoaW5OWWVhcnMsIHdpdGhpbk5Ib3VycywgdHJhbnNsYXRlRXJyb3IgfSBmcm9tICcuL3ZhbGlkYXRvcnMnO1xuXG5jb25zdCBhcHBEYXRhUHJvcGVydHlTZXRJZCA9ICczNGQ0NjQ3Ny1hZDRiLTQ3YjQtYjU1NS0wNjM1OGI5MmY2MGMnO1xuY29uc3QgZGV2aWNlRGF0YVByb3BlcnR5U2V0SWQgPSAnN2EzMmQ4NTEtNWU4OS00NmE2LWE0YjYtY2NhMTYyZGFjZTI5JztcbmNvbnN0IHByb3BlcnR5Q29kZXMgPSBbJ1JlY29yZGluZ1Nlc3Npb24nLCAnU3RhdHVzJywgJ1VzZXJEZXRhaWxDaGFuZ2VMb2cnXTtcblxuaW50ZXJmYWNlIEZvcm1WYWx1ZSB7XG4gIGRvYjogc3RyaW5nLFxuICBoZWlnaHQ6IG51bWJlcixcbiAgd2VpZ2h0OiBudW1iZXIsXG4gIG1lYWxTdGFydDogc3RyaW5nLFxuICBtZWFsRW5kOiBzdHJpbmdcbn1cblxuaW50ZXJmYWNlIENoYW5nZSB7XG4gIHRpbWVzdGFtcDogc3RyaW5nLFxuICBhdXRob3I6IHN0cmluZyxcbiAgZnJvbTogUGFydGlhbDxGb3JtVmFsdWU+LFxuICB0bzogUGFydGlhbDxGb3JtVmFsdWU+XG59XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2xpYi1kZXRhaWwtZWRpdCcsIHRlbXBsYXRlVXJsOiAnLi9kZXRhaWwtZWRpdC5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL2RldGFpbC1lZGl0LmNvbXBvbmVudC5jc3MnXVxufSlcbmV4cG9ydCBjbGFzcyBEZXRhaWxFZGl0Q29tcG9uZW50IHtcbiAgQElucHV0KCkgY29uZmlnITogQ29uZmlnO1xuXG4gIHN0YXR1czogJ2Vycm9yJyB8ICdsb2FkaW5nJyB8ICdzdWNjZXNzJyB8ICdnZW5lcmF0aW5nJyB8ICdzZW5kaW5nJyB8ICdub3VzZXInID0gJ2xvYWRpbmcnO1xuXG4gIC8vIGRldmljZSBkYXRhIHBvcHVsYXRlZCBieSBsb2FkIHJlcXVlc3RcbiAgcHJpdmF0ZSBkZXZpY2VEYXRhSWQ6IHN0cmluZztcbiAgcHJpdmF0ZSByZWNvcmRpbmdTZXNzaW9uOiBvYmplY3Q7XG4gIHByaXZhdGUgcmVjb3JkaW5nU3RhcnQ6IHN0cmluZztcbiAgcHJpdmF0ZSBpbml0aWFsRm9ybVN0YXRlOiBvYmplY3Q7XG5cbiAgLy8gdXNlciBkYXRhIGV4cGFuZGVkIGZyb20gaWRzIHBhc3NlZCBpbiBjb25maWdcbiAgcHJpdmF0ZSBjdXJyZW50VXNlcjogVXNlcjtcbiAgcHJpdmF0ZSBvd25lcjogVXNlcjtcblxuICBwcml2YXRlIGRldGFpbENoYW5nZUxvZzogQ2hhbmdlW107XG5cbiAgZm9ybUdyb3VwID0gbmV3IEZvcm1Hcm91cCh7XG4gICAgZG9iOiBuZXcgRm9ybUNvbnRyb2w8c3RyaW5nPignJywgW1ZhbGlkYXRvcnMucmVxdWlyZWQsIHdpdGhpbk5ZZWFycygxMjAsICdiZWZvcmUnKV0pLFxuICAgIGhlaWdodDogbmV3IEZvcm1Db250cm9sPG51bWJlcj4oMCwgW1ZhbGlkYXRvcnMucmVxdWlyZWQsIFZhbGlkYXRvcnMubWluKDMwKSwgVmFsaWRhdG9ycy5tYXgoMjcyKV0pLFxuICAgIHdlaWdodDogbmV3IEZvcm1Db250cm9sPG51bWJlcj4oMCwgW1ZhbGlkYXRvcnMucmVxdWlyZWQsIFZhbGlkYXRvcnMubWluKDEpLCBWYWxpZGF0b3JzLm1heCg2MzUpXSksXG4gICAgbWVhbFN0YXJ0OiBuZXcgRm9ybUNvbnRyb2w8c3RyaW5nPignJywgW1ZhbGlkYXRvcnMucmVxdWlyZWRdKSxcbiAgICBtZWFsRW5kOiBuZXcgRm9ybUNvbnRyb2w8c3RyaW5nPignJywgW1ZhbGlkYXRvcnMucmVxdWlyZWRdKVxuICB9LCBbXG4gICAgZGF0ZUNvbXBhcmlzb24oJ21lYWxFbmQnLCAnbWVhbFN0YXJ0JywgJ2FmdGVyJyksXG4gICAgZGF0ZUNvbXBhcmlzb24oJ21lYWxTdGFydCcsICdkb2InLCAnYWZ0ZXInKSxcbiAgXSk7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSBzaGFyZWQ6IFNoYXJlZFNlcnZpY2UpIHsgfVxuXG4gIHBhcnNlSW5wdXRFcnJvcnMobmFtZTogc3RyaW5nLCBjb250cm9sOiBBYnN0cmFjdENvbnRyb2wpIHtcbiAgICByZXR1cm4gdHJhbnNsYXRlRXJyb3IobmFtZSwgY29udHJvbCk7XG4gIH1cblxuICAvLyBtYWtlIHN1cmUgdGhhbiBtb2RpZmljYXRpb25zIHRoYXQgZG9uJ3QgYWN0dWFsbHkgZGlmZmVyIGZyb20gdGhlIGN1cnJlbnQgYXJlIG1hcmtlZCBhcyBzdWNoXG4gIHByaXZhdGUgbW9uaXRvckZvcm1DaGFuZ2VzKCkge1xuICAgIHRoaXMuZm9ybUdyb3VwLnZhbHVlQ2hhbmdlcy5zdWJzY3JpYmUoY3VycmVudCA9PiB7XG4gICAgICBpZiAoc2hhbGxvd0NvbXBhcmUoY3VycmVudCwgdGhpcy5pbml0aWFsRm9ybVN0YXRlKSkge1xuICAgICAgICB0aGlzLmZvcm1Hcm91cC5tYXJrQXNQcmlzdGluZSgpO1xuICAgICAgfVxuICAgIH0pXG4gIH1cblxuICAvLyBoYW5kbGUgdGhlIHJlbGV2YW50IGRhdGEgZnJvbSB0aGUgcmVzcG9uc2UgYm9keVxuICBwcml2YXRlIGV4dHJhY3RGaWVsZHMocmVjb3JkaW5nU2Vzc2lvbjogUmVjb3JkPHN0cmluZywgYW55Pikge1xuICAgIGNvbnN0IHsgcGF0aWVudCwgbWVhbFN0YXJ0LCBtZWFsRW5kLCByZWNvcmRpbmdTdGFydCB9ID0gcmVjb3JkaW5nU2Vzc2lvbjtcbiAgICB0aGlzLnJlY29yZGluZ1N0YXJ0ID0gcmVjb3JkaW5nU3RhcnQ7XG5cbiAgICByZXR1cm4ge1xuICAgICAgZG9iOiB0aGlzLm93bmVyLmRhdGVPZkJpcnRoLFxuICAgICAgaGVpZ2h0OiBwYXRpZW50LmhlaWdodCxcbiAgICAgIHdlaWdodDogcGF0aWVudC53ZWlnaHQsXG4gICAgICBtZWFsU3RhcnQ6IGxvY2FsaXNlRGF0ZVRpbWUobWVhbFN0YXJ0KSxcbiAgICAgIG1lYWxFbmQ6IGxvY2FsaXNlRGF0ZVRpbWUobWVhbEVuZClcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGluaXRpYWxpc2VGb3JtKHN0YXRlOiBvYmplY3QpIHtcbiAgICB0aGlzLmZvcm1Hcm91cC5wYXRjaFZhbHVlKHN0YXRlKTtcbiAgICB0aGlzLmZvcm1Hcm91cC5tYXJrQXNQcmlzdGluZSgpO1xuXG4gICAgdGhpcy5mb3JtR3JvdXAuZ2V0KCdtZWFsU3RhcnQnKS5hZGRWYWxpZGF0b3JzKHdpdGhpbk5Ib3VycygyNCwgJ2FmdGVyJywgbmV3IERhdGUodGhpcy5yZWNvcmRpbmdTdGFydCkpKTtcbiAgICB0aGlzLmZvcm1Hcm91cC5nZXQoJ21lYWxFbmQnKS5hZGRWYWxpZGF0b3JzKHdpdGhpbk5Ib3VycygyNCwgJ2FmdGVyJywgbmV3IERhdGUodGhpcy5yZWNvcmRpbmdTdGFydCkpKTtcblxuICAgIHRoaXMuaW5pdGlhbEZvcm1TdGF0ZSA9IHN0YXRlOyAvLyBzYXZlIHRoaXMgZm9yIHVzZSBpbiByZXNldHNcbiAgICB0aGlzLm1vbml0b3JGb3JtQ2hhbmdlcygpO1xuICB9XG5cbiAgLy8gY29uc3RydWN0IGEgcGF0Y2ggb2JqZWN0IGZvciB0aGUgc2F2ZSByZXF1ZXN0XG4gIHByaXZhdGUgaW50ZWdyYXRlRmllbGRzKG1vZHM6IEZvcm1WYWx1ZSwgcmVjb3JkaW5nU2Vzc2lvbjogUmVjb3JkPHN0cmluZywgYW55Pikge1xuICAgIGNvbnN0IHsgcGF0aWVudCB9ID0gcmVjb3JkaW5nU2Vzc2lvbjtcbiAgICBwYXRpZW50LmhlaWdodCA9IG1vZHMuaGVpZ2h0O1xuICAgIHBhdGllbnQud2VpZ2h0ID0gbW9kcy53ZWlnaHQ7XG4gICAgcGF0aWVudC5hZ2UgPSBnZXRBZ2UobW9kcy5kb2IpO1xuXG4gICAgcmVjb3JkaW5nU2Vzc2lvbi5tZWFsU3RhcnQgPSBnbG9iYWxpc2VEYXRlVGltZShtb2RzLm1lYWxTdGFydCk7XG4gICAgcmVjb3JkaW5nU2Vzc2lvbi5tZWFsRW5kID0gZ2xvYmFsaXNlRGF0ZVRpbWUobW9kcy5tZWFsRW5kKTtcblxuICAgIHRoaXMubG9nQ2hhbmdlKG1vZHMpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgICdBZ2UnOiBwYXRpZW50LmFnZSxcbiAgICAgICdSZWNvcmRpbmdTZXNzaW9uJzogSlNPTi5zdHJpbmdpZnkocmVjb3JkaW5nU2Vzc2lvbiksXG4gICAgICAnVXNlckRldGFpbENoYW5nZUxvZyc6IHRoaXMuZGV0YWlsQ2hhbmdlTG9nXG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBwb3N0RGV2aWNlRGF0YShkZXZpY2VQcm9wZXJ0eVNldElkOiBzdHJpbmcsIGRhdGE6IG9iamVjdCkge1xuICAgIHJldHVybiB0aGlzLnNoYXJlZC5zYXZlRGV2aWNlRGF0YShcbiAgICAgIHRoaXMuY29uZmlnLmRldmljZURhdGFNb2RlbElkLFxuICAgICAgdGhpcy5kZXZpY2VEYXRhSWQsXG4gICAgICBkZXZpY2VQcm9wZXJ0eVNldElkLFxuICAgICAgdGhpcy5jb25maWcub3duZXJzWzBdLFxuICAgICAgZGF0YVxuICAgICk7XG4gIH1cblxuICAvLyBwYXRjaCB0aGUgZGV2aWNlIGRhdGEgcmVjb3JkIHdpdGggdGhlIG1vZGlmaWNhdGlvbnNcbiAgc2F2ZU1vZGlmaWNhdGlvbnMoKSB7XG4gICAgY29uc3QgbW9kcyA9IHRoaXMuZm9ybUdyb3VwLmdldFJhd1ZhbHVlKCk7XG4gICAgY29uc3QgcGF0Y2hlZERldmljZURhdGEgPSB0aGlzLmludGVncmF0ZUZpZWxkcyhtb2RzLCB0aGlzLnJlY29yZGluZ1Nlc3Npb24pO1xuICAgIGNvbnN0IHBhdGNoZWRVc2VyRGF0YSA9IE9iamVjdC5hc3NpZ24odGhpcy5vd25lciwgeyBkYXRlT2ZCaXJ0aDogbW9kcy5kb2IgfSk7XG5cbiAgICB0aGlzLnN0YXR1cyA9ICdzZW5kaW5nJztcbiAgICBmb3JrSm9pbihbXG4gICAgICB0aGlzLnBvc3REZXZpY2VEYXRhKGFwcERhdGFQcm9wZXJ0eVNldElkLCBwYXRjaGVkRGV2aWNlRGF0YSksXG4gICAgICB0aGlzLnNoYXJlZC51cGRhdGVVc2VyKHRoaXMuY29uZmlnLm93bmVyc1swXSwgcGF0Y2hlZFVzZXJEYXRhKVxuICAgIF0pLnBpcGUoXG4gICAgICB0YXAoKCkgPT4gdGhpcy5yZWdlblJlcG9ydCgpKVxuICAgICkuc3Vic2NyaWJlKCk7XG4gIH1cblxuICBwcml2YXRlIGxvZ0NoYW5nZShtb2RzOiBGb3JtVmFsdWUpIHtcbiAgICBjb25zdCBlbnRyeSA9IHtcbiAgICAgIGF1dGhvcjogdGhpcy5jdXJyZW50VXNlci5lbWFpbEFkZHJlc3MsXG4gICAgICB0aW1lc3RhbXA6IG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKSxcbiAgICAgIC4uLnNoYWxsb3dEaWZmKHRoaXMuaW5pdGlhbEZvcm1TdGF0ZSwgbW9kcylcbiAgICB9XG5cbiAgICB0aGlzLmRldGFpbENoYW5nZUxvZy5wdXNoKGVudHJ5KTtcblxuICAgIGNvbnNvbGUubG9nKHRoaXMuZGV0YWlsQ2hhbmdlTG9nKTtcbiAgfVxuXG4gIC8vIGdldCB0aGUgZGV2aWNlIGRhdGEgcmVjb3JkIGFuZCBpbml0aWFsaXNlIHRoZSBmb3JtXG4gIHByaXZhdGUgbG9hZERldmljZURhdGEoKSB7XG4gICAgdGhpcy5zaGFyZWQuZ2V0RGV2aWNlRGF0YShcbiAgICAgIHRoaXMuY29uZmlnLmRldmljZURhdGFNb2RlbElkLFxuICAgICAgdGhpcy5jb25maWcub3duZXJzWzBdLFxuICAgICAgcHJvcGVydHlDb2Rlc1xuICAgICkuc3Vic2NyaWJlKHtcbiAgICAgIG5leHQ6IChyZXMpID0+IHtcbiAgICAgICAgdGhpcy5kZXZpY2VEYXRhSWQgPSByZXMuZGV2aWNlRGF0YUlkO1xuICAgICAgICB0aGlzLnJlY29yZGluZ1Nlc3Npb24gPSBKU09OLnBhcnNlKHJlcy5kYXRhWydSZWNvcmRpbmdTZXNzaW9uJ10udmFsdWUpO1xuICAgICAgICB0aGlzLmluaXRpYWxpc2VGb3JtKHRoaXMuZXh0cmFjdEZpZWxkcyh0aGlzLnJlY29yZGluZ1Nlc3Npb24pKTtcblxuICAgICAgICAvLyBkYXRhIGZpZWxkIHVuaW5pdGlhbGlzZWQgZm9yIHVubW9kaWZpZWQgcmVjb3JkXG4gICAgICAgIHRoaXMuZGV0YWlsQ2hhbmdlTG9nID0gcmVzLmRhdGFbJ1VzZXJEZXRhaWxDaGFuZ2VMb2cnXT8udmFsdWUgPz8gW107XG5cbiAgICAgICAgdGhpcy5zdGF0dXMgPSByZXMuZGF0YVsnU3RhdHVzJ10/LnZhbHVlID09PSAnR2VuZXJhdGluZyBSZXBvcnQnID9cbiAgICAgICAgICAnZ2VuZXJhdGluZycgOlxuICAgICAgICAgICdzdWNjZXNzJztcbiAgICAgIH0sXG4gICAgICBlcnJvcjogKGVycikgPT4ge1xuICAgICAgICBjb25zb2xlLmVycm9yKGVycik7XG4gICAgICAgIHRoaXMuc3RhdHVzID0gXCJlcnJvclwiO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgcmVnZW5SZXBvcnQoKSB7XG4gICAgdGhpcy5wb3N0RGV2aWNlRGF0YShcbiAgICAgIGRldmljZURhdGFQcm9wZXJ0eVNldElkLFxuICAgICAgeyAnQWxnb3JpdGhtaGFzcnVuJzogZmFsc2UsICdBbGdvcml0aG1SdW4nOiB0cnVlIH1cbiAgICApLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICB0aGlzLnN0YXR1cyA9ICdnZW5lcmF0aW5nJzsgLy8gYXNzdW1lIHJlcG9ydCBzdGFydHMgZ2VuZXJhdGluZyBpbW1lZGlhdGVseVxuICAgIH0pXG4gIH1cblxuICByZXNldE1vZGlmaWNhdGlvbnMoKSB7XG4gICAgdGhpcy5mb3JtR3JvdXAucGF0Y2hWYWx1ZSh0aGlzLmluaXRpYWxGb3JtU3RhdGUpO1xuICB9XG5cbiAgbmdPbkluaXQoKSB7XG4gICAgaWYgKCF0aGlzLmNvbmZpZz8ub3duZXJzPy5bMF0pIHtcbiAgICAgIHRoaXMuc3RhdHVzID0gJ25vdXNlcic7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgZm9ya0pvaW4oW1xuICAgICAgdGhpcy5zaGFyZWQuZ2V0VXNlcih0aGlzLmNvbmZpZy5jdXJyZW50VXNlcklkKSxcbiAgICAgIHRoaXMuc2hhcmVkLmdldFVzZXIodGhpcy5jb25maWcub3duZXJzWzBdKVxuICAgIF0pLnBpcGUodGFwKChbY3VycmVudCwgb3duZXJdKSA9PiB7XG4gICAgICB0aGlzLmN1cnJlbnRVc2VyID0gY3VycmVudDtcbiAgICAgIHRoaXMub3duZXIgPSBvd25lcjtcbiAgICB9KSkuc3Vic2NyaWJlKCk7XG5cbiAgICB0aGlzLmxvYWREZXZpY2VEYXRhKCk7XG4gIH1cbn1cbiIsIjxkaXYgY2xhc3M9XCJ3cmFwcGVyXCI+XG4gIDxkaXYgY2xhc3M9XCJzdGF0dXNcIiAqbmdJZj1cInN0YXR1cyA9PT0gJ2Vycm9yJ1wiPlxuICAgIEFuIGVycm9yIG9jY3VyZWQgd2hpbGUgdHJ5aW5nIHRvIGdldCB0aGUgZGV0YWlscy5cbiAgPC9kaXY+XG4gIDxkaXYgY2xhc3M9XCJzdGF0dXNcIiAqbmdJZj1cInN0YXR1cyA9PT0gJ25vdXNlcidcIj5cbiAgICBUaGVyZSBpcyBubyB1c2VyIHNwZWNpZmllZCBhcyB0aGUgZGF0YSBvd25lci5cbiAgPC9kaXY+XG4gIDxmb3JtICpuZ0lmPVwic3RhdHVzICE9PSAnZXJyb3InICYmIHN0YXR1cyAhPT0gJ25vdXNlcidcIiBbZm9ybUdyb3VwXT1cImZvcm1Hcm91cFwiIChuZ1N1Ym1pdCk9XCJzYXZlTW9kaWZpY2F0aW9ucygpXCI+XG4gICAgPGRpdiBjbGFzcz1cImlucHV0c1wiPlxuICAgICAgPGRpdiBjbGFzcz1cImZvcm0tcm93XCI+XG4gICAgICAgIDxsYWJlbCBmb3I9XCJkb2JcIj5EYXRlIG9mIEJpcnRoOjwvbGFiZWw+XG4gICAgICAgIDxpbnB1dCBpZD1cImRvYlwiIHR5cGU9XCJkYXRlXCIgZm9ybUNvbnRyb2xOYW1lPVwiZG9iXCI+XG4gICAgICA8L2Rpdj5cblxuICAgICAgPGRpdiBjbGFzcz1cImZvcm0tcm93XCI+XG4gICAgICAgIDxsYWJlbCBmb3I9XCJ3ZWlnaHRcIj5QYXRpZW50IFdlaWdodCAoa2cpOjwvbGFiZWw+XG4gICAgICAgIDxpbnB1dCBpZD1cIndlaWdodFwiIHR5cGU9XCJudW1iZXJcIiBmb3JtQ29udHJvbE5hbWU9XCJ3ZWlnaHRcIj5cbiAgICAgIDwvZGl2PlxuXG4gICAgICA8ZGl2IGNsYXNzPVwiZm9ybS1yb3dcIj5cbiAgICAgICAgPGxhYmVsIGZvcj1cImhlaWdodFwiPlBhdGllbnQgSGVpZ2h0IChjbSk6PC9sYWJlbD5cbiAgICAgICAgPGlucHV0IGlkPVwiaGVpZ2h0XCIgdHlwZT1cIm51bWJlclwiIGZvcm1Db250cm9sTmFtZT1cImhlaWdodFwiPlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDxkaXYgY2xhc3M9XCJmb3JtLXJvd1wiPlxuICAgICAgICA8bGFiZWwgZm9yPVwibWVhbFN0YXJ0XCI+TWVhbCBTdGFydCBUaW1lOjwvbGFiZWw+XG4gICAgICAgIDxpbnB1dCBpZD1cIm1lYWxTdGFydFwiIHR5cGU9XCJkYXRldGltZS1sb2NhbFwiIGZvcm1Db250cm9sTmFtZT1cIm1lYWxTdGFydFwiPlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDxkaXYgY2xhc3M9XCJmb3JtLXJvd1wiPlxuICAgICAgICA8bGFiZWwgZm9yPVwibWVhbEVuZFwiPk1lYWwgRW5kIFRpbWU6PC9sYWJlbD5cbiAgICAgICAgPGlucHV0IGlkPVwibWVhbEVuZFwiIHR5cGU9XCJkYXRldGltZS1sb2NhbFwiIGZvcm1Db250cm9sTmFtZT1cIm1lYWxFbmRcIj5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuXG4gICAgPGRpdiAqbmdJZj1cIiFmb3JtR3JvdXAudmFsaWQgJiYgZm9ybUdyb3VwLmRpcnR5XCIgY2xhc3M9XCJlcnJvcnNcIj5cbiAgICAgIDxkaXYgKm5nRm9yPVwibGV0IGNvbnRyb2wgb2YgZm9ybUdyb3VwLmNvbnRyb2xzIHwgZW50cmllc1wiPlxuICAgICAgICB7eyBwYXJzZUlucHV0RXJyb3JzKGNvbnRyb2xbMF0sIGNvbnRyb2xbMV0pIH19XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cblxuICAgIDxkaXYgKm5nSWY9XCJzdGF0dXMgPT09ICdnZW5lcmF0aW5nJ1wiIGNsYXNzPVwiaW5mb1wiPlxuICAgICAgPGRpdj5UaGUgcmVwb3J0IGlzIGdlbmVyYXRpbmcgYXQgdGhlIG1vbWVudCwgY2hlY2sgYmFjayBsYXRlciBpZiB5b3UgbmVlZCB0byBtb2RpZnkgdGhpcyBlbnRyeS48L2Rpdj5cbiAgICA8L2Rpdj5cblxuICAgIDxkaXYgY2xhc3M9XCJidXR0b25zXCI+XG4gICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiAoY2xpY2spPVwicmVnZW5SZXBvcnQoKVwiIFtkaXNhYmxlZF09XCJzdGF0dXMgPT09ICdzZW5kaW5nJyB8fCBzdGF0dXMgPT09ICdnZW5lcmF0aW5nJyB8fCBzdGF0dXMgPT09ICdsb2FkaW5nJ1wiPlJlZ2VuZXJhdGUgUmVwb3J0PC9idXR0b24+XG4gICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiAoY2xpY2spPVwicmVzZXRNb2RpZmljYXRpb25zKClcIiBbZGlzYWJsZWRdPVwic3RhdHVzID09PSAnc2VuZGluZycgfHwgc3RhdHVzID09PSAnZ2VuZXJhdGluZycgfHwgZm9ybUdyb3VwLnByaXN0aW5lXCI+Q2FuY2VsIE1vZGlmaWNhdGlvbjwvYnV0dG9uPlxuICAgICAgPGJ1dHRvbiB0eXBlPVwic3VibWl0XCIgW2Rpc2FibGVkXT1cInN0YXR1cyA9PT0gJ3NlbmRpbmcnIHx8IHN0YXR1cyA9PT0gJ2dlbmVyYXRpbmcnIHx8ICFmb3JtR3JvdXAudmFsaWQgfHwgZm9ybUdyb3VwLnByaXN0aW5lXCI+U2F2ZSBEZXRhaWxzPC9idXR0b24+XG4gICAgPC9kaXY+XG4gIDwvZm9ybT5cbjwvZGl2PlxuIl19
169
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGV0YWlsLWVkaXQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvZGV0YWlsLWVkaXQvc3JjL2xpYi9kZXRhaWwtZWRpdC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9wcm9qZWN0cy9kZXRhaWwtZWRpdC9zcmMvbGliL2RldGFpbC1lZGl0LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQVcsS0FBSyxFQUFvRSxNQUFNLGVBQWUsQ0FBQztBQUM1SCxPQUFPLEVBQW1CLFdBQVcsRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDckYsT0FBTyxFQUFFLFFBQVEsRUFBRSxHQUFHLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFFckMsT0FBTyxFQUFFLE1BQU0sRUFBRSxpQkFBaUIsRUFBRSxnQkFBZ0IsRUFBRSxjQUFjLEVBQUUsV0FBVyxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQ25HLE9BQU8sRUFBRSxjQUFjLEVBQUUsWUFBWSxFQUFFLFlBQVksRUFBRSxjQUFjLEVBQUUsTUFBTSxjQUFjLENBQUM7Ozs7OztBQUUxRixNQUFNLG9CQUFvQixHQUFHLHNDQUFzQyxDQUFDO0FBQ3BFLE1BQU0sdUJBQXVCLEdBQUcsc0NBQXNDLENBQUM7QUFDdkUsTUFBTSxhQUFhLEdBQUcsQ0FBQyxrQkFBa0IsRUFBRSxRQUFRLEVBQUUscUJBQXFCLENBQUMsQ0FBQztBQXNCNUUsTUFBTSxPQUFPLG1CQUFtQjtJQStCOUIsWUFBb0IsTUFBcUIsRUFBVSxTQUEwQixFQUFVLFNBQTBCO1FBQTdGLFdBQU0sR0FBTixNQUFNLENBQWU7UUFBVSxjQUFTLEdBQVQsU0FBUyxDQUFpQjtRQUFVLGNBQVMsR0FBVCxTQUFTLENBQWlCO1FBekJqSCxXQUFNLEdBQXVGLFNBQVMsQ0FBQztRQWN2RyxjQUFTLEdBQUcsSUFBSSxTQUFTLENBQUM7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QUUsQ0FBQztRQUNyRyxJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUUsTUFBTSxJQUFJLENBQUMsSUFBSSxDQUFDLFlBQVk7WUFBRSxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUM7SUFDdEgsQ0FBQztJQUVELFNBQVM7UUFDUCxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsWUFBWSxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDM0QsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLFlBQVksRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQztRQUVuRSxJQUFJLGFBQWEsSUFBSSxhQUFhO1lBQUUsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ2xELENBQUM7O2lIQXBNVSxtQkFBbUI7cUdBQW5CLG1CQUFtQixxRkMvQmhDLGk3RUF1REE7NEZEeEJhLG1CQUFtQjtrQkFML0IsU0FBUzsrQkFDRSxpQkFBaUI7Z0tBS2xCLE1BQU07c0JBQWQsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgRG9DaGVjaywgSW5wdXQsIEtleVZhbHVlRGlmZmVycywgS2V5VmFsdWVEaWZmZXIsIEl0ZXJhYmxlRGlmZmVyLCBJdGVyYWJsZURpZmZlcnMgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEFic3RyYWN0Q29udHJvbCwgRm9ybUNvbnRyb2wsIEZvcm1Hcm91cCwgVmFsaWRhdG9ycyB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IGZvcmtKb2luLCB0YXAgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IENvbmZpZywgU2hhcmVkU2VydmljZSwgVXNlciB9IGZyb20gJ2FsaW1ldHJ5LXNoYXJlZCc7XG5pbXBvcnQgeyBnZXRBZ2UsIGdsb2JhbGlzZURhdGVUaW1lLCBsb2NhbGlzZURhdGVUaW1lLCBzaGFsbG93Q29tcGFyZSwgc2hhbGxvd0RpZmYgfSBmcm9tICcuL3V0aWxzJztcbmltcG9ydCB7IGRhdGVDb21wYXJpc29uLCB3aXRoaW5OWWVhcnMsIHdpdGhpbk5Ib3VycywgdHJhbnNsYXRlRXJyb3IgfSBmcm9tICcuL3ZhbGlkYXRvcnMnO1xuXG5jb25zdCBhcHBEYXRhUHJvcGVydHlTZXRJZCA9ICczNGQ0NjQ3Ny1hZDRiLTQ3YjQtYjU1NS0wNjM1OGI5MmY2MGMnO1xuY29uc3QgZGV2aWNlRGF0YVByb3BlcnR5U2V0SWQgPSAnN2EzMmQ4NTEtNWU4OS00NmE2LWE0YjYtY2NhMTYyZGFjZTI5JztcbmNvbnN0IHByb3BlcnR5Q29kZXMgPSBbJ1JlY29yZGluZ1Nlc3Npb24nLCAnU3RhdHVzJywgJ1VzZXJEZXRhaWxDaGFuZ2VMb2cnXTtcblxuaW50ZXJmYWNlIEZvcm1WYWx1ZSB7XG4gIGRvYjogc3RyaW5nLFxuICBoZWlnaHQ6IG51bWJlcixcbiAgd2VpZ2h0OiBudW1iZXIsXG4gIG1lYWxTdGFydDogc3RyaW5nLFxuICBtZWFsRW5kOiBzdHJpbmdcbn1cblxuaW50ZXJmYWNlIENoYW5nZSB7XG4gIHRpbWVzdGFtcDogc3RyaW5nLFxuICBhdXRob3I6IHN0cmluZyxcbiAgZnJvbTogUGFydGlhbDxGb3JtVmFsdWU+LFxuICB0bzogUGFydGlhbDxGb3JtVmFsdWU+XG59XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2xpYi1kZXRhaWwtZWRpdCcsXG4gIHRlbXBsYXRlVXJsOiAnLi9kZXRhaWwtZWRpdC5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL2RldGFpbC1lZGl0LmNvbXBvbmVudC5jc3MnXVxufSlcbmV4cG9ydCBjbGFzcyBEZXRhaWxFZGl0Q29tcG9uZW50IGltcGxlbWVudHMgRG9DaGVjayB7XG4gIEBJbnB1dCgpIGNvbmZpZyE6IENvbmZpZztcblxuICBwcml2YXRlIGNvbmZpZ0RpZmZlcj86IEtleVZhbHVlRGlmZmVyPGtleW9mIENvbmZpZywgYW55PjtcbiAgcHJpdmF0ZSBvd25lcnNEaWZmZXI/OiBJdGVyYWJsZURpZmZlcjxzdHJpbmc+O1xuXG4gIHN0YXR1czogJ2Vycm9yJyB8ICdjZmdlcnJvcicgfCAnbG9hZGluZycgfCAnc3VjY2VzcycgfCAnZ2VuZXJhdGluZycgfCAnc2VuZGluZycgfCAnbm91c2VyJyA9ICdsb2FkaW5nJztcblxuICAvLyBkZXZpY2UgZGF0YSBwb3B1bGF0ZWQgYnkgbG9hZCByZXF1ZXN0XG4gIHByaXZhdGUgZGV2aWNlRGF0YUlkOiBzdHJpbmc7XG4gIHByaXZhdGUgcmVjb3JkaW5nU2Vzc2lvbjogb2JqZWN0O1xuICBwcml2YXRlIHJlY29yZGluZ1N0YXJ0OiBzdHJpbmc7XG4gIHByaXZhdGUgaW5pdGlhbEZvcm1TdGF0ZTogb2JqZWN0O1xuXG4gIC8vIHVzZXIgZGF0YSBleHBhbmRlZCBmcm9tIGlkcyBwYXNzZWQgaW4gY29uZmlnXG4gIHByaXZhdGUgY3VycmVudFVzZXI6IFVzZXI7XG4gIHByaXZhdGUgb3duZXI6IFVzZXI7XG5cbiAgcHJpdmF0ZSBkZXRhaWxDaGFuZ2VMb2c6IENoYW5nZVtdO1xuXG4gIGZvcm1Hcm91cCA9IG5ldyBGb3JtR3JvdXAoe1xuICAgIGRvYjogbmV3IEZvcm1Db250cm9sPHN0cmluZz4oJycsIFtWYWxpZGF0b3JzLnJlcXVpcmVkLCB3aXRoaW5OWWVhcnMoMTIwLCAnYmVmb3JlJyldKSxcbiAgICBoZWlnaHQ6IG5ldyBGb3JtQ29udHJvbDxudW1iZXI+KDAsIFtWYWxpZGF0b3JzLnJlcXVpcmVkLCBWYWxpZGF0b3JzLm1pbigzMCksIFZhbGlkYXRvcnMubWF4KDI3MildKSxcbiAgICB3ZWlnaHQ6IG5ldyBGb3JtQ29udHJvbDxudW1iZXI+KDAsIFtWYWxpZGF0b3JzLnJlcXVpcmVkLCBWYWxpZGF0b3JzLm1pbigxKSwgVmFsaWRhdG9ycy5tYXgoNjM1KV0pLFxuICAgIG1lYWxTdGFydDogbmV3IEZvcm1Db250cm9sPHN0cmluZz4oJycsIFtWYWxpZGF0b3JzLnJlcXVpcmVkXSksXG4gICAgbWVhbEVuZDogbmV3IEZvcm1Db250cm9sPHN0cmluZz4oJycsIFtWYWxpZGF0b3JzLnJlcXVpcmVkXSlcbiAgfSwgW1xuICAgIGRhdGVDb21wYXJpc29uKCdtZWFsRW5kJywgJ21lYWxTdGFydCcsICdhZnRlcicpLFxuICAgIGRhdGVDb21wYXJpc29uKCdtZWFsU3RhcnQnLCAnZG9iJywgJ2FmdGVyJyksXG4gIF0pO1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgc2hhcmVkOiBTaGFyZWRTZXJ2aWNlLCBwcml2YXRlIGt2RGlmZmVyczogS2V5VmFsdWVEaWZmZXJzLCBwcml2YXRlIGl0RGlmZmVyczogSXRlcmFibGVEaWZmZXJzKSB7IH1cblxuICBwYXJzZUlucHV0RXJyb3JzKG5hbWU6IHN0cmluZywgY29udHJvbDogQWJzdHJhY3RDb250cm9sKSB7XG4gICAgcmV0dXJuIHRyYW5zbGF0ZUVycm9yKG5hbWUsIGNvbnRyb2wpO1xuICB9XG5cbiAgLy8gbWFrZSBzdXJlIHRoYW4gbW9kaWZpY2F0aW9ucyB0aGF0IGRvbid0IGFjdHVhbGx5IGRpZmZlciBmcm9tIHRoZSBjdXJyZW50IGFyZSBtYXJrZWQgYXMgc3VjaFxuICBwcml2YXRlIG1vbml0b3JGb3JtQ2hhbmdlcygpIHtcbiAgICB0aGlzLmZvcm1Hcm91cC52YWx1ZUNoYW5nZXMuc3Vic2NyaWJlKGN1cnJlbnQgPT4ge1xuICAgICAgaWYgKHNoYWxsb3dDb21wYXJlKGN1cnJlbnQsIHRoaXMuaW5pdGlhbEZvcm1TdGF0ZSkpIHtcbiAgICAgICAgdGhpcy5mb3JtR3JvdXAubWFya0FzUHJpc3RpbmUoKTtcbiAgICAgIH1cbiAgICB9KVxuICB9XG5cbiAgLy8gaGFuZGxlIHRoZSByZWxldmFudCBkYXRhIGZyb20gdGhlIHJlc3BvbnNlIGJvZHlcbiAgcHJpdmF0ZSBleHRyYWN0RmllbGRzKHJlY29yZGluZ1Nlc3Npb246IFJlY29yZDxzdHJpbmcsIGFueT4pIHtcbiAgICBjb25zdCB7IHBhdGllbnQsIG1lYWxTdGFydCwgbWVhbEVuZCwgcmVjb3JkaW5nU3RhcnQgfSA9IHJlY29yZGluZ1Nlc3Npb247XG4gICAgdGhpcy5yZWNvcmRpbmdTdGFydCA9IHJlY29yZGluZ1N0YXJ0O1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIGRvYjogdGhpcy5vd25lci5kYXRlT2ZCaXJ0aCxcbiAgICAgIGhlaWdodDogcGF0aWVudC5oZWlnaHQsXG4gICAgICB3ZWlnaHQ6IHBhdGllbnQud2VpZ2h0LFxuICAgICAgbWVhbFN0YXJ0OiBsb2NhbGlzZURhdGVUaW1lKG1lYWxTdGFydCksXG4gICAgICBtZWFsRW5kOiBsb2NhbGlzZURhdGVUaW1lKG1lYWxFbmQpXG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBpbml0aWFsaXNlRm9ybShzdGF0ZTogb2JqZWN0KSB7XG4gICAgdGhpcy5mb3JtR3JvdXAucGF0Y2hWYWx1ZShzdGF0ZSk7XG4gICAgdGhpcy5mb3JtR3JvdXAubWFya0FzUHJpc3RpbmUoKTtcblxuICAgIHRoaXMuZm9ybUdyb3VwLmdldCgnbWVhbFN0YXJ0JykuYWRkVmFsaWRhdG9ycyh3aXRoaW5OSG91cnMoMjQsICdhZnRlcicsIG5ldyBEYXRlKHRoaXMucmVjb3JkaW5nU3RhcnQpKSk7XG4gICAgdGhpcy5mb3JtR3JvdXAuZ2V0KCdtZWFsRW5kJykuYWRkVmFsaWRhdG9ycyh3aXRoaW5OSG91cnMoMjQsICdhZnRlcicsIG5ldyBEYXRlKHRoaXMucmVjb3JkaW5nU3RhcnQpKSk7XG5cbiAgICB0aGlzLmluaXRpYWxGb3JtU3RhdGUgPSBzdGF0ZTsgLy8gc2F2ZSB0aGlzIGZvciB1c2UgaW4gcmVzZXRzXG4gICAgdGhpcy5tb25pdG9yRm9ybUNoYW5nZXMoKTtcbiAgfVxuXG4gIC8vIGNvbnN0cnVjdCBhIHBhdGNoIG9iamVjdCBmb3IgdGhlIHNhdmUgcmVxdWVzdFxuICBwcml2YXRlIGludGVncmF0ZUZpZWxkcyhtb2RzOiBGb3JtVmFsdWUsIHJlY29yZGluZ1Nlc3Npb246IFJlY29yZDxzdHJpbmcsIGFueT4pIHtcbiAgICBjb25zdCB7IHBhdGllbnQgfSA9IHJlY29yZGluZ1Nlc3Npb247XG4gICAgcGF0aWVudC5oZWlnaHQgPSBtb2RzLmhlaWdodDtcbiAgICBwYXRpZW50LndlaWdodCA9IG1vZHMud2VpZ2h0O1xuICAgIHBhdGllbnQuYWdlID0gZ2V0QWdlKG1vZHMuZG9iKTtcblxuICAgIHJlY29yZGluZ1Nlc3Npb24ubWVhbFN0YXJ0ID0gZ2xvYmFsaXNlRGF0ZVRpbWUobW9kcy5tZWFsU3RhcnQpO1xuICAgIHJlY29yZGluZ1Nlc3Npb24ubWVhbEVuZCA9IGdsb2JhbGlzZURhdGVUaW1lKG1vZHMubWVhbEVuZCk7XG5cbiAgICB0aGlzLmxvZ0NoYW5nZShtb2RzKTtcblxuICAgIHJldHVybiB7XG4gICAgICAnQWdlJzogcGF0aWVudC5hZ2UsXG4gICAgICAnUmVjb3JkaW5nU2Vzc2lvbic6IEpTT04uc3RyaW5naWZ5KHJlY29yZGluZ1Nlc3Npb24pLFxuICAgICAgJ1VzZXJEZXRhaWxDaGFuZ2VMb2cnOiB0aGlzLmRldGFpbENoYW5nZUxvZ1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgcG9zdERldmljZURhdGEoZGV2aWNlUHJvcGVydHlTZXRJZDogc3RyaW5nLCBkYXRhOiBvYmplY3QpIHtcbiAgICByZXR1cm4gdGhpcy5zaGFyZWQuc2F2ZURldmljZURhdGEoXG4gICAgICB0aGlzLmNvbmZpZy5kZXZpY2VEYXRhTW9kZWxJZCxcbiAgICAgIHRoaXMuZGV2aWNlRGF0YUlkLFxuICAgICAgZGV2aWNlUHJvcGVydHlTZXRJZCxcbiAgICAgIHRoaXMuY29uZmlnLm93bmVyc1swXSxcbiAgICAgIGRhdGFcbiAgICApO1xuICB9XG5cbiAgLy8gcGF0Y2ggdGhlIGRldmljZSBkYXRhIHJlY29yZCB3aXRoIHRoZSBtb2RpZmljYXRpb25zXG4gIHNhdmVNb2RpZmljYXRpb25zKCkge1xuICAgIGNvbnN0IG1vZHMgPSB0aGlzLmZvcm1Hcm91cC5nZXRSYXdWYWx1ZSgpO1xuICAgIGNvbnN0IHBhdGNoZWREZXZpY2VEYXRhID0gdGhpcy5pbnRlZ3JhdGVGaWVsZHMobW9kcywgdGhpcy5yZWNvcmRpbmdTZXNzaW9uKTtcbiAgICBjb25zdCBwYXRjaGVkVXNlckRhdGEgPSBPYmplY3QuYXNzaWduKHRoaXMub3duZXIsIHsgZGF0ZU9mQmlydGg6IG1vZHMuZG9iIH0pO1xuXG4gICAgdGhpcy5zdGF0dXMgPSAnc2VuZGluZyc7XG4gICAgZm9ya0pvaW4oW1xuICAgICAgdGhpcy5wb3N0RGV2aWNlRGF0YShhcHBEYXRhUHJvcGVydHlTZXRJZCwgcGF0Y2hlZERldmljZURhdGEpLFxuICAgICAgdGhpcy5zaGFyZWQudXBkYXRlVXNlcih0aGlzLmNvbmZpZy5vd25lcnNbMF0sIHBhdGNoZWRVc2VyRGF0YSlcbiAgICBdKS5waXBlKFxuICAgICAgdGFwKCgpID0+IHRoaXMucmVnZW5SZXBvcnQoKSlcbiAgICApLnN1YnNjcmliZSgpO1xuICB9XG5cbiAgcHJpdmF0ZSBsb2dDaGFuZ2UobW9kczogRm9ybVZhbHVlKSB7XG4gICAgY29uc3QgZW50cnkgPSB7XG4gICAgICBhdXRob3I6IHRoaXMuY3VycmVudFVzZXIuZW1haWxBZGRyZXNzLFxuICAgICAgdGltZXN0YW1wOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgICAuLi5zaGFsbG93RGlmZih0aGlzLmluaXRpYWxGb3JtU3RhdGUsIG1vZHMpXG4gICAgfVxuXG4gICAgdGhpcy5kZXRhaWxDaGFuZ2VMb2cucHVzaChlbnRyeSk7XG5cbiAgICBjb25zb2xlLmxvZyh0aGlzLmRldGFpbENoYW5nZUxvZyk7XG4gIH1cblxuICByZWdlblJlcG9ydCgpIHtcbiAgICB0aGlzLnBvc3REZXZpY2VEYXRhKFxuICAgICAgZGV2aWNlRGF0YVByb3BlcnR5U2V0SWQsXG4gICAgICB7ICdBbGdvcml0aG1oYXNydW4nOiBmYWxzZSwgJ0FsZ29yaXRobVJ1bic6IHRydWUgfVxuICAgICkuc3Vic2NyaWJlKCgpID0+IHtcbiAgICAgIHRoaXMuc3RhdHVzID0gJ2dlbmVyYXRpbmcnOyAvLyBhc3N1bWUgcmVwb3J0IHN0YXJ0cyBnZW5lcmF0aW5nIGltbWVkaWF0ZWx5XG4gICAgfSlcbiAgfVxuXG4gIHJlc2V0TW9kaWZpY2F0aW9ucygpIHtcbiAgICB0aGlzLmZvcm1Hcm91cC5wYXRjaFZhbHVlKHRoaXMuaW5pdGlhbEZvcm1TdGF0ZSk7XG4gIH1cblxuICBwcml2YXRlIGxvYWREYXRhKGN1cnJlbnRVc2VySWQ6IHN0cmluZywgb3duZXJJZDogc3RyaW5nLCBkZXZpY2VEYXRhTW9kZWxJZDogc3RyaW5nKSB7XG4gICAgZm9ya0pvaW4oW1xuICAgICAgdGhpcy5zaGFyZWQuZ2V0VXNlcihjdXJyZW50VXNlcklkKSxcbiAgICAgIHRoaXMuc2hhcmVkLmdldFVzZXIob3duZXJJZCksXG4gICAgICB0aGlzLnNoYXJlZC5nZXREZXZpY2VEYXRhKGRldmljZURhdGFNb2RlbElkLCBvd25lcklkLCBwcm9wZXJ0eUNvZGVzKVxuICAgIF0pLnN1YnNjcmliZSh7XG4gICAgICBuZXh0OiAoW2N1cnJlbnRVc2VyLCBvd25lciwgeyBkZXZpY2VEYXRhSWQsIGRhdGE6IGRldmljZURhdGEgfV0pID0+IHtcbiAgICAgICAgdGhpcy5jdXJyZW50VXNlciA9IGN1cnJlbnRVc2VyO1xuICAgICAgICB0aGlzLm93bmVyID0gb3duZXI7XG4gICAgICAgIHRoaXMuZGV2aWNlRGF0YUlkID0gZGV2aWNlRGF0YUlkO1xuXG4gICAgICAgIHRoaXMucmVjb3JkaW5nU2Vzc2lvbiA9IEpTT04ucGFyc2UoZGV2aWNlRGF0YVsnUmVjb3JkaW5nU2Vzc2lvbiddLnZhbHVlKTtcbiAgICAgICAgdGhpcy5pbml0aWFsaXNlRm9ybSh0aGlzLmV4dHJhY3RGaWVsZHModGhpcy5yZWNvcmRpbmdTZXNzaW9uKSk7XG5cbiAgICAgICAgLy8gZGF0YSBmaWVsZCB1bmluaXRpYWxpc2VkIGZvciB1bm1vZGlmaWVkIHJlY29yZFxuICAgICAgICB0aGlzLmRldGFpbENoYW5nZUxvZyA9IGRldmljZURhdGFbJ1VzZXJEZXRhaWxDaGFuZ2VMb2cnXT8udmFsdWUgPz8gW107XG5cbiAgICAgICAgdGhpcy5zdGF0dXMgPSBkZXZpY2VEYXRhWydTdGF0dXMnXT8udmFsdWUgPT09ICdHZW5lcmF0aW5nIFJlcG9ydCcgP1xuICAgICAgICAgICdnZW5lcmF0aW5nJyA6ICdzdWNjZXNzJztcbiAgICAgIH0sXG4gICAgICBlcnJvcjogKGVycikgPT4ge1xuICAgICAgICBjb25zb2xlLmVycm9yKGVycik7XG4gICAgICAgIHRoaXMuc3RhdHVzID0gXCJlcnJvclwiO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBpbml0KCkge1xuICAgIGlmICghdGhpcy5jb25maWc/LmN1cnJlbnRVc2VySWQgfHwgIXRoaXMuY29uZmlnLmRldmljZURhdGFNb2RlbElkKSB7XG4gICAgICB0aGlzLnN0YXR1cyA9ICdjZmdlcnJvcidcbiAgICAgIHJldHVybjtcbiAgICB9IGVsc2UgaWYgKCF0aGlzLmNvbmZpZz8ub3duZXJzPy5bMF0pIHtcbiAgICAgIHRoaXMuc3RhdHVzID0gJ25vdXNlcic7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5zdGF0dXMgPSAnbG9hZGluZyc7XG4gICAgdGhpcy5sb2FkRGF0YSh0aGlzLmNvbmZpZy5jdXJyZW50VXNlcklkLCB0aGlzLmNvbmZpZy5vd25lcnNbMF0sIHRoaXMuY29uZmlnLmRldmljZURhdGFNb2RlbElkKTtcbiAgfVxuXG4gIC8vIHRoaXMgc2hvdWxkIGJlIGNhbGxlZCBmcm9tIHRoZSBwYXJlbnQgdXNpbmcgdGhlIFZpZXdDaGlsZCBhdHRyXG4gIHJlZnJlc2goKSB7XG4gICAgdGhpcy5pbml0KCk7XG4gIH1cblxuICAvLyBOT1RFOiB0aGVyZSBjb3VsZCBiZSBzb21ldGhpbmcgd3JvbmcgLyB1bnVzdWFsIGhlcmUgYnV0IGl0IHNlZW1zIHRvIHdvcmsgb2tcbiAgbmdPbkluaXQoKSB7XG4gICAgaWYgKHRoaXMuY29uZmlnICYmICF0aGlzLmNvbmZpZ0RpZmZlcikgdGhpcy5jb25maWdEaWZmZXIgPSB0aGlzLmt2RGlmZmVycy5maW5kKHRoaXMuY29uZmlnKS5jcmVhdGUoKTtcbiAgICBpZiAodGhpcy5jb25maWc/Lm93bmVycyAmJiAhdGhpcy5vd25lcnNEaWZmZXIpIHRoaXMub3duZXJzRGlmZmVyID0gdGhpcy5pdERpZmZlcnMuZmluZCh0aGlzLmNvbmZpZy5vd25lcnMpLmNyZWF0ZSgpO1xuICB9XG5cbiAgbmdEb0NoZWNrKCkge1xuICAgIGNvbnN0IGNvbmZpZ0NoYW5nZXMgPSB0aGlzLmNvbmZpZ0RpZmZlcj8uZGlmZih0aGlzLmNvbmZpZyk7XG4gICAgY29uc3Qgb3duZXJzQ2hhbmdlcyA9IHRoaXMub3duZXJzRGlmZmVyPy5kaWZmKHRoaXMuY29uZmlnPy5vd25lcnMpO1xuXG4gICAgaWYgKGNvbmZpZ0NoYW5nZXMgfHwgb3duZXJzQ2hhbmdlcykgdGhpcy5pbml0KCk7XG4gIH1cbn1cbiIsIjxkaXYgY2xhc3M9XCJ3cmFwcGVyXCI+XG4gIDxkaXYgY2xhc3M9XCJzdGF0dXNcIiAqbmdJZj1cInN0YXR1cyA9PT0gJ2Vycm9yJ1wiPlxuICAgIEFuIGVycm9yIG9jY3VyZWQgd2hpbGUgdHJ5aW5nIHRvIGdldCB0aGUgZGV0YWlscy5cbiAgPC9kaXY+XG4gIDxkaXYgY2xhc3M9XCJzdGF0dXNcIiAqbmdJZj1cInN0YXR1cyA9PT0gJ2NmZ2Vycm9yJ1wiPlxuICAgIFRoZSB3aWRnZXQgaGFzIG5vdCBiZWVuIGNvbmZpZ3VyZWQgY29ycmVjdGx5LCBvciBpcyBtaXNzaW5nIGNvbmZpZ3VyYXRpb24gaW5mb3JtYXRpb24uXG4gIDwvZGl2PlxuICA8ZGl2IGNsYXNzPVwic3RhdHVzXCIgKm5nSWY9XCJzdGF0dXMgPT09ICdub3VzZXInXCI+XG4gICAgVGhlcmUgaXMgbm8gdXNlciBzcGVjaWZpZWQgYXMgdGhlIGRhdGEgb3duZXIuXG4gIDwvZGl2PlxuICA8Zm9ybSAqbmdJZj1cIiFzdGF0dXMuaW5jbHVkZXMoJ2Vycm9yJykgJiYgc3RhdHVzICE9PSAnbm91c2VyJ1wiIFtmb3JtR3JvdXBdPVwiZm9ybUdyb3VwXCIgKG5nU3VibWl0KT1cInNhdmVNb2RpZmljYXRpb25zKClcIj5cbiAgICA8ZGl2IGNsYXNzPVwiaW5wdXRzXCI+XG4gICAgICA8ZGl2IGNsYXNzPVwiZm9ybS1yb3dcIj5cbiAgICAgICAgPGxhYmVsIGZvcj1cImRvYlwiPkRhdGUgb2YgQmlydGg6PC9sYWJlbD5cbiAgICAgICAgPGlucHV0IGlkPVwiZG9iXCIgdHlwZT1cImRhdGVcIiBmb3JtQ29udHJvbE5hbWU9XCJkb2JcIj5cbiAgICAgIDwvZGl2PlxuXG4gICAgICA8ZGl2IGNsYXNzPVwiZm9ybS1yb3dcIj5cbiAgICAgICAgPGxhYmVsIGZvcj1cIndlaWdodFwiPlBhdGllbnQgV2VpZ2h0IChrZyk6PC9sYWJlbD5cbiAgICAgICAgPGlucHV0IGlkPVwid2VpZ2h0XCIgdHlwZT1cIm51bWJlclwiIGZvcm1Db250cm9sTmFtZT1cIndlaWdodFwiPlxuICAgICAgPC9kaXY+XG5cbiAgICAgIDxkaXYgY2xhc3M9XCJmb3JtLXJvd1wiPlxuICAgICAgICA8bGFiZWwgZm9yPVwiaGVpZ2h0XCI+UGF0aWVudCBIZWlnaHQgKGNtKTo8L2xhYmVsPlxuICAgICAgICA8aW5wdXQgaWQ9XCJoZWlnaHRcIiB0eXBlPVwibnVtYmVyXCIgZm9ybUNvbnRyb2xOYW1lPVwiaGVpZ2h0XCI+XG4gICAgICA8L2Rpdj5cblxuICAgICAgPGRpdiBjbGFzcz1cImZvcm0tcm93XCI+XG4gICAgICAgIDxsYWJlbCBmb3I9XCJtZWFsU3RhcnRcIj5NZWFsIFN0YXJ0IFRpbWU6PC9sYWJlbD5cbiAgICAgICAgPGlucHV0IGlkPVwibWVhbFN0YXJ0XCIgdHlwZT1cImRhdGV0aW1lLWxvY2FsXCIgZm9ybUNvbnRyb2xOYW1lPVwibWVhbFN0YXJ0XCI+XG4gICAgICA8L2Rpdj5cblxuICAgICAgPGRpdiBjbGFzcz1cImZvcm0tcm93XCI+XG4gICAgICAgIDxsYWJlbCBmb3I9XCJtZWFsRW5kXCI+TWVhbCBFbmQgVGltZTo8L2xhYmVsPlxuICAgICAgICA8aW5wdXQgaWQ9XCJtZWFsRW5kXCIgdHlwZT1cImRhdGV0aW1lLWxvY2FsXCIgZm9ybUNvbnRyb2xOYW1lPVwibWVhbEVuZFwiPlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG5cbiAgICA8ZGl2ICpuZ0lmPVwiIWZvcm1Hcm91cC52YWxpZCAmJiBmb3JtR3JvdXAuZGlydHlcIiBjbGFzcz1cImVycm9yc1wiPlxuICAgICAgPGRpdiAqbmdGb3I9XCJsZXQgY29udHJvbCBvZiBmb3JtR3JvdXAuY29udHJvbHMgfCBlbnRyaWVzXCI+XG4gICAgICAgIHt7IHBhcnNlSW5wdXRFcnJvcnMoY29udHJvbFswXSwgY29udHJvbFsxXSkgfX1cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuXG4gICAgPGRpdiAqbmdJZj1cInN0YXR1cyA9PT0gJ2dlbmVyYXRpbmcnXCIgY2xhc3M9XCJpbmZvXCI+XG4gICAgICA8ZGl2PlRoZSByZXBvcnQgaXMgZ2VuZXJhdGluZyBhdCB0aGUgbW9tZW50LCBjaGVjayBiYWNrIGxhdGVyIGlmIHlvdSBuZWVkIHRvIG1vZGlmeSB0aGlzIGVudHJ5LjwvZGl2PlxuICAgIDwvZGl2PlxuXG4gICAgPGRpdiBjbGFzcz1cImJ1dHRvbnNcIj5cbiAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIChjbGljayk9XCJyZWdlblJlcG9ydCgpXCIgW2Rpc2FibGVkXT1cInN0YXR1cyA9PT0gJ3NlbmRpbmcnIHx8IHN0YXR1cyA9PT0gJ2dlbmVyYXRpbmcnIHx8IHN0YXR1cyA9PT0gJ2xvYWRpbmcnXCI+UmVnZW5lcmF0ZSBSZXBvcnQ8L2J1dHRvbj5cbiAgICAgIDxidXR0b24gdHlwZT1cImJ1dHRvblwiIChjbGljayk9XCJyZXNldE1vZGlmaWNhdGlvbnMoKVwiIFtkaXNhYmxlZF09XCJzdGF0dXMgPT09ICdzZW5kaW5nJyB8fCBzdGF0dXMgPT09ICdnZW5lcmF0aW5nJyB8fCBmb3JtR3JvdXAucHJpc3RpbmVcIj5DYW5jZWwgTW9kaWZpY2F0aW9uPC9idXR0b24+XG4gICAgICA8YnV0dG9uIHR5cGU9XCJzdWJtaXRcIiBbZGlzYWJsZWRdPVwic3RhdHVzID09PSAnc2VuZGluZycgfHwgc3RhdHVzID09PSAnZ2VuZXJhdGluZycgfHwgIWZvcm1Hcm91cC52YWxpZCB8fCBmb3JtR3JvdXAucHJpc3RpbmVcIj5TYXZlIERldGFpbHM8L2J1dHRvbj5cbiAgICA8L2Rpdj5cbiAgPC9mb3JtPlxuPC9kaXY+XG4iXX0=
@@ -187,8 +187,10 @@ const appDataPropertySetId = '34d46477-ad4b-47b4-b555-06358b92f60c';
187
187
  const deviceDataPropertySetId = '7a32d851-5e89-46a6-a4b6-cca162dace29';
188
188
  const propertyCodes = ['RecordingSession', 'Status', 'UserDetailChangeLog'];
189
189
  class DetailEditComponent {
190
- constructor(shared) {
190
+ constructor(shared, kvDiffers, itDiffers) {
191
191
  this.shared = shared;
192
+ this.kvDiffers = kvDiffers;
193
+ this.itDiffers = itDiffers;
192
194
  this.status = 'loading';
193
195
  this.formGroup = new FormGroup({
194
196
  dob: new FormControl('', [Validators.required, withinNYears(120, 'before')]),
@@ -266,19 +268,31 @@ class DetailEditComponent {
266
268
  this.detailChangeLog.push(entry);
267
269
  console.log(this.detailChangeLog);
268
270
  }
269
- // get the device data record and initialise the form
270
- loadDeviceData() {
271
- this.shared.getDeviceData(this.config.deviceDataModelId, this.config.owners[0], propertyCodes).subscribe({
272
- next: (res) => {
271
+ regenReport() {
272
+ this.postDeviceData(deviceDataPropertySetId, { 'Algorithmhasrun': false, 'AlgorithmRun': true }).subscribe(() => {
273
+ this.status = 'generating'; // assume report starts generating immediately
274
+ });
275
+ }
276
+ resetModifications() {
277
+ this.formGroup.patchValue(this.initialFormState);
278
+ }
279
+ loadData(currentUserId, ownerId, deviceDataModelId) {
280
+ forkJoin([
281
+ this.shared.getUser(currentUserId),
282
+ this.shared.getUser(ownerId),
283
+ this.shared.getDeviceData(deviceDataModelId, ownerId, propertyCodes)
284
+ ]).subscribe({
285
+ next: ([currentUser, owner, { deviceDataId, data: deviceData }]) => {
273
286
  var _a, _b, _c;
274
- this.deviceDataId = res.deviceDataId;
275
- this.recordingSession = JSON.parse(res.data['RecordingSession'].value);
287
+ this.currentUser = currentUser;
288
+ this.owner = owner;
289
+ this.deviceDataId = deviceDataId;
290
+ this.recordingSession = JSON.parse(deviceData['RecordingSession'].value);
276
291
  this.initialiseForm(this.extractFields(this.recordingSession));
277
292
  // data field uninitialised for unmodified record
278
- this.detailChangeLog = (_b = (_a = res.data['UserDetailChangeLog']) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : [];
279
- this.status = ((_c = res.data['Status']) === null || _c === void 0 ? void 0 : _c.value) === 'Generating Report' ?
280
- 'generating' :
281
- 'success';
293
+ this.detailChangeLog = (_b = (_a = deviceData['UserDetailChangeLog']) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : [];
294
+ this.status = ((_c = deviceData['Status']) === null || _c === void 0 ? void 0 : _c.value) === 'Generating Report' ?
295
+ 'generating' : 'success';
282
296
  },
283
297
  error: (err) => {
284
298
  console.error(err);
@@ -286,36 +300,45 @@ class DetailEditComponent {
286
300
  }
287
301
  });
288
302
  }
289
- regenReport() {
290
- this.postDeviceData(deviceDataPropertySetId, { 'Algorithmhasrun': false, 'AlgorithmRun': true }).subscribe(() => {
291
- this.status = 'generating'; // assume report starts generating immediately
292
- });
293
- }
294
- resetModifications() {
295
- this.formGroup.patchValue(this.initialFormState);
296
- }
297
- ngOnInit() {
298
- var _a, _b;
299
- if (!((_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.owners) === null || _b === void 0 ? void 0 : _b[0])) {
303
+ init() {
304
+ var _a, _b, _c;
305
+ if (!((_a = this.config) === null || _a === void 0 ? void 0 : _a.currentUserId) || !this.config.deviceDataModelId) {
306
+ this.status = 'cfgerror';
307
+ return;
308
+ }
309
+ else if (!((_c = (_b = this.config) === null || _b === void 0 ? void 0 : _b.owners) === null || _c === void 0 ? void 0 : _c[0])) {
300
310
  this.status = 'nouser';
301
311
  return;
302
312
  }
303
- forkJoin([
304
- this.shared.getUser(this.config.currentUserId),
305
- this.shared.getUser(this.config.owners[0])
306
- ]).pipe(tap(([current, owner]) => {
307
- this.currentUser = current;
308
- this.owner = owner;
309
- })).subscribe();
310
- this.loadDeviceData();
313
+ this.status = 'loading';
314
+ this.loadData(this.config.currentUserId, this.config.owners[0], this.config.deviceDataModelId);
315
+ }
316
+ // this should be called from the parent using the ViewChild attr
317
+ refresh() {
318
+ this.init();
319
+ }
320
+ // NOTE: there could be something wrong / unusual here but it seems to work ok
321
+ ngOnInit() {
322
+ var _a;
323
+ if (this.config && !this.configDiffer)
324
+ this.configDiffer = this.kvDiffers.find(this.config).create();
325
+ if (((_a = this.config) === null || _a === void 0 ? void 0 : _a.owners) && !this.ownersDiffer)
326
+ this.ownersDiffer = this.itDiffers.find(this.config.owners).create();
327
+ }
328
+ ngDoCheck() {
329
+ var _a, _b, _c;
330
+ const configChanges = (_a = this.configDiffer) === null || _a === void 0 ? void 0 : _a.diff(this.config);
331
+ const ownersChanges = (_b = this.ownersDiffer) === null || _b === void 0 ? void 0 : _b.diff((_c = this.config) === null || _c === void 0 ? void 0 : _c.owners);
332
+ if (configChanges || ownersChanges)
333
+ this.init();
311
334
  }
312
335
  }
313
- DetailEditComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DetailEditComponent, deps: [{ token: i1.SharedService }], target: i0.ɵɵFactoryTarget.Component });
314
- DetailEditComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: DetailEditComponent, selector: "lib-detail-edit", inputs: { config: "config" }, ngImport: i0, template: "<div class=\"wrapper\">\n <div class=\"status\" *ngIf=\"status === 'error'\">\n An error occured while trying to get the details.\n </div>\n <div class=\"status\" *ngIf=\"status === 'nouser'\">\n There is no user specified as the data owner.\n </div>\n <form *ngIf=\"status !== 'error' && status !== 'nouser'\" [formGroup]=\"formGroup\" (ngSubmit)=\"saveModifications()\">\n <div class=\"inputs\">\n <div class=\"form-row\">\n <label for=\"dob\">Date of Birth:</label>\n <input id=\"dob\" type=\"date\" formControlName=\"dob\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"weight\">Patient Weight (kg):</label>\n <input id=\"weight\" type=\"number\" formControlName=\"weight\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"height\">Patient Height (cm):</label>\n <input id=\"height\" type=\"number\" formControlName=\"height\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealStart\">Meal Start Time:</label>\n <input id=\"mealStart\" type=\"datetime-local\" formControlName=\"mealStart\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealEnd\">Meal End Time:</label>\n <input id=\"mealEnd\" type=\"datetime-local\" formControlName=\"mealEnd\">\n </div>\n </div>\n\n <div *ngIf=\"!formGroup.valid && formGroup.dirty\" class=\"errors\">\n <div *ngFor=\"let control of formGroup.controls | entries\">\n {{ parseInputErrors(control[0], control[1]) }}\n </div>\n </div>\n\n <div *ngIf=\"status === 'generating'\" class=\"info\">\n <div>The report is generating at the moment, check back later if you need to modify this entry.</div>\n </div>\n\n <div class=\"buttons\">\n <button type=\"button\" (click)=\"regenReport()\" [disabled]=\"status === 'sending' || status === 'generating' || status === 'loading'\">Regenerate Report</button>\n <button type=\"button\" (click)=\"resetModifications()\" [disabled]=\"status === 'sending' || status === 'generating' || formGroup.pristine\">Cancel Modification</button>\n <button type=\"submit\" [disabled]=\"status === 'sending' || status === 'generating' || !formGroup.valid || formGroup.pristine\">Save Details</button>\n </div>\n </form>\n</div>\n", styles: [".wrapper{width:100%;height:100%}.status{font-size:2rem;margin:5rem auto;text-align:center}form{display:flex;flex-direction:column;padding:2rem;gap:2rem;font-size:.9rem;max-width:70rem;margin:0 auto}form .inputs{display:flex;flex-flow:row wrap;gap:1rem 3rem}form .inputs .form-row{display:flex;gap:1rem;align-items:center;flex:1 0 calc(50% - 3rem);min-width:400px}form .inputs .form-row label{min-width:9rem}form .inputs .form-row input{background:#f5f5f6;height:36px;border:none;padding-inline:10px;flex-grow:1}form.ng-dirty .form-row .ng-invalid{outline:1px auto red}form .buttons{display:flex;gap:1rem}form .buttons button{padding:.5rem 1rem;height:36px;border:none;font-size:inherit;background:#f5f5f6}form .buttons button:not([disabled]){cursor:pointer}form .buttons button[type=submit]{background:#242C69;color:#fff}form .buttons button[disabled]{background:#fafafa;cursor:not-allowed}form .buttons button[type=submit][disabled]{background:#444C89}form .buttons button:first-child{margin-right:auto}.errors{padding:1rem;background:#fee;border:2px solid red;border-radius:4px;color:red}.info{padding:1rem;background:#eef;border:2px solid #242C69;border-radius:4px;color:#242c69}\n"], dependencies: [{ kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: EntriesPipe, name: "entries" }] });
336
+ DetailEditComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DetailEditComponent, deps: [{ token: i1.SharedService }, { token: i0.KeyValueDiffers }, { token: i0.IterableDiffers }], target: i0.ɵɵFactoryTarget.Component });
337
+ DetailEditComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: DetailEditComponent, selector: "lib-detail-edit", inputs: { config: "config" }, ngImport: i0, template: "<div class=\"wrapper\">\n <div class=\"status\" *ngIf=\"status === 'error'\">\n An error occured while trying to get the details.\n </div>\n <div class=\"status\" *ngIf=\"status === 'cfgerror'\">\n The widget has not been configured correctly, or is missing configuration information.\n </div>\n <div class=\"status\" *ngIf=\"status === 'nouser'\">\n There is no user specified as the data owner.\n </div>\n <form *ngIf=\"!status.includes('error') && status !== 'nouser'\" [formGroup]=\"formGroup\" (ngSubmit)=\"saveModifications()\">\n <div class=\"inputs\">\n <div class=\"form-row\">\n <label for=\"dob\">Date of Birth:</label>\n <input id=\"dob\" type=\"date\" formControlName=\"dob\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"weight\">Patient Weight (kg):</label>\n <input id=\"weight\" type=\"number\" formControlName=\"weight\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"height\">Patient Height (cm):</label>\n <input id=\"height\" type=\"number\" formControlName=\"height\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealStart\">Meal Start Time:</label>\n <input id=\"mealStart\" type=\"datetime-local\" formControlName=\"mealStart\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealEnd\">Meal End Time:</label>\n <input id=\"mealEnd\" type=\"datetime-local\" formControlName=\"mealEnd\">\n </div>\n </div>\n\n <div *ngIf=\"!formGroup.valid && formGroup.dirty\" class=\"errors\">\n <div *ngFor=\"let control of formGroup.controls | entries\">\n {{ parseInputErrors(control[0], control[1]) }}\n </div>\n </div>\n\n <div *ngIf=\"status === 'generating'\" class=\"info\">\n <div>The report is generating at the moment, check back later if you need to modify this entry.</div>\n </div>\n\n <div class=\"buttons\">\n <button type=\"button\" (click)=\"regenReport()\" [disabled]=\"status === 'sending' || status === 'generating' || status === 'loading'\">Regenerate Report</button>\n <button type=\"button\" (click)=\"resetModifications()\" [disabled]=\"status === 'sending' || status === 'generating' || formGroup.pristine\">Cancel Modification</button>\n <button type=\"submit\" [disabled]=\"status === 'sending' || status === 'generating' || !formGroup.valid || formGroup.pristine\">Save Details</button>\n </div>\n </form>\n</div>\n", styles: [".wrapper{width:100%;height:100%}.status{font-size:2rem;margin:5rem auto;text-align:center}form{display:flex;flex-direction:column;padding:2rem;gap:2rem;font-size:.9rem;max-width:70rem;margin:0 auto}form .inputs{display:flex;flex-flow:row wrap;gap:1rem 3rem}form .inputs .form-row{display:flex;gap:1rem;align-items:center;flex:1 0 calc(50% - 3rem);min-width:400px}form .inputs .form-row label{min-width:9rem}form .inputs .form-row input{background:#f5f5f6;height:36px;border:none;padding-inline:10px;flex-grow:1}form.ng-dirty .form-row .ng-invalid{outline:1px auto red}form .buttons{display:flex;gap:1rem}form .buttons button{padding:.5rem 1rem;height:36px;border:none;font-size:inherit;background:#f5f5f6}form .buttons button:not([disabled]){cursor:pointer}form .buttons button[type=submit]{background:#242C69;color:#fff}form .buttons button[disabled]{background:#fafafa;cursor:not-allowed}form .buttons button[type=submit][disabled]{background:#444C89}form .buttons button:first-child{margin-right:auto}.errors{padding:1rem;background:#fee;border:2px solid red;border-radius:4px;color:red}.info{padding:1rem;background:#eef;border:2px solid #242C69;border-radius:4px;color:#242c69}\n"], dependencies: [{ kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: EntriesPipe, name: "entries" }] });
315
338
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DetailEditComponent, decorators: [{
316
339
  type: Component,
317
- args: [{ selector: 'lib-detail-edit', template: "<div class=\"wrapper\">\n <div class=\"status\" *ngIf=\"status === 'error'\">\n An error occured while trying to get the details.\n </div>\n <div class=\"status\" *ngIf=\"status === 'nouser'\">\n There is no user specified as the data owner.\n </div>\n <form *ngIf=\"status !== 'error' && status !== 'nouser'\" [formGroup]=\"formGroup\" (ngSubmit)=\"saveModifications()\">\n <div class=\"inputs\">\n <div class=\"form-row\">\n <label for=\"dob\">Date of Birth:</label>\n <input id=\"dob\" type=\"date\" formControlName=\"dob\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"weight\">Patient Weight (kg):</label>\n <input id=\"weight\" type=\"number\" formControlName=\"weight\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"height\">Patient Height (cm):</label>\n <input id=\"height\" type=\"number\" formControlName=\"height\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealStart\">Meal Start Time:</label>\n <input id=\"mealStart\" type=\"datetime-local\" formControlName=\"mealStart\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealEnd\">Meal End Time:</label>\n <input id=\"mealEnd\" type=\"datetime-local\" formControlName=\"mealEnd\">\n </div>\n </div>\n\n <div *ngIf=\"!formGroup.valid && formGroup.dirty\" class=\"errors\">\n <div *ngFor=\"let control of formGroup.controls | entries\">\n {{ parseInputErrors(control[0], control[1]) }}\n </div>\n </div>\n\n <div *ngIf=\"status === 'generating'\" class=\"info\">\n <div>The report is generating at the moment, check back later if you need to modify this entry.</div>\n </div>\n\n <div class=\"buttons\">\n <button type=\"button\" (click)=\"regenReport()\" [disabled]=\"status === 'sending' || status === 'generating' || status === 'loading'\">Regenerate Report</button>\n <button type=\"button\" (click)=\"resetModifications()\" [disabled]=\"status === 'sending' || status === 'generating' || formGroup.pristine\">Cancel Modification</button>\n <button type=\"submit\" [disabled]=\"status === 'sending' || status === 'generating' || !formGroup.valid || formGroup.pristine\">Save Details</button>\n </div>\n </form>\n</div>\n", styles: [".wrapper{width:100%;height:100%}.status{font-size:2rem;margin:5rem auto;text-align:center}form{display:flex;flex-direction:column;padding:2rem;gap:2rem;font-size:.9rem;max-width:70rem;margin:0 auto}form .inputs{display:flex;flex-flow:row wrap;gap:1rem 3rem}form .inputs .form-row{display:flex;gap:1rem;align-items:center;flex:1 0 calc(50% - 3rem);min-width:400px}form .inputs .form-row label{min-width:9rem}form .inputs .form-row input{background:#f5f5f6;height:36px;border:none;padding-inline:10px;flex-grow:1}form.ng-dirty .form-row .ng-invalid{outline:1px auto red}form .buttons{display:flex;gap:1rem}form .buttons button{padding:.5rem 1rem;height:36px;border:none;font-size:inherit;background:#f5f5f6}form .buttons button:not([disabled]){cursor:pointer}form .buttons button[type=submit]{background:#242C69;color:#fff}form .buttons button[disabled]{background:#fafafa;cursor:not-allowed}form .buttons button[type=submit][disabled]{background:#444C89}form .buttons button:first-child{margin-right:auto}.errors{padding:1rem;background:#fee;border:2px solid red;border-radius:4px;color:red}.info{padding:1rem;background:#eef;border:2px solid #242C69;border-radius:4px;color:#242c69}\n"] }]
318
- }], ctorParameters: function () { return [{ type: i1.SharedService }]; }, propDecorators: { config: [{
340
+ args: [{ selector: 'lib-detail-edit', template: "<div class=\"wrapper\">\n <div class=\"status\" *ngIf=\"status === 'error'\">\n An error occured while trying to get the details.\n </div>\n <div class=\"status\" *ngIf=\"status === 'cfgerror'\">\n The widget has not been configured correctly, or is missing configuration information.\n </div>\n <div class=\"status\" *ngIf=\"status === 'nouser'\">\n There is no user specified as the data owner.\n </div>\n <form *ngIf=\"!status.includes('error') && status !== 'nouser'\" [formGroup]=\"formGroup\" (ngSubmit)=\"saveModifications()\">\n <div class=\"inputs\">\n <div class=\"form-row\">\n <label for=\"dob\">Date of Birth:</label>\n <input id=\"dob\" type=\"date\" formControlName=\"dob\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"weight\">Patient Weight (kg):</label>\n <input id=\"weight\" type=\"number\" formControlName=\"weight\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"height\">Patient Height (cm):</label>\n <input id=\"height\" type=\"number\" formControlName=\"height\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealStart\">Meal Start Time:</label>\n <input id=\"mealStart\" type=\"datetime-local\" formControlName=\"mealStart\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealEnd\">Meal End Time:</label>\n <input id=\"mealEnd\" type=\"datetime-local\" formControlName=\"mealEnd\">\n </div>\n </div>\n\n <div *ngIf=\"!formGroup.valid && formGroup.dirty\" class=\"errors\">\n <div *ngFor=\"let control of formGroup.controls | entries\">\n {{ parseInputErrors(control[0], control[1]) }}\n </div>\n </div>\n\n <div *ngIf=\"status === 'generating'\" class=\"info\">\n <div>The report is generating at the moment, check back later if you need to modify this entry.</div>\n </div>\n\n <div class=\"buttons\">\n <button type=\"button\" (click)=\"regenReport()\" [disabled]=\"status === 'sending' || status === 'generating' || status === 'loading'\">Regenerate Report</button>\n <button type=\"button\" (click)=\"resetModifications()\" [disabled]=\"status === 'sending' || status === 'generating' || formGroup.pristine\">Cancel Modification</button>\n <button type=\"submit\" [disabled]=\"status === 'sending' || status === 'generating' || !formGroup.valid || formGroup.pristine\">Save Details</button>\n </div>\n </form>\n</div>\n", styles: [".wrapper{width:100%;height:100%}.status{font-size:2rem;margin:5rem auto;text-align:center}form{display:flex;flex-direction:column;padding:2rem;gap:2rem;font-size:.9rem;max-width:70rem;margin:0 auto}form .inputs{display:flex;flex-flow:row wrap;gap:1rem 3rem}form .inputs .form-row{display:flex;gap:1rem;align-items:center;flex:1 0 calc(50% - 3rem);min-width:400px}form .inputs .form-row label{min-width:9rem}form .inputs .form-row input{background:#f5f5f6;height:36px;border:none;padding-inline:10px;flex-grow:1}form.ng-dirty .form-row .ng-invalid{outline:1px auto red}form .buttons{display:flex;gap:1rem}form .buttons button{padding:.5rem 1rem;height:36px;border:none;font-size:inherit;background:#f5f5f6}form .buttons button:not([disabled]){cursor:pointer}form .buttons button[type=submit]{background:#242C69;color:#fff}form .buttons button[disabled]{background:#fafafa;cursor:not-allowed}form .buttons button[type=submit][disabled]{background:#444C89}form .buttons button:first-child{margin-right:auto}.errors{padding:1rem;background:#fee;border:2px solid red;border-radius:4px;color:red}.info{padding:1rem;background:#eef;border:2px solid #242C69;border-radius:4px;color:#242c69}\n"] }]
341
+ }], ctorParameters: function () { return [{ type: i1.SharedService }, { type: i0.KeyValueDiffers }, { type: i0.IterableDiffers }]; }, propDecorators: { config: [{
319
342
  type: Input
320
343
  }] } });
321
344
 
@@ -1 +1 @@
1
- {"version":3,"file":"alimetry-detail-edit.mjs","sources":["../../../projects/detail-edit/src/lib/detail-edit.service.ts","../../../projects/detail-edit/src/lib/utils.ts","../../../projects/detail-edit/src/lib/validators.ts","../../../projects/detail-edit/src/lib/entries.pipe.ts","../../../projects/detail-edit/src/lib/detail-edit.component.ts","../../../projects/detail-edit/src/lib/detail-edit.component.html","../../../projects/detail-edit/src/lib/detail-edit.module.ts","../../../projects/detail-edit/src/public-api.ts","../../../projects/detail-edit/src/alimetry-detail-edit.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class DetailEditService {\n\n constructor() { }\n}\n","// strip the timezone offset to create format usable by <input>\nexport function localiseDateTime(datetime: string) {\n const date = new Date(datetime);\n\n const year = date.getFullYear(); const month = (date.getMonth() + 1).toString().padStart(2, '0');\n const day = date.getDate().toString().padStart(2, '0');\n const hour = date.getHours().toString().padStart(2, '0');\n const minute = date.getMinutes().toString().padStart(2, '0');\n const second = date.getSeconds().toString().padStart(2, '0');\n\n return `${year}-${month}-${day}T${hour}:${minute}:${second}`;\n}\n\n// reconstruct original ISO format\nexport function globaliseDateTime(datetime: string) {\n const date = new Date(datetime);\n\n const offset = -date.getTimezoneOffset();\n const offsetAbs = Math.abs(offset);\n\n const sign = offset >= 0 ? '+' : '-';\n const hours = String(Math.floor(offsetAbs / 60)).padStart(2, '0');\n const minutes = String(offsetAbs % 60).padStart(2, '0');\n const offsetString = `${sign}${hours}:${minutes}`;\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n const hour = String(date.getHours()).padStart(2, '0');\n const minute = String(date.getMinutes()).padStart(2, '0');\n const second = String(date.getSeconds()).padStart(2, '0');\n\n const datePart = `${year}-${month}-${day}`;\n const timePart = `${hour}:${minute}:${second}.000`;\n\n return `${datePart}T${timePart}${offsetString}`;\n}\n\nexport function getAge(dob: string) {\n const then = new Date(dob);\n const now = new Date();\n\n let age = now.getFullYear() - then.getFullYear();\n\n if (now.getMonth() < then.getMonth() ||\n (now.getMonth() === then.getMonth() && now.getDate() < then.getDate())) {\n age--;\n }\n\n return age;\n}\n\nexport function titleise(camel: string) {\n let spaced = camel.replace(/(?=[A-Z])/g, ' ');\n return spaced.toLowerCase().replace(/\\b\\w/g, ch => ch.toUpperCase());\n}\n\nexport function shallowCompare(a: object, b: object) {\n return Object.entries(a).every(([k, v]) => b[k] === v);\n}\n\nexport function shallowDiff(a: object, b: object) {\n const from = Object.fromEntries(Object.entries(a).filter(([k, v]) => b[k] !== v));\n const to = Object.fromEntries(Object.entries(b).filter(([k, _]) => from[k]));\n return { from, to };\n}\n","import { AbstractControl, FormControl, FormGroup, ValidationErrors, ValidatorFn } from \"@angular/forms\";\nimport { titleise } from \"./utils\";\n\nfunction setControlError(control: AbstractControl, errorKey: string, errorValue: any) {\n const currentErrors = control.errors || {};\n if (currentErrors[errorKey]) return;\n control.setErrors({ ...currentErrors, [errorKey]: errorValue });\n}\n\nfunction clearControlError(control: AbstractControl, errorKey: string) {\n const currentErrors = control.errors || {};\n if (!currentErrors[errorKey]) return;\n control.setErrors({ ...currentErrors, [errorKey]: null });\n}\n\nexport function dateComparison(a: string, b: string, comparator: 'before' | 'after') {\n return function(control: AbstractControl<any, any>): ValidationErrors | null {\n if (!(control instanceof FormGroup)) return null;\n\n const formGroup = control as FormGroup;\n\n const aControl = formGroup.get(a);\n const bControl = formGroup.get(b);\n\n if (!aControl?.value || !bControl?.value) {\n clearControlError(aControl, 'dateRange');\n return null;\n }\n\n const aDate = new Date(aControl.value);\n const bDate = new Date(bControl.value);\n\n const hasError = (\n comparator === 'after' && aDate <= bDate ||\n comparator === 'before' && aDate >= bDate\n );\n\n if (hasError) {\n setControlError(aControl, 'dateRange', { against: b, comparator });\n return { dateRange: true };\n }\n\n clearControlError(aControl, 'dateRange');\n return null;\n }\n}\n\nexport function withinNYears(n: number, dir: 'both' | 'before' | 'after' = 'both', of?: Date): ValidatorFn {\n return function(control: AbstractControl): ValidationErrors | null {\n const timestamp = control?.value;\n if (!timestamp || isNaN(new Date(timestamp).getTime())) return null;\n\n const date = new Date(timestamp);\n const against = of ?? new Date();\n\n const min = new Date(against)\n min.setFullYear(against.getFullYear() - n);\n const max = new Date(against)\n max.setFullYear(against.getFullYear() + n);\n\n let isValid = false;\n if (dir === 'after') isValid = date < max && date > against;\n else if (dir === 'before') isValid = date > min && date < against;\n else isValid = date > min && date < max;\n\n return isValid ? null : { notWithinYears: { n, against, dir } };\n }\n}\n\nexport function withinNHours(n: number, dir: 'both' | 'before' | 'after' = 'both', of?: Date): ValidatorFn {\n return function(control: AbstractControl): ValidationErrors | null {\n const timestamp = control?.value;\n if (!timestamp || isNaN(new Date(timestamp).getTime())) return null;\n\n const date = new Date(timestamp);\n const against = of ?? new Date();\n\n const min = new Date(against)\n min.setHours(against.getHours() - n);\n const max = new Date(against)\n max.setHours(against.getHours() + n);\n\n let isValid = false;\n if (dir === 'after') isValid = date < max && date > against;\n else if (dir === 'before') isValid = date > min && date < against;\n else isValid = date > min && date < max;\n\n return isValid ? null : { notWithinHours: { n, against, dir } };\n }\n}\n\n// translate validation errors into human readable strings\nexport function translateError(name: string, control: AbstractControl) {\n const { errors } = control;\n\n if (control.hasError('required'))\n return `${titleise(name)} is a required value.`;\n else if (control.hasError('min'))\n return `${titleise(name)} needs to be a minimum of ${errors.min.min}.`;\n else if (control.hasError('max'))\n return `${titleise(name)} needs to be a maximum of ${errors.max.max}.`;\n else if (control.hasError('future'))\n return `${titleise(name)} needs to be in the past.`;\n else if (control.hasError('dateRange'))\n return `${titleise(name)} needs to be ${errors.dateRange.comparator} ${titleise(errors.dateRange.against)}.`;\n else if (control.hasError('notWithinYears'))\n return `${titleise(name)} needs to be within ${errors.notWithinYears.n} years of ${errors.notWithinYears.against}`;\n else if (control.hasError('notWithinHours'))\n return `${titleise(name)} needs to be within ${errors.notWithinHours.n} hours of ${errors.notWithinHours.against}`;\n\n return null;\n}\n","import { Pipe, PipeTransform } from '@angular/core';\n\n@Pipe({\n name: 'entries'\n})\nexport class EntriesPipe implements PipeTransform {\n transform(value: object): [string, any][] {\n return Object.entries(value);\n }\n}\n","import { Component, Input } from '@angular/core';\nimport { AbstractControl, FormControl, FormGroup, Validators } from '@angular/forms';\nimport { forkJoin, tap } from 'rxjs';\nimport { Config, SharedService, User } from 'alimetry-shared';\nimport { getAge, globaliseDateTime, localiseDateTime, shallowCompare, shallowDiff } from './utils';\nimport { dateComparison, withinNYears, withinNHours, translateError } from './validators';\n\nconst appDataPropertySetId = '34d46477-ad4b-47b4-b555-06358b92f60c';\nconst deviceDataPropertySetId = '7a32d851-5e89-46a6-a4b6-cca162dace29';\nconst propertyCodes = ['RecordingSession', 'Status', 'UserDetailChangeLog'];\n\ninterface FormValue {\n dob: string,\n height: number,\n weight: number,\n mealStart: string,\n mealEnd: string\n}\n\ninterface Change {\n timestamp: string,\n author: string,\n from: Partial<FormValue>,\n to: Partial<FormValue>\n}\n\n@Component({\n selector: 'lib-detail-edit', templateUrl: './detail-edit.component.html',\n styleUrls: ['./detail-edit.component.css']\n})\nexport class DetailEditComponent {\n @Input() config!: Config;\n\n status: 'error' | 'loading' | 'success' | 'generating' | 'sending' | 'nouser' = 'loading';\n\n // device data populated by load request\n private deviceDataId: string;\n private recordingSession: object;\n private recordingStart: string;\n private initialFormState: object;\n\n // user data expanded from ids passed in config\n private currentUser: User;\n private owner: User;\n\n private detailChangeLog: Change[];\n\n formGroup = new FormGroup({\n dob: new FormControl<string>('', [Validators.required, withinNYears(120, 'before')]),\n height: new FormControl<number>(0, [Validators.required, Validators.min(30), Validators.max(272)]),\n weight: new FormControl<number>(0, [Validators.required, Validators.min(1), Validators.max(635)]),\n mealStart: new FormControl<string>('', [Validators.required]),\n mealEnd: new FormControl<string>('', [Validators.required])\n }, [\n dateComparison('mealEnd', 'mealStart', 'after'),\n dateComparison('mealStart', 'dob', 'after'),\n ]);\n\n constructor(private shared: SharedService) { }\n\n parseInputErrors(name: string, control: AbstractControl) {\n return translateError(name, control);\n }\n\n // make sure than modifications that don't actually differ from the current are marked as such\n private monitorFormChanges() {\n this.formGroup.valueChanges.subscribe(current => {\n if (shallowCompare(current, this.initialFormState)) {\n this.formGroup.markAsPristine();\n }\n })\n }\n\n // handle the relevant data from the response body\n private extractFields(recordingSession: Record<string, any>) {\n const { patient, mealStart, mealEnd, recordingStart } = recordingSession;\n this.recordingStart = recordingStart;\n\n return {\n dob: this.owner.dateOfBirth,\n height: patient.height,\n weight: patient.weight,\n mealStart: localiseDateTime(mealStart),\n mealEnd: localiseDateTime(mealEnd)\n }\n }\n\n private initialiseForm(state: object) {\n this.formGroup.patchValue(state);\n this.formGroup.markAsPristine();\n\n this.formGroup.get('mealStart').addValidators(withinNHours(24, 'after', new Date(this.recordingStart)));\n this.formGroup.get('mealEnd').addValidators(withinNHours(24, 'after', new Date(this.recordingStart)));\n\n this.initialFormState = state; // save this for use in resets\n this.monitorFormChanges();\n }\n\n // construct a patch object for the save request\n private integrateFields(mods: FormValue, recordingSession: Record<string, any>) {\n const { patient } = recordingSession;\n patient.height = mods.height;\n patient.weight = mods.weight;\n patient.age = getAge(mods.dob);\n\n recordingSession.mealStart = globaliseDateTime(mods.mealStart);\n recordingSession.mealEnd = globaliseDateTime(mods.mealEnd);\n\n this.logChange(mods);\n\n return {\n 'Age': patient.age,\n 'RecordingSession': JSON.stringify(recordingSession),\n 'UserDetailChangeLog': this.detailChangeLog\n }\n }\n\n private postDeviceData(devicePropertySetId: string, data: object) {\n return this.shared.saveDeviceData(\n this.config.deviceDataModelId,\n this.deviceDataId,\n devicePropertySetId,\n this.config.owners[0],\n data\n );\n }\n\n // patch the device data record with the modifications\n saveModifications() {\n const mods = this.formGroup.getRawValue();\n const patchedDeviceData = this.integrateFields(mods, this.recordingSession);\n const patchedUserData = Object.assign(this.owner, { dateOfBirth: mods.dob });\n\n this.status = 'sending';\n forkJoin([\n this.postDeviceData(appDataPropertySetId, patchedDeviceData),\n this.shared.updateUser(this.config.owners[0], patchedUserData)\n ]).pipe(\n tap(() => this.regenReport())\n ).subscribe();\n }\n\n private logChange(mods: FormValue) {\n const entry = {\n author: this.currentUser.emailAddress,\n timestamp: new Date().toISOString(),\n ...shallowDiff(this.initialFormState, mods)\n }\n\n this.detailChangeLog.push(entry);\n\n console.log(this.detailChangeLog);\n }\n\n // get the device data record and initialise the form\n private loadDeviceData() {\n this.shared.getDeviceData(\n this.config.deviceDataModelId,\n this.config.owners[0],\n propertyCodes\n ).subscribe({\n next: (res) => {\n this.deviceDataId = res.deviceDataId;\n this.recordingSession = JSON.parse(res.data['RecordingSession'].value);\n this.initialiseForm(this.extractFields(this.recordingSession));\n\n // data field uninitialised for unmodified record\n this.detailChangeLog = res.data['UserDetailChangeLog']?.value ?? [];\n\n this.status = res.data['Status']?.value === 'Generating Report' ?\n 'generating' :\n 'success';\n },\n error: (err) => {\n console.error(err);\n this.status = \"error\";\n }\n });\n }\n\n regenReport() {\n this.postDeviceData(\n deviceDataPropertySetId,\n { 'Algorithmhasrun': false, 'AlgorithmRun': true }\n ).subscribe(() => {\n this.status = 'generating'; // assume report starts generating immediately\n })\n }\n\n resetModifications() {\n this.formGroup.patchValue(this.initialFormState);\n }\n\n ngOnInit() {\n if (!this.config?.owners?.[0]) {\n this.status = 'nouser';\n return;\n }\n\n forkJoin([\n this.shared.getUser(this.config.currentUserId),\n this.shared.getUser(this.config.owners[0])\n ]).pipe(tap(([current, owner]) => {\n this.currentUser = current;\n this.owner = owner;\n })).subscribe();\n\n this.loadDeviceData();\n }\n}\n","<div class=\"wrapper\">\n <div class=\"status\" *ngIf=\"status === 'error'\">\n An error occured while trying to get the details.\n </div>\n <div class=\"status\" *ngIf=\"status === 'nouser'\">\n There is no user specified as the data owner.\n </div>\n <form *ngIf=\"status !== 'error' && status !== 'nouser'\" [formGroup]=\"formGroup\" (ngSubmit)=\"saveModifications()\">\n <div class=\"inputs\">\n <div class=\"form-row\">\n <label for=\"dob\">Date of Birth:</label>\n <input id=\"dob\" type=\"date\" formControlName=\"dob\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"weight\">Patient Weight (kg):</label>\n <input id=\"weight\" type=\"number\" formControlName=\"weight\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"height\">Patient Height (cm):</label>\n <input id=\"height\" type=\"number\" formControlName=\"height\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealStart\">Meal Start Time:</label>\n <input id=\"mealStart\" type=\"datetime-local\" formControlName=\"mealStart\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealEnd\">Meal End Time:</label>\n <input id=\"mealEnd\" type=\"datetime-local\" formControlName=\"mealEnd\">\n </div>\n </div>\n\n <div *ngIf=\"!formGroup.valid && formGroup.dirty\" class=\"errors\">\n <div *ngFor=\"let control of formGroup.controls | entries\">\n {{ parseInputErrors(control[0], control[1]) }}\n </div>\n </div>\n\n <div *ngIf=\"status === 'generating'\" class=\"info\">\n <div>The report is generating at the moment, check back later if you need to modify this entry.</div>\n </div>\n\n <div class=\"buttons\">\n <button type=\"button\" (click)=\"regenReport()\" [disabled]=\"status === 'sending' || status === 'generating' || status === 'loading'\">Regenerate Report</button>\n <button type=\"button\" (click)=\"resetModifications()\" [disabled]=\"status === 'sending' || status === 'generating' || formGroup.pristine\">Cancel Modification</button>\n <button type=\"submit\" [disabled]=\"status === 'sending' || status === 'generating' || !formGroup.valid || formGroup.pristine\">Save Details</button>\n </div>\n </form>\n</div>\n","import { CommonModule, JsonPipe } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { ReactiveFormsModule } from '@angular/forms';\nimport { DetailEditComponent } from './detail-edit.component';\nimport { EntriesPipe } from './entries.pipe';\n\n\n\n@NgModule({\n declarations: [\n DetailEditComponent,\n EntriesPipe\n ],\n imports: [\n JsonPipe,\n ReactiveFormsModule,\n CommonModule\n ],\n exports: [\n DetailEditComponent\n ]\n})\nexport class DetailEditModule { }\n","/*\n * Public API Surface of detail-edit\n */\n\nexport * from './lib/detail-edit.service';\nexport * from './lib/detail-edit.component';\nexport * from './lib/detail-edit.module';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i4.EntriesPipe"],"mappings":"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"}
1
+ {"version":3,"file":"alimetry-detail-edit.mjs","sources":["../../../projects/detail-edit/src/lib/detail-edit.service.ts","../../../projects/detail-edit/src/lib/utils.ts","../../../projects/detail-edit/src/lib/validators.ts","../../../projects/detail-edit/src/lib/entries.pipe.ts","../../../projects/detail-edit/src/lib/detail-edit.component.ts","../../../projects/detail-edit/src/lib/detail-edit.component.html","../../../projects/detail-edit/src/lib/detail-edit.module.ts","../../../projects/detail-edit/src/public-api.ts","../../../projects/detail-edit/src/alimetry-detail-edit.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class DetailEditService {\n\n constructor() { }\n}\n","// strip the timezone offset to create format usable by <input>\nexport function localiseDateTime(datetime: string) {\n const date = new Date(datetime);\n\n const year = date.getFullYear(); const month = (date.getMonth() + 1).toString().padStart(2, '0');\n const day = date.getDate().toString().padStart(2, '0');\n const hour = date.getHours().toString().padStart(2, '0');\n const minute = date.getMinutes().toString().padStart(2, '0');\n const second = date.getSeconds().toString().padStart(2, '0');\n\n return `${year}-${month}-${day}T${hour}:${minute}:${second}`;\n}\n\n// reconstruct original ISO format\nexport function globaliseDateTime(datetime: string) {\n const date = new Date(datetime);\n\n const offset = -date.getTimezoneOffset();\n const offsetAbs = Math.abs(offset);\n\n const sign = offset >= 0 ? '+' : '-';\n const hours = String(Math.floor(offsetAbs / 60)).padStart(2, '0');\n const minutes = String(offsetAbs % 60).padStart(2, '0');\n const offsetString = `${sign}${hours}:${minutes}`;\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n const hour = String(date.getHours()).padStart(2, '0');\n const minute = String(date.getMinutes()).padStart(2, '0');\n const second = String(date.getSeconds()).padStart(2, '0');\n\n const datePart = `${year}-${month}-${day}`;\n const timePart = `${hour}:${minute}:${second}.000`;\n\n return `${datePart}T${timePart}${offsetString}`;\n}\n\nexport function getAge(dob: string) {\n const then = new Date(dob);\n const now = new Date();\n\n let age = now.getFullYear() - then.getFullYear();\n\n if (now.getMonth() < then.getMonth() ||\n (now.getMonth() === then.getMonth() && now.getDate() < then.getDate())) {\n age--;\n }\n\n return age;\n}\n\nexport function titleise(camel: string) {\n let spaced = camel.replace(/(?=[A-Z])/g, ' ');\n return spaced.toLowerCase().replace(/\\b\\w/g, ch => ch.toUpperCase());\n}\n\nexport function shallowCompare(a: object, b: object) {\n return Object.entries(a).every(([k, v]) => b[k] === v);\n}\n\nexport function shallowDiff(a: object, b: object) {\n const from = Object.fromEntries(Object.entries(a).filter(([k, v]) => b[k] !== v));\n const to = Object.fromEntries(Object.entries(b).filter(([k, _]) => from[k]));\n return { from, to };\n}\n","import { AbstractControl, FormControl, FormGroup, ValidationErrors, ValidatorFn } from \"@angular/forms\";\nimport { titleise } from \"./utils\";\n\nfunction setControlError(control: AbstractControl, errorKey: string, errorValue: any) {\n const currentErrors = control.errors || {};\n if (currentErrors[errorKey]) return;\n control.setErrors({ ...currentErrors, [errorKey]: errorValue });\n}\n\nfunction clearControlError(control: AbstractControl, errorKey: string) {\n const currentErrors = control.errors || {};\n if (!currentErrors[errorKey]) return;\n control.setErrors({ ...currentErrors, [errorKey]: null });\n}\n\nexport function dateComparison(a: string, b: string, comparator: 'before' | 'after') {\n return function(control: AbstractControl<any, any>): ValidationErrors | null {\n if (!(control instanceof FormGroup)) return null;\n\n const formGroup = control as FormGroup;\n\n const aControl = formGroup.get(a);\n const bControl = formGroup.get(b);\n\n if (!aControl?.value || !bControl?.value) {\n clearControlError(aControl, 'dateRange');\n return null;\n }\n\n const aDate = new Date(aControl.value);\n const bDate = new Date(bControl.value);\n\n const hasError = (\n comparator === 'after' && aDate <= bDate ||\n comparator === 'before' && aDate >= bDate\n );\n\n if (hasError) {\n setControlError(aControl, 'dateRange', { against: b, comparator });\n return { dateRange: true };\n }\n\n clearControlError(aControl, 'dateRange');\n return null;\n }\n}\n\nexport function withinNYears(n: number, dir: 'both' | 'before' | 'after' = 'both', of?: Date): ValidatorFn {\n return function(control: AbstractControl): ValidationErrors | null {\n const timestamp = control?.value;\n if (!timestamp || isNaN(new Date(timestamp).getTime())) return null;\n\n const date = new Date(timestamp);\n const against = of ?? new Date();\n\n const min = new Date(against)\n min.setFullYear(against.getFullYear() - n);\n const max = new Date(against)\n max.setFullYear(against.getFullYear() + n);\n\n let isValid = false;\n if (dir === 'after') isValid = date < max && date > against;\n else if (dir === 'before') isValid = date > min && date < against;\n else isValid = date > min && date < max;\n\n return isValid ? null : { notWithinYears: { n, against, dir } };\n }\n}\n\nexport function withinNHours(n: number, dir: 'both' | 'before' | 'after' = 'both', of?: Date): ValidatorFn {\n return function(control: AbstractControl): ValidationErrors | null {\n const timestamp = control?.value;\n if (!timestamp || isNaN(new Date(timestamp).getTime())) return null;\n\n const date = new Date(timestamp);\n const against = of ?? new Date();\n\n const min = new Date(against)\n min.setHours(against.getHours() - n);\n const max = new Date(against)\n max.setHours(against.getHours() + n);\n\n let isValid = false;\n if (dir === 'after') isValid = date < max && date > against;\n else if (dir === 'before') isValid = date > min && date < against;\n else isValid = date > min && date < max;\n\n return isValid ? null : { notWithinHours: { n, against, dir } };\n }\n}\n\n// translate validation errors into human readable strings\nexport function translateError(name: string, control: AbstractControl) {\n const { errors } = control;\n\n if (control.hasError('required'))\n return `${titleise(name)} is a required value.`;\n else if (control.hasError('min'))\n return `${titleise(name)} needs to be a minimum of ${errors.min.min}.`;\n else if (control.hasError('max'))\n return `${titleise(name)} needs to be a maximum of ${errors.max.max}.`;\n else if (control.hasError('future'))\n return `${titleise(name)} needs to be in the past.`;\n else if (control.hasError('dateRange'))\n return `${titleise(name)} needs to be ${errors.dateRange.comparator} ${titleise(errors.dateRange.against)}.`;\n else if (control.hasError('notWithinYears'))\n return `${titleise(name)} needs to be within ${errors.notWithinYears.n} years of ${errors.notWithinYears.against}`;\n else if (control.hasError('notWithinHours'))\n return `${titleise(name)} needs to be within ${errors.notWithinHours.n} hours of ${errors.notWithinHours.against}`;\n\n return null;\n}\n","import { Pipe, PipeTransform } from '@angular/core';\n\n@Pipe({\n name: 'entries'\n})\nexport class EntriesPipe implements PipeTransform {\n transform(value: object): [string, any][] {\n return Object.entries(value);\n }\n}\n","import { Component, DoCheck, Input, KeyValueDiffers, KeyValueDiffer, IterableDiffer, IterableDiffers } from '@angular/core';\nimport { AbstractControl, FormControl, FormGroup, Validators } from '@angular/forms';\nimport { forkJoin, tap } from 'rxjs';\nimport { Config, SharedService, User } from 'alimetry-shared';\nimport { getAge, globaliseDateTime, localiseDateTime, shallowCompare, shallowDiff } from './utils';\nimport { dateComparison, withinNYears, withinNHours, translateError } from './validators';\n\nconst appDataPropertySetId = '34d46477-ad4b-47b4-b555-06358b92f60c';\nconst deviceDataPropertySetId = '7a32d851-5e89-46a6-a4b6-cca162dace29';\nconst propertyCodes = ['RecordingSession', 'Status', 'UserDetailChangeLog'];\n\ninterface FormValue {\n dob: string,\n height: number,\n weight: number,\n mealStart: string,\n mealEnd: string\n}\n\ninterface Change {\n timestamp: string,\n author: string,\n from: Partial<FormValue>,\n to: Partial<FormValue>\n}\n\n@Component({\n selector: 'lib-detail-edit',\n templateUrl: './detail-edit.component.html',\n styleUrls: ['./detail-edit.component.css']\n})\nexport class DetailEditComponent implements DoCheck {\n @Input() config!: Config;\n\n private configDiffer?: KeyValueDiffer<keyof Config, any>;\n private ownersDiffer?: IterableDiffer<string>;\n\n status: 'error' | 'cfgerror' | 'loading' | 'success' | 'generating' | 'sending' | 'nouser' = 'loading';\n\n // device data populated by load request\n private deviceDataId: string;\n private recordingSession: object;\n private recordingStart: string;\n private initialFormState: object;\n\n // user data expanded from ids passed in config\n private currentUser: User;\n private owner: User;\n\n private detailChangeLog: Change[];\n\n formGroup = new FormGroup({\n dob: new FormControl<string>('', [Validators.required, withinNYears(120, 'before')]),\n height: new FormControl<number>(0, [Validators.required, Validators.min(30), Validators.max(272)]),\n weight: new FormControl<number>(0, [Validators.required, Validators.min(1), Validators.max(635)]),\n mealStart: new FormControl<string>('', [Validators.required]),\n mealEnd: new FormControl<string>('', [Validators.required])\n }, [\n dateComparison('mealEnd', 'mealStart', 'after'),\n dateComparison('mealStart', 'dob', 'after'),\n ]);\n\n constructor(private shared: SharedService, private kvDiffers: KeyValueDiffers, private itDiffers: IterableDiffers) { }\n\n parseInputErrors(name: string, control: AbstractControl) {\n return translateError(name, control);\n }\n\n // make sure than modifications that don't actually differ from the current are marked as such\n private monitorFormChanges() {\n this.formGroup.valueChanges.subscribe(current => {\n if (shallowCompare(current, this.initialFormState)) {\n this.formGroup.markAsPristine();\n }\n })\n }\n\n // handle the relevant data from the response body\n private extractFields(recordingSession: Record<string, any>) {\n const { patient, mealStart, mealEnd, recordingStart } = recordingSession;\n this.recordingStart = recordingStart;\n\n return {\n dob: this.owner.dateOfBirth,\n height: patient.height,\n weight: patient.weight,\n mealStart: localiseDateTime(mealStart),\n mealEnd: localiseDateTime(mealEnd)\n }\n }\n\n private initialiseForm(state: object) {\n this.formGroup.patchValue(state);\n this.formGroup.markAsPristine();\n\n this.formGroup.get('mealStart').addValidators(withinNHours(24, 'after', new Date(this.recordingStart)));\n this.formGroup.get('mealEnd').addValidators(withinNHours(24, 'after', new Date(this.recordingStart)));\n\n this.initialFormState = state; // save this for use in resets\n this.monitorFormChanges();\n }\n\n // construct a patch object for the save request\n private integrateFields(mods: FormValue, recordingSession: Record<string, any>) {\n const { patient } = recordingSession;\n patient.height = mods.height;\n patient.weight = mods.weight;\n patient.age = getAge(mods.dob);\n\n recordingSession.mealStart = globaliseDateTime(mods.mealStart);\n recordingSession.mealEnd = globaliseDateTime(mods.mealEnd);\n\n this.logChange(mods);\n\n return {\n 'Age': patient.age,\n 'RecordingSession': JSON.stringify(recordingSession),\n 'UserDetailChangeLog': this.detailChangeLog\n }\n }\n\n private postDeviceData(devicePropertySetId: string, data: object) {\n return this.shared.saveDeviceData(\n this.config.deviceDataModelId,\n this.deviceDataId,\n devicePropertySetId,\n this.config.owners[0],\n data\n );\n }\n\n // patch the device data record with the modifications\n saveModifications() {\n const mods = this.formGroup.getRawValue();\n const patchedDeviceData = this.integrateFields(mods, this.recordingSession);\n const patchedUserData = Object.assign(this.owner, { dateOfBirth: mods.dob });\n\n this.status = 'sending';\n forkJoin([\n this.postDeviceData(appDataPropertySetId, patchedDeviceData),\n this.shared.updateUser(this.config.owners[0], patchedUserData)\n ]).pipe(\n tap(() => this.regenReport())\n ).subscribe();\n }\n\n private logChange(mods: FormValue) {\n const entry = {\n author: this.currentUser.emailAddress,\n timestamp: new Date().toISOString(),\n ...shallowDiff(this.initialFormState, mods)\n }\n\n this.detailChangeLog.push(entry);\n\n console.log(this.detailChangeLog);\n }\n\n regenReport() {\n this.postDeviceData(\n deviceDataPropertySetId,\n { 'Algorithmhasrun': false, 'AlgorithmRun': true }\n ).subscribe(() => {\n this.status = 'generating'; // assume report starts generating immediately\n })\n }\n\n resetModifications() {\n this.formGroup.patchValue(this.initialFormState);\n }\n\n private loadData(currentUserId: string, ownerId: string, deviceDataModelId: string) {\n forkJoin([\n this.shared.getUser(currentUserId),\n this.shared.getUser(ownerId),\n this.shared.getDeviceData(deviceDataModelId, ownerId, propertyCodes)\n ]).subscribe({\n next: ([currentUser, owner, { deviceDataId, data: deviceData }]) => {\n this.currentUser = currentUser;\n this.owner = owner;\n this.deviceDataId = deviceDataId;\n\n this.recordingSession = JSON.parse(deviceData['RecordingSession'].value);\n this.initialiseForm(this.extractFields(this.recordingSession));\n\n // data field uninitialised for unmodified record\n this.detailChangeLog = deviceData['UserDetailChangeLog']?.value ?? [];\n\n this.status = deviceData['Status']?.value === 'Generating Report' ?\n 'generating' : 'success';\n },\n error: (err) => {\n console.error(err);\n this.status = \"error\";\n }\n });\n }\n\n private init() {\n if (!this.config?.currentUserId || !this.config.deviceDataModelId) {\n this.status = 'cfgerror'\n return;\n } else if (!this.config?.owners?.[0]) {\n this.status = 'nouser';\n return;\n }\n\n this.status = 'loading';\n this.loadData(this.config.currentUserId, this.config.owners[0], this.config.deviceDataModelId);\n }\n\n // this should be called from the parent using the ViewChild attr\n refresh() {\n this.init();\n }\n\n // NOTE: there could be something wrong / unusual here but it seems to work ok\n ngOnInit() {\n if (this.config && !this.configDiffer) this.configDiffer = this.kvDiffers.find(this.config).create();\n if (this.config?.owners && !this.ownersDiffer) this.ownersDiffer = this.itDiffers.find(this.config.owners).create();\n }\n\n ngDoCheck() {\n const configChanges = this.configDiffer?.diff(this.config);\n const ownersChanges = this.ownersDiffer?.diff(this.config?.owners);\n\n if (configChanges || ownersChanges) this.init();\n }\n}\n","<div class=\"wrapper\">\n <div class=\"status\" *ngIf=\"status === 'error'\">\n An error occured while trying to get the details.\n </div>\n <div class=\"status\" *ngIf=\"status === 'cfgerror'\">\n The widget has not been configured correctly, or is missing configuration information.\n </div>\n <div class=\"status\" *ngIf=\"status === 'nouser'\">\n There is no user specified as the data owner.\n </div>\n <form *ngIf=\"!status.includes('error') && status !== 'nouser'\" [formGroup]=\"formGroup\" (ngSubmit)=\"saveModifications()\">\n <div class=\"inputs\">\n <div class=\"form-row\">\n <label for=\"dob\">Date of Birth:</label>\n <input id=\"dob\" type=\"date\" formControlName=\"dob\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"weight\">Patient Weight (kg):</label>\n <input id=\"weight\" type=\"number\" formControlName=\"weight\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"height\">Patient Height (cm):</label>\n <input id=\"height\" type=\"number\" formControlName=\"height\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealStart\">Meal Start Time:</label>\n <input id=\"mealStart\" type=\"datetime-local\" formControlName=\"mealStart\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealEnd\">Meal End Time:</label>\n <input id=\"mealEnd\" type=\"datetime-local\" formControlName=\"mealEnd\">\n </div>\n </div>\n\n <div *ngIf=\"!formGroup.valid && formGroup.dirty\" class=\"errors\">\n <div *ngFor=\"let control of formGroup.controls | entries\">\n {{ parseInputErrors(control[0], control[1]) }}\n </div>\n </div>\n\n <div *ngIf=\"status === 'generating'\" class=\"info\">\n <div>The report is generating at the moment, check back later if you need to modify this entry.</div>\n </div>\n\n <div class=\"buttons\">\n <button type=\"button\" (click)=\"regenReport()\" [disabled]=\"status === 'sending' || status === 'generating' || status === 'loading'\">Regenerate Report</button>\n <button type=\"button\" (click)=\"resetModifications()\" [disabled]=\"status === 'sending' || status === 'generating' || formGroup.pristine\">Cancel Modification</button>\n <button type=\"submit\" [disabled]=\"status === 'sending' || status === 'generating' || !formGroup.valid || formGroup.pristine\">Save Details</button>\n </div>\n </form>\n</div>\n","import { CommonModule, JsonPipe } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { ReactiveFormsModule } from '@angular/forms';\nimport { DetailEditComponent } from './detail-edit.component';\nimport { EntriesPipe } from './entries.pipe';\n\n\n\n@NgModule({\n declarations: [\n DetailEditComponent,\n EntriesPipe\n ],\n imports: [\n JsonPipe,\n ReactiveFormsModule,\n CommonModule\n ],\n exports: [\n DetailEditComponent\n ]\n})\nexport class DetailEditModule { }\n","/*\n * Public API Surface of detail-edit\n */\n\nexport * from './lib/detail-edit.service';\nexport * from './lib/detail-edit.component';\nexport * from './lib/detail-edit.module';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i4.EntriesPipe"],"mappings":"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"}
@@ -187,8 +187,10 @@ const appDataPropertySetId = '34d46477-ad4b-47b4-b555-06358b92f60c';
187
187
  const deviceDataPropertySetId = '7a32d851-5e89-46a6-a4b6-cca162dace29';
188
188
  const propertyCodes = ['RecordingSession', 'Status', 'UserDetailChangeLog'];
189
189
  class DetailEditComponent {
190
- constructor(shared) {
190
+ constructor(shared, kvDiffers, itDiffers) {
191
191
  this.shared = shared;
192
+ this.kvDiffers = kvDiffers;
193
+ this.itDiffers = itDiffers;
192
194
  this.status = 'loading';
193
195
  this.formGroup = new FormGroup({
194
196
  dob: new FormControl('', [Validators.required, withinNYears(120, 'before')]),
@@ -270,18 +272,30 @@ class DetailEditComponent {
270
272
  this.detailChangeLog.push(entry);
271
273
  console.log(this.detailChangeLog);
272
274
  }
273
- // get the device data record and initialise the form
274
- loadDeviceData() {
275
- this.shared.getDeviceData(this.config.deviceDataModelId, this.config.owners[0], propertyCodes).subscribe({
276
- next: (res) => {
277
- this.deviceDataId = res.deviceDataId;
278
- this.recordingSession = JSON.parse(res.data['RecordingSession'].value);
275
+ regenReport() {
276
+ this.postDeviceData(deviceDataPropertySetId, { 'Algorithmhasrun': false, 'AlgorithmRun': true }).subscribe(() => {
277
+ this.status = 'generating'; // assume report starts generating immediately
278
+ });
279
+ }
280
+ resetModifications() {
281
+ this.formGroup.patchValue(this.initialFormState);
282
+ }
283
+ loadData(currentUserId, ownerId, deviceDataModelId) {
284
+ forkJoin([
285
+ this.shared.getUser(currentUserId),
286
+ this.shared.getUser(ownerId),
287
+ this.shared.getDeviceData(deviceDataModelId, ownerId, propertyCodes)
288
+ ]).subscribe({
289
+ next: ([currentUser, owner, { deviceDataId, data: deviceData }]) => {
290
+ this.currentUser = currentUser;
291
+ this.owner = owner;
292
+ this.deviceDataId = deviceDataId;
293
+ this.recordingSession = JSON.parse(deviceData['RecordingSession'].value);
279
294
  this.initialiseForm(this.extractFields(this.recordingSession));
280
295
  // data field uninitialised for unmodified record
281
- this.detailChangeLog = res.data['UserDetailChangeLog']?.value ?? [];
282
- this.status = res.data['Status']?.value === 'Generating Report' ?
283
- 'generating' :
284
- 'success';
296
+ this.detailChangeLog = deviceData['UserDetailChangeLog']?.value ?? [];
297
+ this.status = deviceData['Status']?.value === 'Generating Report' ?
298
+ 'generating' : 'success';
285
299
  },
286
300
  error: (err) => {
287
301
  console.error(err);
@@ -289,35 +303,42 @@ class DetailEditComponent {
289
303
  }
290
304
  });
291
305
  }
292
- regenReport() {
293
- this.postDeviceData(deviceDataPropertySetId, { 'Algorithmhasrun': false, 'AlgorithmRun': true }).subscribe(() => {
294
- this.status = 'generating'; // assume report starts generating immediately
295
- });
296
- }
297
- resetModifications() {
298
- this.formGroup.patchValue(this.initialFormState);
299
- }
300
- ngOnInit() {
301
- if (!this.config?.owners?.[0]) {
306
+ init() {
307
+ if (!this.config?.currentUserId || !this.config.deviceDataModelId) {
308
+ this.status = 'cfgerror';
309
+ return;
310
+ }
311
+ else if (!this.config?.owners?.[0]) {
302
312
  this.status = 'nouser';
303
313
  return;
304
314
  }
305
- forkJoin([
306
- this.shared.getUser(this.config.currentUserId),
307
- this.shared.getUser(this.config.owners[0])
308
- ]).pipe(tap(([current, owner]) => {
309
- this.currentUser = current;
310
- this.owner = owner;
311
- })).subscribe();
312
- this.loadDeviceData();
315
+ this.status = 'loading';
316
+ this.loadData(this.config.currentUserId, this.config.owners[0], this.config.deviceDataModelId);
317
+ }
318
+ // this should be called from the parent using the ViewChild attr
319
+ refresh() {
320
+ this.init();
321
+ }
322
+ // NOTE: there could be something wrong / unusual here but it seems to work ok
323
+ ngOnInit() {
324
+ if (this.config && !this.configDiffer)
325
+ this.configDiffer = this.kvDiffers.find(this.config).create();
326
+ if (this.config?.owners && !this.ownersDiffer)
327
+ this.ownersDiffer = this.itDiffers.find(this.config.owners).create();
328
+ }
329
+ ngDoCheck() {
330
+ const configChanges = this.configDiffer?.diff(this.config);
331
+ const ownersChanges = this.ownersDiffer?.diff(this.config?.owners);
332
+ if (configChanges || ownersChanges)
333
+ this.init();
313
334
  }
314
335
  }
315
- DetailEditComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DetailEditComponent, deps: [{ token: i1.SharedService }], target: i0.ɵɵFactoryTarget.Component });
316
- DetailEditComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: DetailEditComponent, selector: "lib-detail-edit", inputs: { config: "config" }, ngImport: i0, template: "<div class=\"wrapper\">\n <div class=\"status\" *ngIf=\"status === 'error'\">\n An error occured while trying to get the details.\n </div>\n <div class=\"status\" *ngIf=\"status === 'nouser'\">\n There is no user specified as the data owner.\n </div>\n <form *ngIf=\"status !== 'error' && status !== 'nouser'\" [formGroup]=\"formGroup\" (ngSubmit)=\"saveModifications()\">\n <div class=\"inputs\">\n <div class=\"form-row\">\n <label for=\"dob\">Date of Birth:</label>\n <input id=\"dob\" type=\"date\" formControlName=\"dob\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"weight\">Patient Weight (kg):</label>\n <input id=\"weight\" type=\"number\" formControlName=\"weight\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"height\">Patient Height (cm):</label>\n <input id=\"height\" type=\"number\" formControlName=\"height\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealStart\">Meal Start Time:</label>\n <input id=\"mealStart\" type=\"datetime-local\" formControlName=\"mealStart\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealEnd\">Meal End Time:</label>\n <input id=\"mealEnd\" type=\"datetime-local\" formControlName=\"mealEnd\">\n </div>\n </div>\n\n <div *ngIf=\"!formGroup.valid && formGroup.dirty\" class=\"errors\">\n <div *ngFor=\"let control of formGroup.controls | entries\">\n {{ parseInputErrors(control[0], control[1]) }}\n </div>\n </div>\n\n <div *ngIf=\"status === 'generating'\" class=\"info\">\n <div>The report is generating at the moment, check back later if you need to modify this entry.</div>\n </div>\n\n <div class=\"buttons\">\n <button type=\"button\" (click)=\"regenReport()\" [disabled]=\"status === 'sending' || status === 'generating' || status === 'loading'\">Regenerate Report</button>\n <button type=\"button\" (click)=\"resetModifications()\" [disabled]=\"status === 'sending' || status === 'generating' || formGroup.pristine\">Cancel Modification</button>\n <button type=\"submit\" [disabled]=\"status === 'sending' || status === 'generating' || !formGroup.valid || formGroup.pristine\">Save Details</button>\n </div>\n </form>\n</div>\n", styles: [".wrapper{width:100%;height:100%}.status{font-size:2rem;margin:5rem auto;text-align:center}form{display:flex;flex-direction:column;padding:2rem;gap:2rem;font-size:.9rem;max-width:70rem;margin:0 auto}form .inputs{display:flex;flex-flow:row wrap;gap:1rem 3rem}form .inputs .form-row{display:flex;gap:1rem;align-items:center;flex:1 0 calc(50% - 3rem);min-width:400px}form .inputs .form-row label{min-width:9rem}form .inputs .form-row input{background:#f5f5f6;height:36px;border:none;padding-inline:10px;flex-grow:1}form.ng-dirty .form-row .ng-invalid{outline:1px auto red}form .buttons{display:flex;gap:1rem}form .buttons button{padding:.5rem 1rem;height:36px;border:none;font-size:inherit;background:#f5f5f6}form .buttons button:not([disabled]){cursor:pointer}form .buttons button[type=submit]{background:#242C69;color:#fff}form .buttons button[disabled]{background:#fafafa;cursor:not-allowed}form .buttons button[type=submit][disabled]{background:#444C89}form .buttons button:first-child{margin-right:auto}.errors{padding:1rem;background:#fee;border:2px solid red;border-radius:4px;color:red}.info{padding:1rem;background:#eef;border:2px solid #242C69;border-radius:4px;color:#242c69}\n"], dependencies: [{ kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: EntriesPipe, name: "entries" }] });
336
+ DetailEditComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DetailEditComponent, deps: [{ token: i1.SharedService }, { token: i0.KeyValueDiffers }, { token: i0.IterableDiffers }], target: i0.ɵɵFactoryTarget.Component });
337
+ DetailEditComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: DetailEditComponent, selector: "lib-detail-edit", inputs: { config: "config" }, ngImport: i0, template: "<div class=\"wrapper\">\n <div class=\"status\" *ngIf=\"status === 'error'\">\n An error occured while trying to get the details.\n </div>\n <div class=\"status\" *ngIf=\"status === 'cfgerror'\">\n The widget has not been configured correctly, or is missing configuration information.\n </div>\n <div class=\"status\" *ngIf=\"status === 'nouser'\">\n There is no user specified as the data owner.\n </div>\n <form *ngIf=\"!status.includes('error') && status !== 'nouser'\" [formGroup]=\"formGroup\" (ngSubmit)=\"saveModifications()\">\n <div class=\"inputs\">\n <div class=\"form-row\">\n <label for=\"dob\">Date of Birth:</label>\n <input id=\"dob\" type=\"date\" formControlName=\"dob\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"weight\">Patient Weight (kg):</label>\n <input id=\"weight\" type=\"number\" formControlName=\"weight\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"height\">Patient Height (cm):</label>\n <input id=\"height\" type=\"number\" formControlName=\"height\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealStart\">Meal Start Time:</label>\n <input id=\"mealStart\" type=\"datetime-local\" formControlName=\"mealStart\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealEnd\">Meal End Time:</label>\n <input id=\"mealEnd\" type=\"datetime-local\" formControlName=\"mealEnd\">\n </div>\n </div>\n\n <div *ngIf=\"!formGroup.valid && formGroup.dirty\" class=\"errors\">\n <div *ngFor=\"let control of formGroup.controls | entries\">\n {{ parseInputErrors(control[0], control[1]) }}\n </div>\n </div>\n\n <div *ngIf=\"status === 'generating'\" class=\"info\">\n <div>The report is generating at the moment, check back later if you need to modify this entry.</div>\n </div>\n\n <div class=\"buttons\">\n <button type=\"button\" (click)=\"regenReport()\" [disabled]=\"status === 'sending' || status === 'generating' || status === 'loading'\">Regenerate Report</button>\n <button type=\"button\" (click)=\"resetModifications()\" [disabled]=\"status === 'sending' || status === 'generating' || formGroup.pristine\">Cancel Modification</button>\n <button type=\"submit\" [disabled]=\"status === 'sending' || status === 'generating' || !formGroup.valid || formGroup.pristine\">Save Details</button>\n </div>\n </form>\n</div>\n", styles: [".wrapper{width:100%;height:100%}.status{font-size:2rem;margin:5rem auto;text-align:center}form{display:flex;flex-direction:column;padding:2rem;gap:2rem;font-size:.9rem;max-width:70rem;margin:0 auto}form .inputs{display:flex;flex-flow:row wrap;gap:1rem 3rem}form .inputs .form-row{display:flex;gap:1rem;align-items:center;flex:1 0 calc(50% - 3rem);min-width:400px}form .inputs .form-row label{min-width:9rem}form .inputs .form-row input{background:#f5f5f6;height:36px;border:none;padding-inline:10px;flex-grow:1}form.ng-dirty .form-row .ng-invalid{outline:1px auto red}form .buttons{display:flex;gap:1rem}form .buttons button{padding:.5rem 1rem;height:36px;border:none;font-size:inherit;background:#f5f5f6}form .buttons button:not([disabled]){cursor:pointer}form .buttons button[type=submit]{background:#242C69;color:#fff}form .buttons button[disabled]{background:#fafafa;cursor:not-allowed}form .buttons button[type=submit][disabled]{background:#444C89}form .buttons button:first-child{margin-right:auto}.errors{padding:1rem;background:#fee;border:2px solid red;border-radius:4px;color:red}.info{padding:1rem;background:#eef;border:2px solid #242C69;border-radius:4px;color:#242c69}\n"], dependencies: [{ kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: EntriesPipe, name: "entries" }] });
317
338
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DetailEditComponent, decorators: [{
318
339
  type: Component,
319
- args: [{ selector: 'lib-detail-edit', template: "<div class=\"wrapper\">\n <div class=\"status\" *ngIf=\"status === 'error'\">\n An error occured while trying to get the details.\n </div>\n <div class=\"status\" *ngIf=\"status === 'nouser'\">\n There is no user specified as the data owner.\n </div>\n <form *ngIf=\"status !== 'error' && status !== 'nouser'\" [formGroup]=\"formGroup\" (ngSubmit)=\"saveModifications()\">\n <div class=\"inputs\">\n <div class=\"form-row\">\n <label for=\"dob\">Date of Birth:</label>\n <input id=\"dob\" type=\"date\" formControlName=\"dob\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"weight\">Patient Weight (kg):</label>\n <input id=\"weight\" type=\"number\" formControlName=\"weight\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"height\">Patient Height (cm):</label>\n <input id=\"height\" type=\"number\" formControlName=\"height\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealStart\">Meal Start Time:</label>\n <input id=\"mealStart\" type=\"datetime-local\" formControlName=\"mealStart\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealEnd\">Meal End Time:</label>\n <input id=\"mealEnd\" type=\"datetime-local\" formControlName=\"mealEnd\">\n </div>\n </div>\n\n <div *ngIf=\"!formGroup.valid && formGroup.dirty\" class=\"errors\">\n <div *ngFor=\"let control of formGroup.controls | entries\">\n {{ parseInputErrors(control[0], control[1]) }}\n </div>\n </div>\n\n <div *ngIf=\"status === 'generating'\" class=\"info\">\n <div>The report is generating at the moment, check back later if you need to modify this entry.</div>\n </div>\n\n <div class=\"buttons\">\n <button type=\"button\" (click)=\"regenReport()\" [disabled]=\"status === 'sending' || status === 'generating' || status === 'loading'\">Regenerate Report</button>\n <button type=\"button\" (click)=\"resetModifications()\" [disabled]=\"status === 'sending' || status === 'generating' || formGroup.pristine\">Cancel Modification</button>\n <button type=\"submit\" [disabled]=\"status === 'sending' || status === 'generating' || !formGroup.valid || formGroup.pristine\">Save Details</button>\n </div>\n </form>\n</div>\n", styles: [".wrapper{width:100%;height:100%}.status{font-size:2rem;margin:5rem auto;text-align:center}form{display:flex;flex-direction:column;padding:2rem;gap:2rem;font-size:.9rem;max-width:70rem;margin:0 auto}form .inputs{display:flex;flex-flow:row wrap;gap:1rem 3rem}form .inputs .form-row{display:flex;gap:1rem;align-items:center;flex:1 0 calc(50% - 3rem);min-width:400px}form .inputs .form-row label{min-width:9rem}form .inputs .form-row input{background:#f5f5f6;height:36px;border:none;padding-inline:10px;flex-grow:1}form.ng-dirty .form-row .ng-invalid{outline:1px auto red}form .buttons{display:flex;gap:1rem}form .buttons button{padding:.5rem 1rem;height:36px;border:none;font-size:inherit;background:#f5f5f6}form .buttons button:not([disabled]){cursor:pointer}form .buttons button[type=submit]{background:#242C69;color:#fff}form .buttons button[disabled]{background:#fafafa;cursor:not-allowed}form .buttons button[type=submit][disabled]{background:#444C89}form .buttons button:first-child{margin-right:auto}.errors{padding:1rem;background:#fee;border:2px solid red;border-radius:4px;color:red}.info{padding:1rem;background:#eef;border:2px solid #242C69;border-radius:4px;color:#242c69}\n"] }]
320
- }], ctorParameters: function () { return [{ type: i1.SharedService }]; }, propDecorators: { config: [{
340
+ args: [{ selector: 'lib-detail-edit', template: "<div class=\"wrapper\">\n <div class=\"status\" *ngIf=\"status === 'error'\">\n An error occured while trying to get the details.\n </div>\n <div class=\"status\" *ngIf=\"status === 'cfgerror'\">\n The widget has not been configured correctly, or is missing configuration information.\n </div>\n <div class=\"status\" *ngIf=\"status === 'nouser'\">\n There is no user specified as the data owner.\n </div>\n <form *ngIf=\"!status.includes('error') && status !== 'nouser'\" [formGroup]=\"formGroup\" (ngSubmit)=\"saveModifications()\">\n <div class=\"inputs\">\n <div class=\"form-row\">\n <label for=\"dob\">Date of Birth:</label>\n <input id=\"dob\" type=\"date\" formControlName=\"dob\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"weight\">Patient Weight (kg):</label>\n <input id=\"weight\" type=\"number\" formControlName=\"weight\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"height\">Patient Height (cm):</label>\n <input id=\"height\" type=\"number\" formControlName=\"height\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealStart\">Meal Start Time:</label>\n <input id=\"mealStart\" type=\"datetime-local\" formControlName=\"mealStart\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealEnd\">Meal End Time:</label>\n <input id=\"mealEnd\" type=\"datetime-local\" formControlName=\"mealEnd\">\n </div>\n </div>\n\n <div *ngIf=\"!formGroup.valid && formGroup.dirty\" class=\"errors\">\n <div *ngFor=\"let control of formGroup.controls | entries\">\n {{ parseInputErrors(control[0], control[1]) }}\n </div>\n </div>\n\n <div *ngIf=\"status === 'generating'\" class=\"info\">\n <div>The report is generating at the moment, check back later if you need to modify this entry.</div>\n </div>\n\n <div class=\"buttons\">\n <button type=\"button\" (click)=\"regenReport()\" [disabled]=\"status === 'sending' || status === 'generating' || status === 'loading'\">Regenerate Report</button>\n <button type=\"button\" (click)=\"resetModifications()\" [disabled]=\"status === 'sending' || status === 'generating' || formGroup.pristine\">Cancel Modification</button>\n <button type=\"submit\" [disabled]=\"status === 'sending' || status === 'generating' || !formGroup.valid || formGroup.pristine\">Save Details</button>\n </div>\n </form>\n</div>\n", styles: [".wrapper{width:100%;height:100%}.status{font-size:2rem;margin:5rem auto;text-align:center}form{display:flex;flex-direction:column;padding:2rem;gap:2rem;font-size:.9rem;max-width:70rem;margin:0 auto}form .inputs{display:flex;flex-flow:row wrap;gap:1rem 3rem}form .inputs .form-row{display:flex;gap:1rem;align-items:center;flex:1 0 calc(50% - 3rem);min-width:400px}form .inputs .form-row label{min-width:9rem}form .inputs .form-row input{background:#f5f5f6;height:36px;border:none;padding-inline:10px;flex-grow:1}form.ng-dirty .form-row .ng-invalid{outline:1px auto red}form .buttons{display:flex;gap:1rem}form .buttons button{padding:.5rem 1rem;height:36px;border:none;font-size:inherit;background:#f5f5f6}form .buttons button:not([disabled]){cursor:pointer}form .buttons button[type=submit]{background:#242C69;color:#fff}form .buttons button[disabled]{background:#fafafa;cursor:not-allowed}form .buttons button[type=submit][disabled]{background:#444C89}form .buttons button:first-child{margin-right:auto}.errors{padding:1rem;background:#fee;border:2px solid red;border-radius:4px;color:red}.info{padding:1rem;background:#eef;border:2px solid #242C69;border-radius:4px;color:#242c69}\n"] }]
341
+ }], ctorParameters: function () { return [{ type: i1.SharedService }, { type: i0.KeyValueDiffers }, { type: i0.IterableDiffers }]; }, propDecorators: { config: [{
321
342
  type: Input
322
343
  }] } });
323
344
 
@@ -1 +1 @@
1
- {"version":3,"file":"alimetry-detail-edit.mjs","sources":["../../../projects/detail-edit/src/lib/detail-edit.service.ts","../../../projects/detail-edit/src/lib/utils.ts","../../../projects/detail-edit/src/lib/validators.ts","../../../projects/detail-edit/src/lib/entries.pipe.ts","../../../projects/detail-edit/src/lib/detail-edit.component.ts","../../../projects/detail-edit/src/lib/detail-edit.component.html","../../../projects/detail-edit/src/lib/detail-edit.module.ts","../../../projects/detail-edit/src/public-api.ts","../../../projects/detail-edit/src/alimetry-detail-edit.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class DetailEditService {\n\n constructor() { }\n}\n","// strip the timezone offset to create format usable by <input>\nexport function localiseDateTime(datetime: string) {\n const date = new Date(datetime);\n\n const year = date.getFullYear(); const month = (date.getMonth() + 1).toString().padStart(2, '0');\n const day = date.getDate().toString().padStart(2, '0');\n const hour = date.getHours().toString().padStart(2, '0');\n const minute = date.getMinutes().toString().padStart(2, '0');\n const second = date.getSeconds().toString().padStart(2, '0');\n\n return `${year}-${month}-${day}T${hour}:${minute}:${second}`;\n}\n\n// reconstruct original ISO format\nexport function globaliseDateTime(datetime: string) {\n const date = new Date(datetime);\n\n const offset = -date.getTimezoneOffset();\n const offsetAbs = Math.abs(offset);\n\n const sign = offset >= 0 ? '+' : '-';\n const hours = String(Math.floor(offsetAbs / 60)).padStart(2, '0');\n const minutes = String(offsetAbs % 60).padStart(2, '0');\n const offsetString = `${sign}${hours}:${minutes}`;\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n const hour = String(date.getHours()).padStart(2, '0');\n const minute = String(date.getMinutes()).padStart(2, '0');\n const second = String(date.getSeconds()).padStart(2, '0');\n\n const datePart = `${year}-${month}-${day}`;\n const timePart = `${hour}:${minute}:${second}.000`;\n\n return `${datePart}T${timePart}${offsetString}`;\n}\n\nexport function getAge(dob: string) {\n const then = new Date(dob);\n const now = new Date();\n\n let age = now.getFullYear() - then.getFullYear();\n\n if (now.getMonth() < then.getMonth() ||\n (now.getMonth() === then.getMonth() && now.getDate() < then.getDate())) {\n age--;\n }\n\n return age;\n}\n\nexport function titleise(camel: string) {\n let spaced = camel.replace(/(?=[A-Z])/g, ' ');\n return spaced.toLowerCase().replace(/\\b\\w/g, ch => ch.toUpperCase());\n}\n\nexport function shallowCompare(a: object, b: object) {\n return Object.entries(a).every(([k, v]) => b[k] === v);\n}\n\nexport function shallowDiff(a: object, b: object) {\n const from = Object.fromEntries(Object.entries(a).filter(([k, v]) => b[k] !== v));\n const to = Object.fromEntries(Object.entries(b).filter(([k, _]) => from[k]));\n return { from, to };\n}\n","import { AbstractControl, FormControl, FormGroup, ValidationErrors, ValidatorFn } from \"@angular/forms\";\nimport { titleise } from \"./utils\";\n\nfunction setControlError(control: AbstractControl, errorKey: string, errorValue: any) {\n const currentErrors = control.errors || {};\n if (currentErrors[errorKey]) return;\n control.setErrors({ ...currentErrors, [errorKey]: errorValue });\n}\n\nfunction clearControlError(control: AbstractControl, errorKey: string) {\n const currentErrors = control.errors || {};\n if (!currentErrors[errorKey]) return;\n control.setErrors({ ...currentErrors, [errorKey]: null });\n}\n\nexport function dateComparison(a: string, b: string, comparator: 'before' | 'after') {\n return function(control: AbstractControl<any, any>): ValidationErrors | null {\n if (!(control instanceof FormGroup)) return null;\n\n const formGroup = control as FormGroup;\n\n const aControl = formGroup.get(a);\n const bControl = formGroup.get(b);\n\n if (!aControl?.value || !bControl?.value) {\n clearControlError(aControl, 'dateRange');\n return null;\n }\n\n const aDate = new Date(aControl.value);\n const bDate = new Date(bControl.value);\n\n const hasError = (\n comparator === 'after' && aDate <= bDate ||\n comparator === 'before' && aDate >= bDate\n );\n\n if (hasError) {\n setControlError(aControl, 'dateRange', { against: b, comparator });\n return { dateRange: true };\n }\n\n clearControlError(aControl, 'dateRange');\n return null;\n }\n}\n\nexport function withinNYears(n: number, dir: 'both' | 'before' | 'after' = 'both', of?: Date): ValidatorFn {\n return function(control: AbstractControl): ValidationErrors | null {\n const timestamp = control?.value;\n if (!timestamp || isNaN(new Date(timestamp).getTime())) return null;\n\n const date = new Date(timestamp);\n const against = of ?? new Date();\n\n const min = new Date(against)\n min.setFullYear(against.getFullYear() - n);\n const max = new Date(against)\n max.setFullYear(against.getFullYear() + n);\n\n let isValid = false;\n if (dir === 'after') isValid = date < max && date > against;\n else if (dir === 'before') isValid = date > min && date < against;\n else isValid = date > min && date < max;\n\n return isValid ? null : { notWithinYears: { n, against, dir } };\n }\n}\n\nexport function withinNHours(n: number, dir: 'both' | 'before' | 'after' = 'both', of?: Date): ValidatorFn {\n return function(control: AbstractControl): ValidationErrors | null {\n const timestamp = control?.value;\n if (!timestamp || isNaN(new Date(timestamp).getTime())) return null;\n\n const date = new Date(timestamp);\n const against = of ?? new Date();\n\n const min = new Date(against)\n min.setHours(against.getHours() - n);\n const max = new Date(against)\n max.setHours(against.getHours() + n);\n\n let isValid = false;\n if (dir === 'after') isValid = date < max && date > against;\n else if (dir === 'before') isValid = date > min && date < against;\n else isValid = date > min && date < max;\n\n return isValid ? null : { notWithinHours: { n, against, dir } };\n }\n}\n\n// translate validation errors into human readable strings\nexport function translateError(name: string, control: AbstractControl) {\n const { errors } = control;\n\n if (control.hasError('required'))\n return `${titleise(name)} is a required value.`;\n else if (control.hasError('min'))\n return `${titleise(name)} needs to be a minimum of ${errors.min.min}.`;\n else if (control.hasError('max'))\n return `${titleise(name)} needs to be a maximum of ${errors.max.max}.`;\n else if (control.hasError('future'))\n return `${titleise(name)} needs to be in the past.`;\n else if (control.hasError('dateRange'))\n return `${titleise(name)} needs to be ${errors.dateRange.comparator} ${titleise(errors.dateRange.against)}.`;\n else if (control.hasError('notWithinYears'))\n return `${titleise(name)} needs to be within ${errors.notWithinYears.n} years of ${errors.notWithinYears.against}`;\n else if (control.hasError('notWithinHours'))\n return `${titleise(name)} needs to be within ${errors.notWithinHours.n} hours of ${errors.notWithinHours.against}`;\n\n return null;\n}\n","import { Pipe, PipeTransform } from '@angular/core';\n\n@Pipe({\n name: 'entries'\n})\nexport class EntriesPipe implements PipeTransform {\n transform(value: object): [string, any][] {\n return Object.entries(value);\n }\n}\n","import { Component, Input } from '@angular/core';\nimport { AbstractControl, FormControl, FormGroup, Validators } from '@angular/forms';\nimport { forkJoin, tap } from 'rxjs';\nimport { Config, SharedService, User } from 'alimetry-shared';\nimport { getAge, globaliseDateTime, localiseDateTime, shallowCompare, shallowDiff } from './utils';\nimport { dateComparison, withinNYears, withinNHours, translateError } from './validators';\n\nconst appDataPropertySetId = '34d46477-ad4b-47b4-b555-06358b92f60c';\nconst deviceDataPropertySetId = '7a32d851-5e89-46a6-a4b6-cca162dace29';\nconst propertyCodes = ['RecordingSession', 'Status', 'UserDetailChangeLog'];\n\ninterface FormValue {\n dob: string,\n height: number,\n weight: number,\n mealStart: string,\n mealEnd: string\n}\n\ninterface Change {\n timestamp: string,\n author: string,\n from: Partial<FormValue>,\n to: Partial<FormValue>\n}\n\n@Component({\n selector: 'lib-detail-edit', templateUrl: './detail-edit.component.html',\n styleUrls: ['./detail-edit.component.css']\n})\nexport class DetailEditComponent {\n @Input() config!: Config;\n\n status: 'error' | 'loading' | 'success' | 'generating' | 'sending' | 'nouser' = 'loading';\n\n // device data populated by load request\n private deviceDataId: string;\n private recordingSession: object;\n private recordingStart: string;\n private initialFormState: object;\n\n // user data expanded from ids passed in config\n private currentUser: User;\n private owner: User;\n\n private detailChangeLog: Change[];\n\n formGroup = new FormGroup({\n dob: new FormControl<string>('', [Validators.required, withinNYears(120, 'before')]),\n height: new FormControl<number>(0, [Validators.required, Validators.min(30), Validators.max(272)]),\n weight: new FormControl<number>(0, [Validators.required, Validators.min(1), Validators.max(635)]),\n mealStart: new FormControl<string>('', [Validators.required]),\n mealEnd: new FormControl<string>('', [Validators.required])\n }, [\n dateComparison('mealEnd', 'mealStart', 'after'),\n dateComparison('mealStart', 'dob', 'after'),\n ]);\n\n constructor(private shared: SharedService) { }\n\n parseInputErrors(name: string, control: AbstractControl) {\n return translateError(name, control);\n }\n\n // make sure than modifications that don't actually differ from the current are marked as such\n private monitorFormChanges() {\n this.formGroup.valueChanges.subscribe(current => {\n if (shallowCompare(current, this.initialFormState)) {\n this.formGroup.markAsPristine();\n }\n })\n }\n\n // handle the relevant data from the response body\n private extractFields(recordingSession: Record<string, any>) {\n const { patient, mealStart, mealEnd, recordingStart } = recordingSession;\n this.recordingStart = recordingStart;\n\n return {\n dob: this.owner.dateOfBirth,\n height: patient.height,\n weight: patient.weight,\n mealStart: localiseDateTime(mealStart),\n mealEnd: localiseDateTime(mealEnd)\n }\n }\n\n private initialiseForm(state: object) {\n this.formGroup.patchValue(state);\n this.formGroup.markAsPristine();\n\n this.formGroup.get('mealStart').addValidators(withinNHours(24, 'after', new Date(this.recordingStart)));\n this.formGroup.get('mealEnd').addValidators(withinNHours(24, 'after', new Date(this.recordingStart)));\n\n this.initialFormState = state; // save this for use in resets\n this.monitorFormChanges();\n }\n\n // construct a patch object for the save request\n private integrateFields(mods: FormValue, recordingSession: Record<string, any>) {\n const { patient } = recordingSession;\n patient.height = mods.height;\n patient.weight = mods.weight;\n patient.age = getAge(mods.dob);\n\n recordingSession.mealStart = globaliseDateTime(mods.mealStart);\n recordingSession.mealEnd = globaliseDateTime(mods.mealEnd);\n\n this.logChange(mods);\n\n return {\n 'Age': patient.age,\n 'RecordingSession': JSON.stringify(recordingSession),\n 'UserDetailChangeLog': this.detailChangeLog\n }\n }\n\n private postDeviceData(devicePropertySetId: string, data: object) {\n return this.shared.saveDeviceData(\n this.config.deviceDataModelId,\n this.deviceDataId,\n devicePropertySetId,\n this.config.owners[0],\n data\n );\n }\n\n // patch the device data record with the modifications\n saveModifications() {\n const mods = this.formGroup.getRawValue();\n const patchedDeviceData = this.integrateFields(mods, this.recordingSession);\n const patchedUserData = Object.assign(this.owner, { dateOfBirth: mods.dob });\n\n this.status = 'sending';\n forkJoin([\n this.postDeviceData(appDataPropertySetId, patchedDeviceData),\n this.shared.updateUser(this.config.owners[0], patchedUserData)\n ]).pipe(\n tap(() => this.regenReport())\n ).subscribe();\n }\n\n private logChange(mods: FormValue) {\n const entry = {\n author: this.currentUser.emailAddress,\n timestamp: new Date().toISOString(),\n ...shallowDiff(this.initialFormState, mods)\n }\n\n this.detailChangeLog.push(entry);\n\n console.log(this.detailChangeLog);\n }\n\n // get the device data record and initialise the form\n private loadDeviceData() {\n this.shared.getDeviceData(\n this.config.deviceDataModelId,\n this.config.owners[0],\n propertyCodes\n ).subscribe({\n next: (res) => {\n this.deviceDataId = res.deviceDataId;\n this.recordingSession = JSON.parse(res.data['RecordingSession'].value);\n this.initialiseForm(this.extractFields(this.recordingSession));\n\n // data field uninitialised for unmodified record\n this.detailChangeLog = res.data['UserDetailChangeLog']?.value ?? [];\n\n this.status = res.data['Status']?.value === 'Generating Report' ?\n 'generating' :\n 'success';\n },\n error: (err) => {\n console.error(err);\n this.status = \"error\";\n }\n });\n }\n\n regenReport() {\n this.postDeviceData(\n deviceDataPropertySetId,\n { 'Algorithmhasrun': false, 'AlgorithmRun': true }\n ).subscribe(() => {\n this.status = 'generating'; // assume report starts generating immediately\n })\n }\n\n resetModifications() {\n this.formGroup.patchValue(this.initialFormState);\n }\n\n ngOnInit() {\n if (!this.config?.owners?.[0]) {\n this.status = 'nouser';\n return;\n }\n\n forkJoin([\n this.shared.getUser(this.config.currentUserId),\n this.shared.getUser(this.config.owners[0])\n ]).pipe(tap(([current, owner]) => {\n this.currentUser = current;\n this.owner = owner;\n })).subscribe();\n\n this.loadDeviceData();\n }\n}\n","<div class=\"wrapper\">\n <div class=\"status\" *ngIf=\"status === 'error'\">\n An error occured while trying to get the details.\n </div>\n <div class=\"status\" *ngIf=\"status === 'nouser'\">\n There is no user specified as the data owner.\n </div>\n <form *ngIf=\"status !== 'error' && status !== 'nouser'\" [formGroup]=\"formGroup\" (ngSubmit)=\"saveModifications()\">\n <div class=\"inputs\">\n <div class=\"form-row\">\n <label for=\"dob\">Date of Birth:</label>\n <input id=\"dob\" type=\"date\" formControlName=\"dob\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"weight\">Patient Weight (kg):</label>\n <input id=\"weight\" type=\"number\" formControlName=\"weight\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"height\">Patient Height (cm):</label>\n <input id=\"height\" type=\"number\" formControlName=\"height\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealStart\">Meal Start Time:</label>\n <input id=\"mealStart\" type=\"datetime-local\" formControlName=\"mealStart\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealEnd\">Meal End Time:</label>\n <input id=\"mealEnd\" type=\"datetime-local\" formControlName=\"mealEnd\">\n </div>\n </div>\n\n <div *ngIf=\"!formGroup.valid && formGroup.dirty\" class=\"errors\">\n <div *ngFor=\"let control of formGroup.controls | entries\">\n {{ parseInputErrors(control[0], control[1]) }}\n </div>\n </div>\n\n <div *ngIf=\"status === 'generating'\" class=\"info\">\n <div>The report is generating at the moment, check back later if you need to modify this entry.</div>\n </div>\n\n <div class=\"buttons\">\n <button type=\"button\" (click)=\"regenReport()\" [disabled]=\"status === 'sending' || status === 'generating' || status === 'loading'\">Regenerate Report</button>\n <button type=\"button\" (click)=\"resetModifications()\" [disabled]=\"status === 'sending' || status === 'generating' || formGroup.pristine\">Cancel Modification</button>\n <button type=\"submit\" [disabled]=\"status === 'sending' || status === 'generating' || !formGroup.valid || formGroup.pristine\">Save Details</button>\n </div>\n </form>\n</div>\n","import { CommonModule, JsonPipe } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { ReactiveFormsModule } from '@angular/forms';\nimport { DetailEditComponent } from './detail-edit.component';\nimport { EntriesPipe } from './entries.pipe';\n\n\n\n@NgModule({\n declarations: [\n DetailEditComponent,\n EntriesPipe\n ],\n imports: [\n JsonPipe,\n ReactiveFormsModule,\n CommonModule\n ],\n exports: [\n DetailEditComponent\n ]\n})\nexport class DetailEditModule { }\n","/*\n * Public API Surface of detail-edit\n */\n\nexport * from './lib/detail-edit.service';\nexport * from './lib/detail-edit.component';\nexport * from './lib/detail-edit.module';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i4.EntriesPipe"],"mappings":"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"}
1
+ {"version":3,"file":"alimetry-detail-edit.mjs","sources":["../../../projects/detail-edit/src/lib/detail-edit.service.ts","../../../projects/detail-edit/src/lib/utils.ts","../../../projects/detail-edit/src/lib/validators.ts","../../../projects/detail-edit/src/lib/entries.pipe.ts","../../../projects/detail-edit/src/lib/detail-edit.component.ts","../../../projects/detail-edit/src/lib/detail-edit.component.html","../../../projects/detail-edit/src/lib/detail-edit.module.ts","../../../projects/detail-edit/src/public-api.ts","../../../projects/detail-edit/src/alimetry-detail-edit.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\n\n@Injectable({\n providedIn: 'root'\n})\nexport class DetailEditService {\n\n constructor() { }\n}\n","// strip the timezone offset to create format usable by <input>\nexport function localiseDateTime(datetime: string) {\n const date = new Date(datetime);\n\n const year = date.getFullYear(); const month = (date.getMonth() + 1).toString().padStart(2, '0');\n const day = date.getDate().toString().padStart(2, '0');\n const hour = date.getHours().toString().padStart(2, '0');\n const minute = date.getMinutes().toString().padStart(2, '0');\n const second = date.getSeconds().toString().padStart(2, '0');\n\n return `${year}-${month}-${day}T${hour}:${minute}:${second}`;\n}\n\n// reconstruct original ISO format\nexport function globaliseDateTime(datetime: string) {\n const date = new Date(datetime);\n\n const offset = -date.getTimezoneOffset();\n const offsetAbs = Math.abs(offset);\n\n const sign = offset >= 0 ? '+' : '-';\n const hours = String(Math.floor(offsetAbs / 60)).padStart(2, '0');\n const minutes = String(offsetAbs % 60).padStart(2, '0');\n const offsetString = `${sign}${hours}:${minutes}`;\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n const hour = String(date.getHours()).padStart(2, '0');\n const minute = String(date.getMinutes()).padStart(2, '0');\n const second = String(date.getSeconds()).padStart(2, '0');\n\n const datePart = `${year}-${month}-${day}`;\n const timePart = `${hour}:${minute}:${second}.000`;\n\n return `${datePart}T${timePart}${offsetString}`;\n}\n\nexport function getAge(dob: string) {\n const then = new Date(dob);\n const now = new Date();\n\n let age = now.getFullYear() - then.getFullYear();\n\n if (now.getMonth() < then.getMonth() ||\n (now.getMonth() === then.getMonth() && now.getDate() < then.getDate())) {\n age--;\n }\n\n return age;\n}\n\nexport function titleise(camel: string) {\n let spaced = camel.replace(/(?=[A-Z])/g, ' ');\n return spaced.toLowerCase().replace(/\\b\\w/g, ch => ch.toUpperCase());\n}\n\nexport function shallowCompare(a: object, b: object) {\n return Object.entries(a).every(([k, v]) => b[k] === v);\n}\n\nexport function shallowDiff(a: object, b: object) {\n const from = Object.fromEntries(Object.entries(a).filter(([k, v]) => b[k] !== v));\n const to = Object.fromEntries(Object.entries(b).filter(([k, _]) => from[k]));\n return { from, to };\n}\n","import { AbstractControl, FormControl, FormGroup, ValidationErrors, ValidatorFn } from \"@angular/forms\";\nimport { titleise } from \"./utils\";\n\nfunction setControlError(control: AbstractControl, errorKey: string, errorValue: any) {\n const currentErrors = control.errors || {};\n if (currentErrors[errorKey]) return;\n control.setErrors({ ...currentErrors, [errorKey]: errorValue });\n}\n\nfunction clearControlError(control: AbstractControl, errorKey: string) {\n const currentErrors = control.errors || {};\n if (!currentErrors[errorKey]) return;\n control.setErrors({ ...currentErrors, [errorKey]: null });\n}\n\nexport function dateComparison(a: string, b: string, comparator: 'before' | 'after') {\n return function(control: AbstractControl<any, any>): ValidationErrors | null {\n if (!(control instanceof FormGroup)) return null;\n\n const formGroup = control as FormGroup;\n\n const aControl = formGroup.get(a);\n const bControl = formGroup.get(b);\n\n if (!aControl?.value || !bControl?.value) {\n clearControlError(aControl, 'dateRange');\n return null;\n }\n\n const aDate = new Date(aControl.value);\n const bDate = new Date(bControl.value);\n\n const hasError = (\n comparator === 'after' && aDate <= bDate ||\n comparator === 'before' && aDate >= bDate\n );\n\n if (hasError) {\n setControlError(aControl, 'dateRange', { against: b, comparator });\n return { dateRange: true };\n }\n\n clearControlError(aControl, 'dateRange');\n return null;\n }\n}\n\nexport function withinNYears(n: number, dir: 'both' | 'before' | 'after' = 'both', of?: Date): ValidatorFn {\n return function(control: AbstractControl): ValidationErrors | null {\n const timestamp = control?.value;\n if (!timestamp || isNaN(new Date(timestamp).getTime())) return null;\n\n const date = new Date(timestamp);\n const against = of ?? new Date();\n\n const min = new Date(against)\n min.setFullYear(against.getFullYear() - n);\n const max = new Date(against)\n max.setFullYear(against.getFullYear() + n);\n\n let isValid = false;\n if (dir === 'after') isValid = date < max && date > against;\n else if (dir === 'before') isValid = date > min && date < against;\n else isValid = date > min && date < max;\n\n return isValid ? null : { notWithinYears: { n, against, dir } };\n }\n}\n\nexport function withinNHours(n: number, dir: 'both' | 'before' | 'after' = 'both', of?: Date): ValidatorFn {\n return function(control: AbstractControl): ValidationErrors | null {\n const timestamp = control?.value;\n if (!timestamp || isNaN(new Date(timestamp).getTime())) return null;\n\n const date = new Date(timestamp);\n const against = of ?? new Date();\n\n const min = new Date(against)\n min.setHours(against.getHours() - n);\n const max = new Date(against)\n max.setHours(against.getHours() + n);\n\n let isValid = false;\n if (dir === 'after') isValid = date < max && date > against;\n else if (dir === 'before') isValid = date > min && date < against;\n else isValid = date > min && date < max;\n\n return isValid ? null : { notWithinHours: { n, against, dir } };\n }\n}\n\n// translate validation errors into human readable strings\nexport function translateError(name: string, control: AbstractControl) {\n const { errors } = control;\n\n if (control.hasError('required'))\n return `${titleise(name)} is a required value.`;\n else if (control.hasError('min'))\n return `${titleise(name)} needs to be a minimum of ${errors.min.min}.`;\n else if (control.hasError('max'))\n return `${titleise(name)} needs to be a maximum of ${errors.max.max}.`;\n else if (control.hasError('future'))\n return `${titleise(name)} needs to be in the past.`;\n else if (control.hasError('dateRange'))\n return `${titleise(name)} needs to be ${errors.dateRange.comparator} ${titleise(errors.dateRange.against)}.`;\n else if (control.hasError('notWithinYears'))\n return `${titleise(name)} needs to be within ${errors.notWithinYears.n} years of ${errors.notWithinYears.against}`;\n else if (control.hasError('notWithinHours'))\n return `${titleise(name)} needs to be within ${errors.notWithinHours.n} hours of ${errors.notWithinHours.against}`;\n\n return null;\n}\n","import { Pipe, PipeTransform } from '@angular/core';\n\n@Pipe({\n name: 'entries'\n})\nexport class EntriesPipe implements PipeTransform {\n transform(value: object): [string, any][] {\n return Object.entries(value);\n }\n}\n","import { Component, DoCheck, Input, KeyValueDiffers, KeyValueDiffer, IterableDiffer, IterableDiffers } from '@angular/core';\nimport { AbstractControl, FormControl, FormGroup, Validators } from '@angular/forms';\nimport { forkJoin, tap } from 'rxjs';\nimport { Config, SharedService, User } from 'alimetry-shared';\nimport { getAge, globaliseDateTime, localiseDateTime, shallowCompare, shallowDiff } from './utils';\nimport { dateComparison, withinNYears, withinNHours, translateError } from './validators';\n\nconst appDataPropertySetId = '34d46477-ad4b-47b4-b555-06358b92f60c';\nconst deviceDataPropertySetId = '7a32d851-5e89-46a6-a4b6-cca162dace29';\nconst propertyCodes = ['RecordingSession', 'Status', 'UserDetailChangeLog'];\n\ninterface FormValue {\n dob: string,\n height: number,\n weight: number,\n mealStart: string,\n mealEnd: string\n}\n\ninterface Change {\n timestamp: string,\n author: string,\n from: Partial<FormValue>,\n to: Partial<FormValue>\n}\n\n@Component({\n selector: 'lib-detail-edit',\n templateUrl: './detail-edit.component.html',\n styleUrls: ['./detail-edit.component.css']\n})\nexport class DetailEditComponent implements DoCheck {\n @Input() config!: Config;\n\n private configDiffer?: KeyValueDiffer<keyof Config, any>;\n private ownersDiffer?: IterableDiffer<string>;\n\n status: 'error' | 'cfgerror' | 'loading' | 'success' | 'generating' | 'sending' | 'nouser' = 'loading';\n\n // device data populated by load request\n private deviceDataId: string;\n private recordingSession: object;\n private recordingStart: string;\n private initialFormState: object;\n\n // user data expanded from ids passed in config\n private currentUser: User;\n private owner: User;\n\n private detailChangeLog: Change[];\n\n formGroup = new FormGroup({\n dob: new FormControl<string>('', [Validators.required, withinNYears(120, 'before')]),\n height: new FormControl<number>(0, [Validators.required, Validators.min(30), Validators.max(272)]),\n weight: new FormControl<number>(0, [Validators.required, Validators.min(1), Validators.max(635)]),\n mealStart: new FormControl<string>('', [Validators.required]),\n mealEnd: new FormControl<string>('', [Validators.required])\n }, [\n dateComparison('mealEnd', 'mealStart', 'after'),\n dateComparison('mealStart', 'dob', 'after'),\n ]);\n\n constructor(private shared: SharedService, private kvDiffers: KeyValueDiffers, private itDiffers: IterableDiffers) { }\n\n parseInputErrors(name: string, control: AbstractControl) {\n return translateError(name, control);\n }\n\n // make sure than modifications that don't actually differ from the current are marked as such\n private monitorFormChanges() {\n this.formGroup.valueChanges.subscribe(current => {\n if (shallowCompare(current, this.initialFormState)) {\n this.formGroup.markAsPristine();\n }\n })\n }\n\n // handle the relevant data from the response body\n private extractFields(recordingSession: Record<string, any>) {\n const { patient, mealStart, mealEnd, recordingStart } = recordingSession;\n this.recordingStart = recordingStart;\n\n return {\n dob: this.owner.dateOfBirth,\n height: patient.height,\n weight: patient.weight,\n mealStart: localiseDateTime(mealStart),\n mealEnd: localiseDateTime(mealEnd)\n }\n }\n\n private initialiseForm(state: object) {\n this.formGroup.patchValue(state);\n this.formGroup.markAsPristine();\n\n this.formGroup.get('mealStart').addValidators(withinNHours(24, 'after', new Date(this.recordingStart)));\n this.formGroup.get('mealEnd').addValidators(withinNHours(24, 'after', new Date(this.recordingStart)));\n\n this.initialFormState = state; // save this for use in resets\n this.monitorFormChanges();\n }\n\n // construct a patch object for the save request\n private integrateFields(mods: FormValue, recordingSession: Record<string, any>) {\n const { patient } = recordingSession;\n patient.height = mods.height;\n patient.weight = mods.weight;\n patient.age = getAge(mods.dob);\n\n recordingSession.mealStart = globaliseDateTime(mods.mealStart);\n recordingSession.mealEnd = globaliseDateTime(mods.mealEnd);\n\n this.logChange(mods);\n\n return {\n 'Age': patient.age,\n 'RecordingSession': JSON.stringify(recordingSession),\n 'UserDetailChangeLog': this.detailChangeLog\n }\n }\n\n private postDeviceData(devicePropertySetId: string, data: object) {\n return this.shared.saveDeviceData(\n this.config.deviceDataModelId,\n this.deviceDataId,\n devicePropertySetId,\n this.config.owners[0],\n data\n );\n }\n\n // patch the device data record with the modifications\n saveModifications() {\n const mods = this.formGroup.getRawValue();\n const patchedDeviceData = this.integrateFields(mods, this.recordingSession);\n const patchedUserData = Object.assign(this.owner, { dateOfBirth: mods.dob });\n\n this.status = 'sending';\n forkJoin([\n this.postDeviceData(appDataPropertySetId, patchedDeviceData),\n this.shared.updateUser(this.config.owners[0], patchedUserData)\n ]).pipe(\n tap(() => this.regenReport())\n ).subscribe();\n }\n\n private logChange(mods: FormValue) {\n const entry = {\n author: this.currentUser.emailAddress,\n timestamp: new Date().toISOString(),\n ...shallowDiff(this.initialFormState, mods)\n }\n\n this.detailChangeLog.push(entry);\n\n console.log(this.detailChangeLog);\n }\n\n regenReport() {\n this.postDeviceData(\n deviceDataPropertySetId,\n { 'Algorithmhasrun': false, 'AlgorithmRun': true }\n ).subscribe(() => {\n this.status = 'generating'; // assume report starts generating immediately\n })\n }\n\n resetModifications() {\n this.formGroup.patchValue(this.initialFormState);\n }\n\n private loadData(currentUserId: string, ownerId: string, deviceDataModelId: string) {\n forkJoin([\n this.shared.getUser(currentUserId),\n this.shared.getUser(ownerId),\n this.shared.getDeviceData(deviceDataModelId, ownerId, propertyCodes)\n ]).subscribe({\n next: ([currentUser, owner, { deviceDataId, data: deviceData }]) => {\n this.currentUser = currentUser;\n this.owner = owner;\n this.deviceDataId = deviceDataId;\n\n this.recordingSession = JSON.parse(deviceData['RecordingSession'].value);\n this.initialiseForm(this.extractFields(this.recordingSession));\n\n // data field uninitialised for unmodified record\n this.detailChangeLog = deviceData['UserDetailChangeLog']?.value ?? [];\n\n this.status = deviceData['Status']?.value === 'Generating Report' ?\n 'generating' : 'success';\n },\n error: (err) => {\n console.error(err);\n this.status = \"error\";\n }\n });\n }\n\n private init() {\n if (!this.config?.currentUserId || !this.config.deviceDataModelId) {\n this.status = 'cfgerror'\n return;\n } else if (!this.config?.owners?.[0]) {\n this.status = 'nouser';\n return;\n }\n\n this.status = 'loading';\n this.loadData(this.config.currentUserId, this.config.owners[0], this.config.deviceDataModelId);\n }\n\n // this should be called from the parent using the ViewChild attr\n refresh() {\n this.init();\n }\n\n // NOTE: there could be something wrong / unusual here but it seems to work ok\n ngOnInit() {\n if (this.config && !this.configDiffer) this.configDiffer = this.kvDiffers.find(this.config).create();\n if (this.config?.owners && !this.ownersDiffer) this.ownersDiffer = this.itDiffers.find(this.config.owners).create();\n }\n\n ngDoCheck() {\n const configChanges = this.configDiffer?.diff(this.config);\n const ownersChanges = this.ownersDiffer?.diff(this.config?.owners);\n\n if (configChanges || ownersChanges) this.init();\n }\n}\n","<div class=\"wrapper\">\n <div class=\"status\" *ngIf=\"status === 'error'\">\n An error occured while trying to get the details.\n </div>\n <div class=\"status\" *ngIf=\"status === 'cfgerror'\">\n The widget has not been configured correctly, or is missing configuration information.\n </div>\n <div class=\"status\" *ngIf=\"status === 'nouser'\">\n There is no user specified as the data owner.\n </div>\n <form *ngIf=\"!status.includes('error') && status !== 'nouser'\" [formGroup]=\"formGroup\" (ngSubmit)=\"saveModifications()\">\n <div class=\"inputs\">\n <div class=\"form-row\">\n <label for=\"dob\">Date of Birth:</label>\n <input id=\"dob\" type=\"date\" formControlName=\"dob\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"weight\">Patient Weight (kg):</label>\n <input id=\"weight\" type=\"number\" formControlName=\"weight\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"height\">Patient Height (cm):</label>\n <input id=\"height\" type=\"number\" formControlName=\"height\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealStart\">Meal Start Time:</label>\n <input id=\"mealStart\" type=\"datetime-local\" formControlName=\"mealStart\">\n </div>\n\n <div class=\"form-row\">\n <label for=\"mealEnd\">Meal End Time:</label>\n <input id=\"mealEnd\" type=\"datetime-local\" formControlName=\"mealEnd\">\n </div>\n </div>\n\n <div *ngIf=\"!formGroup.valid && formGroup.dirty\" class=\"errors\">\n <div *ngFor=\"let control of formGroup.controls | entries\">\n {{ parseInputErrors(control[0], control[1]) }}\n </div>\n </div>\n\n <div *ngIf=\"status === 'generating'\" class=\"info\">\n <div>The report is generating at the moment, check back later if you need to modify this entry.</div>\n </div>\n\n <div class=\"buttons\">\n <button type=\"button\" (click)=\"regenReport()\" [disabled]=\"status === 'sending' || status === 'generating' || status === 'loading'\">Regenerate Report</button>\n <button type=\"button\" (click)=\"resetModifications()\" [disabled]=\"status === 'sending' || status === 'generating' || formGroup.pristine\">Cancel Modification</button>\n <button type=\"submit\" [disabled]=\"status === 'sending' || status === 'generating' || !formGroup.valid || formGroup.pristine\">Save Details</button>\n </div>\n </form>\n</div>\n","import { CommonModule, JsonPipe } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { ReactiveFormsModule } from '@angular/forms';\nimport { DetailEditComponent } from './detail-edit.component';\nimport { EntriesPipe } from './entries.pipe';\n\n\n\n@NgModule({\n declarations: [\n DetailEditComponent,\n EntriesPipe\n ],\n imports: [\n JsonPipe,\n ReactiveFormsModule,\n CommonModule\n ],\n exports: [\n DetailEditComponent\n ]\n})\nexport class DetailEditModule { }\n","/*\n * Public API Surface of detail-edit\n */\n\nexport * from './lib/detail-edit.service';\nexport * from './lib/detail-edit.component';\nexport * from './lib/detail-edit.module';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i4.EntriesPipe"],"mappings":";;;;;;;;;MAKa,iBAAiB,CAAA;AAE5B,IAAA,WAAA,GAAA,GAAiB;;+GAFN,iBAAiB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;AAAjB,iBAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,iBAAiB,cAFhB,MAAM,EAAA,CAAA,CAAA;4FAEP,iBAAiB,EAAA,UAAA,EAAA,CAAA;kBAH7B,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE,MAAM;AACnB,iBAAA,CAAA;;;ACJD;AACM,SAAU,gBAAgB,CAAC,QAAgB,EAAA;AAC/C,IAAA,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC;AAEhC,IAAA,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IAAC,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACjG,IAAA,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACvD,IAAA,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACzD,IAAA,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAC7D,IAAA,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAE7D,IAAA,OAAO,CAAG,EAAA,IAAI,CAAI,CAAA,EAAA,KAAK,CAAI,CAAA,EAAA,GAAG,CAAI,CAAA,EAAA,IAAI,CAAI,CAAA,EAAA,MAAM,CAAI,CAAA,EAAA,MAAM,EAAE,CAAC;AAC/D,CAAC;AAED;AACM,SAAU,iBAAiB,CAAC,QAAgB,EAAA;AAChD,IAAA,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC;AAEhC,IAAA,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,iBAAiB,EAAE,CAAC;IACzC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AAEnC,IAAA,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC;IACrC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAClE,IAAA,MAAM,OAAO,GAAG,MAAM,CAAC,SAAS,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACxD,MAAM,YAAY,GAAG,CAAG,EAAA,IAAI,GAAG,KAAK,CAAA,CAAA,EAAI,OAAO,CAAA,CAAE,CAAC;AAClD,IAAA,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;AAChC,IAAA,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAC3D,IAAA,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACpD,IAAA,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACtD,IAAA,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAC1D,IAAA,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAE1D,MAAM,QAAQ,GAAG,CAAG,EAAA,IAAI,IAAI,KAAK,CAAA,CAAA,EAAI,GAAG,CAAA,CAAE,CAAC;IAC3C,MAAM,QAAQ,GAAG,CAAG,EAAA,IAAI,IAAI,MAAM,CAAA,CAAA,EAAI,MAAM,CAAA,IAAA,CAAM,CAAC;AAEnD,IAAA,OAAO,GAAG,QAAQ,CAAA,CAAA,EAAI,QAAQ,CAAG,EAAA,YAAY,EAAE,CAAC;AAClD,CAAC;AAEK,SAAU,MAAM,CAAC,GAAW,EAAA;AAChC,IAAA,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;AAC3B,IAAA,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IAEvB,IAAI,GAAG,GAAG,GAAG,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IAEjD,IAAI,GAAG,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE;SACjC,GAAG,CAAC,QAAQ,EAAE,KAAK,IAAI,CAAC,QAAQ,EAAE,IAAI,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE;AACxE,QAAA,GAAG,EAAE,CAAC;AACP,KAAA;AAED,IAAA,OAAO,GAAG,CAAC;AACb,CAAC;AAEK,SAAU,QAAQ,CAAC,KAAa,EAAA;IACpC,IAAI,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;AAC9C,IAAA,OAAO,MAAM,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;AACvE,CAAC;AAEe,SAAA,cAAc,CAAC,CAAS,EAAE,CAAS,EAAA;IACjD,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AACzD,CAAC;AAEe,SAAA,WAAW,CAAC,CAAS,EAAE,CAAS,EAAA;AAC9C,IAAA,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAClF,IAAA,MAAM,EAAE,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7E,IAAA,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;AACtB;;AC7DA,SAAS,eAAe,CAAC,OAAwB,EAAE,QAAgB,EAAE,UAAe,EAAA;AAClF,IAAA,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC;IAC3C,IAAI,aAAa,CAAC,QAAQ,CAAC;QAAE,OAAO;AACpC,IAAA,OAAO,CAAC,SAAS,CAAC,EAAE,GAAG,aAAa,EAAE,CAAC,QAAQ,GAAG,UAAU,EAAE,CAAC,CAAC;AAClE,CAAC;AAED,SAAS,iBAAiB,CAAC,OAAwB,EAAE,QAAgB,EAAA;AACnE,IAAA,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC;AAC3C,IAAA,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC;QAAE,OAAO;AACrC,IAAA,OAAO,CAAC,SAAS,CAAC,EAAE,GAAG,aAAa,EAAE,CAAC,QAAQ,GAAG,IAAI,EAAE,CAAC,CAAC;AAC5D,CAAC;SAEe,cAAc,CAAC,CAAS,EAAE,CAAS,EAAE,UAA8B,EAAA;AACjF,IAAA,OAAO,UAAS,OAAkC,EAAA;AAChD,QAAA,IAAI,EAAE,OAAO,YAAY,SAAS,CAAC;AAAE,YAAA,OAAO,IAAI,CAAC;QAEjD,MAAM,SAAS,GAAG,OAAoB,CAAC;QAEvC,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAClC,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAElC,IAAI,CAAC,QAAQ,EAAE,KAAK,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE;AACxC,YAAA,iBAAiB,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;AACzC,YAAA,OAAO,IAAI,CAAC;AACb,SAAA;QAED,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACvC,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAEvC,MAAM,QAAQ,IACZ,UAAU,KAAK,OAAO,IAAI,KAAK,IAAI,KAAK;AACxC,YAAA,UAAU,KAAK,QAAQ,IAAI,KAAK,IAAI,KAAK,CAC1C,CAAC;AAEF,QAAA,IAAI,QAAQ,EAAE;AACZ,YAAA,eAAe,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC;AACnE,YAAA,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AAC5B,SAAA;AAED,QAAA,iBAAiB,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;AACzC,QAAA,OAAO,IAAI,CAAC;AACd,KAAC,CAAA;AACH,CAAC;AAEK,SAAU,YAAY,CAAC,CAAS,EAAE,GAAmC,GAAA,MAAM,EAAE,EAAS,EAAA;AAC1F,IAAA,OAAO,UAAS,OAAwB,EAAA;AACtC,QAAA,MAAM,SAAS,GAAG,OAAO,EAAE,KAAK,CAAC;AACjC,QAAA,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC;AAAE,YAAA,OAAO,IAAI,CAAC;AAEpE,QAAA,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC;AACjC,QAAA,MAAM,OAAO,GAAG,EAAE,IAAI,IAAI,IAAI,EAAE,CAAC;AAEjC,QAAA,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,CAAA;QAC7B,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC;AAC3C,QAAA,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,CAAA;QAC7B,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC;QAE3C,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,GAAG,KAAK,OAAO;YAAE,OAAO,GAAG,IAAI,GAAG,GAAG,IAAI,IAAI,GAAG,OAAO,CAAC;aACvD,IAAI,GAAG,KAAK,QAAQ;YAAE,OAAO,GAAG,IAAI,GAAG,GAAG,IAAI,IAAI,GAAG,OAAO,CAAC;;YAC7D,OAAO,GAAG,IAAI,GAAG,GAAG,IAAI,IAAI,GAAG,GAAG,CAAC;AAExC,QAAA,OAAO,OAAO,GAAG,IAAI,GAAG,EAAE,cAAc,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC;AAClE,KAAC,CAAA;AACH,CAAC;AAEK,SAAU,YAAY,CAAC,CAAS,EAAE,GAAmC,GAAA,MAAM,EAAE,EAAS,EAAA;AAC1F,IAAA,OAAO,UAAS,OAAwB,EAAA;AACtC,QAAA,MAAM,SAAS,GAAG,OAAO,EAAE,KAAK,CAAC;AACjC,QAAA,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC;AAAE,YAAA,OAAO,IAAI,CAAC;AAEpE,QAAA,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC;AACjC,QAAA,MAAM,OAAO,GAAG,EAAE,IAAI,IAAI,IAAI,EAAE,CAAC;AAEjC,QAAA,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,CAAA;QAC7B,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;AACrC,QAAA,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,CAAA;QAC7B,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;QAErC,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,GAAG,KAAK,OAAO;YAAE,OAAO,GAAG,IAAI,GAAG,GAAG,IAAI,IAAI,GAAG,OAAO,CAAC;aACvD,IAAI,GAAG,KAAK,QAAQ;YAAE,OAAO,GAAG,IAAI,GAAG,GAAG,IAAI,IAAI,GAAG,OAAO,CAAC;;YAC7D,OAAO,GAAG,IAAI,GAAG,GAAG,IAAI,IAAI,GAAG,GAAG,CAAC;AAExC,QAAA,OAAO,OAAO,GAAG,IAAI,GAAG,EAAE,cAAc,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC;AAClE,KAAC,CAAA;AACH,CAAC;AAED;AACgB,SAAA,cAAc,CAAC,IAAY,EAAE,OAAwB,EAAA;AACnE,IAAA,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;AAE3B,IAAA,IAAI,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;AAC9B,QAAA,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,uBAAuB,CAAC;AAC7C,SAAA,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;AAC9B,QAAA,OAAO,CAAG,EAAA,QAAQ,CAAC,IAAI,CAAC,CAAA,0BAAA,EAA6B,MAAM,CAAC,GAAG,CAAC,GAAG,CAAA,CAAA,CAAG,CAAC;AACpE,SAAA,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;AAC9B,QAAA,OAAO,CAAG,EAAA,QAAQ,CAAC,IAAI,CAAC,CAAA,0BAAA,EAA6B,MAAM,CAAC,GAAG,CAAC,GAAG,CAAA,CAAA,CAAG,CAAC;AACpE,SAAA,IAAI,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;AACjC,QAAA,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,2BAA2B,CAAC;AACjD,SAAA,IAAI,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;QACpC,OAAO,CAAA,EAAG,QAAQ,CAAC,IAAI,CAAC,CAAgB,aAAA,EAAA,MAAM,CAAC,SAAS,CAAC,UAAU,CAAI,CAAA,EAAA,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA,CAAA,CAAG,CAAC;AAC1G,SAAA,IAAI,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC;AACzC,QAAA,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAA,oBAAA,EAAuB,MAAM,CAAC,cAAc,CAAC,CAAC,aAAa,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC;AAChH,SAAA,IAAI,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC;AACzC,QAAA,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAA,oBAAA,EAAuB,MAAM,CAAC,cAAc,CAAC,CAAC,aAAa,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC;AAErH,IAAA,OAAO,IAAI,CAAC;AACd;;MC1Ga,WAAW,CAAA;AACtB,IAAA,SAAS,CAAC,KAAa,EAAA;AACrB,QAAA,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;KAC9B;;yGAHU,WAAW,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,IAAA,EAAA,CAAA,CAAA;uGAAX,WAAW,EAAA,IAAA,EAAA,SAAA,EAAA,CAAA,CAAA;4FAAX,WAAW,EAAA,UAAA,EAAA,CAAA;kBAHvB,IAAI;AAAC,YAAA,IAAA,EAAA,CAAA;AACJ,oBAAA,IAAI,EAAE,SAAS;AAChB,iBAAA,CAAA;;;ACGD,MAAM,oBAAoB,GAAG,sCAAsC,CAAC;AACpE,MAAM,uBAAuB,GAAG,sCAAsC,CAAC;AACvE,MAAM,aAAa,GAAG,CAAC,kBAAkB,EAAE,QAAQ,EAAE,qBAAqB,CAAC,CAAC;MAsB/D,mBAAmB,CAAA;AA+B9B,IAAA,WAAA,CAAoB,MAAqB,EAAU,SAA0B,EAAU,SAA0B,EAAA;QAA7F,IAAM,CAAA,MAAA,GAAN,MAAM,CAAe;QAAU,IAAS,CAAA,SAAA,GAAT,SAAS,CAAiB;QAAU,IAAS,CAAA,SAAA,GAAT,SAAS,CAAiB;QAzBjH,IAAM,CAAA,MAAA,GAAuF,SAAS,CAAC;QAcvG,IAAS,CAAA,SAAA,GAAG,IAAI,SAAS,CAAC;AACxB,YAAA,GAAG,EAAE,IAAI,WAAW,CAAS,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,YAAY,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;YACpF,MAAM,EAAE,IAAI,WAAW,CAAS,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;YAClG,MAAM,EAAE,IAAI,WAAW,CAAS,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;YACjG,SAAS,EAAE,IAAI,WAAW,CAAS,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;YAC7D,OAAO,EAAE,IAAI,WAAW,CAAS,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;SAC5D,EAAE;AACD,YAAA,cAAc,CAAC,SAAS,EAAE,WAAW,EAAE,OAAO,CAAC;AAC/C,YAAA,cAAc,CAAC,WAAW,EAAE,KAAK,EAAE,OAAO,CAAC;AAC5C,SAAA,CAAC,CAAC;KAEmH;IAEtH,gBAAgB,CAAC,IAAY,EAAE,OAAwB,EAAA;AACrD,QAAA,OAAO,cAAc,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;KACtC;;IAGO,kBAAkB,GAAA;QACxB,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,SAAS,CAAC,OAAO,IAAG;YAC9C,IAAI,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,gBAAgB,CAAC,EAAE;AAClD,gBAAA,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE,CAAC;AACjC,aAAA;AACH,SAAC,CAAC,CAAA;KACH;;AAGO,IAAA,aAAa,CAAC,gBAAqC,EAAA;QACzD,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,EAAE,GAAG,gBAAgB,CAAC;AACzE,QAAA,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;QAErC,OAAO;AACL,YAAA,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW;YAC3B,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,MAAM,EAAE,OAAO,CAAC,MAAM;AACtB,YAAA,SAAS,EAAE,gBAAgB,CAAC,SAAS,CAAC;AACtC,YAAA,OAAO,EAAE,gBAAgB,CAAC,OAAO,CAAC;SACnC,CAAA;KACF;AAEO,IAAA,cAAc,CAAC,KAAa,EAAA;AAClC,QAAA,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;AACjC,QAAA,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE,CAAC;QAEhC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;QACxG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,aAAa,CAAC,YAAY,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;AAEtG,QAAA,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC;QAC9B,IAAI,CAAC,kBAAkB,EAAE,CAAC;KAC3B;;IAGO,eAAe,CAAC,IAAe,EAAE,gBAAqC,EAAA;AAC5E,QAAA,MAAM,EAAE,OAAO,EAAE,GAAG,gBAAgB,CAAC;AACrC,QAAA,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;AAC7B,QAAA,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC7B,OAAO,CAAC,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAE/B,gBAAgB,CAAC,SAAS,GAAG,iBAAiB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC/D,gBAAgB,CAAC,OAAO,GAAG,iBAAiB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AAE3D,QAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAErB,OAAO;YACL,KAAK,EAAE,OAAO,CAAC,GAAG;AAClB,YAAA,kBAAkB,EAAE,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC;YACpD,qBAAqB,EAAE,IAAI,CAAC,eAAe;SAC5C,CAAA;KACF;IAEO,cAAc,CAAC,mBAA2B,EAAE,IAAY,EAAA;AAC9D,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,cAAc,CAC/B,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAC7B,IAAI,CAAC,YAAY,EACjB,mBAAmB,EACnB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EACrB,IAAI,CACL,CAAC;KACH;;IAGD,iBAAiB,GAAA;QACf,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC;AAC1C,QAAA,MAAM,iBAAiB,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC;AAC5E,QAAA,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;AAE7E,QAAA,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;AACxB,QAAA,QAAQ,CAAC;AACP,YAAA,IAAI,CAAC,cAAc,CAAC,oBAAoB,EAAE,iBAAiB,CAAC;AAC5D,YAAA,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,eAAe,CAAC;AAC/D,SAAA,CAAC,CAAC,IAAI,CACL,GAAG,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC,CAC9B,CAAC,SAAS,EAAE,CAAC;KACf;AAEO,IAAA,SAAS,CAAC,IAAe,EAAA;AAC/B,QAAA,MAAM,KAAK,GAAG;AACZ,YAAA,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,YAAY;AACrC,YAAA,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;AACnC,YAAA,GAAG,WAAW,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC;SAC5C,CAAA;AAED,QAAA,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAEjC,QAAA,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;KACnC;IAED,WAAW,GAAA;AACT,QAAA,IAAI,CAAC,cAAc,CACjB,uBAAuB,EACvB,EAAE,iBAAiB,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,CACnD,CAAC,SAAS,CAAC,MAAK;AACf,YAAA,IAAI,CAAC,MAAM,GAAG,YAAY,CAAC;AAC7B,SAAC,CAAC,CAAA;KACH;IAED,kBAAkB,GAAA;QAChB,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;KAClD;AAEO,IAAA,QAAQ,CAAC,aAAqB,EAAE,OAAe,EAAE,iBAAyB,EAAA;AAChF,QAAA,QAAQ,CAAC;AACP,YAAA,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC;AAClC,YAAA,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC;YAC5B,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,iBAAiB,EAAE,OAAO,EAAE,aAAa,CAAC;SACrE,CAAC,CAAC,SAAS,CAAC;AACX,YAAA,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,KAAK,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,KAAI;AACjE,gBAAA,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;AAC/B,gBAAA,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;AACnB,gBAAA,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;AAEjC,gBAAA,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC,KAAK,CAAC,CAAC;AACzE,gBAAA,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;;gBAG/D,IAAI,CAAC,eAAe,GAAG,UAAU,CAAC,qBAAqB,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;AAEtE,gBAAA,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,EAAE,KAAK,KAAK,mBAAmB;AAC/D,oBAAA,YAAY,GAAG,SAAS,CAAC;aAC5B;AACD,YAAA,KAAK,EAAE,CAAC,GAAG,KAAI;AACb,gBAAA,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AACnB,gBAAA,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC;aACvB;AACF,SAAA,CAAC,CAAC;KACJ;IAEO,IAAI,GAAA;AACV,QAAA,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,aAAa,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAE;AACjE,YAAA,IAAI,CAAC,MAAM,GAAG,UAAU,CAAA;YACxB,OAAO;AACR,SAAA;aAAM,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,EAAE;AACpC,YAAA,IAAI,CAAC,MAAM,GAAG,QAAQ,CAAC;YACvB,OAAO;AACR,SAAA;AAED,QAAA,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;QACxB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;KAChG;;IAGD,OAAO,GAAA;QACL,IAAI,CAAC,IAAI,EAAE,CAAC;KACb;;IAGD,QAAQ,GAAA;AACN,QAAA,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,YAAY;AAAE,YAAA,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC;QACrG,IAAI,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,IAAI,CAAC,YAAY;AAAE,YAAA,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC;KACrH;IAED,SAAS,GAAA;AACP,QAAA,MAAM,aAAa,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC3D,QAAA,MAAM,aAAa,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAEnE,IAAI,aAAa,IAAI,aAAa;YAAE,IAAI,CAAC,IAAI,EAAE,CAAC;KACjD;;iHApMU,mBAAmB,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAA,EAAA,CAAA,aAAA,EAAA,EAAA,EAAA,KAAA,EAAA,EAAA,CAAA,eAAA,EAAA,EAAA,EAAA,KAAA,EAAA,EAAA,CAAA,eAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAnB,mBAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,mBAAmB,qFC/BhC,i7EAuDA,EAAA,MAAA,EAAA,CAAA,kqCAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,aAAA,EAAA,QAAA,EAAA,8CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,8MAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,mBAAA,EAAA,QAAA,EAAA,iGAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,2CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,0FAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,kBAAA,EAAA,QAAA,EAAA,aAAA,EAAA,MAAA,EAAA,CAAA,WAAA,CAAA,EAAA,OAAA,EAAA,CAAA,UAAA,CAAA,EAAA,QAAA,EAAA,CAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,CAAA,iBAAA,EAAA,UAAA,EAAA,SAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,kBAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,cAAA,EAAA,eAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,IAAA,EAAA,QAAA,EAAA,QAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,UAAA,EAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAAA,WAAA,EAAA,IAAA,EAAA,SAAA,EAAA,CAAA,EAAA,CAAA,CAAA;4FDxBa,mBAAmB,EAAA,UAAA,EAAA,CAAA;kBAL/B,SAAS;+BACE,iBAAiB,EAAA,QAAA,EAAA,i7EAAA,EAAA,MAAA,EAAA,CAAA,kqCAAA,CAAA,EAAA,CAAA;gKAKlB,MAAM,EAAA,CAAA;sBAAd,KAAK;;;MEVK,gBAAgB,CAAA;;8GAAhB,gBAAgB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,QAAA,EAAA,CAAA,CAAA;AAAhB,gBAAA,CAAA,IAAA,GAAA,EAAA,CAAA,mBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,gBAAgB,iBAZzB,mBAAmB;AACnB,QAAA,WAAW,aAGX,QAAQ;QACR,mBAAmB;AACnB,QAAA,YAAY,aAGZ,mBAAmB,CAAA,EAAA,CAAA,CAAA;AAGV,gBAAA,CAAA,IAAA,GAAA,EAAA,CAAA,mBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,gBAAgB,YAPzB,mBAAmB;QACnB,YAAY,CAAA,EAAA,CAAA,CAAA;4FAMH,gBAAgB,EAAA,UAAA,EAAA,CAAA;kBAd5B,QAAQ;AAAC,YAAA,IAAA,EAAA,CAAA;AACR,oBAAA,YAAY,EAAE;wBACZ,mBAAmB;wBACnB,WAAW;AACZ,qBAAA;AACD,oBAAA,OAAO,EAAE;wBACP,QAAQ;wBACR,mBAAmB;wBACnB,YAAY;AACb,qBAAA;AACD,oBAAA,OAAO,EAAE;wBACP,mBAAmB;AACpB,qBAAA;AACF,iBAAA,CAAA;;;ACrBD;;AAEG;;ACFH;;AAEG;;;;"}
@@ -1,10 +1,15 @@
1
+ import { DoCheck, KeyValueDiffers, IterableDiffers } from '@angular/core';
1
2
  import { AbstractControl, FormControl, FormGroup } from '@angular/forms';
2
3
  import { Config, SharedService } from 'alimetry-shared';
3
4
  import * as i0 from "@angular/core";
4
- export declare class DetailEditComponent {
5
+ export declare class DetailEditComponent implements DoCheck {
5
6
  private shared;
7
+ private kvDiffers;
8
+ private itDiffers;
6
9
  config: Config;
7
- status: 'error' | 'loading' | 'success' | 'generating' | 'sending' | 'nouser';
10
+ private configDiffer?;
11
+ private ownersDiffer?;
12
+ status: 'error' | 'cfgerror' | 'loading' | 'success' | 'generating' | 'sending' | 'nouser';
8
13
  private deviceDataId;
9
14
  private recordingSession;
10
15
  private recordingStart;
@@ -19,7 +24,7 @@ export declare class DetailEditComponent {
19
24
  mealStart: FormControl<string>;
20
25
  mealEnd: FormControl<string>;
21
26
  }>;
22
- constructor(shared: SharedService);
27
+ constructor(shared: SharedService, kvDiffers: KeyValueDiffers, itDiffers: IterableDiffers);
23
28
  parseInputErrors(name: string, control: AbstractControl): string;
24
29
  private monitorFormChanges;
25
30
  private extractFields;
@@ -28,10 +33,13 @@ export declare class DetailEditComponent {
28
33
  private postDeviceData;
29
34
  saveModifications(): void;
30
35
  private logChange;
31
- private loadDeviceData;
32
36
  regenReport(): void;
33
37
  resetModifications(): void;
38
+ private loadData;
39
+ private init;
40
+ refresh(): void;
34
41
  ngOnInit(): void;
42
+ ngDoCheck(): void;
35
43
  static ɵfac: i0.ɵɵFactoryDeclaration<DetailEditComponent, never>;
36
44
  static ɵcmp: i0.ɵɵComponentDeclaration<DetailEditComponent, "lib-detail-edit", never, { "config": "config"; }, {}, never, never, false, never>;
37
45
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alimetry-detail-edit",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^15.2.0",
6
6
  "@angular/core": "^15.2.0",