From 510b1f32b706a080c8613ba87a9324a8147e517a Mon Sep 17 00:00:00 2001 From: Rafia minhaj Date: Tue, 23 Jun 2026 18:27:40 +0530 Subject: [PATCH] feat(reporting): Add Quick Re-run Action Button to Scans List Table --- frontend/src/pages/Scans.tsx | 37 ++++++++++++++++------ frontend/testing/unit/pages/Scans.test.tsx | 25 +++++++++++++++ 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/frontend/src/pages/Scans.tsx b/frontend/src/pages/Scans.tsx index 143319a70..006f14212 100644 --- a/frontend/src/pages/Scans.tsx +++ b/frontend/src/pages/Scans.tsx @@ -482,15 +482,34 @@ export default function Scans() { {formatLocaleTime(createDate)}

- {task.duration_seconds && ( -
-

- {formatDuration( - task.duration_seconds, - )?.toUpperCase()} -

-
- )} +
+ {task.duration_seconds && ( +
+

+ {formatDuration( + task.duration_seconds, + )?.toUpperCase()} +

+
+ )} + {(task.status === "completed" || + task.status === "failed" || + task.status === "cancelled") && ( + + )} +
diff --git a/frontend/testing/unit/pages/Scans.test.tsx b/frontend/testing/unit/pages/Scans.test.tsx index 994f36581..ca7d083c0 100644 --- a/frontend/testing/unit/pages/Scans.test.tsx +++ b/frontend/testing/unit/pages/Scans.test.tsx @@ -12,6 +12,7 @@ vi.mock('../../../src/api', () => ({ deleteTask: vi.fn().mockResolvedValue({}), clearAllTasks: vi.fn().mockResolvedValue({}), bulkDeleteTasks: vi.fn().mockResolvedValue({}), + startTask: vi.fn().mockResolvedValue({ task_id: 'new-task-123' }), })) vi.mock('../../../src/routes', () => ({ @@ -213,4 +214,28 @@ describe('Scans — task list', () => { await waitFor(() => expect(screen.getByText('Delete Scan Record')).toBeInTheDocument()) }) + + it('renders quick re-run button for completed tasks and triggers handleRescan', async () => { + const tasks = [makeTask({ task_id: 'task-123', status: 'completed', tool: 'nmap' })] + mockFetch(tasks) + renderScans() + + await waitFor(() => expect(screen.getByText('nmap')).toBeInTheDocument()) + + const rerunBtn = screen.getByRole('button', { name: /Re-run nmap scan/i }) + expect(rerunBtn).toBeInTheDocument() + + const { startTask } = await import('../../../src/api') + await userEvent.click(rerunBtn) + + await waitFor(() => { + expect(startTask).toHaveBeenCalledWith( + 'nmap', + expect.any(Object), + true, + undefined, + undefined + ) + }) + }) })