Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 34 additions & 8 deletions src/_nav.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,21 +69,32 @@ export const getNavigation = (departments, onAddDepartment, onAddAsset, dynamicN
{
component: CNavItem,
name: 'Scan Results',
to: '/vulnerabilities/scan-results',
to: '#',
disabled: true,
badge: {
color: 'danger',
text: 'NEW',
color: 'secondary',
text: 'COMING SOON',
},
},
{
component: CNavItem,
name: 'CVE Database',
to: '/vulnerabilities/cve-database',
to: '#',
disabled: true,
badge: {
color: 'secondary',
text: 'COMING SOON',
},
},
{
component: CNavItem,
name: 'Risk Assessment',
to: '/vulnerabilities/risk-assessment',
to: '#',
disabled: true,
badge: {
color: 'secondary',
text: 'COMING SOON',
},
}
]
},
Expand All @@ -95,17 +106,32 @@ export const getNavigation = (departments, onAddDepartment, onAddAsset, dynamicN
{
component: CNavItem,
name: 'Threat Intelligence',
to: '/analytics/threat-intelligence',
to: '#',
disabled: true,
badge: {
color: 'secondary',
text: 'COMING SOON',
},
},
{
component: CNavItem,
name: 'Attack Patterns',
to: '/analytics/attack-patterns',
to: '#',
disabled: true,
badge: {
color: 'secondary',
text: 'COMING SOON',
},
},
{
component: CNavItem,
name: 'Security Metrics',
to: '/analytics/security-metrics',
to: '#',
disabled: true,
badge: {
color: 'secondary',
text: 'COMING SOON',
},
}
]
}
Expand Down
26 changes: 18 additions & 8 deletions src/components/AppBreadcrumb.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ const AppBreadcrumb = () => {
const getBreadcrumbs = (location) => {
const breadcrumbs = []

// Handle root/overview case - don't add extra breadcrumbs
if (location === '/' || location === '/overview') {
return breadcrumbs // Return empty array, the "Overview" will be shown as base
}

// Handle special dynamic routes
if (location.startsWith('/asset/')) {
const asset = assets.find(a => a.id === assetId)
Expand All @@ -44,18 +49,21 @@ const AppBreadcrumb = () => {
// Handle standard routes
const pathSegments = location.split('/').filter(segment => segment !== '')

// Skip if this is just the overview page
if (pathSegments.length === 1 && pathSegments[0] === 'overview') {
return breadcrumbs
}

pathSegments.reduce((prev, curr, index, array) => {
const currentPathname = `${prev}/${curr}`
let routeName = getRouteName(currentPathname, routes)
let icon = null

// Set appropriate icons for known routes
switch (currentPathname) {
case '/overview':
icon = cilHome
break
case '/datamanagement':
icon = cilSettings
routeName = 'Data Management'
break
default:
if (departments.includes(curr)) {
Expand Down Expand Up @@ -89,11 +97,13 @@ const AppBreadcrumb = () => {

return (
<CBreadcrumb className="my-0">
{/* Home/Overview breadcrumb */}
<CBreadcrumbItem href="/#/overview" className="d-flex align-items-center">
<CIcon icon={cilHome} size="sm" className="me-1" />
Overview
</CBreadcrumbItem>
{/* Home/Overview breadcrumb - only show if not already on overview */}
{currentLocation !== '/' && currentLocation !== '/overview' && (
<CBreadcrumbItem href="/#/overview" className="d-flex align-items-center">
<CIcon icon={cilHome} size="sm" className="me-1" />
Overview
</CBreadcrumbItem>
)}

{breadcrumbs.map((breadcrumb, index) => {
return (
Expand Down
189 changes: 104 additions & 85 deletions src/components/AppHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,23 +101,37 @@ const AppHeader = () => {

// Simulate security alerts (in real app, this would come from your backend)
useEffect(() => {
const alerts = [
{
id: 1,
type: 'critical',
title: 'Critical Vulnerability Detected',
message: 'CVE-2024-1234 found in 3 assets',
timestamp: new Date(Date.now() - 30 * 60 * 1000)
},
{
id: 2,
type: 'warning',
title: 'Outdated Software Detected',
message: '5 assets need security updates',
timestamp: new Date(Date.now() - 2 * 60 * 60 * 1000)
const alerts = []

assets.forEach(asset => {
if (asset.vulnerabilities?.cves) {
asset.vulnerabilities.cves.forEach(cve => {
if (cve.cvss >= 7.0) { // Only show high/critical vulnerabilities
alerts.push({
id: `${asset.id}-${cve.cve_id}`,
type: cve.cvss >= 9.0 ? 'critical' : 'high',
title: `${cve.cve_id} - ${asset.name}`,
message: `CVSS: ${cve.cvss} - ${cve.description?.substring(0, 100)}...`,
timestamp: new Date(asset.last_updated || Date.now()),
assetId: asset.id,
assetName: asset.name,
cveId: cve.cve_id,
cvssScore: cve.cvss
})
}
})
}
})

// Sort by CVSS score descending, then by timestamp
alerts.sort((a, b) => {
if (b.cvssScore !== a.cvssScore) {
return b.cvssScore - a.cvssScore
}
]
setSecurityAlerts(alerts)
return b.timestamp - a.timestamp
})

setSecurityAlerts(alerts.slice(0, 20)) // Limit to 20 most critical
}, [assets])

const getSecurityStatusColor = () => {
Expand Down Expand Up @@ -166,72 +180,58 @@ const AppHeader = () => {
</CHeaderNav>

{/* Security Tools */}
<CHeaderNav className="ms-auto">
{/* Security Alerts */}
<CNavItem>
<CNavLink
href="#"
onClick={(e) => {
e.preventDefault()
setShowAlertsModal(true)
}}
className="position-relative"
>
<CIcon icon={cilBell} size="lg" />
{securityAlerts.length > 0 && (
<CHeaderNav className="ms-auto">
{/* Security Alerts */}
<CNavItem>
<CNavLink
href="#"
onClick={(e) => {
e.preventDefault()
setShowAlertsModal(true)
}}
className="position-relative"
title="Security Alerts"
>
<CIcon icon={cilBell} size="lg" />
{securityAlerts.length > 0 && (
<CBadge
color="danger"
position="top-end"
shape="rounded-pill"
className="position-absolute"
>
{securityAlerts.length}
</CBadge>
)}
</CNavLink>
</CNavItem>

{/* Security Status Indicator */}
<CNavItem>
<CNavLink
href="#"
onClick={(e) => {
e.preventDefault()
setShowSecurityStatus(true)
}}
className="position-relative"
title="Security Status Overview"
>
<CIcon
icon={getSecurityStatusIcon()}
size="lg"
className={`text-${getSecurityStatusColor()}`}
/>
<CBadge
color="danger"
position="top-end"
shape="rounded-pill"
className="position-absolute"
color={getSecurityStatusColor()}
className="position-absolute top-0 start-100 translate-middle"
style={{ fontSize: '0.6rem', padding: '0.2rem 0.4rem' }}
>
{securityAlerts.length}
{securityMetrics.overallRiskScore}
</CBadge>
)}
</CNavLink>
</CNavItem>

{/* Vulnerability Scanner */}
<CNavItem>
<CNavLink
href="#"
onClick={(e) => {
e.preventDefault()
// Implement scan functionality
setLastScanTime(new Date())
alert('Vulnerability scan initiated...')
}}
title="Run Vulnerability Scan"
>
<CIcon icon={cilBug} size="lg" />
</CNavLink>
</CNavItem>

{/* Security Status Indicator */}
<CNavItem>
<CNavLink
href="#"
onClick={(e) => {
e.preventDefault()
setShowSecurityStatus(true)
}}
className="position-relative"
>
<CIcon
icon={getSecurityStatusIcon()}
size="lg"
className={`text-${getSecurityStatusColor()}`}
/>
<CBadge
color={getSecurityStatusColor()}
className="position-absolute top-0 start-100 translate-middle"
style={{ fontSize: '0.6rem', padding: '0.2rem 0.4rem' }}
>
{securityMetrics.overallRiskScore}
</CBadge>
</CNavLink>
</CNavItem>
</CHeaderNav>
</CNavLink>
</CNavItem>
</CHeaderNav>

{/* Theme Switcher */}
<CHeaderNav>
Expand Down Expand Up @@ -331,23 +331,42 @@ const AppHeader = () => {
icon={alert.type === 'critical' ? cilWarning : cilTriangle}
className={alert.type === 'critical' ? 'text-danger' : 'text-warning'}
/>
{alert.title}
<code className="text-primary">{alert.cveId}</code>
<span>on {alert.assetName}</span>
</div>
<p className="mb-1">{alert.message}</p>
<div className="d-flex gap-2 my-1">
<CBadge
color={alert.cvssScore >= 9.0 ? 'danger' : 'warning'}
>
CVSS: {alert.cvssScore}
</CBadge>
<CBadge color={alert.type === 'critical' ? 'danger' : 'warning'}>
{alert.type.toUpperCase()}
</CBadge>
</div>
<p className="mb-1 small">{alert.message}</p>
<small className="text-muted">
{alert.timestamp.toLocaleString()}
</small>
</div>
<CBadge color={alert.type === 'critical' ? 'danger' : 'warning'}>
{alert.type}
</CBadge>
<CButton
color="primary"
size="sm"
variant="outline"
onClick={() => {
setShowAlertsModal(false)
navigate(`/asset/${alert.assetId}`)
}}
>
View Asset
</CButton>
</CListGroupItem>
))}
</CListGroup>
) : (
<CAlert color="success">
<CIcon icon={cilCheckCircle} className="me-2" />
No security alerts at this time.
No critical or high-risk vulnerabilities found.
</CAlert>
)}
</CModalBody>
Expand Down
Loading