spiderly 19.11.9 → 19.12.1
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 +56 -14
- package/agent/docs/angular-customization/references/helper-functions.generated.md +1 -0
- package/agent/docs/e2e-testing/index.md +10 -15
- package/agent/skills/add-entity/SKILL.md +12 -1
- package/fesm2022/spiderly.mjs +2206 -449
- package/fesm2022/spiderly.mjs.map +1 -1
- package/lib/components/spiderly-data-table/spiderly-data-table.component.d.ts +512 -141
- package/lib/directives/spiderly-filter-template.directive.d.ts +34 -0
- package/lib/directives/spiderly-overflow-title.directive.d.ts +33 -0
- package/lib/entities/filter-rule.d.ts +5 -7
- package/lib/filters/allowed-operators.d.ts +24 -0
- package/lib/filters/filter-store.d.ts +264 -0
- package/lib/filters/spiderly-filter-bar.component.d.ts +132 -0
- package/lib/services/helper-functions.d.ts +8 -0
- package/package.json +1 -1
- package/public-api.d.ts +5 -0
- package/styles/components/spiderly-data-table/spiderly-data-table.component.scss +150 -18
- package/styles/filters/spiderly-filter-bar.component.scss +163 -0
- package/styles/styles/layout/_mixins.scss +13 -0
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import { AfterViewInit, ErrorHandler, EventEmitter, OnChanges, OnDestroy, OnInit, QueryList, TemplateRef } from '@angular/core';
|
|
1
|
+
import { AfterViewInit, ErrorHandler, EventEmitter, OnChanges, OnDestroy, OnInit, QueryList, SimpleChanges, TemplateRef } from '@angular/core';
|
|
2
2
|
import { ActivatedRoute, Router } from '@angular/router';
|
|
3
3
|
import { TranslocoService } from '@jsverse/transloco';
|
|
4
|
-
import {
|
|
4
|
+
import { SortMeta } from 'primeng/api';
|
|
5
5
|
import { DialogService, DynamicDialogRef } from 'primeng/dynamicdialog';
|
|
6
|
-
import { Table,
|
|
6
|
+
import { Table, TableLazyLoadEvent } from 'primeng/table';
|
|
7
7
|
import { Observable } from 'rxjs';
|
|
8
8
|
import { CellTemplateContext, SpiderlyCellTemplateDirective } from '../../directives/spiderly-cell-template.directive';
|
|
9
9
|
import { Filter } from '../../entities/filter';
|
|
10
10
|
import { LazyLoadSelectedIdsResult } from '../../entities/lazy-load-selected-ids-result';
|
|
11
11
|
import { PaginatedResult } from '../../entities/paginated-result';
|
|
12
12
|
import { PrimengOption } from '../../entities/primeng-option';
|
|
13
|
-
import {
|
|
13
|
+
import { FilterSource, SortKeyLabel } from '../../filters/filter-store';
|
|
14
|
+
import { SpiderlyFilterTemplateDirective } from '../../directives/spiderly-filter-template.directive';
|
|
14
15
|
import { ConfigServiceBase } from '../../services/config.service.base';
|
|
15
16
|
import { SpiderlyMessageService } from '../../services/spiderly-message.service';
|
|
16
17
|
import { SpiderlyFormControl } from '../spiderly-form-control/spiderly-form-control';
|
|
@@ -26,6 +27,52 @@ export declare class SpiderlyDataTableComponent implements OnInit, OnChanges, Af
|
|
|
26
27
|
private locale;
|
|
27
28
|
private readonly destroy$;
|
|
28
29
|
table: Table;
|
|
30
|
+
private readonly injector;
|
|
31
|
+
private readonly zone;
|
|
32
|
+
/**
|
|
33
|
+
* The selection column's declared share. Under the fixed layout this is a RATIO, not a width.
|
|
34
|
+
*
|
|
35
|
+
* 4rem, down from 6: the original reserved room for a five-digit select-all counter sitting at
|
|
36
|
+
* body text size beside the box, which is the widest thing it can ever hold and not what it
|
|
37
|
+
* holds on any ordinary screen. The counter is a smaller step now (see the SCSS), so the same
|
|
38
|
+
* five digits fit in two thirds of the space.
|
|
39
|
+
*/
|
|
40
|
+
protected readonly selectionColumnWidth = "4rem";
|
|
41
|
+
/**
|
|
42
|
+
* The selection column's MEASURED width, which is what the frozen identity column offsets
|
|
43
|
+
* itself by. Declaring `6rem` on both looked like the one-telling answer and is wrong: widths
|
|
44
|
+
* are shares, so that column renders at whatever proportion of the table it gets — 148px for a
|
|
45
|
+
* declared 6rem in one spec — and the identity column would sit 52px inside it, overlapping the
|
|
46
|
+
* checkboxes the moment anyone scrolled. The spec caught it; nothing about the page would have.
|
|
47
|
+
*/
|
|
48
|
+
protected frozenOffsetPx: number;
|
|
49
|
+
private selectionWidthObserver?;
|
|
50
|
+
/** Aborts an in-flight column resize's document listeners, from `onUp` or from teardown. */
|
|
51
|
+
private resizeAbort;
|
|
52
|
+
/**
|
|
53
|
+
* Whether this column is pinned against the left edge. Only the FIRST column, and only when it
|
|
54
|
+
* is `lockVisible`: a sticky column in the middle of the grid pins the wrong thing and leaves a
|
|
55
|
+
* hole where it used to be. Once the grid scrolls sideways a row otherwise loses its identity
|
|
56
|
+
* — "Intesa, plaćeno, 12.400" with no idea whose order it is — and NN/g's Data Tables is
|
|
57
|
+
* explicit that the leftmost header column must lock in place. `lockVisible` already names
|
|
58
|
+
* exactly that column in every table, so this needs no new API (CLAUDE.md -> decision 8).
|
|
59
|
+
*/
|
|
60
|
+
isColumnFrozen(col: Column): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* The rightmost pinned cell, which carries the seam's shadow. It is the identity column when
|
|
63
|
+
* there is one and the checkbox column otherwise — a fact only this side knows, which is why
|
|
64
|
+
* the SCSS asking for it as `:last-of-type` drew nothing at all.
|
|
65
|
+
*/
|
|
66
|
+
isLastFrozenColumn(col: Column): boolean;
|
|
67
|
+
get isSelectionColumnLastFrozen(): boolean;
|
|
68
|
+
/** A frozen column starts after the checkbox column, when there is one. */
|
|
69
|
+
frozenColumnOffset(): string;
|
|
70
|
+
/**
|
|
71
|
+
* Tracks the selection column's rendered width. A ResizeObserver rather than a one-off read:
|
|
72
|
+
* every column drag and every window resize re-splits the shares, so the offset moves without
|
|
73
|
+
* anything about the selection column itself changing.
|
|
74
|
+
*/
|
|
75
|
+
private observeSelectionWidth;
|
|
29
76
|
/**
|
|
30
77
|
* Custom toolbar content projected via `<ng-template spiderlyDataTableActions>`.
|
|
31
78
|
* Rendered in the caption action area ahead of the built-in buttons.
|
|
@@ -43,6 +90,29 @@ export declare class SpiderlyDataTableComponent implements OnInit, OnChanges, Af
|
|
|
43
90
|
/** Paginator page-size choices; merge rules and persistence: CLAUDE.md → "Rows-per-page". */
|
|
44
91
|
rowsPerPageOptions: number[];
|
|
45
92
|
cols: Column[];
|
|
93
|
+
/**
|
|
94
|
+
* The consumer's filter store — the table's WHOLE filter surface, rendered as the chip bar. A
|
|
95
|
+
* table given none has no filtering at all (`Column.filterType` is only the value's shape; the
|
|
96
|
+
* legacy header-filter fallback was deleted — CLAUDE.md -> "Operator-owned view").
|
|
97
|
+
*
|
|
98
|
+
* READ ONCE, in ngOnInit — a store assigned later is silently ignored: the requery effect
|
|
99
|
+
* stays subscribed to the first store's `applied()`, and `resolvedStateKey` (which
|
|
100
|
+
* `additionalFilterIdLong` feeds) is never re-derived either. A consumer that must swap
|
|
101
|
+
* stores at runtime destroys and recreates the table around the swap — PACMS
|
|
102
|
+
* `integration-matching-products` nulls its view model for exactly this. Teaching
|
|
103
|
+
* ngOnChanges to re-arm both is the open upstream fix.
|
|
104
|
+
*/
|
|
105
|
+
filters?: FilterSource;
|
|
106
|
+
/** Saved questions for this table, rendered as tabs above the bar. */
|
|
107
|
+
views?: TableView[];
|
|
108
|
+
/**
|
|
109
|
+
* The view currently selected. Seeded from the first view in `ngOnInit` — then overridden by
|
|
110
|
+
* `restoreActiveView`, so a reload lands where the operator was — and never left null on a
|
|
111
|
+
* table that has views: `viewScope` keys the layout off it, so an unseeded table writes its
|
|
112
|
+
* width and order to the SAME key an unmigrated table uses — orphaned the moment the operator
|
|
113
|
+
* clicks the first tab — and no tab reads as selected until they do.
|
|
114
|
+
*/
|
|
115
|
+
activeViewId: string | null;
|
|
46
116
|
/** Whether the paginator is shown. Pass only when `hasLazyLoad === false`. Defaults to `true`. */
|
|
47
117
|
showPaginator: boolean;
|
|
48
118
|
/** Whether the table is wrapped in a card container. Defaults to `false`. */
|
|
@@ -86,9 +156,6 @@ export declare class SpiderlyDataTableComponent implements OnInit, OnChanges, Af
|
|
|
86
156
|
onIsAllSelectedChange: EventEmitter<AllClickEvent>;
|
|
87
157
|
selectedLazyLoadObservableMethod: (tableFilter: Filter) => Observable<LazyLoadSelectedIdsResult>;
|
|
88
158
|
additionalFilterIdLong: number;
|
|
89
|
-
matchModeDateOptions: SelectItem[];
|
|
90
|
-
matchModeNumberOptions: SelectItem[];
|
|
91
|
-
matchModeTextOptions: SelectItem[];
|
|
92
159
|
/** Whether the "Add" button is shown. Defaults to `true`. */
|
|
93
160
|
showAddButton: boolean;
|
|
94
161
|
/** Whether the "Export to Excel" button is shown. Defaults to `true`. */
|
|
@@ -163,7 +230,7 @@ export declare class SpiderlyDataTableComponent implements OnInit, OnChanges, Af
|
|
|
163
230
|
* backend `.Take`s whatever it is sent.
|
|
164
231
|
*/
|
|
165
232
|
private mergeActivePageSizesIntoOptions;
|
|
166
|
-
ngOnChanges(): void;
|
|
233
|
+
ngOnChanges(changes: SimpleChanges): void;
|
|
167
234
|
ngOnInit(): void;
|
|
168
235
|
/**
|
|
169
236
|
* User visibility choices (field → visible), holding only fields the user explicitly
|
|
@@ -171,12 +238,6 @@ export declare class SpiderlyDataTableComponent implements OnInit, OnChanges, Af
|
|
|
171
238
|
* default later flows through to every user who never touched that column.
|
|
172
239
|
*/
|
|
173
240
|
private columnVisibilityOverrides;
|
|
174
|
-
/**
|
|
175
|
-
* Columns revealed by the load-time reconciliation. Kept apart from
|
|
176
|
-
* `columnVisibilityOverrides` so persisting a later unrelated toggle can't promote a
|
|
177
|
-
* transient safety reveal into a durable choice.
|
|
178
|
-
*/
|
|
179
|
-
private revealedByConstraint;
|
|
180
241
|
/** A data column shows values for a `field`; anything else (the actions column) always renders. */
|
|
181
242
|
private static isDataColumn;
|
|
182
243
|
/**
|
|
@@ -185,8 +246,46 @@ export declare class SpiderlyDataTableComponent implements OnInit, OnChanges, Af
|
|
|
185
246
|
* are a transient working set — different natural lifetimes.
|
|
186
247
|
*/
|
|
187
248
|
private get columnsStateKey();
|
|
188
|
-
/** Actions columns always render; data columns follow
|
|
249
|
+
/** Actions columns always render; data columns follow the override, then declared default. */
|
|
189
250
|
isColumnVisible(col: Column): boolean;
|
|
251
|
+
/**
|
|
252
|
+
* `cols` in the operator's order. A field the stored order has never seen — a column added in a
|
|
253
|
+
* later release — sorts to the END rather than displacing a layout someone built by hand
|
|
254
|
+
* (CLAUDE.md -> "Operator-owned view", decision 7); the sort is stable, so those keep their
|
|
255
|
+
* declared order among themselves. Actions columns carry no field and are always last, which is
|
|
256
|
+
* where every consumer already declares them.
|
|
257
|
+
*/
|
|
258
|
+
private orderedCols;
|
|
259
|
+
/**
|
|
260
|
+
* Whether this column can move one place in `direction` (-1 left, 1 right). A locked column is
|
|
261
|
+
* the row's anchor — and, once the left edge freezes, the thing a horizontal scroll keeps in
|
|
262
|
+
* view — so it does not move and nothing moves in front of it.
|
|
263
|
+
*/
|
|
264
|
+
canMoveColumn(col: Column, direction: -1 | 1): boolean;
|
|
265
|
+
moveMenuColumn(direction: -1 | 1): void;
|
|
266
|
+
/** The move itself, shared by the menu and the drag — two entry points, one rule. */
|
|
267
|
+
private placeColumn;
|
|
268
|
+
private dataColumnsInOrder;
|
|
269
|
+
/**
|
|
270
|
+
* Header drag, ours rather than PrimeNG's `pReorderableColumn`, for two reasons: its
|
|
271
|
+
* `onMouseDown` arms the th for anything that is not an INPUT, a TEXTAREA or its OWN resizer —
|
|
272
|
+
* so our menu chevron and our resize grip would each start a column drag, and reaching for a
|
|
273
|
+
* width would silently reorder the grid — and its `onColumnDrop` reorders blind, with no notion
|
|
274
|
+
* of a locked column (CLAUDE.md -> decision 6).
|
|
275
|
+
*
|
|
276
|
+
* A shortcut for neighbours, never the mechanism: HTML5 dnd has no edge auto-scroll, so a column
|
|
277
|
+
* scrolled off the right is unreachable this way, and there is no keyboard path at all. The menu
|
|
278
|
+
* carries both.
|
|
279
|
+
*
|
|
280
|
+
* This half is the arming rule; the drop rule is `canDropOn` below.
|
|
281
|
+
*/
|
|
282
|
+
onHeaderMouseDown(event: MouseEvent): void;
|
|
283
|
+
onHeaderDragStart(col: Column, event: DragEvent): void;
|
|
284
|
+
onHeaderDragOver(col: Column, event: DragEvent): void;
|
|
285
|
+
onHeaderDrop(col: Column, event: DragEvent): void;
|
|
286
|
+
/** Nothing lands on, or in front of, the locked column. Enforced here as well as in the menu:
|
|
287
|
+
* a drop is a separate entry point, and the rule is about the grid rather than about a button. */
|
|
288
|
+
private canDropOn;
|
|
190
289
|
private refreshVisibleCols;
|
|
191
290
|
/**
|
|
192
291
|
* Locked columns can't be toggled; the last visible data column can't be hidden — the
|
|
@@ -194,46 +293,109 @@ export declare class SpiderlyDataTableComponent implements OnInit, OnChanges, Af
|
|
|
194
293
|
*/
|
|
195
294
|
canToggleColumn(col: Column): boolean;
|
|
196
295
|
toggleColumn(col: Column, visible: boolean): void;
|
|
197
|
-
/** Restores every column to its declared default and forgets the stored override. */
|
|
198
|
-
resetColumnVisibility(): void;
|
|
199
296
|
/**
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
297
|
+
* Restores every column to its declared default and forgets the stored overrides — visibility,
|
|
298
|
+
* wrap, order and width alike. It undid visibility only until the header menu shipped three
|
|
299
|
+
* more gestures beside it, and a layout with no way back is worse than one with no knobs.
|
|
300
|
+
*
|
|
301
|
+
* On a STORE table, hiding — here or from the menu — never touches filters or sort: the chip
|
|
302
|
+
* bar names every applied filter and the sort chip names the sort, hidden column or not
|
|
303
|
+
* (decision 2b). A storeless table keeps the sort half of the legacy invariant instead — see
|
|
304
|
+
* `dropHiddenColumnSort`.
|
|
305
|
+
*/
|
|
306
|
+
resetColumnLayout(): void;
|
|
307
|
+
/**
|
|
308
|
+
* The sort half of the legacy "hidden contributes nothing" invariant, kept ONLY for storeless
|
|
309
|
+
* tables (the generated M2M details grids, until spiderly#407 scaffolds their stores): they
|
|
310
|
+
* have no sort chip, so a hidden column's sort would order the grid with nothing on screen
|
|
311
|
+
* naming it and no control left to clear it. The filter half needs no heir — `lazyLoad`
|
|
312
|
+
* overwrites the outgoing filters unconditionally. On a store table this is a no-op:
|
|
313
|
+
* decision 2b's chips are the visible surface, hidden column or not.
|
|
314
|
+
*/
|
|
315
|
+
private dropHiddenColumnSort;
|
|
316
|
+
/**
|
|
317
|
+
* Per-column wrap, by `field`. A SEPARATE key from the visibility overrides on purpose: folding
|
|
318
|
+
* both into one object would invalidate every layout already in an operator's localStorage, and
|
|
319
|
+
* this is the key the width and order overrides will join (decision 5).
|
|
203
320
|
*/
|
|
204
|
-
private
|
|
205
|
-
/**
|
|
206
|
-
private
|
|
321
|
+
private columnWrap;
|
|
322
|
+
/** Data-column fields in the operator's order. Empty means "as declared". */
|
|
323
|
+
private columnOrder;
|
|
207
324
|
/**
|
|
208
|
-
*
|
|
209
|
-
*
|
|
325
|
+
* Per-column width overrides, as SHARES in the same unit `getColWidth` emits — never pixels.
|
|
326
|
+
* Under the fixed layout the browser splits surplus in proportion to these, so a pixel would
|
|
327
|
+
* pin the column and stop it answering the window: the operator on a 1280 laptop and the one
|
|
328
|
+
* on a 2560 monitor would get the same frozen column (decision 4).
|
|
210
329
|
*/
|
|
211
|
-
|
|
330
|
+
private columnWidths;
|
|
212
331
|
/**
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
332
|
+
* Layout keys carry the ACTIVE VIEW, which is what makes a view more than a saved filter: a
|
|
333
|
+
* picking view and a payments view want different COLUMNS, not just different rows. Global
|
|
334
|
+
* layout would re-create the original complaint one level up — the operator still re-picking
|
|
335
|
+
* columns every time the job changes.
|
|
336
|
+
*
|
|
337
|
+
* A table with no views has no segment, so the twenty-six tables that have not migrated keep
|
|
338
|
+
* reading exactly the keys they already wrote.
|
|
219
339
|
*/
|
|
220
|
-
private
|
|
340
|
+
private get viewScope();
|
|
221
341
|
/**
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
*
|
|
342
|
+
* Where the applied filters live. Follows `stateStorage` rather than the layout's always-local
|
|
343
|
+
* rule, because that is where they lived before the bar took them off the header: PrimeNG's
|
|
344
|
+
* stateful table persisted them for free, and nothing replaced it — a refresh dropped every
|
|
345
|
+
* filter (Filip, on /tags). A filter is a question you are in the middle of asking, not a
|
|
346
|
+
* durable preference like a column's width.
|
|
225
347
|
*/
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
private columnHasConstraint;
|
|
348
|
+
private get filtersStateKey();
|
|
349
|
+
private get filterStorage();
|
|
229
350
|
/**
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
* paint rather than after the first response.
|
|
351
|
+
* Where the active view id lives. Deliberately NOT view-scoped — it is the input `viewScope`
|
|
352
|
+
* derives from — and it follows `stateStorage` like the filters rather than the layout's
|
|
353
|
+
* always-local rule, because the id and the filters it scopes are one question: a durable id
|
|
354
|
+
* over session-scoped filters would restore a tab with nothing under it.
|
|
235
355
|
*/
|
|
236
|
-
private
|
|
356
|
+
private get viewStateKey();
|
|
357
|
+
/** Only `selectView` writes; the `ngOnInit` seed does not — absence means "the default". */
|
|
358
|
+
private persistActiveView;
|
|
359
|
+
/**
|
|
360
|
+
* Puts a reload back on the view the operator was using. Every persisted key carries the view
|
|
361
|
+
* segment, so before this existed the seed decided what got restored: F5 landed on the first
|
|
362
|
+
* view and read `…:all:filters` — the tab snapped to "Sve" and the bar came back empty while
|
|
363
|
+
* the operator's filters sat intact under the old view's segment (Filip, on /porudzbine).
|
|
364
|
+
*
|
|
365
|
+
* An id naming no current view keeps the seed AND the stored key: "vanished by deploy" and
|
|
366
|
+
* "not yet arrived" are indistinguishable here (order-list's catalog-licensed "Za pakovanje"
|
|
367
|
+
* is literally both), so `adoptStoredView` re-reads the key on every `[views]` change and the
|
|
368
|
+
* key self-heals on the next explicit click.
|
|
369
|
+
*/
|
|
370
|
+
private restoreActiveView;
|
|
371
|
+
/**
|
|
372
|
+
* The second half of `restoreActiveView`: a stored view that did not exist at init is adopted
|
|
373
|
+
* when a later `[views]` change brings it — through `selectView`, so it gets the same
|
|
374
|
+
* stored-wins/transient/layout/requery semantics a click would have had. There is no parked
|
|
375
|
+
* copy of the stored id — the key itself is re-read, and because every explicit pick
|
|
376
|
+
* overwrites it, the operator's own choice wins by construction. Accepted cost of adopting
|
|
377
|
+
* late instead of holding the first request: a brief flash of the seeded view's rows and a
|
|
378
|
+
* second request when the late view lands.
|
|
379
|
+
*/
|
|
380
|
+
private adoptStoredView;
|
|
381
|
+
private viewById;
|
|
382
|
+
private persistAppliedFilters;
|
|
383
|
+
/**
|
|
384
|
+
* Applies the right filters for entering `view` — the transient rule's one home. A TRANSIENT
|
|
385
|
+
* view's `apply` is a function of NOW, so it always re-derives; restoring would put
|
|
386
|
+
* yesterday's date under a tab claiming "today" (`persistAppliedFilters` has no transient
|
|
387
|
+
* guard, so storage holds the LAST answer). A non-transient view's own stored answer wins
|
|
388
|
+
* over its `apply`. The semantics argument is the one deliberate difference between the
|
|
389
|
+
* callers: a 'click' re-asks the view's question when nothing is stored, a 'refresh' returns
|
|
390
|
+
* the empty state the operator left — they cleared it, and F5 must give the cleared state
|
|
391
|
+
* back. On a table with no views, `view` is null and this is a plain restore of the
|
|
392
|
+
* `persistAppliedFilters` snapshot.
|
|
393
|
+
*/
|
|
394
|
+
private enterViewFilters;
|
|
395
|
+
private get layoutStateKey();
|
|
396
|
+
/** One key for the whole layout — wrap now, widths next (decision 5). */
|
|
397
|
+
private persistColumnLayout;
|
|
398
|
+
private restoreColumnLayout;
|
|
237
399
|
private persistColumnVisibility;
|
|
238
400
|
private restoreColumnVisibility;
|
|
239
401
|
/**
|
|
@@ -241,20 +403,74 @@ export declare class SpiderlyDataTableComponent implements OnInit, OnChanges, Af
|
|
|
241
403
|
* because we need it before PrimeNG's restoreState() runs on the first [value] change.
|
|
242
404
|
*/
|
|
243
405
|
private persistedTableState;
|
|
406
|
+
private activeView;
|
|
407
|
+
/**
|
|
408
|
+
* Where the operator's per-view sort override lives. Null on a table without views — those
|
|
409
|
+
* keep the pure PrimeNG sort persistence they always had — and null on a STORELESS table:
|
|
410
|
+
* there "hidden contributes nothing" retires a hidden column's sort (`dropHiddenColumnSort`)
|
|
411
|
+
* with no persist call at the hide site, so an override restored blind at the next init
|
|
412
|
+
* would re-impose a sort no chip can name. Store tables — where every viewed consumer
|
|
413
|
+
* lives — have the chip. Follows `stateStorage` like the filters and the view id: the sort
|
|
414
|
+
* is part of the same question they scope.
|
|
415
|
+
*/
|
|
416
|
+
private get viewSortStateKey();
|
|
417
|
+
/** The operator's stored sort for the active view, sanitized like any persisted sort. */
|
|
418
|
+
private persistedViewSort;
|
|
419
|
+
/** The sort this view asks for: the operator's stored override, else its declared sort. */
|
|
420
|
+
private viewSort;
|
|
421
|
+
/**
|
|
422
|
+
* Records the current sort as the active view's override — called from the EXPLICIT sort
|
|
423
|
+
* gestures only (header click, menu sort, Clear filters), never from a load: a sort merely
|
|
424
|
+
* inherited at init must not crystallize into an override, or a later change to the view's
|
|
425
|
+
* declared sort would stop flowing to operators who never touched sort — the same
|
|
426
|
+
* flows-through rule `columnVisibilityOverrides` documents. A sort equal to the declared
|
|
427
|
+
* default is stored as ABSENCE for the same reason.
|
|
428
|
+
*/
|
|
429
|
+
private persistActiveViewSort;
|
|
430
|
+
/**
|
|
431
|
+
* Puts the entering view's sort on the grid — stored override first, then the declared sort;
|
|
432
|
+
* a view stating no preference keeps the ordering already there (the pre-decision-10-sort
|
|
433
|
+
* behavior, and the least surprising for the tab an operator never sorted). Broadcast only —
|
|
434
|
+
* the caller owns the refetch, because which request carries the new sort differs between the
|
|
435
|
+
* store and storeless paths.
|
|
436
|
+
*/
|
|
437
|
+
private applyViewSort;
|
|
438
|
+
/**
|
|
439
|
+
* Rewrites the sort inside PrimeNG's persisted state to the one `ngOnInit` resolved. The two
|
|
440
|
+
* can disagree only on a viewed table — PrimeNG's state is table-global while the resolved
|
|
441
|
+
* sort is the view's — and PrimeNG's restoreState() applies its copy on the first [value]
|
|
442
|
+
* change, AFTER the initial request already left with ours: without this line the grid's
|
|
443
|
+
* arrows and every later request silently fall back to the other view's sort. Handed the
|
|
444
|
+
* already-parsed state: `ngOnInit` reads the blob once for the whole init pass.
|
|
445
|
+
*/
|
|
446
|
+
private alignPersistedTableStateSort;
|
|
447
|
+
/**
|
|
448
|
+
* The DECLARED default in the current context: the active view's own sort when it declares
|
|
449
|
+
* one, else the table-level `defaultSortField`. Every "fall back to the declared default"
|
|
450
|
+
* site — tri-state un-sort, Clear filters, the unsorted-load safety net — reads this, so
|
|
451
|
+
* un-sorting inside a view lands on the view's ordering, not the table's.
|
|
452
|
+
*/
|
|
453
|
+
private defaultMultiSortMeta;
|
|
244
454
|
/**
|
|
245
|
-
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
* In-memory only — once the constraint is gone, the user's stored choice reapplies.
|
|
455
|
+
* The active view's declared sort, sanitized: a non-sortable field would answer every load
|
|
456
|
+
* with a 400 (`keepSortableMeta`'s rationale), so it is dropped rather than sent; a view
|
|
457
|
+
* whose declaration sanitizes to nothing falls through to the table default.
|
|
249
458
|
*/
|
|
250
|
-
private
|
|
459
|
+
private viewDeclaredMultiSortMeta;
|
|
251
460
|
/**
|
|
252
|
-
* The declared default as PrimeNG sort meta, or null when none is declared
|
|
253
|
-
* column is hidden
|
|
254
|
-
*
|
|
461
|
+
* The table-level declared default as PrimeNG sort meta, or null when none is declared. On a
|
|
462
|
+
* store table it applies even while its column is hidden — the sort chip names the ordering
|
|
463
|
+
* whether or not the column is on screen (decision 2b). A STORELESS table has no chip, so a
|
|
464
|
+
* hidden default would order the grid with nothing on screen naming it; there the default
|
|
465
|
+
* dies with the column, exactly as the legacy invariant had it (see `dropHiddenColumnSort`).
|
|
255
466
|
*/
|
|
256
|
-
private
|
|
257
|
-
|
|
467
|
+
private tableDefaultMultiSortMeta;
|
|
468
|
+
/**
|
|
469
|
+
* `keepSortableMeta` with "sanitized to nothing" surfaced as null — the rule every sort
|
|
470
|
+
* SOURCE shares ("a sort that sanitizes to nothing is no sort"), so the resolution chains
|
|
471
|
+
* can `??` past an empty answer instead of stopping on an empty array.
|
|
472
|
+
*/
|
|
473
|
+
private sanitizedSortMeta;
|
|
258
474
|
/**
|
|
259
475
|
* Drops sort meta the backend has no sort case for. Persisted state outlives the rule that
|
|
260
476
|
* produced it — a sort stored before a column became non-sortable (or before the library
|
|
@@ -265,21 +481,9 @@ export declare class SpiderlyDataTableComponent implements OnInit, OnChanges, Af
|
|
|
265
481
|
* declares no column for.
|
|
266
482
|
*/
|
|
267
483
|
private keepSortableMeta;
|
|
268
|
-
/**
|
|
269
|
-
* The filter twin of `keepSortableMeta` — persisted state outlives the rule that produced
|
|
270
|
-
* it, here a match mode stored before the column declared `matchModes`. It has to REWRITE
|
|
271
|
-
* storage rather than filter a value on the way past: `ColumnFilter.ngOnInit` skips
|
|
272
|
-
* `initFieldFilterConstraint()` whenever the field already carries a constraint, so our
|
|
273
|
-
* `[matchMode]` never applies to a restored one. Left alone, the column keeps filtering by
|
|
274
|
-
* a mode it no longer offers while its match-mode `<p-select>` renders blank (the stored
|
|
275
|
-
* value is not among the options). Runs before PrimeNG's `restoreState()`, which reads this
|
|
276
|
-
* same key on the first `[value]` change.
|
|
277
|
-
*
|
|
278
|
-
* Deliberately narrow: it touches only constraints whose mode the declaring column no
|
|
279
|
-
* longer offers, so every other byte of the persisted blob survives.
|
|
280
|
-
*/
|
|
281
|
-
private reconcilePersistedMatchModes;
|
|
282
484
|
private applyDefaultSortIfUnsorted;
|
|
485
|
+
/** Puts `meta` on the grid and tells the header icons — no fetch; the caller owns that. */
|
|
486
|
+
private broadcastSort;
|
|
283
487
|
onPageChange(container: HTMLElement): void;
|
|
284
488
|
/**
|
|
285
489
|
* The one pending predicate: PrimeNG's overlay and the container's `aria-busy` must never
|
|
@@ -300,8 +504,6 @@ export declare class SpiderlyDataTableComponent implements OnInit, OnChanges, Af
|
|
|
300
504
|
*/
|
|
301
505
|
private reconcileSelectionForLoadedPage;
|
|
302
506
|
clientLoad(): void;
|
|
303
|
-
private clientFilterCount;
|
|
304
|
-
filter(event: TableFilterEvent): void;
|
|
305
507
|
private loadFormArrayItems;
|
|
306
508
|
/**
|
|
307
509
|
* Single source for whether a column header offers click-to-sort (drives both
|
|
@@ -311,6 +513,148 @@ export declare class SpiderlyDataTableComponent implements OnInit, OnChanges, Af
|
|
|
311
513
|
* sort fields are rejected with a 400, a clickable header here would be a guaranteed error toast.
|
|
312
514
|
*/
|
|
313
515
|
isColumnSortable(col: Column): boolean;
|
|
516
|
+
/** The column the header menu is currently open for, and its header cell. */
|
|
517
|
+
menuColumn: Column | null;
|
|
518
|
+
private menuHeaderCell;
|
|
519
|
+
private draggedColumn;
|
|
520
|
+
/** False while a gesture that began on the menu chevron or the resize grip is in flight. */
|
|
521
|
+
private headerDragArmed;
|
|
522
|
+
/**
|
|
523
|
+
* A ViewChild rather than a template reference passed in from the header. The popover lives in
|
|
524
|
+
* the CAPTION template and the button that opens it in the HEADER one, and a reference variable
|
|
525
|
+
* does not cross an ng-template boundary — it arrived as undefined, and the click did nothing
|
|
526
|
+
* at all.
|
|
527
|
+
*/
|
|
528
|
+
private readonly columnMenu;
|
|
529
|
+
private readonly filterBar;
|
|
530
|
+
/**
|
|
531
|
+
* Consumer-projected filter controls, forwarded to the bar. Collected here rather than by the
|
|
532
|
+
* bar itself because the bar is OURS: a consumer's template is projected at the table, and
|
|
533
|
+
* content queries only see what was projected into the component that declares them.
|
|
534
|
+
*/
|
|
535
|
+
filterTemplates: QueryList<SpiderlyFilterTemplateDirective>;
|
|
536
|
+
private readonly selectionHeader;
|
|
537
|
+
openColumnMenu(col: Column, event: Event): void;
|
|
538
|
+
/**
|
|
539
|
+
* Switches to a view. Clears first, always: a view is a STATE rather than an addition, and two
|
|
540
|
+
* of them composed produce a question nobody asked. The clear runs through the store directly
|
|
541
|
+
* rather than through `clear(table)`, which would also wipe the sort and the persisted state a
|
|
542
|
+
* view is entitled to keep.
|
|
543
|
+
*/
|
|
544
|
+
selectView(view: TableView): void;
|
|
545
|
+
/**
|
|
546
|
+
* The filter this column stands for. Defaults to the column's own `field`, because a store id
|
|
547
|
+
* IS a backend property name — `toFilterPayload` emits it straight into `Filter.filters`. So
|
|
548
|
+
* `filterId` is an escape hatch for the rare mismatch, not something every column restates:
|
|
549
|
+
* all eight of the first migrated table's declarations were the field name written a second
|
|
550
|
+
* time.
|
|
551
|
+
*/
|
|
552
|
+
private filterIdFor;
|
|
553
|
+
/**
|
|
554
|
+
* Asks the STORE, not the column. Checking only that an id was declared let a typo through to
|
|
555
|
+
* `store.get(id)`, which reads `definitions[id].label` — so a mistyped id threw on click rather
|
|
556
|
+
* than greying the item out. With 195 declarations to migrate, that is the failure mode worth
|
|
557
|
+
* closing here rather than in each consumer.
|
|
558
|
+
*/
|
|
559
|
+
canFilterColumn(col: Column): boolean;
|
|
560
|
+
/**
|
|
561
|
+
* Opens the bar's editor for this column's filter. The bar took the filter off the header and
|
|
562
|
+
* the header is still where an operator reaches for it, which is twenty-seven tables' worth of
|
|
563
|
+
* habit; this is the shortcut back rather than a second filter surface — it drives the same
|
|
564
|
+
* editor, on the same bar, that `+ Filter` opens.
|
|
565
|
+
*/
|
|
566
|
+
filterMenuColumn(): void;
|
|
567
|
+
/**
|
|
568
|
+
* Sorts by this column in the NAMED direction. Clicking a header cycles asc, desc and off,
|
|
569
|
+
* which is fine for one column and a guess for a direction someone wants now — you click, look,
|
|
570
|
+
* and click again if it went the other way. This is also the only sort path that works from a
|
|
571
|
+
* keyboard.
|
|
572
|
+
*
|
|
573
|
+
* A column the generated paginator has no sort case for answers every load with a 400, so the
|
|
574
|
+
* items are disabled by the same predicate that keeps its header from being clickable.
|
|
575
|
+
*/
|
|
576
|
+
sortMenuColumn(order: 1 | -1): void;
|
|
577
|
+
/**
|
|
578
|
+
* Sizes the column to the widest thing in it. The cheaper escape from a cramped column: no
|
|
579
|
+
* drag, no aim. Unlike a drag it does NOT trade with the neighbour — a minimum that grew is
|
|
580
|
+
* exactly the case decision 4 lets push the table past its container and start scrolling.
|
|
581
|
+
*
|
|
582
|
+
* Measures the CELL CONTENT, not the cell: the clamp lives on the inner span, so a `td` reports
|
|
583
|
+
* a scrollWidth that fits while the text inside it does not.
|
|
584
|
+
*/
|
|
585
|
+
fitMenuColumn(): void;
|
|
586
|
+
/**
|
|
587
|
+
* The share that actually yields `needed` pixels — not `needed` scaled by the column's current
|
|
588
|
+
* px-per-share, which is the obvious answer and the wrong one. Shares are a PROPORTION of
|
|
589
|
+
* whatever width the table has, so growing this column's share also shrinks the realized width
|
|
590
|
+
* of every other column, and the naive figure lands short. The spec caught it as a cell that
|
|
591
|
+
* was still clipped after being told to fit.
|
|
592
|
+
*
|
|
593
|
+
* While the columns fit, the table keeps the container's width and the proportion has to solve
|
|
594
|
+
* needed / tableWidth = newShare / (otherShares + newShare)
|
|
595
|
+
* with `otherShares` recovered from what this column currently renders at. Once `needed` is the
|
|
596
|
+
* whole container the proportional regime has no answer: the table is about to overrun its
|
|
597
|
+
* container and scroll (decision 4), and there a share IS its own length, so the pixels convert
|
|
598
|
+
* straight through the root font size.
|
|
599
|
+
*/
|
|
600
|
+
private shareThatFits;
|
|
601
|
+
hideMenuColumn(): void;
|
|
602
|
+
/**
|
|
603
|
+
* Whether this column's cells give up the one-line clamp. The DEFAULT stays clamped
|
|
604
|
+
* (CLAUDE.md -> "Operator-owned view", decision 9); what changes is that the operator picks
|
|
605
|
+
* which column pays the row height, not whoever wrote `cols`.
|
|
606
|
+
*
|
|
607
|
+
* Lands on the td as `.cell-wrap`, whose inherited `--spiderly-cell-*` properties are how the
|
|
608
|
+
* toggle crosses into a projected `spiderlyCellTemplate` too — the contract's one telling is
|
|
609
|
+
* on that SCSS rule; a consumer clamp that hard-codes its values opts out.
|
|
610
|
+
*/
|
|
611
|
+
isColumnWrapped(col: Column): boolean;
|
|
612
|
+
get isMenuColumnWrapped(): boolean;
|
|
613
|
+
toggleWrapForMenuColumn(): void;
|
|
614
|
+
/** Exposed for the template: actions columns carry no field and get no menu. */
|
|
615
|
+
isDataColumn(col: Column): boolean;
|
|
616
|
+
/**
|
|
617
|
+
* What the grid is ordered by, resolved to COLUMN NAMES for the bar. Read off PrimeNG's live
|
|
618
|
+
* meta rather than mirrored into a field, so it cannot fall out of step with the sort the table
|
|
619
|
+
* is actually applying. A field with no column left (hidden, or removed in a later release)
|
|
620
|
+
* falls back to its own name rather than vanishing from the list.
|
|
621
|
+
*/
|
|
622
|
+
/**
|
|
623
|
+
* What the grid is ordered by, resolved to COLUMN NAMES for the bar.
|
|
624
|
+
*
|
|
625
|
+
* A field refreshed per fetch, not a getter: it is bound to the bar's `sort`, which is a SIGNAL
|
|
626
|
+
* input, so a freshly mapped array failed `Object.is` on every change-detection pass and marked
|
|
627
|
+
* the bar's consumers dirty forever — for a value that changes once per request. Same reason
|
|
628
|
+
* `tableStyle` is a field.
|
|
629
|
+
*/
|
|
630
|
+
sortKeys: SortKeyLabel[];
|
|
631
|
+
/**
|
|
632
|
+
* Read off the last REQUEST's sort, not `table._multiSortMeta`. On a first load with a declared
|
|
633
|
+
* default that field is still null: `applyDefaultSortIfUnsorted` writes the default onto the
|
|
634
|
+
* lazy-load event, and PrimeNG fills its own meta only once someone clicks a header. Reading the
|
|
635
|
+
* table there showed no sort on exactly the tables that always have one. A field with no column
|
|
636
|
+
* left falls back to its own name rather than vanishing.
|
|
637
|
+
*/
|
|
638
|
+
private refreshSortKeys;
|
|
639
|
+
/** This column's share, override first, then its declared width, then the per-type default. */
|
|
640
|
+
columnShare(col: Column): number;
|
|
641
|
+
/**
|
|
642
|
+
* A declared width expressed in SHARE units. rem IS the share unit and px converts; any other
|
|
643
|
+
* unit falls back to the per-type default rather than being read as a bare number.
|
|
644
|
+
*
|
|
645
|
+
* `parseFloat` alone shipped here first, so `width: '150px'` resolved to share 150 against
|
|
646
|
+
* neighbours at 12 — one column eating the grid on the first drag or fit. Every declared width
|
|
647
|
+
* in the consumer happens to be rem today, which is exactly why nothing would have caught it.
|
|
648
|
+
*/
|
|
649
|
+
private shareOfDeclaredWidth;
|
|
650
|
+
private defaultShare;
|
|
651
|
+
/**
|
|
652
|
+
* Trades share between the column being dragged and the one on its right, so the table keeps
|
|
653
|
+
* its total: widening a column never starts a horizontal scroll by itself, which only happens
|
|
654
|
+
* once the SUM of the minimums stops fitting. The px delta is converted through the column's
|
|
655
|
+
* own rendered width, which is the only place the share-to-pixel scale is actually known.
|
|
656
|
+
*/
|
|
657
|
+
startColumnResize(col: Column, event: MouseEvent, th: HTMLElement): void;
|
|
314
658
|
/**
|
|
315
659
|
* The column's declared {@link Column.width}, or the default for its filter type.
|
|
316
660
|
*
|
|
@@ -320,51 +664,6 @@ export declare class SpiderlyDataTableComponent implements OnInit, OnChanges, Af
|
|
|
320
664
|
* per-type defaults say — a boolean holds "Da"/"Ne", a text column holds a name.
|
|
321
665
|
*/
|
|
322
666
|
getColWidth(col: Column): string;
|
|
323
|
-
/**
|
|
324
|
-
* Memo for the resolution below. Two jobs: the narrowing maps to a NEW array and a
|
|
325
|
-
* template binding must not hand PrimeNG a fresh reference every CD pass, and both
|
|
326
|
-
* halves (offered list, default mode) must come from ONE computation so they cannot
|
|
327
|
-
* disagree. Keyed on the declared array's identity, so reassigning `col.matchModes`
|
|
328
|
-
* recomputes — note PrimeNG itself reads `matchModeOptions` only in its own `ngOnInit`,
|
|
329
|
-
* so a post-init change still never reaches the rendered dropdown.
|
|
330
|
-
*/
|
|
331
|
-
private matchModeResolutions;
|
|
332
|
-
getColMatchModeOptions(col: Column): SelectItem[] | null;
|
|
333
|
-
getColMatchMode(col: Column): any;
|
|
334
|
-
private resolveMatchModes;
|
|
335
|
-
/**
|
|
336
|
-
* Applies `Column.matchModes`, and refuses to half-apply it. Both ways a declaration can
|
|
337
|
-
* be wrong are consumer mistakes that PrimeNG would otherwise turn into a broken filter
|
|
338
|
-
* rather than an error: it reads `matchModeOptions || <type defaults>`, so handing it
|
|
339
|
-
* `[]` renders an EMPTY dropdown (an empty array is truthy) while the default mode still
|
|
340
|
-
* seeds the constraint, and handing it `null` silently restores PrimeNG's own list. So an
|
|
341
|
-
* unusable narrowing falls back to the full list and says so, instead of shipping a
|
|
342
|
-
* dropdown the user cannot pick from.
|
|
343
|
-
*/
|
|
344
|
-
private computeMatchModes;
|
|
345
|
-
private matchModeOptionsForType;
|
|
346
|
-
private defaultMatchModeForType;
|
|
347
|
-
isDropOrMulti(filterType: string): boolean;
|
|
348
|
-
/**
|
|
349
|
-
* Whether the filter type applies on every value change, which hides the menu's Apply
|
|
350
|
-
* button — an Apply there would promise a pending state that cannot exist. Boolean
|
|
351
|
-
* auto-applies through PrimeNG's own `onModelChange`; date and dropdown/multiselect
|
|
352
|
-
* through the filter templates THIS component projects, which call `filterCallback`
|
|
353
|
-
* directly (PrimeNG's built-in element, and with it its `onModelChange`, is only
|
|
354
|
-
* rendered when no template is projected — so the date path is ours, not PrimeNG's).
|
|
355
|
-
* With showApplyButton off, PrimeNG also auto-applies match-mode, operator and
|
|
356
|
-
* constraint-removal changes, so the whole menu stays consistent. Typed input
|
|
357
|
-
* (text/numeric) is deliberately NOT here — it commits on Enter/Apply, since applying
|
|
358
|
-
* per keystroke would fire a lazy load per key. Listing the auto types (not the typed
|
|
359
|
-
* ones) is the safe polarity: an unlisted future type keeps its Apply button rather
|
|
360
|
-
* than silently losing its commit.
|
|
361
|
-
*
|
|
362
|
-
* Known gap this does not close, and it predates the flag: the projected date template
|
|
363
|
-
* binds `[ngModel]` one-way and commits on `(onSelect)`, which the datepicker raises for
|
|
364
|
-
* a calendar pick but not for `onUserInput` — so a date TYPED into the field never
|
|
365
|
-
* reaches the constraint at all, with or without an Apply button.
|
|
366
|
-
*/
|
|
367
|
-
filterAppliesOnChange(filterType: string): boolean;
|
|
368
667
|
navigateToDetails(rowId: number): void;
|
|
369
668
|
/**
|
|
370
669
|
* Handle row click event. Arbitration between "this click navigates the row" and "this click
|
|
@@ -384,6 +683,28 @@ export declare class SpiderlyDataTableComponent implements OnInit, OnChanges, Af
|
|
|
384
683
|
ngOnDestroy(): void;
|
|
385
684
|
get showSelectAllCheckbox(): boolean;
|
|
386
685
|
private resetSelection;
|
|
686
|
+
/**
|
|
687
|
+
* A COMMITTED filter re-queries; a draft does not. Re-fetching per keystroke would be the same
|
|
688
|
+
* lie the chip bar exists to prevent, only paid for in requests rather than in credibility.
|
|
689
|
+
*
|
|
690
|
+
* Back to page one first, and off FRESH metadata rather than `reload()`: that one replays the
|
|
691
|
+
* cached lazy-load event, whose `first` was copied when the event was built, so a filter applied
|
|
692
|
+
* from page 3 would keep asking the server to skip 50 rows a narrower result set does not have.
|
|
693
|
+
* The grid comes back empty for a value that is definitely in it.
|
|
694
|
+
*
|
|
695
|
+
* The first run is PrimeNG's: it fires the initial lazy load itself, and re-querying here would
|
|
696
|
+
* make every table load twice.
|
|
697
|
+
*/
|
|
698
|
+
private requeryOnAppliedFilters;
|
|
699
|
+
/**
|
|
700
|
+
* Back to page one, state saved, one fetch off FRESH metadata — the shared tail of the
|
|
701
|
+
* requery effect and `selectView`'s sort-only switch. The save is load-bearing: PrimeNG
|
|
702
|
+
* saves state only from its own interactions, so without it the pre-change page offset
|
|
703
|
+
* survives in storage and the NEXT visit replays it against a narrowed result set — the
|
|
704
|
+
* backend answers data=[] for an offset the filtered total no longer reaches, and the grid
|
|
705
|
+
* renders empty under chips claiming matches.
|
|
706
|
+
*/
|
|
707
|
+
private refetchFromFirstPage;
|
|
387
708
|
reload(): void;
|
|
388
709
|
showActions(): boolean;
|
|
389
710
|
getStyleForBodyColumn(col: Column<any>): string;
|
|
@@ -394,6 +715,11 @@ export declare class SpiderlyDataTableComponent implements OnInit, OnChanges, Af
|
|
|
394
715
|
colTrackByFn(index: any, item: any): any;
|
|
395
716
|
actionTrackByFn(index: any, item: Action): string;
|
|
396
717
|
exportListToExcel(): void;
|
|
718
|
+
/**
|
|
719
|
+
* Clears everything that narrows the grid. With a store supplied it has to reach BOTH — the
|
|
720
|
+
* store holds the constraints and PrimeNG holds the persisted state and sort — or the bar goes
|
|
721
|
+
* empty while a reload brings the old filters back.
|
|
722
|
+
*/
|
|
397
723
|
clear(table: Table): void;
|
|
398
724
|
setFakeIsAllSelected(): void;
|
|
399
725
|
selectAll(checked: boolean): void;
|
|
@@ -426,7 +752,7 @@ export declare class SpiderlyDataTableComponent implements OnInit, OnChanges, Af
|
|
|
426
752
|
rowUnselect(id: number): void;
|
|
427
753
|
getFormArrayControlByIndex(formControlName: string, index: number): SpiderlyFormControl;
|
|
428
754
|
static ɵfac: i0.ɵɵFactoryDeclaration<SpiderlyDataTableComponent, never>;
|
|
429
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<SpiderlyDataTableComponent, "spiderly-data-table", never, { "tableTitle": { "alias": "tableTitle"; "required": false; }; "tableIcon": { "alias": "tableIcon"; "required": false; }; "items": { "alias": "items"; "required": false; }; "rows": { "alias": "rows"; "required": false; }; "rowsPerPageOptions": { "alias": "rowsPerPageOptions"; "required": false; }; "cols": { "alias": "cols"; "required": false; }; "showPaginator": { "alias": "showPaginator"; "required": false; }; "showCardWrapper": { "alias": "showCardWrapper"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "idField": { "alias": "idField"; "required": false; }; "getPaginatedListObservableMethod": { "alias": "getPaginatedListObservableMethod"; "required": false; }; "exportListToExcelObservableMethod": { "alias": "exportListToExcelObservableMethod"; "required": false; }; "deleteItemFromTableObservableMethod": { "alias": "deleteItemFromTableObservableMethod"; "required": false; }; "deleteListFromTableObservableMethod": { "alias": "deleteListFromTableObservableMethod"; "required": false; }; "newlySelectedItems": { "alias": "newlySelectedItems"; "required": false; }; "unselectedItems": { "alias": "unselectedItems"; "required": false; }; "selectionMode": { "alias": "selectionMode"; "required": false; }; "selectedLazyLoadObservableMethod": { "alias": "selectedLazyLoadObservableMethod"; "required": false; }; "additionalFilterIdLong": { "alias": "additionalFilterIdLong"; "required": false; }; "showAddButton": { "alias": "showAddButton"; "required": false; }; "showExportToExcelButton": { "alias": "showExportToExcelButton"; "required": false; }; "showReloadTableButton": { "alias": "showReloadTableButton"; "required": false; }; "getFormArrayItems": { "alias": "getFormArrayItems"; "required": false; }; "hasLazyLoad": { "alias": "hasLazyLoad"; "required": false; }; "stateKey": { "alias": "stateKey"; "required": false; }; "stateStorage": { "alias": "stateStorage"; "required": false; }; "defaultSortField": { "alias": "defaultSortField"; "required": false; }; "defaultSortOrder": { "alias": "defaultSortOrder"; "required": false; }; "getAlreadySelectedItemIds": { "alias": "getAlreadySelectedItemIds"; "required": false; }; "getAlreadySelectedItems": { "alias": "getAlreadySelectedItems"; "required": false; }; "getFormControl": { "alias": "getFormControl"; "required": false; }; "additionalIndexes": { "alias": "additionalIndexes"; "required": false; }; "navigateOnRowClick": { "alias": "navigateOnRowClick"; "required": false; }; "rowNavigationPath": { "alias": "rowNavigationPath"; "required": false; }; }, { "onTotalRecordsChange": "onTotalRecordsChange"; "onLazyLoad": "onLazyLoad"; "onIsAllSelectedChange": "onIsAllSelectedChange"; "onRowSelect": "onRowSelect"; "onRowUnselect": "onRowUnselect"; }, ["actionsTemplate", "cellTemplates"], never, true, never>;
|
|
755
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<SpiderlyDataTableComponent, "spiderly-data-table", never, { "tableTitle": { "alias": "tableTitle"; "required": false; }; "tableIcon": { "alias": "tableIcon"; "required": false; }; "items": { "alias": "items"; "required": false; }; "rows": { "alias": "rows"; "required": false; }; "rowsPerPageOptions": { "alias": "rowsPerPageOptions"; "required": false; }; "cols": { "alias": "cols"; "required": false; }; "filters": { "alias": "filters"; "required": false; }; "views": { "alias": "views"; "required": false; }; "showPaginator": { "alias": "showPaginator"; "required": false; }; "showCardWrapper": { "alias": "showCardWrapper"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "idField": { "alias": "idField"; "required": false; }; "getPaginatedListObservableMethod": { "alias": "getPaginatedListObservableMethod"; "required": false; }; "exportListToExcelObservableMethod": { "alias": "exportListToExcelObservableMethod"; "required": false; }; "deleteItemFromTableObservableMethod": { "alias": "deleteItemFromTableObservableMethod"; "required": false; }; "deleteListFromTableObservableMethod": { "alias": "deleteListFromTableObservableMethod"; "required": false; }; "newlySelectedItems": { "alias": "newlySelectedItems"; "required": false; }; "unselectedItems": { "alias": "unselectedItems"; "required": false; }; "selectionMode": { "alias": "selectionMode"; "required": false; }; "selectedLazyLoadObservableMethod": { "alias": "selectedLazyLoadObservableMethod"; "required": false; }; "additionalFilterIdLong": { "alias": "additionalFilterIdLong"; "required": false; }; "showAddButton": { "alias": "showAddButton"; "required": false; }; "showExportToExcelButton": { "alias": "showExportToExcelButton"; "required": false; }; "showReloadTableButton": { "alias": "showReloadTableButton"; "required": false; }; "getFormArrayItems": { "alias": "getFormArrayItems"; "required": false; }; "hasLazyLoad": { "alias": "hasLazyLoad"; "required": false; }; "stateKey": { "alias": "stateKey"; "required": false; }; "stateStorage": { "alias": "stateStorage"; "required": false; }; "defaultSortField": { "alias": "defaultSortField"; "required": false; }; "defaultSortOrder": { "alias": "defaultSortOrder"; "required": false; }; "getAlreadySelectedItemIds": { "alias": "getAlreadySelectedItemIds"; "required": false; }; "getAlreadySelectedItems": { "alias": "getAlreadySelectedItems"; "required": false; }; "getFormControl": { "alias": "getFormControl"; "required": false; }; "additionalIndexes": { "alias": "additionalIndexes"; "required": false; }; "navigateOnRowClick": { "alias": "navigateOnRowClick"; "required": false; }; "rowNavigationPath": { "alias": "rowNavigationPath"; "required": false; }; }, { "onTotalRecordsChange": "onTotalRecordsChange"; "onLazyLoad": "onLazyLoad"; "onIsAllSelectedChange": "onIsAllSelectedChange"; "onRowSelect": "onRowSelect"; "onRowUnselect": "onRowUnselect"; }, ["actionsTemplate", "cellTemplates", "filterTemplates"], never, true, never>;
|
|
430
756
|
}
|
|
431
757
|
export declare class Action {
|
|
432
758
|
name?: string;
|
|
@@ -452,29 +778,77 @@ export declare class Action {
|
|
|
452
778
|
onClick?: (event: ActionClickEvent) => void;
|
|
453
779
|
});
|
|
454
780
|
}
|
|
781
|
+
/**
|
|
782
|
+
* A saved question. The bar lets an operator BUILD one; a view is the one they ask every morning,
|
|
783
|
+
* asked in a click — and without them the whole column-and-filter rework is a pile of knobs
|
|
784
|
+
* someone re-sets daily (CLAUDE.md -> "Operator-owned view", decision 10).
|
|
785
|
+
*
|
|
786
|
+
* Declared in consumer code, not stored per user: with a handful of operators and a handful of
|
|
787
|
+
* fixed daily jobs, shared built-in views cover the work, while personal saved views would drift
|
|
788
|
+
* into five variants of the same question. Personal LAYOUT choices still persist on top, per view.
|
|
789
|
+
*/
|
|
790
|
+
export interface TableView<TFilters = any> {
|
|
791
|
+
id: string;
|
|
792
|
+
label: string;
|
|
793
|
+
/**
|
|
794
|
+
* Sets the filters this view asks for. Receives the table's own store, so a consumer writes it
|
|
795
|
+
* with the store's typing. Called on a CLEARED store: a view is a state, not an addition.
|
|
796
|
+
*/
|
|
797
|
+
apply?: (filters: TFilters) => void;
|
|
798
|
+
/**
|
|
799
|
+
* A view whose `apply` is a function of NOW — "Danas primljene", "this week". Selecting it
|
|
800
|
+
* always re-runs `apply` instead of restoring what an earlier visit stored: under the normal
|
|
801
|
+
* stored-wins rule a relative-date view clicked yesterday would restore yesterday's date under
|
|
802
|
+
* a tab claiming "today". Layout (columns, widths, wrap) still persists per view as usual —
|
|
803
|
+
* transience is about the QUESTION, not the furniture.
|
|
804
|
+
*/
|
|
805
|
+
transient?: boolean;
|
|
806
|
+
/**
|
|
807
|
+
* The view's declared ordering — for the view whose question includes one ("oldest shipped
|
|
808
|
+
* first" IS the work list, not a reading preference). Entering the view applies it; the
|
|
809
|
+
* tri-state un-sort and Clear filters return to it instead of the table default; an operator's
|
|
810
|
+
* own sort overrides it, persisted per view on store tables (decision 10's sort half). A view
|
|
811
|
+
* declaring none keeps whatever ordering the grid already has, exactly as before this field
|
|
812
|
+
* existed.
|
|
813
|
+
*/
|
|
814
|
+
sort?: SortMeta[];
|
|
815
|
+
}
|
|
455
816
|
export declare class Column<T = any> {
|
|
456
817
|
name?: string;
|
|
457
818
|
field?: string & keyof T;
|
|
458
|
-
|
|
819
|
+
/**
|
|
820
|
+
* The column's VALUE SHAPE: it sizes the column (`getColWidth`), picks the cell rendering
|
|
821
|
+
* (`getRowData`, the blob branch) and the numeric right-align. The name is a fossil of the
|
|
822
|
+
* header-filter era — filtering lives in the store handed to `[filters]` — kept because
|
|
823
|
+
* renaming it would be a 195-declaration migration for zero behavior.
|
|
824
|
+
*/
|
|
459
825
|
filterType?: 'text' | 'date' | 'multiselect' | 'boolean' | 'numeric' | 'blob';
|
|
460
|
-
filterPlaceholder?: string;
|
|
461
|
-
showMatchModes?: boolean;
|
|
462
826
|
/**
|
|
463
|
-
*
|
|
464
|
-
*
|
|
465
|
-
*
|
|
466
|
-
* match can never hit: `matchModes: [MatchModeCodes.GreaterThan, MatchModeCodes.LessThan]`.
|
|
467
|
-
*
|
|
468
|
-
* Read at declaration time: PrimeNG generates the dropdown once in its own `ngOnInit`, so
|
|
469
|
-
* reassigning this later never reaches the rendered menu.
|
|
827
|
+
* The id of the filter in the table's store that this column stands for, which is what the
|
|
828
|
+
* header menu's `Filter…` opens. A LINK, not a declaration: the filter exists in the store
|
|
829
|
+
* whether or not any column names it, and a column needs this only to offer the shortcut.
|
|
470
830
|
*
|
|
471
|
-
*
|
|
472
|
-
*
|
|
473
|
-
*
|
|
474
|
-
* anything else is logged and ignored (`computeMatchModes`).
|
|
831
|
+
* Untyped against the store on purpose — a `Column<T>` knows its row type and nothing about
|
|
832
|
+
* which store it will be rendered beside, so the compile-time key check lives where the store
|
|
833
|
+
* is declared (`createFilterStore`), not here.
|
|
475
834
|
*/
|
|
476
|
-
|
|
477
|
-
|
|
835
|
+
filterId?: string;
|
|
836
|
+
/**
|
|
837
|
+
* @deprecated Dead since the header-filter deletion: NOTHING reads it. It survives on the type
|
|
838
|
+
* only so details-table cols emitted by an OLDER Spiderly.SourceGenerators (which wrote
|
|
839
|
+
* `showMatchModes: true`) still compile against this library during a mixed-version window —
|
|
840
|
+
* a consumer on published NuGet generators plus an npm-linked library build. Delete it once
|
|
841
|
+
* every consumer regenerates with a generator from this release or later (spiderly#407).
|
|
842
|
+
*/
|
|
843
|
+
showMatchModes?: boolean;
|
|
844
|
+
/**
|
|
845
|
+
* @deprecated The same version-skew bridge as {@link showMatchModes}, and nothing else: older
|
|
846
|
+
* generators emit `filterField: 'xxxId'` for every dropdown-typed details-table column, so
|
|
847
|
+
* deleting it breaks the mixed window the moment a consumer adds one. NOTHING reads it —
|
|
848
|
+
* filter ids live in the store, linked from a column via {@link filterId}. Delete with
|
|
849
|
+
* `showMatchModes` (spiderly#407).
|
|
850
|
+
*/
|
|
851
|
+
filterField?: string & keyof T;
|
|
478
852
|
dropdownOrMultiselectValues?: PrimengOption[];
|
|
479
853
|
actions?: Action[];
|
|
480
854
|
editable?: boolean;
|
|
@@ -493,9 +867,8 @@ export declare class Column<T = any> {
|
|
|
493
867
|
*/
|
|
494
868
|
lockVisible?: boolean;
|
|
495
869
|
/**
|
|
496
|
-
* CSS length fixing this column's width (e.g. `'8rem'`). Overrides the per-
|
|
497
|
-
* which is
|
|
498
|
-
* for a column of short values.
|
|
870
|
+
* CSS length fixing this column's width (e.g. `'8rem'`). Overrides the per-type default,
|
|
871
|
+
* which is generous for a column of short values.
|
|
499
872
|
*
|
|
500
873
|
* Declare a width on the columns that must stay NARROW and leave the flexible one undeclared:
|
|
501
874
|
* the table distributes its surplus in proportion to the declared widths, so a column carrying
|
|
@@ -512,15 +885,13 @@ export declare class Column<T = any> {
|
|
|
512
885
|
* Not applied to editable cells — those belong to their inline input.
|
|
513
886
|
*/
|
|
514
887
|
onCellClick?: (event: CellClickEvent) => void;
|
|
515
|
-
constructor({ name, field,
|
|
888
|
+
constructor({ name, field, filterType, filterId, showMatchModes, filterField, dropdownOrMultiselectValues, actions, editable, showTime, decimalPlaces, sortable, visible, lockVisible, width, onCellClick, }?: {
|
|
516
889
|
name?: string;
|
|
517
890
|
field?: string & keyof T;
|
|
518
|
-
filterField?: string & keyof T;
|
|
519
891
|
filterType?: 'text' | 'date' | 'multiselect' | 'boolean' | 'numeric' | 'blob';
|
|
520
|
-
|
|
892
|
+
filterId?: string;
|
|
521
893
|
showMatchModes?: boolean;
|
|
522
|
-
|
|
523
|
-
showAddButton?: boolean;
|
|
894
|
+
filterField?: string & keyof T;
|
|
524
895
|
dropdownOrMultiselectValues?: PrimengOption[];
|
|
525
896
|
actions?: Action[];
|
|
526
897
|
editable?: boolean;
|