Files
warpbox/static/js/admin/activity.js

105 lines
4.1 KiB
JavaScript

(() => {
const menuController = window.WarpBoxUI?.bindMenuBar?.() || { close() {} };
const dataNode = document.getElementById("activity-data");
const body = document.getElementById("activity-body");
const searchInput = document.getElementById("activity-search");
const severityFilter = document.getElementById("activity-severity");
const kindFilter = document.getElementById("activity-kind");
const statusLeft = document.getElementById("activity-status-left");
const toast = document.getElementById("toast");
if (!dataNode || !body || !searchInput) return;
const events = parseData();
function parseData() {
try {
return JSON.parse(dataNode.textContent || "[]");
} catch (_) {
return [];
}
}
function showToast(message, type = "info", duration = 1800) {
window.WarpBoxUI?.toast?.(message, type, { target: toast, duration });
}
function renderKindFilter() {
const kinds = new Set(events.map((event) => event.kind || "unknown"));
Array.from(kinds).sort().forEach((kind) => {
const option = document.createElement("option");
option.value = kind;
option.textContent = kind;
kindFilter.appendChild(option);
});
}
function createdLabel(value) {
const parsed = new Date(value);
if (Number.isNaN(parsed.getTime())) return "-";
return parsed.toISOString().replace("T", " ").slice(0, 16) + " UTC";
}
function filtered() {
const query = searchInput.value.trim().toLowerCase();
const severity = severityFilter.value;
const kind = kindFilter.value;
return events.filter((event) => {
const haystack = [event.kind, event.message, event.ip, event.path, event.method].join(" ").toLowerCase();
const matchesQuery = !query || haystack.includes(query);
const matchesSeverity = severity === "all" || event.severity === severity;
const matchesKind = kind === "all" || event.kind === kind;
return matchesQuery && matchesSeverity && matchesKind;
});
}
function render() {
const rows = filtered();
body.innerHTML = "";
rows.forEach((event) => {
const row = document.createElement("tr");
row.innerHTML = `
<td>${createdLabel(event.created_at)}</td>
<td>${escapeHtml(event.kind || "-")}</td>
<td>${escapeHtml(event.severity || "-")}</td>
<td>${escapeHtml(event.ip || "-")}</td>
<td>${escapeHtml(event.method || "-")}</td>
<td title="${escapeHtml(event.path || "-")}">${escapeHtml(event.path || "-")}</td>
<td title="${escapeHtml(event.message || "-")}">${escapeHtml(event.message || "-")}</td>
`;
body.appendChild(row);
});
statusLeft.textContent = `${rows.length} activity event(s) visible`;
}
function escapeHtml(value) {
return window.WarpBoxUI?.htmlEscape?.(value) || String(value ?? "");
}
[searchInput, severityFilter, kindFilter].forEach((element) => {
element.addEventListener(element.tagName === "INPUT" ? "input" : "change", render);
});
document.querySelectorAll("[data-command]").forEach((button) => {
button.addEventListener("click", () => {
menuController.close();
if (button.dataset.command === "refresh") {
window.location.reload();
return;
}
if (button.dataset.command === "export") {
const blob = new Blob([JSON.stringify(filtered(), null, 2)], { type: "application/json;charset=utf-8" });
const url = URL.createObjectURL(blob);
const anchor = document.createElement("a");
anchor.href = url;
anchor.download = `warpbox-activity-${new Date().toISOString().replaceAll(":", "-")}.json`;
anchor.click();
URL.revokeObjectURL(url);
showToast("Visible activity exported");
}
});
});
renderKindFilter();
render();
})();