@yuuvis/client-framework 3.16.0 → 3.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/yuuvis-client-framework-actions.mjs +2 -6
- package/fesm2022/yuuvis-client-framework-actions.mjs.map +1 -1
- package/fesm2022/yuuvis-client-framework-badges.mjs +9 -2
- package/fesm2022/yuuvis-client-framework-badges.mjs.map +1 -1
- package/fesm2022/yuuvis-client-framework-forms.mjs +237 -129
- package/fesm2022/yuuvis-client-framework-forms.mjs.map +1 -1
- package/fesm2022/yuuvis-client-framework-metadata-form-defaults.mjs +1 -1
- package/fesm2022/yuuvis-client-framework-metadata-form-defaults.mjs.map +1 -1
- package/fesm2022/yuuvis-client-framework-object-relationship.mjs +47 -19
- package/fesm2022/yuuvis-client-framework-object-relationship.mjs.map +1 -1
- package/fesm2022/yuuvis-client-framework-renderer.mjs +48 -21
- package/fesm2022/yuuvis-client-framework-renderer.mjs.map +1 -1
- package/fesm2022/yuuvis-client-framework-sequence-list.mjs +1 -1
- package/fesm2022/yuuvis-client-framework-sequence-list.mjs.map +1 -1
- package/fesm2022/yuuvis-client-framework-tile-list.mjs +59 -65
- package/fesm2022/yuuvis-client-framework-tile-list.mjs.map +1 -1
- package/lib/assets/i18n/de.json +7 -6
- package/lib/assets/i18n/en.json +8 -7
- package/package.json +5 -5
- package/types/yuuvis-client-framework-badges.d.ts +7 -0
- package/types/yuuvis-client-framework-forms.d.ts +28 -8
- package/types/yuuvis-client-framework-object-relationship.d.ts +6 -1
- package/types/yuuvis-client-framework-tile-list.d.ts +13 -2
|
@@ -6,7 +6,7 @@ import { FormControl, Validators, ReactiveFormsModule, FormBuilder, NG_VALUE_ACC
|
|
|
6
6
|
import { MatFormFieldControl, MatFormFieldModule } from '@angular/material/form-field';
|
|
7
7
|
import * as i1 from '@angular/material/select';
|
|
8
8
|
import { MatSelectModule } from '@angular/material/select';
|
|
9
|
-
import { SystemService, TranslateService, Classification, TranslatePipe, Situation, Operator, OperatorLabel, Utils, CatalogService, LocaleNumberPipe, FileSizePipe, IdmService, UserService, SearchUtils, LocaleDatePipe, SearchService, DmsService, ObjectConfigService, DmsObject, BaseObjectTypeField, ClassificationPrefix } from '@yuuvis/client-core';
|
|
9
|
+
import { SystemService, TranslateService, Classification, TranslatePipe, Situation, Operator, OperatorLabel, Utils, CatalogService, LocaleNumberPipe, FileSizePipe, IdmService, UserService, AppCacheService, FREE_TEXT_OPTION, USER_ID_REGEX, STORAGE_ROLES_KEY, SearchUtils, LocaleDatePipe, SearchService, DmsService, ObjectConfigService, DmsObject, BaseObjectTypeField, ClassificationPrefix } from '@yuuvis/client-core';
|
|
10
10
|
import { AbstractMatFormField, injectNgControl, FormTranslateService, DialogComponent, ScrollButtonsComponent } from '@yuuvis/client-framework/common';
|
|
11
11
|
import * as i1$3 from '@angular/common';
|
|
12
12
|
import { NgClass, CommonModule } from '@angular/common';
|
|
@@ -32,9 +32,9 @@ import * as i2$1 from '@yuuvis/client-framework/datepicker';
|
|
|
32
32
|
import { DatepickerComponent, YuvDatepickerModule } from '@yuuvis/client-framework/datepicker';
|
|
33
33
|
import * as i2$2 from '@yuuvis/client-framework/autocomplete';
|
|
34
34
|
import { YuvAutocompleteModule } from '@yuuvis/client-framework/autocomplete';
|
|
35
|
-
import { map as map$1, catchError } from 'rxjs/operators';
|
|
36
|
-
import { ShellService } from '@yuuvis/client-shell-core';
|
|
37
35
|
import { ENTER, COMMA } from '@angular/cdk/keycodes';
|
|
36
|
+
import { map as map$1, switchMap, catchError } from 'rxjs/operators';
|
|
37
|
+
import { ShellService } from '@yuuvis/client-shell-core';
|
|
38
38
|
import * as i1$4 from '@angular/material/chips';
|
|
39
39
|
import { MatChipsModule } from '@angular/material/chips';
|
|
40
40
|
|
|
@@ -292,7 +292,6 @@ class DataGridComponent {
|
|
|
292
292
|
this.selectedRow = signal(null, ...(ngDevMode ? [{ debugName: "selectedRow" }] : /* istanbul ignore next */ []));
|
|
293
293
|
this.isRequired = false;
|
|
294
294
|
this.isInvalid = false;
|
|
295
|
-
this.initalTableUpdate = true;
|
|
296
295
|
this.icons = {
|
|
297
296
|
add: YUV_ICONS.add,
|
|
298
297
|
more: YUV_ICONS.more
|
|
@@ -310,38 +309,13 @@ class DataGridComponent {
|
|
|
310
309
|
computation: (readonly, previous) => readonly ? (previous?.value || []).filter((c) => c.columnDef !== 'actions') : previous?.value || [] });
|
|
311
310
|
this.#loadData = effect(() => {
|
|
312
311
|
const formElement = this.formElement();
|
|
313
|
-
|
|
314
|
-
// therefore we need to map them here for proper table rendering
|
|
315
|
-
if (formElement && formElement['columnDefinitions']) {
|
|
316
|
-
// map columnDefinitions to elements for table rendering
|
|
317
|
-
formElement['elements'] = formElement['columnDefinitions'].map((colDef) => ({
|
|
318
|
-
...colDef,
|
|
319
|
-
name: colDef.id,
|
|
320
|
-
label: this.#systemService.getLocalizedLabel(colDef.id) || colDef.id,
|
|
321
|
-
type: colDef.propertyType
|
|
322
|
-
}));
|
|
323
|
-
}
|
|
312
|
+
const elements = this.#resolveElements(formElement);
|
|
324
313
|
this.mappedFormElement.set(formElement);
|
|
325
|
-
const
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
data = data.map((row) => {
|
|
329
|
-
if (Array.isArray(row)) {
|
|
330
|
-
const obj = {};
|
|
331
|
-
for (let i = 0; i < columns.length; i++) {
|
|
332
|
-
obj[columns[i]] = row[i];
|
|
333
|
-
}
|
|
334
|
-
return obj;
|
|
335
|
-
}
|
|
336
|
-
return row;
|
|
337
|
-
});
|
|
314
|
+
const data = this.#toRowObjects(formElement ? formElement['value'] || [] : [], elements);
|
|
315
|
+
// rendering only — the value already lives in the form model, so a (re)bind
|
|
316
|
+
// of the formElement input must never propagate back or dirty the control
|
|
338
317
|
untracked(() => formElement && this.#updateTable(elements, data));
|
|
339
318
|
}, ...(ngDevMode ? [{ debugName: "#loadData" }] : /* istanbul ignore next */ []));
|
|
340
|
-
this.#sourceData = effect(() => {
|
|
341
|
-
const dataSource = this.dataSource();
|
|
342
|
-
!this.initalTableUpdate && this.writeValue(dataSource.filter((row) => !row.isAddRow));
|
|
343
|
-
this.initalTableUpdate = false;
|
|
344
|
-
}, ...(ngDevMode ? [{ debugName: "#sourceData" }] : /* istanbul ignore next */ []));
|
|
345
319
|
this.propagateChange = () => { };
|
|
346
320
|
this.onTouched = () => { };
|
|
347
321
|
}
|
|
@@ -349,7 +323,36 @@ class DataGridComponent {
|
|
|
349
323
|
#systemService;
|
|
350
324
|
#cdRef;
|
|
351
325
|
#loadData;
|
|
352
|
-
|
|
326
|
+
// if the form element is created from the ObjectTypeField it contains 'columnDefinitions' instead of 'elements'
|
|
327
|
+
// therefore we need to map them here for proper table rendering
|
|
328
|
+
#resolveElements(formElement) {
|
|
329
|
+
if (!formElement)
|
|
330
|
+
return [];
|
|
331
|
+
if (formElement['columnDefinitions']) {
|
|
332
|
+
formElement['elements'] = formElement['columnDefinitions'].map((colDef) => ({
|
|
333
|
+
...colDef,
|
|
334
|
+
name: colDef.id,
|
|
335
|
+
label: this.#systemService.getLocalizedLabel(colDef.id) || colDef.id,
|
|
336
|
+
type: colDef.propertyType
|
|
337
|
+
}));
|
|
338
|
+
}
|
|
339
|
+
return formElement['elements'] || [];
|
|
340
|
+
}
|
|
341
|
+
// table values may arrive as 2D arrays ([[a, b], ...]); map them to row objects
|
|
342
|
+
// keyed by the column names so the table can render them
|
|
343
|
+
#toRowObjects(data, elements) {
|
|
344
|
+
const columns = elements.map((e) => e.name || e.id);
|
|
345
|
+
return data.map((row) => {
|
|
346
|
+
if (Array.isArray(row)) {
|
|
347
|
+
const obj = {};
|
|
348
|
+
for (let i = 0; i < columns.length; i++) {
|
|
349
|
+
obj[columns[i]] = row[i];
|
|
350
|
+
}
|
|
351
|
+
return obj;
|
|
352
|
+
}
|
|
353
|
+
return row;
|
|
354
|
+
});
|
|
355
|
+
}
|
|
353
356
|
#openEditOverlay(elementData, adding = false) {
|
|
354
357
|
return this.#dialog
|
|
355
358
|
.open(EditTableDataComponent, {
|
|
@@ -378,7 +381,10 @@ class DataGridComponent {
|
|
|
378
381
|
if (result) {
|
|
379
382
|
const updatedData = this.dataSource().map((item) => JSON.stringify(item) === JSON.stringify(element) ? result : item);
|
|
380
383
|
const formElement = this.mappedFormElement();
|
|
381
|
-
|
|
384
|
+
if (formElement) {
|
|
385
|
+
this.#updateTable(formElement['elements'], [...updatedData]);
|
|
386
|
+
this.#propagateRows();
|
|
387
|
+
}
|
|
382
388
|
}
|
|
383
389
|
this.selectedRow.set(null);
|
|
384
390
|
});
|
|
@@ -390,14 +396,29 @@ class DataGridComponent {
|
|
|
390
396
|
if (result) {
|
|
391
397
|
data.push(result);
|
|
392
398
|
const formElement = this.mappedFormElement();
|
|
393
|
-
|
|
399
|
+
if (formElement) {
|
|
400
|
+
this.#updateTable(formElement['elements'], data);
|
|
401
|
+
this.#propagateRows();
|
|
402
|
+
}
|
|
394
403
|
}
|
|
395
404
|
});
|
|
396
405
|
}
|
|
397
406
|
removeRow(element) {
|
|
398
407
|
const updatedData = this.dataSource().filter((item) => JSON.stringify(item) !== JSON.stringify(element));
|
|
399
408
|
const formElement = this.mappedFormElement();
|
|
400
|
-
|
|
409
|
+
if (formElement) {
|
|
410
|
+
this.#updateTable(formElement['elements'], updatedData);
|
|
411
|
+
this.#propagateRows();
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* View → model, called from user-edit paths only (add/edit/remove row).
|
|
416
|
+
* The propagated value shape is the rendered one: an array of row objects
|
|
417
|
+
* keyed by column name ([{col1: a, col2: b}, ...]) — the same shape
|
|
418
|
+
* ObjectFormService.extractFormData() reads from the control.
|
|
419
|
+
*/
|
|
420
|
+
#propagateRows() {
|
|
421
|
+
this.propagateChange(this.dataSource().filter((row) => !row.isAddRow));
|
|
401
422
|
}
|
|
402
423
|
#updateTable(elements, data = []) {
|
|
403
424
|
if (elements.length > 0) {
|
|
@@ -425,8 +446,15 @@ class DataGridComponent {
|
|
|
425
446
|
this.displayedColumnsWithActions.set(displayedColumns);
|
|
426
447
|
this.dataSource.set(data);
|
|
427
448
|
}
|
|
449
|
+
/**
|
|
450
|
+
* Model → view only. Renders the incoming value (row objects or 2D arrays,
|
|
451
|
+
* which are converted via the column definitions) into the table. Never
|
|
452
|
+
* propagates back to the model — programmatic writes (setValue/patchValue/
|
|
453
|
+
* reset) and rebinds must not change the control's value or dirty state.
|
|
454
|
+
*/
|
|
428
455
|
writeValue(obj) {
|
|
429
|
-
this.
|
|
456
|
+
const elements = this.#resolveElements(this.formElement());
|
|
457
|
+
this.#updateTable(elements, this.#toRowObjects(Array.isArray(obj) ? obj : [], elements));
|
|
430
458
|
}
|
|
431
459
|
registerOnChange(fn) {
|
|
432
460
|
this.propagateChange = fn;
|
|
@@ -438,9 +466,6 @@ class DataGridComponent {
|
|
|
438
466
|
setDisabledState(isDisabled) {
|
|
439
467
|
// console.log('setDisabledState: ', isDisabled);
|
|
440
468
|
}
|
|
441
|
-
onValueChange(e) {
|
|
442
|
-
this.propagateChange(e);
|
|
443
|
-
}
|
|
444
469
|
validate(control) {
|
|
445
470
|
//Has to be delayed here because form init in object-form.component is also delayed
|
|
446
471
|
timer(300)
|
|
@@ -1598,28 +1623,28 @@ class OrganizationSetComponent extends AbstractMatFormField {
|
|
|
1598
1623
|
return undefined;
|
|
1599
1624
|
}
|
|
1600
1625
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: OrganizationSetComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
1601
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.20", type: OrganizationSetComponent, isStandalone: true, selector: "yuv-organization-set", inputs: { situation: { classPropertyName: "situation", publicName: "situation", isSignal: true, isRequired: false, transformFunction: null }, multiselect: { classPropertyName: "multiselect", publicName: "multiselect", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, withMetadata: { classPropertyName: "withMetadata", publicName: "withMetadata", isSignal: true, isRequired: false, transformFunction: null }, autocompleteMinLength: { classPropertyName: "autocompleteMinLength", publicName: "autocompleteMinLength", isSignal: true, isRequired: false, transformFunction: null }, classifications: { classPropertyName: "classifications", publicName: "classifications", isSignal: true, isRequired: false, transformFunction: null }, types: { classPropertyName: "types", publicName: "types", isSignal: true, isRequired: false, transformFunction: null } }, providers: [{ provide: MatFormFieldControl, useExisting: OrganizationSetComponent }], usesInheritance: true, ngImport: i0, template: "<yuv-autocomplete\n [busy]=\"busy()\"\n [formControl]=\"acFormControl\"\n #autocomplete\n [placeholder]=\"placeholder\"\n [disabled]=\"readonly()\"\n [autocompleteValues]=\"autocompleteRes\"\n [forceSelection]=\"true\"\n (autocompleteFnc)=\"autocompleteFn($event)\"\n [multiple]=\"true\"\n [maxItems]=\"multiselect() ? -1 : 1\"\n>\n <!-- template for item inside the dropdown -->\n <ng-template #optionTemplate let-item>\n <span class=\"chip\">{{ item.value.title }}</span>\n </ng-template>\n\n <!-- template for chip -->\n <ng-template #chipTemplate let-item>\n <span class=\"chip\">\n {{ item.value.title || '...' }}\n </span>\n </ng-template>\n</yuv-autocomplete>\n\n<mat-icon class=\"ymt-icon--size-s\" [matTooltip]=\"'yuv.form.element.organization-set.classify.icon.title' | translate\">\n {{ multiselect() ? 'group' : 'person' }}\n</mat-icon>\n", styles: [":host{display:flex;align-items:center}:host yuv-autocomplete{flex:1}:host mat-icon{color:var(--ymt-text-color-subtle)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "ngmodule", type: YuvAutocompleteModule }, { kind: "component", type: i2$2.AutocompleteComponent, selector: "yuv-autocomplete", inputs: ["ariaLabel", "busy", "multiple", "distinctValues", "addOnBlur", "minLength", "maxItems", "forceSelection", "autocompleteValues"], outputs: ["autocompleteFnc", "acBlur"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "pipe", type: TranslatePipe$1, name: "translate" }] }); }
|
|
1626
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.20", type: OrganizationSetComponent, isStandalone: true, selector: "yuv-organization-set", inputs: { situation: { classPropertyName: "situation", publicName: "situation", isSignal: true, isRequired: false, transformFunction: null }, multiselect: { classPropertyName: "multiselect", publicName: "multiselect", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, withMetadata: { classPropertyName: "withMetadata", publicName: "withMetadata", isSignal: true, isRequired: false, transformFunction: null }, autocompleteMinLength: { classPropertyName: "autocompleteMinLength", publicName: "autocompleteMinLength", isSignal: true, isRequired: false, transformFunction: null }, classifications: { classPropertyName: "classifications", publicName: "classifications", isSignal: true, isRequired: false, transformFunction: null }, types: { classPropertyName: "types", publicName: "types", isSignal: true, isRequired: false, transformFunction: null } }, providers: [{ provide: MatFormFieldControl, useExisting: OrganizationSetComponent }], usesInheritance: true, ngImport: i0, template: "<yuv-autocomplete\n [busy]=\"busy()\"\n [formControl]=\"acFormControl\"\n #autocomplete\n [placeholder]=\"placeholder\"\n [disabled]=\"readonly()\"\n [autocompleteValues]=\"autocompleteRes\"\n [forceSelection]=\"true\"\n (autocompleteFnc)=\"autocompleteFn($event)\"\n [multiple]=\"true\"\n [maxItems]=\"multiselect() ? -1 : 1\"\n>\n <!-- template for item inside the dropdown -->\n <ng-template #optionTemplate let-item>\n <span class=\"chip\">{{ item.value.title }}</span>\n </ng-template>\n\n <!-- template for chip -->\n <ng-template #chipTemplate let-item>\n <span class=\"chip\">\n {{ item.value.title || '...' }}\n </span>\n </ng-template>\n</yuv-autocomplete>\n\n<mat-icon class=\"ymt-icon--size-s\" [matTooltip]=\"'yuv.form.element.organization-set.classify.icon.title' | translate\">\n {{ multiselect() ? 'group' : 'person' }}\n</mat-icon>\n", styles: [":host{display:flex;align-items:center}:host yuv-autocomplete{flex:1}:host mat-icon{color:var(--ymt-text-color-subtle)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "ngmodule", type: YuvAutocompleteModule }, { kind: "component", type: i2$2.AutocompleteComponent, selector: "yuv-autocomplete", inputs: ["ariaLabel", "busy", "multiple", "distinctValues", "addOnBlur", "minLength", "maxItems", "forceSelection", "separatorKeys", "autocompleteValues"], outputs: ["autocompleteFnc", "acBlur"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "pipe", type: TranslatePipe$1, name: "translate" }] }); }
|
|
1602
1627
|
}
|
|
1603
1628
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: OrganizationSetComponent, decorators: [{
|
|
1604
1629
|
type: Component,
|
|
1605
1630
|
args: [{ selector: 'yuv-organization-set', imports: [FormsModule, YuvAutocompleteModule, MatTooltipModule, MatIconModule, ReactiveFormsModule, TranslatePipe$1], providers: [{ provide: MatFormFieldControl, useExisting: OrganizationSetComponent }], template: "<yuv-autocomplete\n [busy]=\"busy()\"\n [formControl]=\"acFormControl\"\n #autocomplete\n [placeholder]=\"placeholder\"\n [disabled]=\"readonly()\"\n [autocompleteValues]=\"autocompleteRes\"\n [forceSelection]=\"true\"\n (autocompleteFnc)=\"autocompleteFn($event)\"\n [multiple]=\"true\"\n [maxItems]=\"multiselect() ? -1 : 1\"\n>\n <!-- template for item inside the dropdown -->\n <ng-template #optionTemplate let-item>\n <span class=\"chip\">{{ item.value.title }}</span>\n </ng-template>\n\n <!-- template for chip -->\n <ng-template #chipTemplate let-item>\n <span class=\"chip\">\n {{ item.value.title || '...' }}\n </span>\n </ng-template>\n</yuv-autocomplete>\n\n<mat-icon class=\"ymt-icon--size-s\" [matTooltip]=\"'yuv.form.element.organization-set.classify.icon.title' | translate\">\n {{ multiselect() ? 'group' : 'person' }}\n</mat-icon>\n", styles: [":host{display:flex;align-items:center}:host yuv-autocomplete{flex:1}:host mat-icon{color:var(--ymt-text-color-subtle)}\n"] }]
|
|
1606
1631
|
}], propDecorators: { situation: [{ type: i0.Input, args: [{ isSignal: true, alias: "situation", required: false }] }], multiselect: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiselect", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], withMetadata: [{ type: i0.Input, args: [{ isSignal: true, alias: "withMetadata", required: false }] }], autocompleteMinLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "autocompleteMinLength", required: false }] }], classifications: [{ type: i0.Input, args: [{ isSignal: true, alias: "classifications", required: false }] }], types: [{ type: i0.Input, args: [{ isSignal: true, alias: "types", required: false }] }] } });
|
|
1607
1632
|
|
|
1608
|
-
const mapOrganizationNode = (innerValue) => map$1((
|
|
1609
|
-
.filter((
|
|
1610
|
-
.map((
|
|
1611
|
-
label:
|
|
1633
|
+
const mapOrganizationNode = (innerValue) => map$1((nodes) => nodes
|
|
1634
|
+
.filter((node) => !innerValue?.some((value) => value?.id === node.id))
|
|
1635
|
+
.map((node) => ({
|
|
1636
|
+
label: node.title,
|
|
1612
1637
|
value: {
|
|
1613
|
-
id:
|
|
1614
|
-
title:
|
|
1615
|
-
type: 'user' in
|
|
1638
|
+
id: node.id,
|
|
1639
|
+
title: node.title,
|
|
1640
|
+
type: 'user' in node ? 'user' : 'role'
|
|
1616
1641
|
}
|
|
1617
1642
|
})));
|
|
1618
1643
|
/**
|
|
1619
1644
|
* Creates form input for organization values.
|
|
1620
1645
|
*
|
|
1621
1646
|
* @example
|
|
1622
|
-
* <yuv-organization [multiselect]="true"
|
|
1647
|
+
* <yuv-organization [multiselect]="true" />
|
|
1623
1648
|
*/
|
|
1624
1649
|
class OrganizationComponent extends AbstractMatFormField {
|
|
1625
1650
|
constructor() {
|
|
@@ -1627,16 +1652,24 @@ class OrganizationComponent extends AbstractMatFormField {
|
|
|
1627
1652
|
this.#system = inject(SystemService);
|
|
1628
1653
|
this.#idmService = inject(IdmService);
|
|
1629
1654
|
this.#userService = inject(UserService);
|
|
1655
|
+
this.#appCache = inject(AppCacheService);
|
|
1630
1656
|
this.#dRef = inject(DestroyRef);
|
|
1631
1657
|
this.translate = inject(TranslateService);
|
|
1632
1658
|
this.minLength = 2;
|
|
1633
1659
|
this.busy = signal(false, ...(ngDevMode ? [{ debugName: "busy" }] : /* istanbul ignore next */ []));
|
|
1660
|
+
/**
|
|
1661
|
+
* ENTER only — organization titles contain commas (`Lastname, Firstname (username)`),
|
|
1662
|
+
* so committing free text on COMMA would split a typed name into two chips.
|
|
1663
|
+
*/
|
|
1664
|
+
this.separatorKeys = [ENTER];
|
|
1634
1665
|
this.acFormControl = new FormControl(undefined);
|
|
1635
1666
|
this.ngControl = injectNgControl(this);
|
|
1636
1667
|
this._innerValue = [];
|
|
1637
1668
|
this.autocompleteRes = [];
|
|
1638
1669
|
/**
|
|
1639
|
-
* Possibles values are `EDIT` (default),`SEARCH`,`CREATE`.
|
|
1670
|
+
* Possibles values are `EDIT` (default),`SEARCH`,`CREATE`.
|
|
1671
|
+
* In search situation validation of the form element will be turned off,
|
|
1672
|
+
* so you are able to enter search terms that do not meet the elements validators.
|
|
1640
1673
|
*/
|
|
1641
1674
|
this.situation = input(undefined, ...(ngDevMode ? [{ debugName: "situation" }] : /* istanbul ignore next */ []));
|
|
1642
1675
|
/**
|
|
@@ -1648,9 +1681,9 @@ class OrganizationComponent extends AbstractMatFormField {
|
|
|
1648
1681
|
*/
|
|
1649
1682
|
// #organizationType: Classification = Classification.STRING_ORGANIZATION;
|
|
1650
1683
|
this.#organizationType = computed(() => {
|
|
1651
|
-
const
|
|
1652
|
-
if (
|
|
1653
|
-
const classifications = this.#system.getClassifications(
|
|
1684
|
+
const classificationsInput = this.classifications();
|
|
1685
|
+
if (classificationsInput?.length) {
|
|
1686
|
+
const classifications = this.#system.getClassifications(classificationsInput);
|
|
1654
1687
|
if (classifications.has(Classification.STRING_ORGANIZATION_SET)) {
|
|
1655
1688
|
return Classification.STRING_ORGANIZATION_SET;
|
|
1656
1689
|
}
|
|
@@ -1658,20 +1691,26 @@ class OrganizationComponent extends AbstractMatFormField {
|
|
|
1658
1691
|
return Classification.STRING_ORGANIZATION;
|
|
1659
1692
|
}, ...(ngDevMode ? [{ debugName: "#organizationType" }] : /* istanbul ignore next */ []));
|
|
1660
1693
|
this.classifications = input(undefined, ...(ngDevMode ? [{ debugName: "classifications" }] : /* istanbul ignore next */ []));
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1694
|
+
/**
|
|
1695
|
+
* Options of the organization classification, e.g. `['user', 'role']` for
|
|
1696
|
+
* `id:organization:set[user,role]`.
|
|
1697
|
+
*/
|
|
1698
|
+
this.#classificationOptions = computed(() => {
|
|
1699
|
+
const orgaType = this.#organizationType();
|
|
1700
|
+
const classificationsInput = this.classifications();
|
|
1701
|
+
if (classificationsInput?.length) {
|
|
1702
|
+
const classifications = this.#system.getClassifications(classificationsInput);
|
|
1703
|
+
if (orgaType === Classification.STRING_ORGANIZATION) {
|
|
1667
1704
|
return classifications.get(Classification.STRING_ORGANIZATION).options;
|
|
1668
1705
|
}
|
|
1669
|
-
else if (
|
|
1706
|
+
else if (orgaType === Classification.STRING_ORGANIZATION_SET) {
|
|
1670
1707
|
return classifications.get(Classification.STRING_ORGANIZATION_SET).options;
|
|
1671
1708
|
}
|
|
1672
1709
|
}
|
|
1673
1710
|
return [];
|
|
1674
|
-
}, ...(ngDevMode ? [{ debugName: "#
|
|
1711
|
+
}, ...(ngDevMode ? [{ debugName: "#classificationOptions" }] : /* istanbul ignore next */ []));
|
|
1712
|
+
// The free text option is not a role — it must not end up in the /idm/users role filter.
|
|
1713
|
+
this.#filterRoles = computed(() => this.#classificationOptions().filter((opt) => opt !== FREE_TEXT_OPTION), ...(ngDevMode ? [{ debugName: "#filterRoles" }] : /* istanbul ignore next */ []));
|
|
1675
1714
|
/**
|
|
1676
1715
|
* Will prevent the input from being changed (default: false)
|
|
1677
1716
|
*/
|
|
@@ -1685,15 +1724,23 @@ class OrganizationComponent extends AbstractMatFormField {
|
|
|
1685
1724
|
* or, if set to false only the ID
|
|
1686
1725
|
*/
|
|
1687
1726
|
this.withMetadata = input(false, ...(ngDevMode ? [{ debugName: "withMetadata" }] : /* istanbul ignore next */ []));
|
|
1727
|
+
/**
|
|
1728
|
+
* Whether or not values that the autocomplete cannot resolve may be entered as free
|
|
1729
|
+
* text (default: false). Can also be enabled per field through the `freeText` option
|
|
1730
|
+
* of the organization classification, e.g. `id:organization[freeText]`.
|
|
1731
|
+
*/
|
|
1732
|
+
this.allowFreeText = input(false, ...(ngDevMode ? [{ debugName: "allowFreeText" }] : /* istanbul ignore next */ []));
|
|
1733
|
+
this.freeText = computed(() => this.allowFreeText() || this.#classificationOptions().includes(FREE_TEXT_OPTION), ...(ngDevMode ? [{ debugName: "freeText" }] : /* istanbul ignore next */ []));
|
|
1688
1734
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
1689
1735
|
this.propagateChange = (_) => { };
|
|
1690
1736
|
}
|
|
1691
1737
|
#system;
|
|
1692
1738
|
#idmService;
|
|
1693
1739
|
#userService;
|
|
1740
|
+
#appCache;
|
|
1694
1741
|
#dRef;
|
|
1695
|
-
set innerValue(
|
|
1696
|
-
this._innerValue =
|
|
1742
|
+
set innerValue(iValue) {
|
|
1743
|
+
this._innerValue = iValue || [];
|
|
1697
1744
|
}
|
|
1698
1745
|
get innerValue() {
|
|
1699
1746
|
return this._innerValue;
|
|
@@ -1703,6 +1750,12 @@ class OrganizationComponent extends AbstractMatFormField {
|
|
|
1703
1750
|
*/
|
|
1704
1751
|
// #organizationType: Classification = Classification.STRING_ORGANIZATION;
|
|
1705
1752
|
#organizationType;
|
|
1753
|
+
/**
|
|
1754
|
+
* Options of the organization classification, e.g. `['user', 'role']` for
|
|
1755
|
+
* `id:organization:set[user,role]`.
|
|
1756
|
+
*/
|
|
1757
|
+
#classificationOptions;
|
|
1758
|
+
// The free text option is not a role — it must not end up in the /idm/users role filter.
|
|
1706
1759
|
#filterRoles;
|
|
1707
1760
|
writeValue(value) {
|
|
1708
1761
|
this.value = value;
|
|
@@ -1725,10 +1778,6 @@ class OrganizationComponent extends AbstractMatFormField {
|
|
|
1725
1778
|
}
|
|
1726
1779
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
1727
1780
|
registerOnTouched(fn) { }
|
|
1728
|
-
propagate() {
|
|
1729
|
-
this.value = this.#getPropagateValue();
|
|
1730
|
-
this.propagateChange(this.value);
|
|
1731
|
-
}
|
|
1732
1781
|
setDisabledState(isDisabled) {
|
|
1733
1782
|
if (isDisabled) {
|
|
1734
1783
|
this.acFormControl.disable();
|
|
@@ -1738,65 +1787,16 @@ class OrganizationComponent extends AbstractMatFormField {
|
|
|
1738
1787
|
}
|
|
1739
1788
|
this.disabled = isDisabled;
|
|
1740
1789
|
}
|
|
1741
|
-
#getPropagateValue() {
|
|
1742
|
-
const value = this.innerValue.map((v) => this.withMetadata() ? JSON.stringify({ id: v.id, title: v.title, type: v.type }) : v.id);
|
|
1743
|
-
return this.multiselect() ? value : value[0];
|
|
1744
|
-
}
|
|
1745
1790
|
resolveFn(value) {
|
|
1746
|
-
//
|
|
1747
|
-
|
|
1748
|
-
const
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
id: res.id,
|
|
1753
|
-
title: res.title,
|
|
1754
|
-
type: 'user'
|
|
1755
|
-
}
|
|
1756
|
-
: {
|
|
1757
|
-
id: v,
|
|
1758
|
-
title: v,
|
|
1759
|
-
type: 'user',
|
|
1760
|
-
notFound: true
|
|
1761
|
-
};
|
|
1762
|
-
}))
|
|
1763
|
-
: of({
|
|
1764
|
-
id: v,
|
|
1765
|
-
title: v,
|
|
1766
|
-
type: 'role'
|
|
1767
|
-
}));
|
|
1768
|
-
forkJoin(tasks).subscribe((data) => {
|
|
1791
|
+
// Free text and role names are both plain strings on the wire, so telling them apart
|
|
1792
|
+
// requires the role catalog. Only load it when free text is actually enabled.
|
|
1793
|
+
const roleNames$ = this.freeText() ? this.#roleNames() : of(null);
|
|
1794
|
+
roleNames$
|
|
1795
|
+
.pipe(switchMap((roleNames) => forkJoin(value.map((v) => this.#resolveEntry(v, roleNames)))), takeUntilDestroyed(this.#dRef))
|
|
1796
|
+
.subscribe((data) => {
|
|
1769
1797
|
this.#updateAutocompleteControl(data);
|
|
1770
1798
|
});
|
|
1771
1799
|
}
|
|
1772
|
-
#updateAutocompleteControl(data) {
|
|
1773
|
-
this.innerValue = data;
|
|
1774
|
-
const mapped = this.innerValue.map((n) => ({
|
|
1775
|
-
label: n.title,
|
|
1776
|
-
value: n
|
|
1777
|
-
}));
|
|
1778
|
-
this.acFormControl.setValue(this.multiselect() ? mapped : [mapped[0]], { emitEvent: false });
|
|
1779
|
-
this.acFormControl.updateValueAndValidity({ emitEvent: false });
|
|
1780
|
-
}
|
|
1781
|
-
#resolveOrganization(query, excludeMe, filterRoles) {
|
|
1782
|
-
return this.#userService.queryUser(query, excludeMe, filterRoles).pipe(mapOrganizationNode(this.innerValue), catchError(() => of([])));
|
|
1783
|
-
}
|
|
1784
|
-
#resolveOrganizationSet(query, filterRoles) {
|
|
1785
|
-
return this.#idmService.queryOrganizationEntity(query, filterRoles).pipe(mapOrganizationNode(this.innerValue), catchError(() => of([])));
|
|
1786
|
-
}
|
|
1787
|
-
#getMetadataString(value) {
|
|
1788
|
-
try {
|
|
1789
|
-
if (Array.isArray(value)) {
|
|
1790
|
-
return value.map((v) => JSON.parse(v));
|
|
1791
|
-
}
|
|
1792
|
-
else {
|
|
1793
|
-
return JSON.parse(value);
|
|
1794
|
-
}
|
|
1795
|
-
}
|
|
1796
|
-
catch (e) {
|
|
1797
|
-
return undefined;
|
|
1798
|
-
}
|
|
1799
|
-
}
|
|
1800
1800
|
autocompleteFn(query) {
|
|
1801
1801
|
if (query.length >= this.minLength) {
|
|
1802
1802
|
this.busy.set(true);
|
|
@@ -1824,18 +1824,126 @@ class OrganizationComponent extends AbstractMatFormField {
|
|
|
1824
1824
|
}
|
|
1825
1825
|
});
|
|
1826
1826
|
this.acFormControl.updateValueAndValidity({ emitEvent: false });
|
|
1827
|
-
this.acFormControl.valueChanges.subscribe((v) => {
|
|
1827
|
+
this.acFormControl.valueChanges.pipe(takeUntilDestroyed(this.#dRef)).subscribe((v) => {
|
|
1828
1828
|
if (!Array.isArray(v))
|
|
1829
1829
|
v = v ? [v] : [];
|
|
1830
|
-
this.innerValue = v.map((i) => i
|
|
1830
|
+
this.innerValue = v.map((i) => this.#toNode(i));
|
|
1831
1831
|
this.propagate();
|
|
1832
1832
|
});
|
|
1833
1833
|
}
|
|
1834
1834
|
ngOnDestroy() {
|
|
1835
1835
|
super.onNgOnDestroy();
|
|
1836
1836
|
}
|
|
1837
|
+
#resolveEntry(value, roleNames) {
|
|
1838
|
+
// check if entry is a user
|
|
1839
|
+
if (USER_ID_REGEX.test(value)) {
|
|
1840
|
+
return this.#idmService.getUserById(value).pipe(map$1((res) => {
|
|
1841
|
+
return res
|
|
1842
|
+
? {
|
|
1843
|
+
id: res.id,
|
|
1844
|
+
title: res.title,
|
|
1845
|
+
type: 'user'
|
|
1846
|
+
}
|
|
1847
|
+
: {
|
|
1848
|
+
id: value,
|
|
1849
|
+
title: value,
|
|
1850
|
+
type: 'user',
|
|
1851
|
+
notFound: true
|
|
1852
|
+
};
|
|
1853
|
+
}));
|
|
1854
|
+
}
|
|
1855
|
+
// Roles are a closed set, so a value the catalog does not know can only have been typed.
|
|
1856
|
+
if (roleNames && !roleNames.includes(value)) {
|
|
1857
|
+
return of({
|
|
1858
|
+
id: value,
|
|
1859
|
+
title: value,
|
|
1860
|
+
type: 'text'
|
|
1861
|
+
});
|
|
1862
|
+
}
|
|
1863
|
+
return of({
|
|
1864
|
+
id: value,
|
|
1865
|
+
title: value,
|
|
1866
|
+
type: 'role'
|
|
1867
|
+
});
|
|
1868
|
+
}
|
|
1869
|
+
/**
|
|
1870
|
+
* Role names from the shared cache, falling back to IDM. Mirrors the organization
|
|
1871
|
+
* renderer so both sides partition stored values identically and share one request.
|
|
1872
|
+
*/
|
|
1873
|
+
#roleNames() {
|
|
1874
|
+
return this.#appCache.getItem(STORAGE_ROLES_KEY).pipe(switchMap((cachedRoles) => cachedRoles
|
|
1875
|
+
? of(cachedRoles)
|
|
1876
|
+
: this.#idmService.getRoles().pipe(
|
|
1877
|
+
// Only persist when the backend actually returned something — caching an
|
|
1878
|
+
// empty array would mask later successful fetches.
|
|
1879
|
+
switchMap((roles) => roles.length ? this.#appCache.setItem(STORAGE_ROLES_KEY, roles).pipe(map$1(() => roles)) : of(roles)))), map$1((roles) => roles.map((role) => role.name)), catchError(() => of([])));
|
|
1880
|
+
}
|
|
1881
|
+
#getPropagateValue() {
|
|
1882
|
+
const value = this.innerValue.map((v) => this.withMetadata()
|
|
1883
|
+
? // `text` is a client-side distinction only — the stored value stays a plain string and
|
|
1884
|
+
// the metadata `type` keeps its existing vocabulary, so no consumer sees a new value.
|
|
1885
|
+
// Trade-off: in metadata mode free text is not marked as such again after a reload.
|
|
1886
|
+
JSON.stringify({ id: v.id, title: v.title, type: v.type === 'text' ? 'role' : v.type })
|
|
1887
|
+
: v.id);
|
|
1888
|
+
return this.multiselect() ? value : value[0];
|
|
1889
|
+
}
|
|
1890
|
+
/**
|
|
1891
|
+
* The autocomplete emits free text as a raw string instead of a node, so it has to be
|
|
1892
|
+
* lifted back into an {@link OrganizationNode} before it reaches the form control value.
|
|
1893
|
+
*/
|
|
1894
|
+
#toNode(item) {
|
|
1895
|
+
return typeof item.value === 'string'
|
|
1896
|
+
? { id: item.value, title: item.value, type: 'text' }
|
|
1897
|
+
: item.value;
|
|
1898
|
+
}
|
|
1899
|
+
#updateAutocompleteControl(data) {
|
|
1900
|
+
this.innerValue = data;
|
|
1901
|
+
const freeTextHint = this.translate.instant('yuv.form.element.organization.freetext.tooltip');
|
|
1902
|
+
const mapped = this.innerValue.map((iVal) => ({
|
|
1903
|
+
label: iVal.title,
|
|
1904
|
+
value: iVal,
|
|
1905
|
+
// Marks stored free text as such again, so the chip looks the same before and after reload.
|
|
1906
|
+
custom: iVal.type === 'text',
|
|
1907
|
+
hint: iVal.type === 'text' ? freeTextHint : undefined
|
|
1908
|
+
}));
|
|
1909
|
+
this.acFormControl.setValue(this.multiselect() ? mapped : [mapped[0]], { emitEvent: false });
|
|
1910
|
+
this.acFormControl.updateValueAndValidity({ emitEvent: false });
|
|
1911
|
+
}
|
|
1912
|
+
#resolveOrganization(query, excludeMe, filterRoles) {
|
|
1913
|
+
return this.#userService.queryUser(query, excludeMe, filterRoles).pipe(mapOrganizationNode(this.innerValue), catchError(() => of([])));
|
|
1914
|
+
}
|
|
1915
|
+
#resolveOrganizationSet(query, filterRoles) {
|
|
1916
|
+
return this.#idmService.queryOrganizationEntity(query, filterRoles).pipe(mapOrganizationNode(this.innerValue), catchError(() => of([])));
|
|
1917
|
+
}
|
|
1918
|
+
#getMetadataString(value) {
|
|
1919
|
+
try {
|
|
1920
|
+
if (Array.isArray(value)) {
|
|
1921
|
+
const parsed = value.map((val) => JSON.parse(val));
|
|
1922
|
+
return parsed.every((entry) => this.#isMetadata(entry)) ? parsed : undefined;
|
|
1923
|
+
}
|
|
1924
|
+
else {
|
|
1925
|
+
const parsed = JSON.parse(value);
|
|
1926
|
+
return this.#isMetadata(parsed) ? parsed : undefined;
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
catch (error) {
|
|
1930
|
+
return undefined;
|
|
1931
|
+
}
|
|
1932
|
+
}
|
|
1933
|
+
/**
|
|
1934
|
+
* Guards against plain values that happen to be valid JSON — free text like `42`, `true`
|
|
1935
|
+
* or `[1,2]` would otherwise be mistaken for metadata and yield a chip without id/title.
|
|
1936
|
+
* Deliberately permissive about the id's runtime type so real metadata is never rejected.
|
|
1937
|
+
*/
|
|
1938
|
+
#isMetadata(parsed) {
|
|
1939
|
+
return !!parsed && typeof parsed === 'object' && !Array.isArray(parsed) && 'id' in parsed;
|
|
1940
|
+
}
|
|
1941
|
+
propagate() {
|
|
1942
|
+
this.value = this.#getPropagateValue();
|
|
1943
|
+
this.propagateChange(this.value);
|
|
1944
|
+
}
|
|
1837
1945
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: OrganizationComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
1838
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: OrganizationComponent, isStandalone: true, selector: "yuv-organization", inputs: { situation: { classPropertyName: "situation", publicName: "situation", isSignal: true, isRequired: false, transformFunction: null }, multiselect: { classPropertyName: "multiselect", publicName: "multiselect", isSignal: true, isRequired: false, transformFunction: null }, classifications: { classPropertyName: "classifications", publicName: "classifications", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, excludeMe: { classPropertyName: "excludeMe", publicName: "excludeMe", isSignal: true, isRequired: false, transformFunction: null }, withMetadata: { classPropertyName: "withMetadata", publicName: "withMetadata", isSignal: true, isRequired: false, transformFunction: null } }, providers: [{ provide: MatFormFieldControl, useExisting: OrganizationComponent }], usesInheritance: true, ngImport: i0, template: "<yuv-autocomplete\n [required]=\"required\"\n [busy]=\"busy()\"\n [formControl]=\"acFormControl\"\n #autocomplete\n [placeholder]=\"placeholder\"\n [disabled]=\"readonly()\"\n [autocompleteValues]=\"autocompleteRes\"\n [forceSelection]=\"
|
|
1946
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: OrganizationComponent, isStandalone: true, selector: "yuv-organization", inputs: { situation: { classPropertyName: "situation", publicName: "situation", isSignal: true, isRequired: false, transformFunction: null }, multiselect: { classPropertyName: "multiselect", publicName: "multiselect", isSignal: true, isRequired: false, transformFunction: null }, classifications: { classPropertyName: "classifications", publicName: "classifications", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, excludeMe: { classPropertyName: "excludeMe", publicName: "excludeMe", isSignal: true, isRequired: false, transformFunction: null }, withMetadata: { classPropertyName: "withMetadata", publicName: "withMetadata", isSignal: true, isRequired: false, transformFunction: null }, allowFreeText: { classPropertyName: "allowFreeText", publicName: "allowFreeText", isSignal: true, isRequired: false, transformFunction: null } }, providers: [{ provide: MatFormFieldControl, useExisting: OrganizationComponent }], usesInheritance: true, ngImport: i0, template: "<yuv-autocomplete\n [required]=\"required\"\n [busy]=\"busy()\"\n [formControl]=\"acFormControl\"\n #autocomplete\n [placeholder]=\"placeholder\"\n [disabled]=\"readonly()\"\n [autocompleteValues]=\"autocompleteRes\"\n [forceSelection]=\"!freeText()\"\n [distinctValues]=\"true\"\n [separatorKeys]=\"separatorKeys\"\n (autocompleteFnc)=\"autocompleteFn($event)\"\n [multiple]=\"true\"\n [maxItems]=\"multiselect() ? -1 : 1\"\n>\n <!-- template for item inside the dropdown -->\n <ng-template #optionTemplate let-item>\n @if (item.value) {\n <span class=\"chip\">{{ item.value.title }}</span>\n }\n </ng-template>\n\n <!-- template for chip -->\n <ng-template #chipTemplate let-item>\n @if (item.value) {\n <span class=\"chip\" [ngClass]=\"{ notFound: item.value.notFound }\" [matTooltip]=\"item.value.titleString\">\n {{ item.value.title || '...' }}\n </span>\n }\n </ng-template>\n</yuv-autocomplete>\n\n<mat-icon class=\"ymt-icon--size-s\" [matTooltip]=\"'yuv.form.element.organization.classify.icon.title' | translate\">\n {{ multiselect() ? 'group' : 'person' }}\n</mat-icon>\n", styles: [":host{display:flex;align-items:center}:host .chip.notFound{color:var(--ymt-on-danger-container);text-decoration:line-through}:host .chip.notFound:before{content:\"!\";display:inline-block;background-color:var(--ymt-danger-container);color:#fff;border-radius:2px;padding-inline:.3em;text-decoration:none;margin-inline-end:.75em}:host yuv-autocomplete{flex:1}:host mat-icon{color:var(--ymt-text-color-subtle)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "ngmodule", type: YuvAutocompleteModule }, { kind: "component", type: i2$2.AutocompleteComponent, selector: "yuv-autocomplete", inputs: ["ariaLabel", "busy", "multiple", "distinctValues", "addOnBlur", "minLength", "maxItems", "forceSelection", "separatorKeys", "autocompleteValues"], outputs: ["autocompleteFnc", "acBlur"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
|
|
1839
1947
|
}
|
|
1840
1948
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: OrganizationComponent, decorators: [{
|
|
1841
1949
|
type: Component,
|
|
@@ -1847,8 +1955,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImpo
|
|
|
1847
1955
|
MatIconModule,
|
|
1848
1956
|
ReactiveFormsModule,
|
|
1849
1957
|
TranslatePipe
|
|
1850
|
-
], providers: [{ provide: MatFormFieldControl, useExisting: OrganizationComponent }], template: "<yuv-autocomplete\n [required]=\"required\"\n [busy]=\"busy()\"\n [formControl]=\"acFormControl\"\n #autocomplete\n [placeholder]=\"placeholder\"\n [disabled]=\"readonly()\"\n [autocompleteValues]=\"autocompleteRes\"\n [forceSelection]=\"
|
|
1851
|
-
}], propDecorators: { situation: [{ type: i0.Input, args: [{ isSignal: true, alias: "situation", required: false }] }], multiselect: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiselect", required: false }] }], classifications: [{ type: i0.Input, args: [{ isSignal: true, alias: "classifications", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], excludeMe: [{ type: i0.Input, args: [{ isSignal: true, alias: "excludeMe", required: false }] }], withMetadata: [{ type: i0.Input, args: [{ isSignal: true, alias: "withMetadata", required: false }] }] } });
|
|
1958
|
+
], providers: [{ provide: MatFormFieldControl, useExisting: OrganizationComponent }], template: "<yuv-autocomplete\n [required]=\"required\"\n [busy]=\"busy()\"\n [formControl]=\"acFormControl\"\n #autocomplete\n [placeholder]=\"placeholder\"\n [disabled]=\"readonly()\"\n [autocompleteValues]=\"autocompleteRes\"\n [forceSelection]=\"!freeText()\"\n [distinctValues]=\"true\"\n [separatorKeys]=\"separatorKeys\"\n (autocompleteFnc)=\"autocompleteFn($event)\"\n [multiple]=\"true\"\n [maxItems]=\"multiselect() ? -1 : 1\"\n>\n <!-- template for item inside the dropdown -->\n <ng-template #optionTemplate let-item>\n @if (item.value) {\n <span class=\"chip\">{{ item.value.title }}</span>\n }\n </ng-template>\n\n <!-- template for chip -->\n <ng-template #chipTemplate let-item>\n @if (item.value) {\n <span class=\"chip\" [ngClass]=\"{ notFound: item.value.notFound }\" [matTooltip]=\"item.value.titleString\">\n {{ item.value.title || '...' }}\n </span>\n }\n </ng-template>\n</yuv-autocomplete>\n\n<mat-icon class=\"ymt-icon--size-s\" [matTooltip]=\"'yuv.form.element.organization.classify.icon.title' | translate\">\n {{ multiselect() ? 'group' : 'person' }}\n</mat-icon>\n", styles: [":host{display:flex;align-items:center}:host .chip.notFound{color:var(--ymt-on-danger-container);text-decoration:line-through}:host .chip.notFound:before{content:\"!\";display:inline-block;background-color:var(--ymt-danger-container);color:#fff;border-radius:2px;padding-inline:.3em;text-decoration:none;margin-inline-end:.75em}:host yuv-autocomplete{flex:1}:host mat-icon{color:var(--ymt-text-color-subtle)}\n"] }]
|
|
1959
|
+
}], propDecorators: { situation: [{ type: i0.Input, args: [{ isSignal: true, alias: "situation", required: false }] }], multiselect: [{ type: i0.Input, args: [{ isSignal: true, alias: "multiselect", required: false }] }], classifications: [{ type: i0.Input, args: [{ isSignal: true, alias: "classifications", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], excludeMe: [{ type: i0.Input, args: [{ isSignal: true, alias: "excludeMe", required: false }] }], withMetadata: [{ type: i0.Input, args: [{ isSignal: true, alias: "withMetadata", required: false }] }], allowFreeText: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowFreeText", required: false }] }] } });
|
|
1852
1960
|
|
|
1853
1961
|
class DateRangePickerComponent {
|
|
1854
1962
|
constructor() {
|
|
@@ -2402,7 +2510,7 @@ class ReferenceComponent extends AbstractMatFormField {
|
|
|
2402
2510
|
super.onNgOnDestroy();
|
|
2403
2511
|
}
|
|
2404
2512
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: ReferenceComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
2405
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: ReferenceComponent, isStandalone: true, selector: "yuv-reference", inputs: { situation: { classPropertyName: "situation", publicName: "situation", isSignal: true, isRequired: false, transformFunction: null }, multiselect: { classPropertyName: "multiselect", publicName: "multiselect", isSignal: true, isRequired: false, transformFunction: null }, classifications: { classPropertyName: "classifications", publicName: "classifications", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, minChars: { classPropertyName: "minChars", publicName: "minChars", isSignal: true, isRequired: false, transformFunction: null }, maxSuggestions: { classPropertyName: "maxSuggestions", publicName: "maxSuggestions", isSignal: true, isRequired: false, transformFunction: null } }, providers: [{ provide: MatFormFieldControl, useExisting: ReferenceComponent }], usesInheritance: true, ngImport: i0, template: "<yuv-autocomplete\n [required]=\"required\"\n [busy]=\"busy()\"\n [formControl]=\"acFormControl\"\n #autocomplete\n [placeholder]=\"placeholder\"\n [disabled]=\"readonly()\"\n [autocompleteValues]=\"autocompleteRes\"\n [minLength]=\"minChars()\"\n [forceSelection]=\"true\"\n [distinctValues]=\"true\"\n (autocompleteFnc)=\"autocompleteFn($event)\"\n [multiple]=\"true\"\n [maxItems]=\"multiselect() ? -1 : 1\"\n>\n <!-- template for item inside the dropdown -->\n <ng-template #optionTemplate let-item>\n @if (item.value) {\n <span class=\"option\">{{ item.value.title }}</span>\n }\n </ng-template>\n\n <!-- template for chip -->\n <ng-template #chipTemplate let-item>\n @if (item.value) {\n <span class=\"chip\" [class.notFound]=\"item.value.notFound\" [matTooltip]=\"item.value.title\">\n {{ item.value.title || '...' }}\n @if (canOpen(item.value)) {\n <mat-icon\n class=\"open ymt-icon--size-s\"\n (click)=\"open(item.value); $event.stopPropagation()\"\n [matTooltip]=\"'yuv.form.element.reference.open.title' | translate\"\n >\n open_in_new\n </mat-icon>\n }\n </span>\n }\n </ng-template>\n</yuv-autocomplete>\n\n<mat-icon class=\"ymt-icon--size-s\" [matTooltip]=\"'yuv.form.element.reference.classify.icon.title' | translate\">link</mat-icon>\n", styles: [":host{display:flex;align-items:center}:host .chip{display:inline-flex;align-items:center;gap:.25em}:host .chip .open{cursor:pointer;color:var(--ymt-text-color-subtle)}:host .chip .open:hover{color:var(--ymt-primary)}:host .chip.notFound{color:var(--ymt-on-danger-container);text-decoration:line-through}:host .chip.notFound:before{content:\"!\";display:inline-block;background-color:var(--ymt-danger-container);color:var(--ymt-on-danger-container);border-radius:2px;padding-inline:.3em;text-decoration:none;margin-inline-end:.75em}:host yuv-autocomplete{flex:1}:host mat-icon{color:var(--ymt-text-color-subtle)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: YuvAutocompleteModule }, { kind: "component", type: i2$2.AutocompleteComponent, selector: "yuv-autocomplete", inputs: ["ariaLabel", "busy", "multiple", "distinctValues", "addOnBlur", "minLength", "maxItems", "forceSelection", "autocompleteValues"], outputs: ["autocompleteFnc", "acBlur"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
2513
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.20", type: ReferenceComponent, isStandalone: true, selector: "yuv-reference", inputs: { situation: { classPropertyName: "situation", publicName: "situation", isSignal: true, isRequired: false, transformFunction: null }, multiselect: { classPropertyName: "multiselect", publicName: "multiselect", isSignal: true, isRequired: false, transformFunction: null }, classifications: { classPropertyName: "classifications", publicName: "classifications", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, minChars: { classPropertyName: "minChars", publicName: "minChars", isSignal: true, isRequired: false, transformFunction: null }, maxSuggestions: { classPropertyName: "maxSuggestions", publicName: "maxSuggestions", isSignal: true, isRequired: false, transformFunction: null } }, providers: [{ provide: MatFormFieldControl, useExisting: ReferenceComponent }], usesInheritance: true, ngImport: i0, template: "<yuv-autocomplete\n [required]=\"required\"\n [busy]=\"busy()\"\n [formControl]=\"acFormControl\"\n #autocomplete\n [placeholder]=\"placeholder\"\n [disabled]=\"readonly()\"\n [autocompleteValues]=\"autocompleteRes\"\n [minLength]=\"minChars()\"\n [forceSelection]=\"true\"\n [distinctValues]=\"true\"\n (autocompleteFnc)=\"autocompleteFn($event)\"\n [multiple]=\"true\"\n [maxItems]=\"multiselect() ? -1 : 1\"\n>\n <!-- template for item inside the dropdown -->\n <ng-template #optionTemplate let-item>\n @if (item.value) {\n <span class=\"option\">{{ item.value.title }}</span>\n }\n </ng-template>\n\n <!-- template for chip -->\n <ng-template #chipTemplate let-item>\n @if (item.value) {\n <span class=\"chip\" [class.notFound]=\"item.value.notFound\" [matTooltip]=\"item.value.title\">\n {{ item.value.title || '...' }}\n @if (canOpen(item.value)) {\n <mat-icon\n class=\"open ymt-icon--size-s\"\n (click)=\"open(item.value); $event.stopPropagation()\"\n [matTooltip]=\"'yuv.form.element.reference.open.title' | translate\"\n >\n open_in_new\n </mat-icon>\n }\n </span>\n }\n </ng-template>\n</yuv-autocomplete>\n\n<mat-icon class=\"ymt-icon--size-s\" [matTooltip]=\"'yuv.form.element.reference.classify.icon.title' | translate\">link</mat-icon>\n", styles: [":host{display:flex;align-items:center}:host .chip{display:inline-flex;align-items:center;gap:.25em}:host .chip .open{cursor:pointer;color:var(--ymt-text-color-subtle)}:host .chip .open:hover{color:var(--ymt-primary)}:host .chip.notFound{color:var(--ymt-on-danger-container);text-decoration:line-through}:host .chip.notFound:before{content:\"!\";display:inline-block;background-color:var(--ymt-danger-container);color:var(--ymt-on-danger-container);border-radius:2px;padding-inline:.3em;text-decoration:none;margin-inline-end:.75em}:host yuv-autocomplete{flex:1}:host mat-icon{color:var(--ymt-text-color-subtle)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: YuvAutocompleteModule }, { kind: "component", type: i2$2.AutocompleteComponent, selector: "yuv-autocomplete", inputs: ["ariaLabel", "busy", "multiple", "distinctValues", "addOnBlur", "minLength", "maxItems", "forceSelection", "separatorKeys", "autocompleteValues"], outputs: ["autocompleteFnc", "acBlur"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
2406
2514
|
}
|
|
2407
2515
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.20", ngImport: i0, type: ReferenceComponent, decorators: [{
|
|
2408
2516
|
type: Component,
|