spiderly 19.11.3 → 19.11.5

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,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Input, Component, EventEmitter, Output, Injectable, ViewChild, NgModule, PLATFORM_ID, Inject, HostBinding, Directive, LOCALE_ID, TemplateRef, ContentChild, inject } from '@angular/core';
2
+ import { Input, Component, EventEmitter, Output, Injectable, ViewChild, NgModule, PLATFORM_ID, Inject, HostBinding, Directive, LOCALE_ID, TemplateRef, ContentChildren, ContentChild, inject } from '@angular/core';
3
3
  import * as i1 from '@jsverse/transloco';
4
4
  import { TranslocoDirective, TranslocoService } from '@jsverse/transloco';
5
5
  import * as i2 from '@angular/common';
@@ -87,6 +87,9 @@ const ApiErrorCodes = {
87
87
  EmailNotVerified: 'email_not_verified',
88
88
  ExternalProviderNotConfigured: 'external_provider_not_configured',
89
89
  ExternalEmailMissing: 'external_email_missing',
90
+ UnknownFilterField: 'unknown_filter_field',
91
+ UnknownSortField: 'unknown_sort_field',
92
+ InvalidMatchMode: 'invalid_match_mode',
90
93
  };
91
94
 
92
95
  class BaseControl {
@@ -110,8 +113,19 @@ class BaseControl {
110
113
  this.control.disable();
111
114
  }
112
115
  ngAfterViewInit() { }
116
+ /**
117
+ * Every control's TEMPLATE renders without a control (`*ngIf="control"`, `control?.errors`,
118
+ * spiderly-file's no-control custom uploads), and this was the one shared read that did not —
119
+ * so an absent control took the whole page down through the label rather than rendering
120
+ * label-less: an unhandled TypeError per change-detection pass, which the global ErrorHandler
121
+ * turns into the generic error toast.
122
+ *
123
+ * That fixes the shared path only. `spiderly-autocomplete`, `spiderly-colorpicker` and
124
+ * `spiderly-checkbox` (with `initializeToFalse`) still dereference `control` in their own
125
+ * `ngOnInit`, so those three are not yet safe to hand an absent control.
126
+ */
113
127
  getTranslatedLabel() {
114
- return this.label ?? this.control.labelForDisplay;
128
+ return this.label ?? this.control?.labelForDisplay;
115
129
  }
116
130
  getValidationErrrorMessages() {
117
131
  if (this.control?.errors && this.control?.dirty) {
@@ -1713,6 +1727,12 @@ class InitCompanyAuthDialogDetails extends BaseEntity {
1713
1727
 
1714
1728
  class ConfigServiceBase {
1715
1729
  constructor() {
1730
+ /**
1731
+ * Consumer-facing only — nothing in the library reads it. The error handler and the HTTP
1732
+ * interceptor used to gate their `console.error` on it, which left a deployed app's client
1733
+ * errors with nowhere to go; both now log unconditionally. `spiderly init` still scaffolds the
1734
+ * `override`, so apps keep branching on it.
1735
+ */
1716
1736
  this.production = false;
1717
1737
  this.frontendUrl = 'http://localhost:4200';
1718
1738
  this.companyName = 'Company Name';
@@ -3865,6 +3885,39 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImpo
3865
3885
  type: Input
3866
3886
  }] } });
3867
3887
 
3888
+ /**
3889
+ * Renders the cells of ONE column of a `spiderly-data-table`, replacing the plain formatted
3890
+ * value. Bind it to the column's `field`; columns with no matching template keep the built-in
3891
+ * rendering, so a table opts in one column at a time.
3892
+ *
3893
+ * Consumer guide (context, what it does and does not replace, when to prefer it over
3894
+ * `onCellClick`): the `angular-customization` doc, "Custom Cell Content".
3895
+ */
3896
+ class SpiderlyCellTemplateDirective {
3897
+ constructor(template) {
3898
+ this.template = template;
3899
+ }
3900
+ /**
3901
+ * Without this the `let-` variables are `any` at every consumer, however well
3902
+ * {@link CellTemplateContext} is declared — a directive's injected `TemplateRef<C>` never
3903
+ * reaches the template that declares it. Same mechanism as `SpiderlyTemplateTypeDirective`.
3904
+ */
3905
+ static ngTemplateContextGuard(dir, ctx) {
3906
+ return true;
3907
+ }
3908
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: SpiderlyCellTemplateDirective, deps: [{ token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); }
3909
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.13", type: SpiderlyCellTemplateDirective, isStandalone: true, selector: "ng-template[spiderlyCellTemplate]", inputs: { field: ["spiderlyCellTemplate", "field"] }, ngImport: i0 }); }
3910
+ }
3911
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: SpiderlyCellTemplateDirective, decorators: [{
3912
+ type: Directive,
3913
+ args: [{
3914
+ selector: 'ng-template[spiderlyCellTemplate]',
3915
+ }]
3916
+ }], ctorParameters: () => [{ type: i0.TemplateRef }], propDecorators: { field: [{
3917
+ type: Input,
3918
+ args: ['spiderlyCellTemplate']
3919
+ }] } });
3920
+
3868
3921
  /**
3869
3922
  * Marks an `<ng-template>` projected into `spiderly-data-table` as custom toolbar
3870
3923
  * content. The template is rendered in the table's caption action area, ahead of the
@@ -4015,6 +4068,20 @@ class SpiderlyDataTableComponent {
4015
4068
  ngAfterViewInit() {
4016
4069
  this.setupRemovableSort();
4017
4070
  }
4071
+ /**
4072
+ * The template that renders this column's cells, or null to use the built-in rendering.
4073
+ * Actions columns have no `field`, so they never match one.
4074
+ *
4075
+ * Read straight off the QueryList, which is live — a consumer declaring its templates inside a
4076
+ * `@for`/`@if` is served with no subscription and nothing to invalidate. The scan is over the
4077
+ * TEMPLATED columns only (typically one or two), not over `cols`.
4078
+ */
4079
+ getCellTemplate(col) {
4080
+ if (col.field == null)
4081
+ return null;
4082
+ return (this.cellTemplates?.find((directive) => directive.field === col.field)
4083
+ ?.template ?? null);
4084
+ }
4018
4085
  // PrimeNG v19 removed the removableSort property. This overrides the table's
4019
4086
  // sort() method to add tri-state cycling: ascending → descending → unsorted
4020
4087
  // (or back to the declared default sort when one is set).
@@ -4261,11 +4328,31 @@ class SpiderlyDataTableComponent {
4261
4328
  const defaultSortCol = this.cols?.find((col) => col.field === this.defaultSortField);
4262
4329
  if (defaultSortCol && !this.isColumnVisible(defaultSortCol))
4263
4330
  return null;
4331
+ // A declared default on a non-sortable column is a consumer mistake the backend answers
4332
+ // with a 400 on every load; fall back to its implicit Id DESC instead (see keepSortableMeta).
4333
+ if (defaultSortCol && !this.isColumnSortable(defaultSortCol))
4334
+ return null;
4264
4335
  return [{ field: this.defaultSortField, order: this.defaultSortOrder }];
4265
4336
  }
4266
4337
  persistedMultiSortMeta() {
4267
4338
  const state = this.persistedTableState();
4268
- return state?.multiSortMeta?.length ? state.multiSortMeta : null;
4339
+ const sortable = this.keepSortableMeta(state?.multiSortMeta);
4340
+ return sortable.length ? sortable : null;
4341
+ }
4342
+ /**
4343
+ * Drops sort meta the backend has no sort case for. Persisted state outlives the rule that
4344
+ * produced it — a sort stored before a column became non-sortable (or before the library
4345
+ * started disabling `*CommaSeparated` headers) would otherwise ride every lazy load, and the
4346
+ * generated `Build` answers an unknown sort field with a 400. There would be no way out from
4347
+ * the UI either: the header that could clear it is exactly the one no longer clickable.
4348
+ * Unknown fields (no matching column) are left alone — a consumer may sort on something it
4349
+ * declares no column for.
4350
+ */
4351
+ keepSortableMeta(multiSortMeta) {
4352
+ return (multiSortMeta ?? []).filter((sortMeta) => {
4353
+ const col = this.cols?.find((c) => c.field === sortMeta?.field);
4354
+ return col == null || this.isColumnSortable(col);
4355
+ });
4269
4356
  }
4270
4357
  // Safety net: any lazy load still leaving unsorted (Clear filters — PrimeNG's clear()
4271
4358
  // nulls the sort and emits in one call — or stale persisted state) falls back to the
@@ -4369,8 +4456,23 @@ class SpiderlyDataTableComponent {
4369
4456
  item.index = index;
4370
4457
  });
4371
4458
  }
4372
- getColHeaderWidth(filterType) {
4373
- switch (filterType) {
4459
+ /**
4460
+ * Single source for whether a column header offers click-to-sort (drives both
4461
+ * `pSortableColumnDisabled` and the sort icon). Beyond the consumer's explicit `sortable: false`,
4462
+ * `*CommaSeparated` fields are auto-disabled: the backend's `PaginatedResultGenerator` never emits
4463
+ * a sort case for collection columns (the same naming convention decides both), and since unknown
4464
+ * sort fields are rejected with a 400, a clickable header here would be a guaranteed error toast.
4465
+ */
4466
+ isColumnSortable(col) {
4467
+ return (col.sortable !== false &&
4468
+ !!col.field &&
4469
+ !col.field.endsWith('CommaSeparated'));
4470
+ }
4471
+ /** The column's declared {@link Column.minWidth}, or the default for its filter type. */
4472
+ getColHeaderWidth(col) {
4473
+ if (col.minWidth != null)
4474
+ return `min-width: ${col.minWidth};`;
4475
+ switch (col.filterType) {
4374
4476
  case 'text':
4375
4477
  return 'min-width: 12rem;';
4376
4478
  case 'date':
@@ -4726,7 +4828,7 @@ class SpiderlyDataTableComponent {
4726
4828
  }
4727
4829
  }
4728
4830
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: SpiderlyDataTableComponent, deps: [{ token: i3$2.Router }, { token: i1$5.DialogService }, { token: i3$2.ActivatedRoute }, { token: SpiderlyMessageService }, { token: i1.TranslocoService }, { token: ConfigServiceBase }, { token: LOCALE_ID }], target: i0.ɵɵFactoryTarget.Component }); }
4729
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.13", type: SpiderlyDataTableComponent, isStandalone: true, selector: "spiderly-data-table", inputs: { tableTitle: "tableTitle", tableIcon: "tableIcon", items: "items", rows: "rows", cols: "cols", showPaginator: "showPaginator", showCardWrapper: "showCardWrapper", readonly: "readonly", idField: "idField", getPaginatedListObservableMethod: "getPaginatedListObservableMethod", exportListToExcelObservableMethod: "exportListToExcelObservableMethod", deleteItemFromTableObservableMethod: "deleteItemFromTableObservableMethod", deleteListFromTableObservableMethod: "deleteListFromTableObservableMethod", newlySelectedItems: "newlySelectedItems", unselectedItems: "unselectedItems", selectionMode: "selectionMode", selectedLazyLoadObservableMethod: "selectedLazyLoadObservableMethod", additionalFilterIdLong: "additionalFilterIdLong", showAddButton: "showAddButton", showExportToExcelButton: "showExportToExcelButton", showReloadTableButton: "showReloadTableButton", getFormArrayItems: "getFormArrayItems", hasLazyLoad: "hasLazyLoad", stateKey: "stateKey", stateStorage: "stateStorage", defaultSortField: "defaultSortField", defaultSortOrder: "defaultSortOrder", getAlreadySelectedItemIds: "getAlreadySelectedItemIds", getAlreadySelectedItems: "getAlreadySelectedItems", getFormControl: "getFormControl", additionalIndexes: "additionalIndexes", navigateOnRowClick: "navigateOnRowClick", rowNavigationPath: "rowNavigationPath" }, outputs: { onTotalRecordsChange: "onTotalRecordsChange", onLazyLoad: "onLazyLoad", onIsAllSelectedChange: "onIsAllSelectedChange", onRowSelect: "onRowSelect", onRowUnselect: "onRowUnselect" }, queries: [{ propertyName: "actionsTemplate", first: true, predicate: SpiderlyDataTableActionsDirective, descendants: true, read: TemplateRef }], viewQueries: [{ propertyName: "table", first: true, predicate: ["dt"], descendants: true }], ngImport: i0, template: "<ng-container *transloco=\"let t\">\n <div\n [class]=\"\n showCardWrapper ? 'card responsive-card-padding overflow-auto' : ''\n \"\n >\n <p-table\n #dt\n [value]=\"items\"\n [rows]=\"rows\"\n [rowHover]=\"true\"\n [paginator]=\"showPaginator\"\n responsiveLayout=\"scroll\"\n [lazy]=\"hasLazyLoad\"\n (onLazyLoad)=\"lazyLoad($event)\"\n [totalRecords]=\"totalRecords\"\n class=\"spiderly-table\"\n [loading]=\"items === undefined || loading === true\"\n [selectionMode]=\"selectionMode\"\n dataKey=\"id\"\n (onFilter)=\"filter($event)\"\n sortMode=\"multiple\"\n [multiSortMeta]=\"initialMultiSortMeta\"\n [stateKey]=\"resolvedStateKey\"\n [stateStorage]=\"stateStorage\"\n >\n <ng-template pTemplate=\"caption\">\n <div class=\"table-header overflow-auto\">\n <div style=\"display: flex; align-items: center; gap: 8px\">\n <i class=\"{{ tableIcon }}\" style=\"font-size: 20px\"></i>\n <div style=\"margin: 0px; font-size: 17.5px\">{{ tableTitle }}</div>\n </div>\n <div style=\"display: flex; gap: 8px\">\n <ng-container\n *ngIf=\"actionsTemplate\"\n [ngTemplateOutlet]=\"actionsTemplate\"\n ></ng-container>\n <button\n pButton\n *ngIf=\"hasLazyLoad\"\n data-testid=\"column-chooser-button\"\n [label]=\"t('Columns')\"\n class=\"p-button-outlined\"\n style=\"flex: none\"\n icon=\"pi pi-sliders-h\"\n (click)=\"columnChooser.toggle($event)\"\n ></button>\n <button\n pButton\n [label]=\"t('ClearFilters')\"\n class=\"p-button-outlined\"\n style=\"flex: none\"\n icon=\"pi pi-filter-slash\"\n (click)=\"clear(dt)\"\n ></button>\n <button\n pButton\n *ngIf=\"showExportToExcelButton\"\n [label]=\"t('ExportToExcel')\"\n class=\"p-button-outlined\"\n style=\"flex: none\"\n icon=\"pi pi-download\"\n (click)=\"exportListToExcel()\"\n ></button>\n <button\n pButton\n *ngIf=\"showReloadTableButton\"\n [label]=\"t('Reload')\"\n class=\"p-button-outlined\"\n style=\"flex: none\"\n icon=\"pi pi-refresh\"\n (click)=\"reload()\"\n ></button>\n <button\n pButton\n *ngIf=\"deleteListFromTableObservableMethod && rowsSelectedNumber > 0\"\n [label]=\"t('DeleteSelected') + ' (' + rowsSelectedNumber + ')'\"\n class=\"p-button-danger\"\n style=\"flex: none\"\n icon=\"pi pi-trash\"\n (click)=\"deleteSelectedObjects()\"\n ></button>\n </div>\n </div>\n </ng-template>\n <ng-template pTemplate=\"header\">\n <tr>\n <th style=\"width: 0rem\" *ngIf=\"selectionMode == 'multiple'\">\n <div style=\"display: flex; gap: 8px\">\n <p-checkbox\n *ngIf=\"showSelectAllCheckbox\"\n [disabled]=\"readonly\"\n (onChange)=\"selectAll($event.checked)\"\n [(ngModel)]=\"fakeIsAllSelected\"\n [binary]=\"true\"\n ></p-checkbox>\n ({{ rowsSelectedNumber }})\n </div>\n </th>\n <ng-container *ngFor=\"let col of visibleCols; trackBy: colTrackByFn\">\n <th\n [pSortableColumn]=\"col.field\"\n [pSortableColumnDisabled]=\"col.sortable === false || !col.field\"\n [style]=\"getColHeaderWidth(col.filterType)\"\n >\n <div\n style=\"\n display: flex;\n justify-content: space-between;\n align-items: center;\n \"\n >\n <span style=\"display: flex; align-items: center; gap: 4px\">\n {{ col.name }}\n <p-sortIcon\n *ngIf=\"col.sortable !== false && col.field\"\n [field]=\"col.field!\"\n ></p-sortIcon>\n </span>\n <p-columnFilter\n *ngIf=\"col.filterType != null && col.filterType !== 'blob'\"\n [type]=\"col.filterType\"\n [field]=\"col.filterField ?? col.field\"\n display=\"menu\"\n [placeholder]=\"col.filterPlaceholder\"\n [showOperator]=\"false\"\n [showMatchModes]=\"col.showMatchModes\"\n [showAddButton]=\"col.showAddButton\"\n [matchModeOptions]=\"getColMatchModeOptions(col.filterType)\"\n [matchMode]=\"getColMatchMode(col.filterType)\"\n >\n <ng-template\n *ngIf=\"isDropOrMulti(col.filterType)\"\n pTemplate=\"filter\"\n let-value\n let-filter=\"filterCallback\"\n >\n <p-multiSelect\n [ngModel]=\"value\"\n [options]=\"col.dropdownOrMultiselectValues\"\n [placeholder]=\"t('All')\"\n (onChange)=\"filter($event.value)\"\n optionLabel=\"label\"\n optionValue=\"code\"\n [style]=\"{ width: '240px' }\"\n >\n <ng-template let-item pTemplate=\"item\">\n <div class=\"p-multiselect-representative-option\">\n <span class=\"ml-2\">{{ item.label }}</span>\n </div>\n </ng-template>\n </p-multiSelect>\n </ng-template>\n <ng-template\n *ngIf=\"col.filterType == 'date'\"\n pTemplate=\"filter\"\n let-value\n let-filter=\"filterCallback\"\n >\n <p-datepicker\n [ngModel]=\"value\"\n [showTime]=\"col.showTime\"\n (onSelect)=\"filter($event)\"\n ></p-datepicker>\n </ng-template>\n </p-columnFilter>\n </div>\n </th>\n </ng-container>\n </tr>\n </ng-template>\n <ng-template\n pTemplate=\"body\"\n let-rowData\n let-index=\"rowIndex\"\n let-editing=\"editing\"\n >\n <tr\n [class.clickable]=\"navigateOnRowClick\"\n (click)=\"onRowClick(rowData)\"\n >\n <td *ngIf=\"selectionMode == 'multiple'\">\n <p-checkbox\n [disabled]=\"readonly\"\n (onChange)=\"selectRow(rowData[idField], rowData.index)\"\n [ngModel]=\"isRowSelected(rowData[idField])\"\n [binary]=\"true\"\n ></p-checkbox>\n </td>\n <ng-container *ngFor=\"let col of visibleCols; trackBy: colTrackByFn\">\n <td\n [style]=\"getStyleForBodyColumn(col)\"\n [class.clickable]=\"col.onCellClick\"\n (click)=\"onCellClick(col, rowData, $event)\"\n *ngIf=\"!col.editable\"\n >\n <div\n style=\"\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 18px;\n \"\n >\n <ng-container\n *ngFor=\"let action of col.actions; trackBy: actionTrackByFn\"\n >\n <span\n [pTooltip]=\"action.name\"\n [class]=\"getClassForAction(action)\"\n [style]=\"getStyleForAction(action)\"\n (click)=\"getMethodForAction(action, rowData, $event)\"\n ></span>\n </ng-container>\n </div>\n <ng-container *ngIf=\"col.filterType === 'blob'\">\n <img width=\"45\" [src]=\"getRowData(rowData, col)\" alt=\"\" />\n </ng-container>\n <ng-container *ngIf=\"col.filterType !== 'blob'\">\n {{ getRowData(rowData, col) }}\n </ng-container>\n </td>\n <td *ngIf=\"col.editable\">\n <spiderly-number\n [control]=\"getFormArrayControlByIndex(col.field, rowData.index)\"\n [showLabel]=\"false\"\n ></spiderly-number>\n </td>\n </ng-container>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"emptymessage\">\n <tr>\n <td\n [attr.colspan]=\"\n visibleCols.length + (selectionMode === 'multiple' ? 1 : 0)\n \"\n >\n {{ t(\"NoRecordsFound\") }}\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"loadingbody\">\n <tr>\n <td\n [attr.colspan]=\"\n visibleCols.length + (selectionMode === 'multiple' ? 1 : 0)\n \"\n >\n {{ t(\"Loading\") }}...\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"paginatorleft\">\n {{ t(\"TotalRecords\") }}: {{ totalRecords }}\n </ng-template>\n <ng-template pTemplate=\"paginatorright\">\n <div style=\"display: flex; justify-content: end; gap: 10px\">\n <spiderly-button\n *ngIf=\"showAddButton\"\n [label]=\"t('AddNew')\"\n icon=\"pi pi-plus\"\n (onClick)=\"navigateToDetails(0)\"\n ></spiderly-button>\n </div>\n </ng-template>\n </p-table>\n <p-popover #columnChooser>\n <div class=\"column-chooser\">\n <label\n *ngFor=\"let col of chooserCols; trackBy: colTrackByFn\"\n data-testid=\"column-chooser-option\"\n class=\"column-chooser-option\"\n >\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"isColumnVisible(col)\"\n [disabled]=\"!canToggleColumn(col)\"\n (onChange)=\"toggleColumn(col, $event.checked)\"\n ></p-checkbox>\n <span>{{ col.name }}</span>\n </label>\n <button\n type=\"button\"\n data-testid=\"column-chooser-reset\"\n class=\"column-chooser-reset\"\n (click)=\"resetColumnVisibility()\"\n >\n {{ t('ResetToDefault') }}\n </button>\n </div>\n </p-popover>\n </div>\n</ng-container>\n", styles: [".table-header{display:flex;justify-content:space-between;align-items:center}@media (max-width: 640px){.table-header{display:flex;flex-direction:column;align-items:start;gap:14px}}.spiderly-table .p-paginator{padding:1rem}@media (min-width: 1400px){.spiderly-table .p-paginator-left-content{position:absolute;padding:14px;left:0}}@media (min-width: 1400px){.spiderly-table .p-paginator-right-content{position:absolute;padding:14px;right:0}}.column-chooser{display:flex;flex-direction:column;gap:8px}.column-chooser-option{display:flex;align-items:center;gap:8px;cursor:pointer}.column-chooser-reset{margin-top:4px;padding:0;border:none;background:none;color:var(--p-primary-color);cursor:pointer;align-self:flex-start;font-size:.875rem}.column-chooser-reset:hover{text-decoration:underline}:host ::ng-deep .clickable{cursor:pointer}:host ::ng-deep td.clickable:hover{text-decoration:underline}:host ::ng-deep .p-datatable-thead{position:unset!important}:host ::ng-deep .p-datatable-header{border-radius:6px 6px 0 0}:host ::ng-deep .p-datatable{border-radius:var(--p-content-border-radius);border:1px solid var(--p-datatable-border-color)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "ngmodule", type: SpiderlyControlsModule }, { kind: "component", type: SpiderlyButtonComponent, selector: "spiderly-button", inputs: ["type"] }, { kind: "component", type: SpiderlyNumberComponent, selector: "spiderly-number", inputs: ["prefix", "showButtons", "decimal", "maxFractionDigits"] }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i10.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "style", "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", "scrollDirection", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "responsive", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "autoLayout", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "virtualRowHeight", "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.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i10.SortableColumn, selector: "[pSortableColumn]", inputs: ["pSortableColumn", "pSortableColumnDisabled"] }, { kind: "component", type: i10.SortIcon, selector: "p-sortIcon", inputs: ["field"] }, { kind: "component", type: i10.ColumnFilter, selector: "p-columnFilter", inputs: ["field", "type", "display", "showMenu", "matchMode", "operator", "showOperator", "showClearButton", "showApplyButton", "showMatchModes", "showAddButton", "hideOnClear", "placeholder", "matchModeOptions", "maxConstraints", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "locale", "localeMatcher", "currency", "currencyDisplay", "useGrouping", "showButtons", "ariaLabel", "filterButtonProps"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i12.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i4$5.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "style", "styleClass", "panelStyle", "panelStyleClass", "inputId", "disabled", "fluid", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "variant", "appendTo", "dataKey", "name", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "size", "showClear", "autofocus", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "defaultLabel", "placeholder", "options", "filterValue", "itemSize", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i14.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: DatePickerModule }, { kind: "component", type: i4$1.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "style", "styleClass", "inputStyle", "inputId", "name", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "disabled", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "fluid", "icon", "appendTo", "readonlyInput", "shortYearCutoff", "monthNavigator", "yearNavigator", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "required", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "variant", "size", "minDate", "maxDate", "disabledDates", "disabledDays", "yearRange", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "locale", "view", "defaultDate"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i4$2.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["value", "name", "disabled", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "style", "inputStyle", "styleClass", "inputClass", "indeterminate", "size", "formControl", "checkboxIcon", "readonly", "required", "autofocus", "trueValue", "falseValue", "variant"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i5.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }] }); }
4831
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.13", type: SpiderlyDataTableComponent, isStandalone: true, selector: "spiderly-data-table", inputs: { tableTitle: "tableTitle", tableIcon: "tableIcon", items: "items", rows: "rows", cols: "cols", showPaginator: "showPaginator", showCardWrapper: "showCardWrapper", readonly: "readonly", idField: "idField", getPaginatedListObservableMethod: "getPaginatedListObservableMethod", exportListToExcelObservableMethod: "exportListToExcelObservableMethod", deleteItemFromTableObservableMethod: "deleteItemFromTableObservableMethod", deleteListFromTableObservableMethod: "deleteListFromTableObservableMethod", newlySelectedItems: "newlySelectedItems", unselectedItems: "unselectedItems", selectionMode: "selectionMode", selectedLazyLoadObservableMethod: "selectedLazyLoadObservableMethod", additionalFilterIdLong: "additionalFilterIdLong", showAddButton: "showAddButton", showExportToExcelButton: "showExportToExcelButton", showReloadTableButton: "showReloadTableButton", getFormArrayItems: "getFormArrayItems", hasLazyLoad: "hasLazyLoad", stateKey: "stateKey", stateStorage: "stateStorage", defaultSortField: "defaultSortField", defaultSortOrder: "defaultSortOrder", getAlreadySelectedItemIds: "getAlreadySelectedItemIds", getAlreadySelectedItems: "getAlreadySelectedItems", getFormControl: "getFormControl", additionalIndexes: "additionalIndexes", navigateOnRowClick: "navigateOnRowClick", rowNavigationPath: "rowNavigationPath" }, outputs: { onTotalRecordsChange: "onTotalRecordsChange", onLazyLoad: "onLazyLoad", onIsAllSelectedChange: "onIsAllSelectedChange", onRowSelect: "onRowSelect", onRowUnselect: "onRowUnselect" }, queries: [{ propertyName: "actionsTemplate", first: true, predicate: SpiderlyDataTableActionsDirective, descendants: true, read: TemplateRef }, { propertyName: "cellTemplates", predicate: SpiderlyCellTemplateDirective }], viewQueries: [{ propertyName: "table", first: true, predicate: ["dt"], descendants: true }], ngImport: i0, template: "<ng-container *transloco=\"let t\">\n <div\n [class]=\"\n showCardWrapper ? 'card responsive-card-padding overflow-auto' : ''\n \"\n >\n <p-table\n #dt\n [value]=\"items\"\n [rows]=\"rows\"\n [rowHover]=\"true\"\n [paginator]=\"showPaginator\"\n responsiveLayout=\"scroll\"\n [lazy]=\"hasLazyLoad\"\n (onLazyLoad)=\"lazyLoad($event)\"\n [totalRecords]=\"totalRecords\"\n class=\"spiderly-table\"\n [loading]=\"items === undefined || loading === true\"\n [selectionMode]=\"selectionMode\"\n dataKey=\"id\"\n (onFilter)=\"filter($event)\"\n sortMode=\"multiple\"\n [multiSortMeta]=\"initialMultiSortMeta\"\n [stateKey]=\"resolvedStateKey\"\n [stateStorage]=\"stateStorage\"\n >\n <ng-template pTemplate=\"caption\">\n <div class=\"table-header overflow-auto\">\n <div style=\"display: flex; align-items: center; gap: 8px\">\n <i class=\"{{ tableIcon }}\" style=\"font-size: 20px\"></i>\n <div style=\"margin: 0px; font-size: 17.5px\">{{ tableTitle }}</div>\n </div>\n <div style=\"display: flex; gap: 8px\">\n <ng-container\n *ngIf=\"actionsTemplate\"\n [ngTemplateOutlet]=\"actionsTemplate\"\n ></ng-container>\n <button\n pButton\n *ngIf=\"hasLazyLoad\"\n data-testid=\"column-chooser-button\"\n [label]=\"t('Columns')\"\n class=\"p-button-outlined\"\n style=\"flex: none\"\n icon=\"pi pi-sliders-h\"\n (click)=\"columnChooser.toggle($event)\"\n ></button>\n <button\n pButton\n [label]=\"t('ClearFilters')\"\n class=\"p-button-outlined\"\n style=\"flex: none\"\n icon=\"pi pi-filter-slash\"\n (click)=\"clear(dt)\"\n ></button>\n <button\n pButton\n *ngIf=\"showExportToExcelButton\"\n [label]=\"t('ExportToExcel')\"\n class=\"p-button-outlined\"\n style=\"flex: none\"\n icon=\"pi pi-download\"\n (click)=\"exportListToExcel()\"\n ></button>\n <button\n pButton\n *ngIf=\"showReloadTableButton\"\n [label]=\"t('Reload')\"\n class=\"p-button-outlined\"\n style=\"flex: none\"\n icon=\"pi pi-refresh\"\n (click)=\"reload()\"\n ></button>\n <button\n pButton\n *ngIf=\"deleteListFromTableObservableMethod && rowsSelectedNumber > 0\"\n [label]=\"t('DeleteSelected') + ' (' + rowsSelectedNumber + ')'\"\n class=\"p-button-danger\"\n style=\"flex: none\"\n icon=\"pi pi-trash\"\n (click)=\"deleteSelectedObjects()\"\n ></button>\n </div>\n </div>\n </ng-template>\n <ng-template pTemplate=\"header\">\n <tr>\n <th style=\"width: 0rem\" *ngIf=\"selectionMode == 'multiple'\">\n <div style=\"display: flex; gap: 8px\">\n <p-checkbox\n *ngIf=\"showSelectAllCheckbox\"\n [disabled]=\"readonly\"\n (onChange)=\"selectAll($event.checked)\"\n [(ngModel)]=\"fakeIsAllSelected\"\n [binary]=\"true\"\n ></p-checkbox>\n ({{ rowsSelectedNumber }})\n </div>\n </th>\n <ng-container *ngFor=\"let col of visibleCols; trackBy: colTrackByFn\">\n <th\n [pSortableColumn]=\"col.field\"\n [pSortableColumnDisabled]=\"!isColumnSortable(col)\"\n [style]=\"getColHeaderWidth(col)\"\n >\n <div\n style=\"\n display: flex;\n justify-content: space-between;\n align-items: center;\n \"\n >\n <span style=\"display: flex; align-items: center; gap: 4px\">\n {{ col.name }}\n <p-sortIcon\n *ngIf=\"isColumnSortable(col)\"\n [field]=\"col.field!\"\n ></p-sortIcon>\n </span>\n <p-columnFilter\n *ngIf=\"col.filterType != null && col.filterType !== 'blob'\"\n [type]=\"col.filterType\"\n [field]=\"col.filterField ?? col.field\"\n display=\"menu\"\n [placeholder]=\"col.filterPlaceholder\"\n [showOperator]=\"false\"\n [showMatchModes]=\"col.showMatchModes\"\n [showAddButton]=\"col.showAddButton\"\n [matchModeOptions]=\"getColMatchModeOptions(col.filterType)\"\n [matchMode]=\"getColMatchMode(col.filterType)\"\n >\n <ng-template\n *ngIf=\"isDropOrMulti(col.filterType)\"\n pTemplate=\"filter\"\n let-value\n let-filter=\"filterCallback\"\n >\n <p-multiSelect\n [ngModel]=\"value\"\n [options]=\"col.dropdownOrMultiselectValues\"\n [placeholder]=\"t('All')\"\n (onChange)=\"filter($event.value)\"\n optionLabel=\"label\"\n optionValue=\"code\"\n [style]=\"{ width: '240px' }\"\n >\n <ng-template let-item pTemplate=\"item\">\n <div class=\"p-multiselect-representative-option\">\n <span class=\"ml-2\">{{ item.label }}</span>\n </div>\n </ng-template>\n </p-multiSelect>\n </ng-template>\n <ng-template\n *ngIf=\"col.filterType == 'date'\"\n pTemplate=\"filter\"\n let-value\n let-filter=\"filterCallback\"\n >\n <p-datepicker\n [ngModel]=\"value\"\n [showTime]=\"col.showTime\"\n (onSelect)=\"filter($event)\"\n ></p-datepicker>\n </ng-template>\n </p-columnFilter>\n </div>\n </th>\n </ng-container>\n </tr>\n </ng-template>\n <ng-template\n pTemplate=\"body\"\n let-rowData\n let-index=\"rowIndex\"\n let-editing=\"editing\"\n >\n <!-- The cell rendering every column gets unless it projects a spiderlyCellTemplate. Declared\n once here rather than inside the column loop, and fed the same context the projected\n template gets, so getRowData is evaluated exactly once per cell either way. -->\n <ng-template #defaultCell let-col=\"col\" let-displayValue=\"displayValue\">\n <ng-container *ngIf=\"col.filterType === 'blob'\">\n <img width=\"45\" [src]=\"displayValue\" alt=\"\" />\n </ng-container>\n <ng-container *ngIf=\"col.filterType !== 'blob'\">\n {{ displayValue }}\n </ng-container>\n </ng-template>\n <tr\n [class.clickable]=\"navigateOnRowClick\"\n (click)=\"onRowClick(rowData)\"\n >\n <td *ngIf=\"selectionMode == 'multiple'\">\n <p-checkbox\n [disabled]=\"readonly\"\n (onChange)=\"selectRow(rowData[idField], rowData.index)\"\n [ngModel]=\"isRowSelected(rowData[idField])\"\n [binary]=\"true\"\n ></p-checkbox>\n </td>\n <ng-container *ngFor=\"let col of visibleCols; trackBy: colTrackByFn\">\n <td\n [style]=\"getStyleForBodyColumn(col)\"\n [class.clickable]=\"col.onCellClick\"\n (click)=\"onCellClick(col, rowData, $event)\"\n *ngIf=\"!col.editable\"\n >\n <div\n style=\"\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 18px;\n \"\n >\n <ng-container\n *ngFor=\"let action of col.actions; trackBy: actionTrackByFn\"\n >\n <span\n [pTooltip]=\"action.name\"\n [class]=\"getClassForAction(action)\"\n [style]=\"getStyleForAction(action)\"\n (click)=\"getMethodForAction(action, rowData, $event)\"\n ></span>\n </ng-container>\n </div>\n <ng-container\n [ngTemplateOutlet]=\"getCellTemplate(col) ?? defaultCell\"\n [ngTemplateOutletContext]=\"{\n $implicit: rowData,\n value: rowData[col.field],\n displayValue: getRowData(rowData, col),\n col: col\n }\"\n ></ng-container>\n </td>\n <td *ngIf=\"col.editable\">\n <spiderly-number\n [control]=\"getFormArrayControlByIndex(col.field, rowData.index)\"\n [showLabel]=\"false\"\n ></spiderly-number>\n </td>\n </ng-container>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"emptymessage\">\n <tr>\n <td\n [attr.colspan]=\"\n visibleCols.length + (selectionMode === 'multiple' ? 1 : 0)\n \"\n >\n {{ t(\"NoRecordsFound\") }}\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"loadingbody\">\n <tr>\n <td\n [attr.colspan]=\"\n visibleCols.length + (selectionMode === 'multiple' ? 1 : 0)\n \"\n >\n {{ t(\"Loading\") }}...\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"paginatorleft\">\n {{ t(\"TotalRecords\") }}: {{ totalRecords }}\n </ng-template>\n <ng-template pTemplate=\"paginatorright\">\n <div style=\"display: flex; justify-content: end; gap: 10px\">\n <spiderly-button\n *ngIf=\"showAddButton\"\n [label]=\"t('AddNew')\"\n icon=\"pi pi-plus\"\n (onClick)=\"navigateToDetails(0)\"\n ></spiderly-button>\n </div>\n </ng-template>\n </p-table>\n <p-popover #columnChooser>\n <div class=\"column-chooser\">\n <label\n *ngFor=\"let col of chooserCols; trackBy: colTrackByFn\"\n data-testid=\"column-chooser-option\"\n class=\"column-chooser-option\"\n >\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"isColumnVisible(col)\"\n [disabled]=\"!canToggleColumn(col)\"\n (onChange)=\"toggleColumn(col, $event.checked)\"\n ></p-checkbox>\n <span>{{ col.name }}</span>\n </label>\n <button\n type=\"button\"\n data-testid=\"column-chooser-reset\"\n class=\"column-chooser-reset\"\n (click)=\"resetColumnVisibility()\"\n >\n {{ t('ResetToDefault') }}\n </button>\n </div>\n </p-popover>\n </div>\n</ng-container>\n", styles: [".table-header{display:flex;justify-content:space-between;align-items:center}@media (max-width: 640px){.table-header{display:flex;flex-direction:column;align-items:start;gap:14px}}.spiderly-table .p-paginator{padding:1rem}@media (min-width: 1400px){.spiderly-table .p-paginator-left-content{position:absolute;padding:14px;left:0}}@media (min-width: 1400px){.spiderly-table .p-paginator-right-content{position:absolute;padding:14px;right:0}}.column-chooser{display:flex;flex-direction:column;gap:8px}.column-chooser-option{display:flex;align-items:center;gap:8px;cursor:pointer}.column-chooser-reset{margin-top:4px;padding:0;border:none;background:none;color:var(--p-primary-color);cursor:pointer;align-self:flex-start;font-size:.875rem}.column-chooser-reset:hover{text-decoration:underline}:host ::ng-deep .clickable{cursor:pointer}:host ::ng-deep td.clickable:hover{text-decoration:underline}:host ::ng-deep .p-datatable-thead{position:unset!important}:host ::ng-deep .p-datatable-header{border-radius:6px 6px 0 0}:host ::ng-deep .p-datatable{border-radius:var(--p-content-border-radius);border:1px solid var(--p-datatable-border-color)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: TranslocoDirective, selector: "[transloco]", inputs: ["transloco", "translocoParams", "translocoScope", "translocoRead", "translocoPrefix", "translocoLang", "translocoLoadingTpl"] }, { kind: "ngmodule", type: SpiderlyControlsModule }, { kind: "component", type: SpiderlyButtonComponent, selector: "spiderly-button", inputs: ["type"] }, { kind: "component", type: SpiderlyNumberComponent, selector: "spiderly-number", inputs: ["prefix", "showButtons", "decimal", "maxFractionDigits"] }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i10.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "style", "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", "scrollDirection", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "responsive", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "autoLayout", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "virtualRowHeight", "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.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i10.SortableColumn, selector: "[pSortableColumn]", inputs: ["pSortableColumn", "pSortableColumnDisabled"] }, { kind: "component", type: i10.SortIcon, selector: "p-sortIcon", inputs: ["field"] }, { kind: "component", type: i10.ColumnFilter, selector: "p-columnFilter", inputs: ["field", "type", "display", "showMenu", "matchMode", "operator", "showOperator", "showClearButton", "showApplyButton", "showMatchModes", "showAddButton", "hideOnClear", "placeholder", "matchModeOptions", "maxConstraints", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "locale", "localeMatcher", "currency", "currencyDisplay", "useGrouping", "showButtons", "ariaLabel", "filterButtonProps"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "directive", type: i12.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "ngmodule", type: MultiSelectModule }, { kind: "component", type: i4$5.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "style", "styleClass", "panelStyle", "panelStyleClass", "inputId", "disabled", "fluid", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "variant", "appendTo", "dataKey", "name", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "size", "showClear", "autofocus", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "defaultLabel", "placeholder", "options", "filterValue", "itemSize", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "ngmodule", type: PopoverModule }, { kind: "component", type: i14.Popover, selector: "p-popover", inputs: ["ariaLabel", "ariaLabelledBy", "dismissable", "style", "styleClass", "appendTo", "autoZIndex", "ariaCloseLabel", "baseZIndex", "focusOnShow", "showTransitionOptions", "hideTransitionOptions"], outputs: ["onShow", "onHide"] }, { kind: "ngmodule", type: DatePickerModule }, { kind: "component", type: i4$1.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "style", "styleClass", "inputStyle", "inputId", "name", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "disabled", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "fluid", "icon", "appendTo", "readonlyInput", "shortYearCutoff", "monthNavigator", "yearNavigator", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "required", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "variant", "size", "minDate", "maxDate", "disabledDates", "disabledDays", "yearRange", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "locale", "view", "defaultDate"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i4$2.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["value", "name", "disabled", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "style", "inputStyle", "styleClass", "inputClass", "indeterminate", "size", "formControl", "checkboxIcon", "readonly", "required", "autofocus", "trueValue", "falseValue", "variant"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i5.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }] }); }
4730
4832
  }
4731
4833
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: SpiderlyDataTableComponent, decorators: [{
4732
4834
  type: Component,
@@ -4742,7 +4844,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImpo
4742
4844
  DatePickerModule,
4743
4845
  CheckboxModule,
4744
4846
  TooltipModule,
4745
- ], template: "<ng-container *transloco=\"let t\">\n <div\n [class]=\"\n showCardWrapper ? 'card responsive-card-padding overflow-auto' : ''\n \"\n >\n <p-table\n #dt\n [value]=\"items\"\n [rows]=\"rows\"\n [rowHover]=\"true\"\n [paginator]=\"showPaginator\"\n responsiveLayout=\"scroll\"\n [lazy]=\"hasLazyLoad\"\n (onLazyLoad)=\"lazyLoad($event)\"\n [totalRecords]=\"totalRecords\"\n class=\"spiderly-table\"\n [loading]=\"items === undefined || loading === true\"\n [selectionMode]=\"selectionMode\"\n dataKey=\"id\"\n (onFilter)=\"filter($event)\"\n sortMode=\"multiple\"\n [multiSortMeta]=\"initialMultiSortMeta\"\n [stateKey]=\"resolvedStateKey\"\n [stateStorage]=\"stateStorage\"\n >\n <ng-template pTemplate=\"caption\">\n <div class=\"table-header overflow-auto\">\n <div style=\"display: flex; align-items: center; gap: 8px\">\n <i class=\"{{ tableIcon }}\" style=\"font-size: 20px\"></i>\n <div style=\"margin: 0px; font-size: 17.5px\">{{ tableTitle }}</div>\n </div>\n <div style=\"display: flex; gap: 8px\">\n <ng-container\n *ngIf=\"actionsTemplate\"\n [ngTemplateOutlet]=\"actionsTemplate\"\n ></ng-container>\n <button\n pButton\n *ngIf=\"hasLazyLoad\"\n data-testid=\"column-chooser-button\"\n [label]=\"t('Columns')\"\n class=\"p-button-outlined\"\n style=\"flex: none\"\n icon=\"pi pi-sliders-h\"\n (click)=\"columnChooser.toggle($event)\"\n ></button>\n <button\n pButton\n [label]=\"t('ClearFilters')\"\n class=\"p-button-outlined\"\n style=\"flex: none\"\n icon=\"pi pi-filter-slash\"\n (click)=\"clear(dt)\"\n ></button>\n <button\n pButton\n *ngIf=\"showExportToExcelButton\"\n [label]=\"t('ExportToExcel')\"\n class=\"p-button-outlined\"\n style=\"flex: none\"\n icon=\"pi pi-download\"\n (click)=\"exportListToExcel()\"\n ></button>\n <button\n pButton\n *ngIf=\"showReloadTableButton\"\n [label]=\"t('Reload')\"\n class=\"p-button-outlined\"\n style=\"flex: none\"\n icon=\"pi pi-refresh\"\n (click)=\"reload()\"\n ></button>\n <button\n pButton\n *ngIf=\"deleteListFromTableObservableMethod && rowsSelectedNumber > 0\"\n [label]=\"t('DeleteSelected') + ' (' + rowsSelectedNumber + ')'\"\n class=\"p-button-danger\"\n style=\"flex: none\"\n icon=\"pi pi-trash\"\n (click)=\"deleteSelectedObjects()\"\n ></button>\n </div>\n </div>\n </ng-template>\n <ng-template pTemplate=\"header\">\n <tr>\n <th style=\"width: 0rem\" *ngIf=\"selectionMode == 'multiple'\">\n <div style=\"display: flex; gap: 8px\">\n <p-checkbox\n *ngIf=\"showSelectAllCheckbox\"\n [disabled]=\"readonly\"\n (onChange)=\"selectAll($event.checked)\"\n [(ngModel)]=\"fakeIsAllSelected\"\n [binary]=\"true\"\n ></p-checkbox>\n ({{ rowsSelectedNumber }})\n </div>\n </th>\n <ng-container *ngFor=\"let col of visibleCols; trackBy: colTrackByFn\">\n <th\n [pSortableColumn]=\"col.field\"\n [pSortableColumnDisabled]=\"col.sortable === false || !col.field\"\n [style]=\"getColHeaderWidth(col.filterType)\"\n >\n <div\n style=\"\n display: flex;\n justify-content: space-between;\n align-items: center;\n \"\n >\n <span style=\"display: flex; align-items: center; gap: 4px\">\n {{ col.name }}\n <p-sortIcon\n *ngIf=\"col.sortable !== false && col.field\"\n [field]=\"col.field!\"\n ></p-sortIcon>\n </span>\n <p-columnFilter\n *ngIf=\"col.filterType != null && col.filterType !== 'blob'\"\n [type]=\"col.filterType\"\n [field]=\"col.filterField ?? col.field\"\n display=\"menu\"\n [placeholder]=\"col.filterPlaceholder\"\n [showOperator]=\"false\"\n [showMatchModes]=\"col.showMatchModes\"\n [showAddButton]=\"col.showAddButton\"\n [matchModeOptions]=\"getColMatchModeOptions(col.filterType)\"\n [matchMode]=\"getColMatchMode(col.filterType)\"\n >\n <ng-template\n *ngIf=\"isDropOrMulti(col.filterType)\"\n pTemplate=\"filter\"\n let-value\n let-filter=\"filterCallback\"\n >\n <p-multiSelect\n [ngModel]=\"value\"\n [options]=\"col.dropdownOrMultiselectValues\"\n [placeholder]=\"t('All')\"\n (onChange)=\"filter($event.value)\"\n optionLabel=\"label\"\n optionValue=\"code\"\n [style]=\"{ width: '240px' }\"\n >\n <ng-template let-item pTemplate=\"item\">\n <div class=\"p-multiselect-representative-option\">\n <span class=\"ml-2\">{{ item.label }}</span>\n </div>\n </ng-template>\n </p-multiSelect>\n </ng-template>\n <ng-template\n *ngIf=\"col.filterType == 'date'\"\n pTemplate=\"filter\"\n let-value\n let-filter=\"filterCallback\"\n >\n <p-datepicker\n [ngModel]=\"value\"\n [showTime]=\"col.showTime\"\n (onSelect)=\"filter($event)\"\n ></p-datepicker>\n </ng-template>\n </p-columnFilter>\n </div>\n </th>\n </ng-container>\n </tr>\n </ng-template>\n <ng-template\n pTemplate=\"body\"\n let-rowData\n let-index=\"rowIndex\"\n let-editing=\"editing\"\n >\n <tr\n [class.clickable]=\"navigateOnRowClick\"\n (click)=\"onRowClick(rowData)\"\n >\n <td *ngIf=\"selectionMode == 'multiple'\">\n <p-checkbox\n [disabled]=\"readonly\"\n (onChange)=\"selectRow(rowData[idField], rowData.index)\"\n [ngModel]=\"isRowSelected(rowData[idField])\"\n [binary]=\"true\"\n ></p-checkbox>\n </td>\n <ng-container *ngFor=\"let col of visibleCols; trackBy: colTrackByFn\">\n <td\n [style]=\"getStyleForBodyColumn(col)\"\n [class.clickable]=\"col.onCellClick\"\n (click)=\"onCellClick(col, rowData, $event)\"\n *ngIf=\"!col.editable\"\n >\n <div\n style=\"\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 18px;\n \"\n >\n <ng-container\n *ngFor=\"let action of col.actions; trackBy: actionTrackByFn\"\n >\n <span\n [pTooltip]=\"action.name\"\n [class]=\"getClassForAction(action)\"\n [style]=\"getStyleForAction(action)\"\n (click)=\"getMethodForAction(action, rowData, $event)\"\n ></span>\n </ng-container>\n </div>\n <ng-container *ngIf=\"col.filterType === 'blob'\">\n <img width=\"45\" [src]=\"getRowData(rowData, col)\" alt=\"\" />\n </ng-container>\n <ng-container *ngIf=\"col.filterType !== 'blob'\">\n {{ getRowData(rowData, col) }}\n </ng-container>\n </td>\n <td *ngIf=\"col.editable\">\n <spiderly-number\n [control]=\"getFormArrayControlByIndex(col.field, rowData.index)\"\n [showLabel]=\"false\"\n ></spiderly-number>\n </td>\n </ng-container>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"emptymessage\">\n <tr>\n <td\n [attr.colspan]=\"\n visibleCols.length + (selectionMode === 'multiple' ? 1 : 0)\n \"\n >\n {{ t(\"NoRecordsFound\") }}\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"loadingbody\">\n <tr>\n <td\n [attr.colspan]=\"\n visibleCols.length + (selectionMode === 'multiple' ? 1 : 0)\n \"\n >\n {{ t(\"Loading\") }}...\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"paginatorleft\">\n {{ t(\"TotalRecords\") }}: {{ totalRecords }}\n </ng-template>\n <ng-template pTemplate=\"paginatorright\">\n <div style=\"display: flex; justify-content: end; gap: 10px\">\n <spiderly-button\n *ngIf=\"showAddButton\"\n [label]=\"t('AddNew')\"\n icon=\"pi pi-plus\"\n (onClick)=\"navigateToDetails(0)\"\n ></spiderly-button>\n </div>\n </ng-template>\n </p-table>\n <p-popover #columnChooser>\n <div class=\"column-chooser\">\n <label\n *ngFor=\"let col of chooserCols; trackBy: colTrackByFn\"\n data-testid=\"column-chooser-option\"\n class=\"column-chooser-option\"\n >\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"isColumnVisible(col)\"\n [disabled]=\"!canToggleColumn(col)\"\n (onChange)=\"toggleColumn(col, $event.checked)\"\n ></p-checkbox>\n <span>{{ col.name }}</span>\n </label>\n <button\n type=\"button\"\n data-testid=\"column-chooser-reset\"\n class=\"column-chooser-reset\"\n (click)=\"resetColumnVisibility()\"\n >\n {{ t('ResetToDefault') }}\n </button>\n </div>\n </p-popover>\n </div>\n</ng-container>\n", styles: [".table-header{display:flex;justify-content:space-between;align-items:center}@media (max-width: 640px){.table-header{display:flex;flex-direction:column;align-items:start;gap:14px}}.spiderly-table .p-paginator{padding:1rem}@media (min-width: 1400px){.spiderly-table .p-paginator-left-content{position:absolute;padding:14px;left:0}}@media (min-width: 1400px){.spiderly-table .p-paginator-right-content{position:absolute;padding:14px;right:0}}.column-chooser{display:flex;flex-direction:column;gap:8px}.column-chooser-option{display:flex;align-items:center;gap:8px;cursor:pointer}.column-chooser-reset{margin-top:4px;padding:0;border:none;background:none;color:var(--p-primary-color);cursor:pointer;align-self:flex-start;font-size:.875rem}.column-chooser-reset:hover{text-decoration:underline}:host ::ng-deep .clickable{cursor:pointer}:host ::ng-deep td.clickable:hover{text-decoration:underline}:host ::ng-deep .p-datatable-thead{position:unset!important}:host ::ng-deep .p-datatable-header{border-radius:6px 6px 0 0}:host ::ng-deep .p-datatable{border-radius:var(--p-content-border-radius);border:1px solid var(--p-datatable-border-color)}\n"] }]
4847
+ ], template: "<ng-container *transloco=\"let t\">\n <div\n [class]=\"\n showCardWrapper ? 'card responsive-card-padding overflow-auto' : ''\n \"\n >\n <p-table\n #dt\n [value]=\"items\"\n [rows]=\"rows\"\n [rowHover]=\"true\"\n [paginator]=\"showPaginator\"\n responsiveLayout=\"scroll\"\n [lazy]=\"hasLazyLoad\"\n (onLazyLoad)=\"lazyLoad($event)\"\n [totalRecords]=\"totalRecords\"\n class=\"spiderly-table\"\n [loading]=\"items === undefined || loading === true\"\n [selectionMode]=\"selectionMode\"\n dataKey=\"id\"\n (onFilter)=\"filter($event)\"\n sortMode=\"multiple\"\n [multiSortMeta]=\"initialMultiSortMeta\"\n [stateKey]=\"resolvedStateKey\"\n [stateStorage]=\"stateStorage\"\n >\n <ng-template pTemplate=\"caption\">\n <div class=\"table-header overflow-auto\">\n <div style=\"display: flex; align-items: center; gap: 8px\">\n <i class=\"{{ tableIcon }}\" style=\"font-size: 20px\"></i>\n <div style=\"margin: 0px; font-size: 17.5px\">{{ tableTitle }}</div>\n </div>\n <div style=\"display: flex; gap: 8px\">\n <ng-container\n *ngIf=\"actionsTemplate\"\n [ngTemplateOutlet]=\"actionsTemplate\"\n ></ng-container>\n <button\n pButton\n *ngIf=\"hasLazyLoad\"\n data-testid=\"column-chooser-button\"\n [label]=\"t('Columns')\"\n class=\"p-button-outlined\"\n style=\"flex: none\"\n icon=\"pi pi-sliders-h\"\n (click)=\"columnChooser.toggle($event)\"\n ></button>\n <button\n pButton\n [label]=\"t('ClearFilters')\"\n class=\"p-button-outlined\"\n style=\"flex: none\"\n icon=\"pi pi-filter-slash\"\n (click)=\"clear(dt)\"\n ></button>\n <button\n pButton\n *ngIf=\"showExportToExcelButton\"\n [label]=\"t('ExportToExcel')\"\n class=\"p-button-outlined\"\n style=\"flex: none\"\n icon=\"pi pi-download\"\n (click)=\"exportListToExcel()\"\n ></button>\n <button\n pButton\n *ngIf=\"showReloadTableButton\"\n [label]=\"t('Reload')\"\n class=\"p-button-outlined\"\n style=\"flex: none\"\n icon=\"pi pi-refresh\"\n (click)=\"reload()\"\n ></button>\n <button\n pButton\n *ngIf=\"deleteListFromTableObservableMethod && rowsSelectedNumber > 0\"\n [label]=\"t('DeleteSelected') + ' (' + rowsSelectedNumber + ')'\"\n class=\"p-button-danger\"\n style=\"flex: none\"\n icon=\"pi pi-trash\"\n (click)=\"deleteSelectedObjects()\"\n ></button>\n </div>\n </div>\n </ng-template>\n <ng-template pTemplate=\"header\">\n <tr>\n <th style=\"width: 0rem\" *ngIf=\"selectionMode == 'multiple'\">\n <div style=\"display: flex; gap: 8px\">\n <p-checkbox\n *ngIf=\"showSelectAllCheckbox\"\n [disabled]=\"readonly\"\n (onChange)=\"selectAll($event.checked)\"\n [(ngModel)]=\"fakeIsAllSelected\"\n [binary]=\"true\"\n ></p-checkbox>\n ({{ rowsSelectedNumber }})\n </div>\n </th>\n <ng-container *ngFor=\"let col of visibleCols; trackBy: colTrackByFn\">\n <th\n [pSortableColumn]=\"col.field\"\n [pSortableColumnDisabled]=\"!isColumnSortable(col)\"\n [style]=\"getColHeaderWidth(col)\"\n >\n <div\n style=\"\n display: flex;\n justify-content: space-between;\n align-items: center;\n \"\n >\n <span style=\"display: flex; align-items: center; gap: 4px\">\n {{ col.name }}\n <p-sortIcon\n *ngIf=\"isColumnSortable(col)\"\n [field]=\"col.field!\"\n ></p-sortIcon>\n </span>\n <p-columnFilter\n *ngIf=\"col.filterType != null && col.filterType !== 'blob'\"\n [type]=\"col.filterType\"\n [field]=\"col.filterField ?? col.field\"\n display=\"menu\"\n [placeholder]=\"col.filterPlaceholder\"\n [showOperator]=\"false\"\n [showMatchModes]=\"col.showMatchModes\"\n [showAddButton]=\"col.showAddButton\"\n [matchModeOptions]=\"getColMatchModeOptions(col.filterType)\"\n [matchMode]=\"getColMatchMode(col.filterType)\"\n >\n <ng-template\n *ngIf=\"isDropOrMulti(col.filterType)\"\n pTemplate=\"filter\"\n let-value\n let-filter=\"filterCallback\"\n >\n <p-multiSelect\n [ngModel]=\"value\"\n [options]=\"col.dropdownOrMultiselectValues\"\n [placeholder]=\"t('All')\"\n (onChange)=\"filter($event.value)\"\n optionLabel=\"label\"\n optionValue=\"code\"\n [style]=\"{ width: '240px' }\"\n >\n <ng-template let-item pTemplate=\"item\">\n <div class=\"p-multiselect-representative-option\">\n <span class=\"ml-2\">{{ item.label }}</span>\n </div>\n </ng-template>\n </p-multiSelect>\n </ng-template>\n <ng-template\n *ngIf=\"col.filterType == 'date'\"\n pTemplate=\"filter\"\n let-value\n let-filter=\"filterCallback\"\n >\n <p-datepicker\n [ngModel]=\"value\"\n [showTime]=\"col.showTime\"\n (onSelect)=\"filter($event)\"\n ></p-datepicker>\n </ng-template>\n </p-columnFilter>\n </div>\n </th>\n </ng-container>\n </tr>\n </ng-template>\n <ng-template\n pTemplate=\"body\"\n let-rowData\n let-index=\"rowIndex\"\n let-editing=\"editing\"\n >\n <!-- The cell rendering every column gets unless it projects a spiderlyCellTemplate. Declared\n once here rather than inside the column loop, and fed the same context the projected\n template gets, so getRowData is evaluated exactly once per cell either way. -->\n <ng-template #defaultCell let-col=\"col\" let-displayValue=\"displayValue\">\n <ng-container *ngIf=\"col.filterType === 'blob'\">\n <img width=\"45\" [src]=\"displayValue\" alt=\"\" />\n </ng-container>\n <ng-container *ngIf=\"col.filterType !== 'blob'\">\n {{ displayValue }}\n </ng-container>\n </ng-template>\n <tr\n [class.clickable]=\"navigateOnRowClick\"\n (click)=\"onRowClick(rowData)\"\n >\n <td *ngIf=\"selectionMode == 'multiple'\">\n <p-checkbox\n [disabled]=\"readonly\"\n (onChange)=\"selectRow(rowData[idField], rowData.index)\"\n [ngModel]=\"isRowSelected(rowData[idField])\"\n [binary]=\"true\"\n ></p-checkbox>\n </td>\n <ng-container *ngFor=\"let col of visibleCols; trackBy: colTrackByFn\">\n <td\n [style]=\"getStyleForBodyColumn(col)\"\n [class.clickable]=\"col.onCellClick\"\n (click)=\"onCellClick(col, rowData, $event)\"\n *ngIf=\"!col.editable\"\n >\n <div\n style=\"\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 18px;\n \"\n >\n <ng-container\n *ngFor=\"let action of col.actions; trackBy: actionTrackByFn\"\n >\n <span\n [pTooltip]=\"action.name\"\n [class]=\"getClassForAction(action)\"\n [style]=\"getStyleForAction(action)\"\n (click)=\"getMethodForAction(action, rowData, $event)\"\n ></span>\n </ng-container>\n </div>\n <ng-container\n [ngTemplateOutlet]=\"getCellTemplate(col) ?? defaultCell\"\n [ngTemplateOutletContext]=\"{\n $implicit: rowData,\n value: rowData[col.field],\n displayValue: getRowData(rowData, col),\n col: col\n }\"\n ></ng-container>\n </td>\n <td *ngIf=\"col.editable\">\n <spiderly-number\n [control]=\"getFormArrayControlByIndex(col.field, rowData.index)\"\n [showLabel]=\"false\"\n ></spiderly-number>\n </td>\n </ng-container>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"emptymessage\">\n <tr>\n <td\n [attr.colspan]=\"\n visibleCols.length + (selectionMode === 'multiple' ? 1 : 0)\n \"\n >\n {{ t(\"NoRecordsFound\") }}\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"loadingbody\">\n <tr>\n <td\n [attr.colspan]=\"\n visibleCols.length + (selectionMode === 'multiple' ? 1 : 0)\n \"\n >\n {{ t(\"Loading\") }}...\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"paginatorleft\">\n {{ t(\"TotalRecords\") }}: {{ totalRecords }}\n </ng-template>\n <ng-template pTemplate=\"paginatorright\">\n <div style=\"display: flex; justify-content: end; gap: 10px\">\n <spiderly-button\n *ngIf=\"showAddButton\"\n [label]=\"t('AddNew')\"\n icon=\"pi pi-plus\"\n (onClick)=\"navigateToDetails(0)\"\n ></spiderly-button>\n </div>\n </ng-template>\n </p-table>\n <p-popover #columnChooser>\n <div class=\"column-chooser\">\n <label\n *ngFor=\"let col of chooserCols; trackBy: colTrackByFn\"\n data-testid=\"column-chooser-option\"\n class=\"column-chooser-option\"\n >\n <p-checkbox\n [binary]=\"true\"\n [ngModel]=\"isColumnVisible(col)\"\n [disabled]=\"!canToggleColumn(col)\"\n (onChange)=\"toggleColumn(col, $event.checked)\"\n ></p-checkbox>\n <span>{{ col.name }}</span>\n </label>\n <button\n type=\"button\"\n data-testid=\"column-chooser-reset\"\n class=\"column-chooser-reset\"\n (click)=\"resetColumnVisibility()\"\n >\n {{ t('ResetToDefault') }}\n </button>\n </div>\n </p-popover>\n </div>\n</ng-container>\n", styles: [".table-header{display:flex;justify-content:space-between;align-items:center}@media (max-width: 640px){.table-header{display:flex;flex-direction:column;align-items:start;gap:14px}}.spiderly-table .p-paginator{padding:1rem}@media (min-width: 1400px){.spiderly-table .p-paginator-left-content{position:absolute;padding:14px;left:0}}@media (min-width: 1400px){.spiderly-table .p-paginator-right-content{position:absolute;padding:14px;right:0}}.column-chooser{display:flex;flex-direction:column;gap:8px}.column-chooser-option{display:flex;align-items:center;gap:8px;cursor:pointer}.column-chooser-reset{margin-top:4px;padding:0;border:none;background:none;color:var(--p-primary-color);cursor:pointer;align-self:flex-start;font-size:.875rem}.column-chooser-reset:hover{text-decoration:underline}:host ::ng-deep .clickable{cursor:pointer}:host ::ng-deep td.clickable:hover{text-decoration:underline}:host ::ng-deep .p-datatable-thead{position:unset!important}:host ::ng-deep .p-datatable-header{border-radius:6px 6px 0 0}:host ::ng-deep .p-datatable{border-radius:var(--p-content-border-radius);border:1px solid var(--p-datatable-border-color)}\n"] }]
4746
4848
  }], ctorParameters: () => [{ type: i3$2.Router }, { type: i1$5.DialogService }, { type: i3$2.ActivatedRoute }, { type: SpiderlyMessageService }, { type: i1.TranslocoService }, { type: ConfigServiceBase }, { type: undefined, decorators: [{
4747
4849
  type: Inject,
4748
4850
  args: [LOCALE_ID]
@@ -4752,6 +4854,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImpo
4752
4854
  }], actionsTemplate: [{
4753
4855
  type: ContentChild,
4754
4856
  args: [SpiderlyDataTableActionsDirective, { read: TemplateRef }]
4857
+ }], cellTemplates: [{
4858
+ type: ContentChildren,
4859
+ args: [SpiderlyCellTemplateDirective]
4755
4860
  }], tableTitle: [{
4756
4861
  type: Input
4757
4862
  }], tableIcon: [{
@@ -4840,7 +4945,7 @@ class Action {
4840
4945
  }
4841
4946
  }
4842
4947
  class Column {
4843
- constructor({ name, field, filterField, filterType, filterPlaceholder, showMatchModes, showAddButton, dropdownOrMultiselectValues, actions, editable, showTime, decimalPlaces, sortable, visible, lockVisible, onCellClick, } = {}) {
4948
+ constructor({ name, field, filterField, filterType, filterPlaceholder, showMatchModes, showAddButton, dropdownOrMultiselectValues, actions, editable, showTime, decimalPlaces, sortable, visible, lockVisible, minWidth, onCellClick, } = {}) {
4844
4949
  this.name = name;
4845
4950
  this.field = field;
4846
4951
  this.filterField = filterField;
@@ -4856,6 +4961,7 @@ class Column {
4856
4961
  this.sortable = sortable;
4857
4962
  this.visible = visible;
4858
4963
  this.lockVisible = lockVisible;
4964
+ this.minWidth = minWidth;
4859
4965
  this.onCellClick = onCellClick;
4860
4966
  }
4861
4967
  }
@@ -5302,21 +5408,31 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImpo
5302
5408
  }]
5303
5409
  }], ctorParameters: () => [{ type: AuthServiceBase }] });
5304
5410
 
5411
+ /**
5412
+ * The app's global {@link ErrorHandler}: logs the error and shows the generic error toast. HTTP
5413
+ * errors are skipped entirely — `unauthorizedInterceptor` owns them end to end and has already
5414
+ * logged the failed request and shown the message matched to its status.
5415
+ *
5416
+ * Logging is unconditional, production included. The toast tells the user the team was notified,
5417
+ * and unless the app wires an error tracker this line is the only place the error exists — so
5418
+ * staying quiet in production left a deployed app with a red toast and nothing to open. The
5419
+ * console is a developer surface; a user never sees it.
5420
+ *
5421
+ * An error tracker plugs in by providing an `ErrorHandler` that reports and then delegates here,
5422
+ * which keeps this class's toast copy true (see the PACMS admin's `AdminErrorHandler`).
5423
+ */
5305
5424
  class SpiderlyErrorHandler {
5306
- constructor(messageService, translocoService, config) {
5425
+ constructor(messageService, translocoService) {
5307
5426
  this.messageService = messageService;
5308
5427
  this.translocoService = translocoService;
5309
- this.config = config;
5310
5428
  }
5311
5429
  handleError(error) {
5312
- if (this.config.production == false) {
5313
- console.error(error);
5314
- }
5315
- if (error instanceof HttpErrorResponse == false) {
5316
- this.messageService.errorMessage(this.translocoService.translate('UnexpectedErrorDetails'), this.translocoService.translate('UnexpectedErrorTitle'));
5317
- }
5430
+ if (error instanceof HttpErrorResponse)
5431
+ return;
5432
+ console.error(error);
5433
+ this.messageService.errorMessage(this.translocoService.translate('UnexpectedErrorDetails'), this.translocoService.translate('UnexpectedErrorTitle'));
5318
5434
  }
5319
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: SpiderlyErrorHandler, deps: [{ token: SpiderlyMessageService }, { token: i1.TranslocoService }, { token: ConfigServiceBase }], target: i0.ɵɵFactoryTarget.Injectable }); }
5435
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: SpiderlyErrorHandler, deps: [{ token: SpiderlyMessageService }, { token: i1.TranslocoService }], target: i0.ɵɵFactoryTarget.Injectable }); }
5320
5436
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: SpiderlyErrorHandler, providedIn: 'root' }); }
5321
5437
  }
5322
5438
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: SpiderlyErrorHandler, decorators: [{
@@ -5324,7 +5440,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImpo
5324
5440
  args: [{
5325
5441
  providedIn: 'root',
5326
5442
  }]
5327
- }], ctorParameters: () => [{ type: SpiderlyMessageService }, { type: i1.TranslocoService }, { type: ConfigServiceBase }] });
5443
+ }], ctorParameters: () => [{ type: SpiderlyMessageService }, { type: i1.TranslocoService }] });
5328
5444
 
5329
5445
  const httpLoadingInterceptor = (req, next) => {
5330
5446
  const spinner = inject(NgxSpinnerService);
@@ -5429,12 +5545,15 @@ const jwtInterceptor = (req, next) => {
5429
5545
  const unauthorizedInterceptor = (req, next) => {
5430
5546
  const messageService = inject(SpiderlyMessageService);
5431
5547
  const translocoService = inject(TranslocoService);
5432
- const config = inject(ConfigServiceBase);
5433
5548
  const authService = inject(AuthServiceBase);
5434
5549
  const reactToError = (err, request) => {
5435
- if (!config.production) {
5436
- console.error(err);
5437
- }
5550
+ // Unconditional, production included, and the only log for a failed request (the global
5551
+ // ErrorHandler skips HTTP errors): the toast the user gets is deliberately vague, so this is
5552
+ // where a developer reads which request failed and how. See SpiderlyErrorHandler for why
5553
+ // silence in production cost more than the console noise saves. The summary leads because an
5554
+ // HttpErrorResponse on its own stringifies to "[object HttpErrorResponse]" in an error
5555
+ // tracker's console breadcrumb; the object still follows, to expand in devtools.
5556
+ console.error(`HTTP ${err.status} ${request.method} ${request.url}`, err);
5438
5557
  // TODO: type this as an ApiError interface (TS mirror of ApiErrorDTO, next to errors/api-error-codes.ts)
5439
5558
  // so message/errorCode/traceId reads of the cross-language contract are compile-checked, not conventional.
5440
5559
  let errorResponse = err.error;
@@ -5538,5 +5657,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImpo
5538
5657
  * Generated bundle index. Do not edit.
5539
5658
  */
5540
5659
 
5541
- export { Action, AllClickEvent, ApiErrorCodes, ApiSecurityService, AppSidebarComponent, AuthCardComponent, AuthGuard, AuthResult, AuthResultWithCookies, AuthServiceBase, BaseAutocompleteControl, BaseControl, BaseDropdownControl, BaseEntity, BaseFormComponent, BaseFormService, CardSkeletonComponent, Codebook, Column, ConfigServiceBase, DEFAULT_EXTERNAL_PROVIDER_ICONS, ExternalLoginComponent, ExternalProvider, ExternalProviderPublic, Filter, FilterRule, FilterSortMeta, FooterComponent, IndexCardComponent, InfoCardComponent, InitCompanyAuthDialogDetails, InitTopBarData, IsAuthorizedForSaveEvent, LastMenuIconIndexClicked, LayoutServiceBase, LazyLoadSelectedIdsResult, Login, LoginVerificationComponent, LoginVerificationToken, MatchModeCodes, MenuChangeEvent, MenuitemComponent, Namebook, NotAuthGuard, NotFoundComponent, PROPS_KEY, PaginatedResult, PanelBodyComponent, PanelFooterComponent, PanelHeaderComponent, PrimengOption, ProfileAvatarComponent, ReflectProp, RefreshTokenRequest, RequiredComponent, RowClickEvent, SecurityPermissionCodes, SendLoginVerificationEmailResult, SideMenuTopBarComponent, SidebarMenuComponent, SimpleSaveResult, SpiderlyAutocompleteComponent, SpiderlyButtonBaseComponent, SpiderlyButtonComponent, SpiderlyCalendarComponent, SpiderlyCardComponent, SpiderlyCheckboxComponent, SpiderlyColorPickerComponent, SpiderlyControlsModule, SpiderlyDataTableActionsDirective, SpiderlyDataTableComponent, SpiderlyDataViewComponent, SpiderlyDeleteConfirmationComponent, SpiderlyDropdownComponent, SpiderlyEditorComponent, SpiderlyErrorHandler, SpiderlyFileComponent, SpiderlyFileSelectEvent, SpiderlyFormArray, SpiderlyFormControl, SpiderlyFormGroup, SpiderlyLayoutComponent, SpiderlyLoginComponent, SpiderlyMarkdownComponent, SpiderlyMessageService, SpiderlyMultiAutocompleteComponent, SpiderlyMultiSelectComponent, SpiderlyNumberComponent, SpiderlyPanelComponent, SpiderlyPanelsModule, SpiderlyPasswordComponent, SpiderlyReturnButtonComponent, SpiderlySplitButtonComponent, SpiderlyTab, SpiderlyTemplateTypeDirective, SpiderlyTextareaComponent, SpiderlyTextboxComponent, SpiderlyTranslocoLoader, TopBarComponent, UserBase, UserRole, ValidatorAbstractService, VerificationTokenRequest, VerificationTypeCodes, VerificationWrapperComponent, adjustColor, authInitializer, capitalizeFirstChar, deleteAction, exportListToExcel, firstCharToUpper, getFileNameFromContentDisposition, getHtmlImgDisplayString64, getImageDimensions, getMimeTypeForFileName, getMonth, getParentUrl, getPrimengAutocompleteCodebookOptions, getPrimengAutocompleteNamebookOptions, getPrimengDropdownCodebookOptions, getPrimengDropdownNamebookOptions, getPrimengNamebookOptions, httpLoadingInterceptor, isExcelFileType, isFileImageType, isNullOrEmpty, jsonHttpInterceptor, jwtInterceptor, kebabToTitleCase, nameOf, nameof, parseDateOnlyLocal, pushAction, saveResponseAsFile, selectedTab, singleOrDefault, splitPascalCase, toCommaSeparatedString, unauthorizedInterceptor, validatePrecisionScale };
5660
+ export { Action, AllClickEvent, ApiErrorCodes, ApiSecurityService, AppSidebarComponent, AuthCardComponent, AuthGuard, AuthResult, AuthResultWithCookies, AuthServiceBase, BaseAutocompleteControl, BaseControl, BaseDropdownControl, BaseEntity, BaseFormComponent, BaseFormService, CardSkeletonComponent, Codebook, Column, ConfigServiceBase, DEFAULT_EXTERNAL_PROVIDER_ICONS, ExternalLoginComponent, ExternalProvider, ExternalProviderPublic, Filter, FilterRule, FilterSortMeta, FooterComponent, IndexCardComponent, InfoCardComponent, InitCompanyAuthDialogDetails, InitTopBarData, IsAuthorizedForSaveEvent, LastMenuIconIndexClicked, LayoutServiceBase, LazyLoadSelectedIdsResult, Login, LoginVerificationComponent, LoginVerificationToken, MatchModeCodes, MenuChangeEvent, MenuitemComponent, Namebook, NotAuthGuard, NotFoundComponent, PROPS_KEY, PaginatedResult, PanelBodyComponent, PanelFooterComponent, PanelHeaderComponent, PrimengOption, ProfileAvatarComponent, ReflectProp, RefreshTokenRequest, RequiredComponent, RowClickEvent, SecurityPermissionCodes, SendLoginVerificationEmailResult, SideMenuTopBarComponent, SidebarMenuComponent, SimpleSaveResult, SpiderlyAutocompleteComponent, SpiderlyButtonBaseComponent, SpiderlyButtonComponent, SpiderlyCalendarComponent, SpiderlyCardComponent, SpiderlyCellTemplateDirective, SpiderlyCheckboxComponent, SpiderlyColorPickerComponent, SpiderlyControlsModule, SpiderlyDataTableActionsDirective, SpiderlyDataTableComponent, SpiderlyDataViewComponent, SpiderlyDeleteConfirmationComponent, SpiderlyDropdownComponent, SpiderlyEditorComponent, SpiderlyErrorHandler, SpiderlyFileComponent, SpiderlyFileSelectEvent, SpiderlyFormArray, SpiderlyFormControl, SpiderlyFormGroup, SpiderlyLayoutComponent, SpiderlyLoginComponent, SpiderlyMarkdownComponent, SpiderlyMessageService, SpiderlyMultiAutocompleteComponent, SpiderlyMultiSelectComponent, SpiderlyNumberComponent, SpiderlyPanelComponent, SpiderlyPanelsModule, SpiderlyPasswordComponent, SpiderlyReturnButtonComponent, SpiderlySplitButtonComponent, SpiderlyTab, SpiderlyTemplateTypeDirective, SpiderlyTextareaComponent, SpiderlyTextboxComponent, SpiderlyTranslocoLoader, TopBarComponent, UserBase, UserRole, ValidatorAbstractService, VerificationTokenRequest, VerificationTypeCodes, VerificationWrapperComponent, adjustColor, authInitializer, capitalizeFirstChar, deleteAction, exportListToExcel, firstCharToUpper, getFileNameFromContentDisposition, getHtmlImgDisplayString64, getImageDimensions, getMimeTypeForFileName, getMonth, getParentUrl, getPrimengAutocompleteCodebookOptions, getPrimengAutocompleteNamebookOptions, getPrimengDropdownCodebookOptions, getPrimengDropdownNamebookOptions, getPrimengNamebookOptions, httpLoadingInterceptor, isExcelFileType, isFileImageType, isNullOrEmpty, jsonHttpInterceptor, jwtInterceptor, kebabToTitleCase, nameOf, nameof, parseDateOnlyLocal, pushAction, saveResponseAsFile, selectedTab, singleOrDefault, splitPascalCase, toCommaSeparatedString, unauthorizedInterceptor, validatePrecisionScale };
5542
5661
  //# sourceMappingURL=spiderly.mjs.map