larxius commited on
Commit
53fed5a
·
verified ·
1 Parent(s): 51db5ec

Update frontend/src/pages/Dashboard.jsx

Browse files
Files changed (1) hide show
  1. frontend/src/pages/Dashboard.jsx +71 -29
frontend/src/pages/Dashboard.jsx CHANGED
@@ -54,6 +54,7 @@ export const Dashboard = () => {
54
  const dashboardPollRef = useRef(null);
55
  const activeScanRef = useRef(null);
56
  const completedScanIdRef = useRef(null);
 
57
 
58
  const markScanAsCompleted = useCallback((id) => {
59
  completedScanIdRef.current = id;
@@ -90,10 +91,13 @@ export const Dashboard = () => {
90
  }
91
  }, []);
92
 
93
- const startLogPolling = useCallback((scan) => {
94
  stopLogPolling();
95
  activeScanRef.current = scan;
96
  persistActiveScan(scan);
 
 
 
97
  let consecutiveErrors = 0;
98
  const MAX_ERRORS = 20; // tolerate up to 20 failures (covers token refresh + brief outages)
99
 
@@ -136,7 +140,10 @@ export const Dashboard = () => {
136
  setActiveScan(null);
137
  activeScanRef.current = null;
138
  persistActiveScan(null); // clear localStorage
139
- markScanAsCompleted(currentScan.id);
 
 
 
140
  fetchDashboard();
141
  }
142
  } catch (err) {
@@ -182,6 +189,7 @@ export const Dashboard = () => {
182
  });
183
 
184
  if (runningScans.length > 0) {
 
185
  // If we are ALREADY tracking an active scan that is still in progress, STICK WITH IT!
186
  const currentStillRunning = activeScanRef.current
187
  ? runningScans.find(s => s.id === activeScanRef.current.id)
@@ -197,10 +205,11 @@ export const Dashboard = () => {
197
  setActiveScan(nextScan);
198
  activeScanRef.current = nextScan;
199
  setLiveLogs([]);
200
- startLogPolling(nextScan);
201
  }
202
  } else {
203
  // No active scans remaining
 
204
  if (activeScanRef.current) {
205
  setActiveScan(null);
206
  activeScanRef.current = null;
@@ -226,7 +235,7 @@ export const Dashboard = () => {
226
  if (storedScan && storedScan.id) {
227
  setActiveScan(storedScan);
228
  activeScanRef.current = storedScan;
229
- startLogPolling(storedScan);
230
  }
231
  } catch (_) {
232
  localStorage.removeItem(ACTIVE_SCAN_KEY);
@@ -486,7 +495,13 @@ export const Dashboard = () => {
486
  const scanData = recentScans.find(s => s.id === completedScanId);
487
  const isFailed = scanData?.status === 'failed';
488
  const isTerminated = scanData?.status === 'terminated';
489
-
 
 
 
 
 
 
490
  if (isTerminated) {
491
  return (
492
  <div className="w-full bg-red-50 border border-red-200 rounded-xl p-md flex items-center justify-between shadow-sm">
@@ -497,14 +512,23 @@ export const Dashboard = () => {
497
  <p className="font-body-sm text-body-sm text-red-700">Sorry, due to some problemes we terminate your scanning and also show that scanner is terminated.</p>
498
  </div>
499
  </div>
500
- <Link
501
- to={`/scans/results?id=${completedScanId}`}
502
- className="bg-red-600 hover:bg-red-700 text-white font-label-md text-label-md px-lg py-sm rounded-lg flex items-center gap-sm transition-colors font-bold border-0"
503
- style={{ textDecoration: 'none' }}
504
- >
505
- <span className="material-symbols-outlined text-[18px]">open_in_new</span>
506
- View Details
507
- </Link>
 
 
 
 
 
 
 
 
 
508
  </div>
509
  );
510
  }
@@ -519,14 +543,23 @@ export const Dashboard = () => {
519
  <p className="font-body-sm text-body-sm text-red-700">The scanner encountered a critical error. View logs for details.</p>
520
  </div>
521
  </div>
522
- <Link
523
- to={`/scans/results?id=${completedScanId}`}
524
- className="bg-red-600 hover:bg-red-700 text-white font-label-md text-label-md px-lg py-sm rounded-lg flex items-center gap-sm transition-colors font-bold border-0"
525
- style={{ textDecoration: 'none' }}
526
- >
527
- <span className="material-symbols-outlined text-[18px]">open_in_new</span>
528
- View Details
529
- </Link>
 
 
 
 
 
 
 
 
 
530
  </div>
531
  );
532
  }
@@ -540,14 +573,23 @@ export const Dashboard = () => {
540
  <p className="font-body-sm text-body-sm text-green-700">Vulnerability analysis finished. View the full report below.</p>
541
  </div>
542
  </div>
543
- <Link
544
- to={`/scans/results?id=${completedScanId}`}
545
- className="bg-green-600 hover:bg-green-700 text-white font-label-md text-label-md px-lg py-sm rounded-lg flex items-center gap-sm transition-colors font-bold border-0"
546
- style={{ textDecoration: 'none' }}
547
- >
548
- <span className="material-symbols-outlined text-[18px]">open_in_new</span>
549
- View Full Report
550
- </Link>
 
 
 
 
 
 
 
 
 
551
  </div>
552
  );
553
  })()
 
54
  const dashboardPollRef = useRef(null);
55
  const activeScanRef = useRef(null);
56
  const completedScanIdRef = useRef(null);
57
+ const liveScanIdsRef = useRef(new Set());
58
 
59
  const markScanAsCompleted = useCallback((id) => {
60
  completedScanIdRef.current = id;
 
91
  }
92
  }, []);
93
 
94
+ const startLogPolling = useCallback((scan, isLive = true) => {
95
  stopLogPolling();
96
  activeScanRef.current = scan;
97
  persistActiveScan(scan);
98
+ if (isLive && scan?.id) {
99
+ liveScanIdsRef.current.add(scan.id);
100
+ }
101
  let consecutiveErrors = 0;
102
  const MAX_ERRORS = 20; // tolerate up to 20 failures (covers token refresh + brief outages)
103
 
 
140
  setActiveScan(null);
141
  activeScanRef.current = null;
142
  persistActiveScan(null); // clear localStorage
143
+ if (liveScanIdsRef.current.has(currentScan.id)) {
144
+ markScanAsCompleted(currentScan.id);
145
+ liveScanIdsRef.current.delete(currentScan.id);
146
+ }
147
  fetchDashboard();
148
  }
149
  } catch (err) {
 
189
  });
190
 
191
  if (runningScans.length > 0) {
192
+ runningScans.forEach(s => liveScanIdsRef.current.add(s.id));
193
  // If we are ALREADY tracking an active scan that is still in progress, STICK WITH IT!
194
  const currentStillRunning = activeScanRef.current
195
  ? runningScans.find(s => s.id === activeScanRef.current.id)
 
205
  setActiveScan(nextScan);
206
  activeScanRef.current = nextScan;
207
  setLiveLogs([]);
208
+ startLogPolling(nextScan, true);
209
  }
210
  } else {
211
  // No active scans remaining
212
+ localStorage.removeItem(ACTIVE_SCAN_KEY);
213
  if (activeScanRef.current) {
214
  setActiveScan(null);
215
  activeScanRef.current = null;
 
235
  if (storedScan && storedScan.id) {
236
  setActiveScan(storedScan);
237
  activeScanRef.current = storedScan;
238
+ startLogPolling(storedScan, false); // isLive = false, prevent stale error banner
239
  }
240
  } catch (_) {
241
  localStorage.removeItem(ACTIVE_SCAN_KEY);
 
495
  const scanData = recentScans.find(s => s.id === completedScanId);
496
  const isFailed = scanData?.status === 'failed';
497
  const isTerminated = scanData?.status === 'terminated';
498
+
499
+ const handleDismiss = () => {
500
+ setCompletedScanId(null);
501
+ completedScanIdRef.current = null;
502
+ localStorage.removeItem(ACTIVE_SCAN_KEY);
503
+ };
504
+
505
  if (isTerminated) {
506
  return (
507
  <div className="w-full bg-red-50 border border-red-200 rounded-xl p-md flex items-center justify-between shadow-sm">
 
512
  <p className="font-body-sm text-body-sm text-red-700">Sorry, due to some problemes we terminate your scanning and also show that scanner is terminated.</p>
513
  </div>
514
  </div>
515
+ <div className="flex items-center gap-sm">
516
+ <Link
517
+ to={`/scans/results?id=${completedScanId}`}
518
+ className="bg-red-600 hover:bg-red-700 text-white font-label-md text-label-md px-lg py-sm rounded-lg flex items-center gap-sm transition-colors font-bold border-0"
519
+ style={{ textDecoration: 'none' }}
520
+ >
521
+ <span className="material-symbols-outlined text-[18px]">open_in_new</span>
522
+ View Details
523
+ </Link>
524
+ <button
525
+ onClick={handleDismiss}
526
+ className="p-sm text-red-600 hover:bg-red-100 rounded-lg transition-colors border-0 bg-transparent cursor-pointer flex items-center justify-center"
527
+ title="Dismiss notification"
528
+ >
529
+ <span className="material-symbols-outlined text-[20px]">close</span>
530
+ </button>
531
+ </div>
532
  </div>
533
  );
534
  }
 
543
  <p className="font-body-sm text-body-sm text-red-700">The scanner encountered a critical error. View logs for details.</p>
544
  </div>
545
  </div>
546
+ <div className="flex items-center gap-sm">
547
+ <Link
548
+ to={`/scans/results?id=${completedScanId}`}
549
+ className="bg-red-600 hover:bg-red-700 text-white font-label-md text-label-md px-lg py-sm rounded-lg flex items-center gap-sm transition-colors font-bold border-0"
550
+ style={{ textDecoration: 'none' }}
551
+ >
552
+ <span className="material-symbols-outlined text-[18px]">open_in_new</span>
553
+ View Details
554
+ </Link>
555
+ <button
556
+ onClick={handleDismiss}
557
+ className="p-sm text-red-600 hover:bg-red-100 rounded-lg transition-colors border-0 bg-transparent cursor-pointer flex items-center justify-center"
558
+ title="Dismiss notification"
559
+ >
560
+ <span className="material-symbols-outlined text-[20px]">close</span>
561
+ </button>
562
+ </div>
563
  </div>
564
  );
565
  }
 
573
  <p className="font-body-sm text-body-sm text-green-700">Vulnerability analysis finished. View the full report below.</p>
574
  </div>
575
  </div>
576
+ <div className="flex items-center gap-sm">
577
+ <Link
578
+ to={`/scans/results?id=${completedScanId}`}
579
+ className="bg-green-600 hover:bg-green-700 text-white font-label-md text-label-md px-lg py-sm rounded-lg flex items-center gap-sm transition-colors font-bold border-0"
580
+ style={{ textDecoration: 'none' }}
581
+ >
582
+ <span className="material-symbols-outlined text-[18px]">open_in_new</span>
583
+ View Full Report
584
+ </Link>
585
+ <button
586
+ onClick={handleDismiss}
587
+ className="p-sm text-green-600 hover:bg-green-100 rounded-lg transition-colors border-0 bg-transparent cursor-pointer flex items-center justify-center"
588
+ title="Dismiss notification"
589
+ >
590
+ <span className="material-symbols-outlined text-[20px]">close</span>
591
+ </button>
592
+ </div>
593
  </div>
594
  );
595
  })()