mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-05-26 09:17:55 +02:00
Add files via upload
This commit is contained in:
+152
-77
@@ -46,6 +46,7 @@ const getVulnerabilityPageSize = () => {
|
||||
|
||||
let currentVulnerabilityId = null;
|
||||
let vulnerabilityFilters = {
|
||||
q: '',
|
||||
id: '',
|
||||
conversation_id: '',
|
||||
task_id: '',
|
||||
@@ -65,11 +66,14 @@ const VULN_STAT_SEVERITIES = ['critical', 'high', 'medium', 'low', 'info'];
|
||||
let vulnerabilityStatCardsBound = false;
|
||||
let vulnerabilityFilterPanelBound = false;
|
||||
let vulnerabilityFilterOptionsCache = null;
|
||||
const VULNERABILITY_ADVANCED_OPEN_KEY = 'vulnerabilityAdvancedFiltersOpen';
|
||||
let vulnerabilityMoreFiltersPopoverOpen = false;
|
||||
let vulnerabilityFilterDebounceTimer = null;
|
||||
const VULNERABILITY_FILTER_DEBOUNCE_MS = 400;
|
||||
const VULNERABILITY_DATALIST_MAX = 8;
|
||||
const VULNERABILITY_DATALIST_MIN_QUERY = 2;
|
||||
|
||||
const VULN_FILTER_CHIP_FIELDS = [
|
||||
{ key: 'q', labelKey: 'vulnerabilityPage.searchKeywordShort' },
|
||||
{ key: 'id', labelKey: 'vulnerabilityPage.vulnId' },
|
||||
{ key: 'status', labelKey: null, format: 'status' },
|
||||
{ key: 'severity', labelKey: null, format: 'severity' },
|
||||
@@ -94,10 +98,12 @@ function syncVulnerabilityFiltersFromLocationHash() {
|
||||
const st = (params.get('status') || '').trim();
|
||||
const convTag = (params.get('conversation_tag') || '').trim();
|
||||
const taskTag = (params.get('task_tag') || '').trim();
|
||||
if (!vid && !cid && !tid && !sev && !st && !convTag && !taskTag) {
|
||||
const q = (params.get('q') || params.get('search') || '').trim();
|
||||
if (!vid && !cid && !tid && !sev && !st && !convTag && !taskTag && !q) {
|
||||
return;
|
||||
}
|
||||
|
||||
vulnerabilityFilters.q = '';
|
||||
vulnerabilityFilters.id = '';
|
||||
vulnerabilityFilters.conversation_id = '';
|
||||
vulnerabilityFilters.task_id = '';
|
||||
@@ -105,14 +111,16 @@ function syncVulnerabilityFiltersFromLocationHash() {
|
||||
vulnerabilityFilters.task_tag = '';
|
||||
vulnerabilityFilters.severity = '';
|
||||
vulnerabilityFilters.status = '';
|
||||
const idEl = document.getElementById('vulnerability-id-filter');
|
||||
const searchEl = document.getElementById('vulnerability-search-filter');
|
||||
const exactIdEl = document.getElementById('vulnerability-exact-id-filter');
|
||||
const convEl = document.getElementById('vulnerability-conversation-filter');
|
||||
const taskEl = document.getElementById('vulnerability-task-filter');
|
||||
const convTagEl = document.getElementById('vulnerability-conversation-tag-filter');
|
||||
const taskTagEl = document.getElementById('vulnerability-task-tag-filter');
|
||||
const sevEl = document.getElementById('vulnerability-severity-filter');
|
||||
const stEl = document.getElementById('vulnerability-status-filter');
|
||||
if (idEl) idEl.value = '';
|
||||
if (searchEl) searchEl.value = '';
|
||||
if (exactIdEl) exactIdEl.value = '';
|
||||
if (convEl) convEl.value = '';
|
||||
if (taskEl) taskEl.value = '';
|
||||
if (convTagEl) convTagEl.value = '';
|
||||
@@ -120,9 +128,13 @@ function syncVulnerabilityFiltersFromLocationHash() {
|
||||
if (sevEl) sevEl.value = '';
|
||||
if (stEl) stEl.value = '';
|
||||
|
||||
if (q) {
|
||||
vulnerabilityFilters.q = q;
|
||||
if (searchEl) searchEl.value = q;
|
||||
}
|
||||
if (vid) {
|
||||
vulnerabilityFilters.id = vid;
|
||||
if (idEl) idEl.value = vid;
|
||||
if (exactIdEl) exactIdEl.value = vid;
|
||||
}
|
||||
if (cid) {
|
||||
vulnerabilityFilters.conversation_id = cid;
|
||||
@@ -149,9 +161,6 @@ function syncVulnerabilityFiltersFromLocationHash() {
|
||||
if (stEl) stEl.value = st;
|
||||
}
|
||||
vulnerabilityPagination.currentPage = 1;
|
||||
if (hasVulnerabilityAdvancedFiltersActive()) {
|
||||
setVulnerabilityAdvancedFiltersOpen(true, false);
|
||||
}
|
||||
syncVulnerabilityStatCardActiveState();
|
||||
updateVulnerabilityFilterPanelState();
|
||||
renderVulnerabilityFilterChips();
|
||||
@@ -213,7 +222,8 @@ function applyVulnerabilitySeverityFilter(severity) {
|
||||
}
|
||||
|
||||
function readVulnerabilityFiltersFromForm() {
|
||||
vulnerabilityFilters.id = (document.getElementById('vulnerability-id-filter')?.value || '').trim();
|
||||
vulnerabilityFilters.q = (document.getElementById('vulnerability-search-filter')?.value || '').trim();
|
||||
vulnerabilityFilters.id = (document.getElementById('vulnerability-exact-id-filter')?.value || '').trim();
|
||||
vulnerabilityFilters.conversation_id = (document.getElementById('vulnerability-conversation-filter')?.value || '').trim();
|
||||
vulnerabilityFilters.task_id = (document.getElementById('vulnerability-task-filter')?.value || '').trim();
|
||||
vulnerabilityFilters.conversation_tag = (document.getElementById('vulnerability-conversation-tag-filter')?.value || '').trim();
|
||||
@@ -225,13 +235,13 @@ function readVulnerabilityFiltersFromForm() {
|
||||
|
||||
function hasVulnerabilityAdvancedFiltersActive() {
|
||||
const f = vulnerabilityFilters;
|
||||
return Boolean(f.conversation_id || f.task_id || f.conversation_tag || f.task_tag);
|
||||
return Boolean(f.id || f.conversation_id || f.task_id || f.conversation_tag || f.task_tag);
|
||||
}
|
||||
|
||||
function hasAnyVulnerabilityFilterActive() {
|
||||
const f = vulnerabilityFilters;
|
||||
return Boolean(
|
||||
f.id || f.conversation_id || f.task_id || f.conversation_tag || f.task_tag || f.severity || f.status
|
||||
f.q || f.id || f.conversation_id || f.task_id || f.conversation_tag || f.task_tag || f.severity || f.status
|
||||
);
|
||||
}
|
||||
|
||||
@@ -253,6 +263,7 @@ function updateVulnerabilityLocationHashFromFilters() {
|
||||
const params = new URLSearchParams(hashParts.length >= 2 ? hashParts.slice(1).join('?') : '');
|
||||
const f = vulnerabilityFilters;
|
||||
const pairs = [
|
||||
['q', f.q],
|
||||
['id', f.id],
|
||||
['conversation_id', f.conversation_id],
|
||||
['task_id', f.task_id],
|
||||
@@ -279,17 +290,82 @@ function updateVulnerabilityLocationHashFromFilters() {
|
||||
}
|
||||
}
|
||||
|
||||
function toggleVulnerabilityAdvancedFilters(ev) {
|
||||
function scheduleVulnerabilityFilterApply(immediate) {
|
||||
if (vulnerabilityFilterDebounceTimer) {
|
||||
clearTimeout(vulnerabilityFilterDebounceTimer);
|
||||
vulnerabilityFilterDebounceTimer = null;
|
||||
}
|
||||
if (immediate) {
|
||||
applyVulnerabilityFilters();
|
||||
return;
|
||||
}
|
||||
vulnerabilityFilterDebounceTimer = setTimeout(function () {
|
||||
vulnerabilityFilterDebounceTimer = null;
|
||||
applyVulnerabilityFilters();
|
||||
}, VULNERABILITY_FILTER_DEBOUNCE_MS);
|
||||
}
|
||||
|
||||
function syncVulnerabilityAdvancedFieldsFromFilters() {
|
||||
const map = {
|
||||
id: 'vulnerability-exact-id-filter',
|
||||
conversation_id: 'vulnerability-conversation-filter',
|
||||
task_id: 'vulnerability-task-filter',
|
||||
conversation_tag: 'vulnerability-conversation-tag-filter',
|
||||
task_tag: 'vulnerability-task-tag-filter'
|
||||
};
|
||||
Object.keys(map).forEach(function (key) {
|
||||
const el = document.getElementById(map[key]);
|
||||
if (el) el.value = vulnerabilityFilters[key] || '';
|
||||
});
|
||||
}
|
||||
|
||||
function setVulnerabilityMoreFiltersPopoverOpen(open) {
|
||||
const btn = document.getElementById('vulnerability-more-filters-btn');
|
||||
const popover = document.getElementById('vulnerability-more-filters-popover');
|
||||
if (!btn || !popover) return;
|
||||
vulnerabilityMoreFiltersPopoverOpen = open;
|
||||
btn.setAttribute('aria-expanded', open ? 'true' : 'false');
|
||||
btn.classList.toggle('is-active', open);
|
||||
popover.hidden = !open;
|
||||
}
|
||||
|
||||
function toggleVulnerabilityMoreFiltersPopover(ev) {
|
||||
if (ev) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
}
|
||||
const toggleBtn = document.getElementById('vulnerability-advanced-toggle');
|
||||
if (!toggleBtn) return;
|
||||
const expanded = toggleBtn.getAttribute('aria-expanded') === 'true';
|
||||
setVulnerabilityAdvancedFiltersOpen(!expanded, true);
|
||||
const opening = !vulnerabilityMoreFiltersPopoverOpen;
|
||||
if (opening) {
|
||||
readVulnerabilityFiltersFromForm();
|
||||
syncVulnerabilityAdvancedFieldsFromFilters();
|
||||
}
|
||||
setVulnerabilityMoreFiltersPopoverOpen(opening);
|
||||
}
|
||||
|
||||
function closeVulnerabilityMoreFiltersPopover(revertDraft) {
|
||||
if (revertDraft) syncVulnerabilityAdvancedFieldsFromFilters();
|
||||
setVulnerabilityMoreFiltersPopoverOpen(false);
|
||||
}
|
||||
|
||||
function clearVulnerabilityAdvancedFilterFields() {
|
||||
['vulnerability-exact-id-filter', 'vulnerability-conversation-filter', 'vulnerability-task-filter',
|
||||
'vulnerability-conversation-tag-filter', 'vulnerability-task-tag-filter'].forEach(function (id) {
|
||||
const el = document.getElementById(id);
|
||||
if (el) el.value = '';
|
||||
});
|
||||
}
|
||||
|
||||
function applyVulnerabilityMoreFiltersFromPopover() {
|
||||
closeVulnerabilityMoreFiltersPopover(false);
|
||||
scheduleVulnerabilityFilterApply(true);
|
||||
}
|
||||
|
||||
function onVulnerabilityFilterDocumentPointerDown(ev) {
|
||||
if (!vulnerabilityMoreFiltersPopoverOpen) return;
|
||||
const anchor = document.querySelector('.vulnerability-more-filters-anchor');
|
||||
if (anchor && anchor.contains(ev.target)) return;
|
||||
closeVulnerabilityMoreFiltersPopover(true);
|
||||
}
|
||||
window.toggleVulnerabilityAdvancedFilters = toggleVulnerabilityAdvancedFilters;
|
||||
|
||||
function initVulnerabilityFilterPanel() {
|
||||
const panel = document.getElementById('vulnerability-filter-panel');
|
||||
@@ -301,55 +377,69 @@ function initVulnerabilityFilterPanel() {
|
||||
}
|
||||
vulnerabilityFilterPanelBound = true;
|
||||
|
||||
let savedOpen = false;
|
||||
try {
|
||||
savedOpen = localStorage.getItem(VULNERABILITY_ADVANCED_OPEN_KEY) === 'true';
|
||||
} catch (e) { /* ignore */ }
|
||||
setVulnerabilityAdvancedFiltersOpen(savedOpen, false);
|
||||
|
||||
const stEl = document.getElementById('vulnerability-status-filter');
|
||||
if (stEl) stEl.addEventListener('change', applyVulnerabilityFilters);
|
||||
if (stEl) stEl.addEventListener('change', function () { scheduleVulnerabilityFilterApply(true); });
|
||||
|
||||
const textIds = [
|
||||
'vulnerability-id-filter',
|
||||
const searchEl = document.getElementById('vulnerability-search-filter');
|
||||
if (searchEl) {
|
||||
searchEl.addEventListener('input', function () { scheduleVulnerabilityFilterApply(false); });
|
||||
searchEl.addEventListener('keydown', function (ev) {
|
||||
if (ev.key === 'Enter') {
|
||||
ev.preventDefault();
|
||||
scheduleVulnerabilityFilterApply(true);
|
||||
}
|
||||
});
|
||||
searchEl.addEventListener('search', function () {
|
||||
if (searchEl.value === '') scheduleVulnerabilityFilterApply(true);
|
||||
});
|
||||
}
|
||||
|
||||
const moreBtn = document.getElementById('vulnerability-more-filters-btn');
|
||||
if (moreBtn) moreBtn.addEventListener('click', toggleVulnerabilityMoreFiltersPopover);
|
||||
|
||||
const applyBtn = document.getElementById('vulnerability-more-filters-apply');
|
||||
if (applyBtn) applyBtn.addEventListener('click', applyVulnerabilityMoreFiltersFromPopover);
|
||||
|
||||
const resetBtn = document.getElementById('vulnerability-more-filters-reset');
|
||||
if (resetBtn) {
|
||||
resetBtn.addEventListener('click', function () {
|
||||
clearVulnerabilityAdvancedFilterFields();
|
||||
applyVulnerabilityMoreFiltersFromPopover();
|
||||
});
|
||||
}
|
||||
|
||||
const advancedTextIds = [
|
||||
'vulnerability-exact-id-filter',
|
||||
'vulnerability-conversation-filter',
|
||||
'vulnerability-task-filter',
|
||||
'vulnerability-conversation-tag-filter',
|
||||
'vulnerability-task-tag-filter'
|
||||
];
|
||||
textIds.forEach(function (id) {
|
||||
advancedTextIds.forEach(function (id) {
|
||||
const el = document.getElementById(id);
|
||||
if (!el) return;
|
||||
el.addEventListener('keydown', function (ev) {
|
||||
if (ev.key === 'Enter') {
|
||||
ev.preventDefault();
|
||||
applyVulnerabilityFilters();
|
||||
applyVulnerabilityMoreFiltersFromPopover();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener('mousedown', onVulnerabilityFilterDocumentPointerDown);
|
||||
document.addEventListener('keydown', function (ev) {
|
||||
if (ev.key === 'Escape' && vulnerabilityMoreFiltersPopoverOpen) {
|
||||
closeVulnerabilityMoreFiltersPopover(true);
|
||||
}
|
||||
});
|
||||
|
||||
bindVulnerabilityFilterTypeaheads();
|
||||
}
|
||||
|
||||
function setVulnerabilityAdvancedFiltersOpen(open, persist) {
|
||||
const toggleBtn = document.getElementById('vulnerability-advanced-toggle');
|
||||
const advanced = document.getElementById('vulnerability-advanced-filters');
|
||||
const wrap = document.querySelector('#vulnerability-filter-panel .vulnerability-filter-advanced-wrap');
|
||||
if (!toggleBtn || !advanced) return;
|
||||
toggleBtn.setAttribute('aria-expanded', open ? 'true' : 'false');
|
||||
advanced.hidden = !open;
|
||||
advanced.classList.toggle('is-open', open);
|
||||
if (wrap) wrap.classList.toggle('is-expanded', open);
|
||||
if (persist) {
|
||||
try {
|
||||
localStorage.setItem(VULNERABILITY_ADVANCED_OPEN_KEY, open ? 'true' : 'false');
|
||||
} catch (e) { /* ignore */ }
|
||||
}
|
||||
}
|
||||
|
||||
function countVulnerabilityAdvancedFiltersActive() {
|
||||
const f = vulnerabilityFilters;
|
||||
let n = 0;
|
||||
if (f.id) n++;
|
||||
if (f.conversation_id) n++;
|
||||
if (f.task_id) n++;
|
||||
if (f.conversation_tag) n++;
|
||||
@@ -379,6 +469,8 @@ function updateVulnerabilityFilterPanelState() {
|
||||
readVulnerabilityFiltersFromForm();
|
||||
panel.classList.toggle('is-filtered', hasAnyVulnerabilityFilterActive());
|
||||
updateVulnerabilityAdvancedBadge();
|
||||
const clearBtn = document.getElementById('vulnerability-filter-clear-btn');
|
||||
if (clearBtn) clearBtn.hidden = !hasAnyVulnerabilityFilterActive();
|
||||
}
|
||||
|
||||
function formatVulnerabilityFilterChipValue(key, value) {
|
||||
@@ -431,7 +523,8 @@ function renderVulnerabilityFilterChips() {
|
||||
|
||||
function removeVulnerabilityFilterByKey(key) {
|
||||
const map = {
|
||||
id: 'vulnerability-id-filter',
|
||||
q: 'vulnerability-search-filter',
|
||||
id: 'vulnerability-exact-id-filter',
|
||||
conversation_id: 'vulnerability-conversation-filter',
|
||||
task_id: 'vulnerability-task-filter',
|
||||
conversation_tag: 'vulnerability-conversation-tag-filter',
|
||||
@@ -609,13 +702,7 @@ async function loadVulnerabilityStats() {
|
||||
throw new Error('apiFetch未定义');
|
||||
}
|
||||
|
||||
const params = new URLSearchParams();
|
||||
if (vulnerabilityFilters.conversation_id) {
|
||||
params.append('conversation_id', vulnerabilityFilters.conversation_id);
|
||||
}
|
||||
if (vulnerabilityFilters.task_id) {
|
||||
params.append('task_id', vulnerabilityFilters.task_id);
|
||||
}
|
||||
const params = buildVulnerabilityFilterParams();
|
||||
|
||||
const response = await apiFetch(`/api/vulnerabilities/stats?${params.toString()}`);
|
||||
if (!response.ok) {
|
||||
@@ -689,31 +776,9 @@ async function loadVulnerabilities(page = null) {
|
||||
vulnerabilityPagination.currentPage = page;
|
||||
}
|
||||
|
||||
const params = new URLSearchParams();
|
||||
const params = buildVulnerabilityFilterParams();
|
||||
params.append('page', vulnerabilityPagination.currentPage.toString());
|
||||
params.append('limit', vulnerabilityPagination.pageSize.toString());
|
||||
|
||||
if (vulnerabilityFilters.id) {
|
||||
params.append('id', vulnerabilityFilters.id);
|
||||
}
|
||||
if (vulnerabilityFilters.conversation_id) {
|
||||
params.append('conversation_id', vulnerabilityFilters.conversation_id);
|
||||
}
|
||||
if (vulnerabilityFilters.task_id) {
|
||||
params.append('task_id', vulnerabilityFilters.task_id);
|
||||
}
|
||||
if (vulnerabilityFilters.conversation_tag) {
|
||||
params.append('conversation_tag', vulnerabilityFilters.conversation_tag);
|
||||
}
|
||||
if (vulnerabilityFilters.task_tag) {
|
||||
params.append('task_tag', vulnerabilityFilters.task_tag);
|
||||
}
|
||||
if (vulnerabilityFilters.severity) {
|
||||
params.append('severity', vulnerabilityFilters.severity);
|
||||
}
|
||||
if (vulnerabilityFilters.status) {
|
||||
params.append('status', vulnerabilityFilters.status);
|
||||
}
|
||||
|
||||
const response = await apiFetch(`/api/vulnerabilities?${params.toString()}`);
|
||||
if (!response.ok) {
|
||||
@@ -1090,8 +1155,14 @@ function filterVulnerabilities() {
|
||||
|
||||
// 清除筛选
|
||||
function clearVulnerabilityFilters() {
|
||||
closeVulnerabilityMoreFiltersPopover(false);
|
||||
if (vulnerabilityFilterDebounceTimer) {
|
||||
clearTimeout(vulnerabilityFilterDebounceTimer);
|
||||
vulnerabilityFilterDebounceTimer = null;
|
||||
}
|
||||
const fields = [
|
||||
'vulnerability-id-filter',
|
||||
'vulnerability-search-filter',
|
||||
'vulnerability-exact-id-filter',
|
||||
'vulnerability-conversation-filter',
|
||||
'vulnerability-task-filter',
|
||||
'vulnerability-conversation-tag-filter',
|
||||
@@ -1105,6 +1176,7 @@ function clearVulnerabilityFilters() {
|
||||
});
|
||||
|
||||
vulnerabilityFilters = {
|
||||
q: '',
|
||||
id: '',
|
||||
conversation_id: '',
|
||||
task_id: '',
|
||||
@@ -1277,8 +1349,11 @@ function formatVulnerabilityAsMarkdown(vuln) {
|
||||
|
||||
function buildVulnerabilityFilterParams() {
|
||||
const params = new URLSearchParams();
|
||||
if (vulnerabilityFilters.q) {
|
||||
params.append('q', vulnerabilityFilters.q);
|
||||
}
|
||||
const keys = ['id', 'conversation_id', 'task_id', 'conversation_tag', 'task_tag', 'severity', 'status'];
|
||||
keys.forEach((k) => {
|
||||
keys.forEach(function (k) {
|
||||
if (vulnerabilityFilters[k]) {
|
||||
params.append(k, vulnerabilityFilters[k]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user