@masterteam/components 0.0.150 → 0.0.152

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.
@@ -1,33 +1,120 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, output, signal, computed, forwardRef, ChangeDetectionStrategy, Component, model, booleanAttribute, contentChild, inject, effect } from '@angular/core';
2
+ import { input, booleanAttribute, output, viewChild, computed, ChangeDetectionStrategy, Component, model, signal, forwardRef, Injectable, inject, contentChild, effect } from '@angular/core';
3
3
  import { NgTemplateOutlet } from '@angular/common';
4
4
  import { Card } from '@masterteam/components/card';
5
- import * as i1 from '@angular/forms';
5
+ import * as i1$1 from '@angular/forms';
6
6
  import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
7
+ import * as i2 from '@jsverse/transloco';
8
+ import { TranslocoModule } from '@jsverse/transloco';
7
9
  import { Button } from '@masterteam/components/button';
10
+ import { Tabs } from '@masterteam/components/tabs';
11
+ import { TextField } from '@masterteam/components/text-field';
12
+ import { Avatar } from '@masterteam/components/avatar';
13
+ import { Icon } from '@masterteam/icons';
14
+ import * as i1 from 'primeng/tieredmenu';
15
+ import { TieredMenuModule } from 'primeng/tieredmenu';
16
+ import * as i1$2 from 'primeng/popover';
17
+ import { PopoverModule } from 'primeng/popover';
8
18
  import { DateField } from '@masterteam/components/date-field';
9
19
  import { SelectField } from '@masterteam/components/select-field';
10
- import { TextField } from '@masterteam/components/text-field';
11
20
  import { UserSearchField } from '@masterteam/components/user-search-field';
12
- import * as i3 from '@jsverse/transloco';
13
- import { TranslocoModule } from '@jsverse/transloco';
14
- import * as i2 from 'primeng/popover';
15
- import { PopoverModule } from 'primeng/popover';
21
+ import * as XLSX from 'xlsx';
16
22
  import { ToggleField } from '@masterteam/components/toggle-field';
17
23
  import { Paginator } from '@masterteam/components/paginator';
18
24
  import { CheckboxField } from '@masterteam/components/checkbox-field';
19
- import * as i1$1 from 'primeng/table';
25
+ import * as i1$3 from 'primeng/table';
20
26
  import { TableModule } from 'primeng/table';
21
- import { Tabs } from '@masterteam/components/tabs';
22
- import * as i3$1 from 'primeng/skeleton';
27
+ import * as i3 from 'primeng/skeleton';
23
28
  import { SkeletonModule } from 'primeng/skeleton';
24
29
  import * as i4 from 'primeng/progressbar';
25
30
  import { ProgressBarModule } from 'primeng/progressbar';
26
31
  import { MTDateFormatPipe } from '@masterteam/components';
27
32
  import { ConfirmationService } from '@masterteam/components/confirmation';
28
33
  import { EntityPreview } from '@masterteam/components/entities';
29
- import { Icon } from '@masterteam/icons';
30
- import * as XLSX from 'xlsx';
34
+
35
+ /**
36
+ * Top-right `⋯` menu. Uses PrimeNG TieredMenu (popup mode) so submenu
37
+ * cascading, keyboard navigation, and outside-click-to-close come for free.
38
+ * Item rendering is overridden via the `#item` template so each row shows
39
+ * either a flat tone chip (main actions) or an `mt-avatar` (column picker).
40
+ */
41
+ class TableActionsMenu {
42
+ exportable = input(false, { ...(ngDevMode ? { debugName: "exportable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
43
+ printable = input(false, { ...(ngDevMode ? { debugName: "printable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
44
+ groupable = input(false, { ...(ngDevMode ? { debugName: "groupable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
45
+ groupColumns = input([], ...(ngDevMode ? [{ debugName: "groupColumns" }] : /* istanbul ignore next */ []));
46
+ activeGroup = input(null, ...(ngDevMode ? [{ debugName: "activeGroup" }] : /* istanbul ignore next */ []));
47
+ exportRequested = output();
48
+ printRequested = output();
49
+ groupChange = output();
50
+ menu = viewChild('menu', ...(ngDevMode ? [{ debugName: "menu" }] : /* istanbul ignore next */ []));
51
+ /** Tailwind classes for flat tone chips, keyed by `iconTone`. */
52
+ toneClass = {
53
+ emerald: 'bg-emerald-50 text-emerald-700',
54
+ sky: 'bg-sky-50 text-sky-700',
55
+ indigo: 'bg-indigo-50 text-indigo-700',
56
+ secondary: 'bg-gray-100 text-gray-700',
57
+ };
58
+ items = computed(() => {
59
+ const items = [];
60
+ if (this.exportable()) {
61
+ items.push({
62
+ labelKey: 'components.table.exportExcel',
63
+ iconKey: 'file.file-download-02',
64
+ iconTone: 'emerald',
65
+ command: () => this.exportRequested.emit(),
66
+ });
67
+ }
68
+ if (this.printable()) {
69
+ items.push({
70
+ labelKey: 'components.table.printPdf',
71
+ iconKey: 'media.printer',
72
+ iconTone: 'sky',
73
+ command: () => this.printRequested.emit(),
74
+ });
75
+ }
76
+ if (this.groupable()) {
77
+ const activeKey = this.activeGroup();
78
+ const activeLabel = this.groupColumns().find((c) => c.key === activeKey)?.label ??
79
+ activeKey ??
80
+ null;
81
+ items.push({
82
+ labelKey: 'components.table.groupBy',
83
+ iconKey: 'layout.columns-03',
84
+ iconTone: 'indigo',
85
+ badge: activeLabel ?? undefined,
86
+ items: [
87
+ {
88
+ labelKey: 'components.table.noGrouping',
89
+ iconKey: 'general.x-close',
90
+ iconTone: 'secondary',
91
+ useAvatar: true,
92
+ selected: !activeKey,
93
+ command: () => this.groupChange.emit(null),
94
+ },
95
+ ...this.groupColumns().map((col) => ({
96
+ rawLabel: col.label,
97
+ iconKey: 'layout.columns-03',
98
+ iconTone: 'secondary',
99
+ useAvatar: true,
100
+ selected: activeKey === col.key,
101
+ command: () => this.groupChange.emit(col.key),
102
+ })),
103
+ ],
104
+ });
105
+ }
106
+ return items;
107
+ }, ...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
108
+ toggle(event) {
109
+ this.menu()?.toggle(event);
110
+ }
111
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TableActionsMenu, deps: [], target: i0.ɵɵFactoryTarget.Component });
112
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: TableActionsMenu, isStandalone: true, selector: "mt-table-actions-menu", inputs: { exportable: { classPropertyName: "exportable", publicName: "exportable", isSignal: true, isRequired: false, transformFunction: null }, printable: { classPropertyName: "printable", publicName: "printable", isSignal: true, isRequired: false, transformFunction: null }, groupable: { classPropertyName: "groupable", publicName: "groupable", isSignal: true, isRequired: false, transformFunction: null }, groupColumns: { classPropertyName: "groupColumns", publicName: "groupColumns", isSignal: true, isRequired: false, transformFunction: null }, activeGroup: { classPropertyName: "activeGroup", publicName: "activeGroup", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { exportRequested: "exportRequested", printRequested: "printRequested", groupChange: "groupChange" }, viewQueries: [{ propertyName: "menu", first: true, predicate: ["menu"], descendants: true, isSignal: true }], ngImport: i0, template: "<mt-button\n (click)=\"toggle($event)\"\n icon=\"general.dots-horizontal\"\n severity=\"secondary\"\n variant=\"outlined\"\n size=\"small\"\n [tooltip]=\"'components.table.actions' | transloco\"\n/>\n\n<p-tieredMenu\n #menu\n [model]=\"items()\"\n [popup]=\"true\"\n appendTo=\"body\"\n styleClass=\"mt-table-actions-menu\"\n>\n <ng-template #item let-item let-hasSubmenu=\"hasSubmenu\">\n <button\n type=\"button\"\n class=\"flex items-center gap-2.5 w-full px-2.5 py-2 text-sm cursor-pointer text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-surface-700 transition-colors\"\n [class.bg-primary-50]=\"item.selected\"\n [class.dark:bg-primary-950]=\"item.selected\"\n [class.text-primary-700]=\"item.selected\"\n >\n @if (item.iconKey) {\n @if (item.useAvatar) {\n <mt-avatar [icon]=\"item.iconKey\" shape=\"circle\" />\n } @else {\n <span\n class=\"inline-flex items-center justify-center w-7 h-7 rounded-full shrink-0\"\n [class]=\"toneClass[item.iconTone ?? 'secondary']\"\n >\n <mt-icon [icon]=\"item.iconKey\" class=\"text-sm\" />\n </span>\n }\n }\n <span class=\"flex-1 text-start truncate\">\n @if (item.labelKey) {\n {{ item.labelKey | transloco }}\n } @else {\n {{ item.rawLabel }}\n }\n </span>\n @if (item.badge) {\n <span\n class=\"text-xs px-1.5 py-0.5 rounded-full bg-primary-50 text-primary-700 dark:bg-primary-950 dark:text-primary-300 shrink-0\"\n >\n {{ item.badge }}\n </span>\n }\n @if (hasSubmenu) {\n <mt-icon\n icon=\"arrow.chevron-right\"\n class=\"text-xs text-gray-400 shrink-0\"\n />\n }\n </button>\n </ng-template>\n</p-tieredMenu>\n", dependencies: [{ kind: "component", type: Avatar, selector: "mt-avatar", inputs: ["label", "icon", "image", "styleClass", "size", "shape", "badge", "badgeSize", "badgeSeverity"], outputs: ["onImageError"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "ngmodule", type: TieredMenuModule }, { kind: "component", type: i1.TieredMenu, selector: "p-tieredMenu, p-tieredmenu, p-tiered-menu", inputs: ["model", "popup", "style", "styleClass", "breakpoint", "autoZIndex", "baseZIndex", "autoDisplay", "showTransitionOptions", "hideTransitionOptions", "id", "ariaLabel", "ariaLabelledBy", "disabled", "tabindex", "appendTo", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "pipe", type: i2.TranslocoPipe, name: "transloco" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
113
+ }
114
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TableActionsMenu, decorators: [{
115
+ type: Component,
116
+ args: [{ selector: 'mt-table-actions-menu', standalone: true, imports: [Avatar, Button, Icon, TieredMenuModule, TranslocoModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<mt-button\n (click)=\"toggle($event)\"\n icon=\"general.dots-horizontal\"\n severity=\"secondary\"\n variant=\"outlined\"\n size=\"small\"\n [tooltip]=\"'components.table.actions' | transloco\"\n/>\n\n<p-tieredMenu\n #menu\n [model]=\"items()\"\n [popup]=\"true\"\n appendTo=\"body\"\n styleClass=\"mt-table-actions-menu\"\n>\n <ng-template #item let-item let-hasSubmenu=\"hasSubmenu\">\n <button\n type=\"button\"\n class=\"flex items-center gap-2.5 w-full px-2.5 py-2 text-sm cursor-pointer text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-surface-700 transition-colors\"\n [class.bg-primary-50]=\"item.selected\"\n [class.dark:bg-primary-950]=\"item.selected\"\n [class.text-primary-700]=\"item.selected\"\n >\n @if (item.iconKey) {\n @if (item.useAvatar) {\n <mt-avatar [icon]=\"item.iconKey\" shape=\"circle\" />\n } @else {\n <span\n class=\"inline-flex items-center justify-center w-7 h-7 rounded-full shrink-0\"\n [class]=\"toneClass[item.iconTone ?? 'secondary']\"\n >\n <mt-icon [icon]=\"item.iconKey\" class=\"text-sm\" />\n </span>\n }\n }\n <span class=\"flex-1 text-start truncate\">\n @if (item.labelKey) {\n {{ item.labelKey | transloco }}\n } @else {\n {{ item.rawLabel }}\n }\n </span>\n @if (item.badge) {\n <span\n class=\"text-xs px-1.5 py-0.5 rounded-full bg-primary-50 text-primary-700 dark:bg-primary-950 dark:text-primary-300 shrink-0\"\n >\n {{ item.badge }}\n </span>\n }\n @if (hasSubmenu) {\n <mt-icon\n icon=\"arrow.chevron-right\"\n class=\"text-xs text-gray-400 shrink-0\"\n />\n }\n </button>\n </ng-template>\n</p-tieredMenu>\n" }]
117
+ }], propDecorators: { exportable: [{ type: i0.Input, args: [{ isSignal: true, alias: "exportable", required: false }] }], printable: [{ type: i0.Input, args: [{ isSignal: true, alias: "printable", required: false }] }], groupable: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupable", required: false }] }], groupColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupColumns", required: false }] }], activeGroup: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeGroup", required: false }] }], exportRequested: [{ type: i0.Output, args: ["exportRequested"] }], printRequested: [{ type: i0.Output, args: ["printRequested"] }], groupChange: [{ type: i0.Output, args: ["groupChange"] }], menu: [{ type: i0.ViewChild, args: ['menu', { isSignal: true }] }] } });
31
118
 
32
119
  class TableValueResolver {
33
120
  static ALL_ENTITY_VIEW_TYPES = [
@@ -107,6 +194,241 @@ class TableValueResolver {
107
194
  return 'text';
108
195
  }
109
196
  }
197
+ /**
198
+ * Returns a column with its filterConfig normalized for rendering:
199
+ * - `type` is resolved via `getColumnFilterType`
200
+ * - `options` for `select` filters are auto-generated from `data` when not provided
201
+ *
202
+ * Used by both popover and per-column filter modes so option-building stays in one place.
203
+ */
204
+ static buildFilterableColumn(column, data) {
205
+ const sampleRow = data[0];
206
+ const filterType = TableValueResolver.getColumnFilterType(column, sampleRow);
207
+ if (filterType === 'select' && !column.filterConfig?.options?.length) {
208
+ const uniqueOptions = Array.from(data.reduce((options, row) => {
209
+ const value = TableValueResolver.getColumnFilterValue(row, column);
210
+ if (value === null || value === undefined || value === '') {
211
+ return options;
212
+ }
213
+ const optionKey = `${typeof value}:${String(value)}`;
214
+ if (!options.has(optionKey)) {
215
+ options.set(optionKey, {
216
+ label: String(value),
217
+ value,
218
+ });
219
+ }
220
+ return options;
221
+ }, new Map()))
222
+ .map(([, option]) => option)
223
+ .sort((a, b) => a.label.localeCompare(b.label));
224
+ return {
225
+ ...column,
226
+ filterConfig: {
227
+ ...column.filterConfig,
228
+ type: filterType,
229
+ options: uniqueOptions,
230
+ },
231
+ };
232
+ }
233
+ return {
234
+ ...column,
235
+ filterConfig: {
236
+ ...column.filterConfig,
237
+ type: filterType ?? column.filterConfig?.type ?? 'text',
238
+ },
239
+ };
240
+ }
241
+ /**
242
+ * Returns true when `item` passes the filter for `key`. Pure function — callers
243
+ * pass `column` so the resolver can apply type-aware normalisation (entity,
244
+ * status, user, date, boolean). Shared by `mt-table` row-filtering and
245
+ * `client-list-cards-view` card-filtering.
246
+ */
247
+ static matchesFilter(item, key, filterValue, column) {
248
+ if (filterValue === null ||
249
+ filterValue === undefined ||
250
+ filterValue === '') {
251
+ return true;
252
+ }
253
+ const itemValue = TableValueResolver.getProperty(item, key);
254
+ const normalizedFilterValue = column
255
+ ? TableValueResolver.getColumnFilterValue(item, column)
256
+ : TableValueResolver.resolveDisplayValue(itemValue);
257
+ const filterType = column
258
+ ? TableValueResolver.getColumnFilterType(column, item)
259
+ : null;
260
+ if (typeof filterValue === 'object' && filterValue !== null) {
261
+ const objectFilter = filterValue;
262
+ if (objectFilter.from || objectFilter.to) {
263
+ const itemDateValue = filterType === 'date'
264
+ ? typeof normalizedFilterValue === 'number'
265
+ ? normalizedFilterValue
266
+ : null
267
+ : itemValue instanceof Date
268
+ ? itemValue.getTime()
269
+ : new Date(String(itemValue)).getTime();
270
+ if (itemDateValue === null ||
271
+ itemDateValue === undefined ||
272
+ Number.isNaN(itemDateValue)) {
273
+ return true;
274
+ }
275
+ if (objectFilter.from &&
276
+ itemDateValue < new Date(objectFilter.from).getTime()) {
277
+ return false;
278
+ }
279
+ if (objectFilter.to &&
280
+ itemDateValue > new Date(objectFilter.to).getTime()) {
281
+ return false;
282
+ }
283
+ return true;
284
+ }
285
+ if (objectFilter.userName) {
286
+ const normalizedItemUser = itemValue;
287
+ if (!normalizedItemUser)
288
+ return false;
289
+ return (normalizedItemUser['id'] === objectFilter.id ||
290
+ normalizedItemUser['userName'] === objectFilter.userName ||
291
+ normalizedItemUser['displayName'] === objectFilter.displayName);
292
+ }
293
+ }
294
+ if (typeof filterValue === 'boolean') {
295
+ return normalizedFilterValue === filterValue;
296
+ }
297
+ if (typeof normalizedFilterValue === 'string' ||
298
+ typeof normalizedFilterValue === 'number') {
299
+ return String(normalizedFilterValue)
300
+ .toLowerCase()
301
+ .includes(String(filterValue).toLowerCase());
302
+ }
303
+ return normalizedFilterValue === filterValue;
304
+ }
305
+ /**
306
+ * Applies every entry of `filters` against `item` — used by cards view and
307
+ * anywhere else that consumes the same filter shape as mt-table.
308
+ */
309
+ static matchesAllFilters(item, filters, columns) {
310
+ return Object.keys(filters).every((key) => {
311
+ if (key === 'generalSearch')
312
+ return true;
313
+ const column = columns.find((col) => col.key === key);
314
+ return TableValueResolver.matchesFilter(item, key, filters[key], column);
315
+ });
316
+ }
317
+ /**
318
+ * True when a filter slot holds a meaningful value (scalar, text, date-range bounds,
319
+ * or user lookup). Shared by popover and per-column modes to compute active counts.
320
+ */
321
+ static hasFilterValue(value) {
322
+ if (value === null || value === undefined || value === '') {
323
+ return false;
324
+ }
325
+ if (typeof value === 'object') {
326
+ const filterValue = value;
327
+ return (filterValue.from != null ||
328
+ filterValue.to != null ||
329
+ filterValue.value != null ||
330
+ filterValue.userName != null ||
331
+ filterValue.id != null);
332
+ }
333
+ return true;
334
+ }
335
+ /**
336
+ * Produces the filter payload a cell-click should apply for `column`.
337
+ * Returns null when the cell type is not click-filterable.
338
+ *
339
+ * Shapes match `Table.matchesFilter` branches:
340
+ * - user / entity(User) → `{ id, userName, displayName }`
341
+ * - status / entity(Status|Lookup) → scalar display string
342
+ * - boolean → boolean
343
+ */
344
+ static buildClickFilterValue(row, column) {
345
+ const cellValue = TableValueResolver.getProperty(row, column.key);
346
+ if (cellValue === null || cellValue === undefined || cellValue === '') {
347
+ return null;
348
+ }
349
+ const filterType = TableValueResolver.getColumnFilterType(column, row);
350
+ if (column.type === 'user' || filterType === 'user') {
351
+ // Entity(User) envelopes store the user object under `.value`; plain user
352
+ // columns may hold it directly. Both paths produce the {id,userName,displayName} shape.
353
+ const source = column.type === 'entity' &&
354
+ cellValue &&
355
+ typeof cellValue === 'object' &&
356
+ 'value' in cellValue
357
+ ? cellValue['value']
358
+ : cellValue;
359
+ return TableValueResolver.extractUserFilterValue(source);
360
+ }
361
+ // Entity-typed columns carry a `{ viewType, value, rawValue, ... }` envelope.
362
+ // Unwrap once so boolean / scalar branches below operate on the inner value,
363
+ // matching what `matchesFilter` -> `getColumnFilterValue` compares against.
364
+ const normalized = column.type === 'entity'
365
+ ? TableValueResolver.getEntityValueByType(cellValue, 'filter')
366
+ : cellValue;
367
+ if (normalized === null || normalized === undefined || normalized === '') {
368
+ return null;
369
+ }
370
+ if (filterType === 'boolean') {
371
+ return TableValueResolver.resolveBooleanValue(normalized);
372
+ }
373
+ if (filterType === 'select' || filterType === 'text') {
374
+ if (column.type === 'entity') {
375
+ return String(normalized);
376
+ }
377
+ const display = TableValueResolver.resolveDisplayValue(cellValue);
378
+ return display === null ? null : String(display);
379
+ }
380
+ return null;
381
+ }
382
+ /**
383
+ * True when two filter values refer to the same thing. Mirrors the branches
384
+ * in `Table.matchesFilter`: scalar equality, boolean equality, or user-object
385
+ * identity on id / userName / displayName.
386
+ */
387
+ static isFilterValueEqual(a, b) {
388
+ if (a === b)
389
+ return true;
390
+ if (a === null || a === undefined || b === null || b === undefined) {
391
+ return false;
392
+ }
393
+ if (typeof a === 'object' && typeof b === 'object') {
394
+ const left = a;
395
+ const right = b;
396
+ if (left['id'] != null && left['id'] === right['id'])
397
+ return true;
398
+ if (left['userName'] != null && left['userName'] === right['userName']) {
399
+ return true;
400
+ }
401
+ if (left['displayName'] != null &&
402
+ left['displayName'] === right['displayName']) {
403
+ return true;
404
+ }
405
+ return false;
406
+ }
407
+ return String(a) === String(b);
408
+ }
409
+ static extractUserFilterValue(value) {
410
+ if (value === null || value === undefined)
411
+ return null;
412
+ if (typeof value === 'object') {
413
+ const record = value;
414
+ const inner = record['value'] && typeof record['value'] === 'object'
415
+ ? record['value']
416
+ : record;
417
+ const id = inner['id'];
418
+ const userName = inner['userName'] ?? inner['username'];
419
+ const displayName = inner['displayName'] ?? inner['name'];
420
+ if (id == null && userName == null && displayName == null) {
421
+ const fallback = TableValueResolver.resolveDisplayValue(value);
422
+ return fallback === null ? null : String(fallback);
423
+ }
424
+ return {
425
+ ...(id != null ? { id } : {}),
426
+ ...(userName != null ? { userName } : {}),
427
+ ...(displayName != null ? { displayName } : {}),
428
+ };
429
+ }
430
+ return String(value);
431
+ }
110
432
  static getColumnFilterValue(row, column) {
111
433
  const cellValue = TableValueResolver.getProperty(row, column.key);
112
434
  if (cellValue === null || cellValue === undefined) {
@@ -273,6 +595,57 @@ class TableValueResolver {
273
595
  }
274
596
  }
275
597
 
598
+ /**
599
+ * Renders a single filter control for one `ColumnDef`, dispatching on
600
+ * `column.filterConfig.type` (`text` | `select` | `date` | `boolean` | `user`).
601
+ *
602
+ * Two-way binds the filter value via `value` / `valueChange`. Shared by both
603
+ * filter UX modes (popover + per-column) so field rendering lives in one place.
604
+ * Add a new filter type by adding a `@case` in the template and extending
605
+ * `FilterConfig['type']`.
606
+ */
607
+ class TableFilterField {
608
+ column = input.required(...(ngDevMode ? [{ debugName: "column" }] : /* istanbul ignore next */ []));
609
+ value = model(null, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
610
+ booleanOptions = [
611
+ { label: 'Yes', value: true },
612
+ { label: 'No', value: false },
613
+ ];
614
+ getFilterType() {
615
+ return this.column().filterConfig?.type ?? 'text';
616
+ }
617
+ getScalarValue() {
618
+ const current = this.value();
619
+ return current?.value ?? current ?? null;
620
+ }
621
+ getDateRangeValue(part) {
622
+ const current = this.value();
623
+ if (!current || typeof current !== 'object')
624
+ return null;
625
+ return part === 'from' ? (current.from ?? null) : (current.to ?? null);
626
+ }
627
+ updateScalar(next) {
628
+ this.value.set(next);
629
+ }
630
+ updateDate(part, next) {
631
+ const current = this.value() ?? {};
632
+ this.value.set({ ...current, [part]: next });
633
+ }
634
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TableFilterField, deps: [], target: i0.ɵɵFactoryTarget.Component });
635
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: TableFilterField, isStandalone: true, selector: "mt-table-filter-field", inputs: { column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, ngImport: i0, template: "@switch (getFilterType()) {\n @case (\"text\") {\n <mt-text-field\n [ngModel]=\"getScalarValue()\"\n (ngModelChange)=\"updateScalar($event)\"\n [placeholder]=\"\n ('components.table.select' | transloco) +\n ' ' +\n (column().filterConfig?.label || column().label)\n \"\n />\n }\n @case (\"select\") {\n <mt-select-field\n [ngModel]=\"getScalarValue()\"\n (ngModelChange)=\"updateScalar($event)\"\n [options]=\"column().filterConfig?.options ?? []\"\n [placeholder]=\"\n ('components.table.select' | transloco) +\n ' ' +\n (column().filterConfig?.label || column().label)\n \"\n [hasPlaceholderPrefix]=\"false\"\n showClear\n />\n }\n @case (\"date\") {\n <div class=\"space-y-3\">\n <div class=\"space-y-1\">\n <label\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\n >\n {{ \"components.table.from\" | transloco }}\n </label>\n <mt-date-field\n [ngModel]=\"getDateRangeValue('from')\"\n (ngModelChange)=\"updateDate('from', $event)\"\n [placeholder]=\"'components.table.from' | transloco\"\n />\n </div>\n <div class=\"space-y-1\">\n <label\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\n >\n {{ \"components.table.to\" | transloco }}\n </label>\n <mt-date-field\n [ngModel]=\"getDateRangeValue('to')\"\n (ngModelChange)=\"updateDate('to', $event)\"\n [placeholder]=\"'components.table.to' | transloco\"\n />\n </div>\n </div>\n }\n @case (\"boolean\") {\n <mt-select-field\n [ngModel]=\"getScalarValue()\"\n (ngModelChange)=\"updateScalar($event)\"\n [options]=\"booleanOptions\"\n [placeholder]=\"'components.table.select' | transloco\"\n [hasPlaceholderPrefix]=\"false\"\n showClear\n />\n }\n @case (\"user\") {\n <mt-user-search-field\n [ngModel]=\"getScalarValue()\"\n (ngModelChange)=\"updateScalar($event)\"\n [placeholder]=\"column().filterConfig?.label || column().label\"\n [apiUrl]=\"column().filterConfig?.apiUrl ?? ''\"\n [context]=\"column().filterConfig?.context\"\n />\n }\n}\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "icon", "iconPosition"] }, { kind: "component", type: SelectField, selector: "mt-select-field", inputs: ["field", "hint", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "component", type: DateField, selector: "mt-date-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "showIcon", "showClear", "showTime", "pInputs", "required"] }, { kind: "component", type: UserSearchField, selector: "mt-user-search-field", inputs: ["hint", "label", "placeholder", "class", "readonly", "required", "isMultiple", "apiUrl", "dataKey", "paramName", "context", "size"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "pipe", type: i2.TranslocoPipe, name: "transloco" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
636
+ }
637
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TableFilterField, decorators: [{
638
+ type: Component,
639
+ args: [{ selector: 'mt-table-filter-field', standalone: true, imports: [
640
+ FormsModule,
641
+ TextField,
642
+ SelectField,
643
+ DateField,
644
+ UserSearchField,
645
+ TranslocoModule,
646
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "@switch (getFilterType()) {\n @case (\"text\") {\n <mt-text-field\n [ngModel]=\"getScalarValue()\"\n (ngModelChange)=\"updateScalar($event)\"\n [placeholder]=\"\n ('components.table.select' | transloco) +\n ' ' +\n (column().filterConfig?.label || column().label)\n \"\n />\n }\n @case (\"select\") {\n <mt-select-field\n [ngModel]=\"getScalarValue()\"\n (ngModelChange)=\"updateScalar($event)\"\n [options]=\"column().filterConfig?.options ?? []\"\n [placeholder]=\"\n ('components.table.select' | transloco) +\n ' ' +\n (column().filterConfig?.label || column().label)\n \"\n [hasPlaceholderPrefix]=\"false\"\n showClear\n />\n }\n @case (\"date\") {\n <div class=\"space-y-3\">\n <div class=\"space-y-1\">\n <label\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\n >\n {{ \"components.table.from\" | transloco }}\n </label>\n <mt-date-field\n [ngModel]=\"getDateRangeValue('from')\"\n (ngModelChange)=\"updateDate('from', $event)\"\n [placeholder]=\"'components.table.from' | transloco\"\n />\n </div>\n <div class=\"space-y-1\">\n <label\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\n >\n {{ \"components.table.to\" | transloco }}\n </label>\n <mt-date-field\n [ngModel]=\"getDateRangeValue('to')\"\n (ngModelChange)=\"updateDate('to', $event)\"\n [placeholder]=\"'components.table.to' | transloco\"\n />\n </div>\n </div>\n }\n @case (\"boolean\") {\n <mt-select-field\n [ngModel]=\"getScalarValue()\"\n (ngModelChange)=\"updateScalar($event)\"\n [options]=\"booleanOptions\"\n [placeholder]=\"'components.table.select' | transloco\"\n [hasPlaceholderPrefix]=\"false\"\n showClear\n />\n }\n @case (\"user\") {\n <mt-user-search-field\n [ngModel]=\"getScalarValue()\"\n (ngModelChange)=\"updateScalar($event)\"\n [placeholder]=\"column().filterConfig?.label || column().label\"\n [apiUrl]=\"column().filterConfig?.apiUrl ?? ''\"\n [context]=\"column().filterConfig?.context\"\n />\n }\n}\n" }]
647
+ }], propDecorators: { column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }] } });
648
+
276
649
  class TableFilter {
277
650
  columns = input.required(...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
278
651
  data = input([], ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
@@ -280,68 +653,12 @@ class TableFilter {
280
653
  filterReset = output();
281
654
  pendingFilters = signal({}, ...(ngDevMode ? [{ debugName: "pendingFilters" }] : /* istanbul ignore next */ []));
282
655
  appliedFilters = signal({}, ...(ngDevMode ? [{ debugName: "appliedFilters" }] : /* istanbul ignore next */ []));
283
- booleanOptions = [
284
- { label: 'Yes', value: true },
285
- { label: 'No', value: false },
286
- ];
287
656
  onChange = () => { };
288
657
  onTouched = () => { };
289
658
  filterableColumns = computed(() => this.columns()
290
659
  .filter((col) => TableValueResolver.getColumnFilterType(col, this.data()[0]) !== null)
291
- .map((col) => {
292
- const filterType = TableValueResolver.getColumnFilterType(col, this.data()[0]);
293
- // Auto-generate select options from data if not provided
294
- if (filterType === 'select' && !col.filterConfig?.options?.length) {
295
- const uniqueOptions = Array.from(this.data().reduce((options, row) => {
296
- const value = TableValueResolver.getColumnFilterValue(row, col);
297
- if (value === null || value === undefined || value === '') {
298
- return options;
299
- }
300
- const optionKey = `${typeof value}:${String(value)}`;
301
- if (!options.has(optionKey)) {
302
- options.set(optionKey, {
303
- label: String(value),
304
- value,
305
- });
306
- }
307
- return options;
308
- }, new Map()))
309
- .map(([, option]) => option)
310
- .sort((a, b) => a.label.localeCompare(b.label));
311
- return {
312
- ...col,
313
- filterConfig: {
314
- ...col.filterConfig,
315
- type: filterType,
316
- options: uniqueOptions,
317
- },
318
- };
319
- }
320
- return {
321
- ...col,
322
- filterConfig: {
323
- ...col.filterConfig,
324
- type: filterType ?? col.filterConfig?.type ?? 'text',
325
- },
326
- };
327
- }), ...(ngDevMode ? [{ debugName: "filterableColumns" }] : /* istanbul ignore next */ []));
328
- activeFilterCount = computed(() => {
329
- const filters = this.appliedFilters();
330
- return Object.values(filters).filter((v) => this.hasValue(v)).length;
331
- }, ...(ngDevMode ? [{ debugName: "activeFilterCount" }] : /* istanbul ignore next */ []));
332
- getFilterType(col) {
333
- return (TableValueResolver.getColumnFilterType(col, this.data()[0]) ?? 'text');
334
- }
335
- getFilterValue(key) {
336
- const value = this.pendingFilters()[key];
337
- return value?.value ?? value ?? null;
338
- }
339
- getDateRangeValue(key, part) {
340
- const value = this.pendingFilters()[key];
341
- if (!value || typeof value !== 'object')
342
- return null;
343
- return part === 'from' ? (value.from ?? null) : (value.to ?? null);
344
- }
660
+ .map((col) => TableValueResolver.buildFilterableColumn(col, this.data())), ...(ngDevMode ? [{ debugName: "filterableColumns" }] : /* istanbul ignore next */ []));
661
+ activeFilterCount = computed(() => Object.values(this.appliedFilters()).filter((value) => TableValueResolver.hasFilterValue(value)).length, ...(ngDevMode ? [{ debugName: "activeFilterCount" }] : /* istanbul ignore next */ []));
345
662
  updateFilter(key, value) {
346
663
  this.pendingFilters.update((filters) => ({
347
664
  ...filters,
@@ -349,19 +666,6 @@ class TableFilter {
349
666
  }));
350
667
  this.onTouched();
351
668
  }
352
- updateDateFilter(key, part, value) {
353
- this.pendingFilters.update((filters) => {
354
- const current = filters[key] ?? {};
355
- return {
356
- ...filters,
357
- [key]: {
358
- ...current,
359
- [part]: value,
360
- },
361
- };
362
- });
363
- this.onTouched();
364
- }
365
669
  apply() {
366
670
  const filters = { ...this.pendingFilters() };
367
671
  this.appliedFilters.set(filters);
@@ -374,14 +678,6 @@ class TableFilter {
374
678
  this.onChange({});
375
679
  this.filterReset.emit();
376
680
  }
377
- hasValue(value) {
378
- if (value === null || value === undefined || value === '')
379
- return false;
380
- if (typeof value === 'object') {
381
- return value.from != null || value.to != null || value.value != null;
382
- }
383
- return true;
384
- }
385
681
  // ControlValueAccessor
386
682
  writeValue(value) {
387
683
  const filters = value ?? {};
@@ -401,28 +697,429 @@ class TableFilter {
401
697
  useExisting: forwardRef(() => TableFilter),
402
698
  multi: true,
403
699
  },
404
- ], ngImport: i0, template: "<mt-button\r\n (click)=\"popover.toggle($event)\"\r\n [label]=\"'components.table.filter' | transloco\"\r\n [badge]=\"activeFilterCount()\"\r\n severity=\"primary\"\r\n icon=\"general.filter-funnel-01\"\r\n/>\r\n\r\n<p-popover #popover [style]=\"{ width: '320px' }\" appendTo=\"body\">\r\n <div class=\"flex flex-col max-h-[50vh]\">\r\n <h4\r\n class=\"text-lg py-2 font-semibold border-b border-surface-200 dark:border-surface-700 shrink-0\"\r\n >\r\n {{ \"components.table.filterOptions\" | transloco }}\r\n </h4>\r\n\r\n <div\r\n class=\"space-y-3 overflow-y-auto flex-1 py-3\"\r\n (keydown.enter)=\"apply(); popover.hide()\"\r\n >\r\n @for (col of filterableColumns(); track col.key) {\r\n <div class=\"space-y-1\">\r\n <label\r\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\r\n >\r\n {{ col.filterConfig?.label || col.label }}\r\n </label>\r\n\r\n @switch (getFilterType(col)) {\r\n @case (\"text\") {\r\n <mt-text-field\r\n [ngModel]=\"getFilterValue(col.key)\"\r\n (ngModelChange)=\"updateFilter(col.key, $event)\"\r\n [placeholder]=\"\r\n ('components.table.select' | transloco) +\r\n ' ' +\r\n (col.filterConfig?.label || col.label)\r\n \"\r\n />\r\n }\r\n @case (\"select\") {\r\n <mt-select-field\r\n [ngModel]=\"getFilterValue(col.key)\"\r\n (ngModelChange)=\"updateFilter(col.key, $event)\"\r\n [options]=\"col.filterConfig?.options ?? []\"\r\n [placeholder]=\"\r\n ('components.table.select' | transloco) +\r\n ' ' +\r\n (col.filterConfig?.label || col.label)\r\n \"\r\n [hasPlaceholderPrefix]=\"false\"\r\n showClear\r\n />\r\n }\r\n @case (\"date\") {\r\n <div class=\"space-y-3\">\r\n <div class=\"space-y-1\">\r\n <label\r\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\r\n >\r\n {{ \"components.table.from\" | transloco }}\r\n </label>\r\n <mt-date-field\r\n [ngModel]=\"getDateRangeValue(col.key, 'from')\"\r\n (ngModelChange)=\"updateDateFilter(col.key, 'from', $event)\"\r\n [placeholder]=\"'components.table.from' | transloco\"\r\n />\r\n </div>\r\n <div class=\"space-y-1\">\r\n <label\r\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\r\n >\r\n {{ \"components.table.to\" | transloco }}\r\n </label>\r\n <mt-date-field\r\n [ngModel]=\"getDateRangeValue(col.key, 'to')\"\r\n (ngModelChange)=\"updateDateFilter(col.key, 'to', $event)\"\r\n [placeholder]=\"'components.table.to' | transloco\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n @case (\"boolean\") {\r\n <mt-select-field\r\n [ngModel]=\"getFilterValue(col.key)\"\r\n (ngModelChange)=\"updateFilter(col.key, $event)\"\r\n [options]=\"booleanOptions\"\r\n [placeholder]=\"'components.table.select' | transloco\"\r\n [hasPlaceholderPrefix]=\"false\"\r\n showClear\r\n />\r\n }\r\n @case (\"user\") {\r\n <mt-user-search-field\r\n [ngModel]=\"getFilterValue(col.key)\"\r\n (ngModelChange)=\"updateFilter(col.key, $event)\"\r\n [placeholder]=\"col.filterConfig?.label || col.label\"\r\n [apiUrl]=\"col.filterConfig?.apiUrl ?? ''\"\r\n [context]=\"col.filterConfig?.context\"\r\n />\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n <div\r\n class=\"flex justify-end gap-2 pt-4 border-t border-surface-200 dark:border-surface-700 shrink-0\"\r\n >\r\n <mt-button\r\n variant=\"outlined\"\r\n (click)=\"reset(); popover.hide()\"\r\n [label]=\"'components.table.reset' | transloco\"\r\n />\r\n <mt-button\r\n (click)=\"apply(); popover.hide()\"\r\n [label]=\"'components.table.apply' | transloco\"\r\n />\r\n </div>\r\n </div>\r\n</p-popover>\r\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "icon", "iconPosition"] }, { kind: "component", type: SelectField, selector: "mt-select-field", inputs: ["field", "hint", "label", "placeholder", "hasPlaceholderPrefix", "class", "readonly", "pInputs", "options", "optionValue", "optionLabel", "filter", "filterBy", "dataKey", "showClear", "clearAfterSelect", "required", "group", "size", "optionGroupLabel", "optionGroupChildren", "loading", "optionIcon", "optionIconColor", "optionIconShape", "optionAvatarShape", "optionGroupIcon", "optionGroupIconColor", "optionGroupIconShape", "optionGroupAvatarShape"], outputs: ["onChange"] }, { kind: "component", type: DateField, selector: "mt-date-field", inputs: ["field", "hint", "label", "placeholder", "class", "readonly", "showIcon", "showClear", "showTime", "pInputs", "required"] }, { kind: "component", type: UserSearchField, selector: "mt-user-search-field", inputs: ["hint", "label", "placeholder", "class", "readonly", "required", "isMultiple", "apiUrl", "dataKey", "paramName", "context", "size"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i2.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "pipe", type: i3.TranslocoPipe, name: "transloco" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
700
+ ], ngImport: i0, template: "<mt-button\n (click)=\"popover.toggle($event)\"\n [label]=\"'components.table.filter' | transloco\"\n [badge]=\"activeFilterCount()\"\n severity=\"primary\"\n size=\"small\"\n icon=\"general.filter-funnel-01\"\n/>\n\n<p-popover #popover [style]=\"{ width: '320px' }\" appendTo=\"body\">\n <div class=\"flex flex-col max-h-[50vh]\">\n <h4\n class=\"text-lg py-2 font-semibold border-b border-surface-200 dark:border-surface-700 shrink-0\"\n >\n {{ \"components.table.filterOptions\" | transloco }}\n </h4>\n\n <div\n class=\"space-y-3 overflow-y-auto flex-1 py-3\"\n (keydown.enter)=\"apply(); popover.hide()\"\n >\n @for (col of filterableColumns(); track col.key) {\n <div class=\"space-y-1\">\n <label\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\n >\n {{ col.filterConfig?.label || col.label }}\n </label>\n <mt-table-filter-field\n [column]=\"col\"\n [value]=\"pendingFilters()[col.key]\"\n (valueChange)=\"updateFilter(col.key, $event)\"\n />\n </div>\n }\n </div>\n\n <div\n class=\"flex justify-end gap-2 pt-4 border-t border-surface-200 dark:border-surface-700 shrink-0\"\n >\n <mt-button\n variant=\"outlined\"\n (click)=\"reset(); popover.hide()\"\n [label]=\"'components.table.reset' | transloco\"\n />\n <mt-button\n (click)=\"apply(); popover.hide()\"\n [label]=\"'components.table.apply' | transloco\"\n />\n </div>\n </div>\n</p-popover>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i1$2.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "component", type: TableFilterField, selector: "mt-table-filter-field", inputs: ["column", "value"], outputs: ["valueChange"] }, { kind: "pipe", type: i2.TranslocoPipe, name: "transloco" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
405
701
  }
406
702
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TableFilter, decorators: [{
407
703
  type: Component,
408
704
  args: [{ selector: 'mt-table-filter', standalone: true, imports: [
409
705
  FormsModule,
410
- TextField,
411
- SelectField,
412
- DateField,
413
- UserSearchField,
414
706
  Button,
415
707
  PopoverModule,
416
708
  TranslocoModule,
709
+ TableFilterField,
417
710
  ], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
418
711
  {
419
712
  provide: NG_VALUE_ACCESSOR,
420
713
  useExisting: forwardRef(() => TableFilter),
421
714
  multi: true,
422
715
  },
423
- ], template: "<mt-button\r\n (click)=\"popover.toggle($event)\"\r\n [label]=\"'components.table.filter' | transloco\"\r\n [badge]=\"activeFilterCount()\"\r\n severity=\"primary\"\r\n icon=\"general.filter-funnel-01\"\r\n/>\r\n\r\n<p-popover #popover [style]=\"{ width: '320px' }\" appendTo=\"body\">\r\n <div class=\"flex flex-col max-h-[50vh]\">\r\n <h4\r\n class=\"text-lg py-2 font-semibold border-b border-surface-200 dark:border-surface-700 shrink-0\"\r\n >\r\n {{ \"components.table.filterOptions\" | transloco }}\r\n </h4>\r\n\r\n <div\r\n class=\"space-y-3 overflow-y-auto flex-1 py-3\"\r\n (keydown.enter)=\"apply(); popover.hide()\"\r\n >\r\n @for (col of filterableColumns(); track col.key) {\r\n <div class=\"space-y-1\">\r\n <label\r\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\r\n >\r\n {{ col.filterConfig?.label || col.label }}\r\n </label>\r\n\r\n @switch (getFilterType(col)) {\r\n @case (\"text\") {\r\n <mt-text-field\r\n [ngModel]=\"getFilterValue(col.key)\"\r\n (ngModelChange)=\"updateFilter(col.key, $event)\"\r\n [placeholder]=\"\r\n ('components.table.select' | transloco) +\r\n ' ' +\r\n (col.filterConfig?.label || col.label)\r\n \"\r\n />\r\n }\r\n @case (\"select\") {\r\n <mt-select-field\r\n [ngModel]=\"getFilterValue(col.key)\"\r\n (ngModelChange)=\"updateFilter(col.key, $event)\"\r\n [options]=\"col.filterConfig?.options ?? []\"\r\n [placeholder]=\"\r\n ('components.table.select' | transloco) +\r\n ' ' +\r\n (col.filterConfig?.label || col.label)\r\n \"\r\n [hasPlaceholderPrefix]=\"false\"\r\n showClear\r\n />\r\n }\r\n @case (\"date\") {\r\n <div class=\"space-y-3\">\r\n <div class=\"space-y-1\">\r\n <label\r\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\r\n >\r\n {{ \"components.table.from\" | transloco }}\r\n </label>\r\n <mt-date-field\r\n [ngModel]=\"getDateRangeValue(col.key, 'from')\"\r\n (ngModelChange)=\"updateDateFilter(col.key, 'from', $event)\"\r\n [placeholder]=\"'components.table.from' | transloco\"\r\n />\r\n </div>\r\n <div class=\"space-y-1\">\r\n <label\r\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\r\n >\r\n {{ \"components.table.to\" | transloco }}\r\n </label>\r\n <mt-date-field\r\n [ngModel]=\"getDateRangeValue(col.key, 'to')\"\r\n (ngModelChange)=\"updateDateFilter(col.key, 'to', $event)\"\r\n [placeholder]=\"'components.table.to' | transloco\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n @case (\"boolean\") {\r\n <mt-select-field\r\n [ngModel]=\"getFilterValue(col.key)\"\r\n (ngModelChange)=\"updateFilter(col.key, $event)\"\r\n [options]=\"booleanOptions\"\r\n [placeholder]=\"'components.table.select' | transloco\"\r\n [hasPlaceholderPrefix]=\"false\"\r\n showClear\r\n />\r\n }\r\n @case (\"user\") {\r\n <mt-user-search-field\r\n [ngModel]=\"getFilterValue(col.key)\"\r\n (ngModelChange)=\"updateFilter(col.key, $event)\"\r\n [placeholder]=\"col.filterConfig?.label || col.label\"\r\n [apiUrl]=\"col.filterConfig?.apiUrl ?? ''\"\r\n [context]=\"col.filterConfig?.context\"\r\n />\r\n }\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n <div\r\n class=\"flex justify-end gap-2 pt-4 border-t border-surface-200 dark:border-surface-700 shrink-0\"\r\n >\r\n <mt-button\r\n variant=\"outlined\"\r\n (click)=\"reset(); popover.hide()\"\r\n [label]=\"'components.table.reset' | transloco\"\r\n />\r\n <mt-button\r\n (click)=\"apply(); popover.hide()\"\r\n [label]=\"'components.table.apply' | transloco\"\r\n />\r\n </div>\r\n </div>\r\n</p-popover>\r\n" }]
716
+ ], template: "<mt-button\n (click)=\"popover.toggle($event)\"\n [label]=\"'components.table.filter' | transloco\"\n [badge]=\"activeFilterCount()\"\n severity=\"primary\"\n size=\"small\"\n icon=\"general.filter-funnel-01\"\n/>\n\n<p-popover #popover [style]=\"{ width: '320px' }\" appendTo=\"body\">\n <div class=\"flex flex-col max-h-[50vh]\">\n <h4\n class=\"text-lg py-2 font-semibold border-b border-surface-200 dark:border-surface-700 shrink-0\"\n >\n {{ \"components.table.filterOptions\" | transloco }}\n </h4>\n\n <div\n class=\"space-y-3 overflow-y-auto flex-1 py-3\"\n (keydown.enter)=\"apply(); popover.hide()\"\n >\n @for (col of filterableColumns(); track col.key) {\n <div class=\"space-y-1\">\n <label\n class=\"block text-sm font-medium text-gray-700 dark:text-gray-300\"\n >\n {{ col.filterConfig?.label || col.label }}\n </label>\n <mt-table-filter-field\n [column]=\"col\"\n [value]=\"pendingFilters()[col.key]\"\n (valueChange)=\"updateFilter(col.key, $event)\"\n />\n </div>\n }\n </div>\n\n <div\n class=\"flex justify-end gap-2 pt-4 border-t border-surface-200 dark:border-surface-700 shrink-0\"\n >\n <mt-button\n variant=\"outlined\"\n (click)=\"reset(); popover.hide()\"\n [label]=\"'components.table.reset' | transloco\"\n />\n <mt-button\n (click)=\"apply(); popover.hide()\"\n [label]=\"'components.table.apply' | transloco\"\n />\n </div>\n </div>\n</p-popover>\n" }]
424
717
  }], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], filterApplied: [{ type: i0.Output, args: ["filterApplied"] }], filterReset: [{ type: i0.Output, args: ["filterReset"] }] } });
425
718
 
719
+ /**
720
+ * Stateless, controlled toolbar used by `mt-table` and by list-style consumers
721
+ * (e.g. `client-list-cards-view`) so the two share one caption UI without
722
+ * duplicating the search/filter/actions markup.
723
+ *
724
+ * The caption only renders the popover-mode filter button — per-column filter
725
+ * icons live in the table header itself (cards have no columns).
726
+ */
727
+ class TableCaption {
728
+ // Capability flags
729
+ generalSearch = input(false, { ...(ngDevMode ? { debugName: "generalSearch" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
730
+ showFilters = input(false, { ...(ngDevMode ? { debugName: "showFilters" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
731
+ filterMode = input('popover', ...(ngDevMode ? [{ debugName: "filterMode" }] : /* istanbul ignore next */ []));
732
+ exportable = input(false, { ...(ngDevMode ? { debugName: "exportable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
733
+ printable = input(false, { ...(ngDevMode ? { debugName: "printable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
734
+ groupable = input(false, { ...(ngDevMode ? { debugName: "groupable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
735
+ // Context for pickers
736
+ columns = input([], ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
737
+ data = input([], ...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
738
+ groupColumns = input([], ...(ngDevMode ? [{ debugName: "groupColumns" }] : /* istanbul ignore next */ []));
739
+ // Tabs
740
+ tabs = input(...(ngDevMode ? [undefined, { debugName: "tabs" }] : /* istanbul ignore next */ []));
741
+ tabsOptionLabel = input('label', ...(ngDevMode ? [{ debugName: "tabsOptionLabel" }] : /* istanbul ignore next */ []));
742
+ tabsOptionValue = input('value', ...(ngDevMode ? [{ debugName: "tabsOptionValue" }] : /* istanbul ignore next */ []));
743
+ // Toolbar-level action buttons rendered inline (not the dots menu)
744
+ actions = input([], ...(ngDevMode ? [{ debugName: "actions" }] : /* istanbul ignore next */ []));
745
+ // Projected caption slots
746
+ captionStart = input(null, ...(ngDevMode ? [{ debugName: "captionStart" }] : /* istanbul ignore next */ []));
747
+ captionEnd = input(null, ...(ngDevMode ? [{ debugName: "captionEnd" }] : /* istanbul ignore next */ []));
748
+ // Two-way state (the caption is a controlled component)
749
+ activeTab = model(...(ngDevMode ? [undefined, { debugName: "activeTab" }] : /* istanbul ignore next */ []));
750
+ filters = model({}, ...(ngDevMode ? [{ debugName: "filters" }] : /* istanbul ignore next */ []));
751
+ filterTerm = model('', ...(ngDevMode ? [{ debugName: "filterTerm" }] : /* istanbul ignore next */ []));
752
+ groupBy = model(null, ...(ngDevMode ? [{ debugName: "groupBy" }] : /* istanbul ignore next */ []));
753
+ // Events
754
+ exportRequested = output();
755
+ printRequested = output();
756
+ onTabChange = output();
757
+ searchChange = output();
758
+ filterApplied = output();
759
+ filterReset = output();
760
+ showsAnything = computed(() => !!this.captionStart() ||
761
+ !!this.captionEnd() ||
762
+ this.generalSearch() ||
763
+ (this.showFilters() && this.filterMode() === 'popover') ||
764
+ this.exportable() ||
765
+ this.printable() ||
766
+ this.groupable() ||
767
+ (this.tabs()?.length ?? 0) > 0 ||
768
+ this.actions().length > 0, ...(ngDevMode ? [{ debugName: "showsAnything" }] : /* istanbul ignore next */ []));
769
+ onSearch(term) {
770
+ this.filterTerm.set(term);
771
+ this.searchChange.emit(term);
772
+ }
773
+ onFilterApplied(next) {
774
+ this.filters.set(next);
775
+ this.filterApplied.emit(next);
776
+ }
777
+ onFilterReset() {
778
+ this.filters.set({});
779
+ this.filterReset.emit();
780
+ }
781
+ onGroupChange(key) {
782
+ this.groupBy.set(key);
783
+ }
784
+ tabChanged(tab) {
785
+ this.onTabChange.emit(tab);
786
+ }
787
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TableCaption, deps: [], target: i0.ɵɵFactoryTarget.Component });
788
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: TableCaption, isStandalone: true, selector: "mt-table-caption", inputs: { generalSearch: { classPropertyName: "generalSearch", publicName: "generalSearch", isSignal: true, isRequired: false, transformFunction: null }, showFilters: { classPropertyName: "showFilters", publicName: "showFilters", isSignal: true, isRequired: false, transformFunction: null }, filterMode: { classPropertyName: "filterMode", publicName: "filterMode", isSignal: true, isRequired: false, transformFunction: null }, exportable: { classPropertyName: "exportable", publicName: "exportable", isSignal: true, isRequired: false, transformFunction: null }, printable: { classPropertyName: "printable", publicName: "printable", isSignal: true, isRequired: false, transformFunction: null }, groupable: { classPropertyName: "groupable", publicName: "groupable", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, groupColumns: { classPropertyName: "groupColumns", publicName: "groupColumns", isSignal: true, isRequired: false, transformFunction: null }, tabs: { classPropertyName: "tabs", publicName: "tabs", isSignal: true, isRequired: false, transformFunction: null }, tabsOptionLabel: { classPropertyName: "tabsOptionLabel", publicName: "tabsOptionLabel", isSignal: true, isRequired: false, transformFunction: null }, tabsOptionValue: { classPropertyName: "tabsOptionValue", publicName: "tabsOptionValue", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, captionStart: { classPropertyName: "captionStart", publicName: "captionStart", isSignal: true, isRequired: false, transformFunction: null }, captionEnd: { classPropertyName: "captionEnd", publicName: "captionEnd", isSignal: true, isRequired: false, transformFunction: null }, activeTab: { classPropertyName: "activeTab", publicName: "activeTab", isSignal: true, isRequired: false, transformFunction: null }, filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null }, filterTerm: { classPropertyName: "filterTerm", publicName: "filterTerm", isSignal: true, isRequired: false, transformFunction: null }, groupBy: { classPropertyName: "groupBy", publicName: "groupBy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeTab: "activeTabChange", filters: "filtersChange", filterTerm: "filterTermChange", groupBy: "groupByChange", exportRequested: "exportRequested", printRequested: "printRequested", onTabChange: "onTabChange", searchChange: "searchChange", filterApplied: "filterApplied", filterReset: "filterReset" }, ngImport: i0, template: "@if (showsAnything()) {\n <div class=\"mt-table-caption\">\n <div\n class=\"flex relative items-center gap-2 pb-4\"\n [class]=\"!generalSearch() ? 'justify-end' : 'justify-between'\"\n >\n <div class=\"flex items-center gap-2\">\n @if (captionStart(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\"></ng-container>\n }\n @if (tabs()) {\n <mt-tabs\n [(active)]=\"activeTab\"\n [options]=\"tabs()\"\n [optionLabel]=\"tabsOptionLabel()\"\n [optionValue]=\"tabsOptionValue()\"\n (onChange)=\"tabChanged($event)\"\n size=\"large\"\n ></mt-tabs>\n }\n @if (generalSearch()) {\n <mt-text-field\n [ngModel]=\"filterTerm()\"\n (ngModelChange)=\"onSearch($event)\"\n icon=\"general.search-lg\"\n [placeholder]=\"'components.table.search' | transloco\"\n ></mt-text-field>\n }\n </div>\n <div class=\"flex items-center gap-2\">\n @if (showFilters() && filterMode() === \"popover\") {\n <mt-table-filter\n [columns]=\"columns()\"\n [data]=\"data()\"\n [ngModel]=\"filters()\"\n (filterApplied)=\"onFilterApplied($event)\"\n (filterReset)=\"onFilterReset()\"\n />\n }\n @if (exportable() || printable() || groupable()) {\n <mt-table-actions-menu\n [exportable]=\"exportable()\"\n [printable]=\"printable()\"\n [groupable]=\"groupable()\"\n [groupColumns]=\"groupColumns()\"\n [activeGroup]=\"groupBy()\"\n (exportRequested)=\"exportRequested.emit()\"\n (printRequested)=\"printRequested.emit()\"\n (groupChange)=\"onGroupChange($event)\"\n />\n }\n @if (actions().length > 0) {\n <div class=\"flex items-center space-x-2\">\n @for (action of actions(); track action.label) {\n <mt-button\n [icon]=\"action.icon\"\n [severity]=\"action.color\"\n [variant]=\"action.variant\"\n [size]=\"$any(action).size\"\n (click)=\"action.action(null)\"\n [label]=\"action.label\"\n [tooltip]=\"action.tooltip\"\n ></mt-button>\n }\n </div>\n }\n @if (captionEnd(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\"></ng-container>\n }\n </div>\n </div>\n </div>\n}\n", dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "size", "fluid", "disabled"], outputs: ["activeChange", "onChange"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "icon", "iconPosition"] }, { kind: "component", type: TableFilter, selector: "mt-table-filter", inputs: ["columns", "data"], outputs: ["filterApplied", "filterReset"] }, { kind: "component", type: TableActionsMenu, selector: "mt-table-actions-menu", inputs: ["exportable", "printable", "groupable", "groupColumns", "activeGroup"], outputs: ["exportRequested", "printRequested", "groupChange"] }, { kind: "pipe", type: i2.TranslocoPipe, name: "transloco" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
789
+ }
790
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TableCaption, decorators: [{
791
+ type: Component,
792
+ args: [{ selector: 'mt-table-caption', standalone: true, imports: [
793
+ NgTemplateOutlet,
794
+ FormsModule,
795
+ TranslocoModule,
796
+ Button,
797
+ Tabs,
798
+ TextField,
799
+ TableFilter,
800
+ TableActionsMenu,
801
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (showsAnything()) {\n <div class=\"mt-table-caption\">\n <div\n class=\"flex relative items-center gap-2 pb-4\"\n [class]=\"!generalSearch() ? 'justify-end' : 'justify-between'\"\n >\n <div class=\"flex items-center gap-2\">\n @if (captionStart(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\"></ng-container>\n }\n @if (tabs()) {\n <mt-tabs\n [(active)]=\"activeTab\"\n [options]=\"tabs()\"\n [optionLabel]=\"tabsOptionLabel()\"\n [optionValue]=\"tabsOptionValue()\"\n (onChange)=\"tabChanged($event)\"\n size=\"large\"\n ></mt-tabs>\n }\n @if (generalSearch()) {\n <mt-text-field\n [ngModel]=\"filterTerm()\"\n (ngModelChange)=\"onSearch($event)\"\n icon=\"general.search-lg\"\n [placeholder]=\"'components.table.search' | transloco\"\n ></mt-text-field>\n }\n </div>\n <div class=\"flex items-center gap-2\">\n @if (showFilters() && filterMode() === \"popover\") {\n <mt-table-filter\n [columns]=\"columns()\"\n [data]=\"data()\"\n [ngModel]=\"filters()\"\n (filterApplied)=\"onFilterApplied($event)\"\n (filterReset)=\"onFilterReset()\"\n />\n }\n @if (exportable() || printable() || groupable()) {\n <mt-table-actions-menu\n [exportable]=\"exportable()\"\n [printable]=\"printable()\"\n [groupable]=\"groupable()\"\n [groupColumns]=\"groupColumns()\"\n [activeGroup]=\"groupBy()\"\n (exportRequested)=\"exportRequested.emit()\"\n (printRequested)=\"printRequested.emit()\"\n (groupChange)=\"onGroupChange($event)\"\n />\n }\n @if (actions().length > 0) {\n <div class=\"flex items-center space-x-2\">\n @for (action of actions(); track action.label) {\n <mt-button\n [icon]=\"action.icon\"\n [severity]=\"action.color\"\n [variant]=\"action.variant\"\n [size]=\"$any(action).size\"\n (click)=\"action.action(null)\"\n [label]=\"action.label\"\n [tooltip]=\"action.tooltip\"\n ></mt-button>\n }\n </div>\n }\n @if (captionEnd(); as tpl) {\n <ng-container *ngTemplateOutlet=\"tpl\"></ng-container>\n }\n </div>\n </div>\n </div>\n}\n" }]
802
+ }], propDecorators: { generalSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "generalSearch", required: false }] }], showFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFilters", required: false }] }], filterMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterMode", required: false }] }], exportable: [{ type: i0.Input, args: [{ isSignal: true, alias: "exportable", required: false }] }], printable: [{ type: i0.Input, args: [{ isSignal: true, alias: "printable", required: false }] }], groupable: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupable", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], groupColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupColumns", required: false }] }], tabs: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabs", required: false }] }], tabsOptionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabsOptionLabel", required: false }] }], tabsOptionValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabsOptionValue", required: false }] }], actions: [{ type: i0.Input, args: [{ isSignal: true, alias: "actions", required: false }] }], captionStart: [{ type: i0.Input, args: [{ isSignal: true, alias: "captionStart", required: false }] }], captionEnd: [{ type: i0.Input, args: [{ isSignal: true, alias: "captionEnd", required: false }] }], activeTab: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeTab", required: false }] }, { type: i0.Output, args: ["activeTabChange"] }], filters: [{ type: i0.Input, args: [{ isSignal: true, alias: "filters", required: false }] }, { type: i0.Output, args: ["filtersChange"] }], filterTerm: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterTerm", required: false }] }, { type: i0.Output, args: ["filterTermChange"] }], groupBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupBy", required: false }] }, { type: i0.Output, args: ["groupByChange"] }], exportRequested: [{ type: i0.Output, args: ["exportRequested"] }], printRequested: [{ type: i0.Output, args: ["printRequested"] }], onTabChange: [{ type: i0.Output, args: ["onTabChange"] }], searchChange: [{ type: i0.Output, args: ["searchChange"] }], filterApplied: [{ type: i0.Output, args: ["filterApplied"] }], filterReset: [{ type: i0.Output, args: ["filterReset"] }] } });
803
+
804
+ /**
805
+ * Per-column filter affordance: a small funnel icon in the column header that
806
+ * opens a popover with a single `TableFilterField`.
807
+ *
808
+ * Buffers edits in `pendingValue` until the user hits Apply — matches the
809
+ * popover-mode UX so behavior is predictable between modes. Emits `filterChange`
810
+ * with either the new value or `null` to clear.
811
+ */
812
+ class TableColumnFilter {
813
+ column = input.required(...(ngDevMode ? [{ debugName: "column" }] : /* istanbul ignore next */ []));
814
+ value = input(null, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
815
+ filterChange = output();
816
+ pendingValue = signal(null, ...(ngDevMode ? [{ debugName: "pendingValue" }] : /* istanbul ignore next */ []));
817
+ hasActiveValue = computed(() => TableValueResolver.hasFilterValue(this.value()), ...(ngDevMode ? [{ debugName: "hasActiveValue" }] : /* istanbul ignore next */ []));
818
+ open(popover, event) {
819
+ event.stopPropagation();
820
+ this.pendingValue.set(this.cloneValue(this.value()));
821
+ popover.toggle(event);
822
+ }
823
+ apply(popover) {
824
+ const next = this.pendingValue();
825
+ this.filterChange.emit(TableValueResolver.hasFilterValue(next) ? next : null);
826
+ popover.hide();
827
+ }
828
+ clear(popover) {
829
+ this.pendingValue.set(null);
830
+ this.filterChange.emit(null);
831
+ popover.hide();
832
+ }
833
+ cloneValue(value) {
834
+ if (value === null || value === undefined)
835
+ return null;
836
+ if (typeof value === 'object')
837
+ return { ...value };
838
+ return value;
839
+ }
840
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TableColumnFilter, deps: [], target: i0.ɵɵFactoryTarget.Component });
841
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.8", type: TableColumnFilter, isStandalone: true, selector: "mt-table-column-filter", inputs: { column: { classPropertyName: "column", publicName: "column", isSignal: true, isRequired: true, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filterChange: "filterChange" }, ngImport: i0, template: "<mt-button\n (onClick)=\"open(popover, $event)\"\n [icon]=\"\n hasActiveValue() ? 'general.filter-funnel-02' : 'general.filter-funnel-01'\n \"\n [severity]=\"hasActiveValue() ? 'primary' : 'secondary'\"\n variant=\"text\"\n size=\"small\"\n [tooltip]=\"'components.table.filter' | transloco\"\n styleClass=\"!p-1 !text-sm\"\n/>\n\n<p-popover #popover [style]=\"{ width: '280px' }\" appendTo=\"body\">\n <div\n class=\"flex flex-col gap-3\"\n (keydown.enter)=\"apply(popover)\"\n (click)=\"$event.stopPropagation()\"\n >\n <h4\n class=\"text-sm font-semibold text-gray-700 dark:text-gray-300 truncate\"\n [title]=\"column().filterConfig?.label || column().label\"\n >\n {{ column().filterConfig?.label || column().label }}\n </h4>\n\n <mt-table-filter-field\n [column]=\"column()\"\n [value]=\"pendingValue()\"\n (valueChange)=\"pendingValue.set($event)\"\n />\n\n <div\n class=\"flex justify-end gap-2 pt-2 border-t border-surface-200 dark:border-surface-700\"\n >\n <mt-button\n variant=\"outlined\"\n size=\"small\"\n (onClick)=\"clear(popover)\"\n [label]=\"'components.table.reset' | transloco\"\n />\n <mt-button\n size=\"small\"\n (onClick)=\"apply(popover)\"\n [label]=\"'components.table.apply' | transloco\"\n />\n </div>\n </div>\n</p-popover>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i1$2.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "component", type: TableFilterField, selector: "mt-table-filter-field", inputs: ["column", "value"], outputs: ["valueChange"] }, { kind: "pipe", type: i2.TranslocoPipe, name: "transloco" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
842
+ }
843
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TableColumnFilter, decorators: [{
844
+ type: Component,
845
+ args: [{ selector: 'mt-table-column-filter', standalone: true, imports: [
846
+ FormsModule,
847
+ Button,
848
+ PopoverModule,
849
+ TranslocoModule,
850
+ TableFilterField,
851
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<mt-button\n (onClick)=\"open(popover, $event)\"\n [icon]=\"\n hasActiveValue() ? 'general.filter-funnel-02' : 'general.filter-funnel-01'\n \"\n [severity]=\"hasActiveValue() ? 'primary' : 'secondary'\"\n variant=\"text\"\n size=\"small\"\n [tooltip]=\"'components.table.filter' | transloco\"\n styleClass=\"!p-1 !text-sm\"\n/>\n\n<p-popover #popover [style]=\"{ width: '280px' }\" appendTo=\"body\">\n <div\n class=\"flex flex-col gap-3\"\n (keydown.enter)=\"apply(popover)\"\n (click)=\"$event.stopPropagation()\"\n >\n <h4\n class=\"text-sm font-semibold text-gray-700 dark:text-gray-300 truncate\"\n [title]=\"column().filterConfig?.label || column().label\"\n >\n {{ column().filterConfig?.label || column().label }}\n </h4>\n\n <mt-table-filter-field\n [column]=\"column()\"\n [value]=\"pendingValue()\"\n (valueChange)=\"pendingValue.set($event)\"\n />\n\n <div\n class=\"flex justify-end gap-2 pt-2 border-t border-surface-200 dark:border-surface-700\"\n >\n <mt-button\n variant=\"outlined\"\n size=\"small\"\n (onClick)=\"clear(popover)\"\n [label]=\"'components.table.reset' | transloco\"\n />\n <mt-button\n size=\"small\"\n (onClick)=\"apply(popover)\"\n [label]=\"'components.table.apply' | transloco\"\n />\n </div>\n </div>\n</p-popover>\n" }]
852
+ }], propDecorators: { column: [{ type: i0.Input, args: [{ isSignal: true, alias: "column", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], filterChange: [{ type: i0.Output, args: ["filterChange"] }] } });
853
+
854
+ /**
855
+ * Centralises table export/print so any `mt-table` (and future tables) can
856
+ * drop in the behaviour without reimplementing XLSX serialisation or print
857
+ * DOM cloning. Injected schema-agnostically via `resolveValue` on the config.
858
+ */
859
+ class TableExportService {
860
+ static PRINT_ROOT_CLASS = 'mt-printing';
861
+ static PRINT_REGION_CLASS = 'mt-print-region';
862
+ static PRINT_STYLE_ID = 'mt-table-print-style';
863
+ static PRINT_CSS = `
864
+ @media print {
865
+ html.mt-printing body > *:not(.mt-print-region) { display: none !important; }
866
+ html.mt-printing, html.mt-printing body { background: #ffffff !important; }
867
+ .mt-print-region { display: block !important; padding: 16px; color: #111827;
868
+ font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif; }
869
+ .mt-print-region h1 { font-size: 18px; font-weight: 600; margin: 0 0 12px; }
870
+ .mt-print-region table { width: 100%; border-collapse: collapse; font-size: 12px; }
871
+ .mt-print-region th, .mt-print-region td { text-align: start; padding: 6px 8px;
872
+ border: 1px solid #e5e7eb; vertical-align: top; }
873
+ .mt-print-region thead th { background: #f3f4f6; font-weight: 600; }
874
+ .mt-print-region tbody tr { break-inside: avoid; page-break-inside: avoid; }
875
+ }
876
+ .mt-print-region { display: none; }
877
+ `;
878
+ exportToExcel(config) {
879
+ const columns = this.getExportableColumns(config.columns);
880
+ const workbook = XLSX.utils.book_new();
881
+ const worksheet = XLSX.utils.json_to_sheet(this.buildLabeledRows(config.rows, columns, config.resolveValue));
882
+ XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
883
+ XLSX.writeFileXLSX(workbook, `${this.normalizeFilename(config.filename)}.xlsx`);
884
+ }
885
+ printPdf(config) {
886
+ if (typeof document === 'undefined' || typeof window === 'undefined') {
887
+ return;
888
+ }
889
+ const columns = this.getExportableColumns(config.columns);
890
+ const region = this.buildPrintRegion(config, columns);
891
+ this.ensurePrintStyles();
892
+ document.body.appendChild(region);
893
+ document.documentElement.classList.add(TableExportService.PRINT_ROOT_CLASS);
894
+ const cleanup = () => {
895
+ document.documentElement.classList.remove(TableExportService.PRINT_ROOT_CLASS);
896
+ region.remove();
897
+ window.removeEventListener('afterprint', cleanup);
898
+ };
899
+ window.addEventListener('afterprint', cleanup);
900
+ window.print();
901
+ }
902
+ ensurePrintStyles() {
903
+ if (document.getElementById(TableExportService.PRINT_STYLE_ID)) {
904
+ return;
905
+ }
906
+ const style = document.createElement('style');
907
+ style.id = TableExportService.PRINT_STYLE_ID;
908
+ style.textContent = TableExportService.PRINT_CSS;
909
+ document.head.appendChild(style);
910
+ }
911
+ getExportableColumns(columns) {
912
+ return columns.filter((column) => column.type !== 'custom');
913
+ }
914
+ /**
915
+ * Produces rows keyed by column label (Excel header row).
916
+ * Entity columns use the dedicated entity resolver for a clean export value.
917
+ */
918
+ buildLabeledRows(rows, columns, resolveValue) {
919
+ return rows.map((row) => {
920
+ const labeledRow = {};
921
+ columns.forEach((column) => {
922
+ const cellValue = column.type === 'entity'
923
+ ? TableValueResolver.getEntityValueByType(TableValueResolver.getProperty(row, column.key), 'export')
924
+ : resolveValue(row, column);
925
+ labeledRow[column.label] = cellValue ?? null;
926
+ });
927
+ return labeledRow;
928
+ });
929
+ }
930
+ buildPrintRegion(config, columns) {
931
+ const region = document.createElement('section');
932
+ region.className = TableExportService.PRINT_REGION_CLASS;
933
+ if (config.title) {
934
+ const heading = document.createElement('h1');
935
+ heading.textContent = config.title;
936
+ region.appendChild(heading);
937
+ }
938
+ const table = document.createElement('table');
939
+ const thead = document.createElement('thead');
940
+ const headerRow = document.createElement('tr');
941
+ columns.forEach((column) => {
942
+ const th = document.createElement('th');
943
+ th.textContent = column.label;
944
+ headerRow.appendChild(th);
945
+ });
946
+ thead.appendChild(headerRow);
947
+ table.appendChild(thead);
948
+ const tbody = document.createElement('tbody');
949
+ config.rows.forEach((row) => {
950
+ const tr = document.createElement('tr');
951
+ columns.forEach((column) => {
952
+ const td = document.createElement('td');
953
+ const cellValue = column.type === 'entity'
954
+ ? TableValueResolver.getEntityValueByType(TableValueResolver.getProperty(row, column.key), 'export')
955
+ : config.resolveValue(row, column);
956
+ td.textContent = cellValue === null ? '' : String(cellValue);
957
+ tr.appendChild(td);
958
+ });
959
+ tbody.appendChild(tr);
960
+ });
961
+ table.appendChild(tbody);
962
+ region.appendChild(table);
963
+ return region;
964
+ }
965
+ normalizeFilename(value) {
966
+ const sanitized = (value ?? '').trim().replace(/[\\/:*?"<>|]+/g, '-');
967
+ return sanitized.length ? sanitized : 'download';
968
+ }
969
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TableExportService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
970
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TableExportService, providedIn: 'root' });
971
+ }
972
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: TableExportService, decorators: [{
973
+ type: Injectable,
974
+ args: [{ providedIn: 'root' }]
975
+ }] });
976
+
977
+ /**
978
+ * Column filter types that produce useful (low-cardinality) row groups.
979
+ * Unique-valued columns (plain text, dates) would create a group per row —
980
+ * pointless visually and slow — so we exclude them from the group picker.
981
+ */
982
+ const GROUPABLE_FILTER_TYPES = new Set([
983
+ 'select',
984
+ 'boolean',
985
+ 'user',
986
+ ]);
987
+ /**
988
+ * Pure controller owning all row-grouping concerns. Table instantiates one and
989
+ * binds its signals — keeps grouping logic out of table.ts.
990
+ *
991
+ * PrimeNG's subheader grouping renders only when `sortField === groupRowsBy`.
992
+ * `setGroup` therefore also pins the sort to the grouped column; clearing the
993
+ * group leaves the user's sort untouched.
994
+ */
995
+ class TableGroupingController {
996
+ columns;
997
+ rows;
998
+ groupBy;
999
+ sortField;
1000
+ sortDirection;
1001
+ constructor(columns, rows, groupBy, sortField, sortDirection) {
1002
+ this.columns = columns;
1003
+ this.rows = rows;
1004
+ this.groupBy = groupBy;
1005
+ this.sortField = sortField;
1006
+ this.sortDirection = sortDirection;
1007
+ }
1008
+ groupableColumns = computed(() => {
1009
+ const sampleRow = this.rows()[0];
1010
+ return this.columns().filter((col) => {
1011
+ if (col.type === 'custom')
1012
+ return false;
1013
+ const filterType = TableValueResolver.getColumnFilterType(col, sampleRow);
1014
+ return filterType !== null && GROUPABLE_FILTER_TYPES.has(filterType);
1015
+ });
1016
+ }, ...(ngDevMode ? [{ debugName: "groupableColumns" }] : /* istanbul ignore next */ []));
1017
+ /**
1018
+ * Row counts per group key — consumed by the group header template so each
1019
+ * subheader can show "Status: Active (12)".
1020
+ */
1021
+ groupCounts = computed(() => {
1022
+ const column = this.activeGroupColumn();
1023
+ if (!column)
1024
+ return new Map();
1025
+ const counts = new Map();
1026
+ for (const row of this.rows()) {
1027
+ const key = this.getGroupKey(row, column);
1028
+ counts.set(key, (counts.get(key) ?? 0) + 1);
1029
+ }
1030
+ return counts;
1031
+ }, ...(ngDevMode ? [{ debugName: "groupCounts" }] : /* istanbul ignore next */ []));
1032
+ getGroupCount(row) {
1033
+ const column = this.activeGroupColumn();
1034
+ if (!column)
1035
+ return 0;
1036
+ return this.groupCounts().get(this.getGroupKey(row, column)) ?? 0;
1037
+ }
1038
+ activeGroupColumn = computed(() => {
1039
+ const key = this.groupBy();
1040
+ if (!key)
1041
+ return null;
1042
+ return this.columns().find((col) => col.key === key) ?? null;
1043
+ }, ...(ngDevMode ? [{ debugName: "activeGroupColumn" }] : /* istanbul ignore next */ []));
1044
+ groupingActive = computed(() => this.activeGroupColumn() !== null, ...(ngDevMode ? [{ debugName: "groupingActive" }] : /* istanbul ignore next */ []));
1045
+ /**
1046
+ * Returns true when the given column is the active group column and
1047
+ * therefore cannot have its sort cleared (PrimeNG requirement).
1048
+ */
1049
+ isGroupLockedSort(columnKey) {
1050
+ return this.groupingActive() && this.activeGroupColumn()?.key === columnKey;
1051
+ }
1052
+ setGroup(key) {
1053
+ this.groupBy.set(key && key.length > 0 ? key : null);
1054
+ if (key) {
1055
+ this.sortField.set(key);
1056
+ if (this.sortDirection() === null) {
1057
+ this.sortDirection.set('asc');
1058
+ }
1059
+ }
1060
+ }
1061
+ /**
1062
+ * Display label for a row's grouped value — used by the `#groupheader`
1063
+ * template. Leverages the same resolver pipeline the cells use, so status
1064
+ * maps / user display names render consistently.
1065
+ */
1066
+ getGroupLabel(row) {
1067
+ const column = this.activeGroupColumn();
1068
+ if (!column)
1069
+ return '';
1070
+ const cellValue = TableValueResolver.getProperty(row, column.key);
1071
+ if (cellValue === null || cellValue === undefined || cellValue === '') {
1072
+ return '—';
1073
+ }
1074
+ if (column.type === 'entity') {
1075
+ const entityValue = TableValueResolver.getEntityValueByType(cellValue, 'export');
1076
+ return entityValue === null ? '—' : String(entityValue);
1077
+ }
1078
+ const display = TableValueResolver.resolveDisplayValue(cellValue);
1079
+ if (display === null || display === undefined)
1080
+ return '—';
1081
+ if (typeof display === 'boolean')
1082
+ return display ? 'Yes' : 'No';
1083
+ return String(display);
1084
+ }
1085
+ /**
1086
+ * Accent color for status/entity-Status group headers. Reused from the
1087
+ * cell renderer's status-map pipeline so tint is consistent with the cell.
1088
+ */
1089
+ getGroupAccentColor(row) {
1090
+ const column = this.activeGroupColumn();
1091
+ if (!column)
1092
+ return null;
1093
+ if (column.type !== 'status' && column.type !== 'entity')
1094
+ return null;
1095
+ const cellValue = TableValueResolver.getProperty(row, column.key);
1096
+ if (cellValue === null || cellValue === undefined)
1097
+ return null;
1098
+ if (typeof cellValue === 'object') {
1099
+ const obj = cellValue;
1100
+ const color = obj['color'];
1101
+ if (typeof color === 'string' && color.length > 0)
1102
+ return color;
1103
+ }
1104
+ return null;
1105
+ }
1106
+ /** Stable key used to bucket rows into groups — normalised to string. */
1107
+ getGroupKey(row, column) {
1108
+ const cellValue = TableValueResolver.getProperty(row, column.key);
1109
+ if (cellValue === null || cellValue === undefined || cellValue === '') {
1110
+ return '__mt_group_empty__';
1111
+ }
1112
+ if (column.type === 'entity') {
1113
+ const entityValue = TableValueResolver.getEntityValueByType(cellValue, 'filter');
1114
+ return entityValue === null ? '__mt_group_empty__' : String(entityValue);
1115
+ }
1116
+ const display = TableValueResolver.resolveDisplayValue(cellValue);
1117
+ return display === null || display === undefined
1118
+ ? '__mt_group_empty__'
1119
+ : String(display);
1120
+ }
1121
+ }
1122
+
426
1123
  class Table {
427
1124
  static LOADING_COLUMN_COUNT = 5;
428
1125
  selectionChange = output();
@@ -443,6 +1140,7 @@ class Table {
443
1140
  generalSearch = input(false, { ...(ngDevMode ? { debugName: "generalSearch" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
444
1141
  lazyLocalSearch = input(false, { ...(ngDevMode ? { debugName: "lazyLocalSearch" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
445
1142
  showFilters = input(false, { ...(ngDevMode ? { debugName: "showFilters" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1143
+ filterMode = input('popover', ...(ngDevMode ? [{ debugName: "filterMode" }] : /* istanbul ignore next */ []));
446
1144
  loading = input(false, { ...(ngDevMode ? { debugName: "loading" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
447
1145
  updating = input(false, { ...(ngDevMode ? { debugName: "updating" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
448
1146
  lazy = input(false, { ...(ngDevMode ? { debugName: "lazy" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
@@ -454,10 +1152,15 @@ class Table {
454
1152
  storageKey = input(null, ...(ngDevMode ? [{ debugName: "storageKey" }] : /* istanbul ignore next */ []));
455
1153
  storageMode = input('local', ...(ngDevMode ? [{ debugName: "storageMode" }] : /* istanbul ignore next */ []));
456
1154
  exportable = input(false, { ...(ngDevMode ? { debugName: "exportable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1155
+ printable = input(false, { ...(ngDevMode ? { debugName: "printable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1156
+ groupable = input(false, { ...(ngDevMode ? { debugName: "groupable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1157
+ cellClickFilter = input(false, { ...(ngDevMode ? { debugName: "cellClickFilter" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1158
+ printTitle = input('', ...(ngDevMode ? [{ debugName: "printTitle" }] : /* istanbul ignore next */ []));
457
1159
  exportFilename = input('download', ...(ngDevMode ? [{ debugName: "exportFilename" }] : /* istanbul ignore next */ []));
458
1160
  actionShape = input('flat', ...(ngDevMode ? [{ debugName: "actionShape" }] : /* istanbul ignore next */ []));
459
1161
  tableLayout = input('fixed', ...(ngDevMode ? [{ debugName: "tableLayout" }] : /* istanbul ignore next */ []));
460
1162
  noCard = input(false, { ...(ngDevMode ? { debugName: "noCard" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
1163
+ dateFormat = inject(MTDateFormatPipe);
461
1164
  // Tabs inputs and outputs
462
1165
  tabs = input(...(ngDevMode ? [undefined, { debugName: "tabs" }] : /* istanbul ignore next */ []));
463
1166
  tabsOptionLabel = input('label', ...(ngDevMode ? [{ debugName: "tabsOptionLabel" }] : /* istanbul ignore next */ []));
@@ -477,13 +1180,44 @@ class Table {
477
1180
  currentPage = model(0, ...(ngDevMode ? [{ debugName: "currentPage" }] : /* istanbul ignore next */ []));
478
1181
  first = model(0, ...(ngDevMode ? [{ debugName: "first" }] : /* istanbul ignore next */ []));
479
1182
  filterTerm = model('', ...(ngDevMode ? [{ debugName: "filterTerm" }] : /* istanbul ignore next */ []));
1183
+ groupBy = model(null, ...(ngDevMode ? [{ debugName: "groupBy" }] : /* istanbul ignore next */ []));
480
1184
  sortField = signal(null, ...(ngDevMode ? [{ debugName: "sortField" }] : /* istanbul ignore next */ []));
481
1185
  sortDirection = signal(null, ...(ngDevMode ? [{ debugName: "sortDirection" }] : /* istanbul ignore next */ []));
482
1186
  confirmationService = inject(ConfirmationService);
1187
+ exportService = inject(TableExportService);
1188
+ grouping;
483
1189
  selectedRowKeys = signal(new Set(), ...(ngDevMode ? [{ debugName: "selectedRowKeys" }] : /* istanbul ignore next */ []));
484
1190
  transientSelectedRows = signal(new Set(), ...(ngDevMode ? [{ debugName: "transientSelectedRows" }] : /* istanbul ignore next */ []));
485
1191
  hydratedStorageKey = signal(null, ...(ngDevMode ? [{ debugName: "hydratedStorageKey" }] : /* istanbul ignore next */ []));
486
1192
  storageHydrated = signal(false, ...(ngDevMode ? [{ debugName: "storageHydrated" }] : /* istanbul ignore next */ []));
1193
+ isColumnFilterMode = computed(() => this.showFilters() && this.filterMode() === 'column', ...(ngDevMode ? [{ debugName: "isColumnFilterMode" }] : /* istanbul ignore next */ []));
1194
+ filterableColumnMap = computed(() => {
1195
+ if (!this.isColumnFilterMode()) {
1196
+ return new Map();
1197
+ }
1198
+ const data = this.data();
1199
+ const map = new Map();
1200
+ this.columns().forEach((col) => {
1201
+ if (TableValueResolver.getColumnFilterType(col, data[0]) === null) {
1202
+ return;
1203
+ }
1204
+ map.set(col.key, TableValueResolver.buildFilterableColumn(col, data));
1205
+ });
1206
+ return map;
1207
+ }, ...(ngDevMode ? [{ debugName: "filterableColumnMap" }] : /* istanbul ignore next */ []));
1208
+ getFilterableColumn(key) {
1209
+ return this.filterableColumnMap().get(key);
1210
+ }
1211
+ onColumnFilterChange(key, value) {
1212
+ const next = { ...this.filters() };
1213
+ if (value === null || value === undefined) {
1214
+ delete next[key];
1215
+ }
1216
+ else {
1217
+ next[key] = value;
1218
+ }
1219
+ this.onFilterApplied(next);
1220
+ }
487
1221
  activeFilterCount = computed(() => {
488
1222
  const filters = this.filters();
489
1223
  return Object.values(filters).filter((value) => value !== null && value !== undefined && value !== '').length;
@@ -546,7 +1280,12 @@ class Table {
546
1280
  return false;
547
1281
  return pageData.every((row) => this.isRowSelected(row));
548
1282
  }, ...(ngDevMode ? [{ debugName: "allSelectedOnPage" }] : /* istanbul ignore next */ []));
1283
+ totalColumnSpan = computed(() => this.renderedColumns().length +
1284
+ (this.reorderableRows() ? 1 : 0) +
1285
+ (this.selectableRows() ? 1 : 0) +
1286
+ (this.rowActions().length > 0 ? 1 : 0), ...(ngDevMode ? [{ debugName: "totalColumnSpan" }] : /* istanbul ignore next */ []));
549
1287
  constructor() {
1288
+ this.grouping = new TableGroupingController(this.columns, this.filteredData, this.groupBy, this.sortField, this.sortDirection);
550
1289
  effect(() => {
551
1290
  const storageKey = this.getNormalizedStorageKey();
552
1291
  const storage = this.getStorage();
@@ -580,6 +1319,27 @@ class Table {
580
1319
  }
581
1320
  this.writePersistedState(storage, storageKey, this.buildPersistedState());
582
1321
  });
1322
+ // Drop filters / groupBy whose column no longer exists. Dynamic tables
1323
+ // (e.g. runtime schemas) can drop columns between fetches, which would
1324
+ // otherwise strand a filter the user can't clear from the UI.
1325
+ effect(() => {
1326
+ const columns = this.columns();
1327
+ if (columns.length === 0 || this.loading()) {
1328
+ return;
1329
+ }
1330
+ const validKeys = new Set(columns.map((c) => c.key));
1331
+ const currentFilters = this.filters();
1332
+ const staleFilterKeys = Object.keys(currentFilters).filter((key) => key !== 'generalSearch' && !validKeys.has(key));
1333
+ if (staleFilterKeys.length > 0) {
1334
+ const next = { ...currentFilters };
1335
+ staleFilterKeys.forEach((key) => delete next[key]);
1336
+ this.filters.set(next);
1337
+ }
1338
+ const currentGroup = this.groupBy();
1339
+ if (currentGroup && !validKeys.has(currentGroup)) {
1340
+ this.groupBy.set(null);
1341
+ }
1342
+ });
583
1343
  effect(() => {
584
1344
  if (this.lazy()) {
585
1345
  return;
@@ -620,65 +1380,8 @@ class Table {
620
1380
  }
621
1381
  }
622
1382
  matchesFilter(item, key, filterValue) {
623
- if (filterValue === null ||
624
- filterValue === undefined ||
625
- filterValue === '') {
626
- return true;
627
- }
628
1383
  const column = this.columns().find((col) => col.key === key);
629
- const itemValue = this.getProperty(item, key);
630
- const normalizedFilterValue = column
631
- ? TableValueResolver.getColumnFilterValue(item, column)
632
- : TableValueResolver.resolveDisplayValue(itemValue);
633
- const filterType = column
634
- ? TableValueResolver.getColumnFilterType(column, item)
635
- : null;
636
- // Date range filter
637
- if (typeof filterValue === 'object') {
638
- if (filterValue.from || filterValue.to) {
639
- const itemDateValue = filterType === 'date'
640
- ? typeof normalizedFilterValue === 'number'
641
- ? normalizedFilterValue
642
- : null
643
- : itemValue instanceof Date
644
- ? itemValue.getTime()
645
- : new Date(String(itemValue)).getTime();
646
- if (itemDateValue === null ||
647
- itemDateValue === undefined ||
648
- Number.isNaN(itemDateValue)) {
649
- return true;
650
- }
651
- if (filterValue.from &&
652
- itemDateValue < new Date(filterValue.from).getTime()) {
653
- return false;
654
- }
655
- if (filterValue.to &&
656
- itemDateValue > new Date(filterValue.to).getTime()) {
657
- return false;
658
- }
659
- return true;
660
- }
661
- else if (filterValue?.userName) {
662
- const normalizedItemUser = itemValue;
663
- if (!normalizedItemUser)
664
- return false;
665
- return (normalizedItemUser.id === filterValue?.id ||
666
- normalizedItemUser.userName === filterValue?.userName ||
667
- normalizedItemUser.displayName === filterValue?.displayName);
668
- }
669
- }
670
- // Boolean filter
671
- if (typeof filterValue === 'boolean') {
672
- return normalizedFilterValue === filterValue;
673
- }
674
- // Text filter
675
- if (typeof normalizedFilterValue === 'string' ||
676
- typeof normalizedFilterValue === 'number') {
677
- return String(normalizedFilterValue)
678
- .toLowerCase()
679
- .includes(String(filterValue).toLowerCase());
680
- }
681
- return normalizedFilterValue === filterValue;
1384
+ return TableValueResolver.matchesFilter(item, key, filterValue, column);
682
1385
  }
683
1386
  toggleRow(row) {
684
1387
  const rowKey = this.getRowSelectionKey(row);
@@ -747,6 +1450,20 @@ class Table {
747
1450
  }
748
1451
  return null;
749
1452
  }
1453
+ /**
1454
+ * Entity data resolver that abstracts over the `user` / `status` vs `entity`
1455
+ * distinction — used by the shared filterable-cell template so the three
1456
+ * cases don't duplicate markup.
1457
+ */
1458
+ resolveCellEntityData(row, col) {
1459
+ if (col.type === 'entity') {
1460
+ return this.getEntityColumnData(row, col);
1461
+ }
1462
+ if (col.type === 'user' || col.type === 'status') {
1463
+ return this.getEntityPreviewData(row, col);
1464
+ }
1465
+ return null;
1466
+ }
750
1467
  tabChanged(tab) {
751
1468
  this.filterTerm.set('');
752
1469
  this.first.set(0);
@@ -787,10 +1504,26 @@ class Table {
787
1504
  if (this.sortField() !== column.key) {
788
1505
  this.sortField.set(column.key);
789
1506
  this.sortDirection.set('asc');
1507
+ return;
790
1508
  }
791
- else {
792
- this.sortDirection.set(this.sortDirection() === 'asc' ? 'desc' : 'asc');
1509
+ const direction = this.sortDirection();
1510
+ if (direction === 'asc') {
1511
+ this.sortDirection.set('desc');
1512
+ return;
793
1513
  }
1514
+ if (direction === 'desc') {
1515
+ // Tri-state reset. PrimeNG subheader grouping breaks without a matching
1516
+ // sort, so when this column is the active group we wrap to 'asc' instead.
1517
+ if (this.grouping.isGroupLockedSort(column.key)) {
1518
+ this.sortDirection.set('asc');
1519
+ }
1520
+ else {
1521
+ this.sortField.set(null);
1522
+ this.sortDirection.set(null);
1523
+ }
1524
+ return;
1525
+ }
1526
+ this.sortDirection.set('asc');
794
1527
  }
795
1528
  isColumnSortable(column) {
796
1529
  return column.sortable === true && (!this.lazy() || this.lazyLocalSort());
@@ -863,11 +1596,69 @@ class Table {
863
1596
  if (this.loading()) {
864
1597
  return;
865
1598
  }
866
- const sourceColumns = this.columns().filter((column) => column.type !== 'custom');
867
- const workbook = XLSX.utils.book_new();
868
- const worksheet = XLSX.utils.json_to_sheet(this.buildExcelRows(this.filteredData(), sourceColumns));
869
- XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1');
870
- XLSX.writeFileXLSX(workbook, `${this.normalizeExportFilename(this.exportFilename())}.xlsx`);
1599
+ this.exportService.exportToExcel({
1600
+ rows: this.filteredData(),
1601
+ columns: this.columns(),
1602
+ filename: this.exportFilename(),
1603
+ resolveValue: (row, column) => this.getColumnExportValue(row, column),
1604
+ });
1605
+ }
1606
+ printPdf() {
1607
+ if (this.loading()) {
1608
+ return;
1609
+ }
1610
+ this.exportService.printPdf({
1611
+ rows: this.filteredData(),
1612
+ columns: this.columns(),
1613
+ filename: this.exportFilename(),
1614
+ title: this.printTitle() || undefined,
1615
+ resolveValue: (row, column) => this.getColumnExportValue(row, column),
1616
+ });
1617
+ }
1618
+ onCellFilterClick(event, row, column) {
1619
+ if (!this.cellClickFilter())
1620
+ return;
1621
+ const next = TableValueResolver.buildClickFilterValue(row, column);
1622
+ if (next === null || next === undefined)
1623
+ return;
1624
+ event.stopPropagation();
1625
+ const current = this.filters();
1626
+ const patched = { ...current };
1627
+ if (TableValueResolver.isFilterValueEqual(current[column.key], next)) {
1628
+ delete patched[column.key];
1629
+ }
1630
+ else {
1631
+ patched[column.key] = next;
1632
+ }
1633
+ this.onFilterApplied(patched);
1634
+ }
1635
+ isCellFilterActive(row, column) {
1636
+ if (!this.cellClickFilter())
1637
+ return false;
1638
+ const current = this.filters()[column.key];
1639
+ if (current === null || current === undefined)
1640
+ return false;
1641
+ const next = TableValueResolver.buildClickFilterValue(row, column);
1642
+ if (next === null || next === undefined)
1643
+ return false;
1644
+ return TableValueResolver.isFilterValueEqual(current, next);
1645
+ }
1646
+ isCellClickFilterable(column, row) {
1647
+ if (!this.cellClickFilter())
1648
+ return false;
1649
+ if (column.type === 'boolean') {
1650
+ // Editable booleans keep the toggle interaction; only readonly ones filter.
1651
+ return column.readonly === true;
1652
+ }
1653
+ if (column.type === 'status' || column.type === 'user')
1654
+ return true;
1655
+ if (column.type === 'entity') {
1656
+ const filterType = TableValueResolver.getColumnFilterType(column, row);
1657
+ return (filterType === 'select' ||
1658
+ filterType === 'user' ||
1659
+ filterType === 'boolean');
1660
+ }
1661
+ return false;
871
1662
  }
872
1663
  rowAction(event, action, row) {
873
1664
  if (!action.confirmation) {
@@ -1210,6 +2001,57 @@ class Table {
1210
2001
  }
1211
2002
  return TableValueResolver.normalizeTextSortValue(resolvedValue);
1212
2003
  }
2004
+ /**
2005
+ * Export/print value resolver — same pipeline as `getColumnResolvedValue`
2006
+ * except date / dateTime columns (and their entity counterparts) are
2007
+ * formatted via the MT date pipe so Excel and PDF show locale-aware dates
2008
+ * instead of raw ISO strings. Sort path keeps the ISO form for ordering.
2009
+ */
2010
+ getColumnExportValue(row, column) {
2011
+ const cellValue = this.getProperty(row, column.key);
2012
+ if (cellValue === null || cellValue === undefined)
2013
+ return null;
2014
+ const dateType = this.resolveDateColumnType(column, row);
2015
+ if (dateType) {
2016
+ const dateValue = TableValueResolver.resolveDateValue(column.type === 'entity'
2017
+ ? TableValueResolver.getEntityValueByType(cellValue, 'sort')
2018
+ : cellValue);
2019
+ if (dateValue === null)
2020
+ return null;
2021
+ const formatted = this.dateFormat.transform(dateValue, dateType);
2022
+ return formatted || null;
2023
+ }
2024
+ return this.getColumnResolvedValue(row, column);
2025
+ }
2026
+ /**
2027
+ * Detects whether a column should be treated as a date for export purposes:
2028
+ * native `date` / `dateTime` types, or entity columns whose viewType is
2029
+ * `Date` / `DateTime`.
2030
+ */
2031
+ resolveDateColumnType(column, row) {
2032
+ if (column.type === 'date')
2033
+ return 'date';
2034
+ if (column.type === 'dateTime')
2035
+ return 'dateTime';
2036
+ if (column.type === 'entity') {
2037
+ const filterType = TableValueResolver.getColumnFilterType(column, row);
2038
+ if (filterType !== 'date')
2039
+ return null;
2040
+ const viewType = column.viewType;
2041
+ if (typeof viewType === 'string' &&
2042
+ viewType.toLowerCase() === 'datetime') {
2043
+ return 'dateTime';
2044
+ }
2045
+ const cellValue = this.getProperty(row, column.key);
2046
+ if (cellValue &&
2047
+ typeof cellValue === 'object' &&
2048
+ cellValue.viewType === 'DateTime') {
2049
+ return 'dateTime';
2050
+ }
2051
+ return 'date';
2052
+ }
2053
+ return null;
2054
+ }
1213
2055
  getColumnResolvedValue(row, column) {
1214
2056
  const cellValue = this.getProperty(row, column.key);
1215
2057
  if (cellValue === null || cellValue === undefined) {
@@ -1233,28 +2075,6 @@ class Table {
1233
2075
  }
1234
2076
  return TableValueResolver.resolveDisplayValue(cellValue);
1235
2077
  }
1236
- buildExportRows(rows, columns) {
1237
- return rows.map((row) => {
1238
- const exportRow = {};
1239
- columns.forEach((column) => {
1240
- exportRow[column.key] =
1241
- column.type === 'entity'
1242
- ? TableValueResolver.getEntityValueByType(this.getProperty(row, column.key), 'export')
1243
- : this.getColumnResolvedValue(row, column);
1244
- });
1245
- return exportRow;
1246
- });
1247
- }
1248
- buildExcelRows(rows, columns) {
1249
- const exportRows = this.buildExportRows(rows, columns);
1250
- return exportRows.map((row) => {
1251
- const excelRow = {};
1252
- columns.forEach((column) => {
1253
- excelRow[column.label] = row[column.key] ?? null;
1254
- });
1255
- return excelRow;
1256
- });
1257
- }
1258
2078
  isRowSelected(row) {
1259
2079
  const rowKey = this.getRowSelectionKey(row);
1260
2080
  if (rowKey !== null) {
@@ -1298,10 +2118,6 @@ class Table {
1298
2118
  const storageKey = this.storageKey()?.trim();
1299
2119
  return storageKey ? storageKey : null;
1300
2120
  }
1301
- normalizeExportFilename(value) {
1302
- const sanitized = value.trim().replace(/[\\/:*?"<>|]+/g, '-');
1303
- return sanitized.length ? sanitized : 'download';
1304
- }
1305
2121
  getStorage() {
1306
2122
  if (typeof window === 'undefined') {
1307
2123
  return null;
@@ -1320,6 +2136,7 @@ class Table {
1320
2136
  sortField: this.sortField(),
1321
2137
  sortDirection: this.sortDirection(),
1322
2138
  selectedRowKeys: this.dataKey() ? Array.from(this.selectedRowKeys()) : [],
2139
+ groupBy: this.groupBy(),
1323
2140
  };
1324
2141
  }
1325
2142
  applyPersistedState(persistedState) {
@@ -1359,6 +2176,9 @@ class Table {
1359
2176
  this.selectedRowKeys.set(new Set(Array.isArray(persistedState.selectedRowKeys)
1360
2177
  ? persistedState.selectedRowKeys
1361
2178
  : []));
2179
+ this.groupBy.set(typeof persistedState.groupBy === 'string' && persistedState.groupBy
2180
+ ? persistedState.groupBy
2181
+ : null);
1362
2182
  }
1363
2183
  shouldEmitLazyLoadAfterRestore(persistedState) {
1364
2184
  if (!persistedState) {
@@ -1416,35 +2236,34 @@ class Table {
1416
2236
  return Math.trunc(normalized);
1417
2237
  }
1418
2238
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: Table, deps: [], target: i0.ɵɵFactoryTarget.Component });
1419
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: Table, isStandalone: true, selector: "mt-table", inputs: { filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, rowActions: { classPropertyName: "rowActions", publicName: "rowActions", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, showGridlines: { classPropertyName: "showGridlines", publicName: "showGridlines", isSignal: true, isRequired: false, transformFunction: null }, stripedRows: { classPropertyName: "stripedRows", publicName: "stripedRows", isSignal: true, isRequired: false, transformFunction: null }, selectableRows: { classPropertyName: "selectableRows", publicName: "selectableRows", isSignal: true, isRequired: false, transformFunction: null }, clickableRows: { classPropertyName: "clickableRows", publicName: "clickableRows", isSignal: true, isRequired: false, transformFunction: null }, generalSearch: { classPropertyName: "generalSearch", publicName: "generalSearch", isSignal: true, isRequired: false, transformFunction: null }, lazyLocalSearch: { classPropertyName: "lazyLocalSearch", publicName: "lazyLocalSearch", isSignal: true, isRequired: false, transformFunction: null }, showFilters: { classPropertyName: "showFilters", publicName: "showFilters", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, updating: { classPropertyName: "updating", publicName: "updating", isSignal: true, isRequired: false, transformFunction: null }, lazy: { classPropertyName: "lazy", publicName: "lazy", isSignal: true, isRequired: false, transformFunction: null }, lazyLocalSort: { classPropertyName: "lazyLocalSort", publicName: "lazyLocalSort", isSignal: true, isRequired: false, transformFunction: null }, lazyTotalRecords: { classPropertyName: "lazyTotalRecords", publicName: "lazyTotalRecords", isSignal: true, isRequired: false, transformFunction: null }, reorderableColumns: { classPropertyName: "reorderableColumns", publicName: "reorderableColumns", isSignal: true, isRequired: false, transformFunction: null }, reorderableRows: { classPropertyName: "reorderableRows", publicName: "reorderableRows", isSignal: true, isRequired: false, transformFunction: null }, dataKey: { classPropertyName: "dataKey", publicName: "dataKey", isSignal: true, isRequired: false, transformFunction: null }, storageKey: { classPropertyName: "storageKey", publicName: "storageKey", isSignal: true, isRequired: false, transformFunction: null }, storageMode: { classPropertyName: "storageMode", publicName: "storageMode", isSignal: true, isRequired: false, transformFunction: null }, exportable: { classPropertyName: "exportable", publicName: "exportable", isSignal: true, isRequired: false, transformFunction: null }, exportFilename: { classPropertyName: "exportFilename", publicName: "exportFilename", isSignal: true, isRequired: false, transformFunction: null }, actionShape: { classPropertyName: "actionShape", publicName: "actionShape", isSignal: true, isRequired: false, transformFunction: null }, tableLayout: { classPropertyName: "tableLayout", publicName: "tableLayout", isSignal: true, isRequired: false, transformFunction: null }, noCard: { classPropertyName: "noCard", publicName: "noCard", isSignal: true, isRequired: false, transformFunction: null }, tabs: { classPropertyName: "tabs", publicName: "tabs", isSignal: true, isRequired: false, transformFunction: null }, tabsOptionLabel: { classPropertyName: "tabsOptionLabel", publicName: "tabsOptionLabel", isSignal: true, isRequired: false, transformFunction: null }, tabsOptionValue: { classPropertyName: "tabsOptionValue", publicName: "tabsOptionValue", isSignal: true, isRequired: false, transformFunction: null }, activeTab: { classPropertyName: "activeTab", publicName: "activeTab", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, paginatorPosition: { classPropertyName: "paginatorPosition", publicName: "paginatorPosition", isSignal: true, isRequired: false, transformFunction: null }, alwaysShowPaginator: { classPropertyName: "alwaysShowPaginator", publicName: "alwaysShowPaginator", isSignal: true, isRequired: false, transformFunction: null }, rowsPerPageOptions: { classPropertyName: "rowsPerPageOptions", publicName: "rowsPerPageOptions", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, currentPage: { classPropertyName: "currentPage", publicName: "currentPage", isSignal: true, isRequired: false, transformFunction: null }, first: { classPropertyName: "first", publicName: "first", isSignal: true, isRequired: false, transformFunction: null }, filterTerm: { classPropertyName: "filterTerm", publicName: "filterTerm", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange", cellChange: "cellChange", lazyLoad: "lazyLoad", columnReorder: "columnReorder", rowReorder: "rowReorder", rowClick: "rowClick", filters: "filtersChange", activeTab: "activeTabChange", onTabChange: "onTabChange", pageSize: "pageSizeChange", currentPage: "currentPageChange", first: "firstChange", filterTerm: "filterTermChange" }, queries: [{ propertyName: "captionStartContent", first: true, predicate: ["captionStart"], descendants: true, isSignal: true }, { propertyName: "captionEndContent", first: true, predicate: ["captionEnd"], descendants: true, isSignal: true }, { propertyName: "emptyContent", first: true, predicate: ["empty"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (!noCard()) {\r\n <mt-card>\r\n <ng-container *ngTemplateOutlet=\"tableContent\" />\r\n </mt-card>\r\n} @else {\r\n <ng-container *ngTemplateOutlet=\"tableContent\" />\r\n}\r\n\r\n<ng-template #tableContent>\r\n <div class=\"space-y-4 rounded-lg\">\r\n <div>\r\n @if (\r\n captionStartContent() ||\r\n captionEndContent() ||\r\n generalSearch() ||\r\n showFilters() ||\r\n tabs()?.length > 0 ||\r\n actions()?.length > 0\r\n ) {\r\n <div class=\"p-datatable-header rounded-t-2xl\">\r\n <div\r\n class=\"flex relative\"\r\n [class]=\"!generalSearch() ? 'justify-end' : 'justify-between'\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n <ng-container\r\n *ngTemplateOutlet=\"captionStartContent()\"\r\n ></ng-container>\r\n @if (tabs()) {\r\n <mt-tabs\r\n [(active)]=\"activeTab\"\r\n [options]=\"tabs()\"\r\n [optionLabel]=\"tabsOptionLabel()\"\r\n [optionValue]=\"tabsOptionValue()\"\r\n (onChange)=\"tabChanged($event)\"\r\n size=\"large\"\r\n ></mt-tabs>\r\n }\r\n @if (generalSearch()) {\r\n <mt-text-field\r\n [(ngModel)]=\"filterTerm\"\r\n (ngModelChange)=\"onSearchChange($event)\"\r\n icon=\"general.search-lg\"\r\n [placeholder]=\"'components.table.search' | transloco\"\r\n ></mt-text-field>\r\n }\r\n </div>\r\n <div class=\"flex items-center gap-2\">\r\n @if (showFilters()) {\r\n <mt-table-filter\r\n [columns]=\"columns()\"\r\n [data]=\"data()\"\r\n [ngModel]=\"filters()\"\r\n (filterApplied)=\"onFilterApplied($event)\"\r\n (filterReset)=\"onFilterReset()\"\r\n />\r\n }\r\n @if (exportable()) {\r\n <mt-button\r\n icon=\"file.file-x-03\"\r\n styleClass=\"text-xl! py-1.5!\"\r\n severity=\"success\"\r\n variant=\"outlined\"\r\n [tooltip]=\"'components.table.export' | transloco\"\r\n (click)=\"exportExcel()\"\r\n />\r\n }\r\n @if (actions()?.length > 0) {\r\n <div class=\"flex items-center space-x-2\">\r\n @for (action of actions(); track action.label) {\r\n <mt-button\r\n [icon]=\"action.icon\"\r\n [severity]=\"action.color\"\r\n [variant]=\"action.variant\"\r\n [size]=\"action.size\"\r\n (click)=\"action.action(row)\"\r\n [label]=\"action.label\"\r\n [tooltip]=\"action.tooltip\"\r\n ></mt-button>\r\n }\r\n </div>\r\n }\r\n <ng-container\r\n *ngTemplateOutlet=\"captionEndContent()\"\r\n ></ng-container>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n @if (!loading() && emptyContent() && data().length === 0) {\r\n <div\r\n class=\"p-4 bg-content rounded-md text-center text-gray-600 dark:text-gray-300\"\r\n >\r\n <ng-container *ngTemplateOutlet=\"emptyContent()\"></ng-container>\r\n </div>\r\n } @else {\r\n <div\r\n class=\"overflow-x-auto rounded-[10px] border border-surface-200 bg-white\"\r\n >\r\n <p-table\r\n [value]=\"displayData()\"\r\n [columns]=\"renderedColumns()\"\r\n [size]=\"size()\"\r\n [showGridlines]=\"showGridlines()\"\r\n [stripedRows]=\"stripedRows()\"\r\n [lazy]=\"lazy()\"\r\n [totalRecords]=\"totalRecords()\"\r\n [reorderableColumns]=\"reorderableColumns()\"\r\n [reorderableRows]=\"reorderableRows()\"\r\n [dataKey]=\"dataKey()\"\r\n [first]=\"first()\"\r\n [rows]=\"pageSize()\"\r\n [exportFilename]=\"exportFilename()\"\r\n (onPage)=\"onTablePage($event)\"\r\n (onLazyLoad)=\"handleLazyLoad($event)\"\r\n (onColReorder)=\"onColumnReorder($event)\"\r\n (onRowReorder)=\"onRowReorder($event)\"\r\n paginator\r\n paginatorStyleClass=\"hidden!\"\r\n class=\"mt-table min-w-full align-middle text-sm\"\r\n [class.table-auto]=\"tableLayout() === 'auto'\"\r\n [class.table-fixed]=\"tableLayout() === 'fixed'\"\r\n >\r\n <ng-template\r\n #header\r\n let-columns\r\n class=\"bg-surface-50 dark:bg-surface-950 border-b border-surface-300 dark:border-surface-500\"\r\n >\r\n <tr>\r\n @if (reorderableRows()) {\r\n <th class=\"w-10\"></th>\r\n }\r\n @if (selectableRows()) {\r\n <th class=\"w-12 text-start\">\r\n <mt-checkbox-field\r\n [ngModel]=\"allSelectedOnPage()\"\r\n (ngModelChange)=\"toggleAllRowsOnPage()\"\r\n ></mt-checkbox-field>\r\n </th>\r\n }\r\n\r\n @for (col of columns; track col.key || col.label || $index) {\r\n @if (reorderableColumns()) {\r\n <th\r\n pReorderableColumn\r\n class=\"text-start text-sm font-normal text-[#323232]\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n {{ col.label }}\r\n <!-- <mt-icon-->\r\n <!-- icon=\"general.menu-05\"-->\r\n <!-- class=\"text-xs text-gray-400\"-->\r\n <!-- ></mt-icon>-->\r\n <mt-button\r\n styleClass=\"cursor-move!\"\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n icon=\"general.menu-05\"\r\n ></mt-button>\r\n </div>\r\n </th>\r\n } @else {\r\n <th\r\n class=\"text-start text-sm font-normal text-[#323232]\"\r\n [style.width]=\"col.width ?? null\"\r\n [style.minWidth]=\"getColumnMinWidth(col)\"\r\n >\r\n @if (isColumnSortable(col)) {\r\n <button\r\n type=\"button\"\r\n class=\"inline-flex items-center gap-2 cursor-pointer\"\r\n (click)=\"toggleSort(col)\"\r\n >\r\n <span>{{ col.label }}</span>\r\n <mt-icon\r\n [icon]=\"getSortIcon(col)\"\r\n class=\"text-xs text-gray-400\"\r\n />\r\n </button>\r\n } @else {\r\n {{ col.label }}\r\n }\r\n </th>\r\n }\r\n }\r\n\r\n @if (rowActions().length > 0) {\r\n <th class=\"text-end! text-sm font-normal text-[#323232]\">\r\n {{ \"components.table.actions\" | transloco }}\r\n </th>\r\n }\r\n </tr>\r\n @if (updating()) {\r\n <tr>\r\n <th\r\n [attr.colspan]=\"\r\n columns.length +\r\n (reorderableRows() ? 1 : 0) +\r\n (selectableRows() ? 1 : 0) +\r\n (rowActions().length > 0 ? 1 : 0)\r\n \"\r\n class=\"!p-0\"\r\n >\r\n <p-progressBar\r\n mode=\"indeterminate\"\r\n [style]=\"{ height: '4px' }\"\r\n />\r\n </th>\r\n </tr>\r\n }\r\n </ng-template>\r\n <ng-template\r\n #body\r\n let-row\r\n let-columns=\"columns\"\r\n let-index=\"rowIndex\"\r\n class=\"divide-y divide-gray-200\"\r\n >\r\n @if (loading()) {\r\n <tr>\r\n @if (reorderableRows()) {\r\n <td><p-skeleton /></td>\r\n }\r\n @if (selectableRows()) {\r\n <td><p-skeleton /></td>\r\n }\r\n @for (col of columns; track col.key || col.label || $index) {\r\n <td><p-skeleton /></td>\r\n }\r\n @if (rowActions().length > 0) {\r\n <td><p-skeleton /></td>\r\n }\r\n </tr>\r\n } @else {\r\n <tr\r\n class=\"border-surface-300 transition-colors duration-150 dark:border-surface-500\"\r\n [class.mt-table-clickable-row]=\"clickableRows()\"\r\n [class.mt-table-status-entity-row]=\"\r\n getStatusEntityAccentColor(row)\r\n \"\r\n [style.--mt-table-status-accent]=\"\r\n getStatusEntityAccentColor(row)\r\n \"\r\n [class.cursor-pointer]=\"clickableRows()\"\r\n [pReorderableRow]=\"index\"\r\n (click)=\"onRowClick($event, row)\"\r\n >\r\n @if (reorderableRows()) {\r\n <td class=\"w-10 text-center\">\r\n <mt-button\r\n styleClass=\"cursor-move!\"\r\n pReorderableRowHandle\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n icon=\"general.menu-05\"\r\n ></mt-button>\r\n <!-- <mt-icon-->\r\n <!-- icon=\"general.menu-05\"-->\r\n <!-- class=\"cursor-move text-gray-500\"-->\r\n <!-- pReorderableRowHandle-->\r\n <!-- ></mt-icon>-->\r\n </td>\r\n }\r\n @if (selectableRows()) {\r\n <td class=\"w-12\">\r\n <mt-checkbox-field\r\n [ngModel]=\"isRowSelected(row)\"\r\n (ngModelChange)=\"toggleRow(row)\"\r\n ></mt-checkbox-field>\r\n </td>\r\n }\r\n\r\n @for (col of columns; track col.key || col.label || $index) {\r\n <td\r\n class=\"text-sm font-normal text-[#4b4b4b]\"\r\n [style.width]=\"col.width ?? null\"\r\n [style.minWidth]=\"getColumnMinWidth(col)\"\r\n >\r\n @switch (col.type) {\r\n @case (\"boolean\") {\r\n <mt-toggle-field\r\n disabled=\"col.readonly\"\r\n [ngModel]=\"getBooleanProperty(row, col.key)\"\r\n (ngModelChange)=\"\r\n onCellChange(row, col.key, $event, 'boolean')\r\n \"\r\n ></mt-toggle-field>\r\n }\r\n @case (\"date\") {\r\n {{\r\n getDateProperty(row, col.key) | mtDateFormat: \"date\"\r\n }}\r\n }\r\n @case (\"dateTime\") {\r\n {{\r\n getDateProperty(row, col.key)\r\n | mtDateFormat: \"dateTime\"\r\n }}\r\n }\r\n @case (\"user\") {\r\n @if (getEntityPreviewData(row, col); as entityData) {\r\n <mt-entity-preview\r\n [data]=\"entityData\"\r\n attachmentShape=\"compact\"\r\n ></mt-entity-preview>\r\n } @else {\r\n {{ getProperty(row, col.key) }}\r\n }\r\n }\r\n @case (\"status\") {\r\n @if (getEntityPreviewData(row, col); as entityData) {\r\n <mt-entity-preview\r\n [data]=\"entityData\"\r\n attachmentShape=\"compact\"\r\n ></mt-entity-preview>\r\n } @else {\r\n {{ getProperty(row, col.key) }}\r\n }\r\n }\r\n @case (\"entity\") {\r\n @if (getEntityColumnData(row, col); as entityData) {\r\n <mt-entity-preview\r\n [data]=\"entityData\"\r\n attachmentShape=\"compact\"\r\n ></mt-entity-preview>\r\n } @else {\r\n {{ getProperty(row, col.key) }}\r\n }\r\n }\r\n @case (\"custom\") {\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n col.customCellTpl;\r\n context: { $implicit: row }\r\n \"\r\n >\r\n </ng-container>\r\n }\r\n @default {\r\n {{ getProperty(row, col.key) }}\r\n }\r\n }\r\n </td>\r\n }\r\n\r\n @if (rowActions().length > 0) {\r\n <td class=\"text-right\">\r\n @if (actionShape() === \"popover\") {\r\n <div class=\"flex items-center justify-end\">\r\n <mt-button\r\n icon=\"general.dots-vertical\"\r\n severity=\"secondary\"\r\n variant=\"text\"\r\n size=\"large\"\r\n (click)=\"rowPopover.toggle($event)\"\r\n data-row-click-ignore=\"true\"\r\n ></mt-button>\r\n <p-popover #rowPopover appendTo=\"body\">\r\n <div class=\"flex flex-col min-w-40\">\r\n @for (\r\n action of getVisibleRowActions(row);\r\n track $index\r\n ) {\r\n <button\r\n class=\"flex items-center gap-2 px-2 cursor-pointer py-2 text-sm rounded transition-colors\"\r\n [class]=\"\r\n action.color === 'danger'\r\n ? 'text-red-600 hover:bg-red-50 dark:hover:bg-red-950'\r\n : 'text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-surface-700'\r\n \"\r\n (click)=\"\r\n rowAction($event, action, row);\r\n rowPopover.hide()\r\n \"\r\n >\r\n @if (action.icon) {\r\n <mt-icon\r\n [icon]=\"action.icon\"\r\n class=\"text-base\"\r\n />\r\n }\r\n <span>{{\r\n action.label || action.tooltip\r\n }}</span>\r\n </button>\r\n }\r\n </div>\r\n </p-popover>\r\n </div>\r\n } @else {\r\n <div class=\"flex items-center justify-end space-x-2\">\r\n @for (action of rowActions(); track $index) {\r\n @let hidden = action.hidden?.(row);\r\n @if (!hidden) {\r\n <mt-button\r\n [icon]=\"action.icon\"\r\n [severity]=\"action.color\"\r\n [variant]=\"action.variant\"\r\n [size]=\"action.size || 'small'\"\r\n (click)=\"rowAction($event, action, row)\"\r\n [tooltip]=\"action.tooltip\"\r\n [label]=\"action.label\"\r\n [loading]=\"resolveActionLoading(action, row)\"\r\n ></mt-button>\r\n }\r\n }\r\n </div>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </ng-template>\r\n <ng-template #emptymessage>\r\n <tr>\r\n <td\r\n [attr.colspan]=\"\r\n renderedColumns().length +\r\n (reorderableRows() ? 1 : 0) +\r\n (selectableRows() ? 1 : 0) +\r\n (rowActions().length > 0 ? 1 : 0)\r\n \"\r\n class=\"text-center\"\r\n >\r\n <div\r\n class=\"flex min-h-44 flex-col items-center justify-center gap-3 py-8 text-center\"\r\n >\r\n <svg\r\n width=\"152\"\r\n height=\"120\"\r\n viewBox=\"0 0 152 120\"\r\n fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n >\r\n <circle cx=\"76\" cy=\"52\" r=\"52\" fill=\"#E9EAEB\" />\r\n <g filter=\"url(#filter0_ddd_2474_28277)\">\r\n <path\r\n d=\"M77.6 16C66.8273 16 57.2978 21.3233 51.4987 29.4829C49.605 29.0363 47.6301 28.8 45.6 28.8C31.4615 28.8 20 40.2615 20 54.4C20 68.5385 31.4615 80 45.6 80L109.6 80C121.971 80 132 69.9712 132 57.6C132 45.2288 121.971 35.2 109.6 35.2C108.721 35.2 107.854 35.2506 107.002 35.349C102.098 23.9677 90.7797 16 77.6 16Z\"\r\n fill=\"#FAFAFA\"\r\n />\r\n <ellipse\r\n cx=\"45.6\"\r\n cy=\"54.3998\"\r\n rx=\"25.6\"\r\n ry=\"25.6\"\r\n fill=\"url(#paint0_linear_2474_28277)\"\r\n />\r\n <circle\r\n cx=\"77.6016\"\r\n cy=\"48\"\r\n r=\"32\"\r\n fill=\"url(#paint1_linear_2474_28277)\"\r\n />\r\n <ellipse\r\n cx=\"109.599\"\r\n cy=\"57.6002\"\r\n rx=\"22.4\"\r\n ry=\"22.4\"\r\n fill=\"url(#paint2_linear_2474_28277)\"\r\n />\r\n </g>\r\n <circle cx=\"21\" cy=\"19\" r=\"5\" fill=\"#F5F5F5\" />\r\n <circle cx=\"18\" cy=\"109\" r=\"7\" fill=\"#F5F5F5\" />\r\n <circle cx=\"145\" cy=\"35\" r=\"7\" fill=\"#F5F5F5\" />\r\n <circle cx=\"134\" cy=\"8\" r=\"4\" fill=\"#F5F5F5\" />\r\n <foreignObject x=\"44\" y=\"54\" width=\"64\" height=\"64\">\r\n <div\r\n xmlns=\"http://www.w3.org/1999/xhtml\"\r\n style=\"\r\n backdrop-filter: blur(4px);\r\n clip-path: url(#bgblur_0_2474_28277_clip_path);\r\n height: 100%;\r\n width: 100%;\r\n \"\r\n ></div>\r\n </foreignObject>\r\n <g data-figma-bg-blur-radius=\"8\">\r\n <path\r\n d=\"M52 86C52 72.7452 62.7452 62 76 62C89.2548 62 100 72.7452 100 86C100 99.2548 89.2548 110 76 110C62.7452 110 52 99.2548 52 86Z\"\r\n fill=\"#344054\"\r\n fill-opacity=\"0.4\"\r\n />\r\n <path\r\n d=\"M85 95L81.5001 91.5M84 85.5C84 90.1944 80.1944 94 75.5 94C70.8056 94 67 90.1944 67 85.5C67 80.8056 70.8056 77 75.5 77C80.1944 77 84 80.8056 84 85.5Z\"\r\n stroke=\"white\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </g>\r\n <defs>\r\n <filter\r\n id=\"filter0_ddd_2474_28277\"\r\n x=\"0\"\r\n y=\"16\"\r\n width=\"152\"\r\n height=\"104\"\r\n filterUnits=\"userSpaceOnUse\"\r\n color-interpolation-filters=\"sRGB\"\r\n >\r\n <feFlood\r\n flood-opacity=\"0\"\r\n result=\"BackgroundImageFix\"\r\n />\r\n <feColorMatrix\r\n in=\"SourceAlpha\"\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"\r\n result=\"hardAlpha\"\r\n />\r\n <feMorphology\r\n radius=\"1.5\"\r\n operator=\"erode\"\r\n in=\"SourceAlpha\"\r\n result=\"effect1_dropShadow_2474_28277\"\r\n />\r\n <feOffset dy=\"3\" />\r\n <feGaussianBlur stdDeviation=\"1.5\" />\r\n <feComposite in2=\"hardAlpha\" operator=\"out\" />\r\n <feColorMatrix\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0.0392157 0 0 0 0 0.0496732 0 0 0 0 0.0705882 0 0 0 0.04 0\"\r\n />\r\n <feBlend\r\n mode=\"normal\"\r\n in2=\"BackgroundImageFix\"\r\n result=\"effect1_dropShadow_2474_28277\"\r\n />\r\n <feColorMatrix\r\n in=\"SourceAlpha\"\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"\r\n result=\"hardAlpha\"\r\n />\r\n <feMorphology\r\n radius=\"4\"\r\n operator=\"erode\"\r\n in=\"SourceAlpha\"\r\n result=\"effect2_dropShadow_2474_28277\"\r\n />\r\n <feOffset dy=\"8\" />\r\n <feGaussianBlur stdDeviation=\"4\" />\r\n <feComposite in2=\"hardAlpha\" operator=\"out\" />\r\n <feColorMatrix\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0.0392157 0 0 0 0 0.0496732 0 0 0 0 0.0705882 0 0 0 0.03 0\"\r\n />\r\n <feBlend\r\n mode=\"normal\"\r\n in2=\"effect1_dropShadow_2474_28277\"\r\n result=\"effect2_dropShadow_2474_28277\"\r\n />\r\n <feColorMatrix\r\n in=\"SourceAlpha\"\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"\r\n result=\"hardAlpha\"\r\n />\r\n <feMorphology\r\n radius=\"4\"\r\n operator=\"erode\"\r\n in=\"SourceAlpha\"\r\n result=\"effect3_dropShadow_2474_28277\"\r\n />\r\n <feOffset dy=\"20\" />\r\n <feGaussianBlur stdDeviation=\"12\" />\r\n <feComposite in2=\"hardAlpha\" operator=\"out\" />\r\n <feColorMatrix\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0.0392157 0 0 0 0 0.0496732 0 0 0 0 0.0705882 0 0 0 0.08 0\"\r\n />\r\n <feBlend\r\n mode=\"normal\"\r\n in2=\"effect2_dropShadow_2474_28277\"\r\n result=\"effect3_dropShadow_2474_28277\"\r\n />\r\n <feBlend\r\n mode=\"normal\"\r\n in=\"SourceGraphic\"\r\n in2=\"effect3_dropShadow_2474_28277\"\r\n result=\"shape\"\r\n />\r\n </filter>\r\n <clipPath\r\n id=\"bgblur_0_2474_28277_clip_path\"\r\n transform=\"translate(-44 -54)\"\r\n >\r\n <path\r\n d=\"M52 86C52 72.7452 62.7452 62 76 62C89.2548 62 100 72.7452 100 86C100 99.2548 89.2548 110 76 110C62.7452 110 52 99.2548 52 86Z\"\r\n />\r\n </clipPath>\r\n <linearGradient\r\n id=\"paint0_linear_2474_28277\"\r\n x1=\"25.9429\"\r\n y1=\"37.4855\"\r\n x2=\"71.2\"\r\n y2=\"79.9998\"\r\n gradientUnits=\"userSpaceOnUse\"\r\n >\r\n <stop stop-color=\"#D0D5DD\" />\r\n <stop\r\n offset=\"0.350715\"\r\n stop-color=\"white\"\r\n stop-opacity=\"0\"\r\n />\r\n </linearGradient>\r\n <linearGradient\r\n id=\"paint1_linear_2474_28277\"\r\n x1=\"53.0301\"\r\n y1=\"26.8571\"\r\n x2=\"109.602\"\r\n y2=\"80\"\r\n gradientUnits=\"userSpaceOnUse\"\r\n >\r\n <stop stop-color=\"#D0D5DD\" />\r\n <stop\r\n offset=\"0.350715\"\r\n stop-color=\"white\"\r\n stop-opacity=\"0\"\r\n />\r\n </linearGradient>\r\n <linearGradient\r\n id=\"paint2_linear_2474_28277\"\r\n x1=\"92.3992\"\r\n y1=\"42.8002\"\r\n x2=\"131.999\"\r\n y2=\"80.0002\"\r\n gradientUnits=\"userSpaceOnUse\"\r\n >\r\n <stop stop-color=\"#D0D5DD\" />\r\n <stop\r\n offset=\"0.350715\"\r\n stop-color=\"white\"\r\n stop-opacity=\"0\"\r\n />\r\n </linearGradient>\r\n </defs>\r\n </svg>\r\n <p class=\"m-0 text-base font-medium text-surface-500\">\r\n {{ \"components.table.no-data-found\" | transloco }}\r\n </p>\r\n </div>\r\n </td>\r\n </tr>\r\n </ng-template>\r\n </p-table>\r\n </div>\r\n }\r\n </div>\r\n\r\n <div\r\n class=\"flex flex-col gap-3 pb-3 px-4\"\r\n [class]=\"'items-' + paginatorPosition()\"\r\n >\r\n <mt-paginator\r\n [(rows)]=\"pageSize\"\r\n [(first)]=\"first\"\r\n [(page)]=\"currentPage\"\r\n [totalRecords]=\"totalRecords()\"\r\n [alwaysShow]=\"alwaysShowPaginator()\"\r\n [rowsPerPageOptions]=\"rowsPerPageOptions()\"\r\n (onPageChange)=\"onPaginatorPage($event)\"\r\n ></mt-paginator>\r\n </div>\r\n </div>\r\n</ng-template>\r\n", styles: [":host ::ng-deep .p-datatable-header{padding:0 0 1.5rem;background:transparent;border:0}:host ::ng-deep .p-datatable-table{border-collapse:separate;border-spacing:0}:host ::ng-deep .p-datatable-thead>tr>th{padding:.9rem 1rem;background:#fff;border-bottom:1px solid #ebebf0;color:#323232;font-size:14px;font-weight:400;line-height:20px;white-space:nowrap}:host ::ng-deep .p-datatable-tbody>tr>td{padding:.72rem 1rem;background:#fff;border-bottom:1px solid #ebebf0;color:#4b4b4b;font-size:14px;font-weight:400;line-height:20px;vertical-align:middle}:host ::ng-deep .p-datatable-tbody>tr:last-child>td{border-bottom:0}:host ::ng-deep .p-datatable-thead>tr>th:first-child{border-top-left-radius:.625rem}:host ::ng-deep .p-datatable-thead>tr>th:last-child{border-top-right-radius:.625rem}:host ::ng-deep .p-datatable-tbody>tr:last-child>td:first-child{border-bottom-left-radius:.625rem}:host ::ng-deep .p-datatable-tbody>tr:last-child>td:last-child{border-bottom-right-radius:.625rem}.mt-table-clickable-row>td{transition:background-color .16s ease,color .16s ease,border-color .16s ease}.mt-table-clickable-row:hover>td,.mt-table-clickable-row:focus-within>td{background:#fafafa}.mt-table-clickable-row:hover>td:first-child,.mt-table-clickable-row:focus-within>td:first-child{border-inline-start:none}.mt-table-status-entity-row>td{background:#fff}.mt-table-status-entity-row>td:first-child:before{display:none}\n"], dependencies: [{ kind: "ngmodule", type: TableModule }, { kind: "component", type: i1$1.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: i1$1.ReorderableColumn, selector: "[pReorderableColumn]", inputs: ["pReorderableColumnDisabled"] }, { kind: "directive", type: i1$1.ReorderableRowHandle, selector: "[pReorderableRowHandle]" }, { kind: "directive", type: i1$1.ReorderableRow, selector: "[pReorderableRow]", inputs: ["pReorderableRow", "pReorderableRowDisabled"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], outputs: ["onChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: TextField, selector: "mt-text-field", inputs: ["field", "hint", "label", "placeholder", "class", "type", "readonly", "pInputs", "required", "icon", "iconPosition"] }, { kind: "component", type: Paginator, selector: "mt-paginator", inputs: ["rows", "totalRecords", "first", "page", "rowsPerPageOptions", "showFirstLastIcon", "showCurrentPageReport", "fluid", "pageLinkSize", "alwaysShow"], outputs: ["rowsChange", "firstChange", "pageChange", "onPageChange"] }, { kind: "component", type: CheckboxField, selector: "mt-checkbox-field", inputs: ["label", "labelPosition", "placeholder", "readonly", "pInputs", "required"], outputs: ["onChange"] }, { kind: "component", type: Tabs, selector: "mt-tabs", inputs: ["options", "optionLabel", "optionValue", "active", "mode", "moreLabel", "size", "fluid", "disabled"], outputs: ["activeChange", "onChange"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i3$1.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "ngmodule", type: ProgressBarModule }, { kind: "component", type: i4.ProgressBar, selector: "p-progressBar, p-progressbar, p-progress-bar", inputs: ["value", "showValue", "styleClass", "valueStyleClass", "unit", "mode", "color"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "component", type: TableFilter, selector: "mt-table-filter", inputs: ["columns", "data"], outputs: ["filterApplied", "filterReset"] }, { kind: "component", type: EntityPreview, selector: "mt-entity-preview", inputs: ["data", "attachmentShape"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i2.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "pipe", type: i3.TranslocoPipe, name: "transloco" }, { kind: "pipe", type: MTDateFormatPipe, name: "mtDateFormat" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2239
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: Table, isStandalone: true, selector: "mt-table", inputs: { filters: { classPropertyName: "filters", publicName: "filters", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, rowActions: { classPropertyName: "rowActions", publicName: "rowActions", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, showGridlines: { classPropertyName: "showGridlines", publicName: "showGridlines", isSignal: true, isRequired: false, transformFunction: null }, stripedRows: { classPropertyName: "stripedRows", publicName: "stripedRows", isSignal: true, isRequired: false, transformFunction: null }, selectableRows: { classPropertyName: "selectableRows", publicName: "selectableRows", isSignal: true, isRequired: false, transformFunction: null }, clickableRows: { classPropertyName: "clickableRows", publicName: "clickableRows", isSignal: true, isRequired: false, transformFunction: null }, generalSearch: { classPropertyName: "generalSearch", publicName: "generalSearch", isSignal: true, isRequired: false, transformFunction: null }, lazyLocalSearch: { classPropertyName: "lazyLocalSearch", publicName: "lazyLocalSearch", isSignal: true, isRequired: false, transformFunction: null }, showFilters: { classPropertyName: "showFilters", publicName: "showFilters", isSignal: true, isRequired: false, transformFunction: null }, filterMode: { classPropertyName: "filterMode", publicName: "filterMode", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, updating: { classPropertyName: "updating", publicName: "updating", isSignal: true, isRequired: false, transformFunction: null }, lazy: { classPropertyName: "lazy", publicName: "lazy", isSignal: true, isRequired: false, transformFunction: null }, lazyLocalSort: { classPropertyName: "lazyLocalSort", publicName: "lazyLocalSort", isSignal: true, isRequired: false, transformFunction: null }, lazyTotalRecords: { classPropertyName: "lazyTotalRecords", publicName: "lazyTotalRecords", isSignal: true, isRequired: false, transformFunction: null }, reorderableColumns: { classPropertyName: "reorderableColumns", publicName: "reorderableColumns", isSignal: true, isRequired: false, transformFunction: null }, reorderableRows: { classPropertyName: "reorderableRows", publicName: "reorderableRows", isSignal: true, isRequired: false, transformFunction: null }, dataKey: { classPropertyName: "dataKey", publicName: "dataKey", isSignal: true, isRequired: false, transformFunction: null }, storageKey: { classPropertyName: "storageKey", publicName: "storageKey", isSignal: true, isRequired: false, transformFunction: null }, storageMode: { classPropertyName: "storageMode", publicName: "storageMode", isSignal: true, isRequired: false, transformFunction: null }, exportable: { classPropertyName: "exportable", publicName: "exportable", isSignal: true, isRequired: false, transformFunction: null }, printable: { classPropertyName: "printable", publicName: "printable", isSignal: true, isRequired: false, transformFunction: null }, groupable: { classPropertyName: "groupable", publicName: "groupable", isSignal: true, isRequired: false, transformFunction: null }, cellClickFilter: { classPropertyName: "cellClickFilter", publicName: "cellClickFilter", isSignal: true, isRequired: false, transformFunction: null }, printTitle: { classPropertyName: "printTitle", publicName: "printTitle", isSignal: true, isRequired: false, transformFunction: null }, exportFilename: { classPropertyName: "exportFilename", publicName: "exportFilename", isSignal: true, isRequired: false, transformFunction: null }, actionShape: { classPropertyName: "actionShape", publicName: "actionShape", isSignal: true, isRequired: false, transformFunction: null }, tableLayout: { classPropertyName: "tableLayout", publicName: "tableLayout", isSignal: true, isRequired: false, transformFunction: null }, noCard: { classPropertyName: "noCard", publicName: "noCard", isSignal: true, isRequired: false, transformFunction: null }, tabs: { classPropertyName: "tabs", publicName: "tabs", isSignal: true, isRequired: false, transformFunction: null }, tabsOptionLabel: { classPropertyName: "tabsOptionLabel", publicName: "tabsOptionLabel", isSignal: true, isRequired: false, transformFunction: null }, tabsOptionValue: { classPropertyName: "tabsOptionValue", publicName: "tabsOptionValue", isSignal: true, isRequired: false, transformFunction: null }, activeTab: { classPropertyName: "activeTab", publicName: "activeTab", isSignal: true, isRequired: false, transformFunction: null }, actions: { classPropertyName: "actions", publicName: "actions", isSignal: true, isRequired: false, transformFunction: null }, paginatorPosition: { classPropertyName: "paginatorPosition", publicName: "paginatorPosition", isSignal: true, isRequired: false, transformFunction: null }, alwaysShowPaginator: { classPropertyName: "alwaysShowPaginator", publicName: "alwaysShowPaginator", isSignal: true, isRequired: false, transformFunction: null }, rowsPerPageOptions: { classPropertyName: "rowsPerPageOptions", publicName: "rowsPerPageOptions", isSignal: true, isRequired: false, transformFunction: null }, pageSize: { classPropertyName: "pageSize", publicName: "pageSize", isSignal: true, isRequired: false, transformFunction: null }, currentPage: { classPropertyName: "currentPage", publicName: "currentPage", isSignal: true, isRequired: false, transformFunction: null }, first: { classPropertyName: "first", publicName: "first", isSignal: true, isRequired: false, transformFunction: null }, filterTerm: { classPropertyName: "filterTerm", publicName: "filterTerm", isSignal: true, isRequired: false, transformFunction: null }, groupBy: { classPropertyName: "groupBy", publicName: "groupBy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange", cellChange: "cellChange", lazyLoad: "lazyLoad", columnReorder: "columnReorder", rowReorder: "rowReorder", rowClick: "rowClick", filters: "filtersChange", activeTab: "activeTabChange", onTabChange: "onTabChange", pageSize: "pageSizeChange", currentPage: "currentPageChange", first: "firstChange", filterTerm: "filterTermChange", groupBy: "groupByChange" }, providers: [MTDateFormatPipe], queries: [{ propertyName: "captionStartContent", first: true, predicate: ["captionStart"], descendants: true, isSignal: true }, { propertyName: "captionEndContent", first: true, predicate: ["captionEnd"], descendants: true, isSignal: true }, { propertyName: "emptyContent", first: true, predicate: ["empty"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (!noCard()) {\r\n <mt-card>\r\n <ng-container *ngTemplateOutlet=\"tableContent\" />\r\n </mt-card>\r\n} @else {\r\n <ng-container *ngTemplateOutlet=\"tableContent\" />\r\n}\r\n\r\n<ng-template #tableContent>\r\n <div class=\"space-y-4 rounded-lg\">\r\n <div>\r\n <mt-table-caption\r\n [generalSearch]=\"generalSearch()\"\r\n [showFilters]=\"showFilters()\"\r\n [filterMode]=\"filterMode()\"\r\n [exportable]=\"exportable()\"\r\n [printable]=\"printable()\"\r\n [groupable]=\"groupable()\"\r\n [columns]=\"columns()\"\r\n [data]=\"data()\"\r\n [groupColumns]=\"grouping.groupableColumns()\"\r\n [tabs]=\"tabs()\"\r\n [tabsOptionLabel]=\"tabsOptionLabel()\"\r\n [tabsOptionValue]=\"tabsOptionValue()\"\r\n [actions]=\"actions()\"\r\n [captionStart]=\"captionStartContent() ?? null\"\r\n [captionEnd]=\"captionEndContent() ?? null\"\r\n [(activeTab)]=\"activeTab\"\r\n [(filters)]=\"filters\"\r\n [(filterTerm)]=\"filterTerm\"\r\n [(groupBy)]=\"groupBy\"\r\n (exportRequested)=\"exportExcel()\"\r\n (printRequested)=\"printPdf()\"\r\n (onTabChange)=\"tabChanged($event)\"\r\n (searchChange)=\"onSearchChange($event)\"\r\n (filterApplied)=\"onFilterApplied($event)\"\r\n (filterReset)=\"onFilterReset()\"\r\n />\r\n\r\n @if (!loading() && emptyContent() && data().length === 0) {\r\n <div\r\n class=\"p-4 bg-content rounded-md text-center text-gray-600 dark:text-gray-300\"\r\n >\r\n <ng-container *ngTemplateOutlet=\"emptyContent()\"></ng-container>\r\n </div>\r\n } @else {\r\n <div\r\n class=\"overflow-x-auto rounded-[10px] border border-surface-200 bg-white\"\r\n >\r\n <p-table\r\n [value]=\"displayData()\"\r\n [columns]=\"renderedColumns()\"\r\n [size]=\"size()\"\r\n [showGridlines]=\"showGridlines()\"\r\n [stripedRows]=\"stripedRows()\"\r\n [lazy]=\"lazy()\"\r\n [totalRecords]=\"totalRecords()\"\r\n [reorderableColumns]=\"reorderableColumns()\"\r\n [reorderableRows]=\"reorderableRows()\"\r\n [dataKey]=\"dataKey()\"\r\n [first]=\"first()\"\r\n [rows]=\"pageSize()\"\r\n [exportFilename]=\"exportFilename()\"\r\n [rowGroupMode]=\"grouping.groupingActive() ? 'subheader' : null\"\r\n [groupRowsBy]=\"grouping.activeGroupColumn()?.key ?? null\"\r\n [sortField]=\"sortField()\"\r\n [sortOrder]=\"sortDirection() === 'desc' ? -1 : 1\"\r\n (onPage)=\"onTablePage($event)\"\r\n (onLazyLoad)=\"handleLazyLoad($event)\"\r\n (onColReorder)=\"onColumnReorder($event)\"\r\n (onRowReorder)=\"onRowReorder($event)\"\r\n paginator\r\n paginatorStyleClass=\"hidden!\"\r\n class=\"mt-table min-w-full align-middle text-sm\"\r\n [class.table-auto]=\"tableLayout() === 'auto'\"\r\n [class.table-fixed]=\"tableLayout() === 'fixed'\"\r\n >\r\n <ng-template\r\n #header\r\n let-columns\r\n class=\"bg-surface-50 dark:bg-surface-950 border-b border-surface-300 dark:border-surface-500\"\r\n >\r\n <tr>\r\n @if (reorderableRows()) {\r\n <th class=\"w-10\"></th>\r\n }\r\n @if (selectableRows()) {\r\n <th class=\"w-12 text-start\">\r\n <mt-checkbox-field\r\n [ngModel]=\"allSelectedOnPage()\"\r\n (ngModelChange)=\"toggleAllRowsOnPage()\"\r\n ></mt-checkbox-field>\r\n </th>\r\n }\r\n\r\n @for (col of columns; track col.key || col.label || $index) {\r\n @if (reorderableColumns()) {\r\n <th\r\n pReorderableColumn\r\n class=\"text-start text-sm font-normal text-[#323232]\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n {{ col.label }}\r\n @if (\r\n isColumnFilterMode() && getFilterableColumn(col.key);\r\n as filterableCol\r\n ) {\r\n <mt-table-column-filter\r\n [column]=\"filterableCol\"\r\n [value]=\"filters()[col.key]\"\r\n (filterChange)=\"\r\n onColumnFilterChange(col.key, $event)\r\n \"\r\n />\r\n }\r\n <mt-button\r\n styleClass=\"cursor-move!\"\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n icon=\"general.menu-05\"\r\n ></mt-button>\r\n </div>\r\n </th>\r\n } @else {\r\n <th\r\n class=\"text-start text-sm font-normal text-[#323232]\"\r\n [style.width]=\"col.width ?? null\"\r\n [style.minWidth]=\"getColumnMinWidth(col)\"\r\n >\r\n <div class=\"inline-flex items-center gap-1\">\r\n @if (isColumnSortable(col)) {\r\n <button\r\n type=\"button\"\r\n class=\"inline-flex items-center gap-2 cursor-pointer\"\r\n (click)=\"toggleSort(col)\"\r\n >\r\n <span>{{ col.label }}</span>\r\n <mt-icon\r\n [icon]=\"getSortIcon(col)\"\r\n class=\"text-xs text-gray-400\"\r\n />\r\n </button>\r\n } @else {\r\n {{ col.label }}\r\n }\r\n @if (\r\n isColumnFilterMode() && getFilterableColumn(col.key);\r\n as filterableCol\r\n ) {\r\n <mt-table-column-filter\r\n [column]=\"filterableCol\"\r\n [value]=\"filters()[col.key]\"\r\n (filterChange)=\"\r\n onColumnFilterChange(col.key, $event)\r\n \"\r\n />\r\n }\r\n </div>\r\n </th>\r\n }\r\n }\r\n\r\n @if (rowActions().length > 0) {\r\n <th class=\"text-end! text-sm font-normal text-[#323232]\">\r\n {{ \"components.table.actions\" | transloco }}\r\n </th>\r\n }\r\n </tr>\r\n @if (updating()) {\r\n <tr>\r\n <th [attr.colspan]=\"totalColumnSpan()\" class=\"!p-0\">\r\n <p-progressBar\r\n mode=\"indeterminate\"\r\n [style]=\"{ height: '4px' }\"\r\n />\r\n </th>\r\n </tr>\r\n }\r\n </ng-template>\r\n <ng-template\r\n #body\r\n let-row\r\n let-columns=\"columns\"\r\n let-index=\"rowIndex\"\r\n class=\"divide-y divide-gray-200\"\r\n >\r\n @if (loading()) {\r\n <tr>\r\n @if (reorderableRows()) {\r\n <td><p-skeleton /></td>\r\n }\r\n @if (selectableRows()) {\r\n <td><p-skeleton /></td>\r\n }\r\n @for (col of columns; track col.key || col.label || $index) {\r\n <td><p-skeleton /></td>\r\n }\r\n @if (rowActions().length > 0) {\r\n <td><p-skeleton /></td>\r\n }\r\n </tr>\r\n } @else {\r\n <tr\r\n class=\"border-surface-300 transition-colors duration-150 dark:border-surface-500\"\r\n [class.mt-table-clickable-row]=\"clickableRows()\"\r\n [class.mt-table-status-entity-row]=\"\r\n getStatusEntityAccentColor(row)\r\n \"\r\n [style.--mt-table-status-accent]=\"\r\n getStatusEntityAccentColor(row)\r\n \"\r\n [class.cursor-pointer]=\"clickableRows()\"\r\n [pReorderableRow]=\"index\"\r\n (click)=\"onRowClick($event, row)\"\r\n >\r\n @if (reorderableRows()) {\r\n <td class=\"w-10 text-center\">\r\n <mt-button\r\n styleClass=\"cursor-move!\"\r\n pReorderableRowHandle\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n icon=\"general.menu-05\"\r\n ></mt-button>\r\n <!-- <mt-icon-->\r\n <!-- icon=\"general.menu-05\"-->\r\n <!-- class=\"cursor-move text-gray-500\"-->\r\n <!-- pReorderableRowHandle-->\r\n <!-- ></mt-icon>-->\r\n </td>\r\n }\r\n @if (selectableRows()) {\r\n <td class=\"w-12\">\r\n <mt-checkbox-field\r\n [ngModel]=\"isRowSelected(row)\"\r\n (ngModelChange)=\"toggleRow(row)\"\r\n ></mt-checkbox-field>\r\n </td>\r\n }\r\n\r\n @for (col of columns; track col.key || col.label || $index) {\r\n <td\r\n class=\"text-sm font-normal text-[#4b4b4b]\"\r\n [style.width]=\"col.width ?? null\"\r\n [style.minWidth]=\"getColumnMinWidth(col)\"\r\n >\r\n @switch (col.type) {\r\n @case (\"boolean\") {\r\n @if (isCellClickFilterable(col, row)) {\r\n <span\r\n data-row-click-ignore=\"true\"\r\n class=\"inline-flex items-center cursor-pointer px-1.5 py-0.5 rounded transition-colors\"\r\n [class.ring-2]=\"isCellFilterActive(row, col)\"\r\n [class.ring-primary-400]=\"\r\n isCellFilterActive(row, col)\r\n \"\r\n [class.hover:underline]=\"\r\n !isCellFilterActive(row, col)\r\n \"\r\n (click)=\"onCellFilterClick($event, row, col)\"\r\n >\r\n {{\r\n getBooleanProperty(row, col.key) ? \"Yes\" : \"No\"\r\n }}\r\n </span>\r\n } @else {\r\n <mt-toggle-field\r\n [disabled]=\"col.readonly\"\r\n [ngModel]=\"getBooleanProperty(row, col.key)\"\r\n (ngModelChange)=\"\r\n onCellChange(row, col.key, $event, 'boolean')\r\n \"\r\n ></mt-toggle-field>\r\n }\r\n }\r\n @case (\"date\") {\r\n {{\r\n getDateProperty(row, col.key) | mtDateFormat: \"date\"\r\n }}\r\n }\r\n @case (\"dateTime\") {\r\n {{\r\n getDateProperty(row, col.key)\r\n | mtDateFormat: \"dateTime\"\r\n }}\r\n }\r\n @case (\"user\") {\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n filterableCell;\r\n context: { row: row, col: col }\r\n \"\r\n ></ng-container>\r\n }\r\n @case (\"status\") {\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n filterableCell;\r\n context: { row: row, col: col }\r\n \"\r\n ></ng-container>\r\n }\r\n @case (\"entity\") {\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n filterableCell;\r\n context: { row: row, col: col }\r\n \"\r\n ></ng-container>\r\n }\r\n @case (\"custom\") {\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n col.customCellTpl;\r\n context: { $implicit: row }\r\n \"\r\n >\r\n </ng-container>\r\n }\r\n @default {\r\n {{ getProperty(row, col.key) }}\r\n }\r\n }\r\n </td>\r\n }\r\n\r\n @if (rowActions().length > 0) {\r\n <td class=\"text-right\">\r\n @if (actionShape() === \"popover\") {\r\n <div class=\"flex items-center justify-end\">\r\n <mt-button\r\n icon=\"general.dots-vertical\"\r\n severity=\"secondary\"\r\n variant=\"text\"\r\n size=\"large\"\r\n (click)=\"rowPopover.toggle($event)\"\r\n data-row-click-ignore=\"true\"\r\n ></mt-button>\r\n <p-popover #rowPopover appendTo=\"body\">\r\n <div class=\"flex flex-col min-w-40\">\r\n @for (\r\n action of getVisibleRowActions(row);\r\n track $index\r\n ) {\r\n <button\r\n class=\"flex items-center gap-2 px-2 cursor-pointer py-2 text-sm rounded transition-colors\"\r\n [class]=\"\r\n action.color === 'danger'\r\n ? 'text-red-600 hover:bg-red-50 dark:hover:bg-red-950'\r\n : 'text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-surface-700'\r\n \"\r\n (click)=\"\r\n rowAction($event, action, row);\r\n rowPopover.hide()\r\n \"\r\n >\r\n @if (action.icon) {\r\n <mt-icon\r\n [icon]=\"action.icon\"\r\n class=\"text-base\"\r\n />\r\n }\r\n <span>{{\r\n action.label || action.tooltip\r\n }}</span>\r\n </button>\r\n }\r\n </div>\r\n </p-popover>\r\n </div>\r\n } @else {\r\n <div class=\"flex items-center justify-end space-x-2\">\r\n @for (action of rowActions(); track $index) {\r\n @let hidden = action.hidden?.(row);\r\n @if (!hidden) {\r\n <mt-button\r\n [icon]=\"action.icon\"\r\n [severity]=\"action.color\"\r\n [variant]=\"action.variant\"\r\n [size]=\"action.size || 'small'\"\r\n (click)=\"rowAction($event, action, row)\"\r\n [tooltip]=\"action.tooltip\"\r\n [label]=\"action.label\"\r\n [loading]=\"resolveActionLoading(action, row)\"\r\n ></mt-button>\r\n }\r\n }\r\n </div>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </ng-template>\r\n <ng-template #filterableCell let-row=\"row\" let-col=\"col\">\r\n @let filterable = isCellClickFilterable(col, row);\r\n @let active = isCellFilterActive(row, col);\r\n @if (filterable) {\r\n <span\r\n data-row-click-ignore=\"true\"\r\n class=\"flex w-full items-center rounded transition-colors cursor-pointer\"\r\n [class.ring-2]=\"active\"\r\n [class.ring-primary-400]=\"active\"\r\n (click)=\"onCellFilterClick($event, row, col)\"\r\n >\r\n @if (resolveCellEntityData(row, col); as entityData) {\r\n <mt-entity-preview\r\n [data]=\"entityData\"\r\n attachmentShape=\"compact\"\r\n ></mt-entity-preview>\r\n } @else {\r\n {{ getProperty(row, col.key) }}\r\n }\r\n </span>\r\n } @else {\r\n @if (resolveCellEntityData(row, col); as entityData) {\r\n <mt-entity-preview\r\n [data]=\"entityData\"\r\n attachmentShape=\"compact\"\r\n ></mt-entity-preview>\r\n } @else {\r\n {{ getProperty(row, col.key) }}\r\n }\r\n }\r\n </ng-template>\r\n <ng-template #groupheader let-row>\r\n @if (grouping.groupingActive()) {\r\n <tr\r\n class=\"mt-group-header\"\r\n [style.--mt-group-accent]=\"\r\n grouping.getGroupAccentColor(row) ??\r\n 'var(--p-primary-color)'\r\n \"\r\n >\r\n <td [attr.colspan]=\"totalColumnSpan()\" class=\"!p-0\">\r\n <div\r\n class=\"flex items-center gap-3 px-4 py-2 bg-surface-50 dark:bg-surface-900 border-y border-surface-200 dark:border-surface-700\"\r\n >\r\n <span\r\n class=\"mt-group-header__accent inline-block w-1 h-5 rounded-full\"\r\n ></span>\r\n <span\r\n class=\"text-xs uppercase tracking-wide text-gray-500 dark:text-gray-400\"\r\n >\r\n {{ grouping.activeGroupColumn()?.label }}\r\n </span>\r\n <span\r\n class=\"text-sm font-semibold text-gray-900 dark:text-gray-100\"\r\n >\r\n {{ grouping.getGroupLabel(row) }}\r\n </span>\r\n <span\r\n class=\"ml-auto inline-flex items-center gap-1 text-xs px-2 py-0.5 rounded-full bg-primary-50 text-primary-700 dark:bg-primary-950 dark:text-primary-300\"\r\n >\r\n {{ grouping.getGroupCount(row) }}\r\n </span>\r\n </div>\r\n </td>\r\n </tr>\r\n }\r\n </ng-template>\r\n <ng-template #emptymessage>\r\n <tr>\r\n <td [attr.colspan]=\"totalColumnSpan()\" class=\"text-center\">\r\n <div\r\n class=\"flex min-h-44 flex-col items-center justify-center gap-3 py-8 text-center\"\r\n >\r\n <svg\r\n width=\"152\"\r\n height=\"120\"\r\n viewBox=\"0 0 152 120\"\r\n fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n >\r\n <circle cx=\"76\" cy=\"52\" r=\"52\" fill=\"#E9EAEB\" />\r\n <g filter=\"url(#filter0_ddd_2474_28277)\">\r\n <path\r\n d=\"M77.6 16C66.8273 16 57.2978 21.3233 51.4987 29.4829C49.605 29.0363 47.6301 28.8 45.6 28.8C31.4615 28.8 20 40.2615 20 54.4C20 68.5385 31.4615 80 45.6 80L109.6 80C121.971 80 132 69.9712 132 57.6C132 45.2288 121.971 35.2 109.6 35.2C108.721 35.2 107.854 35.2506 107.002 35.349C102.098 23.9677 90.7797 16 77.6 16Z\"\r\n fill=\"#FAFAFA\"\r\n />\r\n <ellipse\r\n cx=\"45.6\"\r\n cy=\"54.3998\"\r\n rx=\"25.6\"\r\n ry=\"25.6\"\r\n fill=\"url(#paint0_linear_2474_28277)\"\r\n />\r\n <circle\r\n cx=\"77.6016\"\r\n cy=\"48\"\r\n r=\"32\"\r\n fill=\"url(#paint1_linear_2474_28277)\"\r\n />\r\n <ellipse\r\n cx=\"109.599\"\r\n cy=\"57.6002\"\r\n rx=\"22.4\"\r\n ry=\"22.4\"\r\n fill=\"url(#paint2_linear_2474_28277)\"\r\n />\r\n </g>\r\n <circle cx=\"21\" cy=\"19\" r=\"5\" fill=\"#F5F5F5\" />\r\n <circle cx=\"18\" cy=\"109\" r=\"7\" fill=\"#F5F5F5\" />\r\n <circle cx=\"145\" cy=\"35\" r=\"7\" fill=\"#F5F5F5\" />\r\n <circle cx=\"134\" cy=\"8\" r=\"4\" fill=\"#F5F5F5\" />\r\n <foreignObject x=\"44\" y=\"54\" width=\"64\" height=\"64\">\r\n <div\r\n xmlns=\"http://www.w3.org/1999/xhtml\"\r\n style=\"\r\n backdrop-filter: blur(4px);\r\n clip-path: url(#bgblur_0_2474_28277_clip_path);\r\n height: 100%;\r\n width: 100%;\r\n \"\r\n ></div>\r\n </foreignObject>\r\n <g data-figma-bg-blur-radius=\"8\">\r\n <path\r\n d=\"M52 86C52 72.7452 62.7452 62 76 62C89.2548 62 100 72.7452 100 86C100 99.2548 89.2548 110 76 110C62.7452 110 52 99.2548 52 86Z\"\r\n fill=\"#344054\"\r\n fill-opacity=\"0.4\"\r\n />\r\n <path\r\n d=\"M85 95L81.5001 91.5M84 85.5C84 90.1944 80.1944 94 75.5 94C70.8056 94 67 90.1944 67 85.5C67 80.8056 70.8056 77 75.5 77C80.1944 77 84 80.8056 84 85.5Z\"\r\n stroke=\"white\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </g>\r\n <defs>\r\n <filter\r\n id=\"filter0_ddd_2474_28277\"\r\n x=\"0\"\r\n y=\"16\"\r\n width=\"152\"\r\n height=\"104\"\r\n filterUnits=\"userSpaceOnUse\"\r\n color-interpolation-filters=\"sRGB\"\r\n >\r\n <feFlood\r\n flood-opacity=\"0\"\r\n result=\"BackgroundImageFix\"\r\n />\r\n <feColorMatrix\r\n in=\"SourceAlpha\"\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"\r\n result=\"hardAlpha\"\r\n />\r\n <feMorphology\r\n radius=\"1.5\"\r\n operator=\"erode\"\r\n in=\"SourceAlpha\"\r\n result=\"effect1_dropShadow_2474_28277\"\r\n />\r\n <feOffset dy=\"3\" />\r\n <feGaussianBlur stdDeviation=\"1.5\" />\r\n <feComposite in2=\"hardAlpha\" operator=\"out\" />\r\n <feColorMatrix\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0.0392157 0 0 0 0 0.0496732 0 0 0 0 0.0705882 0 0 0 0.04 0\"\r\n />\r\n <feBlend\r\n mode=\"normal\"\r\n in2=\"BackgroundImageFix\"\r\n result=\"effect1_dropShadow_2474_28277\"\r\n />\r\n <feColorMatrix\r\n in=\"SourceAlpha\"\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"\r\n result=\"hardAlpha\"\r\n />\r\n <feMorphology\r\n radius=\"4\"\r\n operator=\"erode\"\r\n in=\"SourceAlpha\"\r\n result=\"effect2_dropShadow_2474_28277\"\r\n />\r\n <feOffset dy=\"8\" />\r\n <feGaussianBlur stdDeviation=\"4\" />\r\n <feComposite in2=\"hardAlpha\" operator=\"out\" />\r\n <feColorMatrix\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0.0392157 0 0 0 0 0.0496732 0 0 0 0 0.0705882 0 0 0 0.03 0\"\r\n />\r\n <feBlend\r\n mode=\"normal\"\r\n in2=\"effect1_dropShadow_2474_28277\"\r\n result=\"effect2_dropShadow_2474_28277\"\r\n />\r\n <feColorMatrix\r\n in=\"SourceAlpha\"\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"\r\n result=\"hardAlpha\"\r\n />\r\n <feMorphology\r\n radius=\"4\"\r\n operator=\"erode\"\r\n in=\"SourceAlpha\"\r\n result=\"effect3_dropShadow_2474_28277\"\r\n />\r\n <feOffset dy=\"20\" />\r\n <feGaussianBlur stdDeviation=\"12\" />\r\n <feComposite in2=\"hardAlpha\" operator=\"out\" />\r\n <feColorMatrix\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0.0392157 0 0 0 0 0.0496732 0 0 0 0 0.0705882 0 0 0 0.08 0\"\r\n />\r\n <feBlend\r\n mode=\"normal\"\r\n in2=\"effect2_dropShadow_2474_28277\"\r\n result=\"effect3_dropShadow_2474_28277\"\r\n />\r\n <feBlend\r\n mode=\"normal\"\r\n in=\"SourceGraphic\"\r\n in2=\"effect3_dropShadow_2474_28277\"\r\n result=\"shape\"\r\n />\r\n </filter>\r\n <clipPath\r\n id=\"bgblur_0_2474_28277_clip_path\"\r\n transform=\"translate(-44 -54)\"\r\n >\r\n <path\r\n d=\"M52 86C52 72.7452 62.7452 62 76 62C89.2548 62 100 72.7452 100 86C100 99.2548 89.2548 110 76 110C62.7452 110 52 99.2548 52 86Z\"\r\n />\r\n </clipPath>\r\n <linearGradient\r\n id=\"paint0_linear_2474_28277\"\r\n x1=\"25.9429\"\r\n y1=\"37.4855\"\r\n x2=\"71.2\"\r\n y2=\"79.9998\"\r\n gradientUnits=\"userSpaceOnUse\"\r\n >\r\n <stop stop-color=\"#D0D5DD\" />\r\n <stop\r\n offset=\"0.350715\"\r\n stop-color=\"white\"\r\n stop-opacity=\"0\"\r\n />\r\n </linearGradient>\r\n <linearGradient\r\n id=\"paint1_linear_2474_28277\"\r\n x1=\"53.0301\"\r\n y1=\"26.8571\"\r\n x2=\"109.602\"\r\n y2=\"80\"\r\n gradientUnits=\"userSpaceOnUse\"\r\n >\r\n <stop stop-color=\"#D0D5DD\" />\r\n <stop\r\n offset=\"0.350715\"\r\n stop-color=\"white\"\r\n stop-opacity=\"0\"\r\n />\r\n </linearGradient>\r\n <linearGradient\r\n id=\"paint2_linear_2474_28277\"\r\n x1=\"92.3992\"\r\n y1=\"42.8002\"\r\n x2=\"131.999\"\r\n y2=\"80.0002\"\r\n gradientUnits=\"userSpaceOnUse\"\r\n >\r\n <stop stop-color=\"#D0D5DD\" />\r\n <stop\r\n offset=\"0.350715\"\r\n stop-color=\"white\"\r\n stop-opacity=\"0\"\r\n />\r\n </linearGradient>\r\n </defs>\r\n </svg>\r\n <p class=\"m-0 text-base font-medium text-surface-500\">\r\n {{ \"components.table.no-data-found\" | transloco }}\r\n </p>\r\n </div>\r\n </td>\r\n </tr>\r\n </ng-template>\r\n </p-table>\r\n </div>\r\n }\r\n </div>\r\n\r\n <div\r\n class=\"flex flex-col gap-3 pb-3 px-4\"\r\n [class]=\"'items-' + paginatorPosition()\"\r\n >\r\n <mt-paginator\r\n [(rows)]=\"pageSize\"\r\n [(first)]=\"first\"\r\n [(page)]=\"currentPage\"\r\n [totalRecords]=\"totalRecords()\"\r\n [alwaysShow]=\"alwaysShowPaginator()\"\r\n [rowsPerPageOptions]=\"rowsPerPageOptions()\"\r\n (onPageChange)=\"onPaginatorPage($event)\"\r\n ></mt-paginator>\r\n </div>\r\n </div>\r\n</ng-template>\r\n", styles: [":host ::ng-deep .p-datatable-header{padding:0 0 1.5rem;background:transparent;border:0}:host ::ng-deep .p-datatable-table{border-collapse:separate;border-spacing:0}:host ::ng-deep .p-datatable-thead>tr>th{padding:.9rem 1rem;background:#fff;border-bottom:1px solid #ebebf0;color:#323232;font-size:14px;font-weight:400;line-height:20px;white-space:nowrap}:host ::ng-deep .p-datatable-tbody>tr>td{padding:.72rem 1rem;background:#fff;border-bottom:1px solid #ebebf0;color:#4b4b4b;font-size:14px;font-weight:400;line-height:20px;vertical-align:middle}:host ::ng-deep .p-datatable-tbody>tr:last-child>td{border-bottom:0}:host ::ng-deep .p-datatable-thead>tr>th:first-child{border-top-left-radius:.625rem}:host ::ng-deep .p-datatable-thead>tr>th:last-child{border-top-right-radius:.625rem}:host ::ng-deep .p-datatable-tbody>tr:last-child>td:first-child{border-bottom-left-radius:.625rem}:host ::ng-deep .p-datatable-tbody>tr:last-child>td:last-child{border-bottom-right-radius:.625rem}.mt-table-clickable-row>td{transition:background-color .16s ease,color .16s ease,border-color .16s ease}.mt-table-clickable-row:hover>td,.mt-table-clickable-row:focus-within>td{background:#fafafa}.mt-table-clickable-row:hover>td:first-child,.mt-table-clickable-row:focus-within>td:first-child{border-inline-start:none}.mt-table-status-entity-row>td{background:#fff}.mt-table-status-entity-row>td:first-child:before{display:none}:host ::ng-deep tr.mt-group-header>td{padding:0!important;background:transparent}tr.mt-group-header .mt-group-header__accent{background:var(--mt-group-accent, var(--p-primary-color))}\n"], dependencies: [{ kind: "ngmodule", type: TableModule }, { kind: "component", type: i1$3.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: i1$3.ReorderableColumn, selector: "[pReorderableColumn]", inputs: ["pReorderableColumnDisabled"] }, { kind: "directive", type: i1$3.ReorderableRowHandle, selector: "[pReorderableRowHandle]" }, { kind: "directive", type: i1$3.ReorderableRow, selector: "[pReorderableRow]", inputs: ["pReorderableRow", "pReorderableRowDisabled"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ToggleField, selector: "mt-toggle-field", inputs: ["label", "inputId", "labelPosition", "placeholder", "readonly", "pInputs", "required", "toggleShape", "size", "icon", "descriptionCard"], outputs: ["onChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: Button, selector: "mt-button", inputs: ["icon", "label", "tooltip", "class", "type", "styleClass", "severity", "badge", "variant", "badgeSeverity", "size", "iconPos", "autofocus", "fluid", "raised", "rounded", "text", "plain", "outlined", "link", "disabled", "loading", "pInputs"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: Paginator, selector: "mt-paginator", inputs: ["rows", "totalRecords", "first", "page", "rowsPerPageOptions", "showFirstLastIcon", "showCurrentPageReport", "fluid", "pageLinkSize", "alwaysShow"], outputs: ["rowsChange", "firstChange", "pageChange", "onPageChange"] }, { kind: "component", type: CheckboxField, selector: "mt-checkbox-field", inputs: ["label", "labelPosition", "placeholder", "readonly", "pInputs", "required"], outputs: ["onChange"] }, { kind: "ngmodule", type: SkeletonModule }, { kind: "component", type: i3.Skeleton, selector: "p-skeleton", inputs: ["styleClass", "shape", "animation", "borderRadius", "size", "width", "height"] }, { kind: "ngmodule", type: ProgressBarModule }, { kind: "component", type: i4.ProgressBar, selector: "p-progressBar, p-progressbar, p-progress-bar", inputs: ["value", "showValue", "styleClass", "valueStyleClass", "unit", "mode", "color"] }, { kind: "ngmodule", type: TranslocoModule }, { kind: "component", type: TableCaption, selector: "mt-table-caption", inputs: ["generalSearch", "showFilters", "filterMode", "exportable", "printable", "groupable", "columns", "data", "groupColumns", "tabs", "tabsOptionLabel", "tabsOptionValue", "actions", "captionStart", "captionEnd", "activeTab", "filters", "filterTerm", "groupBy"], outputs: ["activeTabChange", "filtersChange", "filterTermChange", "groupByChange", "exportRequested", "printRequested", "onTabChange", "searchChange", "filterApplied", "filterReset"] }, { kind: "component", type: TableColumnFilter, selector: "mt-table-column-filter", inputs: ["column", "value"], outputs: ["filterChange"] }, { kind: "component", type: EntityPreview, selector: "mt-entity-preview", inputs: ["data", "attachmentShape"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i1$2.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "component", type: Icon, selector: "mt-icon", inputs: ["icon"] }, { kind: "component", type: Card, selector: "mt-card", inputs: ["class", "title", "paddingless"] }, { kind: "pipe", type: i2.TranslocoPipe, name: "transloco" }, { kind: "pipe", type: MTDateFormatPipe, name: "mtDateFormat" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1420
2240
  }
1421
2241
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: Table, decorators: [{
1422
2242
  type: Component,
1423
- args: [{ selector: 'mt-table', standalone: true, imports: [
2243
+ args: [{ selector: 'mt-table', standalone: true, providers: [MTDateFormatPipe], imports: [
1424
2244
  TableModule,
1425
2245
  NgTemplateOutlet,
1426
2246
  ToggleField,
1427
2247
  FormsModule,
1428
2248
  Button,
1429
- TextField,
1430
2249
  Paginator,
1431
2250
  CheckboxField,
1432
- Tabs,
1433
2251
  SkeletonModule,
1434
2252
  ProgressBarModule,
1435
2253
  TranslocoModule,
1436
- TableFilter,
2254
+ TableCaption,
2255
+ TableColumnFilter,
1437
2256
  EntityPreview,
1438
2257
  PopoverModule,
1439
2258
  Icon,
1440
2259
  Card,
1441
2260
  MTDateFormatPipe,
1442
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (!noCard()) {\r\n <mt-card>\r\n <ng-container *ngTemplateOutlet=\"tableContent\" />\r\n </mt-card>\r\n} @else {\r\n <ng-container *ngTemplateOutlet=\"tableContent\" />\r\n}\r\n\r\n<ng-template #tableContent>\r\n <div class=\"space-y-4 rounded-lg\">\r\n <div>\r\n @if (\r\n captionStartContent() ||\r\n captionEndContent() ||\r\n generalSearch() ||\r\n showFilters() ||\r\n tabs()?.length > 0 ||\r\n actions()?.length > 0\r\n ) {\r\n <div class=\"p-datatable-header rounded-t-2xl\">\r\n <div\r\n class=\"flex relative\"\r\n [class]=\"!generalSearch() ? 'justify-end' : 'justify-between'\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n <ng-container\r\n *ngTemplateOutlet=\"captionStartContent()\"\r\n ></ng-container>\r\n @if (tabs()) {\r\n <mt-tabs\r\n [(active)]=\"activeTab\"\r\n [options]=\"tabs()\"\r\n [optionLabel]=\"tabsOptionLabel()\"\r\n [optionValue]=\"tabsOptionValue()\"\r\n (onChange)=\"tabChanged($event)\"\r\n size=\"large\"\r\n ></mt-tabs>\r\n }\r\n @if (generalSearch()) {\r\n <mt-text-field\r\n [(ngModel)]=\"filterTerm\"\r\n (ngModelChange)=\"onSearchChange($event)\"\r\n icon=\"general.search-lg\"\r\n [placeholder]=\"'components.table.search' | transloco\"\r\n ></mt-text-field>\r\n }\r\n </div>\r\n <div class=\"flex items-center gap-2\">\r\n @if (showFilters()) {\r\n <mt-table-filter\r\n [columns]=\"columns()\"\r\n [data]=\"data()\"\r\n [ngModel]=\"filters()\"\r\n (filterApplied)=\"onFilterApplied($event)\"\r\n (filterReset)=\"onFilterReset()\"\r\n />\r\n }\r\n @if (exportable()) {\r\n <mt-button\r\n icon=\"file.file-x-03\"\r\n styleClass=\"text-xl! py-1.5!\"\r\n severity=\"success\"\r\n variant=\"outlined\"\r\n [tooltip]=\"'components.table.export' | transloco\"\r\n (click)=\"exportExcel()\"\r\n />\r\n }\r\n @if (actions()?.length > 0) {\r\n <div class=\"flex items-center space-x-2\">\r\n @for (action of actions(); track action.label) {\r\n <mt-button\r\n [icon]=\"action.icon\"\r\n [severity]=\"action.color\"\r\n [variant]=\"action.variant\"\r\n [size]=\"action.size\"\r\n (click)=\"action.action(row)\"\r\n [label]=\"action.label\"\r\n [tooltip]=\"action.tooltip\"\r\n ></mt-button>\r\n }\r\n </div>\r\n }\r\n <ng-container\r\n *ngTemplateOutlet=\"captionEndContent()\"\r\n ></ng-container>\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n @if (!loading() && emptyContent() && data().length === 0) {\r\n <div\r\n class=\"p-4 bg-content rounded-md text-center text-gray-600 dark:text-gray-300\"\r\n >\r\n <ng-container *ngTemplateOutlet=\"emptyContent()\"></ng-container>\r\n </div>\r\n } @else {\r\n <div\r\n class=\"overflow-x-auto rounded-[10px] border border-surface-200 bg-white\"\r\n >\r\n <p-table\r\n [value]=\"displayData()\"\r\n [columns]=\"renderedColumns()\"\r\n [size]=\"size()\"\r\n [showGridlines]=\"showGridlines()\"\r\n [stripedRows]=\"stripedRows()\"\r\n [lazy]=\"lazy()\"\r\n [totalRecords]=\"totalRecords()\"\r\n [reorderableColumns]=\"reorderableColumns()\"\r\n [reorderableRows]=\"reorderableRows()\"\r\n [dataKey]=\"dataKey()\"\r\n [first]=\"first()\"\r\n [rows]=\"pageSize()\"\r\n [exportFilename]=\"exportFilename()\"\r\n (onPage)=\"onTablePage($event)\"\r\n (onLazyLoad)=\"handleLazyLoad($event)\"\r\n (onColReorder)=\"onColumnReorder($event)\"\r\n (onRowReorder)=\"onRowReorder($event)\"\r\n paginator\r\n paginatorStyleClass=\"hidden!\"\r\n class=\"mt-table min-w-full align-middle text-sm\"\r\n [class.table-auto]=\"tableLayout() === 'auto'\"\r\n [class.table-fixed]=\"tableLayout() === 'fixed'\"\r\n >\r\n <ng-template\r\n #header\r\n let-columns\r\n class=\"bg-surface-50 dark:bg-surface-950 border-b border-surface-300 dark:border-surface-500\"\r\n >\r\n <tr>\r\n @if (reorderableRows()) {\r\n <th class=\"w-10\"></th>\r\n }\r\n @if (selectableRows()) {\r\n <th class=\"w-12 text-start\">\r\n <mt-checkbox-field\r\n [ngModel]=\"allSelectedOnPage()\"\r\n (ngModelChange)=\"toggleAllRowsOnPage()\"\r\n ></mt-checkbox-field>\r\n </th>\r\n }\r\n\r\n @for (col of columns; track col.key || col.label || $index) {\r\n @if (reorderableColumns()) {\r\n <th\r\n pReorderableColumn\r\n class=\"text-start text-sm font-normal text-[#323232]\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n {{ col.label }}\r\n <!-- <mt-icon-->\r\n <!-- icon=\"general.menu-05\"-->\r\n <!-- class=\"text-xs text-gray-400\"-->\r\n <!-- ></mt-icon>-->\r\n <mt-button\r\n styleClass=\"cursor-move!\"\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n icon=\"general.menu-05\"\r\n ></mt-button>\r\n </div>\r\n </th>\r\n } @else {\r\n <th\r\n class=\"text-start text-sm font-normal text-[#323232]\"\r\n [style.width]=\"col.width ?? null\"\r\n [style.minWidth]=\"getColumnMinWidth(col)\"\r\n >\r\n @if (isColumnSortable(col)) {\r\n <button\r\n type=\"button\"\r\n class=\"inline-flex items-center gap-2 cursor-pointer\"\r\n (click)=\"toggleSort(col)\"\r\n >\r\n <span>{{ col.label }}</span>\r\n <mt-icon\r\n [icon]=\"getSortIcon(col)\"\r\n class=\"text-xs text-gray-400\"\r\n />\r\n </button>\r\n } @else {\r\n {{ col.label }}\r\n }\r\n </th>\r\n }\r\n }\r\n\r\n @if (rowActions().length > 0) {\r\n <th class=\"text-end! text-sm font-normal text-[#323232]\">\r\n {{ \"components.table.actions\" | transloco }}\r\n </th>\r\n }\r\n </tr>\r\n @if (updating()) {\r\n <tr>\r\n <th\r\n [attr.colspan]=\"\r\n columns.length +\r\n (reorderableRows() ? 1 : 0) +\r\n (selectableRows() ? 1 : 0) +\r\n (rowActions().length > 0 ? 1 : 0)\r\n \"\r\n class=\"!p-0\"\r\n >\r\n <p-progressBar\r\n mode=\"indeterminate\"\r\n [style]=\"{ height: '4px' }\"\r\n />\r\n </th>\r\n </tr>\r\n }\r\n </ng-template>\r\n <ng-template\r\n #body\r\n let-row\r\n let-columns=\"columns\"\r\n let-index=\"rowIndex\"\r\n class=\"divide-y divide-gray-200\"\r\n >\r\n @if (loading()) {\r\n <tr>\r\n @if (reorderableRows()) {\r\n <td><p-skeleton /></td>\r\n }\r\n @if (selectableRows()) {\r\n <td><p-skeleton /></td>\r\n }\r\n @for (col of columns; track col.key || col.label || $index) {\r\n <td><p-skeleton /></td>\r\n }\r\n @if (rowActions().length > 0) {\r\n <td><p-skeleton /></td>\r\n }\r\n </tr>\r\n } @else {\r\n <tr\r\n class=\"border-surface-300 transition-colors duration-150 dark:border-surface-500\"\r\n [class.mt-table-clickable-row]=\"clickableRows()\"\r\n [class.mt-table-status-entity-row]=\"\r\n getStatusEntityAccentColor(row)\r\n \"\r\n [style.--mt-table-status-accent]=\"\r\n getStatusEntityAccentColor(row)\r\n \"\r\n [class.cursor-pointer]=\"clickableRows()\"\r\n [pReorderableRow]=\"index\"\r\n (click)=\"onRowClick($event, row)\"\r\n >\r\n @if (reorderableRows()) {\r\n <td class=\"w-10 text-center\">\r\n <mt-button\r\n styleClass=\"cursor-move!\"\r\n pReorderableRowHandle\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n icon=\"general.menu-05\"\r\n ></mt-button>\r\n <!-- <mt-icon-->\r\n <!-- icon=\"general.menu-05\"-->\r\n <!-- class=\"cursor-move text-gray-500\"-->\r\n <!-- pReorderableRowHandle-->\r\n <!-- ></mt-icon>-->\r\n </td>\r\n }\r\n @if (selectableRows()) {\r\n <td class=\"w-12\">\r\n <mt-checkbox-field\r\n [ngModel]=\"isRowSelected(row)\"\r\n (ngModelChange)=\"toggleRow(row)\"\r\n ></mt-checkbox-field>\r\n </td>\r\n }\r\n\r\n @for (col of columns; track col.key || col.label || $index) {\r\n <td\r\n class=\"text-sm font-normal text-[#4b4b4b]\"\r\n [style.width]=\"col.width ?? null\"\r\n [style.minWidth]=\"getColumnMinWidth(col)\"\r\n >\r\n @switch (col.type) {\r\n @case (\"boolean\") {\r\n <mt-toggle-field\r\n disabled=\"col.readonly\"\r\n [ngModel]=\"getBooleanProperty(row, col.key)\"\r\n (ngModelChange)=\"\r\n onCellChange(row, col.key, $event, 'boolean')\r\n \"\r\n ></mt-toggle-field>\r\n }\r\n @case (\"date\") {\r\n {{\r\n getDateProperty(row, col.key) | mtDateFormat: \"date\"\r\n }}\r\n }\r\n @case (\"dateTime\") {\r\n {{\r\n getDateProperty(row, col.key)\r\n | mtDateFormat: \"dateTime\"\r\n }}\r\n }\r\n @case (\"user\") {\r\n @if (getEntityPreviewData(row, col); as entityData) {\r\n <mt-entity-preview\r\n [data]=\"entityData\"\r\n attachmentShape=\"compact\"\r\n ></mt-entity-preview>\r\n } @else {\r\n {{ getProperty(row, col.key) }}\r\n }\r\n }\r\n @case (\"status\") {\r\n @if (getEntityPreviewData(row, col); as entityData) {\r\n <mt-entity-preview\r\n [data]=\"entityData\"\r\n attachmentShape=\"compact\"\r\n ></mt-entity-preview>\r\n } @else {\r\n {{ getProperty(row, col.key) }}\r\n }\r\n }\r\n @case (\"entity\") {\r\n @if (getEntityColumnData(row, col); as entityData) {\r\n <mt-entity-preview\r\n [data]=\"entityData\"\r\n attachmentShape=\"compact\"\r\n ></mt-entity-preview>\r\n } @else {\r\n {{ getProperty(row, col.key) }}\r\n }\r\n }\r\n @case (\"custom\") {\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n col.customCellTpl;\r\n context: { $implicit: row }\r\n \"\r\n >\r\n </ng-container>\r\n }\r\n @default {\r\n {{ getProperty(row, col.key) }}\r\n }\r\n }\r\n </td>\r\n }\r\n\r\n @if (rowActions().length > 0) {\r\n <td class=\"text-right\">\r\n @if (actionShape() === \"popover\") {\r\n <div class=\"flex items-center justify-end\">\r\n <mt-button\r\n icon=\"general.dots-vertical\"\r\n severity=\"secondary\"\r\n variant=\"text\"\r\n size=\"large\"\r\n (click)=\"rowPopover.toggle($event)\"\r\n data-row-click-ignore=\"true\"\r\n ></mt-button>\r\n <p-popover #rowPopover appendTo=\"body\">\r\n <div class=\"flex flex-col min-w-40\">\r\n @for (\r\n action of getVisibleRowActions(row);\r\n track $index\r\n ) {\r\n <button\r\n class=\"flex items-center gap-2 px-2 cursor-pointer py-2 text-sm rounded transition-colors\"\r\n [class]=\"\r\n action.color === 'danger'\r\n ? 'text-red-600 hover:bg-red-50 dark:hover:bg-red-950'\r\n : 'text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-surface-700'\r\n \"\r\n (click)=\"\r\n rowAction($event, action, row);\r\n rowPopover.hide()\r\n \"\r\n >\r\n @if (action.icon) {\r\n <mt-icon\r\n [icon]=\"action.icon\"\r\n class=\"text-base\"\r\n />\r\n }\r\n <span>{{\r\n action.label || action.tooltip\r\n }}</span>\r\n </button>\r\n }\r\n </div>\r\n </p-popover>\r\n </div>\r\n } @else {\r\n <div class=\"flex items-center justify-end space-x-2\">\r\n @for (action of rowActions(); track $index) {\r\n @let hidden = action.hidden?.(row);\r\n @if (!hidden) {\r\n <mt-button\r\n [icon]=\"action.icon\"\r\n [severity]=\"action.color\"\r\n [variant]=\"action.variant\"\r\n [size]=\"action.size || 'small'\"\r\n (click)=\"rowAction($event, action, row)\"\r\n [tooltip]=\"action.tooltip\"\r\n [label]=\"action.label\"\r\n [loading]=\"resolveActionLoading(action, row)\"\r\n ></mt-button>\r\n }\r\n }\r\n </div>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </ng-template>\r\n <ng-template #emptymessage>\r\n <tr>\r\n <td\r\n [attr.colspan]=\"\r\n renderedColumns().length +\r\n (reorderableRows() ? 1 : 0) +\r\n (selectableRows() ? 1 : 0) +\r\n (rowActions().length > 0 ? 1 : 0)\r\n \"\r\n class=\"text-center\"\r\n >\r\n <div\r\n class=\"flex min-h-44 flex-col items-center justify-center gap-3 py-8 text-center\"\r\n >\r\n <svg\r\n width=\"152\"\r\n height=\"120\"\r\n viewBox=\"0 0 152 120\"\r\n fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n >\r\n <circle cx=\"76\" cy=\"52\" r=\"52\" fill=\"#E9EAEB\" />\r\n <g filter=\"url(#filter0_ddd_2474_28277)\">\r\n <path\r\n d=\"M77.6 16C66.8273 16 57.2978 21.3233 51.4987 29.4829C49.605 29.0363 47.6301 28.8 45.6 28.8C31.4615 28.8 20 40.2615 20 54.4C20 68.5385 31.4615 80 45.6 80L109.6 80C121.971 80 132 69.9712 132 57.6C132 45.2288 121.971 35.2 109.6 35.2C108.721 35.2 107.854 35.2506 107.002 35.349C102.098 23.9677 90.7797 16 77.6 16Z\"\r\n fill=\"#FAFAFA\"\r\n />\r\n <ellipse\r\n cx=\"45.6\"\r\n cy=\"54.3998\"\r\n rx=\"25.6\"\r\n ry=\"25.6\"\r\n fill=\"url(#paint0_linear_2474_28277)\"\r\n />\r\n <circle\r\n cx=\"77.6016\"\r\n cy=\"48\"\r\n r=\"32\"\r\n fill=\"url(#paint1_linear_2474_28277)\"\r\n />\r\n <ellipse\r\n cx=\"109.599\"\r\n cy=\"57.6002\"\r\n rx=\"22.4\"\r\n ry=\"22.4\"\r\n fill=\"url(#paint2_linear_2474_28277)\"\r\n />\r\n </g>\r\n <circle cx=\"21\" cy=\"19\" r=\"5\" fill=\"#F5F5F5\" />\r\n <circle cx=\"18\" cy=\"109\" r=\"7\" fill=\"#F5F5F5\" />\r\n <circle cx=\"145\" cy=\"35\" r=\"7\" fill=\"#F5F5F5\" />\r\n <circle cx=\"134\" cy=\"8\" r=\"4\" fill=\"#F5F5F5\" />\r\n <foreignObject x=\"44\" y=\"54\" width=\"64\" height=\"64\">\r\n <div\r\n xmlns=\"http://www.w3.org/1999/xhtml\"\r\n style=\"\r\n backdrop-filter: blur(4px);\r\n clip-path: url(#bgblur_0_2474_28277_clip_path);\r\n height: 100%;\r\n width: 100%;\r\n \"\r\n ></div>\r\n </foreignObject>\r\n <g data-figma-bg-blur-radius=\"8\">\r\n <path\r\n d=\"M52 86C52 72.7452 62.7452 62 76 62C89.2548 62 100 72.7452 100 86C100 99.2548 89.2548 110 76 110C62.7452 110 52 99.2548 52 86Z\"\r\n fill=\"#344054\"\r\n fill-opacity=\"0.4\"\r\n />\r\n <path\r\n d=\"M85 95L81.5001 91.5M84 85.5C84 90.1944 80.1944 94 75.5 94C70.8056 94 67 90.1944 67 85.5C67 80.8056 70.8056 77 75.5 77C80.1944 77 84 80.8056 84 85.5Z\"\r\n stroke=\"white\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </g>\r\n <defs>\r\n <filter\r\n id=\"filter0_ddd_2474_28277\"\r\n x=\"0\"\r\n y=\"16\"\r\n width=\"152\"\r\n height=\"104\"\r\n filterUnits=\"userSpaceOnUse\"\r\n color-interpolation-filters=\"sRGB\"\r\n >\r\n <feFlood\r\n flood-opacity=\"0\"\r\n result=\"BackgroundImageFix\"\r\n />\r\n <feColorMatrix\r\n in=\"SourceAlpha\"\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"\r\n result=\"hardAlpha\"\r\n />\r\n <feMorphology\r\n radius=\"1.5\"\r\n operator=\"erode\"\r\n in=\"SourceAlpha\"\r\n result=\"effect1_dropShadow_2474_28277\"\r\n />\r\n <feOffset dy=\"3\" />\r\n <feGaussianBlur stdDeviation=\"1.5\" />\r\n <feComposite in2=\"hardAlpha\" operator=\"out\" />\r\n <feColorMatrix\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0.0392157 0 0 0 0 0.0496732 0 0 0 0 0.0705882 0 0 0 0.04 0\"\r\n />\r\n <feBlend\r\n mode=\"normal\"\r\n in2=\"BackgroundImageFix\"\r\n result=\"effect1_dropShadow_2474_28277\"\r\n />\r\n <feColorMatrix\r\n in=\"SourceAlpha\"\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"\r\n result=\"hardAlpha\"\r\n />\r\n <feMorphology\r\n radius=\"4\"\r\n operator=\"erode\"\r\n in=\"SourceAlpha\"\r\n result=\"effect2_dropShadow_2474_28277\"\r\n />\r\n <feOffset dy=\"8\" />\r\n <feGaussianBlur stdDeviation=\"4\" />\r\n <feComposite in2=\"hardAlpha\" operator=\"out\" />\r\n <feColorMatrix\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0.0392157 0 0 0 0 0.0496732 0 0 0 0 0.0705882 0 0 0 0.03 0\"\r\n />\r\n <feBlend\r\n mode=\"normal\"\r\n in2=\"effect1_dropShadow_2474_28277\"\r\n result=\"effect2_dropShadow_2474_28277\"\r\n />\r\n <feColorMatrix\r\n in=\"SourceAlpha\"\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"\r\n result=\"hardAlpha\"\r\n />\r\n <feMorphology\r\n radius=\"4\"\r\n operator=\"erode\"\r\n in=\"SourceAlpha\"\r\n result=\"effect3_dropShadow_2474_28277\"\r\n />\r\n <feOffset dy=\"20\" />\r\n <feGaussianBlur stdDeviation=\"12\" />\r\n <feComposite in2=\"hardAlpha\" operator=\"out\" />\r\n <feColorMatrix\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0.0392157 0 0 0 0 0.0496732 0 0 0 0 0.0705882 0 0 0 0.08 0\"\r\n />\r\n <feBlend\r\n mode=\"normal\"\r\n in2=\"effect2_dropShadow_2474_28277\"\r\n result=\"effect3_dropShadow_2474_28277\"\r\n />\r\n <feBlend\r\n mode=\"normal\"\r\n in=\"SourceGraphic\"\r\n in2=\"effect3_dropShadow_2474_28277\"\r\n result=\"shape\"\r\n />\r\n </filter>\r\n <clipPath\r\n id=\"bgblur_0_2474_28277_clip_path\"\r\n transform=\"translate(-44 -54)\"\r\n >\r\n <path\r\n d=\"M52 86C52 72.7452 62.7452 62 76 62C89.2548 62 100 72.7452 100 86C100 99.2548 89.2548 110 76 110C62.7452 110 52 99.2548 52 86Z\"\r\n />\r\n </clipPath>\r\n <linearGradient\r\n id=\"paint0_linear_2474_28277\"\r\n x1=\"25.9429\"\r\n y1=\"37.4855\"\r\n x2=\"71.2\"\r\n y2=\"79.9998\"\r\n gradientUnits=\"userSpaceOnUse\"\r\n >\r\n <stop stop-color=\"#D0D5DD\" />\r\n <stop\r\n offset=\"0.350715\"\r\n stop-color=\"white\"\r\n stop-opacity=\"0\"\r\n />\r\n </linearGradient>\r\n <linearGradient\r\n id=\"paint1_linear_2474_28277\"\r\n x1=\"53.0301\"\r\n y1=\"26.8571\"\r\n x2=\"109.602\"\r\n y2=\"80\"\r\n gradientUnits=\"userSpaceOnUse\"\r\n >\r\n <stop stop-color=\"#D0D5DD\" />\r\n <stop\r\n offset=\"0.350715\"\r\n stop-color=\"white\"\r\n stop-opacity=\"0\"\r\n />\r\n </linearGradient>\r\n <linearGradient\r\n id=\"paint2_linear_2474_28277\"\r\n x1=\"92.3992\"\r\n y1=\"42.8002\"\r\n x2=\"131.999\"\r\n y2=\"80.0002\"\r\n gradientUnits=\"userSpaceOnUse\"\r\n >\r\n <stop stop-color=\"#D0D5DD\" />\r\n <stop\r\n offset=\"0.350715\"\r\n stop-color=\"white\"\r\n stop-opacity=\"0\"\r\n />\r\n </linearGradient>\r\n </defs>\r\n </svg>\r\n <p class=\"m-0 text-base font-medium text-surface-500\">\r\n {{ \"components.table.no-data-found\" | transloco }}\r\n </p>\r\n </div>\r\n </td>\r\n </tr>\r\n </ng-template>\r\n </p-table>\r\n </div>\r\n }\r\n </div>\r\n\r\n <div\r\n class=\"flex flex-col gap-3 pb-3 px-4\"\r\n [class]=\"'items-' + paginatorPosition()\"\r\n >\r\n <mt-paginator\r\n [(rows)]=\"pageSize\"\r\n [(first)]=\"first\"\r\n [(page)]=\"currentPage\"\r\n [totalRecords]=\"totalRecords()\"\r\n [alwaysShow]=\"alwaysShowPaginator()\"\r\n [rowsPerPageOptions]=\"rowsPerPageOptions()\"\r\n (onPageChange)=\"onPaginatorPage($event)\"\r\n ></mt-paginator>\r\n </div>\r\n </div>\r\n</ng-template>\r\n", styles: [":host ::ng-deep .p-datatable-header{padding:0 0 1.5rem;background:transparent;border:0}:host ::ng-deep .p-datatable-table{border-collapse:separate;border-spacing:0}:host ::ng-deep .p-datatable-thead>tr>th{padding:.9rem 1rem;background:#fff;border-bottom:1px solid #ebebf0;color:#323232;font-size:14px;font-weight:400;line-height:20px;white-space:nowrap}:host ::ng-deep .p-datatable-tbody>tr>td{padding:.72rem 1rem;background:#fff;border-bottom:1px solid #ebebf0;color:#4b4b4b;font-size:14px;font-weight:400;line-height:20px;vertical-align:middle}:host ::ng-deep .p-datatable-tbody>tr:last-child>td{border-bottom:0}:host ::ng-deep .p-datatable-thead>tr>th:first-child{border-top-left-radius:.625rem}:host ::ng-deep .p-datatable-thead>tr>th:last-child{border-top-right-radius:.625rem}:host ::ng-deep .p-datatable-tbody>tr:last-child>td:first-child{border-bottom-left-radius:.625rem}:host ::ng-deep .p-datatable-tbody>tr:last-child>td:last-child{border-bottom-right-radius:.625rem}.mt-table-clickable-row>td{transition:background-color .16s ease,color .16s ease,border-color .16s ease}.mt-table-clickable-row:hover>td,.mt-table-clickable-row:focus-within>td{background:#fafafa}.mt-table-clickable-row:hover>td:first-child,.mt-table-clickable-row:focus-within>td:first-child{border-inline-start:none}.mt-table-status-entity-row>td{background:#fff}.mt-table-status-entity-row>td:first-child:before{display:none}\n"] }]
1443
- }], ctorParameters: () => [], propDecorators: { selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], cellChange: [{ type: i0.Output, args: ["cellChange"] }], lazyLoad: [{ type: i0.Output, args: ["lazyLoad"] }], columnReorder: [{ type: i0.Output, args: ["columnReorder"] }], rowReorder: [{ type: i0.Output, args: ["rowReorder"] }], rowClick: [{ type: i0.Output, args: ["rowClick"] }], filters: [{ type: i0.Input, args: [{ isSignal: true, alias: "filters", required: false }] }, { type: i0.Output, args: ["filtersChange"] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], rowActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowActions", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], showGridlines: [{ type: i0.Input, args: [{ isSignal: true, alias: "showGridlines", required: false }] }], stripedRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "stripedRows", required: false }] }], selectableRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectableRows", required: false }] }], clickableRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "clickableRows", required: false }] }], generalSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "generalSearch", required: false }] }], lazyLocalSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "lazyLocalSearch", required: false }] }], showFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFilters", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], updating: [{ type: i0.Input, args: [{ isSignal: true, alias: "updating", required: false }] }], lazy: [{ type: i0.Input, args: [{ isSignal: true, alias: "lazy", required: false }] }], lazyLocalSort: [{ type: i0.Input, args: [{ isSignal: true, alias: "lazyLocalSort", required: false }] }], lazyTotalRecords: [{ type: i0.Input, args: [{ isSignal: true, alias: "lazyTotalRecords", required: false }] }], reorderableColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "reorderableColumns", required: false }] }], reorderableRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "reorderableRows", required: false }] }], dataKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataKey", required: false }] }], storageKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "storageKey", required: false }] }], storageMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "storageMode", required: false }] }], exportable: [{ type: i0.Input, args: [{ isSignal: true, alias: "exportable", required: false }] }], exportFilename: [{ type: i0.Input, args: [{ isSignal: true, alias: "exportFilename", required: false }] }], actionShape: [{ type: i0.Input, args: [{ isSignal: true, alias: "actionShape", required: false }] }], tableLayout: [{ type: i0.Input, args: [{ isSignal: true, alias: "tableLayout", required: false }] }], noCard: [{ type: i0.Input, args: [{ isSignal: true, alias: "noCard", required: false }] }], tabs: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabs", required: false }] }], tabsOptionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabsOptionLabel", required: false }] }], tabsOptionValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabsOptionValue", required: false }] }], activeTab: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeTab", required: false }] }, { type: i0.Output, args: ["activeTabChange"] }], onTabChange: [{ type: i0.Output, args: ["onTabChange"] }], actions: [{ type: i0.Input, args: [{ isSignal: true, alias: "actions", required: false }] }], captionStartContent: [{ type: i0.ContentChild, args: ['captionStart', { isSignal: true }] }], captionEndContent: [{ type: i0.ContentChild, args: ['captionEnd', { isSignal: true }] }], emptyContent: [{ type: i0.ContentChild, args: ['empty', { isSignal: true }] }], paginatorPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "paginatorPosition", required: false }] }], alwaysShowPaginator: [{ type: i0.Input, args: [{ isSignal: true, alias: "alwaysShowPaginator", required: false }] }], rowsPerPageOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowsPerPageOptions", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }, { type: i0.Output, args: ["pageSizeChange"] }], currentPage: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentPage", required: false }] }, { type: i0.Output, args: ["currentPageChange"] }], first: [{ type: i0.Input, args: [{ isSignal: true, alias: "first", required: false }] }, { type: i0.Output, args: ["firstChange"] }], filterTerm: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterTerm", required: false }] }, { type: i0.Output, args: ["filterTermChange"] }] } });
2261
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (!noCard()) {\r\n <mt-card>\r\n <ng-container *ngTemplateOutlet=\"tableContent\" />\r\n </mt-card>\r\n} @else {\r\n <ng-container *ngTemplateOutlet=\"tableContent\" />\r\n}\r\n\r\n<ng-template #tableContent>\r\n <div class=\"space-y-4 rounded-lg\">\r\n <div>\r\n <mt-table-caption\r\n [generalSearch]=\"generalSearch()\"\r\n [showFilters]=\"showFilters()\"\r\n [filterMode]=\"filterMode()\"\r\n [exportable]=\"exportable()\"\r\n [printable]=\"printable()\"\r\n [groupable]=\"groupable()\"\r\n [columns]=\"columns()\"\r\n [data]=\"data()\"\r\n [groupColumns]=\"grouping.groupableColumns()\"\r\n [tabs]=\"tabs()\"\r\n [tabsOptionLabel]=\"tabsOptionLabel()\"\r\n [tabsOptionValue]=\"tabsOptionValue()\"\r\n [actions]=\"actions()\"\r\n [captionStart]=\"captionStartContent() ?? null\"\r\n [captionEnd]=\"captionEndContent() ?? null\"\r\n [(activeTab)]=\"activeTab\"\r\n [(filters)]=\"filters\"\r\n [(filterTerm)]=\"filterTerm\"\r\n [(groupBy)]=\"groupBy\"\r\n (exportRequested)=\"exportExcel()\"\r\n (printRequested)=\"printPdf()\"\r\n (onTabChange)=\"tabChanged($event)\"\r\n (searchChange)=\"onSearchChange($event)\"\r\n (filterApplied)=\"onFilterApplied($event)\"\r\n (filterReset)=\"onFilterReset()\"\r\n />\r\n\r\n @if (!loading() && emptyContent() && data().length === 0) {\r\n <div\r\n class=\"p-4 bg-content rounded-md text-center text-gray-600 dark:text-gray-300\"\r\n >\r\n <ng-container *ngTemplateOutlet=\"emptyContent()\"></ng-container>\r\n </div>\r\n } @else {\r\n <div\r\n class=\"overflow-x-auto rounded-[10px] border border-surface-200 bg-white\"\r\n >\r\n <p-table\r\n [value]=\"displayData()\"\r\n [columns]=\"renderedColumns()\"\r\n [size]=\"size()\"\r\n [showGridlines]=\"showGridlines()\"\r\n [stripedRows]=\"stripedRows()\"\r\n [lazy]=\"lazy()\"\r\n [totalRecords]=\"totalRecords()\"\r\n [reorderableColumns]=\"reorderableColumns()\"\r\n [reorderableRows]=\"reorderableRows()\"\r\n [dataKey]=\"dataKey()\"\r\n [first]=\"first()\"\r\n [rows]=\"pageSize()\"\r\n [exportFilename]=\"exportFilename()\"\r\n [rowGroupMode]=\"grouping.groupingActive() ? 'subheader' : null\"\r\n [groupRowsBy]=\"grouping.activeGroupColumn()?.key ?? null\"\r\n [sortField]=\"sortField()\"\r\n [sortOrder]=\"sortDirection() === 'desc' ? -1 : 1\"\r\n (onPage)=\"onTablePage($event)\"\r\n (onLazyLoad)=\"handleLazyLoad($event)\"\r\n (onColReorder)=\"onColumnReorder($event)\"\r\n (onRowReorder)=\"onRowReorder($event)\"\r\n paginator\r\n paginatorStyleClass=\"hidden!\"\r\n class=\"mt-table min-w-full align-middle text-sm\"\r\n [class.table-auto]=\"tableLayout() === 'auto'\"\r\n [class.table-fixed]=\"tableLayout() === 'fixed'\"\r\n >\r\n <ng-template\r\n #header\r\n let-columns\r\n class=\"bg-surface-50 dark:bg-surface-950 border-b border-surface-300 dark:border-surface-500\"\r\n >\r\n <tr>\r\n @if (reorderableRows()) {\r\n <th class=\"w-10\"></th>\r\n }\r\n @if (selectableRows()) {\r\n <th class=\"w-12 text-start\">\r\n <mt-checkbox-field\r\n [ngModel]=\"allSelectedOnPage()\"\r\n (ngModelChange)=\"toggleAllRowsOnPage()\"\r\n ></mt-checkbox-field>\r\n </th>\r\n }\r\n\r\n @for (col of columns; track col.key || col.label || $index) {\r\n @if (reorderableColumns()) {\r\n <th\r\n pReorderableColumn\r\n class=\"text-start text-sm font-normal text-[#323232]\"\r\n >\r\n <div class=\"flex items-center gap-2\">\r\n {{ col.label }}\r\n @if (\r\n isColumnFilterMode() && getFilterableColumn(col.key);\r\n as filterableCol\r\n ) {\r\n <mt-table-column-filter\r\n [column]=\"filterableCol\"\r\n [value]=\"filters()[col.key]\"\r\n (filterChange)=\"\r\n onColumnFilterChange(col.key, $event)\r\n \"\r\n />\r\n }\r\n <mt-button\r\n styleClass=\"cursor-move!\"\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n icon=\"general.menu-05\"\r\n ></mt-button>\r\n </div>\r\n </th>\r\n } @else {\r\n <th\r\n class=\"text-start text-sm font-normal text-[#323232]\"\r\n [style.width]=\"col.width ?? null\"\r\n [style.minWidth]=\"getColumnMinWidth(col)\"\r\n >\r\n <div class=\"inline-flex items-center gap-1\">\r\n @if (isColumnSortable(col)) {\r\n <button\r\n type=\"button\"\r\n class=\"inline-flex items-center gap-2 cursor-pointer\"\r\n (click)=\"toggleSort(col)\"\r\n >\r\n <span>{{ col.label }}</span>\r\n <mt-icon\r\n [icon]=\"getSortIcon(col)\"\r\n class=\"text-xs text-gray-400\"\r\n />\r\n </button>\r\n } @else {\r\n {{ col.label }}\r\n }\r\n @if (\r\n isColumnFilterMode() && getFilterableColumn(col.key);\r\n as filterableCol\r\n ) {\r\n <mt-table-column-filter\r\n [column]=\"filterableCol\"\r\n [value]=\"filters()[col.key]\"\r\n (filterChange)=\"\r\n onColumnFilterChange(col.key, $event)\r\n \"\r\n />\r\n }\r\n </div>\r\n </th>\r\n }\r\n }\r\n\r\n @if (rowActions().length > 0) {\r\n <th class=\"text-end! text-sm font-normal text-[#323232]\">\r\n {{ \"components.table.actions\" | transloco }}\r\n </th>\r\n }\r\n </tr>\r\n @if (updating()) {\r\n <tr>\r\n <th [attr.colspan]=\"totalColumnSpan()\" class=\"!p-0\">\r\n <p-progressBar\r\n mode=\"indeterminate\"\r\n [style]=\"{ height: '4px' }\"\r\n />\r\n </th>\r\n </tr>\r\n }\r\n </ng-template>\r\n <ng-template\r\n #body\r\n let-row\r\n let-columns=\"columns\"\r\n let-index=\"rowIndex\"\r\n class=\"divide-y divide-gray-200\"\r\n >\r\n @if (loading()) {\r\n <tr>\r\n @if (reorderableRows()) {\r\n <td><p-skeleton /></td>\r\n }\r\n @if (selectableRows()) {\r\n <td><p-skeleton /></td>\r\n }\r\n @for (col of columns; track col.key || col.label || $index) {\r\n <td><p-skeleton /></td>\r\n }\r\n @if (rowActions().length > 0) {\r\n <td><p-skeleton /></td>\r\n }\r\n </tr>\r\n } @else {\r\n <tr\r\n class=\"border-surface-300 transition-colors duration-150 dark:border-surface-500\"\r\n [class.mt-table-clickable-row]=\"clickableRows()\"\r\n [class.mt-table-status-entity-row]=\"\r\n getStatusEntityAccentColor(row)\r\n \"\r\n [style.--mt-table-status-accent]=\"\r\n getStatusEntityAccentColor(row)\r\n \"\r\n [class.cursor-pointer]=\"clickableRows()\"\r\n [pReorderableRow]=\"index\"\r\n (click)=\"onRowClick($event, row)\"\r\n >\r\n @if (reorderableRows()) {\r\n <td class=\"w-10 text-center\">\r\n <mt-button\r\n styleClass=\"cursor-move!\"\r\n pReorderableRowHandle\r\n severity=\"secondary\"\r\n variant=\"outlined\"\r\n size=\"small\"\r\n icon=\"general.menu-05\"\r\n ></mt-button>\r\n <!-- <mt-icon-->\r\n <!-- icon=\"general.menu-05\"-->\r\n <!-- class=\"cursor-move text-gray-500\"-->\r\n <!-- pReorderableRowHandle-->\r\n <!-- ></mt-icon>-->\r\n </td>\r\n }\r\n @if (selectableRows()) {\r\n <td class=\"w-12\">\r\n <mt-checkbox-field\r\n [ngModel]=\"isRowSelected(row)\"\r\n (ngModelChange)=\"toggleRow(row)\"\r\n ></mt-checkbox-field>\r\n </td>\r\n }\r\n\r\n @for (col of columns; track col.key || col.label || $index) {\r\n <td\r\n class=\"text-sm font-normal text-[#4b4b4b]\"\r\n [style.width]=\"col.width ?? null\"\r\n [style.minWidth]=\"getColumnMinWidth(col)\"\r\n >\r\n @switch (col.type) {\r\n @case (\"boolean\") {\r\n @if (isCellClickFilterable(col, row)) {\r\n <span\r\n data-row-click-ignore=\"true\"\r\n class=\"inline-flex items-center cursor-pointer px-1.5 py-0.5 rounded transition-colors\"\r\n [class.ring-2]=\"isCellFilterActive(row, col)\"\r\n [class.ring-primary-400]=\"\r\n isCellFilterActive(row, col)\r\n \"\r\n [class.hover:underline]=\"\r\n !isCellFilterActive(row, col)\r\n \"\r\n (click)=\"onCellFilterClick($event, row, col)\"\r\n >\r\n {{\r\n getBooleanProperty(row, col.key) ? \"Yes\" : \"No\"\r\n }}\r\n </span>\r\n } @else {\r\n <mt-toggle-field\r\n [disabled]=\"col.readonly\"\r\n [ngModel]=\"getBooleanProperty(row, col.key)\"\r\n (ngModelChange)=\"\r\n onCellChange(row, col.key, $event, 'boolean')\r\n \"\r\n ></mt-toggle-field>\r\n }\r\n }\r\n @case (\"date\") {\r\n {{\r\n getDateProperty(row, col.key) | mtDateFormat: \"date\"\r\n }}\r\n }\r\n @case (\"dateTime\") {\r\n {{\r\n getDateProperty(row, col.key)\r\n | mtDateFormat: \"dateTime\"\r\n }}\r\n }\r\n @case (\"user\") {\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n filterableCell;\r\n context: { row: row, col: col }\r\n \"\r\n ></ng-container>\r\n }\r\n @case (\"status\") {\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n filterableCell;\r\n context: { row: row, col: col }\r\n \"\r\n ></ng-container>\r\n }\r\n @case (\"entity\") {\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n filterableCell;\r\n context: { row: row, col: col }\r\n \"\r\n ></ng-container>\r\n }\r\n @case (\"custom\") {\r\n <ng-container\r\n *ngTemplateOutlet=\"\r\n col.customCellTpl;\r\n context: { $implicit: row }\r\n \"\r\n >\r\n </ng-container>\r\n }\r\n @default {\r\n {{ getProperty(row, col.key) }}\r\n }\r\n }\r\n </td>\r\n }\r\n\r\n @if (rowActions().length > 0) {\r\n <td class=\"text-right\">\r\n @if (actionShape() === \"popover\") {\r\n <div class=\"flex items-center justify-end\">\r\n <mt-button\r\n icon=\"general.dots-vertical\"\r\n severity=\"secondary\"\r\n variant=\"text\"\r\n size=\"large\"\r\n (click)=\"rowPopover.toggle($event)\"\r\n data-row-click-ignore=\"true\"\r\n ></mt-button>\r\n <p-popover #rowPopover appendTo=\"body\">\r\n <div class=\"flex flex-col min-w-40\">\r\n @for (\r\n action of getVisibleRowActions(row);\r\n track $index\r\n ) {\r\n <button\r\n class=\"flex items-center gap-2 px-2 cursor-pointer py-2 text-sm rounded transition-colors\"\r\n [class]=\"\r\n action.color === 'danger'\r\n ? 'text-red-600 hover:bg-red-50 dark:hover:bg-red-950'\r\n : 'text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-surface-700'\r\n \"\r\n (click)=\"\r\n rowAction($event, action, row);\r\n rowPopover.hide()\r\n \"\r\n >\r\n @if (action.icon) {\r\n <mt-icon\r\n [icon]=\"action.icon\"\r\n class=\"text-base\"\r\n />\r\n }\r\n <span>{{\r\n action.label || action.tooltip\r\n }}</span>\r\n </button>\r\n }\r\n </div>\r\n </p-popover>\r\n </div>\r\n } @else {\r\n <div class=\"flex items-center justify-end space-x-2\">\r\n @for (action of rowActions(); track $index) {\r\n @let hidden = action.hidden?.(row);\r\n @if (!hidden) {\r\n <mt-button\r\n [icon]=\"action.icon\"\r\n [severity]=\"action.color\"\r\n [variant]=\"action.variant\"\r\n [size]=\"action.size || 'small'\"\r\n (click)=\"rowAction($event, action, row)\"\r\n [tooltip]=\"action.tooltip\"\r\n [label]=\"action.label\"\r\n [loading]=\"resolveActionLoading(action, row)\"\r\n ></mt-button>\r\n }\r\n }\r\n </div>\r\n }\r\n </td>\r\n }\r\n </tr>\r\n }\r\n </ng-template>\r\n <ng-template #filterableCell let-row=\"row\" let-col=\"col\">\r\n @let filterable = isCellClickFilterable(col, row);\r\n @let active = isCellFilterActive(row, col);\r\n @if (filterable) {\r\n <span\r\n data-row-click-ignore=\"true\"\r\n class=\"flex w-full items-center rounded transition-colors cursor-pointer\"\r\n [class.ring-2]=\"active\"\r\n [class.ring-primary-400]=\"active\"\r\n (click)=\"onCellFilterClick($event, row, col)\"\r\n >\r\n @if (resolveCellEntityData(row, col); as entityData) {\r\n <mt-entity-preview\r\n [data]=\"entityData\"\r\n attachmentShape=\"compact\"\r\n ></mt-entity-preview>\r\n } @else {\r\n {{ getProperty(row, col.key) }}\r\n }\r\n </span>\r\n } @else {\r\n @if (resolveCellEntityData(row, col); as entityData) {\r\n <mt-entity-preview\r\n [data]=\"entityData\"\r\n attachmentShape=\"compact\"\r\n ></mt-entity-preview>\r\n } @else {\r\n {{ getProperty(row, col.key) }}\r\n }\r\n }\r\n </ng-template>\r\n <ng-template #groupheader let-row>\r\n @if (grouping.groupingActive()) {\r\n <tr\r\n class=\"mt-group-header\"\r\n [style.--mt-group-accent]=\"\r\n grouping.getGroupAccentColor(row) ??\r\n 'var(--p-primary-color)'\r\n \"\r\n >\r\n <td [attr.colspan]=\"totalColumnSpan()\" class=\"!p-0\">\r\n <div\r\n class=\"flex items-center gap-3 px-4 py-2 bg-surface-50 dark:bg-surface-900 border-y border-surface-200 dark:border-surface-700\"\r\n >\r\n <span\r\n class=\"mt-group-header__accent inline-block w-1 h-5 rounded-full\"\r\n ></span>\r\n <span\r\n class=\"text-xs uppercase tracking-wide text-gray-500 dark:text-gray-400\"\r\n >\r\n {{ grouping.activeGroupColumn()?.label }}\r\n </span>\r\n <span\r\n class=\"text-sm font-semibold text-gray-900 dark:text-gray-100\"\r\n >\r\n {{ grouping.getGroupLabel(row) }}\r\n </span>\r\n <span\r\n class=\"ml-auto inline-flex items-center gap-1 text-xs px-2 py-0.5 rounded-full bg-primary-50 text-primary-700 dark:bg-primary-950 dark:text-primary-300\"\r\n >\r\n {{ grouping.getGroupCount(row) }}\r\n </span>\r\n </div>\r\n </td>\r\n </tr>\r\n }\r\n </ng-template>\r\n <ng-template #emptymessage>\r\n <tr>\r\n <td [attr.colspan]=\"totalColumnSpan()\" class=\"text-center\">\r\n <div\r\n class=\"flex min-h-44 flex-col items-center justify-center gap-3 py-8 text-center\"\r\n >\r\n <svg\r\n width=\"152\"\r\n height=\"120\"\r\n viewBox=\"0 0 152 120\"\r\n fill=\"none\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n >\r\n <circle cx=\"76\" cy=\"52\" r=\"52\" fill=\"#E9EAEB\" />\r\n <g filter=\"url(#filter0_ddd_2474_28277)\">\r\n <path\r\n d=\"M77.6 16C66.8273 16 57.2978 21.3233 51.4987 29.4829C49.605 29.0363 47.6301 28.8 45.6 28.8C31.4615 28.8 20 40.2615 20 54.4C20 68.5385 31.4615 80 45.6 80L109.6 80C121.971 80 132 69.9712 132 57.6C132 45.2288 121.971 35.2 109.6 35.2C108.721 35.2 107.854 35.2506 107.002 35.349C102.098 23.9677 90.7797 16 77.6 16Z\"\r\n fill=\"#FAFAFA\"\r\n />\r\n <ellipse\r\n cx=\"45.6\"\r\n cy=\"54.3998\"\r\n rx=\"25.6\"\r\n ry=\"25.6\"\r\n fill=\"url(#paint0_linear_2474_28277)\"\r\n />\r\n <circle\r\n cx=\"77.6016\"\r\n cy=\"48\"\r\n r=\"32\"\r\n fill=\"url(#paint1_linear_2474_28277)\"\r\n />\r\n <ellipse\r\n cx=\"109.599\"\r\n cy=\"57.6002\"\r\n rx=\"22.4\"\r\n ry=\"22.4\"\r\n fill=\"url(#paint2_linear_2474_28277)\"\r\n />\r\n </g>\r\n <circle cx=\"21\" cy=\"19\" r=\"5\" fill=\"#F5F5F5\" />\r\n <circle cx=\"18\" cy=\"109\" r=\"7\" fill=\"#F5F5F5\" />\r\n <circle cx=\"145\" cy=\"35\" r=\"7\" fill=\"#F5F5F5\" />\r\n <circle cx=\"134\" cy=\"8\" r=\"4\" fill=\"#F5F5F5\" />\r\n <foreignObject x=\"44\" y=\"54\" width=\"64\" height=\"64\">\r\n <div\r\n xmlns=\"http://www.w3.org/1999/xhtml\"\r\n style=\"\r\n backdrop-filter: blur(4px);\r\n clip-path: url(#bgblur_0_2474_28277_clip_path);\r\n height: 100%;\r\n width: 100%;\r\n \"\r\n ></div>\r\n </foreignObject>\r\n <g data-figma-bg-blur-radius=\"8\">\r\n <path\r\n d=\"M52 86C52 72.7452 62.7452 62 76 62C89.2548 62 100 72.7452 100 86C100 99.2548 89.2548 110 76 110C62.7452 110 52 99.2548 52 86Z\"\r\n fill=\"#344054\"\r\n fill-opacity=\"0.4\"\r\n />\r\n <path\r\n d=\"M85 95L81.5001 91.5M84 85.5C84 90.1944 80.1944 94 75.5 94C70.8056 94 67 90.1944 67 85.5C67 80.8056 70.8056 77 75.5 77C80.1944 77 84 80.8056 84 85.5Z\"\r\n stroke=\"white\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n />\r\n </g>\r\n <defs>\r\n <filter\r\n id=\"filter0_ddd_2474_28277\"\r\n x=\"0\"\r\n y=\"16\"\r\n width=\"152\"\r\n height=\"104\"\r\n filterUnits=\"userSpaceOnUse\"\r\n color-interpolation-filters=\"sRGB\"\r\n >\r\n <feFlood\r\n flood-opacity=\"0\"\r\n result=\"BackgroundImageFix\"\r\n />\r\n <feColorMatrix\r\n in=\"SourceAlpha\"\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"\r\n result=\"hardAlpha\"\r\n />\r\n <feMorphology\r\n radius=\"1.5\"\r\n operator=\"erode\"\r\n in=\"SourceAlpha\"\r\n result=\"effect1_dropShadow_2474_28277\"\r\n />\r\n <feOffset dy=\"3\" />\r\n <feGaussianBlur stdDeviation=\"1.5\" />\r\n <feComposite in2=\"hardAlpha\" operator=\"out\" />\r\n <feColorMatrix\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0.0392157 0 0 0 0 0.0496732 0 0 0 0 0.0705882 0 0 0 0.04 0\"\r\n />\r\n <feBlend\r\n mode=\"normal\"\r\n in2=\"BackgroundImageFix\"\r\n result=\"effect1_dropShadow_2474_28277\"\r\n />\r\n <feColorMatrix\r\n in=\"SourceAlpha\"\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"\r\n result=\"hardAlpha\"\r\n />\r\n <feMorphology\r\n radius=\"4\"\r\n operator=\"erode\"\r\n in=\"SourceAlpha\"\r\n result=\"effect2_dropShadow_2474_28277\"\r\n />\r\n <feOffset dy=\"8\" />\r\n <feGaussianBlur stdDeviation=\"4\" />\r\n <feComposite in2=\"hardAlpha\" operator=\"out\" />\r\n <feColorMatrix\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0.0392157 0 0 0 0 0.0496732 0 0 0 0 0.0705882 0 0 0 0.03 0\"\r\n />\r\n <feBlend\r\n mode=\"normal\"\r\n in2=\"effect1_dropShadow_2474_28277\"\r\n result=\"effect2_dropShadow_2474_28277\"\r\n />\r\n <feColorMatrix\r\n in=\"SourceAlpha\"\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\"\r\n result=\"hardAlpha\"\r\n />\r\n <feMorphology\r\n radius=\"4\"\r\n operator=\"erode\"\r\n in=\"SourceAlpha\"\r\n result=\"effect3_dropShadow_2474_28277\"\r\n />\r\n <feOffset dy=\"20\" />\r\n <feGaussianBlur stdDeviation=\"12\" />\r\n <feComposite in2=\"hardAlpha\" operator=\"out\" />\r\n <feColorMatrix\r\n type=\"matrix\"\r\n values=\"0 0 0 0 0.0392157 0 0 0 0 0.0496732 0 0 0 0 0.0705882 0 0 0 0.08 0\"\r\n />\r\n <feBlend\r\n mode=\"normal\"\r\n in2=\"effect2_dropShadow_2474_28277\"\r\n result=\"effect3_dropShadow_2474_28277\"\r\n />\r\n <feBlend\r\n mode=\"normal\"\r\n in=\"SourceGraphic\"\r\n in2=\"effect3_dropShadow_2474_28277\"\r\n result=\"shape\"\r\n />\r\n </filter>\r\n <clipPath\r\n id=\"bgblur_0_2474_28277_clip_path\"\r\n transform=\"translate(-44 -54)\"\r\n >\r\n <path\r\n d=\"M52 86C52 72.7452 62.7452 62 76 62C89.2548 62 100 72.7452 100 86C100 99.2548 89.2548 110 76 110C62.7452 110 52 99.2548 52 86Z\"\r\n />\r\n </clipPath>\r\n <linearGradient\r\n id=\"paint0_linear_2474_28277\"\r\n x1=\"25.9429\"\r\n y1=\"37.4855\"\r\n x2=\"71.2\"\r\n y2=\"79.9998\"\r\n gradientUnits=\"userSpaceOnUse\"\r\n >\r\n <stop stop-color=\"#D0D5DD\" />\r\n <stop\r\n offset=\"0.350715\"\r\n stop-color=\"white\"\r\n stop-opacity=\"0\"\r\n />\r\n </linearGradient>\r\n <linearGradient\r\n id=\"paint1_linear_2474_28277\"\r\n x1=\"53.0301\"\r\n y1=\"26.8571\"\r\n x2=\"109.602\"\r\n y2=\"80\"\r\n gradientUnits=\"userSpaceOnUse\"\r\n >\r\n <stop stop-color=\"#D0D5DD\" />\r\n <stop\r\n offset=\"0.350715\"\r\n stop-color=\"white\"\r\n stop-opacity=\"0\"\r\n />\r\n </linearGradient>\r\n <linearGradient\r\n id=\"paint2_linear_2474_28277\"\r\n x1=\"92.3992\"\r\n y1=\"42.8002\"\r\n x2=\"131.999\"\r\n y2=\"80.0002\"\r\n gradientUnits=\"userSpaceOnUse\"\r\n >\r\n <stop stop-color=\"#D0D5DD\" />\r\n <stop\r\n offset=\"0.350715\"\r\n stop-color=\"white\"\r\n stop-opacity=\"0\"\r\n />\r\n </linearGradient>\r\n </defs>\r\n </svg>\r\n <p class=\"m-0 text-base font-medium text-surface-500\">\r\n {{ \"components.table.no-data-found\" | transloco }}\r\n </p>\r\n </div>\r\n </td>\r\n </tr>\r\n </ng-template>\r\n </p-table>\r\n </div>\r\n }\r\n </div>\r\n\r\n <div\r\n class=\"flex flex-col gap-3 pb-3 px-4\"\r\n [class]=\"'items-' + paginatorPosition()\"\r\n >\r\n <mt-paginator\r\n [(rows)]=\"pageSize\"\r\n [(first)]=\"first\"\r\n [(page)]=\"currentPage\"\r\n [totalRecords]=\"totalRecords()\"\r\n [alwaysShow]=\"alwaysShowPaginator()\"\r\n [rowsPerPageOptions]=\"rowsPerPageOptions()\"\r\n (onPageChange)=\"onPaginatorPage($event)\"\r\n ></mt-paginator>\r\n </div>\r\n </div>\r\n</ng-template>\r\n", styles: [":host ::ng-deep .p-datatable-header{padding:0 0 1.5rem;background:transparent;border:0}:host ::ng-deep .p-datatable-table{border-collapse:separate;border-spacing:0}:host ::ng-deep .p-datatable-thead>tr>th{padding:.9rem 1rem;background:#fff;border-bottom:1px solid #ebebf0;color:#323232;font-size:14px;font-weight:400;line-height:20px;white-space:nowrap}:host ::ng-deep .p-datatable-tbody>tr>td{padding:.72rem 1rem;background:#fff;border-bottom:1px solid #ebebf0;color:#4b4b4b;font-size:14px;font-weight:400;line-height:20px;vertical-align:middle}:host ::ng-deep .p-datatable-tbody>tr:last-child>td{border-bottom:0}:host ::ng-deep .p-datatable-thead>tr>th:first-child{border-top-left-radius:.625rem}:host ::ng-deep .p-datatable-thead>tr>th:last-child{border-top-right-radius:.625rem}:host ::ng-deep .p-datatable-tbody>tr:last-child>td:first-child{border-bottom-left-radius:.625rem}:host ::ng-deep .p-datatable-tbody>tr:last-child>td:last-child{border-bottom-right-radius:.625rem}.mt-table-clickable-row>td{transition:background-color .16s ease,color .16s ease,border-color .16s ease}.mt-table-clickable-row:hover>td,.mt-table-clickable-row:focus-within>td{background:#fafafa}.mt-table-clickable-row:hover>td:first-child,.mt-table-clickable-row:focus-within>td:first-child{border-inline-start:none}.mt-table-status-entity-row>td{background:#fff}.mt-table-status-entity-row>td:first-child:before{display:none}:host ::ng-deep tr.mt-group-header>td{padding:0!important;background:transparent}tr.mt-group-header .mt-group-header__accent{background:var(--mt-group-accent, var(--p-primary-color))}\n"] }]
2262
+ }], ctorParameters: () => [], propDecorators: { selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], cellChange: [{ type: i0.Output, args: ["cellChange"] }], lazyLoad: [{ type: i0.Output, args: ["lazyLoad"] }], columnReorder: [{ type: i0.Output, args: ["columnReorder"] }], rowReorder: [{ type: i0.Output, args: ["rowReorder"] }], rowClick: [{ type: i0.Output, args: ["rowClick"] }], filters: [{ type: i0.Input, args: [{ isSignal: true, alias: "filters", required: false }] }, { type: i0.Output, args: ["filtersChange"] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], rowActions: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowActions", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], showGridlines: [{ type: i0.Input, args: [{ isSignal: true, alias: "showGridlines", required: false }] }], stripedRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "stripedRows", required: false }] }], selectableRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectableRows", required: false }] }], clickableRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "clickableRows", required: false }] }], generalSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "generalSearch", required: false }] }], lazyLocalSearch: [{ type: i0.Input, args: [{ isSignal: true, alias: "lazyLocalSearch", required: false }] }], showFilters: [{ type: i0.Input, args: [{ isSignal: true, alias: "showFilters", required: false }] }], filterMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterMode", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], updating: [{ type: i0.Input, args: [{ isSignal: true, alias: "updating", required: false }] }], lazy: [{ type: i0.Input, args: [{ isSignal: true, alias: "lazy", required: false }] }], lazyLocalSort: [{ type: i0.Input, args: [{ isSignal: true, alias: "lazyLocalSort", required: false }] }], lazyTotalRecords: [{ type: i0.Input, args: [{ isSignal: true, alias: "lazyTotalRecords", required: false }] }], reorderableColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "reorderableColumns", required: false }] }], reorderableRows: [{ type: i0.Input, args: [{ isSignal: true, alias: "reorderableRows", required: false }] }], dataKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataKey", required: false }] }], storageKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "storageKey", required: false }] }], storageMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "storageMode", required: false }] }], exportable: [{ type: i0.Input, args: [{ isSignal: true, alias: "exportable", required: false }] }], printable: [{ type: i0.Input, args: [{ isSignal: true, alias: "printable", required: false }] }], groupable: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupable", required: false }] }], cellClickFilter: [{ type: i0.Input, args: [{ isSignal: true, alias: "cellClickFilter", required: false }] }], printTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "printTitle", required: false }] }], exportFilename: [{ type: i0.Input, args: [{ isSignal: true, alias: "exportFilename", required: false }] }], actionShape: [{ type: i0.Input, args: [{ isSignal: true, alias: "actionShape", required: false }] }], tableLayout: [{ type: i0.Input, args: [{ isSignal: true, alias: "tableLayout", required: false }] }], noCard: [{ type: i0.Input, args: [{ isSignal: true, alias: "noCard", required: false }] }], tabs: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabs", required: false }] }], tabsOptionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabsOptionLabel", required: false }] }], tabsOptionValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabsOptionValue", required: false }] }], activeTab: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeTab", required: false }] }, { type: i0.Output, args: ["activeTabChange"] }], onTabChange: [{ type: i0.Output, args: ["onTabChange"] }], actions: [{ type: i0.Input, args: [{ isSignal: true, alias: "actions", required: false }] }], captionStartContent: [{ type: i0.ContentChild, args: ['captionStart', { isSignal: true }] }], captionEndContent: [{ type: i0.ContentChild, args: ['captionEnd', { isSignal: true }] }], emptyContent: [{ type: i0.ContentChild, args: ['empty', { isSignal: true }] }], paginatorPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "paginatorPosition", required: false }] }], alwaysShowPaginator: [{ type: i0.Input, args: [{ isSignal: true, alias: "alwaysShowPaginator", required: false }] }], rowsPerPageOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowsPerPageOptions", required: false }] }], pageSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "pageSize", required: false }] }, { type: i0.Output, args: ["pageSizeChange"] }], currentPage: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentPage", required: false }] }, { type: i0.Output, args: ["currentPageChange"] }], first: [{ type: i0.Input, args: [{ isSignal: true, alias: "first", required: false }] }, { type: i0.Output, args: ["firstChange"] }], filterTerm: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterTerm", required: false }] }, { type: i0.Output, args: ["filterTermChange"] }], groupBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupBy", required: false }] }, { type: i0.Output, args: ["groupByChange"] }] } });
1444
2263
 
1445
2264
  /**
1446
2265
  * Generated bundle index. Do not edit.
1447
2266
  */
1448
2267
 
1449
- export { Table, TableFilter };
2268
+ export { Table, TableActionsMenu, TableCaption, TableColumnFilter, TableExportService, TableFilter, TableFilterField, TableGroupingController, TableValueResolver };
1450
2269
  //# sourceMappingURL=masterteam-components-table.mjs.map