LearnNewsExamplesServices
Frontmatter
id19794
titleGrid record search: the optional search toolbar and its summary
stateClosed
labels
enhancementaigrid
assigneesneo-gpt-emmy
createdAtOct 16, 2026, 11:48 AM
updatedAtOct 16, 2026, 6:09 PM
githubUrlhttps://github.com/neomjs/neo/issues/19794
authorneo-opus-grace
commentsCount2
parentIssue19791
subIssues
19820 A destroyed grid leaves main-thread addon registrations behind
subIssuesCompleted1
subIssuesTotal1
contentTrust
projected
quarantined0
signals[]
blockedBy[x] 19792 Grid record search: the Store-wide search contribution and its counting
blocking[]
closedAtOct 16, 2026, 6:09 PM
milestonev13.3

Grid record search: the optional search toolbar and its summary

Closed Backlog/active-chunk-9 enhancementaigrid
neo-opus-grace
neo-opus-grace commented on Oct 16, 2026, 11:48 AM

Context

This is the toolbar leaf of epic #19791, graduated from #19786 (contracts 4, 5 summary part and 6; options A2, I and J). The operator put the optional toolbar into v13.3 on 2026-10-16. The issues showcase has no text path to Title and Summary, which carry columnMenu: false, and a reset means clearing each menu in turn.

The Problem

A grid cannot offer record search. Nothing shows the filters that have no column header (the search itself, Title and Summary), and nothing clears the grid's own filters in one step.

The Architectural Reality

  • grid.Container has no toolbar slot above the header. footerToolbar_ is a descriptor config that becomes a container item (src/grid/Container.mjs:151–155, :340–342); it is the precedent.
  • form.field.Search exists.
  • The search contribution, its settings and its validation come from the data-contract leaf of this epic. The toolbar only projects them and writes settings.
  • Grid columns declare no hidden config, so a "visible columns" scope has no meaning yet. Body.visibleColumns is the horizontal viewport range and must never feed the scope.
  • Design authority: the graduated contract in #19786 (body SHA-256 72b90388…).

The Fix

  • searchToolbar_ descriptor config on grid.Container, mirroring footerToolbar_, placed before headerWrapper, null by default.
  • Search field, a scope selector and a case toggle; clear empties the field. The scope choices are this grid's columns with locked ones included (the default), all record fields, or one column. Labels use the columns' text, never field names. A stored field with no column in this grid reads "Record field: ", and only then. A column whose values are neither plain text nor hooked through fieldText stays listed as not searchable. "All record fields" says it searches values no column shows. The selector shows the stored field list, so a second toolbar on the same Store shows the same list. (Default set by the author after the operator's design challenge, D#19786: contract 4 left it open.)
  • Summary strip: one removable entry per effective header contribution (header-inline, header-picker). The search has no entry: its field shows the query, and its clear button empties it while keeping scope and case. Non-removable notes name any restriction the toolbar does not own, a disabled query, an empty resolved scope and a refusal. (Contract 5 delta, ratified on D#19786 by the author and Emmy.)
  • "Clear filters" removes header-inline, header-picker and grid-search by enumeration, never every non-null role and never unowned predicates.
  • The issues showcase turns the toolbar on.

Contract Ledger

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
grid.Container.searchToolbar_ (new descriptor config) #19786 contract 6 Renders the toolbar before the header null: the grid renders unchanged config JSDoc, Grids.md section e2e
grid.SearchToolbar.fieldText_ (new descriptor config) #19792 / #19796: Store#getSearchRefusal and the SearchFilter fieldText contract Optional per-field (value, item) => String hooks, passed with an explicit search write; hooks the Store's search filter already holds are kept. No new producer API, no conversion through column renderers null: only the plain-text field types the producer supports are searchable config JSDoc, Grids.md section unit: a Date column is a disabled choice without a hook, and enabled and matching with one
Clear action #19786 option J (rejected), contract 5 Removes the three UI roles only Application predicates survive and are named toolbar JSDoc e2e four-predicate witness
Summary strip #19786 option I, contract 5 as amended One entry per effective header contribution; the search shows in its own field; notes for unowned restrictions and a disabled, empty or refused search Narrow grids keep every entry reachable toolbar JSDoc e2e at narrow width
examples/grid/issues #19786 witnesses Toolbar on; Title and Summary searchable none example JSDoc real-browser drive

Decision Record impact: none. Decision Record: NOT_NEEDED.

Acceptance Criteria

  • searchToolbar_ is null by default, and a grid without it renders unchanged.
  • The scope selector writes the resolved field list, and a second toolbar on the same Store shows that list.
  • The scope defaults to this grid's columns, labelled by column text. A stored field with no column in this grid reads "Record field: ". "All record fields" states that it searches values no column shows, and a column without searchable text is listed as not searchable.
  • The summary has no entry for the search; clearing the field keeps scope and case. Header contributions keep removable entries, and a disabled, empty-scope or refused search gets a note.
  • Clear removes only the three UI roles. An independent application predicate survives, and the summary names it.
  • On a narrow grid, the summary exposes every removable state and the reset without widening the grid.
  • The issues showcase reaches Title and Summary through the toolbar in a real browser.
  • A receipt with numbers covers per-keystroke input and row-response latency for literal terms on the 100k bigData grid.
  • Grid lifecycle (moved from #19792, which needs no grid): a Store swap, grid destroy and recreate, and two grids on one Store keep or retire the search intent deterministically. Recreating either grid leaves the other's results unchanged.
  • The toolbar writes through Store#getSearchRefusal() first and shows its reason instead of writing.

Out of Scope

Regex (#19786 OQ4), the header active state (the epic's header leaf), the display-policy menu, and the header-filter layout (OQ8).

Related

#19791 · #19786 · #19712

Live latest-open sweep: newest open issues at 09:47Z, no equivalent. A2A claim sweep: no claim on the toolbar. MC sweep: "grid record search toolbar", clear miss beyond #19786.

unowned-rationale: open for self-selection by the v13.3 pair (Emmy, Grace) or any peer. It builds on the data-contract leaf, so it starts once that leaf's API is stable. The release-notes epic (#19712) gains a line when this lands.

Origin Session ID: bb2e8968-a6d6-4ef7-a4ed-5ab3157b1ac8 Retrieval Hint: "grid searchToolbar summary strip clear filters issues showcase"

tobiu referenced in commit eedc33c - "feat(grid): add optional shared record search toolbar (#19794) (#19804) on Oct 16, 2026, 6:09 PM
tobiu closed this issue on Oct 16, 2026, 6:09 PM