secubox-openwrt/package/secubox/luci-app-cve-triage/htdocs/luci-static/resources/view/cve-triage/dashboard.js
CyberMind-FR 1bbd345cee refactor(luci): Mass KissTheme UI rework across all LuCI apps
Convert 90+ LuCI view files from legacy cbi-button-* classes to
KissTheme kiss-btn-* classes for consistent dark theme styling.

Pattern conversions applied:
- cbi-button-positive → kiss-btn-green
- cbi-button-negative/remove → kiss-btn-red
- cbi-button-apply → kiss-btn-cyan
- cbi-button-action → kiss-btn-blue
- cbi-button (plain) → kiss-btn

Also replaced hardcoded colors (#080, #c00, #888, etc.) with
CSS variables (--kiss-green, --kiss-red, --kiss-muted, etc.)
for proper dark theme compatibility.

Apps updated include: ai-gateway, auth-guardian, bandwidth-manager,
cloner, config-advisor, crowdsec-dashboard, dns-provider, exposure,
glances, haproxy, hexojs, iot-guard, jellyfin, ksm-manager,
mac-guardian, magicmirror2, master-link, meshname-dns, metablogizer,
metabolizer, mqtt-bridge, netdata-dashboard, picobrew, routes-status,
secubox-admin, secubox-mirror, secubox-p2p, secubox-security-threats,
service-registry, simplex, streamlit, system-hub, tor-shield,
traffic-shaper, vhost-manager, vortex-dns, vortex-firewall,
webradio, wireguard-dashboard, zigbee2mqtt, zkp, and more.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-12 11:09:34 +01:00

246 lines
7.9 KiB
JavaScript

'use strict';
'require view';
'require dom';
'require poll';
'require ui';
'require cve-triage.api as api';
'require secubox/kiss-theme';
return view.extend({
handleSaveApply: null,
handleSave: null,
handleReset: null,
load: function() {
return Promise.all([
api.callStatus(),
api.callGetPending(),
api.callGetAlerts(),
api.callGetSummary()
]);
},
renderStats: function(status, pending, alerts) {
var c = KissTheme.colors;
var localaiColor = status.localai_status === 'online' ? c.green : c.red;
return [
KissTheme.stat(status.enabled ? 'ON' : 'OFF', 'Agent', status.enabled ? c.green : c.red),
KissTheme.stat(status.localai_status.toUpperCase(), 'LocalAI', localaiColor),
KissTheme.stat(status.pending_count, 'Pending', c.orange),
KissTheme.stat(status.alert_count, 'Alerts', status.alert_count > 0 ? c.red : c.muted)
];
},
renderSummaryCard: function(summaryData) {
var summary = summaryData.summary || {};
var riskScore = summary.risk_score || 0;
var riskColor = riskScore >= 70 ? 'red' : (riskScore >= 40 ? 'orange' : 'green');
var riskCssColor = riskScore >= 70 ? 'var(--kiss-red)' : (riskScore >= 40 ? 'var(--kiss-orange)' : 'var(--kiss-green)');
return KissTheme.card('Security Summary',
E('div', { 'style': 'text-align: center;' }, [
E('div', { 'style': 'font-size: 48px; font-weight: 700; color: ' + riskCssColor + ';' }, riskScore),
E('div', { 'style': 'font-size: 14px; color: var(--kiss-muted); margin-bottom: 16px;' }, '/100 Risk Score'),
E('div', { 'style': 'padding: 12px; background: var(--kiss-bg); border-radius: 8px; text-align: left;' },
summary.summary || 'No analysis available. Run a triage cycle.')
])
);
},
renderAlertsCard: function(alertsData) {
var alerts = alertsData.alerts || [];
var activeAlerts = alerts.filter(function(a) { return !a.acknowledged; });
if (activeAlerts.length === 0) {
return KissTheme.card('Alerts',
E('p', { 'style': 'color: var(--kiss-muted); text-align: center; padding: 20px;' },
'No active alerts')
);
}
var alertItems = activeAlerts.slice(0, 5).map(function(alert) {
var severityColor = {
'critical': 'red', 'high': 'orange', 'medium': 'orange', 'low': 'blue'
}[alert.severity] || 'muted';
var borderColor = {
'critical': 'var(--kiss-red)', 'high': 'var(--kiss-orange)', 'medium': 'var(--kiss-orange)', 'low': 'var(--kiss-blue)'
}[alert.severity] || 'var(--kiss-line)';
return E('div', {
'style': 'padding: 12px; background: var(--kiss-bg); border-radius: 6px; border-left: 3px solid ' + borderColor + '; margin-bottom: 8px;'
}, [
E('div', { 'style': 'display: flex; align-items: center; gap: 8px; margin-bottom: 6px;' }, [
KissTheme.badge(alert.severity.toUpperCase(), severityColor),
api.formatCVE(alert.cve),
E('button', {
'class': 'kiss-btn',
'style': 'margin-left: auto; padding: 4px 10px; font-size: 11px;',
'click': function() {
api.callAckAlert(alert.id).then(function() {
window.location.reload();
});
}
}, 'Ack')
]),
E('div', { 'style': 'color: var(--kiss-muted); font-size: 13px;' }, alert.message)
]);
});
return KissTheme.card(
E('div', { 'style': 'display: flex; justify-content: space-between; align-items: center;' }, [
E('span', {}, 'Active Alerts'),
KissTheme.badge(activeAlerts.length + ' alerts', 'red')
]),
E('div', {}, alertItems)
);
},
renderPendingCard: function(pendingData) {
var pending = pendingData.pending || [];
if (pending.length === 0) {
return KissTheme.card('Pending Recommendations',
E('p', { 'style': 'color: var(--kiss-muted); text-align: center; padding: 20px;' },
'No pending recommendations')
);
}
var actionButtons = E('div', { 'style': 'display: flex; gap: 12px; margin-bottom: 16px;' }, [
E('button', {
'class': 'kiss-btn kiss-btn-green',
'click': function() {
if (confirm('Approve all ' + pending.length + ' recommendations?')) {
api.callApproveAll().then(function() {
window.location.reload();
});
}
}
}, 'Approve All'),
E('button', {
'class': 'kiss-btn kiss-btn-red',
'click': function() {
if (confirm('Clear all pending recommendations?')) {
api.callClearPending().then(function() {
window.location.reload();
});
}
}
}, 'Clear All')
]);
var rows = pending.map(function(rec) {
var severityColor = {
'critical': 'red', 'high': 'orange', 'medium': 'orange', 'low': 'blue'
}[rec.severity] || 'muted';
return E('tr', {}, [
E('td', {}, KissTheme.badge(rec.severity.toUpperCase(), severityColor)),
E('td', {}, api.formatCVE(rec.cve)),
E('td', { 'style': 'font-family: monospace;' }, rec.affected_package || '-'),
E('td', {}, rec.action),
E('td', {}, rec.urgency),
E('td', { 'style': 'width: 100px;' }, [
E('div', { 'style': 'display: flex; gap: 6px;' }, [
E('button', {
'class': 'kiss-btn kiss-btn-green',
'style': 'padding: 4px 10px; font-size: 11px;',
'click': function() {
api.callApprove(rec.id).then(function() {
window.location.reload();
});
}
}, '\u2713'),
E('button', {
'class': 'kiss-btn kiss-btn-red',
'style': 'padding: 4px 10px; font-size: 11px;',
'click': function() {
api.callReject(rec.id, 'Manual rejection').then(function() {
window.location.reload();
});
}
}, '\u2717')
])
])
]);
});
return KissTheme.card(
E('div', { 'style': 'display: flex; justify-content: space-between; align-items: center;' }, [
E('span', {}, 'Pending Recommendations'),
KissTheme.badge(pending.length + ' pending', 'orange')
]),
E('div', {}, [
actionButtons,
E('table', { 'class': 'kiss-table' }, [
E('thead', {}, [
E('tr', {}, [
E('th', { 'style': 'width: 80px;' }, 'Severity'),
E('th', {}, 'CVE'),
E('th', {}, 'Package'),
E('th', {}, 'Action'),
E('th', {}, 'Urgency'),
E('th', {}, 'Actions')
])
]),
E('tbody', {}, rows)
])
])
);
},
render: function(data) {
var self = this;
var status = data[0] || {};
var pending = data[1] || {};
var alerts = data[2] || {};
var summary = data[3] || {};
var content = [
// Header
E('div', { 'style': 'margin-bottom: 24px;' }, [
E('div', { 'style': 'display: flex; align-items: center; gap: 16px;' }, [
E('h2', { 'style': 'font-size: 24px; font-weight: 700; margin: 0;' }, 'CVE Triage'),
status.enabled ? KissTheme.badge('Active', 'green') : KissTheme.badge('Inactive', 'red'),
E('button', {
'class': 'kiss-btn kiss-btn-blue',
'style': 'margin-left: auto;',
'click': function() {
ui.showModal('Running Triage...', [
E('p', { 'class': 'spinning' }, 'Starting CVE triage cycle...')
]);
api.callRun().then(function() {
setTimeout(function() {
ui.hideModal();
window.location.reload();
}, 3000);
});
}
}, 'Run Triage')
]),
E('p', { 'style': 'color: var(--kiss-muted); margin: 8px 0 0 0;' },
'AI-powered CVE vulnerability triage and remediation recommendations')
]),
// Stats
E('div', { 'class': 'kiss-grid kiss-grid-4', 'style': 'margin: 20px 0;' },
this.renderStats(status, pending, alerts)),
// Package counts
E('div', { 'style': 'color: var(--kiss-muted); font-size: 12px; margin-bottom: 20px;' },
'Monitored: ' + status.packages.opkg + ' opkg, ' + status.packages.lxc + ' LXC, ' + status.packages.docker + ' Docker' +
(status.last_run ? ' | Last run: ' + status.last_run : '')),
// Two column layout
E('div', { 'class': 'kiss-grid kiss-grid-2', 'style': 'margin-bottom: 20px;' }, [
this.renderSummaryCard(summary),
this.renderAlertsCard(alerts)
]),
// Pending recommendations (full width)
this.renderPendingCard(pending)
];
return KissTheme.wrap(content, 'admin/secubox/security/cve-triage');
}
});