From 4a50cd100b5e3a2a069db3d3a0ab1365969dbee9 Mon Sep 17 00:00:00 2001 From: jramos Date: Tue, 10 Feb 2026 10:12:56 -0700 Subject: [PATCH] drastic changes --- frontend/src/App.css | 13 +++ frontend/src/App.js | 240 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 209 insertions(+), 44 deletions(-) diff --git a/frontend/src/App.css b/frontend/src/App.css index 9fbc320..be6df2b 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -1,9 +1,22 @@ /* Tactical Intelligence Dashboard Styles */ +/* IMPORTANT: This file MUST be imported in App.js */ * { font-family: 'Outfit', system-ui, sans-serif; } +/* Pulse animation for glowing dots - used by inline styles */ +@keyframes pulse { + 0%, 100% { + opacity: 1; + transform: scale(1); + } + 50% { + opacity: 0.7; + transform: scale(1.2); + } +} + :root { /* Base Colors */ --intel-darkest: #0A0E27; diff --git a/frontend/src/App.js b/frontend/src/App.js index 92a498a..e57fb04 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -6,8 +6,150 @@ import UserMenu from './components/UserMenu'; import UserManagement from './components/UserManagement'; import AuditLog from './components/AuditLog'; import NvdSyncModal from './components/NvdSyncModal'; +import './App.css'; const API_BASE = process.env.REACT_APP_API_BASE || 'http://localhost:3001/api'; + +// ============================================ +// INLINE STYLES - NUCLEAR OPTION FOR VISIBILITY +// ============================================ +const STYLES = { + // Main container with visible background + mainContainer: { + minHeight: '100vh', + background: 'linear-gradient(135deg, #0A0E27 0%, #131937 50%, #0A0E27 100%)', + padding: '1.5rem', + position: 'relative', + overflow: 'hidden', + }, + // Stat cards with BRIGHT CYAN borders + statCard: { + background: 'linear-gradient(135deg, rgba(19, 25, 55, 1) 0%, rgba(30, 39, 73, 0.95) 100%)', + border: '3px solid #00D9FF', + borderRadius: '0.5rem', + padding: '1rem', + boxShadow: '0 8px 24px rgba(0, 0, 0, 0.6), 0 0 30px rgba(0, 217, 255, 0.3), inset 0 2px 0 rgba(0, 217, 255, 0.2)', + position: 'relative', + overflow: 'hidden', + }, + // Intel card with thick glowing border + intelCard: { + background: 'linear-gradient(135deg, rgba(19, 25, 55, 1) 0%, rgba(30, 39, 73, 0.95) 50%, rgba(19, 25, 55, 1) 100%)', + border: '3px solid rgba(0, 217, 255, 0.6)', + borderRadius: '0.5rem', + boxShadow: '0 12px 32px rgba(0, 0, 0, 0.7), 0 0 40px rgba(0, 217, 255, 0.25), inset 0 2px 0 rgba(0, 217, 255, 0.15)', + position: 'relative', + overflow: 'hidden', + }, + // Vendor card with depth + vendorCard: { + background: 'linear-gradient(135deg, rgba(10, 14, 39, 0.95) 0%, rgba(19, 25, 55, 0.9) 100%)', + border: '2px solid rgba(0, 217, 255, 0.4)', + borderRadius: '0.5rem', + padding: '1rem', + boxShadow: '0 6px 16px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(0, 217, 255, 0.1)', + marginBottom: '0.75rem', + }, + // CRITICAL severity badge - BRIGHT RED with WHITE text + badgeCritical: { + display: 'inline-flex', + alignItems: 'center', + gap: '0.5rem', + background: 'linear-gradient(135deg, rgba(255, 51, 102, 0.4) 0%, rgba(255, 51, 102, 0.3) 100%)', + border: '2px solid #FF3366', + borderRadius: '0.375rem', + padding: '0.375rem 0.875rem', + color: '#FFFFFF', + fontWeight: '700', + fontSize: '0.75rem', + textTransform: 'uppercase', + letterSpacing: '0.5px', + textShadow: '0 0 10px rgba(255, 51, 102, 0.9)', + boxShadow: '0 0 20px rgba(255, 51, 102, 0.5), 0 4px 8px rgba(0, 0, 0, 0.4)', + }, + // HIGH severity badge - BRIGHT ORANGE/YELLOW with WHITE text + badgeHigh: { + display: 'inline-flex', + alignItems: 'center', + gap: '0.5rem', + background: 'linear-gradient(135deg, rgba(255, 184, 0, 0.4) 0%, rgba(255, 184, 0, 0.3) 100%)', + border: '2px solid #FFB800', + borderRadius: '0.375rem', + padding: '0.375rem 0.875rem', + color: '#FFFFFF', + fontWeight: '700', + fontSize: '0.75rem', + textTransform: 'uppercase', + letterSpacing: '0.5px', + textShadow: '0 0 10px rgba(255, 184, 0, 0.9)', + boxShadow: '0 0 20px rgba(255, 184, 0, 0.5), 0 4px 8px rgba(0, 0, 0, 0.4)', + }, + // MEDIUM severity badge - BRIGHT CYAN with WHITE text + badgeMedium: { + display: 'inline-flex', + alignItems: 'center', + gap: '0.5rem', + background: 'linear-gradient(135deg, rgba(0, 217, 255, 0.4) 0%, rgba(0, 217, 255, 0.3) 100%)', + border: '2px solid #00D9FF', + borderRadius: '0.375rem', + padding: '0.375rem 0.875rem', + color: '#FFFFFF', + fontWeight: '700', + fontSize: '0.75rem', + textTransform: 'uppercase', + letterSpacing: '0.5px', + textShadow: '0 0 10px rgba(0, 217, 255, 0.9)', + boxShadow: '0 0 20px rgba(0, 217, 255, 0.5), 0 4px 8px rgba(0, 0, 0, 0.4)', + }, + // LOW severity badge - BRIGHT GREEN with WHITE text + badgeLow: { + display: 'inline-flex', + alignItems: 'center', + gap: '0.5rem', + background: 'linear-gradient(135deg, rgba(0, 255, 136, 0.4) 0%, rgba(0, 255, 136, 0.3) 100%)', + border: '2px solid #00FF88', + borderRadius: '0.375rem', + padding: '0.375rem 0.875rem', + color: '#FFFFFF', + fontWeight: '700', + fontSize: '0.75rem', + textTransform: 'uppercase', + letterSpacing: '0.5px', + textShadow: '0 0 10px rgba(0, 255, 136, 0.9)', + boxShadow: '0 0 20px rgba(0, 255, 136, 0.5), 0 4px 8px rgba(0, 0, 0, 0.4)', + }, + // Glowing dot for badges + glowDot: (color) => ({ + width: '8px', + height: '8px', + borderRadius: '50%', + background: color, + boxShadow: `0 0 12px ${color}, 0 0 6px ${color}`, + animation: 'pulse 2s ease-in-out infinite', + }), +}; + +// Helper function to get severity badge style +const getSeverityBadgeStyle = (severity) => { + switch (severity?.toLowerCase()) { + case 'critical': return STYLES.badgeCritical; + case 'high': return STYLES.badgeHigh; + case 'medium': return STYLES.badgeMedium; + case 'low': return STYLES.badgeLow; + default: return STYLES.badgeMedium; + } +}; + +// Helper function to get severity dot color +const getSeverityDotColor = (severity) => { + switch (severity?.toLowerCase()) { + case 'critical': return '#FF3366'; + case 'high': return '#FFB800'; + case 'medium': return '#00D9FF'; + case 'low': return '#00FF88'; + default: return '#00D9FF'; + } +}; const API_HOST = process.env.REACT_APP_API_HOST || 'http://localhost:3001'; const severityLevels = ['All Severities', 'Critical', 'High', 'Medium', 'Low']; @@ -628,23 +770,27 @@ export default function App() { - {/* Stats Bar */} + {/* Stats Bar - INLINE STYLES FOR GUARANTEED VISIBILITY */}
-
-
Total CVEs
-
{Object.keys(filteredGroupedCVEs).length}
+
+
+
Total CVEs
+
{Object.keys(filteredGroupedCVEs).length}
-
-
Vendor Entries
-
{cves.length}
+
+
+
Vendor Entries
+
{cves.length}
-
-
Open Tickets
-
{jiraTickets.filter(t => t.status !== 'Closed').length}
+
+
+
Open Tickets
+
{jiraTickets.filter(t => t.status !== 'Closed').length}
-
-
Critical
-
{cves.filter(c => c.severity === 'Critical').length}
+
+
+
Critical
+
{cves.filter(c => c.severity === 'Critical').length}
@@ -1110,9 +1256,9 @@ export default function App() { )} {/* Quick Check */} -
+
-

Quick CVE Lookup

+

Quick CVE Lookup

t.status !== 'Closed').length > 0 && ( -
+
-

+

Open Tickets ({jiraTickets.filter(t => t.status !== 'Closed').length})

@@ -1192,7 +1338,7 @@ export default function App() {
{jiraTickets.filter(t => t.status !== 'Closed').map(ticket => ( -
+
@@ -1228,7 +1373,7 @@ export default function App() { )} {/* Search and Filters */} -
+
+
{/* Clickable CVE Header */}
toggleCVEExpand(cveId)} >
@@ -1346,17 +1491,18 @@ export default function App() { {/* Collapsed: truncated description + summary row */} {!isCVEExpanded && (
-

{vendorEntries[0].description}

+

{vendorEntries[0].description}

- + + {highestSeverity} - {vendorEntries.length} vendor{vendorEntries.length > 1 ? 's' : ''} - + {vendorEntries.length} vendor{vendorEntries.length > 1 ? 's' : ''} + {totalDocCount} doc{totalDocCount !== 1 ? 's' : ''} - + {overallStatuses.join(', ')}
@@ -1397,18 +1543,19 @@ export default function App() { const isDocExpanded = selectedCVE === cve.cve_id && selectedVendorView === cve.vendor; return ( -
+
-

{cve.vendor}

- +

{cve.vendor}

+ + {cve.severity}
-
- Status: {cve.status} - +
+ Status: {cve.status} + {cve.document_count} doc{cve.document_count !== 1 ? 's' : ''} @@ -1534,7 +1681,7 @@ export default function App() { {vendorTickets.length > 0 ? (
{vendorTickets.map(ticket => ( -
+
{ticket.ticket_key} - {ticket.summary && {ticket.summary}} - + {ticket.summary && {ticket.summary}} + + {ticket.status}