@masterteam/components 0.0.181 → 0.0.183
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/assets/common.css +1 -1
- package/assets/i18n/ar.json +3 -0
- package/assets/i18n/en.json +3 -0
- package/fesm2022/masterteam-components-entities.mjs +8 -3
- package/fesm2022/masterteam-components-entities.mjs.map +1 -1
- package/fesm2022/masterteam-components-table.mjs.map +1 -1
- package/fesm2022/masterteam-components-user-search-field.mjs +14 -3
- package/fesm2022/masterteam-components-user-search-field.mjs.map +1 -1
- package/package.json +17 -17
- package/types/masterteam-components-entities.d.ts +10 -0
- package/types/masterteam-components-table.d.ts +2 -2
- package/types/masterteam-components-user-search-field.d.ts +11 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, signal, inject, viewChild, effect, HostBinding, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
2
|
+
import { input, signal, computed, inject, viewChild, effect, HostBinding, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
3
|
import * as i1 from '@angular/forms';
|
|
4
4
|
import { Validators, NgControl, FormsModule } from '@angular/forms';
|
|
5
5
|
import * as i2 from 'primeng/autocomplete';
|
|
@@ -39,6 +39,17 @@ class UserSearchField {
|
|
|
39
39
|
size = input(...(ngDevMode ? [undefined, { debugName: "size" }] : /* istanbul ignore next */ []));
|
|
40
40
|
filteredUsers = signal([], ...(ngDevMode ? [{ debugName: "filteredUsers" }] : /* istanbul ignore next */ []));
|
|
41
41
|
searchTerms = new Subject();
|
|
42
|
+
/**
|
|
43
|
+
* In single-select mode, `true` when the currently selected user is no
|
|
44
|
+
* longer linked to the application. Drives the inline info badge/tooltip.
|
|
45
|
+
* Multiple-select mode handles this per-chip via the `selecteditem` template.
|
|
46
|
+
*/
|
|
47
|
+
unlinkedSingleUser = computed(() => {
|
|
48
|
+
if (this.isMultiple())
|
|
49
|
+
return false;
|
|
50
|
+
const current = this.value();
|
|
51
|
+
return !!current && current.isLinkedToCurrentApplication === false;
|
|
52
|
+
}, ...(ngDevMode ? [{ debugName: "unlinkedSingleUser" }] : /* istanbul ignore next */ []));
|
|
42
53
|
translocoService = inject(TranslocoService);
|
|
43
54
|
autocomplete = viewChild('autocomplete', ...(ngDevMode ? [{ debugName: "autocomplete" }] : /* istanbul ignore next */ []));
|
|
44
55
|
onTouched = () => { };
|
|
@@ -197,7 +208,7 @@ class UserSearchField {
|
|
|
197
208
|
null);
|
|
198
209
|
}
|
|
199
210
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: UserSearchField, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
200
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: UserSearchField, isStandalone: true, selector: "mt-user-search-field", inputs: { hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, isMultiple: { classPropertyName: "isMultiple", publicName: "isMultiple", isSignal: true, isRequired: false, transformFunction: null }, apiUrl: { classPropertyName: "apiUrl", publicName: "apiUrl", isSignal: true, isRequired: true, transformFunction: null }, dataKey: { classPropertyName: "dataKey", publicName: "dataKey", isSignal: true, isRequired: false, transformFunction: null }, paramName: { classPropertyName: "paramName", publicName: "paramName", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "this.styleClass" }, classAttribute: "grid gap-1" }, viewQueries: [{ propertyName: "autocomplete", first: true, predicate: ["autocomplete"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (label()) {\n <label\n [class.required]=\"ngControl?.control?.hasValidator(requiredValidator)\"\n [for]=\"ngControl?.name || label()\"\n >\n {{ label() }}\n </label>\n}\n<div class=\"relative\">\n <p-inputgroup>\n <p-autoComplete\n #autocomplete=\"\"\n [suggestions]=\"filteredUsers()\"\n (completeMethod)=\"search($event)\"\n (onSelect)=\"onSelect($event)\"\n (onUnselect)=\"onUnselect($event)\"\n (onClear)=\"onClear()\"\n (onFocus)=\"onFocus()\"\n (onBlur)=\"onBlur()\"\n [ngModel]=\"isMultiple() ? value() : value()?.['displayName']\"\n [disabled]=\"disabled() || readonly()\"\n [id]=\"ngControl?.name || label()\"\n [invalid]=\"isInvalid(ngControl?.control)\"\n [placeholder]=\"'components.userSearchField.search' | transloco\"\n [multiple]=\"isMultiple()\"\n [optionLabel]=\"'displayName'\"\n class=\"w-full\"\n appendTo=\"body\"\n styleClass=\"w-full\"\n [dropdown]=\"false\"\n [size]=\"size()\"\n >\n <ng-template let-user pTemplate=\"item\">\n <div class=\"flex items-center gap-2\">\n <mt-avatar size=\"small\" icon=\"user.user-01\" />\n <div class=\"flex align-items-center gap-3\">\n <span class=\"font-medium\">{{ user.displayName }}</span>\n <medium class=\"text-gray-500\">{{ \"@\" + user.userName }}</medium>\n </div>\n </div>\n </ng-template>\n\n
|
|
211
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: UserSearchField, isStandalone: true, selector: "mt-user-search-field", inputs: { hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, class: { classPropertyName: "class", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, isMultiple: { classPropertyName: "isMultiple", publicName: "isMultiple", isSignal: true, isRequired: false, transformFunction: null }, apiUrl: { classPropertyName: "apiUrl", publicName: "apiUrl", isSignal: true, isRequired: true, transformFunction: null }, dataKey: { classPropertyName: "dataKey", publicName: "dataKey", isSignal: true, isRequired: false, transformFunction: null }, paramName: { classPropertyName: "paramName", publicName: "paramName", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "this.styleClass" }, classAttribute: "grid gap-1" }, viewQueries: [{ propertyName: "autocomplete", first: true, predicate: ["autocomplete"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (label()) {\r\n <label\r\n [class.required]=\"ngControl?.control?.hasValidator(requiredValidator)\"\r\n [for]=\"ngControl?.name || label()\"\r\n >\r\n {{ label() }}\r\n </label>\r\n}\r\n<div class=\"relative\">\r\n <p-inputgroup>\r\n @if (unlinkedSingleUser()) {\r\n <p-inputgroup-addon\r\n [mtTooltip]=\"'components.userReference.notLinked' | transloco\"\r\n tooltipPosition=\"top\"\r\n >\r\n <mt-icon icon=\"general.info-circle\" class=\"text-amber-500\" />\r\n </p-inputgroup-addon>\r\n }\r\n <p-autoComplete\r\n #autocomplete=\"\"\r\n [suggestions]=\"filteredUsers()\"\r\n (completeMethod)=\"search($event)\"\r\n (onSelect)=\"onSelect($event)\"\r\n (onUnselect)=\"onUnselect($event)\"\r\n (onClear)=\"onClear()\"\r\n (onFocus)=\"onFocus()\"\r\n (onBlur)=\"onBlur()\"\r\n [ngModel]=\"isMultiple() ? value() : value()?.['displayName']\"\r\n [disabled]=\"disabled() || readonly()\"\r\n [id]=\"ngControl?.name || label()\"\r\n [invalid]=\"isInvalid(ngControl?.control)\"\r\n [placeholder]=\"'components.userSearchField.search' | transloco\"\r\n [multiple]=\"isMultiple()\"\r\n [optionLabel]=\"'displayName'\"\r\n class=\"w-full\"\r\n appendTo=\"body\"\r\n styleClass=\"w-full\"\r\n [dropdown]=\"false\"\r\n [size]=\"size()\"\r\n >\r\n <ng-template let-user pTemplate=\"item\">\r\n <div class=\"flex items-center gap-2\">\r\n <mt-avatar size=\"small\" icon=\"user.user-01\" />\r\n <div class=\"flex align-items-center gap-3\">\r\n <span class=\"font-medium\">{{ user.displayName }}</span>\r\n <medium class=\"text-gray-500\">{{ \"@\" + user.userName }}</medium>\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n <ng-template let-user pTemplate=\"selecteditem\">\r\n <span class=\"inline-flex items-center gap-1\">\r\n <span>{{ user.displayName }}</span>\r\n @if (user.isLinkedToCurrentApplication === false) {\r\n <mt-icon\r\n icon=\"general.info-circle\"\r\n class=\"text-amber-500 text-sm shrink-0\"\r\n [mtTooltip]=\"'components.userReference.notLinked' | transloco\"\r\n tooltipPosition=\"top\"\r\n />\r\n }\r\n </span>\r\n </ng-template>\r\n </p-autoComplete>\r\n @if (hint()) {\r\n <p-inputgroup-addon [mtTooltip]=\"hint()\" tooltipPosition=\"top\">\r\n <mt-icon icon=\"general.help-circle\" />\r\n </p-inputgroup-addon>\r\n } @else {\r\n <p-inputgroup-addon tooltipPosition=\"top\">\r\n <mt-icon icon=\"user.user-03\" />\r\n </p-inputgroup-addon>\r\n }\r\n </p-inputgroup>\r\n\r\n @if (loading()) {\r\n <mt-icon\r\n icon=\"general.loading-01\"\r\n class=\"animate-spin absolute right-3 bg-white top-1/2 -translate-y-1/2\"\r\n />\r\n }\r\n</div>\r\n<mt-field-validation [control]=\"ngControl?.control\"></mt-field-validation>\r\n", styles: [":host ::ng-deep .p-autocomplete-input-multiple{border-start-end-radius:0;border-end-end-radius:0}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: AutoCompleteModule }, { kind: "component", type: i2.AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "directive", type: i3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: Tooltip, selector: "[mtTooltip]" }, { kind: "ngmodule", type: InputGroupModule }, { kind: "component", type: i4.InputGroup, selector: "p-inputgroup, p-inputGroup, p-input-group", inputs: ["styleClass"] }, { kind: "ngmodule", type: InputGroupAddonModule }, { kind: "component", type: i5.InputGroupAddon, selector: "p-inputgroup-addon, p-inputGroupAddon", inputs: ["style", "styleClass"] }, { kind: "component", type: FieldValidation, selector: "mt-field-validation", inputs: ["control", "touched"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "component", type: Avatar, selector: "mt-avatar", inputs: ["label", "icon", "image", "styleClass", "size", "shape", "badge", "badgeSize", "badgeSeverity"], outputs: ["onImageError"] }, { kind: "pipe", type: TranslocoPipe, name: "transloco" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
201
212
|
}
|
|
202
213
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: UserSearchField, decorators: [{
|
|
203
214
|
type: Component,
|
|
@@ -213,7 +224,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImpor
|
|
|
213
224
|
TranslocoPipe,
|
|
214
225
|
], changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
215
226
|
class: 'grid gap-1',
|
|
216
|
-
}, template: "@if (label()) {\n <label\n [class.required]=\"ngControl?.control?.hasValidator(requiredValidator)\"\n [for]=\"ngControl?.name || label()\"\n >\n {{ label() }}\n </label>\n}\n<div class=\"relative\">\n <p-inputgroup>\n <p-autoComplete\n #autocomplete=\"\"\n [suggestions]=\"filteredUsers()\"\n (completeMethod)=\"search($event)\"\n (onSelect)=\"onSelect($event)\"\n (onUnselect)=\"onUnselect($event)\"\n (onClear)=\"onClear()\"\n (onFocus)=\"onFocus()\"\n (onBlur)=\"onBlur()\"\n [ngModel]=\"isMultiple() ? value() : value()?.['displayName']\"\n [disabled]=\"disabled() || readonly()\"\n [id]=\"ngControl?.name || label()\"\n [invalid]=\"isInvalid(ngControl?.control)\"\n [placeholder]=\"'components.userSearchField.search' | transloco\"\n [multiple]=\"isMultiple()\"\n [optionLabel]=\"'displayName'\"\n class=\"w-full\"\n appendTo=\"body\"\n styleClass=\"w-full\"\n [dropdown]=\"false\"\n [size]=\"size()\"\n >\n <ng-template let-user pTemplate=\"item\">\n <div class=\"flex items-center gap-2\">\n <mt-avatar size=\"small\" icon=\"user.user-01\" />\n <div class=\"flex align-items-center gap-3\">\n <span class=\"font-medium\">{{ user.displayName }}</span>\n <medium class=\"text-gray-500\">{{ \"@\" + user.userName }}</medium>\n </div>\n </div>\n </ng-template>\n\n
|
|
227
|
+
}, template: "@if (label()) {\r\n <label\r\n [class.required]=\"ngControl?.control?.hasValidator(requiredValidator)\"\r\n [for]=\"ngControl?.name || label()\"\r\n >\r\n {{ label() }}\r\n </label>\r\n}\r\n<div class=\"relative\">\r\n <p-inputgroup>\r\n @if (unlinkedSingleUser()) {\r\n <p-inputgroup-addon\r\n [mtTooltip]=\"'components.userReference.notLinked' | transloco\"\r\n tooltipPosition=\"top\"\r\n >\r\n <mt-icon icon=\"general.info-circle\" class=\"text-amber-500\" />\r\n </p-inputgroup-addon>\r\n }\r\n <p-autoComplete\r\n #autocomplete=\"\"\r\n [suggestions]=\"filteredUsers()\"\r\n (completeMethod)=\"search($event)\"\r\n (onSelect)=\"onSelect($event)\"\r\n (onUnselect)=\"onUnselect($event)\"\r\n (onClear)=\"onClear()\"\r\n (onFocus)=\"onFocus()\"\r\n (onBlur)=\"onBlur()\"\r\n [ngModel]=\"isMultiple() ? value() : value()?.['displayName']\"\r\n [disabled]=\"disabled() || readonly()\"\r\n [id]=\"ngControl?.name || label()\"\r\n [invalid]=\"isInvalid(ngControl?.control)\"\r\n [placeholder]=\"'components.userSearchField.search' | transloco\"\r\n [multiple]=\"isMultiple()\"\r\n [optionLabel]=\"'displayName'\"\r\n class=\"w-full\"\r\n appendTo=\"body\"\r\n styleClass=\"w-full\"\r\n [dropdown]=\"false\"\r\n [size]=\"size()\"\r\n >\r\n <ng-template let-user pTemplate=\"item\">\r\n <div class=\"flex items-center gap-2\">\r\n <mt-avatar size=\"small\" icon=\"user.user-01\" />\r\n <div class=\"flex align-items-center gap-3\">\r\n <span class=\"font-medium\">{{ user.displayName }}</span>\r\n <medium class=\"text-gray-500\">{{ \"@\" + user.userName }}</medium>\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n <ng-template let-user pTemplate=\"selecteditem\">\r\n <span class=\"inline-flex items-center gap-1\">\r\n <span>{{ user.displayName }}</span>\r\n @if (user.isLinkedToCurrentApplication === false) {\r\n <mt-icon\r\n icon=\"general.info-circle\"\r\n class=\"text-amber-500 text-sm shrink-0\"\r\n [mtTooltip]=\"'components.userReference.notLinked' | transloco\"\r\n tooltipPosition=\"top\"\r\n />\r\n }\r\n </span>\r\n </ng-template>\r\n </p-autoComplete>\r\n @if (hint()) {\r\n <p-inputgroup-addon [mtTooltip]=\"hint()\" tooltipPosition=\"top\">\r\n <mt-icon icon=\"general.help-circle\" />\r\n </p-inputgroup-addon>\r\n } @else {\r\n <p-inputgroup-addon tooltipPosition=\"top\">\r\n <mt-icon icon=\"user.user-03\" />\r\n </p-inputgroup-addon>\r\n }\r\n </p-inputgroup>\r\n\r\n @if (loading()) {\r\n <mt-icon\r\n icon=\"general.loading-01\"\r\n class=\"animate-spin absolute right-3 bg-white top-1/2 -translate-y-1/2\"\r\n />\r\n }\r\n</div>\r\n<mt-field-validation [control]=\"ngControl?.control\"></mt-field-validation>\r\n", styles: [":host ::ng-deep .p-autocomplete-input-multiple{border-start-end-radius:0;border-end-end-radius:0}\n"] }]
|
|
217
228
|
}], ctorParameters: () => [], propDecorators: { hint: [{ type: i0.Input, args: [{ isSignal: true, alias: "hint", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], class: [{ type: i0.Input, args: [{ isSignal: true, alias: "class", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], isMultiple: [{ type: i0.Input, args: [{ isSignal: true, alias: "isMultiple", required: false }] }], apiUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "apiUrl", required: true }] }], dataKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataKey", required: false }] }], paramName: [{ type: i0.Input, args: [{ isSignal: true, alias: "paramName", required: false }] }], context: [{ type: i0.Input, args: [{ isSignal: true, alias: "context", required: false }] }], styleClass: [{
|
|
218
229
|
type: HostBinding,
|
|
219
230
|
args: ['class']
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"masterteam-components-user-search-field.mjs","sources":["../../../../packages/masterteam/components/user-search-field/user-search-field.ts","../../../../packages/masterteam/components/user-search-field/user-search-field.html","../../../../packages/masterteam/components/user-search-field/masterteam-components-user-search-field.ts"],"sourcesContent":["import {\n Component,\n HostBinding,\n signal,\n input,\n OnInit,\n inject,\n ChangeDetectionStrategy,\n effect,\n viewChild,\n} from '@angular/core';\nimport {\n ControlValueAccessor,\n FormsModule,\n NgControl,\n Validators,\n} from '@angular/forms';\nimport { AutoComplete, AutoCompleteModule } from 'primeng/autocomplete';\nimport { InputGroupModule } from 'primeng/inputgroup';\nimport { InputGroupAddonModule } from 'primeng/inputgroupaddon';\nimport { Tooltip } from '@masterteam/components/tooltip';\nimport { FieldValidation } from '@masterteam/components/field-validation';\nimport { isInvalid } from '@masterteam/components';\nimport { Icon } from '@masterteam/icons';\nimport {\n Subject,\n debounceTime,\n switchMap,\n tap,\n of,\n finalize,\n catchError,\n} from 'rxjs';\nimport { HttpClient, HttpContext, HttpParams } from '@angular/common/http';\nimport { Avatar } from '@masterteam/components/avatar';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { TranslocoService, TranslocoPipe } from '@jsverse/transloco';\n\nexport interface User {\n isExternal: boolean;\n id: string;\n displayName: string;\n userName: string;\n photo: string;\n}\n\n@Component({\n selector: 'mt-user-search-field',\n standalone: true,\n imports: [\n FormsModule,\n AutoCompleteModule,\n Tooltip,\n InputGroupModule,\n InputGroupAddonModule,\n FieldValidation,\n Icon,\n Avatar,\n TranslocoPipe,\n ],\n templateUrl: './user-search-field.html',\n styleUrls: ['./user-search-field.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n class: 'grid gap-1',\n },\n})\nexport class UserSearchField implements ControlValueAccessor, OnInit {\n readonly hint = input<string>();\n readonly label = input<string>();\n readonly placeholder = input<string>();\n readonly class = input<string>('');\n readonly readonly = input<boolean>(false);\n readonly required = input<boolean>(false);\n readonly isMultiple = input<boolean>(false);\n readonly apiUrl = input.required<string>();\n readonly dataKey = input<string>('data');\n readonly paramName = input<string>('query');\n readonly context = input<HttpContext | undefined>(undefined);\n\n @HostBinding('class') styleClass: string;\n\n requiredValidator = Validators.required;\n value = signal<User | User[] | null>(null);\n disabled = signal<boolean>(false);\n loading = signal<boolean>(false);\n\n readonly size = input<'small' | 'large' | undefined>();\n\n filteredUsers = signal<User[]>([]);\n private searchTerms = new Subject<string>();\n\n private readonly translocoService = inject(TranslocoService);\n\n readonly autocomplete = viewChild<AutoComplete>('autocomplete');\n\n onTouched: () => void = () => {};\n onModelChange: (value: any) => void = () => {};\n\n public ngControl: NgControl | null = null;\n private http = inject(HttpClient);\n\n isInvalid = isInvalid;\n\n constructor() {\n this.ngControl = inject(NgControl, { self: true, optional: true });\n if (this.ngControl) {\n this.ngControl.valueAccessor = this;\n }\n effect(() => {\n if (this.ngControl?.control && this.required()) {\n this.ngControl.control.addValidators(Validators.required);\n this.ngControl.control.updateValueAndValidity();\n }\n });\n this.getUsers();\n }\n\n ngOnInit() {\n this.styleClass = this.class();\n }\n\n search(event: { query: string }) {\n this.searchTerms.next(event.query);\n }\n\n onFocus() {\n const autocomplete = this.autocomplete();\n if (!autocomplete) return;\n const inputEl = this.getInputElement(autocomplete);\n const typed = (inputEl?.value ?? '').trim();\n if (!typed) {\n this.filteredUsers.set([]);\n return;\n }\n if (this.filteredUsers().length > 0) {\n autocomplete.show();\n }\n }\n\n onBlur() {\n this.onTouched();\n\n const autocomplete = this.autocomplete();\n if (!autocomplete || this.filteredUsers().length > 0) return;\n\n const inputEl = this.getInputElement(autocomplete);\n const typed = (inputEl?.value ?? '').trim();\n if (!typed) return;\n\n if (!this.isMultiple()) {\n const value = this.value();\n const selectedLabel = Array.isArray(value)\n ? value[0]?.displayName\n : value?.displayName;\n\n if (selectedLabel?.trim() === typed) return;\n\n this.value.set(null);\n this.onModelChange(null);\n }\n\n if (inputEl) {\n inputEl.value = '';\n }\n this.filteredUsers.set([]);\n this.loading.set(false);\n autocomplete.hide();\n }\n\n onSelect(event: { originalEvent: Event; value: User }) {\n const selectedUser = event.value;\n if (this.isMultiple()) {\n const current = (this.value() as User[]) || [];\n const updated = [...current, selectedUser];\n this.value.set(updated);\n this.onModelChange(updated);\n const remaining = this.filteredUsers().filter(\n (u) => u.id !== selectedUser.id,\n );\n this.filteredUsers.set(remaining);\n if (remaining.length > 0) {\n queueMicrotask(() => this.autocomplete()?.show());\n }\n } else {\n this.value.set(selectedUser);\n this.onModelChange(selectedUser);\n this.filteredUsers.set([]);\n this.autocomplete()?.hide();\n }\n this.onTouched();\n this.loading.set(false);\n }\n\n onUnselect(event: { originalEvent: Event; value: User }) {\n const removedUser = event.value;\n const current = (this.value() as User[]) || [];\n const updated = current.filter((u) => u.id !== removedUser.id);\n this.value.set(updated);\n this.onModelChange(updated);\n this.onTouched();\n }\n\n onClear() {\n this.value.set(this.isMultiple() ? [] : null);\n this.onModelChange(this.isMultiple() ? [] : null);\n this.filteredUsers.set([]);\n this.loading.set(false);\n }\n\n writeValue(value: User | User[] | null): void {\n if (this.isMultiple()) {\n this.value.set(Array.isArray(value) ? value : value ? [value] : []);\n } else {\n this.value.set(Array.isArray(value) ? (value[0] ?? null) : value);\n }\n }\n\n registerOnChange(fn: (value: User | null) => void) {\n this.onModelChange = fn;\n }\n\n registerOnTouched(fn: any) {\n this.onTouched = fn;\n }\n\n setDisabledState(disabled: boolean) {\n this.disabled.set(disabled);\n }\n\n getUsers() {\n this.searchTerms\n .pipe(\n takeUntilDestroyed(),\n debounceTime(250),\n tap(() => this.loading.set(true)),\n switchMap((term: string) => {\n const trimmed = term?.trim();\n if (!trimmed) {\n this.filteredUsers.set([]);\n this.loading.set(false);\n return of({ [this.dataKey()]: [] } as Record<string, User[]>);\n }\n const params = new HttpParams().set(this.paramName(), trimmed);\n return this.http\n .get<Record<string, User[]>>(this.apiUrl(), {\n params,\n context: this.context(),\n })\n .pipe(\n finalize(() => this.loading.set(false)),\n catchError((err) => {\n console.error('API search failed:', err);\n return of({ [this.dataKey()]: [] } as Record<string, User[]>);\n }),\n );\n }),\n )\n .subscribe({\n next: (response) => {\n const users = (response?.[this.dataKey()] ?? []) as User[];\n if (this.isMultiple()) {\n const selectedIds = new Set(\n ((this.value() as User[]) ?? []).map((u) => u.id),\n );\n this.filteredUsers.set(users.filter((u) => !selectedIds.has(u.id)));\n } else {\n this.filteredUsers.set(users);\n }\n },\n });\n }\n\n private getInputElement(autocomplete: AutoComplete): HTMLInputElement | null {\n return (\n autocomplete.multiInputEl?.nativeElement ??\n autocomplete.inputEL?.nativeElement ??\n null\n );\n }\n}\n","@if (label()) {\n <label\n [class.required]=\"ngControl?.control?.hasValidator(requiredValidator)\"\n [for]=\"ngControl?.name || label()\"\n >\n {{ label() }}\n </label>\n}\n<div class=\"relative\">\n <p-inputgroup>\n <p-autoComplete\n #autocomplete=\"\"\n [suggestions]=\"filteredUsers()\"\n (completeMethod)=\"search($event)\"\n (onSelect)=\"onSelect($event)\"\n (onUnselect)=\"onUnselect($event)\"\n (onClear)=\"onClear()\"\n (onFocus)=\"onFocus()\"\n (onBlur)=\"onBlur()\"\n [ngModel]=\"isMultiple() ? value() : value()?.['displayName']\"\n [disabled]=\"disabled() || readonly()\"\n [id]=\"ngControl?.name || label()\"\n [invalid]=\"isInvalid(ngControl?.control)\"\n [placeholder]=\"'components.userSearchField.search' | transloco\"\n [multiple]=\"isMultiple()\"\n [optionLabel]=\"'displayName'\"\n class=\"w-full\"\n appendTo=\"body\"\n styleClass=\"w-full\"\n [dropdown]=\"false\"\n [size]=\"size()\"\n >\n <ng-template let-user pTemplate=\"item\">\n <div class=\"flex items-center gap-2\">\n <mt-avatar size=\"small\" icon=\"user.user-01\" />\n <div class=\"flex align-items-center gap-3\">\n <span class=\"font-medium\">{{ user.displayName }}</span>\n <medium class=\"text-gray-500\">{{ \"@\" + user.userName }}</medium>\n </div>\n </div>\n </ng-template>\n\n <!-- <ng-template let-user #pTemplate=\"selecteditem\">\n <div class=\"flex items-center gap-2\">\n <mt-avatar size=\"small\" icon=\"user.user-01\" />\n <div class=\"flex align-items-center gap-3\">\n <span class=\"font-medium\">{{ user.displayName }}</span>\n <medium class=\"text-gray-500\">{{ \"@\" + user.userName }}</medium>\n </div>\n </div>\n </ng-template> -->\n </p-autoComplete>\n @if (hint()) {\n <p-inputgroup-addon [mtTooltip]=\"hint()\" tooltipPosition=\"top\">\n <mt-icon icon=\"general.help-circle\" />\n </p-inputgroup-addon>\n } @else {\n <p-inputgroup-addon tooltipPosition=\"top\">\n <mt-icon icon=\"user.user-03\" />\n </p-inputgroup-addon>\n }\n </p-inputgroup>\n\n @if (loading()) {\n <mt-icon\n icon=\"general.loading-01\"\n class=\"animate-spin absolute right-3 bg-white top-1/2 -translate-y-1/2\"\n />\n }\n</div>\n<mt-field-validation [control]=\"ngControl?.control\"></mt-field-validation>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"masterteam-components-user-search-field.mjs","sources":["../../../../packages/masterteam/components/user-search-field/user-search-field.ts","../../../../packages/masterteam/components/user-search-field/user-search-field.html","../../../../packages/masterteam/components/user-search-field/masterteam-components-user-search-field.ts"],"sourcesContent":["import {\r\n Component,\r\n HostBinding,\r\n signal,\r\n computed,\r\n input,\r\n OnInit,\r\n inject,\r\n ChangeDetectionStrategy,\r\n effect,\r\n viewChild,\r\n} from '@angular/core';\r\nimport {\r\n ControlValueAccessor,\r\n FormsModule,\r\n NgControl,\r\n Validators,\r\n} from '@angular/forms';\r\nimport { AutoComplete, AutoCompleteModule } from 'primeng/autocomplete';\r\nimport { InputGroupModule } from 'primeng/inputgroup';\r\nimport { InputGroupAddonModule } from 'primeng/inputgroupaddon';\r\nimport { Tooltip } from '@masterteam/components/tooltip';\r\nimport { FieldValidation } from '@masterteam/components/field-validation';\r\nimport { isInvalid } from '@masterteam/components';\r\nimport { Icon } from '@masterteam/icons';\r\nimport {\r\n Subject,\r\n debounceTime,\r\n switchMap,\r\n tap,\r\n of,\r\n finalize,\r\n catchError,\r\n} from 'rxjs';\r\nimport { HttpClient, HttpContext, HttpParams } from '@angular/common/http';\r\nimport { Avatar } from '@masterteam/components/avatar';\r\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\r\nimport { TranslocoService, TranslocoPipe } from '@jsverse/transloco';\r\n\r\nexport interface User {\r\n isExternal: boolean;\r\n id: string;\r\n displayName: string;\r\n userName: string;\r\n photo: string;\r\n /**\r\n * `false` when the user is no longer linked to the current application\r\n * (e.g. removed/deleted) but is still referenced by historical records.\r\n */\r\n isLinkedToCurrentApplication?: boolean;\r\n}\r\n\r\n@Component({\r\n selector: 'mt-user-search-field',\r\n standalone: true,\r\n imports: [\r\n FormsModule,\r\n AutoCompleteModule,\r\n Tooltip,\r\n InputGroupModule,\r\n InputGroupAddonModule,\r\n FieldValidation,\r\n Icon,\r\n Avatar,\r\n TranslocoPipe,\r\n ],\r\n templateUrl: './user-search-field.html',\r\n styleUrls: ['./user-search-field.scss'],\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n host: {\r\n class: 'grid gap-1',\r\n },\r\n})\r\nexport class UserSearchField implements ControlValueAccessor, OnInit {\r\n readonly hint = input<string>();\r\n readonly label = input<string>();\r\n readonly placeholder = input<string>();\r\n readonly class = input<string>('');\r\n readonly readonly = input<boolean>(false);\r\n readonly required = input<boolean>(false);\r\n readonly isMultiple = input<boolean>(false);\r\n readonly apiUrl = input.required<string>();\r\n readonly dataKey = input<string>('data');\r\n readonly paramName = input<string>('query');\r\n readonly context = input<HttpContext | undefined>(undefined);\r\n\r\n @HostBinding('class') styleClass: string;\r\n\r\n requiredValidator = Validators.required;\r\n value = signal<User | User[] | null>(null);\r\n disabled = signal<boolean>(false);\r\n loading = signal<boolean>(false);\r\n\r\n readonly size = input<'small' | 'large' | undefined>();\r\n\r\n filteredUsers = signal<User[]>([]);\r\n private searchTerms = new Subject<string>();\r\n\r\n /**\r\n * In single-select mode, `true` when the currently selected user is no\r\n * longer linked to the application. Drives the inline info badge/tooltip.\r\n * Multiple-select mode handles this per-chip via the `selecteditem` template.\r\n */\r\n readonly unlinkedSingleUser = computed<boolean>(() => {\r\n if (this.isMultiple()) return false;\r\n const current = this.value() as User | null;\r\n return !!current && current.isLinkedToCurrentApplication === false;\r\n });\r\n\r\n private readonly translocoService = inject(TranslocoService);\r\n\r\n readonly autocomplete = viewChild<AutoComplete>('autocomplete');\r\n\r\n onTouched: () => void = () => {};\r\n onModelChange: (value: any) => void = () => {};\r\n\r\n public ngControl: NgControl | null = null;\r\n private http = inject(HttpClient);\r\n\r\n isInvalid = isInvalid;\r\n\r\n constructor() {\r\n this.ngControl = inject(NgControl, { self: true, optional: true });\r\n if (this.ngControl) {\r\n this.ngControl.valueAccessor = this;\r\n }\r\n effect(() => {\r\n if (this.ngControl?.control && this.required()) {\r\n this.ngControl.control.addValidators(Validators.required);\r\n this.ngControl.control.updateValueAndValidity();\r\n }\r\n });\r\n this.getUsers();\r\n }\r\n\r\n ngOnInit() {\r\n this.styleClass = this.class();\r\n }\r\n\r\n search(event: { query: string }) {\r\n this.searchTerms.next(event.query);\r\n }\r\n\r\n onFocus() {\r\n const autocomplete = this.autocomplete();\r\n if (!autocomplete) return;\r\n const inputEl = this.getInputElement(autocomplete);\r\n const typed = (inputEl?.value ?? '').trim();\r\n if (!typed) {\r\n this.filteredUsers.set([]);\r\n return;\r\n }\r\n if (this.filteredUsers().length > 0) {\r\n autocomplete.show();\r\n }\r\n }\r\n\r\n onBlur() {\r\n this.onTouched();\r\n\r\n const autocomplete = this.autocomplete();\r\n if (!autocomplete || this.filteredUsers().length > 0) return;\r\n\r\n const inputEl = this.getInputElement(autocomplete);\r\n const typed = (inputEl?.value ?? '').trim();\r\n if (!typed) return;\r\n\r\n if (!this.isMultiple()) {\r\n const value = this.value();\r\n const selectedLabel = Array.isArray(value)\r\n ? value[0]?.displayName\r\n : value?.displayName;\r\n\r\n if (selectedLabel?.trim() === typed) return;\r\n\r\n this.value.set(null);\r\n this.onModelChange(null);\r\n }\r\n\r\n if (inputEl) {\r\n inputEl.value = '';\r\n }\r\n this.filteredUsers.set([]);\r\n this.loading.set(false);\r\n autocomplete.hide();\r\n }\r\n\r\n onSelect(event: { originalEvent: Event; value: User }) {\r\n const selectedUser = event.value;\r\n if (this.isMultiple()) {\r\n const current = (this.value() as User[]) || [];\r\n const updated = [...current, selectedUser];\r\n this.value.set(updated);\r\n this.onModelChange(updated);\r\n const remaining = this.filteredUsers().filter(\r\n (u) => u.id !== selectedUser.id,\r\n );\r\n this.filteredUsers.set(remaining);\r\n if (remaining.length > 0) {\r\n queueMicrotask(() => this.autocomplete()?.show());\r\n }\r\n } else {\r\n this.value.set(selectedUser);\r\n this.onModelChange(selectedUser);\r\n this.filteredUsers.set([]);\r\n this.autocomplete()?.hide();\r\n }\r\n this.onTouched();\r\n this.loading.set(false);\r\n }\r\n\r\n onUnselect(event: { originalEvent: Event; value: User }) {\r\n const removedUser = event.value;\r\n const current = (this.value() as User[]) || [];\r\n const updated = current.filter((u) => u.id !== removedUser.id);\r\n this.value.set(updated);\r\n this.onModelChange(updated);\r\n this.onTouched();\r\n }\r\n\r\n onClear() {\r\n this.value.set(this.isMultiple() ? [] : null);\r\n this.onModelChange(this.isMultiple() ? [] : null);\r\n this.filteredUsers.set([]);\r\n this.loading.set(false);\r\n }\r\n\r\n writeValue(value: User | User[] | null): void {\r\n if (this.isMultiple()) {\r\n this.value.set(Array.isArray(value) ? value : value ? [value] : []);\r\n } else {\r\n this.value.set(Array.isArray(value) ? (value[0] ?? null) : value);\r\n }\r\n }\r\n\r\n registerOnChange(fn: (value: User | null) => void) {\r\n this.onModelChange = fn;\r\n }\r\n\r\n registerOnTouched(fn: any) {\r\n this.onTouched = fn;\r\n }\r\n\r\n setDisabledState(disabled: boolean) {\r\n this.disabled.set(disabled);\r\n }\r\n\r\n getUsers() {\r\n this.searchTerms\r\n .pipe(\r\n takeUntilDestroyed(),\r\n debounceTime(250),\r\n tap(() => this.loading.set(true)),\r\n switchMap((term: string) => {\r\n const trimmed = term?.trim();\r\n if (!trimmed) {\r\n this.filteredUsers.set([]);\r\n this.loading.set(false);\r\n return of({ [this.dataKey()]: [] } as Record<string, User[]>);\r\n }\r\n const params = new HttpParams().set(this.paramName(), trimmed);\r\n return this.http\r\n .get<Record<string, User[]>>(this.apiUrl(), {\r\n params,\r\n context: this.context(),\r\n })\r\n .pipe(\r\n finalize(() => this.loading.set(false)),\r\n catchError((err) => {\r\n console.error('API search failed:', err);\r\n return of({ [this.dataKey()]: [] } as Record<string, User[]>);\r\n }),\r\n );\r\n }),\r\n )\r\n .subscribe({\r\n next: (response) => {\r\n const users = (response?.[this.dataKey()] ?? []) as User[];\r\n if (this.isMultiple()) {\r\n const selectedIds = new Set(\r\n ((this.value() as User[]) ?? []).map((u) => u.id),\r\n );\r\n this.filteredUsers.set(users.filter((u) => !selectedIds.has(u.id)));\r\n } else {\r\n this.filteredUsers.set(users);\r\n }\r\n },\r\n });\r\n }\r\n\r\n private getInputElement(autocomplete: AutoComplete): HTMLInputElement | null {\r\n return (\r\n autocomplete.multiInputEl?.nativeElement ??\r\n autocomplete.inputEL?.nativeElement ??\r\n null\r\n );\r\n }\r\n}\r\n","@if (label()) {\r\n <label\r\n [class.required]=\"ngControl?.control?.hasValidator(requiredValidator)\"\r\n [for]=\"ngControl?.name || label()\"\r\n >\r\n {{ label() }}\r\n </label>\r\n}\r\n<div class=\"relative\">\r\n <p-inputgroup>\r\n @if (unlinkedSingleUser()) {\r\n <p-inputgroup-addon\r\n [mtTooltip]=\"'components.userReference.notLinked' | transloco\"\r\n tooltipPosition=\"top\"\r\n >\r\n <mt-icon icon=\"general.info-circle\" class=\"text-amber-500\" />\r\n </p-inputgroup-addon>\r\n }\r\n <p-autoComplete\r\n #autocomplete=\"\"\r\n [suggestions]=\"filteredUsers()\"\r\n (completeMethod)=\"search($event)\"\r\n (onSelect)=\"onSelect($event)\"\r\n (onUnselect)=\"onUnselect($event)\"\r\n (onClear)=\"onClear()\"\r\n (onFocus)=\"onFocus()\"\r\n (onBlur)=\"onBlur()\"\r\n [ngModel]=\"isMultiple() ? value() : value()?.['displayName']\"\r\n [disabled]=\"disabled() || readonly()\"\r\n [id]=\"ngControl?.name || label()\"\r\n [invalid]=\"isInvalid(ngControl?.control)\"\r\n [placeholder]=\"'components.userSearchField.search' | transloco\"\r\n [multiple]=\"isMultiple()\"\r\n [optionLabel]=\"'displayName'\"\r\n class=\"w-full\"\r\n appendTo=\"body\"\r\n styleClass=\"w-full\"\r\n [dropdown]=\"false\"\r\n [size]=\"size()\"\r\n >\r\n <ng-template let-user pTemplate=\"item\">\r\n <div class=\"flex items-center gap-2\">\r\n <mt-avatar size=\"small\" icon=\"user.user-01\" />\r\n <div class=\"flex align-items-center gap-3\">\r\n <span class=\"font-medium\">{{ user.displayName }}</span>\r\n <medium class=\"text-gray-500\">{{ \"@\" + user.userName }}</medium>\r\n </div>\r\n </div>\r\n </ng-template>\r\n\r\n <ng-template let-user pTemplate=\"selecteditem\">\r\n <span class=\"inline-flex items-center gap-1\">\r\n <span>{{ user.displayName }}</span>\r\n @if (user.isLinkedToCurrentApplication === false) {\r\n <mt-icon\r\n icon=\"general.info-circle\"\r\n class=\"text-amber-500 text-sm shrink-0\"\r\n [mtTooltip]=\"'components.userReference.notLinked' | transloco\"\r\n tooltipPosition=\"top\"\r\n />\r\n }\r\n </span>\r\n </ng-template>\r\n </p-autoComplete>\r\n @if (hint()) {\r\n <p-inputgroup-addon [mtTooltip]=\"hint()\" tooltipPosition=\"top\">\r\n <mt-icon icon=\"general.help-circle\" />\r\n </p-inputgroup-addon>\r\n } @else {\r\n <p-inputgroup-addon tooltipPosition=\"top\">\r\n <mt-icon icon=\"user.user-03\" />\r\n </p-inputgroup-addon>\r\n }\r\n </p-inputgroup>\r\n\r\n @if (loading()) {\r\n <mt-icon\r\n icon=\"general.loading-01\"\r\n class=\"animate-spin absolute right-3 bg-white top-1/2 -translate-y-1/2\"\r\n />\r\n }\r\n</div>\r\n<mt-field-validation [control]=\"ngControl?.control\"></mt-field-validation>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@masterteam/components",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.183",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"directory": "../../../dist/masterteam/components",
|
|
6
6
|
"linkDirectory": true,
|
|
7
7
|
"access": "public"
|
|
8
8
|
},
|
|
9
9
|
"peerDependencies": {
|
|
10
|
-
"@angular/cdk": "
|
|
11
|
-
"@angular/common": "
|
|
12
|
-
"@angular/core": "
|
|
13
|
-
"@angular/forms": "
|
|
14
|
-
"@jsverse/transloco": "
|
|
15
|
-
"@masterteam/icons": "
|
|
16
|
-
"@primeuix/themes": "
|
|
17
|
-
"@tailwindcss/postcss": "
|
|
10
|
+
"@angular/cdk": "^21.2.6",
|
|
11
|
+
"@angular/common": "^21.2.8",
|
|
12
|
+
"@angular/core": "^21.2.8",
|
|
13
|
+
"@angular/forms": "^21.2.8",
|
|
14
|
+
"@jsverse/transloco": "^8.3.0",
|
|
15
|
+
"@masterteam/icons": "^0.0.15",
|
|
16
|
+
"@primeuix/themes": "^2.0.3",
|
|
17
|
+
"@tailwindcss/postcss": "^4.2.2",
|
|
18
18
|
"monaco-editor": "^0.52.0",
|
|
19
|
-
"ngx-quill": "
|
|
20
|
-
"postcss": "
|
|
21
|
-
"primeng": "
|
|
22
|
-
"quill": "
|
|
23
|
-
"tailwindcss": "
|
|
24
|
-
"tailwindcss-primeui": "
|
|
19
|
+
"ngx-quill": "^30.0.1",
|
|
20
|
+
"postcss": "^8.5.9",
|
|
21
|
+
"primeng": "21.1.5",
|
|
22
|
+
"quill": "^2.0.3",
|
|
23
|
+
"tailwindcss": "^4.2.2",
|
|
24
|
+
"tailwindcss-primeui": "^0.6.1"
|
|
25
25
|
},
|
|
26
26
|
"repository": {
|
|
27
27
|
"type": "git",
|
|
@@ -262,9 +262,9 @@
|
|
|
262
262
|
},
|
|
263
263
|
"dependencies": {
|
|
264
264
|
"xlsx": "^0.18.5",
|
|
265
|
-
"tslib": "
|
|
265
|
+
"tslib": "^2.8.1"
|
|
266
266
|
},
|
|
267
267
|
"module": "fesm2022/masterteam-components.mjs",
|
|
268
268
|
"typings": "types/masterteam-components.d.ts",
|
|
269
269
|
"type": "module"
|
|
270
|
-
}
|
|
270
|
+
}
|
|
@@ -97,6 +97,11 @@ interface EntityUserValue {
|
|
|
97
97
|
photoUrl?: string;
|
|
98
98
|
phoneNumber?: string;
|
|
99
99
|
email?: string;
|
|
100
|
+
/**
|
|
101
|
+
* `false` when the user is no longer linked to the current application
|
|
102
|
+
* (e.g. removed/deleted) but is still referenced by historical records.
|
|
103
|
+
*/
|
|
104
|
+
isLinkedToCurrentApplication?: boolean;
|
|
100
105
|
}
|
|
101
106
|
interface LeafDetailsStatusSummary {
|
|
102
107
|
key: string;
|
|
@@ -265,6 +270,11 @@ declare class EntityUser {
|
|
|
265
270
|
readonly userName: _angular_core.Signal<string>;
|
|
266
271
|
readonly userPhoto: _angular_core.Signal<string>;
|
|
267
272
|
readonly labelText: _angular_core.Signal<string>;
|
|
273
|
+
/**
|
|
274
|
+
* `true` when the referenced user is no longer linked to the application.
|
|
275
|
+
* Drives the inline info badge/tooltip next to the display name.
|
|
276
|
+
*/
|
|
277
|
+
readonly isUnlinked: _angular_core.Signal<boolean>;
|
|
268
278
|
private readonly config;
|
|
269
279
|
readonly showDisplayName: _angular_core.Signal<boolean>;
|
|
270
280
|
readonly showPhoneNumber: _angular_core.Signal<boolean>;
|
|
@@ -239,7 +239,7 @@ declare class Table {
|
|
|
239
239
|
captionStartContent: _angular_core.Signal<TemplateRef<any> | undefined>;
|
|
240
240
|
captionEndContent: _angular_core.Signal<TemplateRef<any> | undefined>;
|
|
241
241
|
emptyContent: _angular_core.Signal<TemplateRef<any> | undefined>;
|
|
242
|
-
paginatorPosition: _angular_core.InputSignal<"
|
|
242
|
+
paginatorPosition: _angular_core.InputSignal<"end" | "start" | "center">;
|
|
243
243
|
alwaysShowPaginator: _angular_core.InputSignalWithTransform<boolean, unknown>;
|
|
244
244
|
rowsPerPageOptions: _angular_core.InputSignal<number[]>;
|
|
245
245
|
pageSize: _angular_core.ModelSignal<number>;
|
|
@@ -248,7 +248,7 @@ declare class Table {
|
|
|
248
248
|
filterTerm: _angular_core.ModelSignal<string>;
|
|
249
249
|
groupBy: _angular_core.ModelSignal<string | null>;
|
|
250
250
|
sortField: _angular_core.WritableSignal<string | null>;
|
|
251
|
-
sortDirection: _angular_core.WritableSignal<"
|
|
251
|
+
sortDirection: _angular_core.WritableSignal<"asc" | "desc" | null>;
|
|
252
252
|
confirmationService: ConfirmationService;
|
|
253
253
|
private readonly exportService;
|
|
254
254
|
private readonly transloco;
|
|
@@ -11,6 +11,11 @@ interface User {
|
|
|
11
11
|
displayName: string;
|
|
12
12
|
userName: string;
|
|
13
13
|
photo: string;
|
|
14
|
+
/**
|
|
15
|
+
* `false` when the user is no longer linked to the current application
|
|
16
|
+
* (e.g. removed/deleted) but is still referenced by historical records.
|
|
17
|
+
*/
|
|
18
|
+
isLinkedToCurrentApplication?: boolean;
|
|
14
19
|
}
|
|
15
20
|
declare class UserSearchField implements ControlValueAccessor, OnInit {
|
|
16
21
|
readonly hint: _angular_core.InputSignal<string | undefined>;
|
|
@@ -32,6 +37,12 @@ declare class UserSearchField implements ControlValueAccessor, OnInit {
|
|
|
32
37
|
readonly size: _angular_core.InputSignal<"small" | "large" | undefined>;
|
|
33
38
|
filteredUsers: _angular_core.WritableSignal<User[]>;
|
|
34
39
|
private searchTerms;
|
|
40
|
+
/**
|
|
41
|
+
* In single-select mode, `true` when the currently selected user is no
|
|
42
|
+
* longer linked to the application. Drives the inline info badge/tooltip.
|
|
43
|
+
* Multiple-select mode handles this per-chip via the `selecteditem` template.
|
|
44
|
+
*/
|
|
45
|
+
readonly unlinkedSingleUser: _angular_core.Signal<boolean>;
|
|
35
46
|
private readonly translocoService;
|
|
36
47
|
readonly autocomplete: _angular_core.Signal<AutoComplete | undefined>;
|
|
37
48
|
onTouched: () => void;
|