更新: 2 个文件 - 2026-03-21 18:00:07
这个提交包含在:
@@ -63,6 +63,10 @@ const DATA_HUB_ITEMS = [
|
||||
{ title: "entity-completeness.json", href: "/data/entity-completeness.json", description: "实体级 catalog 完整度、版本映射和 workflow 覆盖。", badge: "json" },
|
||||
{ title: "entity-discovery-backlog.json", href: "/data/entity-discovery-backlog.json", description: "发现但尚未正式编目的 repo / 插件 / 包 backlog。", badge: "json" },
|
||||
{ title: "entity-queues.json", href: "/data/entity-queues.json", description: "discovery/history/latest/workflow 四类队列摘要。", badge: "json" },
|
||||
{ title: "version-completeness.json", href: "/data/version-completeness.json", description: "最新版本同步覆盖、安全相关版本历史与 auto-promoted 统计。", badge: "json" },
|
||||
{ title: "version-backlog.json", href: "/data/version-backlog.json", description: "source-gap、未解决版本缺口与 lab pending 队列。", badge: "json" },
|
||||
{ title: "release-index.json", href: "/data/release-index.json", description: "安全相关版本记录索引真值。", badge: "json" },
|
||||
{ title: "lab-enqueue-summary.json", href: "/data/lab-enqueue-summary.json", description: "版本变化触发的 lab 入队与 pending 摘要。", badge: "json" },
|
||||
{ title: "runs.json", href: "/runs.json", description: "最近运行的结构化详情,可用于 UI 和调试。", badge: "json" },
|
||||
{ title: "systems.json", href: "/systems.json", description: "系统级覆盖、分类、更新时间和浏览器证据统计。", badge: "json" },
|
||||
{ title: "entities.json", href: "/entities.json", description: "分层实体索引、实体状态和系统归属。", badge: "json" },
|
||||
@@ -101,6 +105,7 @@ const state = {
|
||||
architecture: null,
|
||||
completeness: null,
|
||||
entityCompleteness: null,
|
||||
versionCompleteness: null,
|
||||
sourceHealth: null,
|
||||
alerts: [],
|
||||
monitorSummary: null,
|
||||
@@ -297,11 +302,14 @@ function familyOptions() {
|
||||
function metricCards() {
|
||||
const completeness = state.completeness || state.summary?.completeness || {};
|
||||
const entityCoverage = state.entityCompleteness || state.summary?.entity_coverage || completeness.entity_coverage || {};
|
||||
const versionCoverage = state.versionCompleteness || state.summary?.version_coverage || completeness.version_coverage || {};
|
||||
const monitoring = state.monitorSummary || state.summary?.monitoring || {};
|
||||
const advisoryTotal = Number(completeness.advisory_total || state.summary?.advisory_count || 0);
|
||||
const advisorySuccess = Number(completeness.verified_real || 0);
|
||||
const catalogedEntities = Number(entityCoverage.cataloged_entity_total || 0);
|
||||
const candidateEntities = Number(entityCoverage.candidate_entity_total || 0);
|
||||
const latestVersionSynced = Number(versionCoverage.latest_version_synced_count || 0);
|
||||
const sourceGapCount = Number(versionCoverage.source_gap_count || 0);
|
||||
const activeSources = Number(monitoring.active_source_count || state.sourceHealth?.active_source_count || 0);
|
||||
const greenSources = Number(monitoring.green_source_count || state.sourceHealth?.green_source_count || 0);
|
||||
const openAlerts = Number(monitoring.open_alert_count || state.sourceHealth?.open_alert_count || 0);
|
||||
@@ -322,6 +330,13 @@ function metricCards() {
|
||||
color: "var(--accent-yellow)",
|
||||
iconName: "systems"
|
||||
},
|
||||
{
|
||||
label: "版本同步",
|
||||
value: latestVersionSynced,
|
||||
note: `source-gap ${sourceGapCount}`,
|
||||
color: "var(--accent-blue)",
|
||||
iconName: "spark"
|
||||
},
|
||||
{
|
||||
label: "active sources",
|
||||
value: activeSources,
|
||||
@@ -602,6 +617,7 @@ function renderSystemCards(items, compact = false) {
|
||||
const verified = Number(system.verified_real || 0) + Number(system.verified_synthetic || 0);
|
||||
const coverage = Math.round((verified / total) * 100);
|
||||
const entitySummary = system.entity_summary || {};
|
||||
const versionSummary = system.version_summary || {};
|
||||
const topEntities = system.top_entities || [];
|
||||
const backlogPreview = system.backlog_preview || [];
|
||||
return `
|
||||
@@ -617,6 +633,8 @@ function renderSystemCards(items, compact = false) {
|
||||
<span class="tag">阻塞 ${escapeHtml(system.blocked || 0)}</span>
|
||||
<span class="tag">实体 ${escapeHtml(entitySummary.cataloged_entity_total || 0)}</span>
|
||||
<span class="tag">backlog ${escapeHtml(entitySummary.candidate_entity_total || 0)}</span>
|
||||
<span class="tag">latest ${escapeHtml(system.latest_version || "-")}</span>
|
||||
<span class="tag">version ${escapeHtml(system.version_sync_status || "-")}</span>
|
||||
</div>
|
||||
<div class="meter"><span style="--fill:${coverage}%"></span></div>
|
||||
${compact ? "" : `
|
||||
@@ -629,6 +647,10 @@ function renderSystemCards(items, compact = false) {
|
||||
<span class="plan-label">队列与缺口</span>
|
||||
<div class="plan-copy">history complete ${escapeHtml(entitySummary.history_full_complete_count || 0)} · latest green ${escapeHtml(entitySummary.latest_green_count || 0)} · version gap ${escapeHtml(entitySummary.version_gap_entity_count || 0)}</div>
|
||||
</article>
|
||||
<article class="plan-card">
|
||||
<span class="plan-label">版本同步</span>
|
||||
<div class="plan-copy">latest synced ${escapeHtml(versionSummary.latest_version_synced_count || 0)} · source-gap ${escapeHtml(versionSummary.source_gap_count || 0)} · security versions ${escapeHtml(system.security_version_count || 0)}</div>
|
||||
</article>
|
||||
</div>
|
||||
${(topEntities.length || backlogPreview.length) ? `
|
||||
<div class="tag-row" style="margin-top:10px;">
|
||||
@@ -816,6 +838,7 @@ function renderPanel(panelKey, title, meta, iconName, content) {
|
||||
function renderCompletenessPanel(panelKey, compact = false) {
|
||||
const completeness = state.completeness || state.summary?.completeness || {};
|
||||
const entityCoverage = state.entityCompleteness || state.summary?.entity_coverage || completeness.entity_coverage || {};
|
||||
const versionCoverage = state.versionCompleteness || state.summary?.version_coverage || completeness.version_coverage || {};
|
||||
const sourceHealth = state.sourceHealth || completeness.source_health || {};
|
||||
const systems = (state.completeness?.systems || []).map((system) => `
|
||||
<article class="plan-card">
|
||||
@@ -874,14 +897,32 @@ function renderCompletenessPanel(panelKey, compact = false) {
|
||||
<strong>version mapped</strong>
|
||||
<span>${escapeHtml(entityCoverage.version_mapped_count || 0)}</span>
|
||||
</article>
|
||||
<article class="detail-stat">
|
||||
<strong>latest version synced</strong>
|
||||
<span>${escapeHtml(versionCoverage.latest_version_synced_count || 0)}</span>
|
||||
</article>
|
||||
<article class="detail-stat">
|
||||
<strong>version source-gap</strong>
|
||||
<span>${escapeHtml(versionCoverage.source_gap_count || 0)}</span>
|
||||
</article>
|
||||
<article class="detail-stat">
|
||||
<strong>security versions</strong>
|
||||
<span>${escapeHtml(versionCoverage.security_version_total || 0)}</span>
|
||||
</article>
|
||||
<article class="detail-stat">
|
||||
<strong>lab enqueued</strong>
|
||||
<span>${escapeHtml(versionCoverage.lab_enqueued_count || 0)}</span>
|
||||
</article>
|
||||
</div>
|
||||
<div class="plan-grid" style="margin-top:16px;">${systems || `<div class="empty-state">暂无系统完整度数据。</div>`}</div>
|
||||
${compact ? "" : `
|
||||
<div class="detail-actions" style="margin-top:16px;">
|
||||
<a class="button button-secondary" href="/docs/testing-completeness-report.html" target="_blank" rel="noreferrer">${icon("docs")}<span>打开中文报告</span></a>
|
||||
<a class="button button-secondary" href="/docs/entity-catalog-report.html" target="_blank" rel="noreferrer">${icon("docs")}<span>打开实体报告</span></a>
|
||||
<a class="button button-secondary" href="/docs/version-sync-report.html" target="_blank" rel="noreferrer">${icon("docs")}<span>打开版本报告</span></a>
|
||||
<a class="button button-secondary" href="/data/completeness.json" target="_blank" rel="noreferrer">${icon("json")}<span>打开 completeness.json</span></a>
|
||||
<a class="button button-secondary" href="/data/entity-completeness.json" target="_blank" rel="noreferrer">${icon("json")}<span>打开 entity-completeness.json</span></a>
|
||||
<a class="button button-secondary" href="/data/version-completeness.json" target="_blank" rel="noreferrer">${icon("json")}<span>打开 version-completeness.json</span></a>
|
||||
<a class="button button-secondary" href="/data/source-health.json" target="_blank" rel="noreferrer">${icon("json")}<span>打开 source-health.json</span></a>
|
||||
</div>
|
||||
${failures.length ? `<div class="callout" style="margin-top:16px;"><strong>Ingest 未清零</strong><div class="plan-copy">${escapeHtml(failures.join(" | "))}</div></div>` : ""}
|
||||
@@ -1634,7 +1675,7 @@ async function loadData(preserveSelection = true) {
|
||||
renderSyncState("loading", "刷新中", `本地时间 ${new Date().toLocaleTimeString("zh-CN", { hour12: false })}`);
|
||||
|
||||
try {
|
||||
const [summary, runs, systems, entities, advisories, profiles, architecture, completeness, entityCompleteness, sourceHealth, alerts, monitorSummary] = await Promise.all([
|
||||
const [summary, runs, systems, entities, advisories, profiles, architecture, completeness, entityCompleteness, versionCompleteness, sourceHealth, alerts, monitorSummary] = await Promise.all([
|
||||
fetchJson("/summary.json"),
|
||||
fetchJson("/runs.json"),
|
||||
fetchJson("/systems.json"),
|
||||
@@ -1644,6 +1685,7 @@ async function loadData(preserveSelection = true) {
|
||||
fetchJson("/architecture.json"),
|
||||
fetchJson("/data/completeness.json"),
|
||||
fetchJson("/data/entity-completeness.json"),
|
||||
fetchJson("/data/version-completeness.json"),
|
||||
fetchJson("/data/source-health.json"),
|
||||
fetchJson("/data/alerts.json"),
|
||||
fetchJson("/data/monitor-summary.json")
|
||||
@@ -1658,6 +1700,7 @@ async function loadData(preserveSelection = true) {
|
||||
state.architecture = architecture;
|
||||
state.completeness = completeness;
|
||||
state.entityCompleteness = entityCompleteness;
|
||||
state.versionCompleteness = versionCompleteness;
|
||||
state.sourceHealth = sourceHealth;
|
||||
state.alerts = alerts;
|
||||
state.monitorSummary = monitorSummary;
|
||||
|
||||
@@ -1101,6 +1101,12 @@ def _write_dashboard_docs(architecture: Dict[str, Any]) -> None:
|
||||
_safe_read_text(ROOT / "08-threat-intel" / "generated" / "entity-discovery-backlog.md", "entity discovery backlog has not been generated yet."),
|
||||
"工作台内置镜像页:待编目 repo / 插件 / 包 backlog 与等待原因。",
|
||||
),
|
||||
(
|
||||
"version-sync-report.html",
|
||||
"安全相关版本同步报告",
|
||||
_safe_read_text(ROOT / "08-threat-intel" / "generated" / "version-sync-report.md", "version sync report has not been generated yet."),
|
||||
"工作台内置镜像页:安全相关版本历史、source-gap 与版本驱动 lab enqueue 摘要。",
|
||||
),
|
||||
(
|
||||
"coverage-matrix.html",
|
||||
"覆盖矩阵镜像",
|
||||
@@ -1440,12 +1446,22 @@ def render_dashboard(
|
||||
|
||||
for system_id, system in systems.items():
|
||||
entity_summary = entity_summary_map.get(system_id, {})
|
||||
version_summary = version_summary_map.get(system_id, {})
|
||||
root_entity = next((item for item in entities_by_system.get(system_id, []) if item.get("entity_id") == system_id), {})
|
||||
system["entity_summary"] = entity_summary
|
||||
system["version_summary"] = version_summary
|
||||
system["top_entities"] = entity_summary.get("top_entities", [])
|
||||
system["backlog_preview"] = entity_summary.get("backlog_preview", [])
|
||||
system["entity_total"] = entity_summary.get("cataloged_entity_total", 0)
|
||||
system["entity_backlog"] = entity_summary.get("candidate_entity_total", 0)
|
||||
system["entity_type_counts"] = entity_summary.get("entity_type_counts", {})
|
||||
system["latest_version"] = root_entity.get("latest_version") or next(
|
||||
(item.get("latest_version") for item in (version_summary.get("latest_versions") or []) if item.get("latest_version")),
|
||||
"",
|
||||
)
|
||||
system["last_version_synced_at"] = root_entity.get("last_version_synced_at") or ""
|
||||
system["version_sync_status"] = root_entity.get("version_sync_status") or ("source-gap" if version_summary.get("source_gap_count") else "green")
|
||||
system["security_version_count"] = version_summary.get("security_version_count", 0)
|
||||
|
||||
recent_runs = sorted(runs, key=lambda item: item.get("finished_at") or "", reverse=True)[:100]
|
||||
decorated_runs: List[Dict[str, Any]] = []
|
||||
@@ -1511,6 +1527,7 @@ def render_dashboard(
|
||||
"last_fully_green_run": source_health.get("last_fully_green_run"),
|
||||
},
|
||||
"entity_coverage": entity_completeness,
|
||||
"version_coverage": version_completeness,
|
||||
}
|
||||
for item in merged_advisories:
|
||||
status = item.get("verification_status", "triage-manual")
|
||||
@@ -1555,6 +1572,10 @@ def render_dashboard(
|
||||
"candidate_entity_total": entity_completeness.get("candidate_entity_total", 0),
|
||||
"workflow_complete_count": entity_completeness.get("workflow_complete_count", 0),
|
||||
"version_mapped_count": entity_completeness.get("version_mapped_count", 0),
|
||||
"latest_version_synced_count": version_completeness.get("latest_version_synced_count", 0),
|
||||
"version_source_gap_count": version_completeness.get("source_gap_count", 0),
|
||||
"security_version_total": version_completeness.get("security_version_total", 0),
|
||||
"lab_enqueued_count": version_completeness.get("lab_enqueued_count", 0),
|
||||
}
|
||||
|
||||
write_json(DASHBOARD_DIR / "summary.json", summary)
|
||||
@@ -1571,6 +1592,10 @@ def render_dashboard(
|
||||
write_json(DASHBOARD_DIR / "data" / "entity-completeness.json", entity_completeness)
|
||||
write_json(DASHBOARD_DIR / "data" / "entity-discovery-backlog.json", entity_backlog)
|
||||
write_json(DASHBOARD_DIR / "data" / "entity-queues.json", entity_queues)
|
||||
write_json(DASHBOARD_DIR / "data" / "version-completeness.json", version_completeness)
|
||||
write_json(DASHBOARD_DIR / "data" / "version-backlog.json", version_backlog)
|
||||
write_json(DASHBOARD_DIR / "data" / "release-index.json", release_index)
|
||||
write_json(DASHBOARD_DIR / "data" / "lab-enqueue-summary.json", lab_enqueue_summary)
|
||||
_write_testing_completeness_report(completeness)
|
||||
architecture = _build_architecture_data(summary, source_map, repro_map)
|
||||
write_json(DASHBOARD_DIR / "architecture.json", architecture)
|
||||
|
||||
在新工单中引用
屏蔽一个用户