Skip to content

feat(table)!: settings filter tab, inline query bar default, switch rows - #130

Merged
sdcorejs merged 7 commits into
mainfrom
claude/sd-table-settings-filters
Nov 1, 2026
Merged

sdcorejs merged 7 commits into
mainfrom
claude/sd-table-settings-filters

Conversation

@sdcorejs

@sdcorejs sdcorejs commented Oct 31, 2026 •

Copy link
Copy Markdown
Owner

Summary

Follow-up to the 3.4 table settings modal, from user feedback: the query bar could not be picked from the settings, the query bar did not default to the inline editor, and the truncate hint pushed the column checkboxes out of line. Planned for 3.5; plan and decisions in .sdcorejs/handoff/table-settings-filters/PLAN.md.

  • Settings modal tabs. The modal gets Cột and Bộ lọc tabs with one footer: Apply stores both, Skip drops both, Khôi phục mặc định resets both.
    • Kiểu lọc: two radio cards, Khung bộ lọc ('default') and Thanh bộ lọc ('query-bar').
    • Bộ lọc hiển thị: one switch row per external filter (inlineExternal): shown in the panel, or pinned as a chip on the bar.
    • Required filters are locked. On the bar, a filter the bar cannot show is off and locked, and queryBar.pinned locks the list.
    • Thanh bộ lọc is disabled, with a note naming them, while a required external filter cannot go on the bar. With the bar picked, a warning says that filters not on the bar still filter by their value.
    • The tab shows on desktop when filtering is on and the table has a filter.
  • The user's filter mode. TableFilterConfiguration.mode stores the picked mode next to inlineExternal.
    • It wins over filter.mode unless filter.modeSelectable is false (new, default true, also in SD_TABLE_CONFIGURATION.filter).
    • It turns on the settings button dot while it differs from filter.mode, and Restore defaults clears it.
    • A pick equal to filter.mode is not stored, so the table keeps following the option.
  • Inline query bar by default (breaking). filter.queryBar.editor defaults to 'inline'; a standalone sd-query-bar keeps 'popover'. The header filter icon's aria-haspopup follows what opens: menu with the popover editor; with the inline editor nothing for a field with a chip, else menu / listbox / dialog for the chip being built.
  • Switch rows. The fixed / truncate options of an open column row are label + description rows with an sd-switch on the right (were checkboxes).

Breaking change

  filter: {
    mode: 'query-bar',
+   queryBar: { editor: 'popover' }, // keep the popover chips
  },

Users can now switch a table between the filter panel and the query bar in the settings modal. Set filter.modeSelectable: false to keep filter.mode fixed. Both are in the CHANGELOG under Before upgrading.

Commits

  1. feat(table): show column options as switch rows in settings: new i18n key config.fixed-hint.
  2. feat(table)!: edit query bar chips inline by default
  3. feat(table): store the filter mode the user picks: configuration.set() now merges, which also fixes a set without inlineExternal dropping it.
  4. feat(table): add a filter tab to the settings modal: 12 new i18n keys in vi/en/ja/ko/zh. The off-bar rule moves to sdTableExternalOffBar (internal) so the bar and the tab share it.
  5. docs(table): document the settings filter tab and update the showcase
  6. fix(table): address the review of the settings filter tab: the fixes from the independent review below.
  7. test(table): cover the filter mode and inline editor with reads in flight: 12 specs in table.component.filter-mode-async.spec.ts, with a server loader whose reads stay in flight until the spec answers them.
    • Mode switch with a read in flight: no read; applied values carried both ways with the same pagingReq; mobile flip.
    • Inline editor: the late answer of a replaced read is dropped, and edits inside the 700 ms debounce share one read.
    • A change from outside waits for the chip being built, and text being typed in a chip survives a change to another field.
    • Settings Apply / Restore defaults cause only their one re-read.
    • Reload with cache, and a new option object with and without filter.key.
    • Mutation-checked: removing the "chip being built" guard makes the build spec fail.

API consistency review

  • New options. filter.modeSelectable follows the boolean options of filter (manualFilter, cacheable, hideInlineFilter). It is merged from SD_TABLE_CONFIGURATION.filter the same way as mode and queryBar (the option wins).
  • New fields. TableFilterConfiguration.mode? reuses SdTableOptionFilter['mode'].
  • Changed default. Only filter.queryBar.editor changes its default. Nothing is renamed or removed, and every new field is optional.
  • Internal names. The settings component (internal) gets the filterSetup input and the filterApplied output, next to the existing defaultsRestored.
  • Rollout. v20–v22 were rolled out with npm run sync; npm run check:sync passes.
  • Independent review: done (2026-11-01). No blocker. Fixed in commit 6:
    • the bar card is blocked by a required filter the bar cannot show, plus the off-bar warning (major);
    • aria-haspopup follows what the header icon opens (minor);
    • docs on how long the choice lasts without filter.key (minor);
    • tablist aria-controls and focusable panels, configFilter protected, the storage spec now covers the read path, CHANGELOG fixes (nits).
  • Kept on purpose: the filter list ignores hideExternalFilterToolbar (documented).
  • Left for later: the notes under the switches are not tied to them with aria-describedby. That needs a new sd-switch input.

Tests

  • Full v19 suite with coverage after the review fixes: 8782/8784; statements 87.57%, branches 78.6%.
    • The 2 red specs are SdPreviewPdf thumbnail specs: a 5000 ms canvas timeout, plus one red as a knock-on.
    • That component is untouched; its specs pass alone (155/155, twice).
    • Table specs: 1227/1227 with the async specs.
  • Every step was written specs first, and the new specs failed for the expected reason before the code change.
    • New file config.component.filter-tab.spec.ts: 20 specs.
    • Table integration specs: filter tab, stored mode, modeSelectable, Restore defaults.
    • Service and util specs for the stored mode and the settings dot.
    • Query-bar specs for the default editor.
  • npm run lint, check:scss-hex (0 findings), test:theme (53/53), test:showcase-changelog, test:showcase-examples, npm run check:sync.
  • Showcase unit tests: 331/331.
  • Checked in a real browser (Playwright on the showcase): Thiết lập › Bộ lọc › Khung bộ lọc › Áp dụng moves the demo to the panel and turns on the dot. A reload keeps the panel, and Restore defaults goes back to the bar.

Screenshots

Switch rows Inline query bar Filter tab: panel Filter tab: bar Filter tab: dark

More screenshots in .sdcorejs/handoff/screenshots/:

  • 18: switch rows, dark
  • 20: inline query bar, dark
  • 24: the showcase query-bar demo

Known limits

  • The filter list holds external filters only. Quick-search filters show in both layouts, so there is nothing to switch.
  • The modal height changes with the tab.
  • The stored mode survives a reload only with filter.key. Without it, it lasts until the table gets a new option object, like inlineExternal.
  • The notes under the filter switches are not linked with aria-describedby yet.
  • Apply in the settings modal always re-reads once, even when the column setup did not change. This predates this PR (#hydrateConfiguration); a separate session looks at skipping it.

🤖 Generated with Claude Code

nghiatt15 and others added 7 commits October 30, 2026 17:42
The fixed and truncate options in the column details become rows with the
label and a description on the left and an sd-switch on the right, so the
truncate hint no longer pushes the options out of line. Adds the
config.fixed-hint key in all five locales and the plan for the settings
filter tab.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sd-table's query bar (filter.mode 'query-bar') now defaults
filter.queryBar.editor to 'inline', so each chip's operator and value are
edited on the bar. A standalone sd-query-bar keeps 'popover'. The header
filter icon declares aria-haspopup="menu" only with the popover editor,
since the inline editor focuses the chip instead of opening a menu.

BREAKING CHANGE: set filter.queryBar.editor: 'popover' (per table or in
SD_TABLE_CONFIGURATION) to keep the popover chips.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TableFilterConfiguration gains an optional mode, stored next to the inline
external filters. It wins over filter.mode while filter.modeSelectable is
not false (also settable in SD_TABLE_CONFIGURATION.filter), turns on the
settings button dot while it differs from filter.mode, and Restore
defaults clears it. configuration.set() now keeps the fields it is not
given, so writing only inlineExternal no longer drops the rest.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The settings modal gets Cột and Bộ lọc tabs with one footer: Apply stores
both, Skip drops both, Restore defaults resets both. Bộ lọc offers the
filter kind as two radio cards (Khung bộ lọc / Thanh bộ lọc, hidden with
filter.modeSelectable false) and one switch row per external filter,
shown in the panel or pinned on the bar. Required filters are locked; on
the bar a filter it cannot show is off and locked, and queryBar.pinned
locks the list. A kind equal to filter.mode is not stored.

The tab shows on desktop when filtering is on and the table has a
filter. The off-bar rule moves to sdTableExternalOffBar so the bar and
the tab share it. The showcase query-bar demo shows the settings button.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The showcase query-bar demo swaps its Mode buttons, which a stored choice
would override, for Editor inline / popover buttons, and its notes and
the column settings notes describe the Bộ lọc tab. Adds the missing
English entries for both demos. sd-table.md and the CHANGELOG cover the
filter tab, the user's filter mode and the switch rows; the plan records
each step and its deviations.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The Thanh bộ lọc card is disabled, with a note naming them, while a
  required external filter cannot go on the bar: the bar would block the
  read with no place to fill it. With the bar picked, a warning says that
  filters not on the bar still filter by their value.
- The header filter icon's aria-haspopup follows what opens: the chip
  menu with the popover editor; with the inline editor nothing for a
  field with a chip, else the operator menu, the value picker or the date
  picker of the chip being built (sdTableQueryTriggerPopup).
- Only the selected tab has aria-controls, and the tab panels take focus.
- configFilter is protected.
- The storage spec writes an unknown mode straight into storage, so it
  covers the read path.
- Docs and CHANGELOG: the choice without filter.key lasts until the table
  gets a new option object; the configuration.set() merge moves to
  Changed; Before upgrading lists the XLSX change; the filter list ignores
  hideExternalFilterToolbar on purpose. New i18n keys
  mode-query-bar-blocked and filters-off-bar-warning in all five
  languages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ight

Adds table.component.filter-mode-async.spec.ts: twelve specs with a server
loader whose reads stay in flight until the spec answers them.
- Switching the mode sends no read, also with a read in flight, and
  carries the applied values both ways with the same pagingReq.
- The mobile flip sends no read.
- With the inline editor, a late answer of a replaced read is dropped,
  and edits inside the 700 ms debounce share one read.
- A change from outside waits for the chip being built, and text being
  typed in a chip survives a change to another field.
- The settings Apply and Restore defaults cause only their one re-read,
  and a dropped read never renders.
- The stored mode and cached values come back after a reload with one
  read; a new option object keeps the mode only with filter.key.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sdcorejs
sdcorejs merged commit ef7e30f into main Nov 1, 2026
7 checks passed
@sdcorejs
sdcorejs deleted the claude/sd-table-settings-filters branch November 1, 2026 14:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants