Description
In the logs management page, the message filter input directly sets TanStack Table's column filter value on every keystroke (line 726). For large log datasets, this triggers the full filtering pipeline on every character, causing UI jank.
File to change
surfsense_web/app/dashboard/[search_space_id]/logs/(manage)/page.tsx (lines 719-727)
Current code
<Input
ref={inputRef}
value={(table.getColumn("message")?.getFilterValue() ?? "") as string}
onChange={(e) => table.getColumn("message")?.setFilterValue(e.target.value)}
placeholder={t("filter_by_message")}
/>
What to do
Use local state for the input + debounce before setting the table filter:
const [filterInput, setFilterInput] = useState(
(table.getColumn("message")?.getFilterValue() ?? "") as string
);
const debouncedFilter = useDebouncedValue(filterInput, 300);
useEffect(() => {
table.getColumn("message")?.setFilterValue(debouncedFilter || undefined);
}, [debouncedFilter, table]);
// In JSX:
<Input
ref={inputRef}
value={filterInput}
onChange={(e) => setFilterInput(e.target.value)}
placeholder={t("filter_by_message")}
/>
The codebase already has useDebouncedValue in hooks/use-debounced-value.ts.
Acceptance criteria
- Input feels responsive (no lag while typing)
- Table filtering only runs after typing pauses (~300ms)
- Filter still works correctly
Description
In the logs management page, the message filter input directly sets TanStack Table's column filter value on every keystroke (line 726). For large log datasets, this triggers the full filtering pipeline on every character, causing UI jank.
File to change
surfsense_web/app/dashboard/[search_space_id]/logs/(manage)/page.tsx(lines 719-727)Current code
What to do
Use local state for the input + debounce before setting the table filter:
The codebase already has
useDebouncedValueinhooks/use-debounced-value.ts.Acceptance criteria