mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-06-10 08:13:59 +02:00
Add files via upload
This commit is contained in:
+36
-14
@@ -16049,17 +16049,10 @@ tr.mcp-stats-tool-row[data-tool-name]:focus-visible {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.dashboard-recent-facts-meta {
|
||||
font-size: 0.75rem;
|
||||
color: var(--text-secondary, #6b7280);
|
||||
padding: 2px 4px 8px;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.dashboard-recent-fact-item {
|
||||
display: grid;
|
||||
/* 置顶 / 分类 / 置信度 固定列宽,保证各行对齐 */
|
||||
grid-template-columns: 20px 64px 56px minmax(0, 1.4fr) minmax(0, 1fr) 9.5rem;
|
||||
/* 置顶 / 分类 / 置信度 / 摘要 / fact_key / 项目 / 时间 */
|
||||
grid-template-columns: 20px 64px 56px minmax(0, 1.2fr) minmax(0, 1fr) 72px 9.5rem;
|
||||
align-items: center;
|
||||
column-gap: 10px;
|
||||
padding: 12px 10px;
|
||||
@@ -16097,6 +16090,35 @@ tr.mcp-stats-tool-row[data-tool-name]:focus-visible {
|
||||
justify-self: center;
|
||||
}
|
||||
|
||||
.dashboard-recent-fact-project {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 72px;
|
||||
box-sizing: border-box;
|
||||
padding: 3px 6px;
|
||||
border-radius: 6px;
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.2;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
justify-self: start;
|
||||
background: #fff;
|
||||
border: 1px dashed transparent;
|
||||
}
|
||||
|
||||
/* 项目:虚线描边 + 浅底,与置信度实心药丸区分 */
|
||||
.dashboard-recent-fact-project.proj-tone-0 { background: rgba(139, 92, 246, 0.05); color: #6d28d9; border-color: rgba(109, 40, 217, 0.45); }
|
||||
.dashboard-recent-fact-project.proj-tone-1 { background: rgba(59, 130, 246, 0.05); color: #1d4ed8; border-color: rgba(29, 78, 216, 0.45); }
|
||||
.dashboard-recent-fact-project.proj-tone-2 { background: rgba(20, 184, 166, 0.05); color: #0f766e; border-color: rgba(15, 118, 110, 0.45); }
|
||||
.dashboard-recent-fact-project.proj-tone-3 { background: rgba(245, 158, 11, 0.06); color: #b45309; border-color: rgba(180, 83, 9, 0.45); }
|
||||
.dashboard-recent-fact-project.proj-tone-4 { background: rgba(244, 63, 94, 0.05); color: #be123c; border-color: rgba(190, 18, 60, 0.45); }
|
||||
.dashboard-recent-fact-project.proj-tone-5 { background: rgba(99, 102, 241, 0.05); color: #4338ca; border-color: rgba(67, 56, 202, 0.45); }
|
||||
.dashboard-recent-fact-project.proj-tone-6 { background: rgba(16, 185, 129, 0.05); color: #047857; border-color: rgba(4, 120, 87, 0.45); }
|
||||
.dashboard-recent-fact-project.proj-tone-7 { background: rgba(236, 72, 153, 0.05); color: #be185d; border-color: rgba(190, 24, 93, 0.45); }
|
||||
|
||||
.dashboard-recent-fact-cat,
|
||||
.dashboard-recent-fact-conf {
|
||||
display: inline-flex;
|
||||
@@ -16165,7 +16187,7 @@ tr.mcp-stats-tool-row[data-tool-name]:focus-visible {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.dashboard-recent-fact-meta {
|
||||
.dashboard-recent-fact-key {
|
||||
color: var(--text-secondary);
|
||||
font-size: 0.8125rem;
|
||||
min-width: 0;
|
||||
@@ -16188,21 +16210,21 @@ tr.mcp-stats-tool-row[data-tool-name]:focus-visible {
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.dashboard-recent-fact-item {
|
||||
grid-template-columns: 20px 64px minmax(0, 1fr) auto 8.25rem;
|
||||
grid-template-columns: 20px 64px minmax(0, 1fr) minmax(0, 0.8fr) 72px 8.25rem;
|
||||
}
|
||||
.dashboard-recent-fact-conf { display: none; }
|
||||
}
|
||||
|
||||
@media (max-width: 720px) {
|
||||
.dashboard-recent-fact-item {
|
||||
grid-template-columns: 20px 64px minmax(0, 1fr) auto;
|
||||
grid-template-columns: 20px 64px minmax(0, 1fr) 72px auto;
|
||||
}
|
||||
.dashboard-recent-fact-meta { display: none; }
|
||||
.dashboard-recent-fact-key { display: none; }
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.dashboard-recent-fact-item {
|
||||
grid-template-columns: 20px minmax(0, 1fr) auto;
|
||||
grid-template-columns: 20px 72px minmax(0, 1fr) auto;
|
||||
}
|
||||
.dashboard-recent-fact-cat { display: none; }
|
||||
.dashboard-recent-fact-time { display: none; }
|
||||
|
||||
+23
-19
@@ -116,7 +116,7 @@ async function refreshDashboard() {
|
||||
fetchJson('/api/monitor/stats'),
|
||||
fetchJson('/api/knowledge/stats'),
|
||||
fetchJson('/api/skills/stats'),
|
||||
fetchJson('/api/vulnerabilities?limit=5&page=1'),
|
||||
fetchJson('/api/vulnerabilities?limit=10&page=1'),
|
||||
fetchJson('/api/roles'),
|
||||
fetchJson('/api/multi-agent/markdown-agents'),
|
||||
openVulnQuery('critical'),
|
||||
@@ -139,7 +139,7 @@ async function refreshDashboard() {
|
||||
fetchJson('/api/c2/listeners'),
|
||||
fetchJson('/api/c2/sessions?limit=500'),
|
||||
fetchJson('/api/c2/tasks?page=1&page_size=1'),
|
||||
fetchJson('/api/projects/dashboard-summary?fact_limit=5')
|
||||
fetchJson('/api/projects/dashboard-summary?fact_limit=10')
|
||||
]);
|
||||
|
||||
// 如果在 await 期间 controller 已被 abort,说明又有新刷新启动了,丢弃本次结果
|
||||
@@ -1117,7 +1117,7 @@ function renderRecentVulns(res) {
|
||||
empty.classList.remove('is-rich');
|
||||
}
|
||||
|
||||
list.slice(0, 5).forEach(function (v) {
|
||||
list.slice(0, 10).forEach(function (v) {
|
||||
const sev = (v.severity || 'info').toLowerCase();
|
||||
const status = (v.status || 'open').toLowerCase();
|
||||
const item = document.createElement('a');
|
||||
@@ -1211,6 +1211,18 @@ function factCategoryShortLabel(category) {
|
||||
return raw || 'note';
|
||||
}
|
||||
|
||||
// 按 project_id(回退 project_name)稳定映射 8 种配色,同一项目跨刷新颜色一致
|
||||
function projectFactProjectTone(projectId, projectName) {
|
||||
var key = String(projectId || projectName || '').trim();
|
||||
if (!key) return 0;
|
||||
var hash = 0;
|
||||
for (var i = 0; i < key.length; i++) {
|
||||
hash = ((hash << 5) - hash) + key.charCodeAt(i);
|
||||
hash |= 0;
|
||||
}
|
||||
return Math.abs(hash) % 8;
|
||||
}
|
||||
|
||||
function openProjectFactFromDashboard(projectId, factKey) {
|
||||
if (!projectId) return;
|
||||
if (typeof switchPage === 'function') {
|
||||
@@ -1289,15 +1301,7 @@ function renderRecentFacts(res) {
|
||||
empty.classList.remove('is-rich');
|
||||
}
|
||||
|
||||
if (activeProjects > 0 || totalFacts > 0) {
|
||||
var meta = document.createElement('div');
|
||||
meta.className = 'dashboard-recent-facts-meta';
|
||||
meta.textContent = dt('dashboard.factsAcrossProjects', { count: activeProjects, facts: totalFacts },
|
||||
activeProjects + ' 个活跃项目 · ' + totalFacts + ' 条事实');
|
||||
wrap.appendChild(meta);
|
||||
}
|
||||
|
||||
list.slice(0, 5).forEach(function (f) {
|
||||
list.slice(0, 10).forEach(function (f) {
|
||||
if (!f) return;
|
||||
var category = factCategoryShortLabel(f.category);
|
||||
var confidence = String(f.confidence || 'tentative').toLowerCase();
|
||||
@@ -1319,17 +1323,17 @@ function renderRecentFacts(res) {
|
||||
var pinMark = '<span class="dashboard-recent-fact-pin' + (f.pinned ? ' is-pinned' : '') + '"' +
|
||||
(f.pinned ? (' title="' + esc(dt('projects.pinned', null, '置顶')) + '"') : '') +
|
||||
' aria-hidden="true">' + (f.pinned ? '📌' : '') + '</span>';
|
||||
var projectLabel = (f.project_name || '').trim() || dt('projects.defaultProjectName', null, '项目');
|
||||
var factKeyLabel = (f.fact_key || '').trim() || '—';
|
||||
var projectTone = projectFactProjectTone(pid, projectLabel);
|
||||
var projectCol = '<span class="dashboard-recent-fact-project proj-tone-' + projectTone + '" title="' + esc(projectLabel) + '">' + esc(projectLabel) + '</span>';
|
||||
var categoryBadge = '<span class="dashboard-recent-fact-cat cat-' + esc(category.toLowerCase().replace(/[^a-z0-9_-]/g, '')) + '">' + esc(category) + '</span>';
|
||||
var confBadge = '<span class="dashboard-recent-fact-conf conf-' + esc(confidence) + '">' + esc(factConfidenceShortLabel(confidence)) + '</span>';
|
||||
var summary = '<span class="dashboard-recent-fact-summary" title="' + esc(f.summary || '') + '">' + esc(f.summary || dt('common.untitled', null, '无标题')) + '</span>';
|
||||
// 勿用 i18n 插值拼接 fact_key:i18next 会把 / 转成 / 导致乱码
|
||||
var projectLabel = (f.project_name || '').trim() || dt('projects.defaultProjectName', null, '项目');
|
||||
var factKeyLabel = (f.fact_key || '').trim() || '—';
|
||||
var metaText = projectLabel + ' · ' + factKeyLabel;
|
||||
var metaLine = '<span class="dashboard-recent-fact-meta" title="' + esc(metaText) + '">' + esc(metaText) + '</span>';
|
||||
var factKeyCol = '<span class="dashboard-recent-fact-key" title="' + esc(factKeyLabel) + '">' + esc(factKeyLabel) + '</span>';
|
||||
var time = '<span class="dashboard-recent-fact-time">' + esc(timeAgoStr(f.updated_at)) + '</span>';
|
||||
|
||||
item.innerHTML = pinMark + categoryBadge + confBadge + summary + metaLine + time;
|
||||
item.innerHTML = pinMark + categoryBadge + confBadge + summary + factKeyCol + projectCol + time;
|
||||
wrap.appendChild(item);
|
||||
});
|
||||
}
|
||||
@@ -1428,7 +1432,7 @@ function renderVulnStatusPanel(byStatus, total) {
|
||||
//
|
||||
// bySeverityOpen: { critical, high, medium, low }(只统计 status=open 的漏洞;info 不计入)
|
||||
// totalOpen: 待处理漏洞总数(= critical + high + medium + low),仅用于"全无待处理 → safe"判断
|
||||
// recentVulnsRes: /api/vulnerabilities?limit=5 响应(用于"最近发现"时间,口径是全量,与处置状态无关)
|
||||
// recentVulnsRes: /api/vulnerabilities?limit=10 响应(用于"最近发现"时间,口径是全量,与处置状态无关)
|
||||
function renderSeverityInsights(bySeverityOpen, totalOpen, recentVulnsRes) {
|
||||
var riskBox = document.querySelector('.dashboard-severity-insight-risk');
|
||||
var levelEl = document.getElementById('dashboard-severity-risk-level');
|
||||
|
||||
Reference in New Issue
Block a user