feat(admin): shift-select multiple sessions in process list

This commit is contained in:
zipg authored and GitHub committed 2026-09-20 16:49:57 +08:00
1 parent 08cb9287de
commit ec7bc617c4
8 files changed
+144 -9

No files matched your search

@@ -0,0 +1,44 @@
import { orderedListRangeIndices, orderedListSelectionIntent } from "../selection/orderedListSelection";
/** Rows are identified by the server session id, matching the process list grid. */
export interface ProcessListSelectionRow {
id: number;
}
export interface ProcessListSelectionState {
selected: Set<number>;
anchorId: number | null;
}
/**
* Applies a row checkbox click to the current selection.
*
* A plain click toggles the clicked row and moves the anchor; Shift+click applies
* the clicked row's next state to every selectable row between the anchor and the
* clicked row, so long session lists can be selected in one gesture. Rows outside
* the range keep their current state, and an unknown/stale anchor degrades to a
* plain toggle instead of selecting an unexpected range.
*
* The next state is derived from the current selection because the grid binds
* `:checked` without cancelling the native checkbox activation.
*/
export function processListSelectionAfterClick(rows: ProcessListSelectionRow[], state: ProcessListSelectionState, id: number, event: Pick<MouseEvent, "shiftKey" | "metaKey" | "ctrlKey">): ProcessListSelectionState {
const targetIndex = rows.findIndex((row) => row.id === id);
if (targetIndex < 0) return state;
const checked = !state.selected.has(id);
const anchorIndex = state.anchorId === null ? -1 : rows.findIndex((row) => row.id === state.anchorId);
if (orderedListSelectionIntent(event) === "range" && anchorIndex >= 0) {
const selected = new Set(state.selected);
for (const index of orderedListRangeIndices(rows.length, anchorIndex, targetIndex)) {
const row = rows[index];
if (!row) continue;
if (checked) selected.add(row.id);
else selected.delete(row.id);
}
return { selected, anchorId: state.anchorId };
}
const selected = new Set(state.selected);
if (checked) selected.add(id);
else selected.delete(id);
return { selected, anchorId: id };
}