From 7af44608d072777d81dc9dee1bb90cf694162988 Mon Sep 17 00:00:00 2001 From: jramos Date: Wed, 1 Apr 2026 09:20:30 -0600 Subject: [PATCH] feat(compliance): add 'View in Reporting' link for 2.3.x Ivanti metrics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In ComplianceDetailPanel, active metrics with a metric_id starting with '2.3' and an Ivanti_Vulnerability_ID in extra_json now surface the ID prominently alongside a 'View in Reporting →' button. Clicking navigates directly to the Reporting page. onNavigate prop threaded through App → CompliancePage → ComplianceDetailPanel → MetricRow. Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/App.js | 2 +- .../components/pages/ComplianceDetailPanel.js | 40 +++++++++++++++++-- .../src/components/pages/CompliancePage.js | 3 +- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/frontend/src/App.js b/frontend/src/App.js index 506691d..7d4a8d3 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -1044,7 +1044,7 @@ export default function App() { {/* Page content */} {currentPage === 'reporting' && } - {currentPage === 'compliance' && } + {currentPage === 'compliance' && } {currentPage === 'knowledge-base' && } {currentPage === 'exports' && } diff --git a/frontend/src/components/pages/ComplianceDetailPanel.js b/frontend/src/components/pages/ComplianceDetailPanel.js index 6d582cd..aafd20e 100644 --- a/frontend/src/components/pages/ComplianceDetailPanel.js +++ b/frontend/src/components/pages/ComplianceDetailPanel.js @@ -37,7 +37,7 @@ function MetricChip({ metricId, category, status }) { ); } -export default function ComplianceDetailPanel({ hostname, onClose, onNoteAdded }) { +export default function ComplianceDetailPanel({ hostname, onClose, onNoteAdded, onNavigate }) { const [detail, setDetail] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); @@ -158,7 +158,7 @@ export default function ComplianceDetailPanel({ hostname, onClose, onNoteAdded } {activeMetrics.length > 0 && (
}> {activeMetrics.map(m => ( - + ))}
)} @@ -288,10 +288,14 @@ function Section({ title, icon, children, muted, grow }) { ); } -function MetricRow({ metric, resolved }) { +function MetricRow({ metric, resolved, onNavigate }) { const color = resolved ? '#475569' : categoryColor(metric.category); const extra = metric.extra || {}; + const ivantiId = (!resolved && metric.metric_id?.startsWith('2.3')) + ? (extra['Ivanti_Vulnerability_ID'] || null) + : null; + // Surface the most useful extra fields per metric type const highlights = []; if (extra['CVEs_Associated']) highlights.push({ label: 'CVEs', value: extra['CVEs_Associated'] }); @@ -317,10 +321,38 @@ function MetricRow({ metric, resolved }) { {resolved && resolved {metric.resolved_on || ''}} {metric.metric_desc && ( -
+
{metric.metric_desc.length > 100 ? metric.metric_desc.slice(0, 100) + '…' : metric.metric_desc}
)} + {ivantiId && ( +
+
+ Ivanti ID + {ivantiId} +
+ {onNavigate && ( + + )} +
+ )} {highlights.map(h => (
{h.label} diff --git a/frontend/src/components/pages/CompliancePage.js b/frontend/src/components/pages/CompliancePage.js index c6a5833..85f01d4 100644 --- a/frontend/src/components/pages/CompliancePage.js +++ b/frontend/src/components/pages/CompliancePage.js @@ -141,7 +141,7 @@ function SeenBadge({ count }) { // --------------------------------------------------------------------------- // Main Page // --------------------------------------------------------------------------- -export default function CompliancePage() { +export default function CompliancePage({ onNavigate }) { const { canWrite } = useAuth(); const [activeTeam, setActiveTeam] = useState('STEAM'); @@ -424,6 +424,7 @@ export default function CompliancePage() { hostname={selectedHost} onClose={() => setSelectedHost(null)} onNoteAdded={refresh} + onNavigate={onNavigate} /> )}