@gloww/gloww 20.0.0-beta.42 → 20.0.0-beta.44

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.
@@ -4,7 +4,7 @@ import { Subject, firstValueFrom, BehaviorSubject, of, combineLatest, forkJoin,
4
4
  import * as i1 from '@angular/common/http';
5
5
  import { HttpClient, HttpParams, HttpEventType, HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi, HttpResponse } from '@angular/common/http';
6
6
  import * as i3 from '@angular/common';
7
- import { Location, PlatformLocation, AsyncPipe, NgClass, isPlatformBrowser, NgStyle, CommonModule, DatePipe } from '@angular/common';
7
+ import { Location, PlatformLocation, AsyncPipe, NgClass, isPlatformBrowser, NgStyle, CommonModule } from '@angular/common';
8
8
  import * as i1$2 from '@angular/material/dialog';
9
9
  import { MAT_DIALOG_DATA, MatDialogTitle, MatDialogContent, MatDialogActions, MatDialogConfig, MatDialogModule } from '@angular/material/dialog';
10
10
  import { CdkScrollable } from '@angular/cdk/scrolling';
@@ -16,18 +16,19 @@ import * as i1$1 from '@angular/platform-browser';
16
16
  import * as i5 from '@kolkov/angular-editor';
17
17
  import { AngularEditorModule } from '@kolkov/angular-editor';
18
18
  import { switchMap, map, tap, filter, catchError, take, mergeMap, retryWhen, scan, delay, first, distinctUntilChanged, debounceTime, finalize } from 'rxjs/operators';
19
- import * as i9 from '@angular/material/sort';
19
+ import * as i9$1 from '@angular/material/sort';
20
20
  import { MatSort, MatSortModule } from '@angular/material/sort';
21
- import * as i7 from '@angular/material/paginator';
21
+ import * as i7$1 from '@angular/material/paginator';
22
22
  import { MatPaginator, MatPaginatorIntl, MatPaginatorModule } from '@angular/material/paginator';
23
23
  import * as i10 from '@angular/material/table';
24
24
  import { MatColumnDef, MatTableDataSource, MatTable, MatHeaderCellDef, MatHeaderCell, MatCellDef, MatCell, MatHeaderRowDef, MatHeaderRow, MatRowDef, MatRow, MatTableModule } from '@angular/material/table';
25
- import * as i8 from '@angular/material/progress-spinner';
25
+ import * as i8$1 from '@angular/material/progress-spinner';
26
26
  import { MatProgressSpinner, MatProgressSpinnerModule } from '@angular/material/progress-spinner';
27
- import * as i5$1 from '@angular/material/card';
27
+ import * as i5$2 from '@angular/material/card';
28
28
  import { MatCard, MatCardContent, MatCardActions, MatCardHeader, MatCardTitle, MatCardModule } from '@angular/material/card';
29
- import * as i6 from '@angular/material/icon';
29
+ import * as i7 from '@angular/material/icon';
30
30
  import { MatIcon, MatIconModule } from '@angular/material/icon';
31
+ import * as i6 from '@angular/material/input';
31
32
  import { MatError, MatFormField, MatInput, MatLabel, MatInputModule, MatSuffix } from '@angular/material/input';
32
33
  import * as i4 from '@ctrl/ngx-codemirror';
33
34
  import { CodemirrorModule, CodemirrorComponent } from '@ctrl/ngx-codemirror';
@@ -39,6 +40,7 @@ import { NgxMatDatetimePickerModule, NgxMatTimepickerComponent, NgxMatNativeDate
39
40
  import moment from 'moment';
40
41
  import * as i1$4 from '@ngx-translate/core';
41
42
  import { TranslateDefaultParser } from '@ngx-translate/core';
43
+ import * as i9 from '@angular/material/select';
42
44
  import { MatSelect, MatOption, MatSelectModule } from '@angular/material/select';
43
45
  import { trigger, state, style, transition, animate } from '@angular/animations';
44
46
  import { MatListItem, MatListItemIcon, MatListItemTitle } from '@angular/material/list';
@@ -55,6 +57,10 @@ import JSZip from 'jszip';
55
57
  import { MatAutocompleteTrigger, MatAutocomplete, MatAutocompleteModule } from '@angular/material/autocomplete';
56
58
  import { MAT_DATE_LOCALE } from '@angular/material/core';
57
59
  import { AngularResizeEventModule } from 'angular-resize-event';
60
+ import * as i5$1 from '@angular/material/checkbox';
61
+ import { MatCheckboxModule } from '@angular/material/checkbox';
62
+ import * as i8 from '@angular/material/radio';
63
+ import { MatRadioModule } from '@angular/material/radio';
58
64
 
59
65
  const API_SERVER_URL = new InjectionToken('ApiServerUrl.config');
60
66
  const GLOWW_APPLI = new InjectionToken('GlowwAppli.config');
@@ -4171,13 +4177,153 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
4171
4177
  type: Injectable
4172
4178
  }], ctorParameters: () => [{ type: GlowwI18nService }] });
4173
4179
 
4180
+ class AssignedUserTaskResponseDialogComponent {
4181
+ constructor(formBuilder, dialogRef, data, sanitizer) {
4182
+ this.formBuilder = formBuilder;
4183
+ this.dialogRef = dialogRef;
4184
+ this.data = data;
4185
+ this.sanitizer = sanitizer;
4186
+ this.externalWindowRef = null;
4187
+ this.choiceFieldNames = [];
4188
+ this.form = this.formBuilder.group({});
4189
+ }
4190
+ ngOnInit() {
4191
+ this.initializeForm();
4192
+ this.initializeExternalContent();
4193
+ }
4194
+ onCancel() {
4195
+ this.externalWindowRef?.close();
4196
+ this.dialogRef.close();
4197
+ }
4198
+ onSubmit() {
4199
+ if (this.form.invalid) {
4200
+ this.form.markAllAsTouched();
4201
+ return;
4202
+ }
4203
+ this.dialogRef.close({ payload: this.buildPayload() });
4204
+ }
4205
+ reopenExternalWindow() {
4206
+ if (!this.data.externalUrl) {
4207
+ return;
4208
+ }
4209
+ this.externalWindowRef = window.open(this.data.externalUrl, '_blank', 'noopener,noreferrer');
4210
+ }
4211
+ control(name) {
4212
+ return this.form.get(name);
4213
+ }
4214
+ choiceControlName(choice) {
4215
+ return this.choiceFieldName(choice);
4216
+ }
4217
+ initializeForm() {
4218
+ switch (this.data.mode) {
4219
+ case 'single-choice':
4220
+ this.form.addControl('choice', new UntypedFormControl(null, Validators.required));
4221
+ break;
4222
+ case 'multi-choice':
4223
+ (this.data.choices ?? []).forEach(choice => {
4224
+ const fieldName = this.choiceFieldName(choice);
4225
+ this.choiceFieldNames.push(fieldName);
4226
+ this.form.addControl(fieldName, new UntypedFormControl(false));
4227
+ });
4228
+ break;
4229
+ case 'adhoc':
4230
+ case 'external':
4231
+ (this.data.fields ?? []).forEach(field => {
4232
+ this.form.addControl(field.name, new UntypedFormControl(this.resolveDefaultValue(field), field.required ? Validators.required : null));
4233
+ });
4234
+ break;
4235
+ }
4236
+ }
4237
+ initializeExternalContent() {
4238
+ if (this.data.mode !== 'external' || !this.data.externalUrl) {
4239
+ return;
4240
+ }
4241
+ if (this.data.externalOpenMode === 'window') {
4242
+ this.reopenExternalWindow();
4243
+ return;
4244
+ }
4245
+ this.externalSafeUrl = this.sanitizer.bypassSecurityTrustResourceUrl(this.data.externalUrl);
4246
+ }
4247
+ resolveDefaultValue(field) {
4248
+ if (field.defaultValue !== undefined) {
4249
+ return field.defaultValue;
4250
+ }
4251
+ const currentValue = this.data.currentVariables?.[field.name];
4252
+ if (currentValue !== undefined) {
4253
+ return currentValue;
4254
+ }
4255
+ return field.type === 'boolean' ? false : null;
4256
+ }
4257
+ buildPayload() {
4258
+ const payload = {};
4259
+ switch (this.data.mode) {
4260
+ case 'single-choice': {
4261
+ const selectedValue = this.form.getRawValue().choice;
4262
+ const selectedChoice = (this.data.choices ?? []).find(choice => choice.value === selectedValue);
4263
+ payload.response = selectedValue;
4264
+ payload.choice = selectedValue;
4265
+ payload.responseLabel = selectedChoice?.label ?? selectedValue;
4266
+ if (selectedChoice?.fieldName) {
4267
+ payload[selectedChoice.fieldName] = true;
4268
+ }
4269
+ break;
4270
+ }
4271
+ case 'multi-choice': {
4272
+ const selectedChoices = (this.data.choices ?? []).filter(choice => {
4273
+ const fieldName = this.choiceFieldName(choice);
4274
+ return !!this.form.getRawValue()[fieldName];
4275
+ });
4276
+ payload.responses = selectedChoices.map(choice => choice.value);
4277
+ payload.choices = [...payload.responses];
4278
+ payload.responseLabels = selectedChoices.map(choice => choice.label);
4279
+ selectedChoices.forEach(choice => {
4280
+ payload[choice.fieldName ?? choice.value] = true;
4281
+ });
4282
+ break;
4283
+ }
4284
+ case 'adhoc':
4285
+ case 'external':
4286
+ Object.assign(payload, this.form.getRawValue());
4287
+ break;
4288
+ }
4289
+ return payload;
4290
+ }
4291
+ choiceFieldName(choice) {
4292
+ return choice.fieldName ?? `choice_${choice.value.replace(/[^a-zA-Z0-9_]/g, '_')}`;
4293
+ }
4294
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: AssignedUserTaskResponseDialogComponent, deps: [{ token: i1$3.UntypedFormBuilder }, { token: i1$2.MatDialogRef }, { token: MAT_DIALOG_DATA }, { token: i1$1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component }); }
4295
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: AssignedUserTaskResponseDialogComponent, isStandalone: true, selector: "glw-assigned-user-task-response-dialog", ngImport: i0, template: "<h2 mat-dialog-title>{{ data.title }}</h2>\n\n<mat-dialog-content cdkScrollable>\n @if (data.message) {\n <div class=\"assigned-user-task-response-message\">{{ data.message }}</div>\n }\n\n <form [formGroup]=\"form\" class=\"assigned-user-task-response-form\">\n @if (data.mode === 'single-choice') {\n <mat-radio-group formControlName=\"choice\" class=\"assigned-user-task-response-choices\">\n @for (choice of data.choices ?? []; track choice.value) {\n <mat-radio-button [value]=\"choice.value\">{{ choice.label }}</mat-radio-button>\n }\n </mat-radio-group>\n }\n\n @if (data.mode === 'multi-choice') {\n <div class=\"assigned-user-task-response-choices\">\n @for (choice of data.choices ?? []; track choice.value) {\n <mat-checkbox [formControlName]=\"choiceControlName(choice)\">\n {{ choice.label }}\n </mat-checkbox>\n }\n </div>\n }\n\n @if (data.mode === 'adhoc' || data.mode === 'external') {\n <div class=\"assigned-user-task-response-fields\">\n @for (field of data.fields ?? []; track field.name) {\n <div class=\"assigned-user-task-response-field\">\n @if (field.type === 'boolean') {\n <mat-checkbox [formControlName]=\"field.name\">{{ field.label }}</mat-checkbox>\n }\n\n @if (field.type === 'text' || field.type === 'number' || field.type === 'textarea') {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ field.label }}</mat-label>\n @if (field.type === 'textarea') {\n <textarea\n matInput\n [formControlName]=\"field.name\"\n [rows]=\"field.rows ?? 4\"\n [placeholder]=\"field.placeholder ?? ''\"></textarea>\n } @else {\n <input\n matInput\n [type]=\"field.type === 'number' ? 'number' : 'text'\"\n [formControlName]=\"field.name\"\n [placeholder]=\"field.placeholder ?? ''\" />\n }\n </mat-form-field>\n }\n\n @if (field.type === 'select') {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ field.label }}</mat-label>\n <mat-select [formControlName]=\"field.name\">\n @for (option of field.options ?? []; track option.value) {\n <mat-option [value]=\"option.value\">{{ option.label }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n }\n\n @if (field.type === 'date' || field.type === 'datetime') {\n <label class=\"assigned-user-task-response-datetime-label\">{{ field.label }}</label>\n <gloww-datetime\n [mode]=\"field.type === 'date' ? 'date' : 'datetime'\"\n [showSeconds]=\"field.type === 'datetime'\"\n [formControlName]=\"field.name\"></gloww-datetime>\n }\n </div>\n }\n </div>\n }\n\n @if (data.mode === 'external' && data.externalOpenMode !== 'window' && externalSafeUrl) {\n <div class=\"assigned-user-task-response-iframe-wrapper\">\n <iframe class=\"assigned-user-task-response-iframe\" [src]=\"externalSafeUrl\" title=\"User task external response\"></iframe>\n </div>\n }\n\n @if (data.mode === 'external' && data.externalOpenMode === 'window') {\n <div class=\"assigned-user-task-response-window-message\">\n {{ data.externalWindowMessage }}\n </div>\n <button mat-stroked-button type=\"button\" (click)=\"reopenExternalWindow()\">\n <mat-icon>open_in_new</mat-icon>\n {{ data.reopenExternalLabel }}\n </button>\n }\n </form>\n</mat-dialog-content>\n\n<mat-dialog-actions align=\"end\">\n <button mat-button type=\"button\" (click)=\"onCancel()\">{{ data.cancelLabel }}</button>\n <button mat-flat-button color=\"primary\" type=\"button\" (click)=\"onSubmit()\">\n {{ data.mode === 'external' ? data.completeExternalLabel : data.submitLabel }}\n </button>\n</mat-dialog-actions>\n", styles: [":host{display:block}.assigned-user-task-response-message{margin-bottom:16px;white-space:pre-wrap}.assigned-user-task-response-form{display:flex;flex-direction:column;gap:16px;min-width:min(640px,100vw - 64px)}.assigned-user-task-response-choices,.assigned-user-task-response-fields{display:flex;flex-direction:column;gap:12px}.assigned-user-task-response-field{display:flex;flex-direction:column;gap:8px}.assigned-user-task-response-datetime-label{font-weight:600}.assigned-user-task-response-iframe-wrapper{border:1px solid rgba(0,0,0,.12);border-radius:8px;overflow:hidden;min-height:60vh}.assigned-user-task-response-iframe{border:0;display:block;height:60vh;width:100%}.assigned-user-task-response-window-message{color:#000000b3}mat-form-field{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$3.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: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }, { kind: "directive", type: MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "directive", type: MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i5$1.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i6.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i6.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i6.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatRadioModule }, { kind: "directive", type: i8.MatRadioGroup, selector: "mat-radio-group", inputs: ["color", "name", "labelPosition", "value", "selected", "disabled", "required", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioGroup"] }, { kind: "component", type: i8.MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i9.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i9.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "component", type: DatetimeComponent, selector: "gloww-datetime", inputs: ["value", "display", "placeHolder", "mode", "showSeconds"] }] }); }
4296
+ }
4297
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: AssignedUserTaskResponseDialogComponent, decorators: [{
4298
+ type: Component,
4299
+ args: [{ selector: 'glw-assigned-user-task-response-dialog', standalone: true, imports: [
4300
+ CommonModule,
4301
+ ReactiveFormsModule,
4302
+ CdkScrollable,
4303
+ MatDialogTitle,
4304
+ MatDialogContent,
4305
+ MatDialogActions,
4306
+ MatButtonModule,
4307
+ MatCheckboxModule,
4308
+ MatFormFieldModule,
4309
+ MatIconModule,
4310
+ MatInputModule,
4311
+ MatRadioModule,
4312
+ MatSelectModule,
4313
+ DatetimeComponent
4314
+ ], template: "<h2 mat-dialog-title>{{ data.title }}</h2>\n\n<mat-dialog-content cdkScrollable>\n @if (data.message) {\n <div class=\"assigned-user-task-response-message\">{{ data.message }}</div>\n }\n\n <form [formGroup]=\"form\" class=\"assigned-user-task-response-form\">\n @if (data.mode === 'single-choice') {\n <mat-radio-group formControlName=\"choice\" class=\"assigned-user-task-response-choices\">\n @for (choice of data.choices ?? []; track choice.value) {\n <mat-radio-button [value]=\"choice.value\">{{ choice.label }}</mat-radio-button>\n }\n </mat-radio-group>\n }\n\n @if (data.mode === 'multi-choice') {\n <div class=\"assigned-user-task-response-choices\">\n @for (choice of data.choices ?? []; track choice.value) {\n <mat-checkbox [formControlName]=\"choiceControlName(choice)\">\n {{ choice.label }}\n </mat-checkbox>\n }\n </div>\n }\n\n @if (data.mode === 'adhoc' || data.mode === 'external') {\n <div class=\"assigned-user-task-response-fields\">\n @for (field of data.fields ?? []; track field.name) {\n <div class=\"assigned-user-task-response-field\">\n @if (field.type === 'boolean') {\n <mat-checkbox [formControlName]=\"field.name\">{{ field.label }}</mat-checkbox>\n }\n\n @if (field.type === 'text' || field.type === 'number' || field.type === 'textarea') {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ field.label }}</mat-label>\n @if (field.type === 'textarea') {\n <textarea\n matInput\n [formControlName]=\"field.name\"\n [rows]=\"field.rows ?? 4\"\n [placeholder]=\"field.placeholder ?? ''\"></textarea>\n } @else {\n <input\n matInput\n [type]=\"field.type === 'number' ? 'number' : 'text'\"\n [formControlName]=\"field.name\"\n [placeholder]=\"field.placeholder ?? ''\" />\n }\n </mat-form-field>\n }\n\n @if (field.type === 'select') {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ field.label }}</mat-label>\n <mat-select [formControlName]=\"field.name\">\n @for (option of field.options ?? []; track option.value) {\n <mat-option [value]=\"option.value\">{{ option.label }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n }\n\n @if (field.type === 'date' || field.type === 'datetime') {\n <label class=\"assigned-user-task-response-datetime-label\">{{ field.label }}</label>\n <gloww-datetime\n [mode]=\"field.type === 'date' ? 'date' : 'datetime'\"\n [showSeconds]=\"field.type === 'datetime'\"\n [formControlName]=\"field.name\"></gloww-datetime>\n }\n </div>\n }\n </div>\n }\n\n @if (data.mode === 'external' && data.externalOpenMode !== 'window' && externalSafeUrl) {\n <div class=\"assigned-user-task-response-iframe-wrapper\">\n <iframe class=\"assigned-user-task-response-iframe\" [src]=\"externalSafeUrl\" title=\"User task external response\"></iframe>\n </div>\n }\n\n @if (data.mode === 'external' && data.externalOpenMode === 'window') {\n <div class=\"assigned-user-task-response-window-message\">\n {{ data.externalWindowMessage }}\n </div>\n <button mat-stroked-button type=\"button\" (click)=\"reopenExternalWindow()\">\n <mat-icon>open_in_new</mat-icon>\n {{ data.reopenExternalLabel }}\n </button>\n }\n </form>\n</mat-dialog-content>\n\n<mat-dialog-actions align=\"end\">\n <button mat-button type=\"button\" (click)=\"onCancel()\">{{ data.cancelLabel }}</button>\n <button mat-flat-button color=\"primary\" type=\"button\" (click)=\"onSubmit()\">\n {{ data.mode === 'external' ? data.completeExternalLabel : data.submitLabel }}\n </button>\n</mat-dialog-actions>\n", styles: [":host{display:block}.assigned-user-task-response-message{margin-bottom:16px;white-space:pre-wrap}.assigned-user-task-response-form{display:flex;flex-direction:column;gap:16px;min-width:min(640px,100vw - 64px)}.assigned-user-task-response-choices,.assigned-user-task-response-fields{display:flex;flex-direction:column;gap:12px}.assigned-user-task-response-field{display:flex;flex-direction:column;gap:8px}.assigned-user-task-response-datetime-label{font-weight:600}.assigned-user-task-response-iframe-wrapper{border:1px solid rgba(0,0,0,.12);border-radius:8px;overflow:hidden;min-height:60vh}.assigned-user-task-response-iframe{border:0;display:block;height:60vh;width:100%}.assigned-user-task-response-window-message{color:#000000b3}mat-form-field{width:100%}\n"] }]
4315
+ }], ctorParameters: () => [{ type: i1$3.UntypedFormBuilder }, { type: i1$2.MatDialogRef }, { type: undefined, decorators: [{
4316
+ type: Inject,
4317
+ args: [MAT_DIALOG_DATA]
4318
+ }] }, { type: i1$1.DomSanitizer }] });
4319
+
4174
4320
  class AssignedUserTasksComponent {
4175
- constructor(glowwService, authenticationService, i18n, router) {
4321
+ constructor(glowwService, authenticationService, i18n, dialog) {
4176
4322
  this.glowwService = glowwService;
4177
4323
  this.authenticationService = authenticationService;
4178
4324
  this.i18n = i18n;
4179
- this.router = router;
4180
- this.displayedColumns = ['action', 'task', 'definition', 'execution', 'status', 'message', 'assignment'];
4325
+ this.dialog = dialog;
4326
+ this.displayedColumns = ['action', 'task', 'definition', 'status', 'message', 'assignment'];
4181
4327
  this.dataSource = new MatTableDataSource([]);
4182
4328
  this.loading = false;
4183
4329
  this.errorMessage = '';
@@ -4209,22 +4355,49 @@ class AssignedUserTasksComponent {
4209
4355
  }
4210
4356
  });
4211
4357
  }
4212
- openExecution(taskAssignment) {
4213
- const executionId = taskAssignment.IsCandidate?.HasAsExecutionStep?.ExecutionID;
4214
- if (!executionId) {
4358
+ async respondToTask(taskAssignment) {
4359
+ const userTaskId = taskAssignment.UserTaskId ?? taskAssignment.IsCandidate?.USERTASKID;
4360
+ if (!userTaskId) {
4215
4361
  return;
4216
4362
  }
4217
- this.router.navigate(['/execution', executionId]);
4218
- }
4219
- openExecutionSteps(taskAssignment) {
4220
- const executionId = taskAssignment.IsCandidate?.HasAsExecutionStep?.ExecutionID;
4221
- if (!executionId) {
4222
- return;
4363
+ this.respondingTaskId = userTaskId;
4364
+ try {
4365
+ const task = await firstValueFrom(this.glowwService.getBPMN2_UserTask(userTaskId));
4366
+ const dialogData = this.buildDialogData(task);
4367
+ const dialogRef = this.dialog.open(AssignedUserTaskResponseDialogComponent, {
4368
+ width: 'min(960px, calc(100vw - 24px))',
4369
+ maxWidth: 'calc(100vw - 24px)',
4370
+ maxHeight: 'calc(100vh - 24px)',
4371
+ disableClose: true,
4372
+ autoFocus: false,
4373
+ data: dialogData
4374
+ });
4375
+ const result = await firstValueFrom(dialogRef.afterClosed());
4376
+ if (!result?.payload) {
4377
+ return;
4378
+ }
4379
+ const currentUser = this.authenticationService.currentUserValue;
4380
+ const payload = {
4381
+ ...this.parseVariables(task.VARIABLES),
4382
+ ...result.payload,
4383
+ __Username: currentUser?.username ?? '',
4384
+ __UserTaskId: userTaskId
4385
+ };
4386
+ const updatedTask = {
4387
+ ...task,
4388
+ Statut: 'RESPONDED',
4389
+ RepliedBY: currentUser?.username ?? '',
4390
+ VARIABLES: JSON.stringify(payload)
4391
+ };
4392
+ await firstValueFrom(this.glowwService.putBPMN2_UserTask(userTaskId, updatedTask));
4393
+ this.loadAssignments();
4394
+ }
4395
+ catch (error) {
4396
+ this.errorMessage = error?.error?.message || error?.message || `${error}`;
4397
+ }
4398
+ finally {
4399
+ this.respondingTaskId = undefined;
4223
4400
  }
4224
- this.router.navigate(['/executionsteps', executionId]);
4225
- }
4226
- hasExecution(taskAssignment) {
4227
- return !!taskAssignment.IsCandidate?.HasAsExecutionStep?.ExecutionID;
4228
4401
  }
4229
4402
  getTaskLabel(taskAssignment) {
4230
4403
  return taskAssignment.IsCandidate?.Title
@@ -4240,16 +4413,6 @@ class AssignedUserTasksComponent {
4240
4413
  ? `${execution.DefinitionID} (${execution.ProcessID})`
4241
4414
  : execution.DefinitionID;
4242
4415
  }
4243
- getExecutionLabel(taskAssignment) {
4244
- const step = taskAssignment.IsCandidate?.HasAsExecutionStep;
4245
- if (!step?.ExecutionID) {
4246
- return '';
4247
- }
4248
- const processStepId = step.ProcessStepID ?? taskAssignment.IsCandidate?.ProcessStepID;
4249
- return processStepId
4250
- ? `${step.ExecutionID} / ${processStepId}`
4251
- : `${step.ExecutionID}`;
4252
- }
4253
4416
  getStatusLabel(taskAssignment) {
4254
4417
  return taskAssignment.IsCandidate?.Statut
4255
4418
  || taskAssignment.STATUT
@@ -4261,6 +4424,11 @@ class AssignedUserTasksComponent {
4261
4424
  : this.t('GLOWW.CANDIDATE', 'Candidate');
4262
4425
  return `${taskAssignment.Domain ? `${taskAssignment.Domain}\\` : ''}${taskAssignment.Username ?? ''} (${type})`;
4263
4426
  }
4427
+ canRespond(taskAssignment) {
4428
+ const status = this.getStatusLabel(taskAssignment).toUpperCase();
4429
+ return !!(taskAssignment.UserTaskId ?? taskAssignment.IsCandidate?.USERTASKID)
4430
+ && (status === '' || status === 'RUNNING');
4431
+ }
4264
4432
  buildQuery() {
4265
4433
  const currentUser = this.authenticationService.currentUserValue;
4266
4434
  const query = {};
@@ -4278,8 +4446,6 @@ class AssignedUserTasksComponent {
4278
4446
  return this.getTaskLabel(item).toLowerCase();
4279
4447
  case 'definition':
4280
4448
  return this.getDefinitionLabel(item).toLowerCase();
4281
- case 'execution':
4282
- return item.IsCandidate?.HasAsExecutionStep?.ExecutionID ?? 0;
4283
4449
  case 'status':
4284
4450
  return this.getStatusLabel(item).toLowerCase();
4285
4451
  case 'message':
@@ -4290,26 +4456,232 @@ class AssignedUserTasksComponent {
4290
4456
  return item.AssignmentID ?? 0;
4291
4457
  }
4292
4458
  }
4293
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: AssignedUserTasksComponent, deps: [{ token: 'glowwService' }, { token: AuthenticationService }, { token: GlowwI18nService }, { token: i2.Router }], target: i0.ɵɵFactoryTarget.Component }); }
4294
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: AssignedUserTasksComponent, isStandalone: true, selector: "glw-assigned-user-tasks", viewQueries: [{ propertyName: "sort", first: true, predicate: MatSort, descendants: true, static: true }, { propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true }], ngImport: i0, template: "<mat-card class=\"assigned-user-tasks-card\" appearance=\"outlined\">\n <mat-card-header class=\"assigned-user-tasks-header\">\n <mat-card-title>{{ t('GLOWW.MY_ASSIGNED_TASKS', 'My assigned tasks') }}</mat-card-title>\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"loadAssignments()\">\n <mat-icon>refresh</mat-icon>\n {{ t('COMMON.REFRESH', 'Refresh') }}\n </button>\n </mat-card-header>\n\n <mat-card-content>\n @if (errorMessage) {\n <div class=\"assigned-user-tasks-error\">\n {{ t('GLOWW.UNABLE_TO_QUERY', 'Unable to query') }}: {{ errorMessage }}\n </div>\n }\n\n @if (loading) {\n <div class=\"assigned-user-tasks-loading\">\n <mat-spinner diameter=\"36\"></mat-spinner>\n </div>\n }\n\n @if (!loading) {\n <div class=\"assigned-user-tasks-table-wrapper\">\n <table mat-table [dataSource]=\"dataSource\" matSort>\n <ng-container matColumnDef=\"action\">\n <th mat-header-cell *matHeaderCellDef></th>\n <td mat-cell *matCellDef=\"let obj\">\n <button mat-icon-button type=\"button\" (click)=\"openExecution(obj)\" [disabled]=\"!hasExecution(obj)\" [attr.aria-label]=\"t('LISTS.DISPLAY', 'Display')\">\n <i class=\"fal fa-eye\"></i>\n </button>\n <button mat-icon-button type=\"button\" (click)=\"openExecutionSteps(obj)\" [disabled]=\"!hasExecution(obj)\" [attr.aria-label]=\"t('LISTS.STEPS', 'Steps')\">\n <i class=\"fal fa-list-check\"></i>\n </button>\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"task\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header=\"task\">{{ t('LISTS.TASK', 'Task') }}</th>\n <td mat-cell *matCellDef=\"let obj\">{{ getTaskLabel(obj) }}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"definition\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header=\"definition\">{{ t('LISTS.DEFINITION_ID', 'Definition ID') }}</th>\n <td mat-cell *matCellDef=\"let obj\">{{ getDefinitionLabel(obj) }}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"execution\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header=\"execution\">{{ t('LISTS.EXECUTION', 'Execution') }}</th>\n <td mat-cell *matCellDef=\"let obj\">{{ getExecutionLabel(obj) }}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"status\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header=\"status\">{{ t('LISTS.STATUS', 'Status') }}</th>\n <td mat-cell *matCellDef=\"let obj\">{{ getStatusLabel(obj) }}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"message\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header=\"message\">{{ t('LISTS.MESSAGE', 'Message') }}</th>\n <td mat-cell *matCellDef=\"let obj\">{{ obj.IsCandidate?.MESSAGE }}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"assignment\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header=\"assignment\">{{ t('LISTS.ASSIGNED_TO', 'Assigned to') }}</th>\n <td mat-cell *matCellDef=\"let obj\">{{ getAssignmentLabel(obj) }}</td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns\"></tr>\n </table>\n </div>\n\n @if (!dataSource.data.length) {\n <div class=\"assigned-user-tasks-empty\">\n {{ t('GLOWW.NO_ASSIGNED_TASKS', 'No task is currently assigned to you.') }}\n </div>\n }\n }\n </mat-card-content>\n\n <mat-card-actions>\n <mat-paginator [pageSize]=\"10\" [pageSizeOptions]=\"[10, 20, 50, 100]\" [showFirstLastButtons]=\"true\"></mat-paginator>\n </mat-card-actions>\n</mat-card>\n", styles: [":host{display:block}.assigned-user-tasks-card{margin:16px}.assigned-user-tasks-header{display:flex;align-items:center;justify-content:space-between;gap:12px;padding-bottom:12px}.assigned-user-tasks-loading,.assigned-user-tasks-empty,.assigned-user-tasks-error{padding:16px 0}.assigned-user-tasks-table-wrapper{overflow:auto}table{width:100%}th:first-child,td:first-child{width:88px;white-space:nowrap}button[mat-icon-button]{margin-right:4px}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i4$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i5$1.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i5$1.MatCardActions, selector: "mat-card-actions", inputs: ["align"], exportAs: ["matCardActions"] }, { kind: "directive", type: i5$1.MatCardContent, selector: "mat-card-content" }, { kind: "component", type: i5$1.MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: i5$1.MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i7.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i8.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatSortModule }, { kind: "directive", type: i9.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i9.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i10.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i10.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i10.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i10.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i10.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i10.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i10.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i10.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i10.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i10.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }] }); }
4459
+ buildDialogData(task) {
4460
+ const jsInfo = this.parseMaybeJson(task.JSINFO);
4461
+ const formInfo = this.parseMaybeJson(task.Form);
4462
+ const currentVariables = this.parseVariables(task.VARIABLES);
4463
+ const fields = this.normalizeFields(jsInfo, formInfo, currentVariables);
4464
+ const externalConfig = this.resolveExternalConfig(task, jsInfo, formInfo);
4465
+ if (externalConfig) {
4466
+ return {
4467
+ mode: 'external',
4468
+ title: task.DialogTitle || task.Title || this.t('GLOWW.RESPOND_TO_TASK', 'Respond to task'),
4469
+ message: task.MESSAGE,
4470
+ fields,
4471
+ currentVariables,
4472
+ externalUrl: externalConfig.url,
4473
+ externalOpenMode: externalConfig.openMode,
4474
+ submitLabel: this.t('COMMON.SAVE', 'Save'),
4475
+ cancelLabel: this.t('COMMON.CANCEL', 'Cancel'),
4476
+ reopenExternalLabel: this.t('GLOWW.REOPEN_EXTERNAL_FORM', 'Reopen external form'),
4477
+ completeExternalLabel: this.t('GLOWW.COMPLETE_TASK', 'Complete task'),
4478
+ externalWindowMessage: this.t('GLOWW.COMPLETE_EXTERNAL_FORM_THEN_VALIDATE', 'Complete the external form, then validate the task here.')
4479
+ };
4480
+ }
4481
+ if ((task.FormType || '1') === '2') {
4482
+ return {
4483
+ mode: 'multi-choice',
4484
+ title: task.DialogTitle || task.Title || this.t('GLOWW.RESPOND_TO_TASK', 'Respond to task'),
4485
+ message: task.MESSAGE,
4486
+ choices: this.parseChoices(task.CHOICES),
4487
+ submitLabel: this.t('GLOWW.SUBMIT_RESPONSE', 'Submit response'),
4488
+ cancelLabel: this.t('COMMON.CANCEL', 'Cancel'),
4489
+ reopenExternalLabel: '',
4490
+ completeExternalLabel: '',
4491
+ externalWindowMessage: ''
4492
+ };
4493
+ }
4494
+ if ((task.FormType || '1') === '1' && (task.CHOICES || '').trim()) {
4495
+ return {
4496
+ mode: 'single-choice',
4497
+ title: task.DialogTitle || task.Title || this.t('GLOWW.RESPOND_TO_TASK', 'Respond to task'),
4498
+ message: task.MESSAGE,
4499
+ choices: this.parseChoices(task.CHOICES),
4500
+ submitLabel: this.t('GLOWW.SUBMIT_RESPONSE', 'Submit response'),
4501
+ cancelLabel: this.t('COMMON.CANCEL', 'Cancel'),
4502
+ reopenExternalLabel: '',
4503
+ completeExternalLabel: '',
4504
+ externalWindowMessage: ''
4505
+ };
4506
+ }
4507
+ return {
4508
+ mode: 'adhoc',
4509
+ title: task.DialogTitle || task.Title || this.t('GLOWW.RESPOND_TO_TASK', 'Respond to task'),
4510
+ message: task.MESSAGE,
4511
+ fields: fields.length > 0 ? fields : [{
4512
+ name: 'response',
4513
+ label: this.t('GLOWW.RESPONSE', 'Response'),
4514
+ type: 'textarea',
4515
+ rows: 6
4516
+ }],
4517
+ currentVariables,
4518
+ submitLabel: this.t('GLOWW.SUBMIT_RESPONSE', 'Submit response'),
4519
+ cancelLabel: this.t('COMMON.CANCEL', 'Cancel'),
4520
+ reopenExternalLabel: '',
4521
+ completeExternalLabel: '',
4522
+ externalWindowMessage: ''
4523
+ };
4524
+ }
4525
+ parseChoices(rawChoices) {
4526
+ if (!rawChoices?.trim()) {
4527
+ return [];
4528
+ }
4529
+ const parsedJson = this.parseMaybeJson(rawChoices);
4530
+ if (Array.isArray(parsedJson)) {
4531
+ return parsedJson
4532
+ .map(choice => this.normalizeChoice(choice))
4533
+ .filter((choice) => !!choice);
4534
+ }
4535
+ return rawChoices
4536
+ .split(/\r?\n/)
4537
+ .map(line => line.trim())
4538
+ .filter(line => !!line)
4539
+ .map(line => this.normalizeChoice(line))
4540
+ .filter((choice) => !!choice);
4541
+ }
4542
+ normalizeChoice(choice) {
4543
+ if (!choice && choice !== 0) {
4544
+ return null;
4545
+ }
4546
+ if (typeof choice === 'object') {
4547
+ const value = `${choice.value ?? choice.key ?? choice.id ?? choice.name ?? choice.label ?? choice}`;
4548
+ const label = `${choice.label ?? choice.name ?? value}`;
4549
+ return {
4550
+ value,
4551
+ label,
4552
+ fieldName: choice.fieldName ?? choice.name
4553
+ };
4554
+ }
4555
+ const text = `${choice}`.trim();
4556
+ const match = text.match(/^([^|=;:]+)\s*[|=;:]\s*(.+)$/);
4557
+ if (!match) {
4558
+ return { value: text, label: text };
4559
+ }
4560
+ const value = match[1].trim();
4561
+ const label = match[2].trim();
4562
+ return {
4563
+ value,
4564
+ label,
4565
+ fieldName: value.replace(/[^a-zA-Z0-9_]/g, '_')
4566
+ };
4567
+ }
4568
+ parseMaybeJson(rawValue) {
4569
+ if (!rawValue?.trim()) {
4570
+ return null;
4571
+ }
4572
+ try {
4573
+ return JSON.parse(rawValue);
4574
+ }
4575
+ catch {
4576
+ return null;
4577
+ }
4578
+ }
4579
+ parseVariables(rawValue) {
4580
+ const parsed = this.parseMaybeJson(rawValue);
4581
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
4582
+ ? parsed
4583
+ : {};
4584
+ }
4585
+ normalizeFields(jsInfo, formInfo, currentVariables) {
4586
+ const rawFields = Array.isArray(jsInfo)
4587
+ ? jsInfo
4588
+ : Array.isArray(jsInfo?.fields)
4589
+ ? jsInfo.fields
4590
+ : Array.isArray(formInfo)
4591
+ ? formInfo
4592
+ : Array.isArray(formInfo?.fields)
4593
+ ? formInfo.fields
4594
+ : [];
4595
+ return rawFields
4596
+ .map((field) => this.normalizeField(field, currentVariables))
4597
+ .filter((field) => !!field);
4598
+ }
4599
+ normalizeField(field, currentVariables) {
4600
+ if (!field) {
4601
+ return null;
4602
+ }
4603
+ if (typeof field === 'string') {
4604
+ return {
4605
+ name: field,
4606
+ label: field,
4607
+ type: 'text',
4608
+ defaultValue: currentVariables[field]
4609
+ };
4610
+ }
4611
+ const typeMap = {
4612
+ string: 'text',
4613
+ text: 'text',
4614
+ textarea: 'textarea',
4615
+ memo: 'textarea',
4616
+ number: 'number',
4617
+ integer: 'number',
4618
+ bool: 'boolean',
4619
+ boolean: 'boolean',
4620
+ select: 'select',
4621
+ choice: 'select',
4622
+ date: 'date',
4623
+ datetime: 'datetime'
4624
+ };
4625
+ const name = field.name ?? field.key ?? field.id;
4626
+ if (!name) {
4627
+ return null;
4628
+ }
4629
+ return {
4630
+ name,
4631
+ label: field.label ?? field.title ?? name,
4632
+ type: typeMap[(field.type ?? 'text').toString().toLowerCase()] ?? 'text',
4633
+ required: !!field.required,
4634
+ rows: field.rows,
4635
+ placeholder: field.placeholder,
4636
+ defaultValue: currentVariables[name] ?? field.defaultValue ?? field.value,
4637
+ options: Array.isArray(field.options)
4638
+ ? field.options.map((option) => ({
4639
+ value: option?.value ?? option?.key ?? option,
4640
+ label: option?.label ?? option?.name ?? option?.value ?? option
4641
+ }))
4642
+ : undefined
4643
+ };
4644
+ }
4645
+ resolveExternalConfig(task, jsInfo, formInfo) {
4646
+ const configCandidate = [jsInfo, formInfo].find(candidate => candidate && typeof candidate === 'object' && !Array.isArray(candidate));
4647
+ const directUrl = `${configCandidate?.url ?? configCandidate?.href ?? configCandidate?.externalUrl ?? task.Form ?? task.JSINFO ?? ''}`.trim();
4648
+ if (!this.looksLikeUrl(directUrl)) {
4649
+ return null;
4650
+ }
4651
+ const openModeValue = `${configCandidate?.openMode ?? configCandidate?.openIn ?? configCandidate?.target ?? ''}`.toLowerCase();
4652
+ const openMode = configCandidate?.newWindow === true
4653
+ || openModeValue === 'window'
4654
+ || openModeValue === 'new-window'
4655
+ || openModeValue === '_blank'
4656
+ ? 'window'
4657
+ : 'iframe';
4658
+ return {
4659
+ url: directUrl,
4660
+ openMode
4661
+ };
4662
+ }
4663
+ looksLikeUrl(value) {
4664
+ return !!value && /^(https?:\/\/|\/)/i.test(value.trim());
4665
+ }
4666
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: AssignedUserTasksComponent, deps: [{ token: 'glowwService' }, { token: AuthenticationService }, { token: GlowwI18nService }, { token: i1$2.MatDialog }], target: i0.ɵɵFactoryTarget.Component }); }
4667
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: AssignedUserTasksComponent, isStandalone: true, selector: "glw-assigned-user-tasks", viewQueries: [{ propertyName: "sort", first: true, predicate: MatSort, descendants: true, static: true }, { propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true }], ngImport: i0, template: "<mat-card class=\"assigned-user-tasks-card\" appearance=\"outlined\">\n <mat-card-header class=\"assigned-user-tasks-header\">\n <mat-card-title>{{ t('GLOWW.MY_ASSIGNED_TASKS', 'My assigned tasks') }}</mat-card-title>\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"loadAssignments()\">\n <mat-icon>refresh</mat-icon>\n {{ t('COMMON.REFRESH', 'Refresh') }}\n </button>\n </mat-card-header>\n\n <mat-card-content>\n @if (errorMessage) {\n <div class=\"assigned-user-tasks-error\">\n {{ t('GLOWW.UNABLE_TO_QUERY', 'Unable to query') }}: {{ errorMessage }}\n </div>\n }\n\n @if (loading) {\n <div class=\"assigned-user-tasks-loading\">\n <mat-spinner diameter=\"36\"></mat-spinner>\n </div>\n }\n\n @if (!loading) {\n <div class=\"assigned-user-tasks-table-wrapper\">\n <table mat-table [dataSource]=\"dataSource\" matSort>\n <ng-container matColumnDef=\"action\">\n <th mat-header-cell *matHeaderCellDef></th>\n <td mat-cell *matCellDef=\"let obj\">\n <button\n mat-stroked-button\n color=\"primary\"\n type=\"button\"\n (click)=\"respondToTask(obj)\"\n [disabled]=\"!canRespond(obj) || respondingTaskId === (obj.UserTaskId ?? obj.IsCandidate?.USERTASKID)\">\n <i class=\"fal fa-reply\"></i>\n {{ t('GLOWW.RESPOND', 'Respond') }}\n </button>\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"task\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header=\"task\">{{ t('LISTS.TASK', 'Task') }}</th>\n <td mat-cell *matCellDef=\"let obj\">{{ getTaskLabel(obj) }}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"definition\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header=\"definition\">{{ t('LISTS.DEFINITION_ID', 'Definition ID') }}</th>\n <td mat-cell *matCellDef=\"let obj\">{{ getDefinitionLabel(obj) }}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"status\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header=\"status\">{{ t('LISTS.STATUS', 'Status') }}</th>\n <td mat-cell *matCellDef=\"let obj\">{{ getStatusLabel(obj) }}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"message\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header=\"message\">{{ t('LISTS.MESSAGE', 'Message') }}</th>\n <td mat-cell *matCellDef=\"let obj\">{{ obj.IsCandidate?.MESSAGE }}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"assignment\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header=\"assignment\">{{ t('LISTS.ASSIGNED_TO', 'Assigned to') }}</th>\n <td mat-cell *matCellDef=\"let obj\">{{ getAssignmentLabel(obj) }}</td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns\"></tr>\n </table>\n </div>\n\n @if (!dataSource.data.length) {\n <div class=\"assigned-user-tasks-empty\">\n {{ t('GLOWW.NO_ASSIGNED_TASKS', 'No task is currently assigned to you.') }}\n </div>\n }\n }\n </mat-card-content>\n\n <mat-card-actions>\n <mat-paginator [pageSize]=\"10\" [pageSizeOptions]=\"[10, 20, 50, 100]\" [showFirstLastButtons]=\"true\"></mat-paginator>\n </mat-card-actions>\n</mat-card>\n", styles: [":host{display:block}.assigned-user-tasks-card{margin:16px}.assigned-user-tasks-header{display:flex;align-items:center;justify-content:space-between;gap:12px;padding-bottom:12px}.assigned-user-tasks-loading,.assigned-user-tasks-empty,.assigned-user-tasks-error{padding:16px 0}.assigned-user-tasks-table-wrapper{overflow:auto}table{width:100%}th:first-child,td:first-child{width:140px;white-space:nowrap}button[mat-stroked-button]{min-width:110px}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i5$2.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i5$2.MatCardActions, selector: "mat-card-actions", inputs: ["align"], exportAs: ["matCardActions"] }, { kind: "directive", type: i5$2.MatCardContent, selector: "mat-card-content" }, { kind: "component", type: i5$2.MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: i5$2.MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i7$1.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i8$1.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatSortModule }, { kind: "directive", type: i9$1.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i9$1.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i10.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i10.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i10.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i10.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i10.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i10.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i10.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i10.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i10.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i10.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }] }); }
4295
4668
  }
4296
4669
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: AssignedUserTasksComponent, decorators: [{
4297
4670
  type: Component,
4298
4671
  args: [{ selector: 'glw-assigned-user-tasks', imports: [
4299
- RouterLink,
4300
- DatePipe,
4301
4672
  MatButtonModule,
4302
4673
  MatCardModule,
4303
4674
  MatIconModule,
4675
+ MatDialogModule,
4304
4676
  MatPaginatorModule,
4305
4677
  MatProgressSpinnerModule,
4306
4678
  MatSortModule,
4307
4679
  MatTableModule
4308
- ], template: "<mat-card class=\"assigned-user-tasks-card\" appearance=\"outlined\">\n <mat-card-header class=\"assigned-user-tasks-header\">\n <mat-card-title>{{ t('GLOWW.MY_ASSIGNED_TASKS', 'My assigned tasks') }}</mat-card-title>\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"loadAssignments()\">\n <mat-icon>refresh</mat-icon>\n {{ t('COMMON.REFRESH', 'Refresh') }}\n </button>\n </mat-card-header>\n\n <mat-card-content>\n @if (errorMessage) {\n <div class=\"assigned-user-tasks-error\">\n {{ t('GLOWW.UNABLE_TO_QUERY', 'Unable to query') }}: {{ errorMessage }}\n </div>\n }\n\n @if (loading) {\n <div class=\"assigned-user-tasks-loading\">\n <mat-spinner diameter=\"36\"></mat-spinner>\n </div>\n }\n\n @if (!loading) {\n <div class=\"assigned-user-tasks-table-wrapper\">\n <table mat-table [dataSource]=\"dataSource\" matSort>\n <ng-container matColumnDef=\"action\">\n <th mat-header-cell *matHeaderCellDef></th>\n <td mat-cell *matCellDef=\"let obj\">\n <button mat-icon-button type=\"button\" (click)=\"openExecution(obj)\" [disabled]=\"!hasExecution(obj)\" [attr.aria-label]=\"t('LISTS.DISPLAY', 'Display')\">\n <i class=\"fal fa-eye\"></i>\n </button>\n <button mat-icon-button type=\"button\" (click)=\"openExecutionSteps(obj)\" [disabled]=\"!hasExecution(obj)\" [attr.aria-label]=\"t('LISTS.STEPS', 'Steps')\">\n <i class=\"fal fa-list-check\"></i>\n </button>\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"task\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header=\"task\">{{ t('LISTS.TASK', 'Task') }}</th>\n <td mat-cell *matCellDef=\"let obj\">{{ getTaskLabel(obj) }}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"definition\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header=\"definition\">{{ t('LISTS.DEFINITION_ID', 'Definition ID') }}</th>\n <td mat-cell *matCellDef=\"let obj\">{{ getDefinitionLabel(obj) }}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"execution\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header=\"execution\">{{ t('LISTS.EXECUTION', 'Execution') }}</th>\n <td mat-cell *matCellDef=\"let obj\">{{ getExecutionLabel(obj) }}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"status\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header=\"status\">{{ t('LISTS.STATUS', 'Status') }}</th>\n <td mat-cell *matCellDef=\"let obj\">{{ getStatusLabel(obj) }}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"message\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header=\"message\">{{ t('LISTS.MESSAGE', 'Message') }}</th>\n <td mat-cell *matCellDef=\"let obj\">{{ obj.IsCandidate?.MESSAGE }}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"assignment\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header=\"assignment\">{{ t('LISTS.ASSIGNED_TO', 'Assigned to') }}</th>\n <td mat-cell *matCellDef=\"let obj\">{{ getAssignmentLabel(obj) }}</td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns\"></tr>\n </table>\n </div>\n\n @if (!dataSource.data.length) {\n <div class=\"assigned-user-tasks-empty\">\n {{ t('GLOWW.NO_ASSIGNED_TASKS', 'No task is currently assigned to you.') }}\n </div>\n }\n }\n </mat-card-content>\n\n <mat-card-actions>\n <mat-paginator [pageSize]=\"10\" [pageSizeOptions]=\"[10, 20, 50, 100]\" [showFirstLastButtons]=\"true\"></mat-paginator>\n </mat-card-actions>\n</mat-card>\n", styles: [":host{display:block}.assigned-user-tasks-card{margin:16px}.assigned-user-tasks-header{display:flex;align-items:center;justify-content:space-between;gap:12px;padding-bottom:12px}.assigned-user-tasks-loading,.assigned-user-tasks-empty,.assigned-user-tasks-error{padding:16px 0}.assigned-user-tasks-table-wrapper{overflow:auto}table{width:100%}th:first-child,td:first-child{width:88px;white-space:nowrap}button[mat-icon-button]{margin-right:4px}\n"] }]
4680
+ ], template: "<mat-card class=\"assigned-user-tasks-card\" appearance=\"outlined\">\n <mat-card-header class=\"assigned-user-tasks-header\">\n <mat-card-title>{{ t('GLOWW.MY_ASSIGNED_TASKS', 'My assigned tasks') }}</mat-card-title>\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"loadAssignments()\">\n <mat-icon>refresh</mat-icon>\n {{ t('COMMON.REFRESH', 'Refresh') }}\n </button>\n </mat-card-header>\n\n <mat-card-content>\n @if (errorMessage) {\n <div class=\"assigned-user-tasks-error\">\n {{ t('GLOWW.UNABLE_TO_QUERY', 'Unable to query') }}: {{ errorMessage }}\n </div>\n }\n\n @if (loading) {\n <div class=\"assigned-user-tasks-loading\">\n <mat-spinner diameter=\"36\"></mat-spinner>\n </div>\n }\n\n @if (!loading) {\n <div class=\"assigned-user-tasks-table-wrapper\">\n <table mat-table [dataSource]=\"dataSource\" matSort>\n <ng-container matColumnDef=\"action\">\n <th mat-header-cell *matHeaderCellDef></th>\n <td mat-cell *matCellDef=\"let obj\">\n <button\n mat-stroked-button\n color=\"primary\"\n type=\"button\"\n (click)=\"respondToTask(obj)\"\n [disabled]=\"!canRespond(obj) || respondingTaskId === (obj.UserTaskId ?? obj.IsCandidate?.USERTASKID)\">\n <i class=\"fal fa-reply\"></i>\n {{ t('GLOWW.RESPOND', 'Respond') }}\n </button>\n </td>\n </ng-container>\n\n <ng-container matColumnDef=\"task\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header=\"task\">{{ t('LISTS.TASK', 'Task') }}</th>\n <td mat-cell *matCellDef=\"let obj\">{{ getTaskLabel(obj) }}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"definition\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header=\"definition\">{{ t('LISTS.DEFINITION_ID', 'Definition ID') }}</th>\n <td mat-cell *matCellDef=\"let obj\">{{ getDefinitionLabel(obj) }}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"status\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header=\"status\">{{ t('LISTS.STATUS', 'Status') }}</th>\n <td mat-cell *matCellDef=\"let obj\">{{ getStatusLabel(obj) }}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"message\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header=\"message\">{{ t('LISTS.MESSAGE', 'Message') }}</th>\n <td mat-cell *matCellDef=\"let obj\">{{ obj.IsCandidate?.MESSAGE }}</td>\n </ng-container>\n\n <ng-container matColumnDef=\"assignment\">\n <th mat-header-cell *matHeaderCellDef mat-sort-header=\"assignment\">{{ t('LISTS.ASSIGNED_TO', 'Assigned to') }}</th>\n <td mat-cell *matCellDef=\"let obj\">{{ getAssignmentLabel(obj) }}</td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns\"></tr>\n </table>\n </div>\n\n @if (!dataSource.data.length) {\n <div class=\"assigned-user-tasks-empty\">\n {{ t('GLOWW.NO_ASSIGNED_TASKS', 'No task is currently assigned to you.') }}\n </div>\n }\n }\n </mat-card-content>\n\n <mat-card-actions>\n <mat-paginator [pageSize]=\"10\" [pageSizeOptions]=\"[10, 20, 50, 100]\" [showFirstLastButtons]=\"true\"></mat-paginator>\n </mat-card-actions>\n</mat-card>\n", styles: [":host{display:block}.assigned-user-tasks-card{margin:16px}.assigned-user-tasks-header{display:flex;align-items:center;justify-content:space-between;gap:12px;padding-bottom:12px}.assigned-user-tasks-loading,.assigned-user-tasks-empty,.assigned-user-tasks-error{padding:16px 0}.assigned-user-tasks-table-wrapper{overflow:auto}table{width:100%}th:first-child,td:first-child{width:140px;white-space:nowrap}button[mat-stroked-button]{min-width:110px}\n"] }]
4309
4681
  }], ctorParameters: () => [{ type: undefined, decorators: [{
4310
4682
  type: Inject,
4311
4683
  args: ['glowwService']
4312
- }] }, { type: AuthenticationService }, { type: GlowwI18nService }, { type: i2.Router }], propDecorators: { sort: [{
4684
+ }] }, { type: AuthenticationService }, { type: GlowwI18nService }, { type: i1$2.MatDialog }], propDecorators: { sort: [{
4313
4685
  type: ViewChild,
4314
4686
  args: [MatSort, { static: true }]
4315
4687
  }], paginator: [{