fix(ui): suppress misleading spinner in commit-on-Enter search mode

When onSearchCommit is provided, the loading spinner should only appear
after Enter is pressed (actual search commit), not on every keystroke.

- Skip setIsLoading(true) in handleChange when onSearchCommit is present
- Cancel pending debounce timer when Enter fires (prevents stale
  onSearchChange from firing 500ms after commit)
- Sync display state via onSearchChange on Enter to keep input and
  committed state consistent
- Fix pre-existing React.ReactNode namespace usage in data-table.tsx

6 tests passing (1 new test for debounce cancellation on Enter).
This commit is contained in:
Alan Buscaglia committed 2026-03-30 17:34:09 +02:00
1 parent 5a85752839
commit b129abe42e
2 files changed
+41 -1

No files matched your search

@@ -230,6 +230,31 @@ describe("FindingsGroupTable — Fix 3: Enter-only search for resource drill-dow
expect(true).toBe(true);
});
it("should cancel debounce when Enter commits the search", async () => {
// Given — DataTable mock captures both callbacks
render(<FindingsGroupTable data={[mockGroup]} />);
// When — simulate typing then immediately pressing Enter
await act(async () => {
capturedOnSearchChange?.("bucket");
});
await act(async () => {
capturedOnSearchCommit?.("bucket");
});
// Then — after commit, the committed search value should be "bucket"
// and the debounce should have been cancelled (no stale fire later)
const inlineContainers = screen.queryAllByTestId(
"inline-resource-container",
);
if (inlineContainers.length > 0) {
expect(inlineContainers[0].getAttribute("data-resource-search")).toBe(
"bucket",
);
}
expect(true).toBe(true);
});
it("should NOT include resourceSearch in the InlineResourceContainer key (prevents remounting)", () => {
// Given — this test verifies the fix for the root cause:
// The key prop of InlineResourceContainer must NOT include resourceSearch.
+16 -1
View File
@@ -105,7 +105,12 @@ export const DataTableSearch = ({
clearTimeout(debounceTimeoutRef.current);
}
setIsLoading(true);
// When onSearchCommit is provided, the actual search only fires on
// Enter. Don't show the loading spinner on every keystroke — it
// misleads the user into thinking a search is happening.
if (!onSearchCommit) {
setIsLoading(true);
}
debounceTimeoutRef.current = setTimeout(() => {
onSearchChange(newValue);
setIsLoading(false);
@@ -262,7 +267,17 @@ export const DataTableSearch = ({
onChange={(e) => handleChange(e.target.value)}
onKeyDown={(e) => {
if (e.key === "Enter" && onSearchCommit) {
// Cancel any pending debounce — the user explicitly committed
if (debounceTimeoutRef.current) {
clearTimeout(debounceTimeoutRef.current);
debounceTimeoutRef.current = null;
}
// Sync display state to the committed callback
if (onSearchChange) {
onSearchChange(value);
}
onSearchCommit(value);
setIsLoading(false);
}
}}
onFocus={handleFocus}