fix(ServerHealthSection): add debounce to linesCount input to prevent rapid API calls
- Introduce linesCountRaw state to capture raw input values - Add handleLinesCountChange callback with 300ms debounce delay - Reuse existing filterDebounceRef pattern with linesCountDebounceRef - Guard against zero/negative values by enforcing minimum of 100 lines - Update Select component to use debounced value and new handler - Add comprehensive test coverage for debounce behavior and input validation Fixes TASK-BUG-09: Typing '500' in the Lines field now fires single API request instead of three (one per keystroke). This mirrors the existing debounce pattern used for the filter input. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -54,6 +54,9 @@ const AUTO_REFRESH_INTERVALS: { label: string; value: number }[] = [
|
||||
/** Debounce delay for the filter input in milliseconds. */
|
||||
const FILTER_DEBOUNCE_MS = 300;
|
||||
|
||||
/** Debounce delay for the lines count input in milliseconds. */
|
||||
const LINES_COUNT_DEBOUNCE_MS = 300;
|
||||
|
||||
/** Log targets that are not file paths — file-based viewing is unavailable. */
|
||||
const NON_FILE_TARGETS = new Set(["STDOUT", "STDERR", "SYSLOG", "SYSTEMD-JOURNAL"]);
|
||||
|
||||
@@ -179,6 +182,7 @@ export function ServerHealthSection(): React.JSX.Element {
|
||||
const [isRefreshing, setIsRefreshing] = useState(false);
|
||||
|
||||
// ---- toolbar state -------------------------------------------------------
|
||||
const [linesCountRaw, setLinesCountRaw] = useState<string>("200");
|
||||
const [linesCount, setLinesCount] = useState<number>(200);
|
||||
const [filterRaw, setFilterRaw] = useState<string>("");
|
||||
const [filterValue, setFilterValue] = useState<string>("");
|
||||
@@ -189,6 +193,7 @@ export function ServerHealthSection(): React.JSX.Element {
|
||||
// ---- refs ----------------------------------------------------------------
|
||||
const logContainerRef = useRef<HTMLDivElement>(null);
|
||||
const filterDebounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
const linesCountDebounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
const autoRefreshTimerRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
||||
|
||||
// ---- scroll helper -------------------------------------------------------
|
||||
@@ -259,6 +264,18 @@ export function ServerHealthSection(): React.JSX.Element {
|
||||
}, FILTER_DEBOUNCE_MS);
|
||||
}, []);
|
||||
|
||||
// ---- lines count debounce ------------------------------------------------
|
||||
const handleLinesCountChange = useCallback((value: string): void => {
|
||||
setLinesCountRaw(value);
|
||||
if (linesCountDebounceRef.current) clearTimeout(linesCountDebounceRef.current);
|
||||
linesCountDebounceRef.current = setTimeout(() => {
|
||||
const parsed = Number(value);
|
||||
// Guard against zero or negative values; use minimum of 100
|
||||
const validated = Math.max(parsed || 100, 100);
|
||||
setLinesCount(validated);
|
||||
}, LINES_COUNT_DEBOUNCE_MS);
|
||||
}, []);
|
||||
|
||||
// ---- render helpers ------------------------------------------------------
|
||||
const renderLogLine = (line: string, idx: number): React.JSX.Element => {
|
||||
const severity = detectSeverity(line);
|
||||
@@ -406,8 +423,8 @@ export function ServerHealthSection(): React.JSX.Element {
|
||||
{/* Lines count selector */}
|
||||
<Field label="Lines">
|
||||
<Select
|
||||
value={String(linesCount)}
|
||||
onChange={(_e, d) => { setLinesCount(Number(d.value)); }}
|
||||
value={linesCountRaw}
|
||||
onChange={(_e, d) => { handleLinesCountChange(d.value); }}
|
||||
>
|
||||
{LINE_COUNT_OPTIONS.map((n) => (
|
||||
<option key={n} value={String(n)}>
|
||||
|
||||
Reference in New Issue
Block a user