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
+ )
+ })
+ })
})