feat(datagrid): add per-column value filter (#1454)#1756
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 35c8470f14
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| var sortedIDs: [RowID]? | ||
| var valueFilteredIDs: [RowID]? | ||
| var valueFilterState = GridValueFilterState() | ||
| var displayIDs: [RowID]? { valueFilteredIDs ?? sortedIDs } |
There was a problem hiding this comment.
Map filtered display rows before mutating rows
Once displayIDs can come from valueFilteredIDs, NSTableView row indexes are positions in the filtered list, but mutation delegates still pass selectedRowIndexes/grid selection rows to RowEditingCoordinator.deleteSelectedRows, which indexes tableRows.rows[rowIndex] directly. With a filter where display row 0 is actually RowID.existing(2), pressing Delete marks/removes storage row 0 instead of the visible row, so the wrong record can be deleted; convert display indexes through tableRowsIndex(forDisplayRow:) or pass row IDs for row mutations.
Useful? React with 👍 / 👎.
| invalidateDisplayCache() | ||
| visualIndex.updateRow(row, from: changeManager, sortedIDs: sortedIDs) | ||
| visualIndex.updateRow(row, from: changeManager, sortedIDs: displayIDs) |
There was a problem hiding this comment.
Recompute value filters after edited cells change
When a value filter is active, this commit path only updates the visual index and reloads the edited row; it never recomputes valueFilteredIDs. For example, with a status = active value filter, editing a visible row's status to inactive leaves that row visible and included in copy/selection until a full reload or filter change occurs, even though it no longer matches the active filter.
Useful? React with 👍 / 👎.
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
35c8470 to
f634a3c
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f634a3ca2c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| invalidateDisplayCache() | ||
| visualIndex.updateRow(row, from: changeManager, sortedIDs: sortedIDs) | ||
| visualIndex.updateRow(row, from: changeManager, sortedIDs: displayIDs) |
There was a problem hiding this comment.
Record filtered edits with storage row indices
When a value filter makes display row 0 correspond to a different storage row, recordCellEdit mutates the correct storage row via tableRowsIndex(forDisplayRow:), but the change manager record is still keyed by the display row; this subsequent visual update reinforces that display index as the edited row. For a filtered view where display row 0 is storage row 2, editing the cell records an undo/update for row 0, so Undo or later merged edits can modify the wrong stored row even though the visible cell was changed. Record the change against the storage row/row ID and translate only when painting display state.
Useful? React with 👍 / 👎.
f634a3c to
f622ffc
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f622ffcbc9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| guard row >= 0, row < tableView.numberOfRows else { return } | ||
| invalidateDisplayCache(forDisplayRow: row, column: column) | ||
| visualIndex.updateRow(row, from: changeManager, sortedIDs: sortedIDs) | ||
| visualIndex.updateRow(row, from: changeManager, sortedIDs: displayIDs) |
There was a problem hiding this comment.
Map storage delta rows before repainting filtered views
When a value filter is active, Delta.cellChanged row values still come from TableRows/RowOperationsManager as storage indices, but this branch validates and repaints them as display indices. For example, if storage row 2 is the only visible row after filtering, an undo/discard delta for row 2 fails the row < tableView.numberOfRows check and the visible row is not reloaded; in larger filtered sets it can repaint the wrong display row. Map the row ID to its current filtered display index, or fall back to recomputing/reloading when filters are active.
Useful? React with 👍 / 👎.
f622ffc to
9a897db
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9a897db33a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| recomputeValueFilteredIDs() | ||
| updateCache() | ||
| visualIndex.rebuild(from: changeManager, sortedIDs: displayIDs) | ||
| selectionController.clear() |
There was a problem hiding this comment.
Clear row selection when value filters change
When applying or clearing a value filter while an NSTableView row is selected, this only clears the grid cell-selection overlay; selectedRowIndices and the table view's selected row indexes are left as display indexes across a reordered/shortened displayIDs set. For example, selecting display row 0 for row A and then filtering so row C becomes display row 0 leaves row 0 selected, so subsequent copy/delete/context-menu actions operate as if C was intentionally selected. Deselect rows here or remap the selection by RowID before reloading.
Useful? React with 👍 / 👎.
Closes #1454.
Adds an Excel/DataGrip-style per-column value filter that narrows the loaded rows without re-querying the server.
What it does
(NULL)and(Empty)entries. Search the list, check the values to keep, click Apply (Returnapplies,Esccancels).How it works
displayIDsaccessor (valueFilteredIDs ?? sortedIDs) slots above the existingsortedIDslayer, exactly where the issue suggested. Every read site (displayRow,numberOfRows,cachedRowCount, prewarm, copy/select,RowVisualIndex) goes through it, so the filter composes with SQL sort, pagination, and change tracking.displayIDs == sortedIDswhen no filter is active.SortableHeaderCell(matching the existing sort chevron) rather than overlaidNSButtons, to avoid hundreds of buttons on wide grids. Hover-reveal via the header tracking area;line.3.horizontal.decrease.circle.fillwhen active. The funnel is a distinct hit target from the sort-on-title click.CellDisplayFormatterthe cells use, so popover labels match what's shown in the grid.NSPopoverhosting SwiftUI viaPopoverPresenter, anchored to the funnel rect.Scope boundary
The filter state lives in the grid coordinator and is ephemeral, like
sortedIDs: not persisted to disk, not shown in the status-bar row count, and not counted as "active work" by the tab-replacement guard. The funnel fill is the active-filter indicator the issue asked for. These integrations can be added later if wanted.Tests
GridValueFilterStateTests— set/clear/clearAll/prune, active tracking.TableViewCoordinatorValueFilterTests— distinct extraction with NULL bucket and counts, single/multi-column intersection, null-only selection, clear, inserted-rows-stay-visible, column-set pruning, anddisplayRow/tableRowsIndex/cachedRowCountviadisplayIDs.Docs
docs/features/data-grid.mdx, with a note that it operates on the current page and points to the Filter Panel for server-side filtering.