feat(admin): очистка всех сканов — POST /api/admin/purge-scans + UI (NETTOPO_RESET_DB_SECRET)
Made-with: Cursor
This commit is contained in:
@@ -55,6 +55,14 @@
|
||||
<button id="diffBtn">Сравнить</button>
|
||||
<button id="exportDiffBtn">Экспорт diff JSON</button>
|
||||
</div>
|
||||
<details class="admin-purge" style="margin:10px 0;padding:8px 12px;background:#fff7ed;border:1px solid #fed7aa;border-radius:8px;max-width:720px;">
|
||||
<summary style="cursor:pointer;font-weight:600;color:#9a3412;">Админ: начать всё заново — очистить данные сканов в БД</summary>
|
||||
<p class="hint" style="margin:8px 0;">На сервере должен быть задан <code>NETTOPO_RESET_DB_SECRET</code>. Ключ ниже передаётся только в заголовке запроса и нигде не сохраняется.</p>
|
||||
<div class="row" style="flex-wrap:wrap;gap:8px;align-items:center;">
|
||||
<input type="password" id="purgeSecretInput" placeholder="секрет (X-Nettopo-Reset-Key)" style="min-width:260px;" autocomplete="off" />
|
||||
<button type="button" id="purgeDbBtn" style="background:#b91c1c;color:#fff;border:none;padding:6px 12px;border-radius:6px;cursor:pointer;">Удалить все сканы и результаты</button>
|
||||
</div>
|
||||
</details>
|
||||
<div id="status">Ожидание действия. Строка статуса показывает текущую операцию и прогресс скана.</div>
|
||||
|
||||
<div class="panel">
|
||||
@@ -1097,6 +1105,50 @@
|
||||
});
|
||||
refreshDevicesBtn.addEventListener("click", () => loadDeviceTable(scanIdInput.value.trim()));
|
||||
createScanBtn.addEventListener("click", createScan);
|
||||
document.getElementById("purgeDbBtn")?.addEventListener("click", async () => {
|
||||
const inp = document.getElementById("purgeSecretInput");
|
||||
const secret = (inp && inp.value.trim()) || "";
|
||||
if (!secret) {
|
||||
setStatus("Введите секрет (тот же, что NETTOPO_RESET_DB_SECRET на сервере).");
|
||||
return;
|
||||
}
|
||||
if (
|
||||
!confirm(
|
||||
"Удалить ВСЕ задачи скана и связанные данные (хосты, порты, SNMP, LLDP, интерфейсы)? Это необратимо."
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
setStatus("Очистка данных сканов…");
|
||||
try {
|
||||
const res = await fetch("/api/admin/purge-scans", {
|
||||
method: "POST",
|
||||
headers: { "X-Nettopo-Reset-Key": secret },
|
||||
});
|
||||
const text = await res.text();
|
||||
if (!res.ok) {
|
||||
setStatus(`Ошибка очистки: ${res.status} ${text}`);
|
||||
return;
|
||||
}
|
||||
scanIdInput.value = "";
|
||||
fromScanIdInput.value = "";
|
||||
toScanIdInput.value = "";
|
||||
clearDeviceDetailPanel();
|
||||
deviceRowsCache = [];
|
||||
deviceTableBody.innerHTML =
|
||||
'<tr><td colspan="5" style="padding:10px;color:#64748b;">Нет scan_id. Загрузите после нового скана.</td></tr>';
|
||||
lastTopology = null;
|
||||
lastDiff = null;
|
||||
lastHighlight = null;
|
||||
clearSVG();
|
||||
edgeListPanel.style.display = "none";
|
||||
diffBox.textContent = "";
|
||||
await loadScanOptions();
|
||||
setStatus("Данные сканов удалены. Создайте новый scan или выберите из списка.");
|
||||
} catch (e) {
|
||||
setStatus(`Ошибка: ${e.message}`);
|
||||
}
|
||||
});
|
||||
watchScanBtn.addEventListener("click", watchScan);
|
||||
scanSelect.addEventListener("change", () => {
|
||||
if (scanSelect.value) scanIdInput.value = scanSelect.value;
|
||||
|
||||
Reference in New Issue
Block a user