diff --git a/ui/components/findings/table/findings-group-table.test.tsx b/ui/components/findings/table/findings-group-table.test.tsx index c6b1a2a2f1..d3c2d947ee 100644 --- a/ui/components/findings/table/findings-group-table.test.tsx +++ b/ui/components/findings/table/findings-group-table.test.tsx @@ -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(); + + // 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. diff --git a/ui/components/ui/table/data-table-search.tsx b/ui/components/ui/table/data-table-search.tsx index 28e0490986..73573a96b9 100644 --- a/ui/components/ui/table/data-table-search.tsx +++ b/ui/components/ui/table/data-table-search.tsx @@ -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}