From 12bc9d8ab696ab39b65f6696f61632ada5476c5f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=85=AC=E6=98=8E?=
<83812544+Ed1s0nZ@users.noreply.github.com>
Date: Tue, 26 May 2026 18:49:01 +0800
Subject: [PATCH] Add files via upload
---
web/static/css/style.css | 5 +++++
web/static/js/projects.js | 27 +++++++++++++++++++++++----
2 files changed, 28 insertions(+), 4 deletions(-)
diff --git a/web/static/css/style.css b/web/static/css/style.css
index c10635e2..91051e89 100644
--- a/web/static/css/style.css
+++ b/web/static/css/style.css
@@ -21359,6 +21359,11 @@ button.chat-files-dropdown-item:hover:not(:disabled) {
color: #b45309;
background: #fffbeb;
}
+.projects-action-btn--restore:hover {
+ border-color: #86efac;
+ color: #15803d;
+ background: #f0fdf4;
+}
.projects-action-btn--danger {
color: #dc2626;
border-color: #fecaca;
diff --git a/web/static/js/projects.js b/web/static/js/projects.js
index c1c95b18..ce1c756f 100644
--- a/web/static/js/projects.js
+++ b/web/static/js/projects.js
@@ -286,11 +286,15 @@ function formatConfidenceBadge(confidence) {
return `${escapeHtml(label)}`;
}
-function renderProjectFactActions(keyEsc, idEsc) {
+function renderProjectFactActions(keyEsc, idEsc, confidence) {
+ const isDeprecated = (confidence || '').toLowerCase() === 'deprecated';
+ const toggleBtn = isDeprecated
+ ? ``
+ : ``;
return `
-
+ ${toggleBtn}
`;
}
@@ -434,7 +438,7 @@ async function loadProjectFacts() {
${formatFactBodyBadge(f)} |
${formatConfidenceBadge(f.confidence)} |
${formatProjectTime(f.updated_at, f.created_at)} |
- ${renderProjectFactActions(keyEsc, idEsc)} |
+ ${renderProjectFactActions(keyEsc, idEsc, f.confidence)} |
`;
}).join('');
refreshProjectHeaderStats();
@@ -507,7 +511,7 @@ function closeFactDetailModal() {
}
async function deprecateProjectFactByKey(factKey) {
- if (!confirm(`将事实 ${factKey} 标记为 deprecated?`)) return;
+ if (!confirm(`将事实 ${factKey} 标记为已废弃?`)) return;
const res = await apiFetch(`/api/projects/${currentProjectId}/facts/deprecate`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
@@ -517,6 +521,20 @@ async function deprecateProjectFactByKey(factKey) {
loadProjectFacts();
}
+async function restoreProjectFactByKey(factKey) {
+ if (!confirm(`恢复事实 ${factKey}?将重新进入黑板索引(状态:待确认)。`)) return;
+ const res = await apiFetch(`/api/projects/${currentProjectId}/facts/restore`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ fact_key: factKey, confidence: 'tentative' }),
+ });
+ if (!res.ok) {
+ const err = await res.json().catch(() => ({}));
+ return alert(err.error || '操作失败');
+ }
+ loadProjectFacts();
+}
+
function openVulnerabilitiesForProject(projectId) {
const pid = projectId || currentProjectId;
if (!pid) return;
@@ -1131,6 +1149,7 @@ window.viewProjectFactBody = viewProjectFactBody;
window.insertFactBodyTemplate = insertFactBodyTemplate;
window.updateFactFormHints = updateFactFormHints;
window.deprecateProjectFactByKey = deprecateProjectFactByKey;
+window.restoreProjectFactByKey = restoreProjectFactByKey;
window.openVulnerabilitiesForProject = openVulnerabilitiesForProject;
window.openVulnerabilityDetail = openVulnerabilityDetail;
window.filterProjectsList = filterProjectsList;