From ed2d1ff9b74a15a1db18e7155a01f683abaa6c7d Mon Sep 17 00:00:00 2001 From: kavin553 Date: Sat, 20 Jun 2026 13:45:35 +0530 Subject: [PATCH 1/2] feat : add copy finding ID action --- frontend/src/pages/Findings.tsx | 50 +++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/frontend/src/pages/Findings.tsx b/frontend/src/pages/Findings.tsx index fe65c3274..003f3780e 100644 --- a/frontend/src/pages/Findings.tsx +++ b/frontend/src/pages/Findings.tsx @@ -468,7 +468,21 @@ export default function Findings() { setCopiedFindingId(null) } } + async function copyFindingId(findingId: string) { + try { + await navigator.clipboard.writeText(findingId) + setCopiedFindingId(findingId) + + window.setTimeout(() => { + setCopiedFindingId((current) => + current === findingId ? null : current + ) + }, 1600) + } catch { + setCopiedFindingId(null) + } +} // ─── Keyboard navigation ──────────────────────────────────────────────────── const listRef = useRef(null) @@ -940,9 +954,30 @@ export default function Findings() {
-

Selected Finding

-

{selectedFinding.title}

-
+

+ Selected Finding +

+ +

+ {selectedFinding.title} +

+ +
+ + ID: {selectedFinding.id} + + + +
+
@@ -1133,6 +1168,15 @@ export default function Findings() { > {copiedFindingId === selectedFinding.id ? 'Copied' : 'Copy Brief'} +
From b0db567e60a98870fdd2f124c3aa280fdc893e05 Mon Sep 17 00:00:00 2001 From: kavin553 Date: Mon, 22 Jun 2026 20:33:39 +0530 Subject: [PATCH 2/2] fix : address PR review feedback for finding ID copy action --- frontend/src/pages/Findings.tsx | 22 +++--------- frontend/testing/unit/pages/Findings.test.tsx | 36 +++++++++++++++++++ 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/frontend/src/pages/Findings.tsx b/frontend/src/pages/Findings.tsx index 003f3780e..96d79e689 100644 --- a/frontend/src/pages/Findings.tsx +++ b/frontend/src/pages/Findings.tsx @@ -966,16 +966,6 @@ export default function Findings() { ID: {selectedFinding.id} - - @@ -1169,13 +1159,11 @@ export default function Findings() { {copiedFindingId === selectedFinding.id ? 'Copied' : 'Copy Brief'} diff --git a/frontend/testing/unit/pages/Findings.test.tsx b/frontend/testing/unit/pages/Findings.test.tsx index 5a23d8c85..28df3d6f3 100644 --- a/frontend/testing/unit/pages/Findings.test.tsx +++ b/frontend/testing/unit/pages/Findings.test.tsx @@ -231,6 +231,42 @@ describe('Findings — virtualized list', () => { }) }) + it('copies finding id and shows success feedback', async () => { + const findings = [makeFinding({ id: 'f1', title: 'ID Copy Test' })] + vi.mocked(getFindings).mockResolvedValue({ findings }) + Object.defineProperty(navigator, 'clipboard', { + configurable: true, + value: { writeText: vi.fn().mockResolvedValue(undefined) }, + }) + + render() + await waitFor(() => expect(screen.queryByText('Synchronizing findings feed...')).not.toBeInTheDocument()) + + const copyButton = screen.getByRole('button', { name: /Copy ID/i }) + await userEvent.click(copyButton) + + await waitFor(() => expect(navigator.clipboard.writeText).toHaveBeenCalledWith('f1')) + expect(copyButton).toHaveTextContent('Copied') + }) + + it('keeps copy state idle when finding id copy fails', async () => { + const findings = [makeFinding({ id: 'f2', title: 'ID Copy Failure Test' })] + vi.mocked(getFindings).mockResolvedValue({ findings }) + Object.defineProperty(navigator, 'clipboard', { + configurable: true, + value: { writeText: vi.fn().mockRejectedValue(new Error('clipboard unavailable')) }, + }) + + render() + await waitFor(() => expect(screen.queryByText('Synchronizing findings feed...')).not.toBeInTheDocument()) + + const copyButton = screen.getByRole('button', { name: /Copy ID/i }) + await userEvent.click(copyButton) + + await waitFor(() => expect(navigator.clipboard.writeText).toHaveBeenCalledWith('f2')) + expect(copyButton).toHaveTextContent('Copy ID') + }) + it('persists review state to localStorage', async () => { const findings = [makeFinding({ id: 'f1', title: 'Persist Test', severity: 'high' })] vi.mocked(getFindings).mockResolvedValue({ findings })