feat(triage): Ivanti findings trend chart + rename Reporting to Vulnerability Triage

Add time-based open/closed tracking for Ivanti findings (Tier 2 from
the reporting recommendations doc) and rename the Reporting page to
Vulnerability Triage to better reflect its purpose.

Backend — ivantiFindings.js:
  - Create ivanti_counts_history table (appended on every sync, never
    overwritten — Option B from design discussion)
  - INSERT snapshot after each successful syncClosedCount() call
  - GET /api/ivanti/findings/counts/history endpoint — returns last
    snapshot per calendar day using ROW_NUMBER window function, so
    multiple daily syncs collapse to the end-of-day value

Frontend:
  - New IvantiCountsChart component: collapsible dual-line chart
    (open vs closed) with dark tooltip, delta label showing change
    since previous day, and graceful no-data states
  - Chart placed between the donut metrics panel and the findings table
    on the Vulnerability Triage page
  - Renamed page: 'reporting' → 'triage' (page ID, nav label, component
    export, all cross-file references)
  - ComplianceDetailPanel "View in Reporting" link updated to "View in
    Triage" and navigates to the correct page ID

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-02 10:12:04 -06:00
parent b111273e5a
commit 15ad207464
6 changed files with 266 additions and 9 deletions

View File

@@ -10,7 +10,7 @@ import KnowledgeBaseModal from './components/KnowledgeBaseModal';
import KnowledgeBaseViewer from './components/KnowledgeBaseViewer';
import NavDrawer from './components/NavDrawer';
import CalendarWidget from './components/CalendarWidget';
import ReportingPage from './components/pages/ReportingPage';
import VulnerabilityTriagePage from './components/pages/ReportingPage';
import KnowledgeBasePage from './components/pages/KnowledgeBasePage';
import ExportsPage from './components/pages/ExportsPage';
import CompliancePage from './components/pages/CompliancePage';
@@ -966,14 +966,14 @@ export default function App() {
currentPage={currentPage}
onNavigate={(page) => {
// Clear contextual filters when navigating directly via the nav drawer
if (page === 'reporting') { setCalendarFilter(null); setReportingExcFilter(null); }
if (page === 'triage') { setCalendarFilter(null); setReportingExcFilter(null); }
setCurrentPage(page);
}}
/>
{/* Scanning line effect */}
<div className="scan-line"></div>
<div className={`${currentPage === 'reporting' ? 'w-full' : 'max-w-7xl mx-auto'} relative z-10`}>
<div className={`${currentPage === 'triage' ? 'w-full' : 'max-w-7xl mx-auto'} relative z-10`}>
{/* Header */}
<div className="mb-8">
<div className="flex justify-between items-start mb-6">
@@ -1043,7 +1043,7 @@ export default function App() {
</div>
{/* Page content */}
{currentPage === 'reporting' && <ReportingPage filterDate={calendarFilter} filterEXC={reportingExcFilter} />}
{currentPage === 'triage' && <VulnerabilityTriagePage filterDate={calendarFilter} filterEXC={reportingExcFilter} />}
{currentPage === 'compliance' && <CompliancePage onNavigate={setCurrentPage} />}
{currentPage === 'knowledge-base' && <KnowledgeBasePage />}
{currentPage === 'exports' && <ExportsPage />}
@@ -2231,7 +2231,7 @@ export default function App() {
<CalendarWidget
onDateClick={(dateStr) => {
setCalendarFilter(dateStr);
setCurrentPage('reporting');
setCurrentPage('triage');
}}
/>
</div>