@fuentis/phoenix-ui 0.0.9-alpha.633 → 0.0.9-alpha.635

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.
@@ -67,11 +67,13 @@ import * as i5$2 from 'primeng/multiselect';
67
67
  import { MultiSelectModule } from 'primeng/multiselect';
68
68
  import * as i10 from 'primeng/listbox';
69
69
  import { ListboxModule } from 'primeng/listbox';
70
- import * as i12 from 'primeng/overlaybadge';
70
+ import * as i12 from 'primeng/slider';
71
+ import { SliderModule } from 'primeng/slider';
72
+ import * as i13 from 'primeng/overlaybadge';
71
73
  import { OverlayBadgeModule } from 'primeng/overlaybadge';
72
- import * as i13 from 'primeng/ripple';
74
+ import * as i14 from 'primeng/ripple';
73
75
  import { RippleModule } from 'primeng/ripple';
74
- import * as i14 from 'primeng/floatlabel';
76
+ import * as i15 from 'primeng/floatlabel';
75
77
  import { FloatLabelModule } from 'primeng/floatlabel';
76
78
  import * as i2$3 from 'primeng/selectbutton';
77
79
  import { SelectButtonModule } from 'primeng/selectbutton';
@@ -1781,6 +1783,7 @@ var tableFilterType;
1781
1783
  tableFilterType["BOOLEAN"] = "boolean";
1782
1784
  tableFilterType["MULTISELECT"] = "multiselect";
1783
1785
  tableFilterType["COMPLETNESS"] = "completness";
1786
+ tableFilterType["RANGE"] = "range";
1784
1787
  // ICON = 'icon',
1785
1788
  })(tableFilterType || (tableFilterType = {}));
1786
1789
 
@@ -2070,7 +2073,9 @@ class TableCaptionComponent {
2070
2073
  ? this.normalizeMultiInitial(f.selected)
2071
2074
  : t === 'checkbox'
2072
2075
  ? !!f.selected
2073
- : f.selected ?? '';
2076
+ : t === 'range'
2077
+ ? this.normalizeRangeInitial(f.selected, f)
2078
+ : f.selected ?? '';
2074
2079
  fg.addControl(f.key, this.fb.control(initialValue));
2075
2080
  }
2076
2081
  this.filtersForm = fg;
@@ -2114,7 +2119,13 @@ class TableCaptionComponent {
2114
2119
  });
2115
2120
  }
2116
2121
  buildSignature(tableKey, filtersCfg) {
2117
- const keys = (filtersCfg ?? []).map((f) => f.key).join('|');
2122
+ const keys = (filtersCfg ?? [])
2123
+ .map((f) =>
2124
+ // Range bounds are data-derived and can change without the key set
2125
+ // changing; fold them into the signature so the form rebuilds when
2126
+ // the min/max move.
2127
+ f.type === 'range' ? `${f.key}:${f.min}-${f.max}` : f.key)
2128
+ .join('|');
2118
2129
  return `${tableKey ?? 'table'}::${keys}`;
2119
2130
  }
2120
2131
  applyValidValuesPatch(validMap) {
@@ -2147,6 +2158,35 @@ class TableCaptionComponent {
2147
2158
  return Array.isArray(selected) ? selected : [selected];
2148
2159
  }
2149
2160
  // ---------------------------------------------------------------------------
2161
+ // range helpers (UI value = [from, to]; output = { type:'range', min, max })
2162
+ // ---------------------------------------------------------------------------
2163
+ /** Full bounds of a range filter as [min, max]. */
2164
+ rangeBounds(cfg) {
2165
+ const min = Number.isFinite(cfg.min) ? cfg.min : 0;
2166
+ const max = Number.isFinite(cfg.max) ? cfg.max : 100;
2167
+ return min <= max ? [min, max] : [max, min];
2168
+ }
2169
+ /** Clamp a selected [from, to] to the config bounds; defaults to full bounds. */
2170
+ normalizeRangeInitial(selected, cfg) {
2171
+ const [min, max] = this.rangeBounds(cfg);
2172
+ const arr = Array.isArray(selected) ? selected : [];
2173
+ let from = Number(arr[0]);
2174
+ let to = Number(arr[1]);
2175
+ if (!Number.isFinite(from))
2176
+ from = min;
2177
+ if (!Number.isFinite(to))
2178
+ to = max;
2179
+ from = Math.min(Math.max(from, min), max);
2180
+ to = Math.min(Math.max(to, min), max);
2181
+ return from <= to ? [from, to] : [to, from];
2182
+ }
2183
+ /** A range is "active" only when it is narrower than the full bounds. */
2184
+ isRangeActive(value, cfg) {
2185
+ const [min, max] = this.rangeBounds(cfg);
2186
+ const [from, to] = this.normalizeRangeInitial(value, cfg);
2187
+ return from > min || to < max;
2188
+ }
2189
+ // ---------------------------------------------------------------------------
2150
2190
  // boolean-multiselect helpers (UI value = option objects, output = boolean[])
2151
2191
  // ---------------------------------------------------------------------------
2152
2192
  coerceBool(x) {
@@ -2233,6 +2273,13 @@ class TableCaptionComponent {
2233
2273
  out[key] = true;
2234
2274
  continue;
2235
2275
  }
2276
+ if (t === 'range') {
2277
+ if (this.isRangeActive(v, f)) {
2278
+ const [min, max] = this.normalizeRangeInitial(v, f);
2279
+ out[key] = { type: 'range', min, max };
2280
+ }
2281
+ continue;
2282
+ }
2236
2283
  // dropdown or text:
2237
2284
  if (v != null && v !== '')
2238
2285
  out[key] = v;
@@ -2280,6 +2327,17 @@ class TableCaptionComponent {
2280
2327
  patch[f.key] = !!patch[f.key];
2281
2328
  continue;
2282
2329
  }
2330
+ if (t === 'range') {
2331
+ // persisted payload is { type:'range', min, max }; map -> [from, to]
2332
+ const stored = patch[f.key];
2333
+ if (stored == null) {
2334
+ delete patch[f.key];
2335
+ }
2336
+ else {
2337
+ patch[f.key] = this.normalizeRangeInitial([stored?.min, stored?.max], f);
2338
+ }
2339
+ continue;
2340
+ }
2283
2341
  }
2284
2342
  this.filtersForm.patchValue(patch, { emitEvent: false });
2285
2343
  }
@@ -2351,7 +2409,11 @@ class TableCaptionComponent {
2351
2409
  // ---------------------------------------------------------------------------
2352
2410
  hasFormValues() {
2353
2411
  const v = this.filtersForm?.value ?? {};
2354
- return Object.values(v).some((x) => {
2412
+ const cfgByKey = new Map(this.normalizeFilters(this.filters).map((f) => [f.key, f]));
2413
+ return Object.entries(v).some(([key, x]) => {
2414
+ const cfg = cfgByKey.get(key);
2415
+ if (cfg?.type === 'range')
2416
+ return this.isRangeActive(x, cfg);
2355
2417
  if (x == null || x === '')
2356
2418
  return false;
2357
2419
  if (Array.isArray(x))
@@ -2364,6 +2426,15 @@ class TableCaptionComponent {
2364
2426
  clearSelectFilter(key) {
2365
2427
  this.filtersForm.get(key)?.setValue([], { emitEvent: true });
2366
2428
  }
2429
+ /** True when a range control has been narrowed below its full bounds. */
2430
+ isRangeControlActive(control) {
2431
+ return this.isRangeActive(this.filtersForm.get(control.key)?.value, control);
2432
+ }
2433
+ /** Reset a range filter back to its full [min, max] bounds. */
2434
+ resetRangeFilter(control) {
2435
+ const [min, max] = this.rangeBounds(control);
2436
+ this.filtersForm.get(control.key)?.setValue([min, max], { emitEvent: true });
2437
+ }
2367
2438
  resetFilters() {
2368
2439
  this.filtersForm.reset({}, { emitEvent: true });
2369
2440
  localStorage.removeItem(this.FILTER_KEY);
@@ -2390,7 +2461,7 @@ class TableCaptionComponent {
2390
2461
  .join(', ');
2391
2462
  }
2392
2463
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: TableCaptionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2393
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: TableCaptionComponent, isStandalone: true, selector: "table-caption", inputs: { tableConfiguration: "tableConfiguration", columns: "columns", selectedItems: "selectedItems", filters: "filters", filterValidValues: "filterValidValues" }, outputs: { applyFiltersEvent: "applyFiltersEvent", applyColumnsEvent: "applyColumnsEvent", searchChange: "searchChange", actionClick: "actionClick" }, viewQueries: [{ propertyName: "filtersPopover", first: true, predicate: ["filtersPopover"], descendants: true }, { propertyName: "columnsPopover", first: true, predicate: ["columnsPopover"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"flex justify-content-between border-bottom-1 border-300 p-2\">\n <!-- Left: Tabs + Global actions -->\n <div class=\"flex align-items-center gap-2\">\n <phoenix-data-table-tabs\n [attr.data-cy]=\"'table-select-button-' + (tableConfiguration?.tabs?.key ?? 'tabs')\"\n [actions]=\"tableConfiguration?.tabs\"\n (actionClick)=\"actionClick.emit($event)\"\n />\n\n @for (action of (tableConfiguration?.globalActions ?? []); track action?.key ?? $index) {\n <phoenix-data-table-action\n [actionConfig]=\"action\"\n (actionClick)=\"actionClick.emit($event)\"\n />\n }\n </div>\n\n <!-- Right: caption filters + icons + search + more -->\n <div class=\"flex align-items-center gap-2\">\n <!-- Filters in caption row -->\n @for (control of (filters ?? []); track control.key) {\n @if (control.isInCaption) {\n @switch (control.type ?? (control.options?.length ? 'dropdown' : 'text')) {\n @case ('dropdown') {\n <p-select\n class=\"w-12rem\"\n [options]=\"control.options ?? []\"\n [optionLabel]=\"control.optionLabel ?? 'label'\"\n [optionValue]=\"control.optionValue ?? 'key'\"\n [formControl]=\"$any(filtersForm.get(control.key))\"\n [showClear]=\"true\"\n placeholder=\"{{ control.label | translate }}\"\n (onClear)=\"filtersForm.get(control.key)?.setValue('')\"\n />\n }\n\n @case ('multiselect') {\n <p-multiselect\n class=\"w-12rem\"\n [options]=\"control.options ?? []\"\n [optionLabel]=\"control.optionLabel ?? 'label'\"\n [optionValue]=\"control.optionValue ?? 'key'\"\n [formControl]=\"$any(filtersForm.get(control.key))\"\n [showClear]=\"true\"\n placeholder=\"{{ control.label | translate }}\"\n (onClear)=\"clearSelectFilter(control.key)\"\n />\n }\n\n @case ('boolean-multiselect') {\n <p-multiselect\n class=\"w-12rem\"\n [options]=\"control.options ?? []\"\n [optionLabel]=\"control.optionLabel ?? 'label'\"\n [formControl]=\"$any(filtersForm.get(control.key))\"\n [showClear]=\"true\"\n placeholder=\"{{ control.label | translate }}\"\n (onClear)=\"clearSelectFilter(control.key)\"\n >\n <ng-template pTemplate=\"selectedItems\" let-value>\n @if ((value?.length ?? 0) === 0) {\n <span class=\"p-2 text-500\">{{ control.label | translate }}</span>\n } @else {\n <span class=\"p-2\">{{ getSelectedLabels(value, control) }}</span>\n }\n </ng-template>\n\n <ng-template pTemplate=\"item\" let-item>\n <span>{{ item?.[control.optionLabel ?? 'label'] }}</span>\n </ng-template>\n </p-multiselect>\n }\n\n @case ('checkbox') {\n <p-checkbox binary=\"true\" [formControl]=\"$any(filtersForm.get(control.key))\" />\n }\n\n @default {\n <input\n class=\"w-12rem\"\n pInputText\n [formControl]=\"$any(filtersForm.get(control.key))\"\n placeholder=\"{{ control.label | translate }}\"\n />\n }\n }\n }\n }\n\n <!-- Filter icon -->\n @if (tableConfiguration?.hasFilter) {\n @if (hasFormValues()) {\n <p-overlaybadge class=\"p-2\" severity=\"danger\">\n <span pRipple class=\"cursor-pointer\" (click)=\"filtersPopover?.toggle($event)\">\n <i class=\"pi pi-filter\"></i>\n </span>\n </p-overlaybadge>\n } @else {\n <span pRipple class=\"cursor-pointer p-2\" (click)=\"filtersPopover?.toggle($event)\">\n <i class=\"pi pi-filter\"></i>\n </span>\n }\n }\n\n <!-- Columns icon -->\n @if (tableConfiguration?.hasColumns) {\n @if (columnsChanged) {\n <p-overlaybadge class=\"p-2\" severity=\"danger\">\n <span pRipple class=\"cursor-pointer\" (click)=\"columnsPopover?.toggle($event)\">\n <i class=\"pi pi-sliders-v\"></i>\n </span>\n </p-overlaybadge>\n } @else {\n <span pRipple class=\"cursor-pointer p-2\" (click)=\"columnsPopover?.toggle($event)\">\n <i class=\"pi pi-sliders-v\"></i>\n </span>\n }\n }\n\n <!-- Search + More -->\n <div class=\"flex\">\n @if (tableConfiguration?.hasSearch) {\n <p-iconfield>\n <p-inputicon styleClass=\"pi pi-search\" />\n <input\n type=\"text\"\n pInputText\n (input)=\"emitSearch($any($event.target).value)\"\n placeholder=\"{{ 'SEARCH_KEYWORD' | translate }}\"\n />\n </p-iconfield>\n }\n\n @if (tableConfiguration?.hasMore && tableConfiguration?.moreActions) {\n <phoenix-data-table-action\n [actionConfig]=\"tableConfiguration.moreActions\"\n (actionClick)=\"actionClick.emit($event)\"\n />\n }\n </div>\n </div>\n</div>\n\n<!-- Filters Popover -->\n<p-popover #filtersPopover>\n <div class=\"flex flex-column gap-3 w-25rem\">\n <div class=\"flex justify-content-between align-items-center\">\n <div class=\"text-lg font-bold\">{{ 'LABELS.FILTERS' | translate }}</div>\n <p-button\n icon=\"pi pi-refresh\"\n [text]=\"true\"\n label=\"{{ 'ACTION.CLEAR' | translate }}\"\n class=\"mr-2\"\n (click)=\"resetFilters()\"\n />\n </div>\n\n <form [formGroup]=\"filtersForm\">\n @for (control of (filters ?? []); track control.key) {\n @if (!control.isInCaption) {\n @switch (control.type ?? (control.options?.length ? 'dropdown' : 'text')) {\n @case ('checkbox') {\n <div class=\"mb-2\">\n <p-checkbox binary=\"true\" [formControlName]=\"control.key\" />\n <label class=\"ml-2\">{{ control.label | translate }}</label>\n </div>\n }\n\n @case ('dropdown') {\n <div class=\"mb-2\">\n <label class=\"mb-2 block\">{{ control.label | translate }}</label>\n <p-select\n class=\"w-full\"\n [options]=\"control.options ?? []\"\n [optionLabel]=\"control.optionLabel ?? 'label'\"\n [optionValue]=\"control.optionValue ?? 'key'\"\n [showClear]=\"true\"\n [formControlName]=\"control.key\"\n (onClear)=\"filtersForm.get(control.key)?.setValue('')\"\n />\n </div>\n }\n\n @case ('multiselect') {\n <div class=\"mb-2\">\n <p-floatlabel variant=\"on\">\n <p-multiselect\n class=\"w-full\"\n [options]=\"control.options ?? []\"\n [optionLabel]=\"control.optionLabel ?? 'label'\"\n [optionValue]=\"control.optionValue ?? 'key'\"\n [showClear]=\"true\"\n [formControlName]=\"control.key\"\n (onClear)=\"clearSelectFilter(control.key)\"\n />\n <label>{{ control.label | translate }}</label>\n </p-floatlabel>\n </div>\n }\n\n @case ('boolean-multiselect') {\n <div class=\"mb-2\">\n <p-floatlabel variant=\"on\">\n <p-multiselect\n class=\"w-full\"\n [options]=\"control.options ?? []\"\n [optionLabel]=\"control.optionLabel ?? 'label'\"\n [showClear]=\"true\"\n [formControlName]=\"control.key\"\n (onClear)=\"clearSelectFilter(control.key)\"\n >\n <ng-template pTemplate=\"selectedItems\" let-value>\n @if ((value?.length ?? 0) === 0) {\n <span class=\"p-2 text-500\">{{ control.label | translate }}</span>\n } @else {\n <span class=\"p-2\">{{ getSelectedLabels(value, control) }}</span>\n }\n </ng-template>\n\n <ng-template pTemplate=\"item\" let-item>\n <span>{{ item?.[control.optionLabel ?? 'label'] }}</span>\n </ng-template>\n </p-multiselect>\n <label>{{ control.label | translate }}</label>\n </p-floatlabel>\n </div>\n }\n\n @default {\n <div class=\"mb-2\">\n <label class=\"mb-2 block\">{{ control.label | translate }}</label>\n <input\n class=\"w-full\"\n pInputText\n [formControlName]=\"control.key\"\n placeholder=\"{{ control.label | translate }}\"\n />\n </div>\n }\n }\n }\n }\n </form>\n </div>\n</p-popover>\n\n<!-- Columns Popover -->\n<p-popover #columnsPopover>\n <div class=\"flex flex-column gap-3 w-25rem\">\n <div class=\"flex justify-content-between align-items-center\">\n <div class=\"text-lg font-bold\">{{ 'LABELS.COLUMNS' | translate }}</div>\n <p-button\n icon=\"pi pi-eye\"\n [text]=\"true\"\n label=\"{{ 'ACTION.SHOW_ALL' | translate }}\"\n class=\"mr-2\"\n (click)=\"resetColumns()\"\n />\n </div>\n\n <p-listbox\n [options]=\"columns\"\n [ngModel]=\"_selectedColumns\"\n (ngModelChange)=\"onColumnSelectionChange($event)\"\n [multiple]=\"true\"\n [metaKeySelection]=\"false\"\n [listStyle]=\"{ 'max-height': '420px' }\"\n [attr.data-cy]=\"'table-list-box'\"\n >\n <ng-template pTemplate=\"item\" let-item>\n @if (item | isSelected : selectedColumns) {\n <i class=\"pi pi-eye\"></i>\n } @else {\n <i class=\"pi pi-eye-slash\"></i>\n }\n <span class=\"ml-2\">{{ item.header | translate }}</span>\n </ng-template>\n </p-listbox>\n </div>\n</p-popover>", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i3$2.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { kind: "directive", type: i4.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i3.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i3$4.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i5$2.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "styleClass", "panelStyle", "panelStyleClass", "inputId", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "dataKey", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "showClear", "autofocus", "placeholder", "options", "filterValue", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect", "size", "variant", "fluid", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i3$3.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: InputIconModule }, { kind: "component", type: i5.InputIcon, selector: "p-inputicon, p-inputIcon", inputs: ["hostName", "styleClass"] }, { kind: "ngmodule", type: IconFieldModule }, { kind: "component", type: i4$5.IconField, selector: "p-iconfield, p-iconField, p-icon-field", inputs: ["hostName", "iconPosition", "styleClass"] }, { kind: "ngmodule", type: ListboxModule }, { kind: "component", type: i10.Listbox, selector: "p-listbox, p-listBox, p-list-box", inputs: ["hostName", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "ariaLabel", "selectOnFocus", "searchLocale", "focusOnHover", "filterMessage", "filterFields", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "scrollHeight", "tabindex", "multiple", "styleClass", "listStyle", "listStyleClass", "readonly", "checkbox", "filter", "filterBy", "filterMatchMode", "filterLocale", "metaKeySelection", "dataKey", "showToggleAll", "optionLabel", "optionValue", "optionGroupChildren", "optionGroupLabel", "optionDisabled", "ariaFilterLabel", "filterPlaceHolder", "emptyFilterMessage", "emptyMessage", "group", "options", "filterValue", "selectAll", "striped", "highlightOnSelect", "checkmark", "dragdrop", "dropListData", "fluid"], outputs: ["onChange", "onClick", "onDblClick", "onFilter", "onFocus", "onBlur", "onSelectAllChange", "onLazyLoad", "onDrop"] }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i4$4.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["hostName", "value", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "inputStyle", "styleClass", "inputClass", "indeterminate", "formControl", "checkboxIcon", "readonly", "autofocus", "trueValue", "falseValue", "variant", "size"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "ngmodule", type: OverlayBadgeModule }, { kind: "component", type: i12.OverlayBadge, selector: "p-overlayBadge, p-overlay-badge, p-overlaybadge", inputs: ["styleClass", "style", "badgeSize", "severity", "value", "badgeDisabled", "size"] }, { kind: "ngmodule", type: RippleModule }, { kind: "directive", type: i13.Ripple, selector: "[pRipple]" }, { kind: "ngmodule", type: FloatLabelModule }, { kind: "component", type: i14.FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: PhoenixDataTableActionComponent, selector: "phoenix-data-table-action", inputs: ["actionConfig", "rowData"], outputs: ["actionClick"] }, { kind: "component", type: PhoenixDataTableTabsComponent, selector: "phoenix-data-table-tabs", inputs: ["actions"], outputs: ["actionClick"] }, { kind: "pipe", type: i4$2.TranslatePipe, name: "translate" }, { kind: "pipe", type: IsSelectedPipe, name: "isSelected" }] });
2464
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: TableCaptionComponent, isStandalone: true, selector: "table-caption", inputs: { tableConfiguration: "tableConfiguration", columns: "columns", selectedItems: "selectedItems", filters: "filters", filterValidValues: "filterValidValues" }, outputs: { applyFiltersEvent: "applyFiltersEvent", applyColumnsEvent: "applyColumnsEvent", searchChange: "searchChange", actionClick: "actionClick" }, viewQueries: [{ propertyName: "filtersPopover", first: true, predicate: ["filtersPopover"], descendants: true }, { propertyName: "columnsPopover", first: true, predicate: ["columnsPopover"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"flex justify-content-between border-bottom-1 border-300 p-2\">\n <!-- Left: Tabs + Global actions -->\n <div class=\"flex align-items-center gap-2\">\n <phoenix-data-table-tabs\n [attr.data-cy]=\"'table-select-button-' + (tableConfiguration?.tabs?.key ?? 'tabs')\"\n [actions]=\"tableConfiguration?.tabs\"\n (actionClick)=\"actionClick.emit($event)\"\n />\n\n @for (action of (tableConfiguration?.globalActions ?? []); track action?.key ?? $index) {\n <phoenix-data-table-action\n [actionConfig]=\"action\"\n (actionClick)=\"actionClick.emit($event)\"\n />\n }\n </div>\n\n <!-- Right: caption filters + icons + search + more -->\n <div class=\"flex align-items-center gap-2\">\n <!-- Filters in caption row -->\n @for (control of (filters ?? []); track control.key) {\n @if (control.isInCaption) {\n @switch (control.type ?? (control.options?.length ? 'dropdown' : 'text')) {\n @case ('dropdown') {\n <p-select\n class=\"w-12rem\"\n [options]=\"control.options ?? []\"\n [optionLabel]=\"control.optionLabel ?? 'label'\"\n [optionValue]=\"control.optionValue ?? 'key'\"\n [formControl]=\"$any(filtersForm.get(control.key))\"\n [showClear]=\"true\"\n placeholder=\"{{ control.label | translate }}\"\n (onClear)=\"filtersForm.get(control.key)?.setValue('')\"\n />\n }\n\n @case ('multiselect') {\n <p-multiselect\n class=\"w-12rem\"\n [options]=\"control.options ?? []\"\n [optionLabel]=\"control.optionLabel ?? 'label'\"\n [optionValue]=\"control.optionValue ?? 'key'\"\n [formControl]=\"$any(filtersForm.get(control.key))\"\n [showClear]=\"true\"\n placeholder=\"{{ control.label | translate }}\"\n (onClear)=\"clearSelectFilter(control.key)\"\n />\n }\n\n @case ('boolean-multiselect') {\n <p-multiselect\n class=\"w-12rem\"\n [options]=\"control.options ?? []\"\n [optionLabel]=\"control.optionLabel ?? 'label'\"\n [formControl]=\"$any(filtersForm.get(control.key))\"\n [showClear]=\"true\"\n placeholder=\"{{ control.label | translate }}\"\n (onClear)=\"clearSelectFilter(control.key)\"\n >\n <ng-template pTemplate=\"selectedItems\" let-value>\n @if ((value?.length ?? 0) === 0) {\n <span class=\"p-2 text-500\">{{ control.label | translate }}</span>\n } @else {\n <span class=\"p-2\">{{ getSelectedLabels(value, control) }}</span>\n }\n </ng-template>\n\n <ng-template pTemplate=\"item\" let-item>\n <span>{{ item?.[control.optionLabel ?? 'label'] }}</span>\n </ng-template>\n </p-multiselect>\n }\n\n @case ('checkbox') {\n <p-checkbox binary=\"true\" [formControl]=\"$any(filtersForm.get(control.key))\" />\n }\n\n @default {\n <input\n class=\"w-12rem\"\n pInputText\n [formControl]=\"$any(filtersForm.get(control.key))\"\n placeholder=\"{{ control.label | translate }}\"\n />\n }\n }\n }\n }\n\n <!-- Filter icon -->\n @if (tableConfiguration?.hasFilter) {\n @if (hasFormValues()) {\n <p-overlaybadge class=\"p-2\" severity=\"danger\">\n <span pRipple class=\"cursor-pointer\" (click)=\"filtersPopover?.toggle($event)\">\n <i class=\"pi pi-filter\"></i>\n </span>\n </p-overlaybadge>\n } @else {\n <span pRipple class=\"cursor-pointer p-2\" (click)=\"filtersPopover?.toggle($event)\">\n <i class=\"pi pi-filter\"></i>\n </span>\n }\n }\n\n <!-- Columns icon -->\n @if (tableConfiguration?.hasColumns) {\n @if (columnsChanged) {\n <p-overlaybadge class=\"p-2\" severity=\"danger\">\n <span pRipple class=\"cursor-pointer\" (click)=\"columnsPopover?.toggle($event)\">\n <i class=\"pi pi-sliders-v\"></i>\n </span>\n </p-overlaybadge>\n } @else {\n <span pRipple class=\"cursor-pointer p-2\" (click)=\"columnsPopover?.toggle($event)\">\n <i class=\"pi pi-sliders-v\"></i>\n </span>\n }\n }\n\n <!-- Search + More -->\n <div class=\"flex\">\n @if (tableConfiguration?.hasSearch) {\n <p-iconfield>\n <p-inputicon styleClass=\"pi pi-search\" />\n <input\n type=\"text\"\n pInputText\n (input)=\"emitSearch($any($event.target).value)\"\n placeholder=\"{{ 'SEARCH_KEYWORD' | translate }}\"\n />\n </p-iconfield>\n }\n\n @if (tableConfiguration?.hasMore && tableConfiguration?.moreActions) {\n <phoenix-data-table-action\n [actionConfig]=\"tableConfiguration.moreActions\"\n (actionClick)=\"actionClick.emit($event)\"\n />\n }\n </div>\n </div>\n</div>\n\n<!-- Filters Popover -->\n<p-popover #filtersPopover>\n <div class=\"flex flex-column gap-3 w-25rem\">\n <div class=\"flex justify-content-between align-items-center\">\n <div class=\"text-lg font-bold\">{{ 'LABELS.FILTERS' | translate }}</div>\n <p-button\n icon=\"pi pi-refresh\"\n [text]=\"true\"\n label=\"{{ 'ACTION.CLEAR' | translate }}\"\n class=\"mr-2\"\n (click)=\"resetFilters()\"\n />\n </div>\n\n <form [formGroup]=\"filtersForm\">\n @for (control of (filters ?? []); track control.key) {\n @if (!control.isInCaption) {\n @switch (control.type ?? (control.options?.length ? 'dropdown' : 'text')) {\n @case ('checkbox') {\n <div class=\"mb-2\">\n <p-checkbox binary=\"true\" [formControlName]=\"control.key\" />\n <label class=\"ml-2\">{{ control.label | translate }}</label>\n </div>\n }\n\n @case ('dropdown') {\n <div class=\"mb-2\">\n <label class=\"mb-2 block\">{{ control.label | translate }}</label>\n <p-select\n class=\"w-full\"\n [options]=\"control.options ?? []\"\n [optionLabel]=\"control.optionLabel ?? 'label'\"\n [optionValue]=\"control.optionValue ?? 'key'\"\n [showClear]=\"true\"\n [formControlName]=\"control.key\"\n (onClear)=\"filtersForm.get(control.key)?.setValue('')\"\n />\n </div>\n }\n\n @case ('multiselect') {\n <div class=\"mb-2\">\n <p-floatlabel variant=\"on\">\n <p-multiselect\n class=\"w-full\"\n [options]=\"control.options ?? []\"\n [optionLabel]=\"control.optionLabel ?? 'label'\"\n [optionValue]=\"control.optionValue ?? 'key'\"\n [showClear]=\"true\"\n [formControlName]=\"control.key\"\n (onClear)=\"clearSelectFilter(control.key)\"\n />\n <label>{{ control.label | translate }}</label>\n </p-floatlabel>\n </div>\n }\n\n @case ('range') {\n <div class=\"mb-2 px-3 py-2\">\n <label class=\"block mb-2\">{{ control.label | translate }}</label>\n <div class=\"flex justify-content-between text-sm text-600 mb-2\">\n <span>{{ filtersForm.get(control.key)?.value?.[0] ?? control.min }}</span>\n <span>{{ filtersForm.get(control.key)?.value?.[1] ?? control.max }}</span>\n </div>\n <div class=\"flex align-items-center gap-2\">\n <div class=\"flex-1 px-2\">\n <p-slider\n class=\"w-full\"\n [range]=\"true\"\n [min]=\"control.min ?? 0\"\n [max]=\"control.max ?? 100\"\n [step]=\"control.step ?? 1\"\n [formControlName]=\"control.key\"\n />\n </div>\n <p-button\n icon=\"pi pi-times\"\n [text]=\"true\"\n [rounded]=\"true\"\n size=\"small\"\n [disabled]=\"!isRangeControlActive(control)\"\n (click)=\"resetRangeFilter(control)\"\n />\n </div>\n </div>\n }\n\n @case ('boolean-multiselect') {\n <div class=\"mb-2\">\n <p-floatlabel variant=\"on\">\n <p-multiselect\n class=\"w-full\"\n [options]=\"control.options ?? []\"\n [optionLabel]=\"control.optionLabel ?? 'label'\"\n [showClear]=\"true\"\n [formControlName]=\"control.key\"\n (onClear)=\"clearSelectFilter(control.key)\"\n >\n <ng-template pTemplate=\"selectedItems\" let-value>\n @if ((value?.length ?? 0) === 0) {\n <span class=\"p-2 text-500\">{{ control.label | translate }}</span>\n } @else {\n <span class=\"p-2\">{{ getSelectedLabels(value, control) }}</span>\n }\n </ng-template>\n\n <ng-template pTemplate=\"item\" let-item>\n <span>{{ item?.[control.optionLabel ?? 'label'] }}</span>\n </ng-template>\n </p-multiselect>\n <label>{{ control.label | translate }}</label>\n </p-floatlabel>\n </div>\n }\n\n @default {\n <div class=\"mb-2\">\n <label class=\"mb-2 block\">{{ control.label | translate }}</label>\n <input\n class=\"w-full\"\n pInputText\n [formControlName]=\"control.key\"\n placeholder=\"{{ control.label | translate }}\"\n />\n </div>\n }\n }\n }\n }\n </form>\n </div>\n</p-popover>\n\n<!-- Columns Popover -->\n<p-popover #columnsPopover>\n <div class=\"flex flex-column gap-3 w-25rem\">\n <div class=\"flex justify-content-between align-items-center\">\n <div class=\"text-lg font-bold\">{{ 'LABELS.COLUMNS' | translate }}</div>\n <p-button\n icon=\"pi pi-eye\"\n [text]=\"true\"\n label=\"{{ 'ACTION.SHOW_ALL' | translate }}\"\n class=\"mr-2\"\n (click)=\"resetColumns()\"\n />\n </div>\n\n <p-listbox\n [options]=\"columns\"\n [ngModel]=\"_selectedColumns\"\n (ngModelChange)=\"onColumnSelectionChange($event)\"\n [multiple]=\"true\"\n [metaKeySelection]=\"false\"\n [listStyle]=\"{ 'max-height': '420px' }\"\n [attr.data-cy]=\"'table-list-box'\"\n >\n <ng-template pTemplate=\"item\" let-item>\n @if (item | isSelected : selectedColumns) {\n <i class=\"pi pi-eye\"></i>\n } @else {\n <i class=\"pi pi-eye-slash\"></i>\n }\n <span class=\"ml-2\">{{ item.header | translate }}</span>\n </ng-template>\n </p-listbox>\n </div>\n</p-popover>", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i3$2.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { kind: "directive", type: i4.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i3.Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: SelectModule }, { kind: "component", type: i3$4.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i5$2.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "styleClass", "panelStyle", "panelStyleClass", "inputId", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "dataKey", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "showClear", "autofocus", "placeholder", "options", "filterValue", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect", "size", "variant", "fluid", "appendTo"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i3$3.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pSize", "variant", "fluid", "invalid"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: InputIconModule }, { kind: "component", type: i5.InputIcon, selector: "p-inputicon, p-inputIcon", inputs: ["hostName", "styleClass"] }, { kind: "ngmodule", type: IconFieldModule }, { kind: "component", type: i4$5.IconField, selector: "p-iconfield, p-iconField, p-icon-field", inputs: ["hostName", "iconPosition", "styleClass"] }, { kind: "ngmodule", type: ListboxModule }, { kind: "component", type: i10.Listbox, selector: "p-listbox, p-listBox, p-list-box", inputs: ["hostName", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "ariaLabel", "selectOnFocus", "searchLocale", "focusOnHover", "filterMessage", "filterFields", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "scrollHeight", "tabindex", "multiple", "styleClass", "listStyle", "listStyleClass", "readonly", "checkbox", "filter", "filterBy", "filterMatchMode", "filterLocale", "metaKeySelection", "dataKey", "showToggleAll", "optionLabel", "optionValue", "optionGroupChildren", "optionGroupLabel", "optionDisabled", "ariaFilterLabel", "filterPlaceHolder", "emptyFilterMessage", "emptyMessage", "group", "options", "filterValue", "selectAll", "striped", "highlightOnSelect", "checkmark", "dragdrop", "dropListData", "fluid"], outputs: ["onChange", "onClick", "onDblClick", "onFilter", "onFocus", "onBlur", "onSelectAllChange", "onLazyLoad", "onDrop"] }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i4$4.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["hostName", "value", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "inputStyle", "styleClass", "inputClass", "indeterminate", "formControl", "checkboxIcon", "readonly", "autofocus", "trueValue", "falseValue", "variant", "size"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "ngmodule", type: SliderModule }, { kind: "component", type: i12.Slider, selector: "p-slider", inputs: ["animate", "min", "max", "orientation", "step", "range", "styleClass", "ariaLabel", "ariaLabelledBy", "tabindex", "autofocus"], outputs: ["onChange", "onSlideEnd"] }, { kind: "ngmodule", type: OverlayBadgeModule }, { kind: "component", type: i13.OverlayBadge, selector: "p-overlayBadge, p-overlay-badge, p-overlaybadge", inputs: ["styleClass", "style", "badgeSize", "severity", "value", "badgeDisabled", "size"] }, { kind: "ngmodule", type: RippleModule }, { kind: "directive", type: i14.Ripple, selector: "[pRipple]" }, { kind: "ngmodule", type: FloatLabelModule }, { kind: "component", type: i15.FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: PhoenixDataTableActionComponent, selector: "phoenix-data-table-action", inputs: ["actionConfig", "rowData"], outputs: ["actionClick"] }, { kind: "component", type: PhoenixDataTableTabsComponent, selector: "phoenix-data-table-tabs", inputs: ["actions"], outputs: ["actionClick"] }, { kind: "pipe", type: i4$2.TranslatePipe, name: "translate" }, { kind: "pipe", type: IsSelectedPipe, name: "isSelected" }] });
2394
2465
  }
2395
2466
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: TableCaptionComponent, decorators: [{
2396
2467
  type: Component,
@@ -2407,6 +2478,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2407
2478
  IconFieldModule,
2408
2479
  ListboxModule,
2409
2480
  CheckboxModule,
2481
+ SliderModule,
2410
2482
  OverlayBadgeModule,
2411
2483
  RippleModule,
2412
2484
  FloatLabelModule,
@@ -2414,7 +2486,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2414
2486
  PhoenixDataTableActionComponent,
2415
2487
  PhoenixDataTableTabsComponent,
2416
2488
  IsSelectedPipe,
2417
- ], template: "<div class=\"flex justify-content-between border-bottom-1 border-300 p-2\">\n <!-- Left: Tabs + Global actions -->\n <div class=\"flex align-items-center gap-2\">\n <phoenix-data-table-tabs\n [attr.data-cy]=\"'table-select-button-' + (tableConfiguration?.tabs?.key ?? 'tabs')\"\n [actions]=\"tableConfiguration?.tabs\"\n (actionClick)=\"actionClick.emit($event)\"\n />\n\n @for (action of (tableConfiguration?.globalActions ?? []); track action?.key ?? $index) {\n <phoenix-data-table-action\n [actionConfig]=\"action\"\n (actionClick)=\"actionClick.emit($event)\"\n />\n }\n </div>\n\n <!-- Right: caption filters + icons + search + more -->\n <div class=\"flex align-items-center gap-2\">\n <!-- Filters in caption row -->\n @for (control of (filters ?? []); track control.key) {\n @if (control.isInCaption) {\n @switch (control.type ?? (control.options?.length ? 'dropdown' : 'text')) {\n @case ('dropdown') {\n <p-select\n class=\"w-12rem\"\n [options]=\"control.options ?? []\"\n [optionLabel]=\"control.optionLabel ?? 'label'\"\n [optionValue]=\"control.optionValue ?? 'key'\"\n [formControl]=\"$any(filtersForm.get(control.key))\"\n [showClear]=\"true\"\n placeholder=\"{{ control.label | translate }}\"\n (onClear)=\"filtersForm.get(control.key)?.setValue('')\"\n />\n }\n\n @case ('multiselect') {\n <p-multiselect\n class=\"w-12rem\"\n [options]=\"control.options ?? []\"\n [optionLabel]=\"control.optionLabel ?? 'label'\"\n [optionValue]=\"control.optionValue ?? 'key'\"\n [formControl]=\"$any(filtersForm.get(control.key))\"\n [showClear]=\"true\"\n placeholder=\"{{ control.label | translate }}\"\n (onClear)=\"clearSelectFilter(control.key)\"\n />\n }\n\n @case ('boolean-multiselect') {\n <p-multiselect\n class=\"w-12rem\"\n [options]=\"control.options ?? []\"\n [optionLabel]=\"control.optionLabel ?? 'label'\"\n [formControl]=\"$any(filtersForm.get(control.key))\"\n [showClear]=\"true\"\n placeholder=\"{{ control.label | translate }}\"\n (onClear)=\"clearSelectFilter(control.key)\"\n >\n <ng-template pTemplate=\"selectedItems\" let-value>\n @if ((value?.length ?? 0) === 0) {\n <span class=\"p-2 text-500\">{{ control.label | translate }}</span>\n } @else {\n <span class=\"p-2\">{{ getSelectedLabels(value, control) }}</span>\n }\n </ng-template>\n\n <ng-template pTemplate=\"item\" let-item>\n <span>{{ item?.[control.optionLabel ?? 'label'] }}</span>\n </ng-template>\n </p-multiselect>\n }\n\n @case ('checkbox') {\n <p-checkbox binary=\"true\" [formControl]=\"$any(filtersForm.get(control.key))\" />\n }\n\n @default {\n <input\n class=\"w-12rem\"\n pInputText\n [formControl]=\"$any(filtersForm.get(control.key))\"\n placeholder=\"{{ control.label | translate }}\"\n />\n }\n }\n }\n }\n\n <!-- Filter icon -->\n @if (tableConfiguration?.hasFilter) {\n @if (hasFormValues()) {\n <p-overlaybadge class=\"p-2\" severity=\"danger\">\n <span pRipple class=\"cursor-pointer\" (click)=\"filtersPopover?.toggle($event)\">\n <i class=\"pi pi-filter\"></i>\n </span>\n </p-overlaybadge>\n } @else {\n <span pRipple class=\"cursor-pointer p-2\" (click)=\"filtersPopover?.toggle($event)\">\n <i class=\"pi pi-filter\"></i>\n </span>\n }\n }\n\n <!-- Columns icon -->\n @if (tableConfiguration?.hasColumns) {\n @if (columnsChanged) {\n <p-overlaybadge class=\"p-2\" severity=\"danger\">\n <span pRipple class=\"cursor-pointer\" (click)=\"columnsPopover?.toggle($event)\">\n <i class=\"pi pi-sliders-v\"></i>\n </span>\n </p-overlaybadge>\n } @else {\n <span pRipple class=\"cursor-pointer p-2\" (click)=\"columnsPopover?.toggle($event)\">\n <i class=\"pi pi-sliders-v\"></i>\n </span>\n }\n }\n\n <!-- Search + More -->\n <div class=\"flex\">\n @if (tableConfiguration?.hasSearch) {\n <p-iconfield>\n <p-inputicon styleClass=\"pi pi-search\" />\n <input\n type=\"text\"\n pInputText\n (input)=\"emitSearch($any($event.target).value)\"\n placeholder=\"{{ 'SEARCH_KEYWORD' | translate }}\"\n />\n </p-iconfield>\n }\n\n @if (tableConfiguration?.hasMore && tableConfiguration?.moreActions) {\n <phoenix-data-table-action\n [actionConfig]=\"tableConfiguration.moreActions\"\n (actionClick)=\"actionClick.emit($event)\"\n />\n }\n </div>\n </div>\n</div>\n\n<!-- Filters Popover -->\n<p-popover #filtersPopover>\n <div class=\"flex flex-column gap-3 w-25rem\">\n <div class=\"flex justify-content-between align-items-center\">\n <div class=\"text-lg font-bold\">{{ 'LABELS.FILTERS' | translate }}</div>\n <p-button\n icon=\"pi pi-refresh\"\n [text]=\"true\"\n label=\"{{ 'ACTION.CLEAR' | translate }}\"\n class=\"mr-2\"\n (click)=\"resetFilters()\"\n />\n </div>\n\n <form [formGroup]=\"filtersForm\">\n @for (control of (filters ?? []); track control.key) {\n @if (!control.isInCaption) {\n @switch (control.type ?? (control.options?.length ? 'dropdown' : 'text')) {\n @case ('checkbox') {\n <div class=\"mb-2\">\n <p-checkbox binary=\"true\" [formControlName]=\"control.key\" />\n <label class=\"ml-2\">{{ control.label | translate }}</label>\n </div>\n }\n\n @case ('dropdown') {\n <div class=\"mb-2\">\n <label class=\"mb-2 block\">{{ control.label | translate }}</label>\n <p-select\n class=\"w-full\"\n [options]=\"control.options ?? []\"\n [optionLabel]=\"control.optionLabel ?? 'label'\"\n [optionValue]=\"control.optionValue ?? 'key'\"\n [showClear]=\"true\"\n [formControlName]=\"control.key\"\n (onClear)=\"filtersForm.get(control.key)?.setValue('')\"\n />\n </div>\n }\n\n @case ('multiselect') {\n <div class=\"mb-2\">\n <p-floatlabel variant=\"on\">\n <p-multiselect\n class=\"w-full\"\n [options]=\"control.options ?? []\"\n [optionLabel]=\"control.optionLabel ?? 'label'\"\n [optionValue]=\"control.optionValue ?? 'key'\"\n [showClear]=\"true\"\n [formControlName]=\"control.key\"\n (onClear)=\"clearSelectFilter(control.key)\"\n />\n <label>{{ control.label | translate }}</label>\n </p-floatlabel>\n </div>\n }\n\n @case ('boolean-multiselect') {\n <div class=\"mb-2\">\n <p-floatlabel variant=\"on\">\n <p-multiselect\n class=\"w-full\"\n [options]=\"control.options ?? []\"\n [optionLabel]=\"control.optionLabel ?? 'label'\"\n [showClear]=\"true\"\n [formControlName]=\"control.key\"\n (onClear)=\"clearSelectFilter(control.key)\"\n >\n <ng-template pTemplate=\"selectedItems\" let-value>\n @if ((value?.length ?? 0) === 0) {\n <span class=\"p-2 text-500\">{{ control.label | translate }}</span>\n } @else {\n <span class=\"p-2\">{{ getSelectedLabels(value, control) }}</span>\n }\n </ng-template>\n\n <ng-template pTemplate=\"item\" let-item>\n <span>{{ item?.[control.optionLabel ?? 'label'] }}</span>\n </ng-template>\n </p-multiselect>\n <label>{{ control.label | translate }}</label>\n </p-floatlabel>\n </div>\n }\n\n @default {\n <div class=\"mb-2\">\n <label class=\"mb-2 block\">{{ control.label | translate }}</label>\n <input\n class=\"w-full\"\n pInputText\n [formControlName]=\"control.key\"\n placeholder=\"{{ control.label | translate }}\"\n />\n </div>\n }\n }\n }\n }\n </form>\n </div>\n</p-popover>\n\n<!-- Columns Popover -->\n<p-popover #columnsPopover>\n <div class=\"flex flex-column gap-3 w-25rem\">\n <div class=\"flex justify-content-between align-items-center\">\n <div class=\"text-lg font-bold\">{{ 'LABELS.COLUMNS' | translate }}</div>\n <p-button\n icon=\"pi pi-eye\"\n [text]=\"true\"\n label=\"{{ 'ACTION.SHOW_ALL' | translate }}\"\n class=\"mr-2\"\n (click)=\"resetColumns()\"\n />\n </div>\n\n <p-listbox\n [options]=\"columns\"\n [ngModel]=\"_selectedColumns\"\n (ngModelChange)=\"onColumnSelectionChange($event)\"\n [multiple]=\"true\"\n [metaKeySelection]=\"false\"\n [listStyle]=\"{ 'max-height': '420px' }\"\n [attr.data-cy]=\"'table-list-box'\"\n >\n <ng-template pTemplate=\"item\" let-item>\n @if (item | isSelected : selectedColumns) {\n <i class=\"pi pi-eye\"></i>\n } @else {\n <i class=\"pi pi-eye-slash\"></i>\n }\n <span class=\"ml-2\">{{ item.header | translate }}</span>\n </ng-template>\n </p-listbox>\n </div>\n</p-popover>" }]
2489
+ ], template: "<div class=\"flex justify-content-between border-bottom-1 border-300 p-2\">\n <!-- Left: Tabs + Global actions -->\n <div class=\"flex align-items-center gap-2\">\n <phoenix-data-table-tabs\n [attr.data-cy]=\"'table-select-button-' + (tableConfiguration?.tabs?.key ?? 'tabs')\"\n [actions]=\"tableConfiguration?.tabs\"\n (actionClick)=\"actionClick.emit($event)\"\n />\n\n @for (action of (tableConfiguration?.globalActions ?? []); track action?.key ?? $index) {\n <phoenix-data-table-action\n [actionConfig]=\"action\"\n (actionClick)=\"actionClick.emit($event)\"\n />\n }\n </div>\n\n <!-- Right: caption filters + icons + search + more -->\n <div class=\"flex align-items-center gap-2\">\n <!-- Filters in caption row -->\n @for (control of (filters ?? []); track control.key) {\n @if (control.isInCaption) {\n @switch (control.type ?? (control.options?.length ? 'dropdown' : 'text')) {\n @case ('dropdown') {\n <p-select\n class=\"w-12rem\"\n [options]=\"control.options ?? []\"\n [optionLabel]=\"control.optionLabel ?? 'label'\"\n [optionValue]=\"control.optionValue ?? 'key'\"\n [formControl]=\"$any(filtersForm.get(control.key))\"\n [showClear]=\"true\"\n placeholder=\"{{ control.label | translate }}\"\n (onClear)=\"filtersForm.get(control.key)?.setValue('')\"\n />\n }\n\n @case ('multiselect') {\n <p-multiselect\n class=\"w-12rem\"\n [options]=\"control.options ?? []\"\n [optionLabel]=\"control.optionLabel ?? 'label'\"\n [optionValue]=\"control.optionValue ?? 'key'\"\n [formControl]=\"$any(filtersForm.get(control.key))\"\n [showClear]=\"true\"\n placeholder=\"{{ control.label | translate }}\"\n (onClear)=\"clearSelectFilter(control.key)\"\n />\n }\n\n @case ('boolean-multiselect') {\n <p-multiselect\n class=\"w-12rem\"\n [options]=\"control.options ?? []\"\n [optionLabel]=\"control.optionLabel ?? 'label'\"\n [formControl]=\"$any(filtersForm.get(control.key))\"\n [showClear]=\"true\"\n placeholder=\"{{ control.label | translate }}\"\n (onClear)=\"clearSelectFilter(control.key)\"\n >\n <ng-template pTemplate=\"selectedItems\" let-value>\n @if ((value?.length ?? 0) === 0) {\n <span class=\"p-2 text-500\">{{ control.label | translate }}</span>\n } @else {\n <span class=\"p-2\">{{ getSelectedLabels(value, control) }}</span>\n }\n </ng-template>\n\n <ng-template pTemplate=\"item\" let-item>\n <span>{{ item?.[control.optionLabel ?? 'label'] }}</span>\n </ng-template>\n </p-multiselect>\n }\n\n @case ('checkbox') {\n <p-checkbox binary=\"true\" [formControl]=\"$any(filtersForm.get(control.key))\" />\n }\n\n @default {\n <input\n class=\"w-12rem\"\n pInputText\n [formControl]=\"$any(filtersForm.get(control.key))\"\n placeholder=\"{{ control.label | translate }}\"\n />\n }\n }\n }\n }\n\n <!-- Filter icon -->\n @if (tableConfiguration?.hasFilter) {\n @if (hasFormValues()) {\n <p-overlaybadge class=\"p-2\" severity=\"danger\">\n <span pRipple class=\"cursor-pointer\" (click)=\"filtersPopover?.toggle($event)\">\n <i class=\"pi pi-filter\"></i>\n </span>\n </p-overlaybadge>\n } @else {\n <span pRipple class=\"cursor-pointer p-2\" (click)=\"filtersPopover?.toggle($event)\">\n <i class=\"pi pi-filter\"></i>\n </span>\n }\n }\n\n <!-- Columns icon -->\n @if (tableConfiguration?.hasColumns) {\n @if (columnsChanged) {\n <p-overlaybadge class=\"p-2\" severity=\"danger\">\n <span pRipple class=\"cursor-pointer\" (click)=\"columnsPopover?.toggle($event)\">\n <i class=\"pi pi-sliders-v\"></i>\n </span>\n </p-overlaybadge>\n } @else {\n <span pRipple class=\"cursor-pointer p-2\" (click)=\"columnsPopover?.toggle($event)\">\n <i class=\"pi pi-sliders-v\"></i>\n </span>\n }\n }\n\n <!-- Search + More -->\n <div class=\"flex\">\n @if (tableConfiguration?.hasSearch) {\n <p-iconfield>\n <p-inputicon styleClass=\"pi pi-search\" />\n <input\n type=\"text\"\n pInputText\n (input)=\"emitSearch($any($event.target).value)\"\n placeholder=\"{{ 'SEARCH_KEYWORD' | translate }}\"\n />\n </p-iconfield>\n }\n\n @if (tableConfiguration?.hasMore && tableConfiguration?.moreActions) {\n <phoenix-data-table-action\n [actionConfig]=\"tableConfiguration.moreActions\"\n (actionClick)=\"actionClick.emit($event)\"\n />\n }\n </div>\n </div>\n</div>\n\n<!-- Filters Popover -->\n<p-popover #filtersPopover>\n <div class=\"flex flex-column gap-3 w-25rem\">\n <div class=\"flex justify-content-between align-items-center\">\n <div class=\"text-lg font-bold\">{{ 'LABELS.FILTERS' | translate }}</div>\n <p-button\n icon=\"pi pi-refresh\"\n [text]=\"true\"\n label=\"{{ 'ACTION.CLEAR' | translate }}\"\n class=\"mr-2\"\n (click)=\"resetFilters()\"\n />\n </div>\n\n <form [formGroup]=\"filtersForm\">\n @for (control of (filters ?? []); track control.key) {\n @if (!control.isInCaption) {\n @switch (control.type ?? (control.options?.length ? 'dropdown' : 'text')) {\n @case ('checkbox') {\n <div class=\"mb-2\">\n <p-checkbox binary=\"true\" [formControlName]=\"control.key\" />\n <label class=\"ml-2\">{{ control.label | translate }}</label>\n </div>\n }\n\n @case ('dropdown') {\n <div class=\"mb-2\">\n <label class=\"mb-2 block\">{{ control.label | translate }}</label>\n <p-select\n class=\"w-full\"\n [options]=\"control.options ?? []\"\n [optionLabel]=\"control.optionLabel ?? 'label'\"\n [optionValue]=\"control.optionValue ?? 'key'\"\n [showClear]=\"true\"\n [formControlName]=\"control.key\"\n (onClear)=\"filtersForm.get(control.key)?.setValue('')\"\n />\n </div>\n }\n\n @case ('multiselect') {\n <div class=\"mb-2\">\n <p-floatlabel variant=\"on\">\n <p-multiselect\n class=\"w-full\"\n [options]=\"control.options ?? []\"\n [optionLabel]=\"control.optionLabel ?? 'label'\"\n [optionValue]=\"control.optionValue ?? 'key'\"\n [showClear]=\"true\"\n [formControlName]=\"control.key\"\n (onClear)=\"clearSelectFilter(control.key)\"\n />\n <label>{{ control.label | translate }}</label>\n </p-floatlabel>\n </div>\n }\n\n @case ('range') {\n <div class=\"mb-2 px-3 py-2\">\n <label class=\"block mb-2\">{{ control.label | translate }}</label>\n <div class=\"flex justify-content-between text-sm text-600 mb-2\">\n <span>{{ filtersForm.get(control.key)?.value?.[0] ?? control.min }}</span>\n <span>{{ filtersForm.get(control.key)?.value?.[1] ?? control.max }}</span>\n </div>\n <div class=\"flex align-items-center gap-2\">\n <div class=\"flex-1 px-2\">\n <p-slider\n class=\"w-full\"\n [range]=\"true\"\n [min]=\"control.min ?? 0\"\n [max]=\"control.max ?? 100\"\n [step]=\"control.step ?? 1\"\n [formControlName]=\"control.key\"\n />\n </div>\n <p-button\n icon=\"pi pi-times\"\n [text]=\"true\"\n [rounded]=\"true\"\n size=\"small\"\n [disabled]=\"!isRangeControlActive(control)\"\n (click)=\"resetRangeFilter(control)\"\n />\n </div>\n </div>\n }\n\n @case ('boolean-multiselect') {\n <div class=\"mb-2\">\n <p-floatlabel variant=\"on\">\n <p-multiselect\n class=\"w-full\"\n [options]=\"control.options ?? []\"\n [optionLabel]=\"control.optionLabel ?? 'label'\"\n [showClear]=\"true\"\n [formControlName]=\"control.key\"\n (onClear)=\"clearSelectFilter(control.key)\"\n >\n <ng-template pTemplate=\"selectedItems\" let-value>\n @if ((value?.length ?? 0) === 0) {\n <span class=\"p-2 text-500\">{{ control.label | translate }}</span>\n } @else {\n <span class=\"p-2\">{{ getSelectedLabels(value, control) }}</span>\n }\n </ng-template>\n\n <ng-template pTemplate=\"item\" let-item>\n <span>{{ item?.[control.optionLabel ?? 'label'] }}</span>\n </ng-template>\n </p-multiselect>\n <label>{{ control.label | translate }}</label>\n </p-floatlabel>\n </div>\n }\n\n @default {\n <div class=\"mb-2\">\n <label class=\"mb-2 block\">{{ control.label | translate }}</label>\n <input\n class=\"w-full\"\n pInputText\n [formControlName]=\"control.key\"\n placeholder=\"{{ control.label | translate }}\"\n />\n </div>\n }\n }\n }\n }\n </form>\n </div>\n</p-popover>\n\n<!-- Columns Popover -->\n<p-popover #columnsPopover>\n <div class=\"flex flex-column gap-3 w-25rem\">\n <div class=\"flex justify-content-between align-items-center\">\n <div class=\"text-lg font-bold\">{{ 'LABELS.COLUMNS' | translate }}</div>\n <p-button\n icon=\"pi pi-eye\"\n [text]=\"true\"\n label=\"{{ 'ACTION.SHOW_ALL' | translate }}\"\n class=\"mr-2\"\n (click)=\"resetColumns()\"\n />\n </div>\n\n <p-listbox\n [options]=\"columns\"\n [ngModel]=\"_selectedColumns\"\n (ngModelChange)=\"onColumnSelectionChange($event)\"\n [multiple]=\"true\"\n [metaKeySelection]=\"false\"\n [listStyle]=\"{ 'max-height': '420px' }\"\n [attr.data-cy]=\"'table-list-box'\"\n >\n <ng-template pTemplate=\"item\" let-item>\n @if (item | isSelected : selectedColumns) {\n <i class=\"pi pi-eye\"></i>\n } @else {\n <i class=\"pi pi-eye-slash\"></i>\n }\n <span class=\"ml-2\">{{ item.header | translate }}</span>\n </ng-template>\n </p-listbox>\n </div>\n</p-popover>" }]
2418
2490
  }], propDecorators: { filtersPopover: [{
2419
2491
  type: ViewChild,
2420
2492
  args: ['filtersPopover']
@@ -2982,6 +3054,13 @@ class TableComponent {
2982
3054
  selectedColumnsInput = [];
2983
3055
  tableConfiguration;
2984
3056
  filters;
3057
+ /**
3058
+ * Filters passed down to table-caption.
3059
+ * Identical to `filters`, except range filters get their numeric bounds
3060
+ * (min/max) derived from the actual dataset so the slider reflects the
3061
+ * real values present in the table. Explicit min/max in config still win.
3062
+ */
3063
+ computedFilters = [];
2985
3064
  // ============================================================
2986
3065
  // OUTPUTS
2987
3066
  // ============================================================
@@ -3152,6 +3231,8 @@ class TableComponent {
3152
3231
  */
3153
3232
  set data(value) {
3154
3233
  this.originalData = value ?? [];
3234
+ // Recompute range-filter bounds from the new dataset.
3235
+ this.enrichRangeFilters();
3155
3236
  if (Object.keys(this.currentFilters).length > 0) {
3156
3237
  const validMap = this.getValidFilterValues();
3157
3238
  if (validMap) {
@@ -3185,6 +3266,10 @@ class TableComponent {
3185
3266
  ngOnChanges(changes) {
3186
3267
  // clear selection on inputs update (safe default behavior)
3187
3268
  this.selectedItems.set([]);
3269
+ // Keep computedFilters in sync when the filters config changes.
3270
+ if (changes['filters']) {
3271
+ this.enrichRangeFilters();
3272
+ }
3188
3273
  if (this.tableConfiguration?.key) {
3189
3274
  this.SORT_KEY = `sort_${this.tableConfiguration.key}`;
3190
3275
  }
@@ -3446,6 +3531,13 @@ class TableComponent {
3446
3531
  let hasStale = false;
3447
3532
  const result = {};
3448
3533
  for (const [key, filterValue] of Object.entries(this.currentFilters)) {
3534
+ // Range filters carry numeric bounds, not enumerable option values — never stale.
3535
+ if (filterValue &&
3536
+ typeof filterValue === 'object' &&
3537
+ !Array.isArray(filterValue) &&
3538
+ filterValue.type === 'range') {
3539
+ continue;
3540
+ }
3449
3541
  const values = Array.isArray(filterValue) ? filterValue : filterValue != null ? [filterValue] : [];
3450
3542
  if (!values.length)
3451
3543
  continue;
@@ -3501,6 +3593,16 @@ class TableComponent {
3501
3593
  (Array.isArray(filterValue) && filterValue.length === 0))
3502
3594
  return true;
3503
3595
  const itemValue = this.getNestedValue(item, key);
3596
+ // Range filter: { type: 'range', min, max } -> numeric between check
3597
+ if (filterValue &&
3598
+ typeof filterValue === 'object' &&
3599
+ !Array.isArray(filterValue) &&
3600
+ filterValue.type === 'range') {
3601
+ const num = Number(itemValue);
3602
+ if (!Number.isFinite(num))
3603
+ return false;
3604
+ return num >= filterValue.min && num <= filterValue.max;
3605
+ }
3504
3606
  // Ako je itemValue niz (kao u scopes)
3505
3607
  if (Array.isArray(itemValue)) {
3506
3608
  return filterValue.some((option) => {
@@ -3526,6 +3628,53 @@ class TableComponent {
3526
3628
  });
3527
3629
  });
3528
3630
  }
3631
+ // ============================================================
3632
+ // RANGE FILTER BOUNDS
3633
+ // ============================================================
3634
+ /**
3635
+ * Rebuild `computedFilters` from `filters`, deriving numeric bounds
3636
+ * (min/max) for every range filter from the current dataset.
3637
+ * An explicitly configured min/max always wins over the data-derived value.
3638
+ */
3639
+ enrichRangeFilters() {
3640
+ const list = Array.isArray(this.filters) ? this.filters : [];
3641
+ this.computedFilters = list.map((f) => {
3642
+ if (f?.type !== 'range')
3643
+ return f;
3644
+ const explicitMin = Number.isFinite(f.min) ? f.min : undefined;
3645
+ const explicitMax = Number.isFinite(f.max) ? f.max : undefined;
3646
+ // Both bounds provided by config -> nothing to compute.
3647
+ if (explicitMin !== undefined && explicitMax !== undefined)
3648
+ return f;
3649
+ const bounds = this.computeDataBounds(f.key);
3650
+ return {
3651
+ ...f,
3652
+ min: explicitMin ?? bounds.min,
3653
+ max: explicitMax ?? bounds.max,
3654
+ };
3655
+ });
3656
+ }
3657
+ /**
3658
+ * Min/max numeric bounds for a field across originalData.
3659
+ * Falls back to [0, 100] when no numeric values are present.
3660
+ */
3661
+ computeDataBounds(key) {
3662
+ let min = Infinity;
3663
+ let max = -Infinity;
3664
+ for (const item of this.originalData) {
3665
+ const num = Number(this.getNestedValue(item, key));
3666
+ if (!Number.isFinite(num))
3667
+ continue;
3668
+ if (num < min)
3669
+ min = num;
3670
+ if (num > max)
3671
+ max = num;
3672
+ }
3673
+ if (!Number.isFinite(min) || !Number.isFinite(max)) {
3674
+ return { min: 0, max: 100 };
3675
+ }
3676
+ return { min, max };
3677
+ }
3529
3678
  /**
3530
3679
  * Reads nested values using dot paths and unwraps `.key` when present.
3531
3680
  */
@@ -3675,7 +3824,7 @@ class TableComponent {
3675
3824
  });
3676
3825
  }
3677
3826
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: TableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3678
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: TableComponent, isStandalone: true, selector: "phoenix-table", inputs: { columns: "columns", selectedColumnsInput: "selectedColumnsInput", tableConfiguration: "tableConfiguration", filters: "filters", data: "data" }, outputs: { actionClick: "actionClick", rowSelection: "rowSelection", checkBoxSelection: "checkBoxSelection", saveColumns: "saveColumns" }, viewQueries: [{ propertyName: "dt", first: true, predicate: ["dt"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"border-1 border-round-sm border-300 border-round-md m-2\">\n @if (selectedItems().length === 0) {\n <table-caption\n [columns]=\"columns\"\n [tableConfiguration]=\"tableConfiguration\"\n [filters]=\"filters\"\n [selectedItems]=\"selectedItems()\"\n [filterValidValues]=\"filterValidValues\"\n (applyFiltersEvent)=\"applyFilters($event)\"\n (applyColumnsEvent)=\"applyColumns($event)\"\n (searchChange)=\"onSearch($event)\"\n (actionClick)=\"handleActionClick($event)\"\n ></table-caption>\n } @else {\n <div\n style=\"min-height: 40px; padding: 8px\"\n class=\"flex justify-content-between align-items-center border-bottom-1 border-300 pl-5 pr-5 text-sm text-500\"\n >\n <div>\n @if (tableConfiguration.selectionType === selectionTypeEnum.CHECKBOX) {\n <span>\n {{ selectedItems().length }}\n {{\n selectedItems().length === 1\n ? (\"LABELS.ITEM_SELECTED\" | translate)\n : (\"LABELS.ITEMS_SELECTED\" | translate)\n }}\n </span>\n }\n </div>\n\n <div>\n @for (\n action of tableConfiguration.bulkActions;\n track action?.key ?? $index\n ) {\n <phoenix-data-table-action\n [actionConfig]=\"action\"\n (actionClick)=\"\n handleActionClick({\n action: action,\n selectedItems: selectedItems(),\n });\n clearSelection()\n \"\n ></phoenix-data-table-action>\n }\n\n <button\n [attr.data-cy]=\"'clear-selection-button'\"\n class=\"p-button p-button-text p-button-plain\"\n (click)=\"clearSelection()\"\n aria-label=\"Clear Selection\"\n >\n <i class=\"pi pi-times\"></i>\n </button>\n </div>\n </div>\n }\n <div\n class=\"table-host\"\n [style.height]=\"tableConfiguration.scrollHeight ?? null\"\n >\n <p-table\n #dt\n [columns]=\"selectedColumns\"\n [value]=\"tableData\"\n [size]=\"'small'\"\n scrollable=\"true\"\n scrollHeight=\"flex\"\n [virtualScroll]=\"true\"\n [virtualScrollItemSize]=\"40\"\n [virtualScrollDelay]=\"80\"\n [totalRecords]=\"totalRecords\"\n [sortMode]=\"'multiple'\"\n [customSort]=\"true\"\n (sortFunction)=\"onCustomSort($event)\"\n [selection]=\"selectedItems()\"\n (selectionChange)=\"onSelectionChange($event)\"\n [resizableColumns]=\"true\"\n columnResizeMode=\"expand\"\n [loading]=\"initialSortLoading\"\n >\n <ng-template #header let-columns>\n <tr style=\"height: 40px\" class=\"dt-header\">\n @switch (tableConfiguration.selectionType) {\n @case (selectionTypeEnum.CHECKBOX) {\n <th class=\"custom-th\">\n <p-tableHeaderCheckbox\n [attr.data-cy]=\"'table-header-checkbox'\"\n ></p-tableHeaderCheckbox>\n </th>\n }\n @case (selectionTypeEnum.RADIO_BTN) {\n <th class=\"custom-th\"></th>\n }\n }\n @for (\n col of columns;\n track col.field ?? col.header ?? $index;\n let colIdx = $index\n ) {\n <th\n pResizableColumn\n class=\"custom-th text-primary font-bold\"\n [pSortableColumn]=\"col.field\"\n >\n {{ col.header | translate }}\n <p-sortIcon\n [field]=\"col.field\"\n [attr.data-cy]=\"'sort-button-' + col.header\"\n ></p-sortIcon>\n </th>\n }\n\n <th class=\"custom-th\"></th>\n </tr>\n </ng-template>\n\n <ng-template\n #body\n let-rowData\n let-columns=\"columns\"\n let-rowIndex=\"rowIndex\"\n >\n <tr>\n @switch (tableConfiguration.selectionType) {\n @case (selectionTypeEnum.CHECKBOX) {\n <td class=\"w-2rem\">\n <p-tableCheckbox\n [attr.data-cy]=\"\n 'table-row-' + selectionTypeEnum.CHECKBOX + '-' + rowIndex\n \"\n [disabled]=\"\n rowData?.canSelect !== undefined\n ? !rowData.canSelect\n : false\n \"\n [value]=\"rowData\"\n ></p-tableCheckbox>\n </td>\n }\n @case (selectionTypeEnum.RADIO_BTN) {\n <td>\n <p-tableRadioButton\n [value]=\"rowData\"\n [attr.data-cy]=\"\n 'table-row-' + selectionTypeEnum.RADIO_BTN + '-' + rowIndex\n \"\n ></p-tableRadioButton>\n </td>\n }\n }\n @for (\n col of columns;\n track col.field ?? col.header ?? $index;\n let i = $index\n ) {\n <td\n (click)=\"\n isColumnClickable(i) ? onRowClick($event, rowData) : null\n \"\n [ngClass]=\"{\n 'text-blue-500 underline cursor-pointer': isColumnClickable(i),\n }\"\n >\n @switch (col.columnType) {\n @case (columnTypeEnum.TAG) {\n @if (rowData[col.field]) {\n <div class=\"flex align-items-center gap-2\">\n <div\n class=\"border-round-md font-semibold\"\n [style]=\"{\n fontSize: '12px',\n padding: '3px 8px',\n width: 'fit-content',\n 'background-color':\n (rowData[col.field + 'Color'] || '#ccc') + '56',\n color: rowData[col.field + 'Color'],\n }\"\n >\n {{\n rowData[col.field]?.name ||\n (rowData[col.field] | translate)\n }}\n </div>\n @if (rowData[col.field + \"Tooltip\"]) {\n <i\n [class]=\"\n rowData[col.field + 'Icon'].class +\n ' cursor-pointer'\n \"\n [style]=\"rowData[col.field + 'Icon'].style\"\n [pTooltip]=\"rowData[col.field + 'Tooltip']\"\n tooltipPosition=\"top\"\n ></i>\n }\n </div>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.LIST_TAG) {\n @if (rowData[col.field]) {\n @for (item of rowData[col.field]; track $index) {\n <p-badge severity=\"warn\" class=\"mr-1\" [value]=\"item\" />\n }\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.OBJ_TAG) {\n @if (rowData[col.field]) {\n <p-tag\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.OBJ_TAG +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n [style]=\"{\n fontSize: '12px',\n padding: '3px 8px',\n width: 'fit-content',\n 'background-color':\n (rowData[col.field].color || '#ccc') + '56',\n color: rowData[col.field].color,\n }\"\n [value]=\"rowData[col.field]?.value | translate\"\n ></p-tag>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.PERSON) {\n @if (rowData[col.field]) {\n <p-avatar\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.PERSON +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n [label]=\"rowData[col.field]?.name | initials\"\n class=\"cursor-pointer\"\n [style]=\"{\n 'background-color': '#9c27b0',\n color: '#ffffff',\n 'font-size': '0.8rem!important',\n }\"\n shape=\"circle\"\n (click)=\"personPop.toggle($event)\"\n ></p-avatar>\n\n <p-popover #personPop [dismissable]=\"true\">\n <div>\n <span class=\"text-lg\">{{\n rowData[col.field].name\n }}</span>\n <span class=\"block text-sm\">\n <i class=\"pi pi-envelope mr-1 text-500\"></i>\n {{ rowData[col.field].email ?? \" --\" }}\n </span>\n <span class=\"block text-sm\">\n <i class=\"pi pi-phone text-500\"></i>\n {{ rowData[col.field].phone ?? \" --\" }}\n </span>\n </div>\n </p-popover>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.LIST) {\n @if (rowData[col.field]?.length) {\n @if (rowData[col.field].length > 1) {\n <div\n class=\"cursor-pointer\"\n (click)=\"listPop.toggle($event)\"\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.LIST +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n >\n <span class=\"mr-1\">{{\n rowData[col.field][0].name\n }}</span>\n <p-chip\n class=\"text-sm font-semibold p-1 m-0\"\n [label]=\"'+' + (rowData[col.field].length - 1)\"\n />\n </div>\n } @else {\n <span>{{ rowData[col.field][0].name }}</span>\n }\n\n <p-popover #listPop [dismissable]=\"true\">\n @for (\n item of rowData[col.field];\n track item.name;\n let isFirst = $first\n ) {\n @if (!isFirst) {\n <ul class=\"list-none m-0 p-0\">\n <li>{{ item.name }}</li>\n </ul>\n }\n }\n </p-popover>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.BOOLEAN) {\n @if (rowData[col.field] | isBoolean) {\n <i\n [pTooltip]=\"rowData?.[col.field + 'Tooltip']\"\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.BOOLEAN +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n class=\"pi\"\n [ngClass]=\"\n rowData[col.field]\n ? 'text-green-500 pi-check-circle'\n : 'text-red-500 pi-times-circle'\n \"\n ></i>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.TEXT_AREA) {\n @if (rowData[col.field]) {\n <div\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.TEXT_AREA +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n [pTooltip]=\"rowData[col.field]\"\n >\n {{\n rowData[col.field].length > (col.maxLength ?? 50)\n ? (rowData[col.field]\n | slice: 0 : col.maxLength ?? 50) + \"...\"\n : rowData[col.field]\n }}\n </div>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.EMAIL) {\n @if (rowData[col.field]) {\n <div\n class=\"email-cell\"\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.EMAIL +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n >\n <span>{{ rowData[col.field] }}</span>\n <i\n class=\"pi pi-copy email-copy-icon\"\n (click)=\"copyToClipboard($event, rowData[col.field])\"\n [pTooltip]=\"'LABELS.COPY_EMAIL' | translate\"\n >\n </i>\n </div>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.TIMEPERIOD) {\n @if (rowData[col.field]) {\n <div\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.TIMEPERIOD +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n [pTooltip]=\"rowData[col.field] | timePeriod\"\n style=\"max-width: 200px\"\n >\n {{ rowData[col.field] | timePeriod }}\n </div>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @default {\n @if (col.flag && getNested(rowData, col.flagCodeField)) {\n <div\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.TEXT +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n class=\"flex align-items-center gap-2\"\n style=\"max-width: 200px\"\n [pTooltip]=\"rowData | cell: col : dateFormat\"\n >\n <img\n src=\"https://primefaces.org/cdn/primeng/images/demo/flag/flag_placeholder.png\"\n [class]=\"\n 'flag flag-' +\n (getNested(rowData, col.flagCodeField) || '')\n .toString()\n .toLowerCase()\n \"\n style=\"width: 22px\"\n alt=\"\"\n />\n <span\n [innerHTML]=\"rowData | cell: col : dateFormat\"\n ></span>\n </div>\n } @else {\n @if (rowData | cell: col : dateFormat) {\n <div\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.TEXT +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n [pTooltip]=\"rowData | cell: col : dateFormat\"\n style=\"max-width: 200px\"\n [innerHTML]=\"rowData | cell: col : dateFormat\"\n ></div>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n }\n }\n </td>\n }\n\n <td class=\"p-0\">\n @for (\n action of tableConfiguration.rowActions;\n track action?.key ?? $index\n ) {\n <phoenix-data-table-action\n [actionConfig]=\"action\"\n [rowData]=\"rowData\"\n (actionClick)=\"handleActionClick($event)\"\n ></phoenix-data-table-action>\n }\n </td>\n </tr>\n </ng-template>\n\n <!-- <ng-template pTemplate=\"loadingbody\" let-columns>\n @for (_ of skeletonRows; track $index; let rowIdx = $index) {\n <tr style=\"height: 40px\">\n @switch (tableConfiguration.selectionType) {\n @case (selectionTypeEnum.CHECKBOX) {\n <td class=\"w-2rem\">\n <p-skeleton width=\"1.2rem\" height=\"1.2rem\"></p-skeleton>\n </td>\n }\n @case (selectionTypeEnum.RADIO_BTN) {\n <td class=\"w-2rem\">\n <p-skeleton width=\"1.2rem\" height=\"1.2rem\"></p-skeleton>\n </td>\n }\n }\n\n @for (col of columns; track col.field ?? col.header ?? $index) {\n <td>\n <p-skeleton\n [ngStyle]=\"{\n width: (60 + (rowIdx % 3) * 10) + '%',\n height: '1rem'\n }\"\n ></p-skeleton>\n </td>\n }\n\n <td>\n <p-skeleton width=\"2rem\" height=\"1rem\"></p-skeleton>\n </td>\n </tr>\n }\n </ng-template> -->\n\n <ng-template #emptyCell let-dataCy=\"dataCy\">\n <span [attr.data-cy]=\"dataCy\">--</span>\n </ng-template>\n\n <ng-template pTemplate=\"emptymessage\">\n <td class=\"p-2\" colspan=\"100\">\n <div class=\"flex align-items-center\">\n <i class=\"pi pi-info-circle mr-2\"></i>\n {{ \"NO_RESULTS_FOUND\" | translate }}\n </div>\n </td>\n </ng-template>\n </p-table>\n\n <div class=\"border-top-1 border-300 pl-2 p-1 text-sm text-500\">\n {{ \"LABELS.TOTAL_RECORDS\" | translate }}: {{ totalRecords }}\n </div>\n </div>\n</div>\n", styles: [":is() .p-avatar{border-radius:50%!important}::ng-deep .p-paginator button{scale:.7}::ng-deep .p-paginator-rpp-options{scale:.7}::ng-deep .p-datatable .p-datatable-header{border-radius:10px 10px 0 0}:host::ng-deep .p-tag{font-weight:400!important;font-size:.875rem!important}.email-cell{position:relative;display:inline-block;padding-right:24px}.email-cell .email-copy-icon{position:absolute;top:0;right:0;opacity:0;cursor:pointer;transition:opacity .2s}.email-cell:hover .email-copy-icon{opacity:1}.table-host{display:flex;flex-direction:column;min-height:0;overflow:hidden}.table-host,.table-host>.p-datatable,.table-host>.p-datatable .p-datatable-wrapper{min-height:0}:host ::ng-deep .p-datatable-loading-overlay{display:none!important}:host ::ng-deep .p-datatable-mask{display:none!important}:host ::ng-deep .p-datatable.p-datatable-loading{opacity:1!important;pointer-events:auto!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i2$4.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i4.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i2$4.SortableColumn, selector: "[pSortableColumn]", inputs: ["pSortableColumn", "pSortableColumnDisabled"] }, { kind: "directive", type: i2$4.ResizableColumn, selector: "[pResizableColumn]", inputs: ["pResizableColumnDisabled"] }, { kind: "component", type: i2$4.SortIcon, selector: "p-sortIcon", inputs: ["field"] }, { kind: "component", type: i2$4.TableRadioButton, selector: "p-tableRadioButton", inputs: ["value", "disabled", "index", "inputId", "name", "ariaLabel"] }, { kind: "component", type: i2$4.TableCheckbox, selector: "p-tableCheckbox", inputs: ["value", "disabled", "required", "index", "inputId", "name", "ariaLabel"] }, { kind: "component", type: i2$4.TableHeaderCheckbox, selector: "p-tableHeaderCheckbox", inputs: ["disabled", "inputId", "name", "ariaLabel"] }, { kind: "component", type: TableCaptionComponent, selector: "table-caption", inputs: ["tableConfiguration", "columns", "selectedItems", "filters", "filterValidValues"], outputs: ["applyFiltersEvent", "applyColumnsEvent", "searchChange", "actionClick"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: PhoenixDataTableActionComponent, selector: "phoenix-data-table-action", inputs: ["actionConfig", "rowData"], outputs: ["actionClick"] }, { kind: "ngmodule", type: TagModule }, { kind: "component", type: i4$1.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "ngmodule", type: AvatarModule }, { kind: "component", type: i5$3.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i1.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "ngmodule", type: PanelModule }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i3$2.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: ChipModule }, { kind: "component", type: i8$2.Chip, selector: "p-chip", inputs: ["label", "icon", "image", "alt", "styleClass", "disabled", "removable", "removeIcon", "chipProps"], outputs: ["onRemove", "onImageError"] }, { kind: "ngmodule", type: BadgeModule }, { kind: "component", type: i4$6.Badge, selector: "p-badge", inputs: ["styleClass", "badgeSize", "size", "severity", "value", "badgeDisabled"] }, { kind: "pipe", type: i1$2.SlicePipe, name: "slice" }, { kind: "pipe", type: i4$2.TranslatePipe, name: "translate" }, { kind: "pipe", type: TableCellPipe, name: "cell" }, { kind: "pipe", type: InitialsPipe, name: "initials" }, { kind: "pipe", type: TimePeriodPipe, name: "timePeriod" }, { kind: "pipe", type: IsBooleanPipe, name: "isBoolean" }] });
3827
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: TableComponent, isStandalone: true, selector: "phoenix-table", inputs: { columns: "columns", selectedColumnsInput: "selectedColumnsInput", tableConfiguration: "tableConfiguration", filters: "filters", data: "data" }, outputs: { actionClick: "actionClick", rowSelection: "rowSelection", checkBoxSelection: "checkBoxSelection", saveColumns: "saveColumns" }, viewQueries: [{ propertyName: "dt", first: true, predicate: ["dt"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"border-1 border-round-sm border-300 border-round-md m-2\">\n @if (selectedItems().length === 0) {\n <table-caption\n [columns]=\"columns\"\n [tableConfiguration]=\"tableConfiguration\"\n [filters]=\"computedFilters\"\n [selectedItems]=\"selectedItems()\"\n [filterValidValues]=\"filterValidValues\"\n (applyFiltersEvent)=\"applyFilters($event)\"\n (applyColumnsEvent)=\"applyColumns($event)\"\n (searchChange)=\"onSearch($event)\"\n (actionClick)=\"handleActionClick($event)\"\n ></table-caption>\n } @else {\n <div\n style=\"min-height: 40px; padding: 8px\"\n class=\"flex justify-content-between align-items-center border-bottom-1 border-300 pl-5 pr-5 text-sm text-500\"\n >\n <div>\n @if (tableConfiguration.selectionType === selectionTypeEnum.CHECKBOX) {\n <span>\n {{ selectedItems().length }}\n {{\n selectedItems().length === 1\n ? (\"LABELS.ITEM_SELECTED\" | translate)\n : (\"LABELS.ITEMS_SELECTED\" | translate)\n }}\n </span>\n }\n </div>\n\n <div>\n @for (\n action of tableConfiguration.bulkActions;\n track action?.key ?? $index\n ) {\n <phoenix-data-table-action\n [actionConfig]=\"action\"\n (actionClick)=\"\n handleActionClick({\n action: action,\n selectedItems: selectedItems(),\n });\n clearSelection()\n \"\n ></phoenix-data-table-action>\n }\n\n <button\n [attr.data-cy]=\"'clear-selection-button'\"\n class=\"p-button p-button-text p-button-plain\"\n (click)=\"clearSelection()\"\n aria-label=\"Clear Selection\"\n >\n <i class=\"pi pi-times\"></i>\n </button>\n </div>\n </div>\n }\n <div\n class=\"table-host\"\n [style.height]=\"tableConfiguration.scrollHeight ?? null\"\n >\n <p-table\n #dt\n [columns]=\"selectedColumns\"\n [value]=\"tableData\"\n [size]=\"'small'\"\n scrollable=\"true\"\n scrollHeight=\"flex\"\n [virtualScroll]=\"true\"\n [virtualScrollItemSize]=\"40\"\n [virtualScrollDelay]=\"80\"\n [totalRecords]=\"totalRecords\"\n [sortMode]=\"'multiple'\"\n [customSort]=\"true\"\n (sortFunction)=\"onCustomSort($event)\"\n [selection]=\"selectedItems()\"\n (selectionChange)=\"onSelectionChange($event)\"\n [resizableColumns]=\"true\"\n columnResizeMode=\"expand\"\n [loading]=\"initialSortLoading\"\n >\n <ng-template #header let-columns>\n <tr style=\"height: 40px\" class=\"dt-header\">\n @switch (tableConfiguration.selectionType) {\n @case (selectionTypeEnum.CHECKBOX) {\n <th class=\"custom-th\">\n <p-tableHeaderCheckbox\n [attr.data-cy]=\"'table-header-checkbox'\"\n ></p-tableHeaderCheckbox>\n </th>\n }\n @case (selectionTypeEnum.RADIO_BTN) {\n <th class=\"custom-th\"></th>\n }\n }\n @for (\n col of columns;\n track col.field ?? col.header ?? $index;\n let colIdx = $index\n ) {\n <th\n pResizableColumn\n class=\"custom-th text-primary font-bold\"\n [pSortableColumn]=\"col.field\"\n >\n {{ col.header | translate }}\n <p-sortIcon\n [field]=\"col.field\"\n [attr.data-cy]=\"'sort-button-' + col.header\"\n ></p-sortIcon>\n </th>\n }\n\n <th class=\"custom-th\"></th>\n </tr>\n </ng-template>\n\n <ng-template\n #body\n let-rowData\n let-columns=\"columns\"\n let-rowIndex=\"rowIndex\"\n >\n <tr>\n @switch (tableConfiguration.selectionType) {\n @case (selectionTypeEnum.CHECKBOX) {\n <td class=\"w-2rem\">\n <p-tableCheckbox\n [attr.data-cy]=\"\n 'table-row-' + selectionTypeEnum.CHECKBOX + '-' + rowIndex\n \"\n [disabled]=\"\n rowData?.canSelect !== undefined\n ? !rowData.canSelect\n : false\n \"\n [value]=\"rowData\"\n ></p-tableCheckbox>\n </td>\n }\n @case (selectionTypeEnum.RADIO_BTN) {\n <td>\n <p-tableRadioButton\n [value]=\"rowData\"\n [attr.data-cy]=\"\n 'table-row-' + selectionTypeEnum.RADIO_BTN + '-' + rowIndex\n \"\n ></p-tableRadioButton>\n </td>\n }\n }\n @for (\n col of columns;\n track col.field ?? col.header ?? $index;\n let i = $index\n ) {\n <td\n (click)=\"\n isColumnClickable(i) ? onRowClick($event, rowData) : null\n \"\n [ngClass]=\"{\n 'text-blue-500 underline cursor-pointer': isColumnClickable(i),\n }\"\n >\n @switch (col.columnType) {\n @case (columnTypeEnum.TAG) {\n @if (rowData[col.field]) {\n <div class=\"flex align-items-center gap-2\">\n <div\n class=\"border-round-md font-semibold\"\n [style]=\"{\n fontSize: '12px',\n padding: '3px 8px',\n width: 'fit-content',\n 'background-color':\n (rowData[col.field + 'Color'] || '#ccc') + '56',\n color: rowData[col.field + 'Color'],\n }\"\n >\n {{\n rowData[col.field]?.name ||\n (rowData[col.field] | translate)\n }}\n </div>\n @if (rowData[col.field + \"Tooltip\"]) {\n <i\n [class]=\"\n rowData[col.field + 'Icon'].class +\n ' cursor-pointer'\n \"\n [style]=\"rowData[col.field + 'Icon'].style\"\n [pTooltip]=\"rowData[col.field + 'Tooltip']\"\n tooltipPosition=\"top\"\n ></i>\n }\n </div>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.LIST_TAG) {\n @if (rowData[col.field]) {\n @for (item of rowData[col.field]; track $index) {\n <p-badge severity=\"warn\" class=\"mr-1\" [value]=\"item\" />\n }\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.OBJ_TAG) {\n @if (rowData[col.field]) {\n <p-tag\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.OBJ_TAG +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n [style]=\"{\n fontSize: '12px',\n padding: '3px 8px',\n width: 'fit-content',\n 'background-color':\n (rowData[col.field].color || '#ccc') + '56',\n color: rowData[col.field].color,\n }\"\n [value]=\"rowData[col.field]?.value | translate\"\n ></p-tag>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.PERSON) {\n @if (rowData[col.field]) {\n <p-avatar\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.PERSON +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n [label]=\"rowData[col.field]?.name | initials\"\n class=\"cursor-pointer\"\n [style]=\"{\n 'background-color': '#9c27b0',\n color: '#ffffff',\n 'font-size': '0.8rem!important',\n }\"\n shape=\"circle\"\n (click)=\"personPop.toggle($event)\"\n ></p-avatar>\n\n <p-popover #personPop [dismissable]=\"true\">\n <div>\n <span class=\"text-lg\">{{\n rowData[col.field].name\n }}</span>\n <span class=\"block text-sm\">\n <i class=\"pi pi-envelope mr-1 text-500\"></i>\n {{ rowData[col.field].email ?? \" --\" }}\n </span>\n <span class=\"block text-sm\">\n <i class=\"pi pi-phone text-500\"></i>\n {{ rowData[col.field].phone ?? \" --\" }}\n </span>\n </div>\n </p-popover>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.LIST) {\n @if (rowData[col.field]?.length) {\n @if (rowData[col.field].length > 1) {\n <div\n class=\"cursor-pointer\"\n (click)=\"listPop.toggle($event)\"\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.LIST +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n >\n <span class=\"mr-1\">{{\n rowData[col.field][0].name\n }}</span>\n <p-chip\n class=\"text-sm font-semibold p-1 m-0\"\n [label]=\"'+' + (rowData[col.field].length - 1)\"\n />\n </div>\n } @else {\n <span>{{ rowData[col.field][0].name }}</span>\n }\n\n <p-popover #listPop [dismissable]=\"true\">\n @for (\n item of rowData[col.field];\n track item.name;\n let isFirst = $first\n ) {\n @if (!isFirst) {\n <ul class=\"list-none m-0 p-0\">\n <li>{{ item.name }}</li>\n </ul>\n }\n }\n </p-popover>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.BOOLEAN) {\n @if (rowData[col.field] | isBoolean) {\n <i\n [pTooltip]=\"rowData?.[col.field + 'Tooltip']\"\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.BOOLEAN +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n class=\"pi\"\n [ngClass]=\"\n rowData[col.field]\n ? 'text-green-500 pi-check-circle'\n : 'text-red-500 pi-times-circle'\n \"\n ></i>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.TEXT_AREA) {\n @if (rowData[col.field]) {\n <div\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.TEXT_AREA +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n [pTooltip]=\"rowData[col.field]\"\n >\n {{\n rowData[col.field].length > (col.maxLength ?? 50)\n ? (rowData[col.field]\n | slice: 0 : col.maxLength ?? 50) + \"...\"\n : rowData[col.field]\n }}\n </div>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.EMAIL) {\n @if (rowData[col.field]) {\n <div\n class=\"email-cell\"\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.EMAIL +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n >\n <span>{{ rowData[col.field] }}</span>\n <i\n class=\"pi pi-copy email-copy-icon\"\n (click)=\"copyToClipboard($event, rowData[col.field])\"\n [pTooltip]=\"'LABELS.COPY_EMAIL' | translate\"\n >\n </i>\n </div>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.TIMEPERIOD) {\n @if (rowData[col.field]) {\n <div\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.TIMEPERIOD +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n [pTooltip]=\"rowData[col.field] | timePeriod\"\n style=\"max-width: 200px\"\n >\n {{ rowData[col.field] | timePeriod }}\n </div>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @default {\n @if (col.flag && getNested(rowData, col.flagCodeField)) {\n <div\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.TEXT +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n class=\"flex align-items-center gap-2\"\n style=\"max-width: 200px\"\n [pTooltip]=\"rowData | cell: col : dateFormat\"\n >\n <img\n src=\"https://primefaces.org/cdn/primeng/images/demo/flag/flag_placeholder.png\"\n [class]=\"\n 'flag flag-' +\n (getNested(rowData, col.flagCodeField) || '')\n .toString()\n .toLowerCase()\n \"\n style=\"width: 22px\"\n alt=\"\"\n />\n <span\n [innerHTML]=\"rowData | cell: col : dateFormat\"\n ></span>\n </div>\n } @else {\n @if (rowData | cell: col : dateFormat) {\n <div\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.TEXT +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n [pTooltip]=\"rowData | cell: col : dateFormat\"\n style=\"max-width: 200px\"\n [innerHTML]=\"rowData | cell: col : dateFormat\"\n ></div>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n }\n }\n </td>\n }\n\n <td class=\"p-0\">\n @for (\n action of tableConfiguration.rowActions;\n track action?.key ?? $index\n ) {\n <phoenix-data-table-action\n [actionConfig]=\"action\"\n [rowData]=\"rowData\"\n (actionClick)=\"handleActionClick($event)\"\n ></phoenix-data-table-action>\n }\n </td>\n </tr>\n </ng-template>\n\n <!-- <ng-template pTemplate=\"loadingbody\" let-columns>\n @for (_ of skeletonRows; track $index; let rowIdx = $index) {\n <tr style=\"height: 40px\">\n @switch (tableConfiguration.selectionType) {\n @case (selectionTypeEnum.CHECKBOX) {\n <td class=\"w-2rem\">\n <p-skeleton width=\"1.2rem\" height=\"1.2rem\"></p-skeleton>\n </td>\n }\n @case (selectionTypeEnum.RADIO_BTN) {\n <td class=\"w-2rem\">\n <p-skeleton width=\"1.2rem\" height=\"1.2rem\"></p-skeleton>\n </td>\n }\n }\n\n @for (col of columns; track col.field ?? col.header ?? $index) {\n <td>\n <p-skeleton\n [ngStyle]=\"{\n width: (60 + (rowIdx % 3) * 10) + '%',\n height: '1rem'\n }\"\n ></p-skeleton>\n </td>\n }\n\n <td>\n <p-skeleton width=\"2rem\" height=\"1rem\"></p-skeleton>\n </td>\n </tr>\n }\n </ng-template> -->\n\n <ng-template #emptyCell let-dataCy=\"dataCy\">\n <span [attr.data-cy]=\"dataCy\">--</span>\n </ng-template>\n\n <ng-template pTemplate=\"emptymessage\">\n <td class=\"p-2\" colspan=\"100\">\n <div class=\"flex align-items-center\">\n <i class=\"pi pi-info-circle mr-2\"></i>\n {{ \"NO_RESULTS_FOUND\" | translate }}\n </div>\n </td>\n </ng-template>\n </p-table>\n\n <div class=\"border-top-1 border-300 pl-2 p-1 text-sm text-500\">\n {{ \"LABELS.TOTAL_RECORDS\" | translate }}: {{ totalRecords }}\n </div>\n </div>\n</div>\n", styles: [":is() .p-avatar{border-radius:50%!important}::ng-deep .p-paginator button{scale:.7}::ng-deep .p-paginator-rpp-options{scale:.7}::ng-deep .p-datatable .p-datatable-header{border-radius:10px 10px 0 0}:host::ng-deep .p-tag{font-weight:400!important;font-size:.875rem!important}.email-cell{position:relative;display:inline-block;padding-right:24px}.email-cell .email-copy-icon{position:absolute;top:0;right:0;opacity:0;cursor:pointer;transition:opacity .2s}.email-cell:hover .email-copy-icon{opacity:1}.table-host{display:flex;flex-direction:column;min-height:0;overflow:hidden}.table-host,.table-host>.p-datatable,.table-host>.p-datatable .p-datatable-wrapper{min-height:0}:host ::ng-deep .p-datatable-loading-overlay{display:none!important}:host ::ng-deep .p-datatable-mask{display:none!important}:host ::ng-deep .p-datatable.p-datatable-loading{opacity:1!important;pointer-events:auto!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i2$4.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i4.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i2$4.SortableColumn, selector: "[pSortableColumn]", inputs: ["pSortableColumn", "pSortableColumnDisabled"] }, { kind: "directive", type: i2$4.ResizableColumn, selector: "[pResizableColumn]", inputs: ["pResizableColumnDisabled"] }, { kind: "component", type: i2$4.SortIcon, selector: "p-sortIcon", inputs: ["field"] }, { kind: "component", type: i2$4.TableRadioButton, selector: "p-tableRadioButton", inputs: ["value", "disabled", "index", "inputId", "name", "ariaLabel"] }, { kind: "component", type: i2$4.TableCheckbox, selector: "p-tableCheckbox", inputs: ["value", "disabled", "required", "index", "inputId", "name", "ariaLabel"] }, { kind: "component", type: i2$4.TableHeaderCheckbox, selector: "p-tableHeaderCheckbox", inputs: ["disabled", "inputId", "name", "ariaLabel"] }, { kind: "component", type: TableCaptionComponent, selector: "table-caption", inputs: ["tableConfiguration", "columns", "selectedItems", "filters", "filterValidValues"], outputs: ["applyFiltersEvent", "applyColumnsEvent", "searchChange", "actionClick"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: PhoenixDataTableActionComponent, selector: "phoenix-data-table-action", inputs: ["actionConfig", "rowData"], outputs: ["actionClick"] }, { kind: "ngmodule", type: TagModule }, { kind: "component", type: i4$1.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "ngmodule", type: AvatarModule }, { kind: "component", type: i5$3.Avatar, selector: "p-avatar", inputs: ["label", "icon", "image", "size", "shape", "styleClass", "ariaLabel", "ariaLabelledBy"], outputs: ["onImageError"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i1.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "ngmodule", type: PanelModule }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i3$2.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: ChipModule }, { kind: "component", type: i8$2.Chip, selector: "p-chip", inputs: ["label", "icon", "image", "alt", "styleClass", "disabled", "removable", "removeIcon", "chipProps"], outputs: ["onRemove", "onImageError"] }, { kind: "ngmodule", type: BadgeModule }, { kind: "component", type: i4$6.Badge, selector: "p-badge", inputs: ["styleClass", "badgeSize", "size", "severity", "value", "badgeDisabled"] }, { kind: "pipe", type: i1$2.SlicePipe, name: "slice" }, { kind: "pipe", type: i4$2.TranslatePipe, name: "translate" }, { kind: "pipe", type: TableCellPipe, name: "cell" }, { kind: "pipe", type: InitialsPipe, name: "initials" }, { kind: "pipe", type: TimePeriodPipe, name: "timePeriod" }, { kind: "pipe", type: IsBooleanPipe, name: "isBoolean" }] });
3679
3828
  }
3680
3829
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: TableComponent, decorators: [{
3681
3830
  type: Component,
@@ -3697,7 +3846,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
3697
3846
  TimePeriodPipe,
3698
3847
  IsBooleanPipe,
3699
3848
  BadgeModule,
3700
- ], template: "<div class=\"border-1 border-round-sm border-300 border-round-md m-2\">\n @if (selectedItems().length === 0) {\n <table-caption\n [columns]=\"columns\"\n [tableConfiguration]=\"tableConfiguration\"\n [filters]=\"filters\"\n [selectedItems]=\"selectedItems()\"\n [filterValidValues]=\"filterValidValues\"\n (applyFiltersEvent)=\"applyFilters($event)\"\n (applyColumnsEvent)=\"applyColumns($event)\"\n (searchChange)=\"onSearch($event)\"\n (actionClick)=\"handleActionClick($event)\"\n ></table-caption>\n } @else {\n <div\n style=\"min-height: 40px; padding: 8px\"\n class=\"flex justify-content-between align-items-center border-bottom-1 border-300 pl-5 pr-5 text-sm text-500\"\n >\n <div>\n @if (tableConfiguration.selectionType === selectionTypeEnum.CHECKBOX) {\n <span>\n {{ selectedItems().length }}\n {{\n selectedItems().length === 1\n ? (\"LABELS.ITEM_SELECTED\" | translate)\n : (\"LABELS.ITEMS_SELECTED\" | translate)\n }}\n </span>\n }\n </div>\n\n <div>\n @for (\n action of tableConfiguration.bulkActions;\n track action?.key ?? $index\n ) {\n <phoenix-data-table-action\n [actionConfig]=\"action\"\n (actionClick)=\"\n handleActionClick({\n action: action,\n selectedItems: selectedItems(),\n });\n clearSelection()\n \"\n ></phoenix-data-table-action>\n }\n\n <button\n [attr.data-cy]=\"'clear-selection-button'\"\n class=\"p-button p-button-text p-button-plain\"\n (click)=\"clearSelection()\"\n aria-label=\"Clear Selection\"\n >\n <i class=\"pi pi-times\"></i>\n </button>\n </div>\n </div>\n }\n <div\n class=\"table-host\"\n [style.height]=\"tableConfiguration.scrollHeight ?? null\"\n >\n <p-table\n #dt\n [columns]=\"selectedColumns\"\n [value]=\"tableData\"\n [size]=\"'small'\"\n scrollable=\"true\"\n scrollHeight=\"flex\"\n [virtualScroll]=\"true\"\n [virtualScrollItemSize]=\"40\"\n [virtualScrollDelay]=\"80\"\n [totalRecords]=\"totalRecords\"\n [sortMode]=\"'multiple'\"\n [customSort]=\"true\"\n (sortFunction)=\"onCustomSort($event)\"\n [selection]=\"selectedItems()\"\n (selectionChange)=\"onSelectionChange($event)\"\n [resizableColumns]=\"true\"\n columnResizeMode=\"expand\"\n [loading]=\"initialSortLoading\"\n >\n <ng-template #header let-columns>\n <tr style=\"height: 40px\" class=\"dt-header\">\n @switch (tableConfiguration.selectionType) {\n @case (selectionTypeEnum.CHECKBOX) {\n <th class=\"custom-th\">\n <p-tableHeaderCheckbox\n [attr.data-cy]=\"'table-header-checkbox'\"\n ></p-tableHeaderCheckbox>\n </th>\n }\n @case (selectionTypeEnum.RADIO_BTN) {\n <th class=\"custom-th\"></th>\n }\n }\n @for (\n col of columns;\n track col.field ?? col.header ?? $index;\n let colIdx = $index\n ) {\n <th\n pResizableColumn\n class=\"custom-th text-primary font-bold\"\n [pSortableColumn]=\"col.field\"\n >\n {{ col.header | translate }}\n <p-sortIcon\n [field]=\"col.field\"\n [attr.data-cy]=\"'sort-button-' + col.header\"\n ></p-sortIcon>\n </th>\n }\n\n <th class=\"custom-th\"></th>\n </tr>\n </ng-template>\n\n <ng-template\n #body\n let-rowData\n let-columns=\"columns\"\n let-rowIndex=\"rowIndex\"\n >\n <tr>\n @switch (tableConfiguration.selectionType) {\n @case (selectionTypeEnum.CHECKBOX) {\n <td class=\"w-2rem\">\n <p-tableCheckbox\n [attr.data-cy]=\"\n 'table-row-' + selectionTypeEnum.CHECKBOX + '-' + rowIndex\n \"\n [disabled]=\"\n rowData?.canSelect !== undefined\n ? !rowData.canSelect\n : false\n \"\n [value]=\"rowData\"\n ></p-tableCheckbox>\n </td>\n }\n @case (selectionTypeEnum.RADIO_BTN) {\n <td>\n <p-tableRadioButton\n [value]=\"rowData\"\n [attr.data-cy]=\"\n 'table-row-' + selectionTypeEnum.RADIO_BTN + '-' + rowIndex\n \"\n ></p-tableRadioButton>\n </td>\n }\n }\n @for (\n col of columns;\n track col.field ?? col.header ?? $index;\n let i = $index\n ) {\n <td\n (click)=\"\n isColumnClickable(i) ? onRowClick($event, rowData) : null\n \"\n [ngClass]=\"{\n 'text-blue-500 underline cursor-pointer': isColumnClickable(i),\n }\"\n >\n @switch (col.columnType) {\n @case (columnTypeEnum.TAG) {\n @if (rowData[col.field]) {\n <div class=\"flex align-items-center gap-2\">\n <div\n class=\"border-round-md font-semibold\"\n [style]=\"{\n fontSize: '12px',\n padding: '3px 8px',\n width: 'fit-content',\n 'background-color':\n (rowData[col.field + 'Color'] || '#ccc') + '56',\n color: rowData[col.field + 'Color'],\n }\"\n >\n {{\n rowData[col.field]?.name ||\n (rowData[col.field] | translate)\n }}\n </div>\n @if (rowData[col.field + \"Tooltip\"]) {\n <i\n [class]=\"\n rowData[col.field + 'Icon'].class +\n ' cursor-pointer'\n \"\n [style]=\"rowData[col.field + 'Icon'].style\"\n [pTooltip]=\"rowData[col.field + 'Tooltip']\"\n tooltipPosition=\"top\"\n ></i>\n }\n </div>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.LIST_TAG) {\n @if (rowData[col.field]) {\n @for (item of rowData[col.field]; track $index) {\n <p-badge severity=\"warn\" class=\"mr-1\" [value]=\"item\" />\n }\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.OBJ_TAG) {\n @if (rowData[col.field]) {\n <p-tag\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.OBJ_TAG +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n [style]=\"{\n fontSize: '12px',\n padding: '3px 8px',\n width: 'fit-content',\n 'background-color':\n (rowData[col.field].color || '#ccc') + '56',\n color: rowData[col.field].color,\n }\"\n [value]=\"rowData[col.field]?.value | translate\"\n ></p-tag>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.PERSON) {\n @if (rowData[col.field]) {\n <p-avatar\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.PERSON +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n [label]=\"rowData[col.field]?.name | initials\"\n class=\"cursor-pointer\"\n [style]=\"{\n 'background-color': '#9c27b0',\n color: '#ffffff',\n 'font-size': '0.8rem!important',\n }\"\n shape=\"circle\"\n (click)=\"personPop.toggle($event)\"\n ></p-avatar>\n\n <p-popover #personPop [dismissable]=\"true\">\n <div>\n <span class=\"text-lg\">{{\n rowData[col.field].name\n }}</span>\n <span class=\"block text-sm\">\n <i class=\"pi pi-envelope mr-1 text-500\"></i>\n {{ rowData[col.field].email ?? \" --\" }}\n </span>\n <span class=\"block text-sm\">\n <i class=\"pi pi-phone text-500\"></i>\n {{ rowData[col.field].phone ?? \" --\" }}\n </span>\n </div>\n </p-popover>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.LIST) {\n @if (rowData[col.field]?.length) {\n @if (rowData[col.field].length > 1) {\n <div\n class=\"cursor-pointer\"\n (click)=\"listPop.toggle($event)\"\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.LIST +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n >\n <span class=\"mr-1\">{{\n rowData[col.field][0].name\n }}</span>\n <p-chip\n class=\"text-sm font-semibold p-1 m-0\"\n [label]=\"'+' + (rowData[col.field].length - 1)\"\n />\n </div>\n } @else {\n <span>{{ rowData[col.field][0].name }}</span>\n }\n\n <p-popover #listPop [dismissable]=\"true\">\n @for (\n item of rowData[col.field];\n track item.name;\n let isFirst = $first\n ) {\n @if (!isFirst) {\n <ul class=\"list-none m-0 p-0\">\n <li>{{ item.name }}</li>\n </ul>\n }\n }\n </p-popover>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.BOOLEAN) {\n @if (rowData[col.field] | isBoolean) {\n <i\n [pTooltip]=\"rowData?.[col.field + 'Tooltip']\"\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.BOOLEAN +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n class=\"pi\"\n [ngClass]=\"\n rowData[col.field]\n ? 'text-green-500 pi-check-circle'\n : 'text-red-500 pi-times-circle'\n \"\n ></i>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.TEXT_AREA) {\n @if (rowData[col.field]) {\n <div\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.TEXT_AREA +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n [pTooltip]=\"rowData[col.field]\"\n >\n {{\n rowData[col.field].length > (col.maxLength ?? 50)\n ? (rowData[col.field]\n | slice: 0 : col.maxLength ?? 50) + \"...\"\n : rowData[col.field]\n }}\n </div>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.EMAIL) {\n @if (rowData[col.field]) {\n <div\n class=\"email-cell\"\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.EMAIL +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n >\n <span>{{ rowData[col.field] }}</span>\n <i\n class=\"pi pi-copy email-copy-icon\"\n (click)=\"copyToClipboard($event, rowData[col.field])\"\n [pTooltip]=\"'LABELS.COPY_EMAIL' | translate\"\n >\n </i>\n </div>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.TIMEPERIOD) {\n @if (rowData[col.field]) {\n <div\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.TIMEPERIOD +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n [pTooltip]=\"rowData[col.field] | timePeriod\"\n style=\"max-width: 200px\"\n >\n {{ rowData[col.field] | timePeriod }}\n </div>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @default {\n @if (col.flag && getNested(rowData, col.flagCodeField)) {\n <div\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.TEXT +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n class=\"flex align-items-center gap-2\"\n style=\"max-width: 200px\"\n [pTooltip]=\"rowData | cell: col : dateFormat\"\n >\n <img\n src=\"https://primefaces.org/cdn/primeng/images/demo/flag/flag_placeholder.png\"\n [class]=\"\n 'flag flag-' +\n (getNested(rowData, col.flagCodeField) || '')\n .toString()\n .toLowerCase()\n \"\n style=\"width: 22px\"\n alt=\"\"\n />\n <span\n [innerHTML]=\"rowData | cell: col : dateFormat\"\n ></span>\n </div>\n } @else {\n @if (rowData | cell: col : dateFormat) {\n <div\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.TEXT +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n [pTooltip]=\"rowData | cell: col : dateFormat\"\n style=\"max-width: 200px\"\n [innerHTML]=\"rowData | cell: col : dateFormat\"\n ></div>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n }\n }\n </td>\n }\n\n <td class=\"p-0\">\n @for (\n action of tableConfiguration.rowActions;\n track action?.key ?? $index\n ) {\n <phoenix-data-table-action\n [actionConfig]=\"action\"\n [rowData]=\"rowData\"\n (actionClick)=\"handleActionClick($event)\"\n ></phoenix-data-table-action>\n }\n </td>\n </tr>\n </ng-template>\n\n <!-- <ng-template pTemplate=\"loadingbody\" let-columns>\n @for (_ of skeletonRows; track $index; let rowIdx = $index) {\n <tr style=\"height: 40px\">\n @switch (tableConfiguration.selectionType) {\n @case (selectionTypeEnum.CHECKBOX) {\n <td class=\"w-2rem\">\n <p-skeleton width=\"1.2rem\" height=\"1.2rem\"></p-skeleton>\n </td>\n }\n @case (selectionTypeEnum.RADIO_BTN) {\n <td class=\"w-2rem\">\n <p-skeleton width=\"1.2rem\" height=\"1.2rem\"></p-skeleton>\n </td>\n }\n }\n\n @for (col of columns; track col.field ?? col.header ?? $index) {\n <td>\n <p-skeleton\n [ngStyle]=\"{\n width: (60 + (rowIdx % 3) * 10) + '%',\n height: '1rem'\n }\"\n ></p-skeleton>\n </td>\n }\n\n <td>\n <p-skeleton width=\"2rem\" height=\"1rem\"></p-skeleton>\n </td>\n </tr>\n }\n </ng-template> -->\n\n <ng-template #emptyCell let-dataCy=\"dataCy\">\n <span [attr.data-cy]=\"dataCy\">--</span>\n </ng-template>\n\n <ng-template pTemplate=\"emptymessage\">\n <td class=\"p-2\" colspan=\"100\">\n <div class=\"flex align-items-center\">\n <i class=\"pi pi-info-circle mr-2\"></i>\n {{ \"NO_RESULTS_FOUND\" | translate }}\n </div>\n </td>\n </ng-template>\n </p-table>\n\n <div class=\"border-top-1 border-300 pl-2 p-1 text-sm text-500\">\n {{ \"LABELS.TOTAL_RECORDS\" | translate }}: {{ totalRecords }}\n </div>\n </div>\n</div>\n", styles: [":is() .p-avatar{border-radius:50%!important}::ng-deep .p-paginator button{scale:.7}::ng-deep .p-paginator-rpp-options{scale:.7}::ng-deep .p-datatable .p-datatable-header{border-radius:10px 10px 0 0}:host::ng-deep .p-tag{font-weight:400!important;font-size:.875rem!important}.email-cell{position:relative;display:inline-block;padding-right:24px}.email-cell .email-copy-icon{position:absolute;top:0;right:0;opacity:0;cursor:pointer;transition:opacity .2s}.email-cell:hover .email-copy-icon{opacity:1}.table-host{display:flex;flex-direction:column;min-height:0;overflow:hidden}.table-host,.table-host>.p-datatable,.table-host>.p-datatable .p-datatable-wrapper{min-height:0}:host ::ng-deep .p-datatable-loading-overlay{display:none!important}:host ::ng-deep .p-datatable-mask{display:none!important}:host ::ng-deep .p-datatable.p-datatable-loading{opacity:1!important;pointer-events:auto!important}\n"] }]
3849
+ ], template: "<div class=\"border-1 border-round-sm border-300 border-round-md m-2\">\n @if (selectedItems().length === 0) {\n <table-caption\n [columns]=\"columns\"\n [tableConfiguration]=\"tableConfiguration\"\n [filters]=\"computedFilters\"\n [selectedItems]=\"selectedItems()\"\n [filterValidValues]=\"filterValidValues\"\n (applyFiltersEvent)=\"applyFilters($event)\"\n (applyColumnsEvent)=\"applyColumns($event)\"\n (searchChange)=\"onSearch($event)\"\n (actionClick)=\"handleActionClick($event)\"\n ></table-caption>\n } @else {\n <div\n style=\"min-height: 40px; padding: 8px\"\n class=\"flex justify-content-between align-items-center border-bottom-1 border-300 pl-5 pr-5 text-sm text-500\"\n >\n <div>\n @if (tableConfiguration.selectionType === selectionTypeEnum.CHECKBOX) {\n <span>\n {{ selectedItems().length }}\n {{\n selectedItems().length === 1\n ? (\"LABELS.ITEM_SELECTED\" | translate)\n : (\"LABELS.ITEMS_SELECTED\" | translate)\n }}\n </span>\n }\n </div>\n\n <div>\n @for (\n action of tableConfiguration.bulkActions;\n track action?.key ?? $index\n ) {\n <phoenix-data-table-action\n [actionConfig]=\"action\"\n (actionClick)=\"\n handleActionClick({\n action: action,\n selectedItems: selectedItems(),\n });\n clearSelection()\n \"\n ></phoenix-data-table-action>\n }\n\n <button\n [attr.data-cy]=\"'clear-selection-button'\"\n class=\"p-button p-button-text p-button-plain\"\n (click)=\"clearSelection()\"\n aria-label=\"Clear Selection\"\n >\n <i class=\"pi pi-times\"></i>\n </button>\n </div>\n </div>\n }\n <div\n class=\"table-host\"\n [style.height]=\"tableConfiguration.scrollHeight ?? null\"\n >\n <p-table\n #dt\n [columns]=\"selectedColumns\"\n [value]=\"tableData\"\n [size]=\"'small'\"\n scrollable=\"true\"\n scrollHeight=\"flex\"\n [virtualScroll]=\"true\"\n [virtualScrollItemSize]=\"40\"\n [virtualScrollDelay]=\"80\"\n [totalRecords]=\"totalRecords\"\n [sortMode]=\"'multiple'\"\n [customSort]=\"true\"\n (sortFunction)=\"onCustomSort($event)\"\n [selection]=\"selectedItems()\"\n (selectionChange)=\"onSelectionChange($event)\"\n [resizableColumns]=\"true\"\n columnResizeMode=\"expand\"\n [loading]=\"initialSortLoading\"\n >\n <ng-template #header let-columns>\n <tr style=\"height: 40px\" class=\"dt-header\">\n @switch (tableConfiguration.selectionType) {\n @case (selectionTypeEnum.CHECKBOX) {\n <th class=\"custom-th\">\n <p-tableHeaderCheckbox\n [attr.data-cy]=\"'table-header-checkbox'\"\n ></p-tableHeaderCheckbox>\n </th>\n }\n @case (selectionTypeEnum.RADIO_BTN) {\n <th class=\"custom-th\"></th>\n }\n }\n @for (\n col of columns;\n track col.field ?? col.header ?? $index;\n let colIdx = $index\n ) {\n <th\n pResizableColumn\n class=\"custom-th text-primary font-bold\"\n [pSortableColumn]=\"col.field\"\n >\n {{ col.header | translate }}\n <p-sortIcon\n [field]=\"col.field\"\n [attr.data-cy]=\"'sort-button-' + col.header\"\n ></p-sortIcon>\n </th>\n }\n\n <th class=\"custom-th\"></th>\n </tr>\n </ng-template>\n\n <ng-template\n #body\n let-rowData\n let-columns=\"columns\"\n let-rowIndex=\"rowIndex\"\n >\n <tr>\n @switch (tableConfiguration.selectionType) {\n @case (selectionTypeEnum.CHECKBOX) {\n <td class=\"w-2rem\">\n <p-tableCheckbox\n [attr.data-cy]=\"\n 'table-row-' + selectionTypeEnum.CHECKBOX + '-' + rowIndex\n \"\n [disabled]=\"\n rowData?.canSelect !== undefined\n ? !rowData.canSelect\n : false\n \"\n [value]=\"rowData\"\n ></p-tableCheckbox>\n </td>\n }\n @case (selectionTypeEnum.RADIO_BTN) {\n <td>\n <p-tableRadioButton\n [value]=\"rowData\"\n [attr.data-cy]=\"\n 'table-row-' + selectionTypeEnum.RADIO_BTN + '-' + rowIndex\n \"\n ></p-tableRadioButton>\n </td>\n }\n }\n @for (\n col of columns;\n track col.field ?? col.header ?? $index;\n let i = $index\n ) {\n <td\n (click)=\"\n isColumnClickable(i) ? onRowClick($event, rowData) : null\n \"\n [ngClass]=\"{\n 'text-blue-500 underline cursor-pointer': isColumnClickable(i),\n }\"\n >\n @switch (col.columnType) {\n @case (columnTypeEnum.TAG) {\n @if (rowData[col.field]) {\n <div class=\"flex align-items-center gap-2\">\n <div\n class=\"border-round-md font-semibold\"\n [style]=\"{\n fontSize: '12px',\n padding: '3px 8px',\n width: 'fit-content',\n 'background-color':\n (rowData[col.field + 'Color'] || '#ccc') + '56',\n color: rowData[col.field + 'Color'],\n }\"\n >\n {{\n rowData[col.field]?.name ||\n (rowData[col.field] | translate)\n }}\n </div>\n @if (rowData[col.field + \"Tooltip\"]) {\n <i\n [class]=\"\n rowData[col.field + 'Icon'].class +\n ' cursor-pointer'\n \"\n [style]=\"rowData[col.field + 'Icon'].style\"\n [pTooltip]=\"rowData[col.field + 'Tooltip']\"\n tooltipPosition=\"top\"\n ></i>\n }\n </div>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.LIST_TAG) {\n @if (rowData[col.field]) {\n @for (item of rowData[col.field]; track $index) {\n <p-badge severity=\"warn\" class=\"mr-1\" [value]=\"item\" />\n }\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.OBJ_TAG) {\n @if (rowData[col.field]) {\n <p-tag\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.OBJ_TAG +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n [style]=\"{\n fontSize: '12px',\n padding: '3px 8px',\n width: 'fit-content',\n 'background-color':\n (rowData[col.field].color || '#ccc') + '56',\n color: rowData[col.field].color,\n }\"\n [value]=\"rowData[col.field]?.value | translate\"\n ></p-tag>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.PERSON) {\n @if (rowData[col.field]) {\n <p-avatar\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.PERSON +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n [label]=\"rowData[col.field]?.name | initials\"\n class=\"cursor-pointer\"\n [style]=\"{\n 'background-color': '#9c27b0',\n color: '#ffffff',\n 'font-size': '0.8rem!important',\n }\"\n shape=\"circle\"\n (click)=\"personPop.toggle($event)\"\n ></p-avatar>\n\n <p-popover #personPop [dismissable]=\"true\">\n <div>\n <span class=\"text-lg\">{{\n rowData[col.field].name\n }}</span>\n <span class=\"block text-sm\">\n <i class=\"pi pi-envelope mr-1 text-500\"></i>\n {{ rowData[col.field].email ?? \" --\" }}\n </span>\n <span class=\"block text-sm\">\n <i class=\"pi pi-phone text-500\"></i>\n {{ rowData[col.field].phone ?? \" --\" }}\n </span>\n </div>\n </p-popover>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.LIST) {\n @if (rowData[col.field]?.length) {\n @if (rowData[col.field].length > 1) {\n <div\n class=\"cursor-pointer\"\n (click)=\"listPop.toggle($event)\"\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.LIST +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n >\n <span class=\"mr-1\">{{\n rowData[col.field][0].name\n }}</span>\n <p-chip\n class=\"text-sm font-semibold p-1 m-0\"\n [label]=\"'+' + (rowData[col.field].length - 1)\"\n />\n </div>\n } @else {\n <span>{{ rowData[col.field][0].name }}</span>\n }\n\n <p-popover #listPop [dismissable]=\"true\">\n @for (\n item of rowData[col.field];\n track item.name;\n let isFirst = $first\n ) {\n @if (!isFirst) {\n <ul class=\"list-none m-0 p-0\">\n <li>{{ item.name }}</li>\n </ul>\n }\n }\n </p-popover>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.BOOLEAN) {\n @if (rowData[col.field] | isBoolean) {\n <i\n [pTooltip]=\"rowData?.[col.field + 'Tooltip']\"\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.BOOLEAN +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n class=\"pi\"\n [ngClass]=\"\n rowData[col.field]\n ? 'text-green-500 pi-check-circle'\n : 'text-red-500 pi-times-circle'\n \"\n ></i>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.TEXT_AREA) {\n @if (rowData[col.field]) {\n <div\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.TEXT_AREA +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n [pTooltip]=\"rowData[col.field]\"\n >\n {{\n rowData[col.field].length > (col.maxLength ?? 50)\n ? (rowData[col.field]\n | slice: 0 : col.maxLength ?? 50) + \"...\"\n : rowData[col.field]\n }}\n </div>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.EMAIL) {\n @if (rowData[col.field]) {\n <div\n class=\"email-cell\"\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.EMAIL +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n >\n <span>{{ rowData[col.field] }}</span>\n <i\n class=\"pi pi-copy email-copy-icon\"\n (click)=\"copyToClipboard($event, rowData[col.field])\"\n [pTooltip]=\"'LABELS.COPY_EMAIL' | translate\"\n >\n </i>\n </div>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @case (columnTypeEnum.TIMEPERIOD) {\n @if (rowData[col.field]) {\n <div\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.TIMEPERIOD +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n [pTooltip]=\"rowData[col.field] | timePeriod\"\n style=\"max-width: 200px\"\n >\n {{ rowData[col.field] | timePeriod }}\n </div>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n @default {\n @if (col.flag && getNested(rowData, col.flagCodeField)) {\n <div\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.TEXT +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n class=\"flex align-items-center gap-2\"\n style=\"max-width: 200px\"\n [pTooltip]=\"rowData | cell: col : dateFormat\"\n >\n <img\n src=\"https://primefaces.org/cdn/primeng/images/demo/flag/flag_placeholder.png\"\n [class]=\"\n 'flag flag-' +\n (getNested(rowData, col.flagCodeField) || '')\n .toString()\n .toLowerCase()\n \"\n style=\"width: 22px\"\n alt=\"\"\n />\n <span\n [innerHTML]=\"rowData | cell: col : dateFormat\"\n ></span>\n </div>\n } @else {\n @if (rowData | cell: col : dateFormat) {\n <div\n [attr.data-cy]=\"\n 'table-row-' +\n columnTypeEnum.TEXT +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i\n \"\n [pTooltip]=\"rowData | cell: col : dateFormat\"\n style=\"max-width: 200px\"\n [innerHTML]=\"rowData | cell: col : dateFormat\"\n ></div>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"emptyCell\"\n [ngTemplateOutletContext]=\"{\n dataCy:\n 'table-row-' +\n col.columnType +\n '-row-index-' +\n rowIndex +\n '-col-index-' +\n i,\n }\"\n />\n }\n }\n }\n }\n </td>\n }\n\n <td class=\"p-0\">\n @for (\n action of tableConfiguration.rowActions;\n track action?.key ?? $index\n ) {\n <phoenix-data-table-action\n [actionConfig]=\"action\"\n [rowData]=\"rowData\"\n (actionClick)=\"handleActionClick($event)\"\n ></phoenix-data-table-action>\n }\n </td>\n </tr>\n </ng-template>\n\n <!-- <ng-template pTemplate=\"loadingbody\" let-columns>\n @for (_ of skeletonRows; track $index; let rowIdx = $index) {\n <tr style=\"height: 40px\">\n @switch (tableConfiguration.selectionType) {\n @case (selectionTypeEnum.CHECKBOX) {\n <td class=\"w-2rem\">\n <p-skeleton width=\"1.2rem\" height=\"1.2rem\"></p-skeleton>\n </td>\n }\n @case (selectionTypeEnum.RADIO_BTN) {\n <td class=\"w-2rem\">\n <p-skeleton width=\"1.2rem\" height=\"1.2rem\"></p-skeleton>\n </td>\n }\n }\n\n @for (col of columns; track col.field ?? col.header ?? $index) {\n <td>\n <p-skeleton\n [ngStyle]=\"{\n width: (60 + (rowIdx % 3) * 10) + '%',\n height: '1rem'\n }\"\n ></p-skeleton>\n </td>\n }\n\n <td>\n <p-skeleton width=\"2rem\" height=\"1rem\"></p-skeleton>\n </td>\n </tr>\n }\n </ng-template> -->\n\n <ng-template #emptyCell let-dataCy=\"dataCy\">\n <span [attr.data-cy]=\"dataCy\">--</span>\n </ng-template>\n\n <ng-template pTemplate=\"emptymessage\">\n <td class=\"p-2\" colspan=\"100\">\n <div class=\"flex align-items-center\">\n <i class=\"pi pi-info-circle mr-2\"></i>\n {{ \"NO_RESULTS_FOUND\" | translate }}\n </div>\n </td>\n </ng-template>\n </p-table>\n\n <div class=\"border-top-1 border-300 pl-2 p-1 text-sm text-500\">\n {{ \"LABELS.TOTAL_RECORDS\" | translate }}: {{ totalRecords }}\n </div>\n </div>\n</div>\n", styles: [":is() .p-avatar{border-radius:50%!important}::ng-deep .p-paginator button{scale:.7}::ng-deep .p-paginator-rpp-options{scale:.7}::ng-deep .p-datatable .p-datatable-header{border-radius:10px 10px 0 0}:host::ng-deep .p-tag{font-weight:400!important;font-size:.875rem!important}.email-cell{position:relative;display:inline-block;padding-right:24px}.email-cell .email-copy-icon{position:absolute;top:0;right:0;opacity:0;cursor:pointer;transition:opacity .2s}.email-cell:hover .email-copy-icon{opacity:1}.table-host{display:flex;flex-direction:column;min-height:0;overflow:hidden}.table-host,.table-host>.p-datatable,.table-host>.p-datatable .p-datatable-wrapper{min-height:0}:host ::ng-deep .p-datatable-loading-overlay{display:none!important}:host ::ng-deep .p-datatable-mask{display:none!important}:host ::ng-deep .p-datatable.p-datatable-loading{opacity:1!important;pointer-events:auto!important}\n"] }]
3701
3850
  }], ctorParameters: () => [], propDecorators: { dt: [{
3702
3851
  type: ViewChild,
3703
3852
  args: ['dt']