mirror of
https://github.com/vxcontrol/pentagi.git
synced 2026-08-23 03:26:37 +00:00
fix(frontend): cap DataTable filter input at 200 chars
A paste of multi-KB content into the filter would land in the URL verbatim (`?q=` plus the raw blob), which exceeds the practical reverse-proxy limit (~2–4 KB) and breaks the share-link experience. The user-facing entry point is a single `<input>`, so a DOM-level `maxLength` is sufficient — it truncates both typing and paste before the value ever reaches React state, the URL, or localStorage. 200 chars is well above any realistic search term while leaving plenty of headroom for non-ASCII expansion under percent-encoding. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
022e8f3df0
commit
cc6b525f57
@@ -319,6 +319,27 @@ describe('DataTable — empty results', () => {
|
||||
const secondInput = screen.getByRole('textbox');
|
||||
expect(secondInput.getAttribute('id')).not.toBe(firstId);
|
||||
});
|
||||
|
||||
it('caps the filter input length so a paste of multi-KB content cannot blow past URL limits', () => {
|
||||
render(
|
||||
<DataTable<Row>
|
||||
columns={COLUMNS}
|
||||
data={ROWS}
|
||||
filterColumn="name"
|
||||
filterValue=""
|
||||
onFilterChange={() => {
|
||||
/* no-op */
|
||||
}}
|
||||
/>,
|
||||
{ wrapper: Wrapper },
|
||||
);
|
||||
|
||||
const input = screen.getByRole('textbox') as HTMLInputElement;
|
||||
// The DOM `maxLength` is the only choke point we need — `<input>`
|
||||
// truncates both typing and paste at this boundary, which keeps
|
||||
// shared `?q=` URLs under the practical reverse-proxy limit (~2–4 KB).
|
||||
expect(input.maxLength).toBe(200);
|
||||
});
|
||||
});
|
||||
|
||||
interface MultiRow {
|
||||
|
||||
@@ -155,6 +155,13 @@ interface DataTableFilterProps {
|
||||
}
|
||||
|
||||
const FILTER_DEBOUNCE_MS = 150;
|
||||
// Hard cap on the filter query length. 200 chars is more than any realistic
|
||||
// search term and protects against pathological inputs (paste of a multi-KB
|
||||
// chunk) that would otherwise blow past URL limits — browsers handle ~8 KB,
|
||||
// reverse-proxies typically cap at 2–4 KB, so a 5 KB share-link becomes
|
||||
// unreliable. `<input maxLength>` truncates typing and paste at the DOM
|
||||
// boundary, which is the only entry point users have here.
|
||||
const FILTER_MAX_LENGTH = 200;
|
||||
|
||||
/**
|
||||
* Search input for the table's global filter. Keystrokes update an internal
|
||||
@@ -211,6 +218,7 @@ const DataTableFilter = ({ onQueryChange, placeholder, query }: DataTableFilterP
|
||||
aria-label={placeholder}
|
||||
autoComplete="off"
|
||||
id={fieldId}
|
||||
maxLength={FILTER_MAX_LENGTH}
|
||||
name={fieldId}
|
||||
onChange={(event) => setLocalValue(event.target.value)}
|
||||
placeholder={placeholder}
|
||||
|
||||
Reference in New Issue
Block a user