spiderly 19.12.0 → 19.12.2

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.
@@ -174,7 +174,7 @@ Two details that decide whether the guard actually works:
174
174
  </spiderly-data-table>
175
175
  ```
176
176
 
177
- Lazy tables are always deterministically ordered: when no sort is active the backend falls back to `Id` DESC (newest first). Declare `defaultSortField` (+ `defaultSortOrder`) when a page wants a different, user-visible default — it renders as a normal header sort arrow, persisted user sort wins over it, and un-sorting (tri-state header click, Clear filters) returns to it instead of "unsorted".
177
+ Lazy tables are always deterministically ordered: when no sort is active the backend falls back to `Id` DESC (newest first). Declare `defaultSortField` (+ `defaultSortOrder`) when a page wants a different, user-visible default — it renders as a normal header sort arrow, persisted user sort wins over it, and un-sorting (tri-state header click, the sort picker's reset row) returns to it instead of "unsorted". Clear filters never touches the sort — sort has its own affordances.
178
178
 
179
179
  Every paginated table offers a rows-per-page dropdown — `rowsPerPageOptions`, default `[10, 25, 50, 100]`; a custom initial `rows` value is merged in automatically. The user's pick rides PrimeNG table state, so it persists per table under the existing `stateKey` (session-scoped unless `stateStorage: 'local'`).
180
180
 
@@ -255,7 +255,7 @@ filters = createProductFilters((key) => this.translocoService.translate(key));
255
255
  <spiderly-data-table [cols]="cols" [filters]="filters" ...></spiderly-data-table>
256
256
  ```
257
257
 
258
- The table renders the store as a **chip bar** above the header: one chip per *applied* filter, a read-only sort chip, the result count, `+ Filter` (a searchable popover of every declared filter) and Clear filters. Rules that follow:
258
+ The table renders the store as a **chip bar** above the header: one chip per *applied* filter, the sort picker, the result count, `+ Filter` (a searchable popover of every declared filter) and Clear filters (which clears *only* the filters — never the sort). The sort picker's chip names the current ordering ("Sorted by: …", with the primary key first) and opens a popover of **every sortable column, hidden ones included** — pick to sort ascending, pick the active ascending option to flip it, and a *Reset to default sort* row appears while the ordering differs from the resolved default. Rules that follow:
259
259
 
260
260
  - **Store ids are backend property names** — they go straight into the paginated request — so they normally repeat the column's `field`. A column whose filter id differs links to it with `Column.filterId` (that is what the header menu's `Filter…` opens); columns never *declare* filters.
261
261
  - **Filters live independently of columns.** A filter with no column, or with a hidden one, is still offered and still narrows the grid — the chip is the visible surface, so hiding a column keeps its filter and sort.
@@ -263,10 +263,10 @@ The table renders the store as a **chip bar** above the header: one chip per *ap
263
263
  - **Late-arriving options go through `store.setOptions(id, options)`** — it re-resolves the offered operators and open editors read it live. Never write `definitions[id].options` by hand.
264
264
  - **Programmatic writes use `setAndCommit(id, { operator, value })`** (a view's `apply`, a bulk-action flow). A bare `set` without `commit` changes only the draft and fails silently.
265
265
  - **`offered: false`** keeps a filter out of `+ Filter` when a dedicated control on the page drives it through `filters.get(id)` (render the handle's `value()` draft, `commit()` on your own cadence — a search box, typically). Its chip still renders when applied.
266
- - **Applied filters persist** under `` `${stateKey}:filters` `` in the `stateStorage` storage (session by default), separately from PrimeNG's own sort/pagination blob under `` `${stateKey}` ``.
266
+ - **Applied filters persist** under `` `${stateKey}:filters` `` in the `stateStorage` storage (session by default), separately from PrimeNG's own sort/pagination blob under `` `${stateKey}` ``. On a table with `[views]` the filters key always carries the active view segment (`` `${stateKey}:${viewId}:filters` ``); the active view id itself persists under `` `${stateKey}:view` `` and is restored on reload, seeding from the first view only when nothing is stored.
267
267
  - **A custom editor control for one filter** is a projected `<ng-template spiderlyFilterTemplate="filterId" let-f>`: drive it through the handle (`f.value()`, `f.set(...)`, `f.commit()`). Filters without a template keep the control the bar draws for their kind.
268
268
 
269
- **Views** (`[views]`, `TableView[]`) are saved questions rendered as tabs above the bar: each `apply` receives the cleared store (a view is a state, not an addition) and writes with `setAndCommit`; a view whose apply is a function of *now* ("received today") declares `transient: true` so selecting it re-derives instead of restoring yesterday's answer. Column layout (visibility, order, widths, wrap) persists per view.
269
+ **Views** (`[views]`, `TableView[]`) are saved questions rendered as tabs above the bar: each `apply` receives the cleared store (a view is a state, not an addition) and writes with `setAndCommit`; a view whose apply is a function of *now* ("received today") declares `transient: true` so selecting it re-derives instead of restoring yesterday's answer. Column layout (visibility, order, widths, wrap) persists per view. A stored view id whose view is not in `[views]` yet (async-licensed views) is adopted when it arrives — unless the operator picked another tab meanwhile — and a restored transient view re-derives its question. **Sort is view state too**: entering a view resolves the user's per-view sort override ?? the view's declared `sort` ?? the table's `defaultSortField` ?? unsorted — it never inherits the previous tab's ordering, so give the catch-all first view a table-level default when "newest first" isn't what you want there.
270
270
 
271
271
  ### Column chooser (show/hide columns)
272
272
 
@@ -326,7 +326,7 @@ Project an `<ng-template spiderlyCellTemplate="field">` to render one column's c
326
326
  - **Cells only.** The header and its sorting are untouched, and the column's filter (a store entry, see Filtering above) works whatever the template draws.
327
327
  - The template binds to the **consuming component**, so its handlers and pipes are yours.
328
328
  - A real `<a [routerLink]>` here beats `onCellClick` for navigation — middle-click and Ctrl+click open a new tab, which a JavaScript `navigate()` does not.
329
- - This is also the way out of the enum-cell limit: a `multiselect` column renders the raw stored value in its cell (the table does not map it through `dropdownOrMultiselectValues`), so a template that draws the label from the row's id gets the checkbox filter *and* readable cells.
329
+ - A `multiselect` column needs no template for readable cells — `getRowData` already maps the stored value through the column's `dropdownOrMultiselectValues` (raw value as the fallback while options load). Reach for a template only when the row carries a better display value than the option list can give (e.g. a `*DisplayName` the DTO already holds).
330
330
 
331
331
  ### Custom Toolbar Actions
332
332
 
@@ -101,7 +101,7 @@ Filtering is the chip bar above the table (a `spiderly-data-table` given a filte
101
101
 
102
102
  - **Operator option labels are transloco output** (`'More than'`, `'Less than'`), not `MatchModeCodes` keys. Match Playwright selectors against the value in your `en.json` (or the locale your test runs under). Which operators a filter offers is the store declaration's `operators` (or the kind's full list).
103
103
  - **The boolean editor is a binary `<p-checkbox>`** starting unchecked: one click drafts `true`, a second drafts `false`; commit with Apply.
104
- - **Applied filters persist under `` `${stateKey}:filters` ``** (the store snapshot: `{ id: { operator, value } }` on the wire vocabulary — `'contains'`, `'greaterThan'`, …); sort and pagination stay in PrimeNG's own blob under `` `${stateKey}` ``. Assert each in its own key.
104
+ - **Applied filters persist under `` `${stateKey}:filters` ``** (the store snapshot: `{ id: { operator, value } }` on the wire vocabulary — `'contains'`, `'greaterThan'`, …); sort and pagination stay in PrimeNG's own blob under `` `${stateKey}` ``. Assert each in its own key. **On a table with `[views]` the filters key always carries the active view segment** — `` `${stateKey}:${viewId}:filters` ``, where the active view restores from `` `${stateKey}:view` `` and seeds from the FIRST view only when nothing is stored — so a bare `:filters` key never exists there.
105
105
 
106
106
  ## Test data: seed and clean
107
107