spiderly 19.11.8 → 19.11.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent/docs/angular-customization/index.md +34 -1
- package/agent/docs/angular-customization/references/helper-functions.generated.md +1 -0
- package/fesm2022/spiderly.mjs +396 -75
- package/fesm2022/spiderly.mjs.map +1 -1
- package/lib/components/spiderly-data-table/spiderly-data-table.component.d.ts +160 -14
- package/lib/components/spiderly-data-view/spiderly-data-view.component.d.ts +8 -1
- package/lib/services/helper-functions.d.ts +6 -0
- package/package.json +1 -1
- package/styles/components/spiderly-data-table/spiderly-data-table.component.scss +34 -0
- package/styles/components/spiderly-data-view/spiderly-data-view.component.scss +16 -0
- package/styles/styles/layout/_content.scss +1 -1
- package/styles/styles/layout/_main.scss +15 -1
- package/styles/styles/layout/_menu.scss +1 -1
- package/styles/styles/layout/_mixins.scss +33 -0
- package/styles/styles/layout/_topbar.scss +4 -4
package/fesm2022/spiderly.mjs
CHANGED
|
@@ -723,6 +723,31 @@ function getImageDimensions(file) {
|
|
|
723
723
|
img.src = URL.createObjectURL(file);
|
|
724
724
|
});
|
|
725
725
|
}
|
|
726
|
+
/**
|
|
727
|
+
* Scrolls `element` back under the top of the viewport, but only when it has already scrolled
|
|
728
|
+
* above it. Set the element's `scroll-margin-top` to whatever fixed chrome must stay clear.
|
|
729
|
+
* Assumes the element's nearest scroll container is the viewport itself.
|
|
730
|
+
*/
|
|
731
|
+
// This is the one full telling of the three decisions below; paging is the caller (see
|
|
732
|
+
// spiderly-data-table/CLAUDE.md → "Scroll back to the table on page change").
|
|
733
|
+
// - The offset is READ from CSS rather than passed in, so the amount of fixed chrome to clear
|
|
734
|
+
// stays declared in one place per component and no TypeScript knows the shell's dimensions.
|
|
735
|
+
// That read is also why the viewport assumption above matters: getBoundingClientRect is
|
|
736
|
+
// viewport-relative, so inside a consumer's own overflow container it measures the wrong box.
|
|
737
|
+
// - The early return is what stops a list sitting BELOW other page content (a table inside a
|
|
738
|
+
// details form) from shoving that content off-screen when it was already visible.
|
|
739
|
+
// - `behavior: 'instant'` overrides the element's CSS `scroll-behavior`; `'auto'` defers to it,
|
|
740
|
+
// so an app setting `html { scroll-behavior: smooth }` would animate every call.
|
|
741
|
+
function scrollElementIntoViewIfAboveViewport(element) {
|
|
742
|
+
const offset = parseFloat(getComputedStyle(element).scrollMarginTop) || 0;
|
|
743
|
+
if (element.getBoundingClientRect().top >= offset)
|
|
744
|
+
return;
|
|
745
|
+
element.scrollIntoView({
|
|
746
|
+
block: 'start',
|
|
747
|
+
inline: 'nearest',
|
|
748
|
+
behavior: 'instant',
|
|
749
|
+
});
|
|
750
|
+
}
|
|
726
751
|
|
|
727
752
|
class SpiderlyCalendarComponent extends BaseControl {
|
|
728
753
|
constructor(translocoService) {
|
|
@@ -3976,14 +4001,32 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImpo
|
|
|
3976
4001
|
args: [{ selector: 'spiderly-delete-confirmation', imports: [SpiderlyButtonComponent, TranslocoDirective, ConfirmDialogModule], providers: [ConfirmationService], template: "<ng-container *transloco=\"let t\">\n <p-confirmDialog #cd></p-confirmDialog>\n <div\n class=\"border-b surface-border text-lg\"\n style=\"\n display: flex;\n align-items: center;\n padding-bottom: 10px;\n width: 100%;\n gap: 10px;\n \"\n >\n <i class=\"pi pi-exclamation-circle text-4xl\"></i>\n <p>{{ config.data.message }}</p>\n </div>\n\n <div\n style=\"display: flex; gap: 12px; justify-content: right; margin-top: 28px\"\n >\n <spiderly-button\n (onClick)=\"reject()\"\n icon=\"pi pi-times\"\n [label]=\"t('Cancel')\"\n severity=\"secondary\"\n ></spiderly-button>\n <spiderly-button\n (onClick)=\"accept()\"\n icon=\"pi pi-check\"\n [label]=\"t('Confirm')\"\n styleClass=\"p-button-danger\"\n ></spiderly-button>\n </div>\n</ng-container>\n" }]
|
|
3977
4002
|
}], ctorParameters: () => [{ type: i1$5.DynamicDialogRef }, { type: i1$5.DynamicDialogConfig }] });
|
|
3978
4003
|
|
|
4004
|
+
/**
|
|
4005
|
+
* Default column width per filter type, in rem. Sized for the HEADER — the filter input plus its
|
|
4006
|
+
* match-mode dropdown — so a column of short values reserves more than its content needs; that is
|
|
4007
|
+
* deliberate, and {@link Column.width} is the per-column override.
|
|
4008
|
+
*
|
|
4009
|
+
* A table, not a switch, so the mapping is exhaustive: a new `filterType` fails the build here
|
|
4010
|
+
* instead of silently inheriting the actions-column reservation below.
|
|
4011
|
+
*/
|
|
4012
|
+
const DEFAULT_COLUMN_WIDTH_REM = {
|
|
4013
|
+
text: 12,
|
|
4014
|
+
date: 10,
|
|
4015
|
+
multiselect: 12,
|
|
4016
|
+
boolean: 8,
|
|
4017
|
+
numeric: 12,
|
|
4018
|
+
// Fits the 45px thumbnail `#defaultCell` renders for a blob.
|
|
4019
|
+
blob: 5,
|
|
4020
|
+
};
|
|
3979
4021
|
class SpiderlyDataTableComponent {
|
|
3980
|
-
constructor(router, dialogService, route, messageService, translocoService, configService, locale) {
|
|
4022
|
+
constructor(router, dialogService, route, messageService, translocoService, configService, errorHandler, locale) {
|
|
3981
4023
|
this.router = router;
|
|
3982
4024
|
this.dialogService = dialogService;
|
|
3983
4025
|
this.route = route;
|
|
3984
4026
|
this.messageService = messageService;
|
|
3985
4027
|
this.translocoService = translocoService;
|
|
3986
4028
|
this.configService = configService;
|
|
4029
|
+
this.errorHandler = errorHandler;
|
|
3987
4030
|
this.locale = locale;
|
|
3988
4031
|
this.destroy$ = new Subject();
|
|
3989
4032
|
this.tableIcon = 'pi pi-list';
|
|
@@ -3995,6 +4038,17 @@ class SpiderlyDataTableComponent {
|
|
|
3995
4038
|
this.showCardWrapper = false;
|
|
3996
4039
|
this.readonly = false;
|
|
3997
4040
|
this.idField = 'id';
|
|
4041
|
+
/**
|
|
4042
|
+
* Sizes the columns from their declared widths instead of from the rendered rows.
|
|
4043
|
+
*
|
|
4044
|
+
* The browser default is `table-layout: auto`, which computes every column from the content
|
|
4045
|
+
* of the rows currently on screen — so a column is one width on this page and another on the
|
|
4046
|
+
* next, and a filter (which narrows the variety of values in the column it filters) moves the
|
|
4047
|
+
* whole grid. PrimeNG sets no `table-layout` of its own, so without this the table inherits
|
|
4048
|
+
* that default. Bound to a field, never an object literal in the template: a literal is a new
|
|
4049
|
+
* reference on every change-detection pass.
|
|
4050
|
+
*/
|
|
4051
|
+
this.tableStyle = { 'table-layout': 'fixed' };
|
|
3998
4052
|
this.onTotalRecordsChange = new EventEmitter();
|
|
3999
4053
|
this.loading = true;
|
|
4000
4054
|
this.newlySelectedItems = [];
|
|
@@ -4012,6 +4066,7 @@ class SpiderlyDataTableComponent {
|
|
|
4012
4066
|
this.onIsAllSelectedChange = new EventEmitter();
|
|
4013
4067
|
this.matchModeDateOptions = [];
|
|
4014
4068
|
this.matchModeNumberOptions = [];
|
|
4069
|
+
this.matchModeTextOptions = [];
|
|
4015
4070
|
/** Whether the "Add" button is shown. Defaults to `true`. */
|
|
4016
4071
|
this.showAddButton = true;
|
|
4017
4072
|
/** Whether the "Export to Excel" button is shown. Defaults to `true`. */
|
|
@@ -4054,7 +4109,25 @@ class SpiderlyDataTableComponent {
|
|
|
4054
4109
|
* transient safety reveal into a durable choice.
|
|
4055
4110
|
*/
|
|
4056
4111
|
this.revealedByConstraint = new Set();
|
|
4112
|
+
/**
|
|
4113
|
+
* The filter keys the rows on screen were actually narrowed by. Kept apart from
|
|
4114
|
+
* `table.filters` because those are not the same question: PrimeNG's `onModelChange`
|
|
4115
|
+
* writes each keystroke of a text/numeric filter straight into the meta and only calls
|
|
4116
|
+
* `_filter()` for the auto-applying types, so `table.filters` holds PENDING edits too.
|
|
4117
|
+
* Reading it for the header icon marked a column filtered the moment the operator typed
|
|
4118
|
+
* a character, before Apply — claiming the grid was narrowed when it was not.
|
|
4119
|
+
*/
|
|
4120
|
+
this.appliedFilterKeys = new Set();
|
|
4057
4121
|
this.clientFilterCount = 0;
|
|
4122
|
+
/**
|
|
4123
|
+
* Memo for the resolution below. Two jobs: the narrowing maps to a NEW array and a
|
|
4124
|
+
* template binding must not hand PrimeNG a fresh reference every CD pass, and both
|
|
4125
|
+
* halves (offered list, default mode) must come from ONE computation so they cannot
|
|
4126
|
+
* disagree. Keyed on the declared array's identity, so reassigning `col.matchModes`
|
|
4127
|
+
* recomputes — note PrimeNG itself reads `matchModeOptions` only in its own `ngOnInit`,
|
|
4128
|
+
* so a post-init change still never reaches the rendered dropdown.
|
|
4129
|
+
*/
|
|
4130
|
+
this.matchModeResolutions = new WeakMap();
|
|
4058
4131
|
}
|
|
4059
4132
|
ngAfterViewInit() {
|
|
4060
4133
|
this.setupRemovableSort();
|
|
@@ -4156,6 +4229,24 @@ class SpiderlyDataTableComponent {
|
|
|
4156
4229
|
value: MatchModeCodes.GreaterThan,
|
|
4157
4230
|
},
|
|
4158
4231
|
];
|
|
4232
|
+
// Only the three the generated paginator implements for strings
|
|
4233
|
+
// (PaginatedResultGenerator.GetCaseForString). Declared rather than left to PrimeNG,
|
|
4234
|
+
// whose own text list adds notContains/endsWith/notEquals — modes the backend answers
|
|
4235
|
+
// with InvalidMatchMode, i.e. a 400 on every load once the user picks one.
|
|
4236
|
+
this.matchModeTextOptions = [
|
|
4237
|
+
{
|
|
4238
|
+
label: this.translocoService.translate('StartsWith'),
|
|
4239
|
+
value: MatchModeCodes.StartsWith,
|
|
4240
|
+
},
|
|
4241
|
+
{
|
|
4242
|
+
label: this.translocoService.translate('Contains'),
|
|
4243
|
+
value: MatchModeCodes.Contains,
|
|
4244
|
+
},
|
|
4245
|
+
{
|
|
4246
|
+
label: this.translocoService.translate('Equals'),
|
|
4247
|
+
value: MatchModeCodes.Equals,
|
|
4248
|
+
},
|
|
4249
|
+
];
|
|
4159
4250
|
this.matchModeNumberOptions = [
|
|
4160
4251
|
{
|
|
4161
4252
|
label: this.translocoService.translate('Equals'),
|
|
@@ -4183,6 +4274,10 @@ class SpiderlyDataTableComponent {
|
|
|
4183
4274
|
this.mergeActivePageSizesIntoOptions();
|
|
4184
4275
|
this.restoreColumnVisibility();
|
|
4185
4276
|
this.reconcileVisibilityWithPersistedConstraints();
|
|
4277
|
+
this.reconcilePersistedMatchModes();
|
|
4278
|
+
// Restored filters are applied by definition — mark them before the first paint rather
|
|
4279
|
+
// than waiting for the first response, which is the reload case the icon exists for.
|
|
4280
|
+
this.snapshotAppliedFilters(this.persistedTableState()?.filters);
|
|
4186
4281
|
this.chooserCols = this.cols.filter(SpiderlyDataTableComponent.isDataColumn);
|
|
4187
4282
|
this.refreshVisibleCols();
|
|
4188
4283
|
// Bound to p-table's [multiSortMeta] so the FIRST request already carries the right
|
|
@@ -4262,9 +4357,8 @@ class SpiderlyDataTableComponent {
|
|
|
4262
4357
|
return;
|
|
4263
4358
|
let cleared = false;
|
|
4264
4359
|
for (const col of cols) {
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
delete this.table.filters[filterKey];
|
|
4360
|
+
if (this.columnHasConstraint(this.table, col)) {
|
|
4361
|
+
delete this.table.filters[this.filterKey(col)];
|
|
4268
4362
|
cleared = true;
|
|
4269
4363
|
}
|
|
4270
4364
|
if (this.table._multiSortMeta?.some((m) => m.field === col.field)) {
|
|
@@ -4282,6 +4376,40 @@ class SpiderlyDataTableComponent {
|
|
|
4282
4376
|
m.value !== '' &&
|
|
4283
4377
|
(!Array.isArray(m.value) || m.value.length > 0));
|
|
4284
4378
|
}
|
|
4379
|
+
/**
|
|
4380
|
+
* The one home of the filter-state key rule (sort meta is keyed by `field` instead).
|
|
4381
|
+
* Instance rather than static so the template's `[field]` binding can share it.
|
|
4382
|
+
*/
|
|
4383
|
+
filterKey(col) {
|
|
4384
|
+
return col.filterField ?? col.field;
|
|
4385
|
+
}
|
|
4386
|
+
/**
|
|
4387
|
+
* Whether the rows on screen are narrowed by this column — feeds the projected
|
|
4388
|
+
* `filtericon` template. Why not the template's `let-hasFilter`, and why applied rather
|
|
4389
|
+
* than pending state: CLAUDE.md → "Active-filter header icon".
|
|
4390
|
+
*/
|
|
4391
|
+
isColumnFiltered(col) {
|
|
4392
|
+
return this.appliedFilterKeys.has(this.filterKey(col));
|
|
4393
|
+
}
|
|
4394
|
+
/** Whether the column carries a constraint at all, applied or still being typed. */
|
|
4395
|
+
columnHasConstraint(table, col) {
|
|
4396
|
+
return SpiderlyDataTableComponent.isActiveFilterMeta(table.filters?.[this.filterKey(col)]);
|
|
4397
|
+
}
|
|
4398
|
+
/**
|
|
4399
|
+
* Records what a just-applied filter set narrows by. Called from every path that commits
|
|
4400
|
+
* one: `(onFilter)` (Apply, auto-apply, a per-column Clear), `lazyLoad` (which also covers
|
|
4401
|
+
* `table.clear()` — it re-queries WITHOUT emitting onFilter), the caption's Clear filters,
|
|
4402
|
+
* and once from `ngOnInit` off persisted state, so a restored filter is marked on first
|
|
4403
|
+
* paint rather than after the first response.
|
|
4404
|
+
*/
|
|
4405
|
+
snapshotAppliedFilters(filters) {
|
|
4406
|
+
const applied = new Set();
|
|
4407
|
+
for (const [field, meta] of Object.entries(filters ?? {})) {
|
|
4408
|
+
if (SpiderlyDataTableComponent.isActiveFilterMeta(meta))
|
|
4409
|
+
applied.add(field);
|
|
4410
|
+
}
|
|
4411
|
+
this.appliedFilterKeys = applied;
|
|
4412
|
+
}
|
|
4285
4413
|
persistColumnVisibility() {
|
|
4286
4414
|
if (!this.columnsStateKey)
|
|
4287
4415
|
return;
|
|
@@ -4331,7 +4459,7 @@ class SpiderlyDataTableComponent {
|
|
|
4331
4459
|
continue;
|
|
4332
4460
|
if (this.isColumnVisible(col))
|
|
4333
4461
|
continue;
|
|
4334
|
-
if (constrained.has(col
|
|
4462
|
+
if (constrained.has(this.filterKey(col)) || constrained.has(col.field)) {
|
|
4335
4463
|
this.revealedByConstraint.add(col.field);
|
|
4336
4464
|
}
|
|
4337
4465
|
}
|
|
@@ -4374,6 +4502,47 @@ class SpiderlyDataTableComponent {
|
|
|
4374
4502
|
return col == null || this.isColumnSortable(col);
|
|
4375
4503
|
});
|
|
4376
4504
|
}
|
|
4505
|
+
/**
|
|
4506
|
+
* The filter twin of `keepSortableMeta` — persisted state outlives the rule that produced
|
|
4507
|
+
* it, here a match mode stored before the column declared `matchModes`. It has to REWRITE
|
|
4508
|
+
* storage rather than filter a value on the way past: `ColumnFilter.ngOnInit` skips
|
|
4509
|
+
* `initFieldFilterConstraint()` whenever the field already carries a constraint, so our
|
|
4510
|
+
* `[matchMode]` never applies to a restored one. Left alone, the column keeps filtering by
|
|
4511
|
+
* a mode it no longer offers while its match-mode `<p-select>` renders blank (the stored
|
|
4512
|
+
* value is not among the options). Runs before PrimeNG's `restoreState()`, which reads this
|
|
4513
|
+
* same key on the first `[value]` change.
|
|
4514
|
+
*
|
|
4515
|
+
* Deliberately narrow: it touches only constraints whose mode the declaring column no
|
|
4516
|
+
* longer offers, so every other byte of the persisted blob survives.
|
|
4517
|
+
*/
|
|
4518
|
+
reconcilePersistedMatchModes() {
|
|
4519
|
+
if (!this.resolvedStateKey)
|
|
4520
|
+
return;
|
|
4521
|
+
const state = this.persistedTableState();
|
|
4522
|
+
if (!state?.filters)
|
|
4523
|
+
return;
|
|
4524
|
+
let changed = false;
|
|
4525
|
+
for (const col of this.cols ?? []) {
|
|
4526
|
+
if (!col.matchModes?.length)
|
|
4527
|
+
continue;
|
|
4528
|
+
const offered = this.getColMatchModeOptions(col);
|
|
4529
|
+
const meta = state.filters[this.filterKey(col)];
|
|
4530
|
+
if (!offered?.length || !Array.isArray(meta))
|
|
4531
|
+
continue;
|
|
4532
|
+
for (const constraint of meta) {
|
|
4533
|
+
if (constraint?.matchMode == null)
|
|
4534
|
+
continue;
|
|
4535
|
+
if (offered.some((option) => option.value === constraint.matchMode))
|
|
4536
|
+
continue;
|
|
4537
|
+
constraint.matchMode = this.getColMatchMode(col);
|
|
4538
|
+
changed = true;
|
|
4539
|
+
}
|
|
4540
|
+
}
|
|
4541
|
+
if (!changed)
|
|
4542
|
+
return;
|
|
4543
|
+
const storage = this.stateStorage === 'local' ? localStorage : sessionStorage;
|
|
4544
|
+
storage.setItem(this.resolvedStateKey, JSON.stringify(state));
|
|
4545
|
+
}
|
|
4377
4546
|
// Safety net: any lazy load still leaving unsorted (Clear filters — PrimeNG's clear()
|
|
4378
4547
|
// nulls the sort and emits in one call — or stale persisted state) falls back to the
|
|
4379
4548
|
// declared default. Patching the event before it becomes the backend Filter avoids a
|
|
@@ -4392,58 +4561,112 @@ class SpiderlyDataTableComponent {
|
|
|
4392
4561
|
this.table.tableService.onSort(defaultSort);
|
|
4393
4562
|
}
|
|
4394
4563
|
}
|
|
4564
|
+
onPageChange(container) {
|
|
4565
|
+
scrollElementIntoViewIfAboveViewport(container);
|
|
4566
|
+
}
|
|
4567
|
+
/**
|
|
4568
|
+
* The one pending predicate: PrimeNG's overlay and the container's `aria-busy` must never
|
|
4569
|
+
* disagree about whether a fetch is in flight.
|
|
4570
|
+
*
|
|
4571
|
+
* It used to also test `items === undefined`, for the first load. That clause is dead now
|
|
4572
|
+
* that `loading` initialises true and every lazyLoad raises it — except in the one state
|
|
4573
|
+
* where it was actively wrong: a FAILED first load lowers the flag with `items` still
|
|
4574
|
+
* undefined, which pinned the overlay up forever. Same stranded overlay this component was
|
|
4575
|
+
* fixed for once already, through the other door.
|
|
4576
|
+
*/
|
|
4577
|
+
get isPending() {
|
|
4578
|
+
return this.loading;
|
|
4579
|
+
}
|
|
4395
4580
|
lazyLoad(event) {
|
|
4581
|
+
// Every refetch is pending, not just the first load and reload(). `items` is deliberately
|
|
4582
|
+
// left alone: the previous page stays on screen under the overlay (stale-while-revalidate)
|
|
4583
|
+
// rather than blanking. Raising the flag is also what stops PrimeNG's empty message, gated
|
|
4584
|
+
// on `isEmpty() && !loading`, from claiming "no records" for the length of the request.
|
|
4585
|
+
this.loading = true;
|
|
4396
4586
|
this.applyDefaultSortIfUnsorted(event);
|
|
4397
4587
|
this.lastLazyLoadEvent = event;
|
|
4398
4588
|
this.rangeAnchorId = null;
|
|
4589
|
+
this.snapshotAppliedFilters(event.filters);
|
|
4399
4590
|
let tableFilter = event;
|
|
4400
4591
|
tableFilter.additionalFilterIdLong = this.additionalFilterIdLong;
|
|
4401
4592
|
this.onLazyLoad.next(tableFilter);
|
|
4593
|
+
// Issued NOW rather than after the list lands: it needs only `tableFilter`, so serialising
|
|
4594
|
+
// it behind the list response cost a second round trip on every page of every
|
|
4595
|
+
// selection-enabled table — and the overlay is held up for both. The `.catch` at creation
|
|
4596
|
+
// is mandatory, not defensive: when the list request errors, `next` never runs, and a
|
|
4597
|
+
// rejected promise nobody awaits is exactly the unowned rejection this handler exists to
|
|
4598
|
+
// prevent. The rejection is re-thrown out of `awaitSelectedIds` instead, where it has one.
|
|
4599
|
+
const selectedIds = this.selectedLazyLoadObservableMethod != null
|
|
4600
|
+
? firstValueFrom(this.selectedLazyLoadObservableMethod(tableFilter)).catch((error) => error)
|
|
4601
|
+
: null;
|
|
4402
4602
|
this.getPaginatedListObservableMethod(tableFilter).subscribe({
|
|
4403
4603
|
next: async (res) => {
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
this.
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
if (this.isFirstTimeLazyLoad == true) {
|
|
4413
|
-
this.rowsSelectedNumber =
|
|
4414
|
-
selectedRowsMethodResult.totalRecordsSelected;
|
|
4415
|
-
this.setFakeIsAllSelected();
|
|
4416
|
-
this.isFirstTimeLazyLoad = false;
|
|
4417
|
-
}
|
|
4418
|
-
if (this.isAllSelected == true) {
|
|
4419
|
-
let idsToInsert = [...this.items.map((x) => x[this.idField])];
|
|
4420
|
-
idsToInsert = idsToInsert.filter((x) => this.unselectedItems.includes(x) == false);
|
|
4421
|
-
this.fakeSelectedItems = [...idsToInsert]; // Only for showing checkboxes, we will not send this to the backend
|
|
4422
|
-
}
|
|
4423
|
-
else if (this.isAllSelected == false) {
|
|
4424
|
-
this.fakeSelectedItems = [...this.newlySelectedItems]; // Only for showing checkboxes, we will not send this to the backend
|
|
4425
|
-
}
|
|
4426
|
-
else if (this.isAllSelected == null) {
|
|
4427
|
-
let idsToInsert = [
|
|
4428
|
-
...selectedRowsMethodResult.selectedIds,
|
|
4429
|
-
...this.newlySelectedItems,
|
|
4430
|
-
];
|
|
4431
|
-
idsToInsert = idsToInsert.filter((x) => this.unselectedItems.includes(x) == false);
|
|
4432
|
-
this.fakeSelectedItems = [...idsToInsert];
|
|
4433
|
-
}
|
|
4604
|
+
// The await below is INSIDE an async subscriber, so a rejection there settles nothing:
|
|
4605
|
+
// `error:` belongs to the paginated-list observable and never runs. That used to strand
|
|
4606
|
+
// the overlay forever, hence the finally.
|
|
4607
|
+
try {
|
|
4608
|
+
this.items = res.data;
|
|
4609
|
+
this.totalRecords = res.totalRecords;
|
|
4610
|
+
this.onTotalRecordsChange.next(res.totalRecords);
|
|
4611
|
+
await this.reconcileSelectionForLoadedPage(selectedIds);
|
|
4434
4612
|
}
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4613
|
+
catch (error) {
|
|
4614
|
+
// The library's own owner: it toasts, it skips HttpErrorResponse (the interceptor
|
|
4615
|
+
// already reported those), and a consumer's ErrorHandler wrapper forwards to their
|
|
4616
|
+
// tracker. console.error here would have dropped both.
|
|
4617
|
+
this.errorHandler.handleError(error);
|
|
4618
|
+
}
|
|
4619
|
+
finally {
|
|
4620
|
+
this.loading = false;
|
|
4439
4621
|
}
|
|
4440
|
-
this.loading = false;
|
|
4441
4622
|
},
|
|
4442
4623
|
error: () => {
|
|
4443
4624
|
this.loading = false;
|
|
4444
4625
|
},
|
|
4445
4626
|
});
|
|
4446
4627
|
}
|
|
4628
|
+
/**
|
|
4629
|
+
* Repaints the checkbox column for the page that just landed. Split out of the subscriber so
|
|
4630
|
+
* the try/finally that guarantees the pending flag wraps an await, not fifty lines of
|
|
4631
|
+
* selection algebra.
|
|
4632
|
+
*/
|
|
4633
|
+
async reconcileSelectionForLoadedPage(selectedIds) {
|
|
4634
|
+
if (selectedIds == null) {
|
|
4635
|
+
if (this.deleteListFromTableObservableMethod) {
|
|
4636
|
+
this.fakeSelectedItems = this.items
|
|
4637
|
+
.map((x) => x[this.idField])
|
|
4638
|
+
.filter((id) => this.newlySelectedItems.includes(id));
|
|
4639
|
+
}
|
|
4640
|
+
return;
|
|
4641
|
+
}
|
|
4642
|
+
const selectedRowsMethodResult = await selectedIds;
|
|
4643
|
+
if (selectedRowsMethodResult instanceof Error)
|
|
4644
|
+
throw selectedRowsMethodResult;
|
|
4645
|
+
this.currentPageSelectedItemsFromDb = [
|
|
4646
|
+
...selectedRowsMethodResult.selectedIds,
|
|
4647
|
+
];
|
|
4648
|
+
if (this.isFirstTimeLazyLoad == true) {
|
|
4649
|
+
this.rowsSelectedNumber = selectedRowsMethodResult.totalRecordsSelected;
|
|
4650
|
+
this.setFakeIsAllSelected();
|
|
4651
|
+
this.isFirstTimeLazyLoad = false;
|
|
4652
|
+
}
|
|
4653
|
+
if (this.isAllSelected == true) {
|
|
4654
|
+
let idsToInsert = [...this.items.map((x) => x[this.idField])];
|
|
4655
|
+
idsToInsert = idsToInsert.filter((x) => this.unselectedItems.includes(x) == false);
|
|
4656
|
+
this.fakeSelectedItems = [...idsToInsert]; // Only for showing checkboxes, we will not send this to the backend
|
|
4657
|
+
}
|
|
4658
|
+
else if (this.isAllSelected == false) {
|
|
4659
|
+
this.fakeSelectedItems = [...this.newlySelectedItems]; // Only for showing checkboxes, we will not send this to the backend
|
|
4660
|
+
}
|
|
4661
|
+
else if (this.isAllSelected == null) {
|
|
4662
|
+
let idsToInsert = [
|
|
4663
|
+
...selectedRowsMethodResult.selectedIds,
|
|
4664
|
+
...this.newlySelectedItems,
|
|
4665
|
+
];
|
|
4666
|
+
idsToInsert = idsToInsert.filter((x) => this.unselectedItems.includes(x) == false);
|
|
4667
|
+
this.fakeSelectedItems = [...idsToInsert];
|
|
4668
|
+
}
|
|
4669
|
+
}
|
|
4447
4670
|
clientLoad() {
|
|
4448
4671
|
this.loading = false;
|
|
4449
4672
|
this.loadFormArrayItems();
|
|
@@ -4459,6 +4682,8 @@ class SpiderlyDataTableComponent {
|
|
|
4459
4682
|
this.setFakeIsAllSelected();
|
|
4460
4683
|
}
|
|
4461
4684
|
filter(event) {
|
|
4685
|
+
// Fires from _filter(), i.e. only once a filter is COMMITTED — never on a keystroke.
|
|
4686
|
+
this.snapshotAppliedFilters(event.filters ?? this.table?.filters);
|
|
4462
4687
|
if (this.hasLazyLoad && this.selectionMode === 'multiple')
|
|
4463
4688
|
this.selectAll(false); // We need to do it like this because: totalRecords: 1 -> selectedRecords from earlyer selection 2 -> unselect current -> all checkbox is set to true
|
|
4464
4689
|
if (this.hasLazyLoad === false && this.selectionMode === 'multiple') {
|
|
@@ -4490,29 +4715,76 @@ class SpiderlyDataTableComponent {
|
|
|
4490
4715
|
!!col.field &&
|
|
4491
4716
|
!col.field.endsWith('CommaSeparated'));
|
|
4492
4717
|
}
|
|
4493
|
-
/**
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
|
|
4509
|
-
|
|
4510
|
-
}
|
|
4718
|
+
/**
|
|
4719
|
+
* The column's declared {@link Column.width}, or the default for its filter type.
|
|
4720
|
+
*
|
|
4721
|
+
* A width, not a minimum: under the fixed layout {@link tableStyle} establishes, this is what
|
|
4722
|
+
* the column is sized from, and the table shares its surplus in PROPORTION to these numbers.
|
|
4723
|
+
* Columns declaring none would otherwise take an equal share, which throws away what the
|
|
4724
|
+
* per-type defaults say — a boolean holds "Da"/"Ne", a text column holds a name.
|
|
4725
|
+
*/
|
|
4726
|
+
getColWidth(col) {
|
|
4727
|
+
if (col.width != null)
|
|
4728
|
+
return col.width;
|
|
4729
|
+
if (col.filterType)
|
|
4730
|
+
return `${DEFAULT_COLUMN_WIDTH_REM[col.filterType]}rem`;
|
|
4731
|
+
// What is left declares no filterType: an actions column. It cannot shrink to fit any more,
|
|
4732
|
+
// so the icons need a reservation — each sits in a flex row whose gap is set beside them in
|
|
4733
|
+
// the template, inside the cell's own padding. 2.5, not 2.2, so the arithmetic stays exact in
|
|
4734
|
+
// binary and the string never reads `8.6000000001rem`.
|
|
4735
|
+
return `${2 + (col.actions?.length ?? 0) * 2.5}rem`;
|
|
4736
|
+
}
|
|
4737
|
+
getColMatchModeOptions(col) {
|
|
4738
|
+
return this.resolveMatchModes(col).options;
|
|
4739
|
+
}
|
|
4740
|
+
getColMatchMode(col) {
|
|
4741
|
+
return this.resolveMatchModes(col).defaultMode;
|
|
4742
|
+
}
|
|
4743
|
+
resolveMatchModes(col) {
|
|
4744
|
+
const cached = this.matchModeResolutions.get(col);
|
|
4745
|
+
if (cached && cached.source === col.matchModes)
|
|
4746
|
+
return cached.resolution;
|
|
4747
|
+
const resolution = this.computeMatchModes(col);
|
|
4748
|
+
this.matchModeResolutions.set(col, {
|
|
4749
|
+
source: col.matchModes,
|
|
4750
|
+
resolution,
|
|
4751
|
+
});
|
|
4752
|
+
return resolution;
|
|
4511
4753
|
}
|
|
4512
|
-
|
|
4754
|
+
/**
|
|
4755
|
+
* Applies `Column.matchModes`, and refuses to half-apply it. Both ways a declaration can
|
|
4756
|
+
* be wrong are consumer mistakes that PrimeNG would otherwise turn into a broken filter
|
|
4757
|
+
* rather than an error: it reads `matchModeOptions || <type defaults>`, so handing it
|
|
4758
|
+
* `[]` renders an EMPTY dropdown (an empty array is truthy) while the default mode still
|
|
4759
|
+
* seeds the constraint, and handing it `null` silently restores PrimeNG's own list. So an
|
|
4760
|
+
* unusable narrowing falls back to the full list and says so, instead of shipping a
|
|
4761
|
+
* dropdown the user cannot pick from.
|
|
4762
|
+
*/
|
|
4763
|
+
computeMatchModes(col) {
|
|
4764
|
+
const options = this.matchModeOptionsForType(col.filterType);
|
|
4765
|
+
const typeDefault = this.defaultMatchModeForType(col.filterType);
|
|
4766
|
+
const declared = col.matchModes;
|
|
4767
|
+
if (!declared?.length)
|
|
4768
|
+
return { options, defaultMode: typeDefault };
|
|
4769
|
+
if (!options?.length) {
|
|
4770
|
+
console.error(`spiderly-data-table: column "${col.field}" declares matchModes, but filterType "${col.filterType}" has no match modes to narrow — ignoring.`);
|
|
4771
|
+
return { options, defaultMode: typeDefault };
|
|
4772
|
+
}
|
|
4773
|
+
const narrowed = declared
|
|
4774
|
+
.map((code) => options.find((option) => option.value === code))
|
|
4775
|
+
.filter((option) => option != null);
|
|
4776
|
+
if (narrowed.length !== declared.length) {
|
|
4777
|
+
const unsupported = declared.filter((code) => !options.some((option) => option.value === code));
|
|
4778
|
+
console.error(`spiderly-data-table: column "${col.field}" declares match mode(s) [${unsupported.join(', ')}] that filterType "${col.filterType}" does not support — ignoring them.`);
|
|
4779
|
+
}
|
|
4780
|
+
if (!narrowed.length)
|
|
4781
|
+
return { options, defaultMode: typeDefault };
|
|
4782
|
+
return { options: narrowed, defaultMode: narrowed[0].value };
|
|
4783
|
+
}
|
|
4784
|
+
matchModeOptionsForType(filterType) {
|
|
4513
4785
|
switch (filterType) {
|
|
4514
4786
|
case 'text':
|
|
4515
|
-
return
|
|
4787
|
+
return this.matchModeTextOptions;
|
|
4516
4788
|
case 'date':
|
|
4517
4789
|
return this.matchModeDateOptions;
|
|
4518
4790
|
case 'multiselect':
|
|
@@ -4525,7 +4797,7 @@ class SpiderlyDataTableComponent {
|
|
|
4525
4797
|
return null;
|
|
4526
4798
|
}
|
|
4527
4799
|
}
|
|
4528
|
-
|
|
4800
|
+
defaultMatchModeForType(filterType) {
|
|
4529
4801
|
switch (filterType) {
|
|
4530
4802
|
case 'text':
|
|
4531
4803
|
return MatchModeCodes.Contains;
|
|
@@ -4549,6 +4821,30 @@ class SpiderlyDataTableComponent {
|
|
|
4549
4821
|
return false;
|
|
4550
4822
|
}
|
|
4551
4823
|
}
|
|
4824
|
+
/**
|
|
4825
|
+
* Whether the filter type applies on every value change, which hides the menu's Apply
|
|
4826
|
+
* button — an Apply there would promise a pending state that cannot exist. Boolean
|
|
4827
|
+
* auto-applies through PrimeNG's own `onModelChange`; date and dropdown/multiselect
|
|
4828
|
+
* through the filter templates THIS component projects, which call `filterCallback`
|
|
4829
|
+
* directly (PrimeNG's built-in element, and with it its `onModelChange`, is only
|
|
4830
|
+
* rendered when no template is projected — so the date path is ours, not PrimeNG's).
|
|
4831
|
+
* With showApplyButton off, PrimeNG also auto-applies match-mode, operator and
|
|
4832
|
+
* constraint-removal changes, so the whole menu stays consistent. Typed input
|
|
4833
|
+
* (text/numeric) is deliberately NOT here — it commits on Enter/Apply, since applying
|
|
4834
|
+
* per keystroke would fire a lazy load per key. Listing the auto types (not the typed
|
|
4835
|
+
* ones) is the safe polarity: an unlisted future type keeps its Apply button rather
|
|
4836
|
+
* than silently losing its commit.
|
|
4837
|
+
*
|
|
4838
|
+
* Known gap this does not close, and it predates the flag: the projected date template
|
|
4839
|
+
* binds `[ngModel]` one-way and commits on `(onSelect)`, which the datepicker raises for
|
|
4840
|
+
* a calendar pick but not for `onUserInput` — so a date TYPED into the field never
|
|
4841
|
+
* reaches the constraint at all, with or without an Apply button.
|
|
4842
|
+
*/
|
|
4843
|
+
filterAppliesOnChange(filterType) {
|
|
4844
|
+
return (filterType === 'boolean' ||
|
|
4845
|
+
filterType === 'date' ||
|
|
4846
|
+
this.isDropOrMulti(filterType));
|
|
4847
|
+
}
|
|
4552
4848
|
/*
|
|
4553
4849
|
* Navigate to details page based on rowId and rowNavigationPath.
|
|
4554
4850
|
* If rowNavigationPath is provided, it will navigate to that path with the rowId.
|
|
@@ -4661,8 +4957,10 @@ class SpiderlyDataTableComponent {
|
|
|
4661
4957
|
this.fakeIsAllSelected = false;
|
|
4662
4958
|
}
|
|
4663
4959
|
reload() {
|
|
4664
|
-
|
|
4665
|
-
this.
|
|
4960
|
+
// Nothing to replay before the table's own initial load, which is already on its way.
|
|
4961
|
+
if (this.lastLazyLoadEvent == null)
|
|
4962
|
+
return;
|
|
4963
|
+
// Not special: same refetch as a page flip, so lazyLoad owns both the flag and `items`.
|
|
4666
4964
|
this.lazyLoad(this.lastLazyLoadEvent);
|
|
4667
4965
|
}
|
|
4668
4966
|
showActions() {
|
|
@@ -4761,6 +5059,9 @@ class SpiderlyDataTableComponent {
|
|
|
4761
5059
|
clear(table) {
|
|
4762
5060
|
table.clear();
|
|
4763
5061
|
table.clearState();
|
|
5062
|
+
// clear() re-queries without emitting (onFilter), so the icons would keep their fill
|
|
5063
|
+
// on a client-side table; on a lazy one lazyLoad already covers it.
|
|
5064
|
+
this.snapshotAppliedFilters(table.filters);
|
|
4764
5065
|
}
|
|
4765
5066
|
//#region Selection
|
|
4766
5067
|
setFakeIsAllSelected() {
|
|
@@ -4933,8 +5234,8 @@ class SpiderlyDataTableComponent {
|
|
|
4933
5234
|
return null;
|
|
4934
5235
|
}
|
|
4935
5236
|
}
|
|
4936
|
-
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 }); }
|
|
4937
|
-
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", rowsPerPageOptions: "rowsPerPageOptions", 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 }], usesOnChanges: 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 [rowsPerPageOptions]=\"rowsPerPageOptions\"\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, $event)\"\n >\n <!-- row-interactive: a selection gesture must never double as row navigation (onRowClick). -->\n <td\n *ngIf=\"selectionMode == 'multiple'\"\n class=\"selection-cell row-interactive\"\n (mousedown)=\"onSelectionCellMouseDown($event, rowData[idField])\"\n >\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 [class.row-interactive]=\"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) + ' row-interactive'\"\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\" class=\"row-interactive\">\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 td.selection-cell{-webkit-user-select:none;user-select:none}: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"] }] }); }
|
|
5237
|
+
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: i0.ErrorHandler }, { token: LOCALE_ID }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5238
|
+
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", rowsPerPageOptions: "rowsPerPageOptions", 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 }], usesOnChanges: true, ngImport: i0, template: "<ng-container *transloco=\"let t\">\n <div\n #tableContainer\n class=\"spiderly-table-container\"\n [attr.aria-busy]=\"isPending\"\n [ngClass]=\"{\n 'card responsive-card-padding overflow-auto': showCardWrapper\n }\"\n >\n <p-table\n #dt\n [value]=\"items\"\n [rows]=\"rows\"\n [rowsPerPageOptions]=\"rowsPerPageOptions\"\n [rowHover]=\"true\"\n [paginator]=\"showPaginator\"\n responsiveLayout=\"scroll\"\n [lazy]=\"hasLazyLoad\"\n (onLazyLoad)=\"lazyLoad($event)\"\n (onPage)=\"onPageChange(tableContainer)\"\n [totalRecords]=\"totalRecords\"\n class=\"spiderly-table\"\n [loading]=\"isPending\"\n [selectionMode]=\"selectionMode\"\n dataKey=\"id\"\n (onFilter)=\"filter($event)\"\n sortMode=\"multiple\"\n [multiSortMeta]=\"initialMultiSortMeta\"\n [stateKey]=\"resolvedStateKey\"\n [stateStorage]=\"stateStorage\"\n [tableStyle]=\"tableStyle\"\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 <!-- Sized for the checkbox plus the counter beside it, which shows `totalRecords` on a\n select-all and so reaches five digits on a large table. Not `0rem` (see CLAUDE.md \u2192\n Column widths), and not routed through getColWidth: this column has no `Column`. -->\n <th style=\"width: 6rem\" *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.width]=\"getColWidth(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 <!-- hideOnClear: Apply is what closes this menu in PrimeNG (applyFilter =\n _filter + hide), so wherever Apply is hidden Clear is the only button\n left and would otherwise clear-and-linger. Committing a VALUE still\n leaves the menu open deliberately \u2014 a multiselect gets ticked several\n times per visit; dismissal is the popover's own (outside click, Esc). -->\n <p-columnFilter\n *ngIf=\"col.filterType != null && col.filterType !== 'blob'\"\n [type]=\"col.filterType\"\n [field]=\"filterKey(col)\"\n display=\"menu\"\n [placeholder]=\"col.filterPlaceholder\"\n [showOperator]=\"false\"\n [showMatchModes]=\"col.showMatchModes\"\n [showAddButton]=\"col.showAddButton\"\n [showApplyButton]=\"!filterAppliesOnChange(col.filterType)\"\n [hideOnClear]=\"true\"\n [matchModeOptions]=\"getColMatchModeOptions(col)\"\n [matchMode]=\"getColMatchMode(col)\"\n >\n <!-- Marks a filtered column \u2014 PrimeNG's own <FilterIcon> cannot\n (CLAUDE.md \u2192 \"Active-filter header icon\"). Colour: the SCSS. -->\n <ng-template pTemplate=\"filtericon\">\n <i\n [class]=\"\n isColumnFiltered(col) ? 'pi pi-filter-fill' : 'pi pi-filter'\n \"\n ></i>\n </ng-template>\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 <span class=\"cell-text\">{{ displayValue }}</span>\n </ng-container>\n </ng-template>\n <tr\n [class.clickable]=\"navigateOnRowClick\"\n (click)=\"onRowClick(rowData, $event)\"\n >\n <!-- row-interactive: a selection gesture must never double as row navigation (onRowClick). -->\n <td\n *ngIf=\"selectionMode == 'multiple'\"\n class=\"selection-cell row-interactive\"\n (mousedown)=\"onSelectionCellMouseDown($event, rowData[idField])\"\n >\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 [class.row-interactive]=\"col.onCellClick\"\n (click)=\"onCellClick(col, rowData, $event)\"\n *ngIf=\"!col.editable\"\n >\n <!-- getColWidth reserves this column's width from `actions.length`; this gap is\n the geometry it reserves for, so changing it belongs in the same edit. -->\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) + ' row-interactive'\"\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\" class=\"row-interactive\">\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=\"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}.pi-filter-fill{color:var(--p-primary-color)}@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 .spiderly-table-container{scroll-margin-top:calc(var(--spiderly-viewport-top-inset, 0px) + 1rem)}:host ::ng-deep .clickable{cursor:pointer}:host ::ng-deep td.clickable:hover{text-decoration:underline}:host td.selection-cell{-webkit-user-select:none;user-select:none}:host .cell-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host ::ng-deep .p-datatable-mask{background:color-mix(in srgb,var(--p-content-background, #ffffff) 65%,transparent);color:var(--p-primary-color, #334155);align-items:flex-start;padding-top:6rem}: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.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { 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"] }] }); }
|
|
4938
5239
|
}
|
|
4939
5240
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: SpiderlyDataTableComponent, decorators: [{
|
|
4940
5241
|
type: Component,
|
|
@@ -4950,8 +5251,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImpo
|
|
|
4950
5251
|
DatePickerModule,
|
|
4951
5252
|
CheckboxModule,
|
|
4952
5253
|
TooltipModule,
|
|
4953
|
-
], 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 [rowsPerPageOptions]=\"rowsPerPageOptions\"\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, $event)\"\n >\n <!-- row-interactive: a selection gesture must never double as row navigation (onRowClick). -->\n <td\n *ngIf=\"selectionMode == 'multiple'\"\n class=\"selection-cell row-interactive\"\n (mousedown)=\"onSelectionCellMouseDown($event, rowData[idField])\"\n >\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 [class.row-interactive]=\"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) + ' row-interactive'\"\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\" class=\"row-interactive\">\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 td.selection-cell{-webkit-user-select:none;user-select:none}: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"] }]
|
|
4954
|
-
}], ctorParameters: () => [{ type: i3$2.Router }, { type: i1$5.DialogService }, { type: i3$2.ActivatedRoute }, { type: SpiderlyMessageService }, { type: i1.TranslocoService }, { type: ConfigServiceBase }, { type: undefined, decorators: [{
|
|
5254
|
+
], template: "<ng-container *transloco=\"let t\">\n <div\n #tableContainer\n class=\"spiderly-table-container\"\n [attr.aria-busy]=\"isPending\"\n [ngClass]=\"{\n 'card responsive-card-padding overflow-auto': showCardWrapper\n }\"\n >\n <p-table\n #dt\n [value]=\"items\"\n [rows]=\"rows\"\n [rowsPerPageOptions]=\"rowsPerPageOptions\"\n [rowHover]=\"true\"\n [paginator]=\"showPaginator\"\n responsiveLayout=\"scroll\"\n [lazy]=\"hasLazyLoad\"\n (onLazyLoad)=\"lazyLoad($event)\"\n (onPage)=\"onPageChange(tableContainer)\"\n [totalRecords]=\"totalRecords\"\n class=\"spiderly-table\"\n [loading]=\"isPending\"\n [selectionMode]=\"selectionMode\"\n dataKey=\"id\"\n (onFilter)=\"filter($event)\"\n sortMode=\"multiple\"\n [multiSortMeta]=\"initialMultiSortMeta\"\n [stateKey]=\"resolvedStateKey\"\n [stateStorage]=\"stateStorage\"\n [tableStyle]=\"tableStyle\"\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 <!-- Sized for the checkbox plus the counter beside it, which shows `totalRecords` on a\n select-all and so reaches five digits on a large table. Not `0rem` (see CLAUDE.md \u2192\n Column widths), and not routed through getColWidth: this column has no `Column`. -->\n <th style=\"width: 6rem\" *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.width]=\"getColWidth(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 <!-- hideOnClear: Apply is what closes this menu in PrimeNG (applyFilter =\n _filter + hide), so wherever Apply is hidden Clear is the only button\n left and would otherwise clear-and-linger. Committing a VALUE still\n leaves the menu open deliberately \u2014 a multiselect gets ticked several\n times per visit; dismissal is the popover's own (outside click, Esc). -->\n <p-columnFilter\n *ngIf=\"col.filterType != null && col.filterType !== 'blob'\"\n [type]=\"col.filterType\"\n [field]=\"filterKey(col)\"\n display=\"menu\"\n [placeholder]=\"col.filterPlaceholder\"\n [showOperator]=\"false\"\n [showMatchModes]=\"col.showMatchModes\"\n [showAddButton]=\"col.showAddButton\"\n [showApplyButton]=\"!filterAppliesOnChange(col.filterType)\"\n [hideOnClear]=\"true\"\n [matchModeOptions]=\"getColMatchModeOptions(col)\"\n [matchMode]=\"getColMatchMode(col)\"\n >\n <!-- Marks a filtered column \u2014 PrimeNG's own <FilterIcon> cannot\n (CLAUDE.md \u2192 \"Active-filter header icon\"). Colour: the SCSS. -->\n <ng-template pTemplate=\"filtericon\">\n <i\n [class]=\"\n isColumnFiltered(col) ? 'pi pi-filter-fill' : 'pi pi-filter'\n \"\n ></i>\n </ng-template>\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 <span class=\"cell-text\">{{ displayValue }}</span>\n </ng-container>\n </ng-template>\n <tr\n [class.clickable]=\"navigateOnRowClick\"\n (click)=\"onRowClick(rowData, $event)\"\n >\n <!-- row-interactive: a selection gesture must never double as row navigation (onRowClick). -->\n <td\n *ngIf=\"selectionMode == 'multiple'\"\n class=\"selection-cell row-interactive\"\n (mousedown)=\"onSelectionCellMouseDown($event, rowData[idField])\"\n >\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 [class.row-interactive]=\"col.onCellClick\"\n (click)=\"onCellClick(col, rowData, $event)\"\n *ngIf=\"!col.editable\"\n >\n <!-- getColWidth reserves this column's width from `actions.length`; this gap is\n the geometry it reserves for, so changing it belongs in the same edit. -->\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) + ' row-interactive'\"\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\" class=\"row-interactive\">\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=\"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}.pi-filter-fill{color:var(--p-primary-color)}@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 .spiderly-table-container{scroll-margin-top:calc(var(--spiderly-viewport-top-inset, 0px) + 1rem)}:host ::ng-deep .clickable{cursor:pointer}:host ::ng-deep td.clickable:hover{text-decoration:underline}:host td.selection-cell{-webkit-user-select:none;user-select:none}:host .cell-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host ::ng-deep .p-datatable-mask{background:color-mix(in srgb,var(--p-content-background, #ffffff) 65%,transparent);color:var(--p-primary-color, #334155);align-items:flex-start;padding-top:6rem}: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"] }]
|
|
5255
|
+
}], ctorParameters: () => [{ type: i3$2.Router }, { type: i1$5.DialogService }, { type: i3$2.ActivatedRoute }, { type: SpiderlyMessageService }, { type: i1.TranslocoService }, { type: ConfigServiceBase }, { type: i0.ErrorHandler }, { type: undefined, decorators: [{
|
|
4955
5256
|
type: Inject,
|
|
4956
5257
|
args: [LOCALE_ID]
|
|
4957
5258
|
}] }], propDecorators: { table: [{
|
|
@@ -5053,13 +5354,14 @@ class Action {
|
|
|
5053
5354
|
}
|
|
5054
5355
|
}
|
|
5055
5356
|
class Column {
|
|
5056
|
-
constructor({ name, field, filterField, filterType, filterPlaceholder, showMatchModes, showAddButton, dropdownOrMultiselectValues, actions, editable, showTime, decimalPlaces, sortable, visible, lockVisible,
|
|
5357
|
+
constructor({ name, field, filterField, filterType, filterPlaceholder, showMatchModes, matchModes, showAddButton, dropdownOrMultiselectValues, actions, editable, showTime, decimalPlaces, sortable, visible, lockVisible, width, onCellClick, } = {}) {
|
|
5057
5358
|
this.name = name;
|
|
5058
5359
|
this.field = field;
|
|
5059
5360
|
this.filterField = filterField;
|
|
5060
5361
|
this.filterType = filterType;
|
|
5061
5362
|
this.filterPlaceholder = filterPlaceholder;
|
|
5062
5363
|
this.showMatchModes = showMatchModes;
|
|
5364
|
+
this.matchModes = matchModes;
|
|
5063
5365
|
this.showAddButton = showAddButton;
|
|
5064
5366
|
this.dropdownOrMultiselectValues = dropdownOrMultiselectValues;
|
|
5065
5367
|
this.actions = actions;
|
|
@@ -5069,7 +5371,7 @@ class Column {
|
|
|
5069
5371
|
this.sortable = sortable;
|
|
5070
5372
|
this.visible = visible;
|
|
5071
5373
|
this.lockVisible = lockVisible;
|
|
5072
|
-
this.
|
|
5374
|
+
this.width = width;
|
|
5073
5375
|
this.onCellClick = onCellClick;
|
|
5074
5376
|
}
|
|
5075
5377
|
}
|
|
@@ -5142,7 +5444,24 @@ class SpiderlyDataViewComponent {
|
|
|
5142
5444
|
},
|
|
5143
5445
|
];
|
|
5144
5446
|
}
|
|
5447
|
+
// Paging semantics and the scroll-margin contract are documented once, on the data table:
|
|
5448
|
+
// spiderly-data-table/CLAUDE.md → "Scroll back to the table on page change".
|
|
5449
|
+
onPageChange(container) {
|
|
5450
|
+
scrollElementIntoViewIfAboveViewport(container);
|
|
5451
|
+
}
|
|
5452
|
+
/**
|
|
5453
|
+
* The one pending predicate: PrimeNG's overlay and the container's `aria-busy` must never
|
|
5454
|
+
* disagree. Mirrors the data table's, including why it is not also testing `items`; the
|
|
5455
|
+
* rationale lives there.
|
|
5456
|
+
*/
|
|
5457
|
+
get isPending() {
|
|
5458
|
+
return this.loading;
|
|
5459
|
+
}
|
|
5145
5460
|
lazyLoad(event) {
|
|
5461
|
+
// Every refetch is pending, not just the first load. `items` is deliberately left alone so
|
|
5462
|
+
// the previous page stays readable under the overlay. Full reasoning: the data table's
|
|
5463
|
+
// CLAUDE.md → "Pending state".
|
|
5464
|
+
this.loading = true;
|
|
5146
5465
|
this.lastLazyLoadEvent = event;
|
|
5147
5466
|
const transformedFilter = {};
|
|
5148
5467
|
for (const key in event.filters) {
|
|
@@ -5163,7 +5482,7 @@ class SpiderlyDataViewComponent {
|
|
|
5163
5482
|
tableFilter.filters = transformedFilter;
|
|
5164
5483
|
this.onLazyLoad.next(tableFilter);
|
|
5165
5484
|
this.getPaginatedListObservableMethod(tableFilter).subscribe({
|
|
5166
|
-
next:
|
|
5485
|
+
next: (res) => {
|
|
5167
5486
|
this.items = res.data;
|
|
5168
5487
|
this.totalRecords = res.totalRecords;
|
|
5169
5488
|
this.loading = false;
|
|
@@ -5207,8 +5526,10 @@ class SpiderlyDataViewComponent {
|
|
|
5207
5526
|
}
|
|
5208
5527
|
}
|
|
5209
5528
|
reload() {
|
|
5210
|
-
|
|
5211
|
-
this.
|
|
5529
|
+
// Nothing to replay before the initial load, which is already on its way.
|
|
5530
|
+
if (this.lastLazyLoadEvent == null)
|
|
5531
|
+
return;
|
|
5532
|
+
// Not special: same refetch as a page flip, so lazyLoad owns both the flag and `items`.
|
|
5212
5533
|
this.lazyLoad(this.lastLazyLoadEvent);
|
|
5213
5534
|
}
|
|
5214
5535
|
colTrackByFn(index, item) {
|
|
@@ -5221,7 +5542,7 @@ class SpiderlyDataViewComponent {
|
|
|
5221
5542
|
this.table.clear();
|
|
5222
5543
|
}
|
|
5223
5544
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: SpiderlyDataViewComponent, deps: [{ token: i1.TranslocoService }, { token: LOCALE_ID }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5224
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.13", type: SpiderlyDataViewComponent, isStandalone: true, selector: "spiderly-data-view", inputs: { items: "items", rows: "rows", filters: "filters", showCardWrapper: "showCardWrapper", showPaginatorRightData: "showPaginatorRightData", showTotalRecordsNumber: "showTotalRecordsNumber", applyFiltersIcon: "applyFiltersIcon", clearFiltersIcon: "clearFiltersIcon", getPaginatedListObservableMethod: "getPaginatedListObservableMethod" }, outputs: { onLazyLoad: "onLazyLoad" }, queries: [{ propertyName: "cardBody", first: true, predicate: ["cardBody"], 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]=\"false\"\n responsiveLayout=\"scroll\"\n [lazy]=\"true\"\n (onLazyLoad)=\"lazyLoad($event)\"\n [totalRecords]=\"totalRecords\"\n class=\"spiderly-table\"\n [loading]=\"items === undefined || loading === true\"\n dataKey=\"id\"\n (onFilter)=\"filter($event)\"\n [filterDelay]=\"500\"\n [paginator]=\"true\"\n >\n <ng-template #caption>\n <div *ngIf=\"filters.length !== 0\">\n <div class=\"data-view-grid\">\n @for (filter of filters; track $index) {\n <div>\n <div\n style=\"\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n position: relative;\n \"\n >\n <div>\n <label>\n {{ filter.label }}\n </label>\n </div>\n\n <p-columnFilter\n *ngIf=\"filter.type != null\"\n [type]=\"filter.type\"\n [field]=\"filter.filterField ?? filter.field\"\n display=\"row\"\n [placeholder]=\"filter.placeholder\"\n [showOperator]=\"false\"\n [showMenu]=\"filter.showMatchModes\"\n [showMatchModes]=\"true\"\n [showClearButton]=\"false\"\n [matchMode]=\"getDefaultMatchMode(filter.type)\"\n [matchModeOptions]=\"getMatchModeOptions(filter.type)\"\n >\n <ng-container *ngIf=\"filter.type == 'multiselect'\">\n <ng-template\n pTemplate=\"filter\"\n let-value\n let-filter=\"filterCallback\"\n >\n <p-multiSelect\n [ngModel]=\"value\"\n [options]=\"filter.dropdownOrMultiselectValues\"\n [placeholder]=\"t('All')\"\n (onChange)=\"filter($event.value)\"\n optionLabel=\"label\"\n optionValue=\"code\"\n [style]=\"{ width: '100%' }\"\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-container>\n </p-columnFilter>\n </div>\n </div>\n }\n </div>\n <div style=\"display: flex; gap: 12px\">\n <spiderly-button\n [label]=\"t('ApplyFilters')\"\n (onClick)=\"applyFilters()\"\n [icon]=\"applyFiltersIcon\"\n ></spiderly-button>\n <spiderly-button\n [label]=\"t('ClearFilters')\"\n (onClick)=\"clearFilters()\"\n [icon]=\"clearFiltersIcon\"\n ></spiderly-button>\n </div>\n </div>\n </ng-template>\n <ng-template #body let-rowData let-index=\"rowIndex\">\n <tr style=\"padding: 0; margin-bottom: 0\">\n <td style=\"display: block; border: 0; padding: 0\">\n <ng-container\n *ngTemplateOutlet=\"\n cardBody;\n context: { $implicit: rowData, item: rowData, index: index }\n \"\n >\n </ng-container>\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"emptymessage\">\n {{ t(\"NoRecordsFound\") }}\n </ng-template>\n <ng-template *ngIf=\"showTotalRecordsNumber\" pTemplate=\"paginatorleft\">\n {{ t(\"TotalRecords\") }}: {{ totalRecords }}\n </ng-template>\n <ng-template *ngIf=\"showPaginatorRightData\" pTemplate=\"paginatorright\">\n <ng-content select=\"[PAGINATORRIGHT]\"></ng-content>\n </ng-template>\n </p-table>\n </div>\n</ng-container>\n", styles: ["::ng-deep .p-datatable-tbody{display:flex;flex-direction:column;gap:18px}::ng-deep .p-datatable-header{margin-bottom:36px;border:0!important;padding:0!important;background-color:transparent!important}::ng-deep .p-paginator{padding:18px 9px 0!important}::ng-deep .p-fluid{width:100%!important}::ng-deep .p-inputtext{width:100%!important}::ng-deep .p-inputnumber{width:100%!important}::ng-deep .p-datepicker{width:100%!important}.data-view-grid{display:grid;gap:18px;grid-template-columns:1fr 1fr 1fr;margin-bottom:18px}@media (max-width: 1080px){.data-view-grid{gap:12px;grid-template-columns:1fr 1fr}}@media (max-width: 500px){.data-view-grid{grid-template-columns:1fr}}\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.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: "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: "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: "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: CheckboxModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "ngmodule", type: DatePickerModule }, { kind: "ngmodule", type: InputTextModule }, { kind: "ngmodule", type: InputNumberModule }, { kind: "ngmodule", type: SelectModule }] }); }
|
|
5545
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.13", type: SpiderlyDataViewComponent, isStandalone: true, selector: "spiderly-data-view", inputs: { items: "items", rows: "rows", filters: "filters", showCardWrapper: "showCardWrapper", showPaginatorRightData: "showPaginatorRightData", showTotalRecordsNumber: "showTotalRecordsNumber", applyFiltersIcon: "applyFiltersIcon", clearFiltersIcon: "clearFiltersIcon", getPaginatedListObservableMethod: "getPaginatedListObservableMethod" }, outputs: { onLazyLoad: "onLazyLoad" }, queries: [{ propertyName: "cardBody", first: true, predicate: ["cardBody"], descendants: true, read: TemplateRef }], viewQueries: [{ propertyName: "table", first: true, predicate: ["dt"], descendants: true }], ngImport: i0, template: "<ng-container *transloco=\"let t\">\n <div\n #tableContainer\n class=\"spiderly-table-container\"\n [attr.aria-busy]=\"isPending\"\n [ngClass]=\"{\n 'card responsive-card-padding overflow-auto': showCardWrapper\n }\"\n >\n <p-table\n #dt\n [value]=\"items\"\n [rows]=\"rows\"\n [rowHover]=\"false\"\n responsiveLayout=\"scroll\"\n [lazy]=\"true\"\n (onLazyLoad)=\"lazyLoad($event)\"\n (onPage)=\"onPageChange(tableContainer)\"\n [totalRecords]=\"totalRecords\"\n class=\"spiderly-table\"\n [loading]=\"isPending\"\n dataKey=\"id\"\n (onFilter)=\"filter($event)\"\n [filterDelay]=\"500\"\n [paginator]=\"true\"\n >\n <ng-template #caption>\n <div *ngIf=\"filters.length !== 0\">\n <div class=\"data-view-grid\">\n @for (filter of filters; track $index) {\n <div>\n <div\n style=\"\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n position: relative;\n \"\n >\n <div>\n <label>\n {{ filter.label }}\n </label>\n </div>\n\n <p-columnFilter\n *ngIf=\"filter.type != null\"\n [type]=\"filter.type\"\n [field]=\"filter.filterField ?? filter.field\"\n display=\"row\"\n [placeholder]=\"filter.placeholder\"\n [showOperator]=\"false\"\n [showMenu]=\"filter.showMatchModes\"\n [showMatchModes]=\"true\"\n [showClearButton]=\"false\"\n [matchMode]=\"getDefaultMatchMode(filter.type)\"\n [matchModeOptions]=\"getMatchModeOptions(filter.type)\"\n >\n <ng-container *ngIf=\"filter.type == 'multiselect'\">\n <ng-template\n pTemplate=\"filter\"\n let-value\n let-filter=\"filterCallback\"\n >\n <p-multiSelect\n [ngModel]=\"value\"\n [options]=\"filter.dropdownOrMultiselectValues\"\n [placeholder]=\"t('All')\"\n (onChange)=\"filter($event.value)\"\n optionLabel=\"label\"\n optionValue=\"code\"\n [style]=\"{ width: '100%' }\"\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-container>\n </p-columnFilter>\n </div>\n </div>\n }\n </div>\n <div style=\"display: flex; gap: 12px\">\n <spiderly-button\n [label]=\"t('ApplyFilters')\"\n (onClick)=\"applyFilters()\"\n [icon]=\"applyFiltersIcon\"\n ></spiderly-button>\n <spiderly-button\n [label]=\"t('ClearFilters')\"\n (onClick)=\"clearFilters()\"\n [icon]=\"clearFiltersIcon\"\n ></spiderly-button>\n </div>\n </div>\n </ng-template>\n <ng-template #body let-rowData let-index=\"rowIndex\">\n <tr style=\"padding: 0; margin-bottom: 0\">\n <td style=\"display: block; border: 0; padding: 0\">\n <ng-container\n *ngTemplateOutlet=\"\n cardBody;\n context: { $implicit: rowData, item: rowData, index: index }\n \"\n >\n </ng-container>\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"emptymessage\">\n {{ t(\"NoRecordsFound\") }}\n </ng-template>\n <ng-template *ngIf=\"showTotalRecordsNumber\" pTemplate=\"paginatorleft\">\n {{ t(\"TotalRecords\") }}: {{ totalRecords }}\n </ng-template>\n <ng-template *ngIf=\"showPaginatorRightData\" pTemplate=\"paginatorright\">\n <ng-content select=\"[PAGINATORRIGHT]\"></ng-content>\n </ng-template>\n </p-table>\n </div>\n</ng-container>\n", styles: [":host .spiderly-table-container{scroll-margin-top:calc(var(--spiderly-viewport-top-inset, 0px) + 1rem)}:host ::ng-deep .p-datatable-mask{background:color-mix(in srgb,var(--p-content-background, #ffffff) 65%,transparent);color:var(--p-primary-color, #334155);align-items:flex-start;padding-top:6rem}::ng-deep .p-datatable-tbody{display:flex;flex-direction:column;gap:18px}::ng-deep .p-datatable-header{margin-bottom:36px;border:0!important;padding:0!important;background-color:transparent!important}::ng-deep .p-paginator{padding:18px 9px 0!important}::ng-deep .p-fluid{width:100%!important}::ng-deep .p-inputtext{width:100%!important}::ng-deep .p-inputnumber{width:100%!important}::ng-deep .p-datepicker{width:100%!important}.data-view-grid{display:grid;gap:18px;grid-template-columns:1fr 1fr 1fr;margin-bottom:18px}@media (max-width: 1080px){.data-view-grid{gap:12px;grid-template-columns:1fr 1fr}}@media (max-width: 500px){.data-view-grid{grid-template-columns:1fr}}\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.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { 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: "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: "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: "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: CheckboxModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "ngmodule", type: DatePickerModule }, { kind: "ngmodule", type: InputTextModule }, { kind: "ngmodule", type: InputNumberModule }, { kind: "ngmodule", type: SelectModule }] }); }
|
|
5225
5546
|
}
|
|
5226
5547
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: SpiderlyDataViewComponent, decorators: [{
|
|
5227
5548
|
type: Component,
|
|
@@ -5239,7 +5560,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImpo
|
|
|
5239
5560
|
InputTextModule,
|
|
5240
5561
|
InputNumberModule,
|
|
5241
5562
|
SelectModule,
|
|
5242
|
-
], template: "<ng-container *transloco=\"let t\">\n <div\n [
|
|
5563
|
+
], template: "<ng-container *transloco=\"let t\">\n <div\n #tableContainer\n class=\"spiderly-table-container\"\n [attr.aria-busy]=\"isPending\"\n [ngClass]=\"{\n 'card responsive-card-padding overflow-auto': showCardWrapper\n }\"\n >\n <p-table\n #dt\n [value]=\"items\"\n [rows]=\"rows\"\n [rowHover]=\"false\"\n responsiveLayout=\"scroll\"\n [lazy]=\"true\"\n (onLazyLoad)=\"lazyLoad($event)\"\n (onPage)=\"onPageChange(tableContainer)\"\n [totalRecords]=\"totalRecords\"\n class=\"spiderly-table\"\n [loading]=\"isPending\"\n dataKey=\"id\"\n (onFilter)=\"filter($event)\"\n [filterDelay]=\"500\"\n [paginator]=\"true\"\n >\n <ng-template #caption>\n <div *ngIf=\"filters.length !== 0\">\n <div class=\"data-view-grid\">\n @for (filter of filters; track $index) {\n <div>\n <div\n style=\"\n display: flex;\n flex-direction: column;\n gap: 0.5rem;\n position: relative;\n \"\n >\n <div>\n <label>\n {{ filter.label }}\n </label>\n </div>\n\n <p-columnFilter\n *ngIf=\"filter.type != null\"\n [type]=\"filter.type\"\n [field]=\"filter.filterField ?? filter.field\"\n display=\"row\"\n [placeholder]=\"filter.placeholder\"\n [showOperator]=\"false\"\n [showMenu]=\"filter.showMatchModes\"\n [showMatchModes]=\"true\"\n [showClearButton]=\"false\"\n [matchMode]=\"getDefaultMatchMode(filter.type)\"\n [matchModeOptions]=\"getMatchModeOptions(filter.type)\"\n >\n <ng-container *ngIf=\"filter.type == 'multiselect'\">\n <ng-template\n pTemplate=\"filter\"\n let-value\n let-filter=\"filterCallback\"\n >\n <p-multiSelect\n [ngModel]=\"value\"\n [options]=\"filter.dropdownOrMultiselectValues\"\n [placeholder]=\"t('All')\"\n (onChange)=\"filter($event.value)\"\n optionLabel=\"label\"\n optionValue=\"code\"\n [style]=\"{ width: '100%' }\"\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-container>\n </p-columnFilter>\n </div>\n </div>\n }\n </div>\n <div style=\"display: flex; gap: 12px\">\n <spiderly-button\n [label]=\"t('ApplyFilters')\"\n (onClick)=\"applyFilters()\"\n [icon]=\"applyFiltersIcon\"\n ></spiderly-button>\n <spiderly-button\n [label]=\"t('ClearFilters')\"\n (onClick)=\"clearFilters()\"\n [icon]=\"clearFiltersIcon\"\n ></spiderly-button>\n </div>\n </div>\n </ng-template>\n <ng-template #body let-rowData let-index=\"rowIndex\">\n <tr style=\"padding: 0; margin-bottom: 0\">\n <td style=\"display: block; border: 0; padding: 0\">\n <ng-container\n *ngTemplateOutlet=\"\n cardBody;\n context: { $implicit: rowData, item: rowData, index: index }\n \"\n >\n </ng-container>\n </td>\n </tr>\n </ng-template>\n <ng-template pTemplate=\"emptymessage\">\n {{ t(\"NoRecordsFound\") }}\n </ng-template>\n <ng-template *ngIf=\"showTotalRecordsNumber\" pTemplate=\"paginatorleft\">\n {{ t(\"TotalRecords\") }}: {{ totalRecords }}\n </ng-template>\n <ng-template *ngIf=\"showPaginatorRightData\" pTemplate=\"paginatorright\">\n <ng-content select=\"[PAGINATORRIGHT]\"></ng-content>\n </ng-template>\n </p-table>\n </div>\n</ng-container>\n", styles: [":host .spiderly-table-container{scroll-margin-top:calc(var(--spiderly-viewport-top-inset, 0px) + 1rem)}:host ::ng-deep .p-datatable-mask{background:color-mix(in srgb,var(--p-content-background, #ffffff) 65%,transparent);color:var(--p-primary-color, #334155);align-items:flex-start;padding-top:6rem}::ng-deep .p-datatable-tbody{display:flex;flex-direction:column;gap:18px}::ng-deep .p-datatable-header{margin-bottom:36px;border:0!important;padding:0!important;background-color:transparent!important}::ng-deep .p-paginator{padding:18px 9px 0!important}::ng-deep .p-fluid{width:100%!important}::ng-deep .p-inputtext{width:100%!important}::ng-deep .p-inputnumber{width:100%!important}::ng-deep .p-datepicker{width:100%!important}.data-view-grid{display:grid;gap:18px;grid-template-columns:1fr 1fr 1fr;margin-bottom:18px}@media (max-width: 1080px){.data-view-grid{gap:12px;grid-template-columns:1fr 1fr}}@media (max-width: 500px){.data-view-grid{grid-template-columns:1fr}}\n"] }]
|
|
5243
5564
|
}], ctorParameters: () => [{ type: i1.TranslocoService }, { type: undefined, decorators: [{
|
|
5244
5565
|
type: Inject,
|
|
5245
5566
|
args: [LOCALE_ID]
|
|
@@ -5765,5 +6086,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImpo
|
|
|
5765
6086
|
* Generated bundle index. Do not edit.
|
|
5766
6087
|
*/
|
|
5767
6088
|
|
|
5768
|
-
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, 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 };
|
|
6089
|
+
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, 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, scrollElementIntoViewIfAboveViewport, selectedTab, singleOrDefault, splitPascalCase, toCommaSeparatedString, unauthorizedInterceptor, validatePrecisionScale };
|
|
5769
6090
|
//# sourceMappingURL=spiderly.mjs.map
|