202 lines
8.9 KiB
JavaScript
202 lines
8.9 KiB
JavaScript
(() => {
|
|
const menuController = window.WarpBoxUI?.bindMenuBar?.() || {
|
|
close() {
|
|
document.querySelectorAll(".menu-item.is-open").forEach((item) => {
|
|
item.classList.remove("is-open");
|
|
item.querySelector(".menu-button")?.setAttribute("aria-expanded", "false");
|
|
});
|
|
}
|
|
};
|
|
const toast = document.getElementById("toast");
|
|
const statusText = document.getElementById("statusText");
|
|
const modal = document.querySelector("[data-alert-modal]");
|
|
const backdrop = document.querySelector("[data-modal-backdrop]");
|
|
const modalTitle = document.getElementById("modalTitle");
|
|
const modalMeta = document.getElementById("modalMeta");
|
|
const alertCountValue = document.getElementById("alertCountValue");
|
|
const alertStatNote = document.getElementById("alertStatNote");
|
|
const alertsCard = document.getElementById("alertsCard");
|
|
const topAlertChip = document.getElementById("topAlertChip");
|
|
const topTaskbar = document.querySelector(".admin-taskbar");
|
|
|
|
if (!statusText || !alertsCard || !topAlertChip) return;
|
|
|
|
function showToast(message, type = "info") {
|
|
if (window.WarpBoxUI) {
|
|
window.WarpBoxUI.toast(message, type, { target: toast });
|
|
return;
|
|
}
|
|
if (!toast) return;
|
|
toast.textContent = message;
|
|
toast.classList.add("is-visible");
|
|
window.clearTimeout(showToast.timer);
|
|
showToast.timer = window.setTimeout(() => toast.classList.remove("is-visible"), 2600);
|
|
}
|
|
|
|
function setStatus(message) {
|
|
statusText.textContent = message;
|
|
}
|
|
|
|
function openModal(title, meta) {
|
|
if (!modal || !backdrop || !modalTitle || !modalMeta) return;
|
|
modalTitle.textContent = title;
|
|
modalMeta.textContent = meta;
|
|
modal.classList.add("is-visible");
|
|
modal.setAttribute("aria-hidden", "false");
|
|
backdrop.classList.add("is-visible");
|
|
}
|
|
|
|
function closeModal() {
|
|
modal?.classList.remove("is-visible");
|
|
modal?.setAttribute("aria-hidden", "true");
|
|
backdrop?.classList.remove("is-visible");
|
|
}
|
|
|
|
function visibleAlertRows() {
|
|
return Array.from(document.querySelectorAll(".alert-row")).filter((row) => !row.classList.contains("is-dismissed"));
|
|
}
|
|
|
|
function updateStickyHeader() {
|
|
topTaskbar?.classList.toggle("is-scrolled", window.scrollY > 4);
|
|
}
|
|
|
|
function updateAlertSummary() {
|
|
const rows = visibleAlertRows();
|
|
const counts = rows.reduce((acc, row) => {
|
|
const severity = row.dataset.severity || "low";
|
|
acc[severity] = (acc[severity] || 0) + 1;
|
|
return acc;
|
|
}, { high: 0, medium: 0, low: 0 });
|
|
const score = counts.high * 5 + counts.medium * 2 + counts.low;
|
|
const total = rows.length;
|
|
const stateClass = counts.high > 0 || score >= 12 ? "is-danger" : counts.medium >= 2 || score >= 5 ? "is-warning" : total > 0 ? "is-info" : "is-ok";
|
|
|
|
alertsCard.classList.remove("is-ok", "is-info", "is-warning", "is-danger");
|
|
alertsCard.classList.add(stateClass);
|
|
topAlertChip.classList.remove("is-ok", "is-info", "is-warning", "is-danger");
|
|
topAlertChip.classList.add(stateClass);
|
|
if (alertCountValue) alertCountValue.textContent = String(total);
|
|
topAlertChip.textContent = total === 0 ? "OK no alerts" : `! ${total} alerts`;
|
|
if (alertStatNote) {
|
|
alertStatNote.innerHTML = total === 0
|
|
? '<span class="stat-note-pill">all clear</span>'
|
|
: `<span class="stat-note-pill">${counts.high} high</span><span class="stat-note-pill">${counts.medium} medium</span><span class="stat-note-pill">${counts.low} low</span>`;
|
|
}
|
|
}
|
|
|
|
function scrollToSection(id) {
|
|
const target = document.getElementById(id);
|
|
if (!target) return;
|
|
target.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
setStatus(`Focused ${id.replace("-", " ")}`);
|
|
}
|
|
|
|
const commandMessages = {
|
|
refresh: "CURRENTLY_MOCKED_LEAVE_AS_IS: dashboard refresh would re-fetch dashboard data.",
|
|
"dashboard-snapshot": "CURRENTLY_MOCKED_LEAVE_AS_IS: dashboard snapshot export would start here.",
|
|
logout: "CURRENTLY_MOCKED_LEAVE_AS_IS: logout would submit to the account logout route.",
|
|
"compact-mode": "Toggled compact density.",
|
|
"show-all-boxes": "TO-DO: navigate to the admin boxes view when that page exists.",
|
|
"show-all-alerts": "TO-DO: navigate to /admin/alerts.",
|
|
"export-boxes": "CURRENTLY_MOCKED_LEAVE_AS_IS: boxes CSV export would be requested.",
|
|
"export-alerts": "CURRENTLY_MOCKED_LEAVE_AS_IS: alerts JSON export would be requested.",
|
|
"cleanup-dry-run": "CURRENTLY_MOCKED_LEAVE_AS_IS: cleanup dry run would calculate affected boxes without deleting.",
|
|
"dismiss-low-alerts": "Closed visible low-severity alerts in this mock.",
|
|
"config-snapshot": "CURRENTLY_MOCKED_LEAVE_AS_IS: config snapshot would summarize runtime settings and sources.",
|
|
"support-summary": "CURRENTLY_MOCKED_LEAVE_AS_IS: support summary would collect safe diagnostic information.",
|
|
"thumbnail-rebuild": "CURRENTLY_MOCKED_LEAVE_AS_IS: thumbnail rebuild would enqueue preview regeneration.",
|
|
"open-users": "TO-DO: navigate to the admin users view when that page exists.",
|
|
"open-settings": "TO-DO: navigate to the admin settings view when that page exists.",
|
|
"alerts-help": "Alerts use title, description, severity, metadata JSON, trace identifier, and unique numeric code.",
|
|
shortcuts: "Shortcuts: F5 refresh, Alt+A alerts, Alt+B boxes, Alt+R activity, Esc close menus/modal.",
|
|
about: "WarpBox dashboard mock v5, single-window Win98 account dashboard."
|
|
};
|
|
|
|
function runCommand(command) {
|
|
if (command === "compact-mode") document.body.classList.toggle("is-compact");
|
|
if (command === "dismiss-low-alerts") {
|
|
document.querySelectorAll('.alert-row[data-severity="low"]').forEach((row) => row.classList.add("is-dismissed"));
|
|
updateAlertSummary();
|
|
}
|
|
if (command === "show-all-boxes") window.location.hash = "recent-boxes";
|
|
if (command === "show-all-alerts") window.location.hash = "alerts";
|
|
|
|
const message = commandMessages[command] || `Command: ${command}`;
|
|
showToast(message);
|
|
setStatus(message);
|
|
}
|
|
|
|
document.querySelectorAll("[data-command]").forEach((button) => {
|
|
button.addEventListener("click", () => {
|
|
menuController.close();
|
|
runCommand(button.dataset.command);
|
|
});
|
|
});
|
|
|
|
document.querySelectorAll("[data-scroll-to]").forEach((button) => {
|
|
button.addEventListener("click", () => {
|
|
menuController.close();
|
|
scrollToSection(button.dataset.scrollTo);
|
|
});
|
|
});
|
|
|
|
document.querySelectorAll("[data-view-meta]").forEach((button) => {
|
|
button.addEventListener("click", () => {
|
|
const row = button.closest(".alert-row");
|
|
const title = row?.dataset.alertTitle || "Alert Metadata";
|
|
let meta = row?.dataset.alertMeta || "{}";
|
|
try {
|
|
meta = JSON.stringify(JSON.parse(meta), null, 2);
|
|
} catch (_) {
|
|
meta = row?.dataset.alertMeta || "{}";
|
|
}
|
|
openModal(`${title} (${row?.dataset.alertCode || "mock"})`, meta);
|
|
});
|
|
});
|
|
|
|
document.querySelectorAll("[data-dismiss-alert]").forEach((button) => {
|
|
button.addEventListener("click", () => {
|
|
const row = button.closest(".alert-row");
|
|
row?.classList.add("is-dismissed");
|
|
updateAlertSummary();
|
|
showToast(`Closed alert ${row?.dataset.alertCode || "mock"}.`);
|
|
setStatus(`Closed alert ${row?.dataset.alertCode || "mock"}`);
|
|
});
|
|
});
|
|
|
|
document.querySelector("[data-close-modal]")?.addEventListener("click", closeModal);
|
|
backdrop?.addEventListener("click", closeModal);
|
|
topAlertChip.addEventListener("click", (event) => {
|
|
event.preventDefault();
|
|
scrollToSection("alerts");
|
|
});
|
|
|
|
window.addEventListener("scroll", updateStickyHeader, { passive: true });
|
|
|
|
document.addEventListener("keydown", (event) => {
|
|
if (event.key === "Escape") {
|
|
menuController.close();
|
|
closeModal();
|
|
}
|
|
if (event.key === "F5") {
|
|
event.preventDefault();
|
|
runCommand("refresh");
|
|
}
|
|
if (event.altKey && event.key.toLowerCase() === "a") {
|
|
event.preventDefault();
|
|
scrollToSection("alerts");
|
|
}
|
|
if (event.altKey && event.key.toLowerCase() === "b") {
|
|
event.preventDefault();
|
|
scrollToSection("recent-boxes");
|
|
}
|
|
if (event.altKey && event.key.toLowerCase() === "r") {
|
|
event.preventDefault();
|
|
scrollToSection("recent-activity");
|
|
}
|
|
});
|
|
|
|
updateAlertSummary();
|
|
updateStickyHeader();
|
|
})();
|