mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
Shift-clicking a row checkbox in Unified Logs now selects every row between the last clicked row and the clicked one, following up on #50381. Per review, the legacy logs table now uses react-data-grid's native shift-click selection (the same mechanism as the table editor) instead of the custom anchor logic from #50381, and Unified Logs matches the grid's semantics. **Semantics (all three tables):** a shift-click applies the clicked checkbox's new state to every row between the last clicked row and the clicked one. The last clicked row itself is untouched. In Unified Logs a shift-click after the selection has been cleared is a plain toggle. **Changed:** - `LogTable` passes `selectedRows`, `onSelectedRowsChange`, and `rowKeyGetter` to the grid and renders the checkbox through a small `LogSelectCell` component using `useRowSelection`. The custom anchor ref, its resets, and the inline toggle are gone. Checking a row still closes the single-row side panel. - `getShiftClickSelection` moved from the Logs utils to `apps/studio/lib/shift-click-selection.ts` and rewritten to the grid's rule. Only Unified Logs uses it now, via a `getShiftClickRowSelection` adapter for TanStack Table's `RowSelectionState`. Tests cover both. - Unified Logs owns a selection anchor ref and passes it into the column generator. The checkbox cell handles `onClick` with the shift key, computes the range over the table's displayed row model (so it spans sort order and infinite-scrolled pages), and writes back through the table's own selection setter. Shift mousedown is prevented so no text selection spans rows. - The `LogTable` test mock of react-data-grid now implements the grid's row selection so the component tests exercise the native path. ## To test - Postgres logs: click one checkbox, then shift-click a checkbox further down. Every row in between should be checked and the action bar shows the count. Repeat upward. - Shift-click an already-checked row: it and the rows back to the last clicked row uncheck, the last clicked row stays as it was. - Checking a box closes the single-row side panel. Clicking a row body clears the selection and opens the panel. - Tab to a checkbox and press Space: it still toggles. Arrow keys plus Shift+Space still toggle the focused row. - Unified Logs: same shift-click behavior. Clear the selection or change a filter, then shift-click: only that one row toggles. Scroll to load more rows and shift-click across the boundary. - Copy as JSON/Markdown and Explain with AI still use the selected rows in both tables. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Improved row selection in Settings Logs and Unified Logs. - Shift-click now selects or deselects the range between the anchor row and clicked row. - Clicking an already selected row clears the relevant selection while preserving the anchor row. - Added more consistent checkbox, keyboard, and range-selection behavior across log tables. - Selecting a checkbox no longer opens the corresponding log, while clicking the row continues to open it. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
74 lines
2.1 KiB
TypeScript
74 lines
2.1 KiB
TypeScript
import type { RowSelectionState } from '@tanstack/react-table'
|
|
|
|
/**
|
|
* Computes the next multi-select set after a shift-click on `targetKey`, matching
|
|
* react-data-grid's native behavior: the target's new checked state (the opposite of
|
|
* its current one) is applied to every key strictly between `anchorKey` (the last row
|
|
* the user clicked) and the target, plus the target itself. The anchor row is left
|
|
* untouched. Falls back to a plain toggle of `targetKey` when there is no usable anchor
|
|
* (null, no longer in `orderedKeys`, or the target itself).
|
|
*/
|
|
export function getShiftClickSelection({
|
|
orderedKeys,
|
|
selectedKeys,
|
|
anchorKey,
|
|
targetKey,
|
|
}: {
|
|
orderedKeys: string[]
|
|
selectedKeys: Set<string>
|
|
anchorKey: string | null
|
|
targetKey: string
|
|
}): Set<string> {
|
|
const next = new Set(selectedKeys)
|
|
const isChecked = !selectedKeys.has(targetKey)
|
|
|
|
const applyCheckedState = (key: string) => {
|
|
if (isChecked) {
|
|
next.add(key)
|
|
} else {
|
|
next.delete(key)
|
|
}
|
|
}
|
|
|
|
applyCheckedState(targetKey)
|
|
|
|
const anchorIndex = anchorKey === null ? -1 : orderedKeys.indexOf(anchorKey)
|
|
const targetIndex = orderedKeys.indexOf(targetKey)
|
|
const hasUsableAnchor = anchorIndex !== -1 && targetIndex !== -1 && anchorIndex !== targetIndex
|
|
|
|
if (!hasUsableAnchor) return next
|
|
|
|
const step = anchorIndex < targetIndex ? 1 : -1
|
|
for (let index = anchorIndex + step; index !== targetIndex; index += step) {
|
|
applyCheckedState(orderedKeys[index])
|
|
}
|
|
|
|
return next
|
|
}
|
|
|
|
/**
|
|
* `getShiftClickSelection` for TanStack Table's `RowSelectionState` (a map of row id → true).
|
|
*/
|
|
export function getShiftClickRowSelection({
|
|
orderedRowIds,
|
|
rowSelection,
|
|
anchorRowId,
|
|
targetRowId,
|
|
}: {
|
|
orderedRowIds: string[]
|
|
rowSelection: RowSelectionState
|
|
anchorRowId: string | null
|
|
targetRowId: string
|
|
}): RowSelectionState {
|
|
const selectedRowIds = new Set(Object.keys(rowSelection).filter((id) => rowSelection[id]))
|
|
|
|
const next = getShiftClickSelection({
|
|
orderedKeys: orderedRowIds,
|
|
selectedKeys: selectedRowIds,
|
|
anchorKey: anchorRowId,
|
|
targetKey: targetRowId,
|
|
})
|
|
|
|
return Object.fromEntries([...next].map((id) => [id, true]))
|
|
}
|