refactor: Extract inline CSS/JS to separate files for monitoring module
- Create individual CSS files: monitoring.css, alerts.css, health.css, logs.css, metrics.css, resources.css
- Create individual JS files: monitoring.js, alerts.js, health.js, logs.js, metrics.js, resources.js
- Update HTML files to reference external CSS/JS files
- Add CSS/JS files for other modules (analytics, chat, mail, meet, tasks, etc.)
- Remove obsolete implementation plan files
2025-12-07 09:56:27 -03:00
|
|
|
|
/**
|
|
|
|
|
|
* Tools Module JavaScript
|
|
|
|
|
|
* Compliance, Analytics, and Developer Tools
|
|
|
|
|
|
*/
|
2026-01-16 11:29:47 -03:00
|
|
|
|
(function () {
|
|
|
|
|
|
"use strict";
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Initialize the Tools module
|
|
|
|
|
|
*/
|
|
|
|
|
|
function init() {
|
|
|
|
|
|
setupBotSelector();
|
|
|
|
|
|
setupFilters();
|
|
|
|
|
|
setupKeyboardShortcuts();
|
|
|
|
|
|
setupHTMXEvents();
|
|
|
|
|
|
updateStats();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Setup bot chip selection
|
|
|
|
|
|
*/
|
|
|
|
|
|
function setupBotSelector() {
|
|
|
|
|
|
document.addEventListener("click", function (e) {
|
|
|
|
|
|
const chip = e.target.closest(".bot-chip");
|
|
|
|
|
|
if (chip) {
|
|
|
|
|
|
// Toggle selection
|
|
|
|
|
|
chip.classList.toggle("selected");
|
|
|
|
|
|
|
|
|
|
|
|
// Update hidden checkbox
|
|
|
|
|
|
const checkbox = chip.querySelector('input[type="checkbox"]');
|
|
|
|
|
|
if (checkbox) {
|
|
|
|
|
|
checkbox.checked = chip.classList.contains("selected");
|
|
|
|
|
|
}
|
refactor: Extract inline CSS/JS to separate files for monitoring module
- Create individual CSS files: monitoring.css, alerts.css, health.css, logs.css, metrics.css, resources.css
- Create individual JS files: monitoring.js, alerts.js, health.js, logs.js, metrics.js, resources.js
- Update HTML files to reference external CSS/JS files
- Add CSS/JS files for other modules (analytics, chat, mail, meet, tasks, etc.)
- Remove obsolete implementation plan files
2025-12-07 09:56:27 -03:00
|
|
|
|
|
2026-01-16 11:29:47 -03:00
|
|
|
|
// Handle "All Bots" logic
|
|
|
|
|
|
if (chip.querySelector('input[value="all"]')) {
|
|
|
|
|
|
if (chip.classList.contains("selected")) {
|
|
|
|
|
|
// Deselect all other chips
|
|
|
|
|
|
document
|
|
|
|
|
|
.querySelectorAll(".bot-chip:not([data-all])")
|
|
|
|
|
|
.forEach((c) => {
|
|
|
|
|
|
c.classList.remove("selected");
|
|
|
|
|
|
const cb = c.querySelector('input[type="checkbox"]');
|
|
|
|
|
|
if (cb) cb.checked = false;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// Deselect "All Bots" when selecting individual bots
|
|
|
|
|
|
const allChip = document
|
|
|
|
|
|
.querySelector('.bot-chip input[value="all"]')
|
|
|
|
|
|
?.closest(".bot-chip");
|
|
|
|
|
|
if (allChip) {
|
|
|
|
|
|
allChip.classList.remove("selected");
|
|
|
|
|
|
const cb = allChip.querySelector('input[type="checkbox"]');
|
|
|
|
|
|
if (cb) cb.checked = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Setup filter controls
|
|
|
|
|
|
*/
|
|
|
|
|
|
function setupFilters() {
|
|
|
|
|
|
// Filter select changes
|
|
|
|
|
|
document.querySelectorAll(".filter-select").forEach((select) => {
|
|
|
|
|
|
select.addEventListener("change", function () {
|
|
|
|
|
|
applyFilters();
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// Search input
|
|
|
|
|
|
const searchInput = document.querySelector(
|
|
|
|
|
|
'.filter-input[name="filter-search"]',
|
|
|
|
|
|
);
|
|
|
|
|
|
if (searchInput) {
|
|
|
|
|
|
let debounceTimer;
|
|
|
|
|
|
searchInput.addEventListener("input", function () {
|
|
|
|
|
|
clearTimeout(debounceTimer);
|
|
|
|
|
|
debounceTimer = setTimeout(() => applyFilters(), 300);
|
|
|
|
|
|
});
|
refactor: Extract inline CSS/JS to separate files for monitoring module
- Create individual CSS files: monitoring.css, alerts.css, health.css, logs.css, metrics.css, resources.css
- Create individual JS files: monitoring.js, alerts.js, health.js, logs.js, metrics.js, resources.js
- Update HTML files to reference external CSS/JS files
- Add CSS/JS files for other modules (analytics, chat, mail, meet, tasks, etc.)
- Remove obsolete implementation plan files
2025-12-07 09:56:27 -03:00
|
|
|
|
}
|
2026-01-16 11:29:47 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Apply filters to results
|
|
|
|
|
|
*/
|
|
|
|
|
|
function applyFilters() {
|
|
|
|
|
|
const severity = document.getElementById("filter-severity")?.value || "all";
|
|
|
|
|
|
const type = document.getElementById("filter-type")?.value || "all";
|
|
|
|
|
|
const search =
|
|
|
|
|
|
document
|
|
|
|
|
|
.querySelector('.filter-input[name="filter-search"]')
|
|
|
|
|
|
?.value.toLowerCase() || "";
|
|
|
|
|
|
|
|
|
|
|
|
const rows = document.querySelectorAll("#results-body tr");
|
|
|
|
|
|
let visibleCount = 0;
|
|
|
|
|
|
|
|
|
|
|
|
rows.forEach((row) => {
|
|
|
|
|
|
let visible = true;
|
|
|
|
|
|
|
|
|
|
|
|
// Filter by severity
|
|
|
|
|
|
if (severity !== "all") {
|
|
|
|
|
|
const badge = row.querySelector(".severity-badge");
|
|
|
|
|
|
if (badge && !badge.classList.contains(severity)) {
|
|
|
|
|
|
visible = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
refactor: Extract inline CSS/JS to separate files for monitoring module
- Create individual CSS files: monitoring.css, alerts.css, health.css, logs.css, metrics.css, resources.css
- Create individual JS files: monitoring.js, alerts.js, health.js, logs.js, metrics.js, resources.js
- Update HTML files to reference external CSS/JS files
- Add CSS/JS files for other modules (analytics, chat, mail, meet, tasks, etc.)
- Remove obsolete implementation plan files
2025-12-07 09:56:27 -03:00
|
|
|
|
|
2026-01-16 11:29:47 -03:00
|
|
|
|
// Filter by type
|
|
|
|
|
|
if (type !== "all" && visible) {
|
|
|
|
|
|
const issueIcon = row.querySelector(".issue-icon");
|
|
|
|
|
|
if (issueIcon && !issueIcon.classList.contains(type)) {
|
|
|
|
|
|
visible = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
refactor: Extract inline CSS/JS to separate files for monitoring module
- Create individual CSS files: monitoring.css, alerts.css, health.css, logs.css, metrics.css, resources.css
- Create individual JS files: monitoring.js, alerts.js, health.js, logs.js, metrics.js, resources.js
- Update HTML files to reference external CSS/JS files
- Add CSS/JS files for other modules (analytics, chat, mail, meet, tasks, etc.)
- Remove obsolete implementation plan files
2025-12-07 09:56:27 -03:00
|
|
|
|
|
2026-01-16 11:29:47 -03:00
|
|
|
|
// Filter by search
|
|
|
|
|
|
if (search && visible) {
|
|
|
|
|
|
const text = row.textContent.toLowerCase();
|
|
|
|
|
|
if (!text.includes(search)) {
|
|
|
|
|
|
visible = false;
|
refactor: Extract inline CSS/JS to separate files for monitoring module
- Create individual CSS files: monitoring.css, alerts.css, health.css, logs.css, metrics.css, resources.css
- Create individual JS files: monitoring.js, alerts.js, health.js, logs.js, metrics.js, resources.js
- Update HTML files to reference external CSS/JS files
- Add CSS/JS files for other modules (analytics, chat, mail, meet, tasks, etc.)
- Remove obsolete implementation plan files
2025-12-07 09:56:27 -03:00
|
|
|
|
}
|
2026-01-16 11:29:47 -03:00
|
|
|
|
}
|
refactor: Extract inline CSS/JS to separate files for monitoring module
- Create individual CSS files: monitoring.css, alerts.css, health.css, logs.css, metrics.css, resources.css
- Create individual JS files: monitoring.js, alerts.js, health.js, logs.js, metrics.js, resources.js
- Update HTML files to reference external CSS/JS files
- Add CSS/JS files for other modules (analytics, chat, mail, meet, tasks, etc.)
- Remove obsolete implementation plan files
2025-12-07 09:56:27 -03:00
|
|
|
|
|
2026-01-16 11:29:47 -03:00
|
|
|
|
row.style.display = visible ? "" : "none";
|
|
|
|
|
|
if (visible) visibleCount++;
|
|
|
|
|
|
});
|
refactor: Extract inline CSS/JS to separate files for monitoring module
- Create individual CSS files: monitoring.css, alerts.css, health.css, logs.css, metrics.css, resources.css
- Create individual JS files: monitoring.js, alerts.js, health.js, logs.js, metrics.js, resources.js
- Update HTML files to reference external CSS/JS files
- Add CSS/JS files for other modules (analytics, chat, mail, meet, tasks, etc.)
- Remove obsolete implementation plan files
2025-12-07 09:56:27 -03:00
|
|
|
|
|
2026-01-16 11:29:47 -03:00
|
|
|
|
// Update results count
|
|
|
|
|
|
const countEl = document.getElementById("results-count");
|
|
|
|
|
|
if (countEl) {
|
|
|
|
|
|
countEl.textContent = `${visibleCount} issues found`;
|
refactor: Extract inline CSS/JS to separate files for monitoring module
- Create individual CSS files: monitoring.css, alerts.css, health.css, logs.css, metrics.css, resources.css
- Create individual JS files: monitoring.js, alerts.js, health.js, logs.js, metrics.js, resources.js
- Update HTML files to reference external CSS/JS files
- Add CSS/JS files for other modules (analytics, chat, mail, meet, tasks, etc.)
- Remove obsolete implementation plan files
2025-12-07 09:56:27 -03:00
|
|
|
|
}
|
2026-01-16 11:29:47 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Setup keyboard shortcuts
|
|
|
|
|
|
*/
|
|
|
|
|
|
function setupKeyboardShortcuts() {
|
|
|
|
|
|
document.addEventListener("keydown", function (e) {
|
|
|
|
|
|
// Ctrl+Enter to run scan
|
|
|
|
|
|
if ((e.ctrlKey || e.metaKey) && e.key === "Enter") {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
document.getElementById("scan-btn")?.click();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Escape to close any open modals
|
|
|
|
|
|
if (e.key === "Escape") {
|
|
|
|
|
|
closeModals();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Ctrl+E to export report
|
|
|
|
|
|
if ((e.ctrlKey || e.metaKey) && e.key === "e") {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
exportReport();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Setup HTMX events
|
|
|
|
|
|
*/
|
|
|
|
|
|
function setupHTMXEvents() {
|
|
|
|
|
|
if (typeof htmx === "undefined") return;
|
|
|
|
|
|
|
|
|
|
|
|
document.body.addEventListener("htmx:afterSwap", function (e) {
|
|
|
|
|
|
if (e.detail.target.id === "scan-results") {
|
|
|
|
|
|
updateStats();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Update statistics from results
|
|
|
|
|
|
*/
|
|
|
|
|
|
function updateStats() {
|
|
|
|
|
|
const rows = document.querySelectorAll("#results-body tr");
|
|
|
|
|
|
let stats = { critical: 0, high: 0, medium: 0, low: 0, info: 0 };
|
|
|
|
|
|
|
|
|
|
|
|
rows.forEach((row) => {
|
|
|
|
|
|
if (row.style.display === "none") return;
|
|
|
|
|
|
|
|
|
|
|
|
const badge = row.querySelector(".severity-badge");
|
|
|
|
|
|
if (badge) {
|
|
|
|
|
|
if (badge.classList.contains("critical")) stats.critical++;
|
|
|
|
|
|
else if (badge.classList.contains("high")) stats.high++;
|
|
|
|
|
|
else if (badge.classList.contains("medium")) stats.medium++;
|
|
|
|
|
|
else if (badge.classList.contains("low")) stats.low++;
|
|
|
|
|
|
else if (badge.classList.contains("info")) stats.info++;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// Update stat cards
|
|
|
|
|
|
const updateStat = (id, value) => {
|
|
|
|
|
|
const el = document.getElementById(id);
|
|
|
|
|
|
if (el) el.textContent = value;
|
|
|
|
|
|
};
|
refactor: Extract inline CSS/JS to separate files for monitoring module
- Create individual CSS files: monitoring.css, alerts.css, health.css, logs.css, metrics.css, resources.css
- Create individual JS files: monitoring.js, alerts.js, health.js, logs.js, metrics.js, resources.js
- Update HTML files to reference external CSS/JS files
- Add CSS/JS files for other modules (analytics, chat, mail, meet, tasks, etc.)
- Remove obsolete implementation plan files
2025-12-07 09:56:27 -03:00
|
|
|
|
|
2026-01-16 11:29:47 -03:00
|
|
|
|
updateStat("stat-critical", stats.critical);
|
|
|
|
|
|
updateStat("stat-high", stats.high);
|
|
|
|
|
|
updateStat("stat-medium", stats.medium);
|
|
|
|
|
|
updateStat("stat-low", stats.low);
|
|
|
|
|
|
updateStat("stat-info", stats.info);
|
|
|
|
|
|
|
|
|
|
|
|
// Update total count
|
|
|
|
|
|
const total =
|
|
|
|
|
|
stats.critical + stats.high + stats.medium + stats.low + stats.info;
|
|
|
|
|
|
const countEl = document.getElementById("results-count");
|
|
|
|
|
|
if (countEl) {
|
|
|
|
|
|
countEl.textContent = `${total} issues found`;
|
refactor: Extract inline CSS/JS to separate files for monitoring module
- Create individual CSS files: monitoring.css, alerts.css, health.css, logs.css, metrics.css, resources.css
- Create individual JS files: monitoring.js, alerts.js, health.js, logs.js, metrics.js, resources.js
- Update HTML files to reference external CSS/JS files
- Add CSS/JS files for other modules (analytics, chat, mail, meet, tasks, etc.)
- Remove obsolete implementation plan files
2025-12-07 09:56:27 -03:00
|
|
|
|
}
|
2026-01-16 11:29:47 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Export compliance report
|
|
|
|
|
|
*/
|
|
|
|
|
|
function exportReport() {
|
|
|
|
|
|
if (typeof htmx !== "undefined") {
|
|
|
|
|
|
htmx.ajax("GET", "/api/compliance/export", {
|
|
|
|
|
|
swap: "none",
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Fix an issue
|
|
|
|
|
|
*/
|
|
|
|
|
|
function fixIssue(issueId) {
|
|
|
|
|
|
if (typeof htmx !== "undefined") {
|
|
|
|
|
|
htmx
|
|
|
|
|
|
.ajax("POST", `/api/compliance/fix/${issueId}`, {
|
|
|
|
|
|
swap: "none",
|
|
|
|
|
|
})
|
|
|
|
|
|
.then(() => {
|
|
|
|
|
|
// Refresh results
|
|
|
|
|
|
const scanBtn = document.getElementById("scan-btn");
|
|
|
|
|
|
if (scanBtn) scanBtn.click();
|
refactor: Extract inline CSS/JS to separate files for monitoring module
- Create individual CSS files: monitoring.css, alerts.css, health.css, logs.css, metrics.css, resources.css
- Create individual JS files: monitoring.js, alerts.js, health.js, logs.js, metrics.js, resources.js
- Update HTML files to reference external CSS/JS files
- Add CSS/JS files for other modules (analytics, chat, mail, meet, tasks, etc.)
- Remove obsolete implementation plan files
2025-12-07 09:56:27 -03:00
|
|
|
|
});
|
|
|
|
|
|
}
|
2026-01-16 11:29:47 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Close all modals
|
|
|
|
|
|
*/
|
|
|
|
|
|
function closeModals() {
|
|
|
|
|
|
document.querySelectorAll(".modal").forEach((modal) => {
|
|
|
|
|
|
modal.classList.add("hidden");
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Show toast notification
|
|
|
|
|
|
*/
|
|
|
|
|
|
function showToast(message, type = "success") {
|
|
|
|
|
|
const toast = document.createElement("div");
|
|
|
|
|
|
toast.className = `toast toast-${type}`;
|
|
|
|
|
|
toast.textContent = message;
|
|
|
|
|
|
document.body.appendChild(toast);
|
|
|
|
|
|
|
|
|
|
|
|
requestAnimationFrame(() => {
|
|
|
|
|
|
toast.classList.add("show");
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
toast.classList.remove("show");
|
|
|
|
|
|
setTimeout(() => toast.remove(), 300);
|
|
|
|
|
|
}, 3000);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Initialize on DOM ready
|
|
|
|
|
|
if (document.readyState === "loading") {
|
|
|
|
|
|
document.addEventListener("DOMContentLoaded", init);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
init();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Configure a protection tool
|
|
|
|
|
|
*/
|
|
|
|
|
|
function configureProtectionTool(toolName) {
|
|
|
|
|
|
const modal =
|
|
|
|
|
|
document.getElementById("configure-modal") ||
|
|
|
|
|
|
document.getElementById("tool-config-modal");
|
|
|
|
|
|
if (modal) {
|
|
|
|
|
|
const titleEl = modal.querySelector(".modal-title, h2, h3");
|
|
|
|
|
|
if (titleEl) {
|
|
|
|
|
|
titleEl.textContent = `Configure ${toolName}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
modal.dataset.tool = toolName;
|
|
|
|
|
|
if (modal.showModal) {
|
|
|
|
|
|
modal.showModal();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
modal.classList.remove("hidden");
|
|
|
|
|
|
modal.style.display = "flex";
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
showToast(`Opening configuration for ${toolName}...`, "info");
|
|
|
|
|
|
fetch(`/api/tools/security/${toolName}/config`)
|
|
|
|
|
|
.then((r) => r.json())
|
|
|
|
|
|
.then((config) => {
|
|
|
|
|
|
console.log(`${toolName} config:`, config);
|
|
|
|
|
|
showToast(`${toolName} configuration loaded`, "success");
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch((err) => {
|
|
|
|
|
|
console.error(`Error loading ${toolName} config:`, err);
|
|
|
|
|
|
showToast(`Failed to load ${toolName} configuration`, "error");
|
refactor: Extract inline CSS/JS to separate files for monitoring module
- Create individual CSS files: monitoring.css, alerts.css, health.css, logs.css, metrics.css, resources.css
- Create individual JS files: monitoring.js, alerts.js, health.js, logs.js, metrics.js, resources.js
- Update HTML files to reference external CSS/JS files
- Add CSS/JS files for other modules (analytics, chat, mail, meet, tasks, etc.)
- Remove obsolete implementation plan files
2025-12-07 09:56:27 -03:00
|
|
|
|
});
|
|
|
|
|
|
}
|
2026-01-16 11:29:47 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Run a protection tool scan
|
|
|
|
|
|
*/
|
|
|
|
|
|
function runProtectionTool(toolName) {
|
|
|
|
|
|
showToast(`Running ${toolName} scan...`, "info");
|
|
|
|
|
|
|
|
|
|
|
|
const statusEl = document.querySelector(
|
|
|
|
|
|
`[data-tool="${toolName}"] .tool-status, #${toolName}-status`,
|
|
|
|
|
|
);
|
|
|
|
|
|
if (statusEl) {
|
|
|
|
|
|
statusEl.textContent = "Running...";
|
|
|
|
|
|
statusEl.classList.add("running");
|
refactor: Extract inline CSS/JS to separate files for monitoring module
- Create individual CSS files: monitoring.css, alerts.css, health.css, logs.css, metrics.css, resources.css
- Create individual JS files: monitoring.js, alerts.js, health.js, logs.js, metrics.js, resources.js
- Update HTML files to reference external CSS/JS files
- Add CSS/JS files for other modules (analytics, chat, mail, meet, tasks, etc.)
- Remove obsolete implementation plan files
2025-12-07 09:56:27 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-16 11:29:47 -03:00
|
|
|
|
fetch(`/api/tools/security/${toolName}/run`, {
|
|
|
|
|
|
method: "POST",
|
|
|
|
|
|
headers: { "Content-Type": "application/json" },
|
|
|
|
|
|
})
|
|
|
|
|
|
.then((r) => r.json())
|
|
|
|
|
|
.then((result) => {
|
|
|
|
|
|
if (statusEl) {
|
|
|
|
|
|
statusEl.textContent = "Completed";
|
|
|
|
|
|
statusEl.classList.remove("running");
|
|
|
|
|
|
statusEl.classList.add("completed");
|
refactor: Extract inline CSS/JS to separate files for monitoring module
- Create individual CSS files: monitoring.css, alerts.css, health.css, logs.css, metrics.css, resources.css
- Create individual JS files: monitoring.js, alerts.js, health.js, logs.js, metrics.js, resources.js
- Update HTML files to reference external CSS/JS files
- Add CSS/JS files for other modules (analytics, chat, mail, meet, tasks, etc.)
- Remove obsolete implementation plan files
2025-12-07 09:56:27 -03:00
|
|
|
|
}
|
2026-01-16 11:29:47 -03:00
|
|
|
|
showToast(`${toolName} scan completed`, "success");
|
refactor: Extract inline CSS/JS to separate files for monitoring module
- Create individual CSS files: monitoring.css, alerts.css, health.css, logs.css, metrics.css, resources.css
- Create individual JS files: monitoring.js, alerts.js, health.js, logs.js, metrics.js, resources.js
- Update HTML files to reference external CSS/JS files
- Add CSS/JS files for other modules (analytics, chat, mail, meet, tasks, etc.)
- Remove obsolete implementation plan files
2025-12-07 09:56:27 -03:00
|
|
|
|
|
2026-01-16 11:29:47 -03:00
|
|
|
|
if (result.report_url) {
|
|
|
|
|
|
viewReport(toolName);
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch((err) => {
|
|
|
|
|
|
console.error(`Error running ${toolName}:`, err);
|
|
|
|
|
|
if (statusEl) {
|
|
|
|
|
|
statusEl.textContent = "Error";
|
|
|
|
|
|
statusEl.classList.remove("running");
|
|
|
|
|
|
statusEl.classList.add("error");
|
|
|
|
|
|
}
|
|
|
|
|
|
showToast(`Failed to run ${toolName}`, "error");
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Update a protection tool
|
|
|
|
|
|
*/
|
|
|
|
|
|
function updateProtectionTool(toolName) {
|
|
|
|
|
|
showToast(`Updating ${toolName}...`, "info");
|
|
|
|
|
|
|
|
|
|
|
|
fetch(`/api/tools/security/${toolName}/update`, {
|
|
|
|
|
|
method: "POST",
|
|
|
|
|
|
headers: { "Content-Type": "application/json" },
|
|
|
|
|
|
})
|
|
|
|
|
|
.then((r) => r.json())
|
|
|
|
|
|
.then((result) => {
|
|
|
|
|
|
showToast(
|
|
|
|
|
|
`${toolName} updated to version ${result.version || "latest"}`,
|
|
|
|
|
|
"success",
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
const versionEl = document.querySelector(
|
|
|
|
|
|
`[data-tool="${toolName}"] .tool-version, #${toolName}-version`,
|
|
|
|
|
|
);
|
|
|
|
|
|
if (versionEl && result.version) {
|
|
|
|
|
|
versionEl.textContent = result.version;
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch((err) => {
|
|
|
|
|
|
console.error(`Error updating ${toolName}:`, err);
|
|
|
|
|
|
showToast(`Failed to update ${toolName}`, "error");
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* View report for a protection tool
|
|
|
|
|
|
*/
|
|
|
|
|
|
function viewReport(toolName) {
|
|
|
|
|
|
const reportModal =
|
|
|
|
|
|
document.getElementById("report-modal") ||
|
|
|
|
|
|
document.getElementById("view-report-modal");
|
|
|
|
|
|
|
|
|
|
|
|
if (reportModal) {
|
|
|
|
|
|
const titleEl = reportModal.querySelector(".modal-title, h2, h3");
|
|
|
|
|
|
if (titleEl) {
|
|
|
|
|
|
titleEl.textContent = `${toolName} Report`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const contentEl = reportModal.querySelector(
|
|
|
|
|
|
".report-content, .modal-body",
|
|
|
|
|
|
);
|
|
|
|
|
|
if (contentEl) {
|
|
|
|
|
|
contentEl.innerHTML = '<div class="loading">Loading report...</div>';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (reportModal.showModal) {
|
|
|
|
|
|
reportModal.showModal();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
reportModal.classList.remove("hidden");
|
|
|
|
|
|
reportModal.style.display = "flex";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fetch(`/api/tools/security/${toolName}/report`)
|
|
|
|
|
|
.then((r) => r.json())
|
|
|
|
|
|
.then((report) => {
|
|
|
|
|
|
if (contentEl) {
|
|
|
|
|
|
contentEl.innerHTML = renderReport(toolName, report);
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch((err) => {
|
|
|
|
|
|
console.error(`Error loading ${toolName} report:`, err);
|
|
|
|
|
|
if (contentEl) {
|
|
|
|
|
|
contentEl.innerHTML =
|
|
|
|
|
|
'<div class="error">Failed to load report</div>';
|
|
|
|
|
|
}
|
refactor: Extract inline CSS/JS to separate files for monitoring module
- Create individual CSS files: monitoring.css, alerts.css, health.css, logs.css, metrics.css, resources.css
- Create individual JS files: monitoring.js, alerts.js, health.js, logs.js, metrics.js, resources.js
- Update HTML files to reference external CSS/JS files
- Add CSS/JS files for other modules (analytics, chat, mail, meet, tasks, etc.)
- Remove obsolete implementation plan files
2025-12-07 09:56:27 -03:00
|
|
|
|
});
|
2026-01-16 11:29:47 -03:00
|
|
|
|
} else {
|
|
|
|
|
|
window.open(
|
|
|
|
|
|
`/api/tools/security/${toolName}/report?format=html`,
|
|
|
|
|
|
"_blank",
|
|
|
|
|
|
);
|
refactor: Extract inline CSS/JS to separate files for monitoring module
- Create individual CSS files: monitoring.css, alerts.css, health.css, logs.css, metrics.css, resources.css
- Create individual JS files: monitoring.js, alerts.js, health.js, logs.js, metrics.js, resources.js
- Update HTML files to reference external CSS/JS files
- Add CSS/JS files for other modules (analytics, chat, mail, meet, tasks, etc.)
- Remove obsolete implementation plan files
2025-12-07 09:56:27 -03:00
|
|
|
|
}
|
2026-01-16 11:29:47 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Render a security tool report
|
|
|
|
|
|
*/
|
|
|
|
|
|
function renderReport(toolName, report) {
|
|
|
|
|
|
const findings = report.findings || [];
|
|
|
|
|
|
const summary = report.summary || {};
|
|
|
|
|
|
|
|
|
|
|
|
return `
|
|
|
|
|
|
<div class="report-summary">
|
|
|
|
|
|
<h4>Summary</h4>
|
|
|
|
|
|
<div class="summary-stats">
|
|
|
|
|
|
<span class="stat critical">${summary.critical || 0} Critical</span>
|
|
|
|
|
|
<span class="stat high">${summary.high || 0} High</span>
|
|
|
|
|
|
<span class="stat medium">${summary.medium || 0} Medium</span>
|
|
|
|
|
|
<span class="stat low">${summary.low || 0} Low</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<p>Scan completed: ${report.completed_at || new Date().toISOString()}</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="report-findings">
|
|
|
|
|
|
<h4>Findings (${findings.length})</h4>
|
|
|
|
|
|
${findings.length === 0 ? '<p class="no-findings">No issues found</p>' : ""}
|
|
|
|
|
|
${findings
|
|
|
|
|
|
.map(
|
|
|
|
|
|
(f) => `
|
|
|
|
|
|
<div class="finding ${f.severity || "info"}">
|
|
|
|
|
|
<span class="severity-badge ${f.severity || "info"}">${f.severity || "info"}</span>
|
|
|
|
|
|
<span class="finding-title">${f.title || f.message || "Finding"}</span>
|
|
|
|
|
|
<p class="finding-description">${f.description || ""}</p>
|
|
|
|
|
|
${f.remediation ? `<p class="finding-remediation"><strong>Fix:</strong> ${f.remediation}</p>` : ""}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
`,
|
|
|
|
|
|
)
|
|
|
|
|
|
.join("")}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Toggle auto action for a protection tool
|
|
|
|
|
|
*/
|
|
|
|
|
|
function toggleAutoAction(toolName, btn) {
|
|
|
|
|
|
const isEnabled =
|
|
|
|
|
|
btn.classList.contains("active") ||
|
|
|
|
|
|
btn.getAttribute("aria-pressed") === "true";
|
|
|
|
|
|
const newState = !isEnabled;
|
|
|
|
|
|
|
|
|
|
|
|
fetch(`/api/tools/security/${toolName}/auto`, {
|
|
|
|
|
|
method: "POST",
|
|
|
|
|
|
headers: { "Content-Type": "application/json" },
|
|
|
|
|
|
body: JSON.stringify({ enabled: newState }),
|
|
|
|
|
|
})
|
|
|
|
|
|
.then((r) => r.json())
|
|
|
|
|
|
.then((result) => {
|
|
|
|
|
|
if (newState) {
|
|
|
|
|
|
btn.classList.add("active");
|
|
|
|
|
|
btn.setAttribute("aria-pressed", "true");
|
|
|
|
|
|
showToast(`Auto-scan enabled for ${toolName}`, "success");
|
|
|
|
|
|
} else {
|
|
|
|
|
|
btn.classList.remove("active");
|
|
|
|
|
|
btn.setAttribute("aria-pressed", "false");
|
|
|
|
|
|
showToast(`Auto-scan disabled for ${toolName}`, "info");
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch((err) => {
|
|
|
|
|
|
console.error(`Error toggling auto action for ${toolName}:`, err);
|
|
|
|
|
|
showToast(`Failed to update ${toolName} settings`, "error");
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Reindex a data source for search
|
|
|
|
|
|
*/
|
|
|
|
|
|
function reindexSource(sourceName) {
|
|
|
|
|
|
showToast(`Reindexing ${sourceName}...`, "info");
|
|
|
|
|
|
|
|
|
|
|
|
fetch(`/api/search/reindex/${sourceName}`, {
|
|
|
|
|
|
method: "POST",
|
|
|
|
|
|
headers: { "Content-Type": "application/json" },
|
|
|
|
|
|
})
|
|
|
|
|
|
.then((r) => r.json())
|
|
|
|
|
|
.then((result) => {
|
|
|
|
|
|
showToast(
|
|
|
|
|
|
`${sourceName} reindexing started. ${result.documents || 0} documents queued.`,
|
|
|
|
|
|
"success",
|
|
|
|
|
|
);
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch((err) => {
|
|
|
|
|
|
console.error(`Error reindexing ${sourceName}:`, err);
|
|
|
|
|
|
showToast(`Failed to reindex ${sourceName}`, "error");
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Show TSC (Trust Service Criteria) details
|
|
|
|
|
|
*/
|
|
|
|
|
|
function showTscDetails(category) {
|
|
|
|
|
|
const detailPanel =
|
|
|
|
|
|
document.getElementById("tsc-detail-panel") ||
|
|
|
|
|
|
document.querySelector(".tsc-details");
|
|
|
|
|
|
|
|
|
|
|
|
if (detailPanel) {
|
|
|
|
|
|
fetch(`/api/compliance/tsc/${category}`)
|
|
|
|
|
|
.then((r) => r.json())
|
|
|
|
|
|
.then((data) => {
|
|
|
|
|
|
detailPanel.innerHTML = renderTscDetails(category, data);
|
|
|
|
|
|
detailPanel.classList.add("open");
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch((err) => {
|
|
|
|
|
|
console.error(`Error loading TSC details for ${category}:`, err);
|
|
|
|
|
|
showToast(`Failed to load ${category} details`, "error");
|
refactor: Extract inline CSS/JS to separate files for monitoring module
- Create individual CSS files: monitoring.css, alerts.css, health.css, logs.css, metrics.css, resources.css
- Create individual JS files: monitoring.js, alerts.js, health.js, logs.js, metrics.js, resources.js
- Update HTML files to reference external CSS/JS files
- Add CSS/JS files for other modules (analytics, chat, mail, meet, tasks, etc.)
- Remove obsolete implementation plan files
2025-12-07 09:56:27 -03:00
|
|
|
|
});
|
2026-01-16 11:29:47 -03:00
|
|
|
|
} else {
|
|
|
|
|
|
showToast(`Viewing ${category} criteria...`, "info");
|
refactor: Extract inline CSS/JS to separate files for monitoring module
- Create individual CSS files: monitoring.css, alerts.css, health.css, logs.css, metrics.css, resources.css
- Create individual JS files: monitoring.js, alerts.js, health.js, logs.js, metrics.js, resources.js
- Update HTML files to reference external CSS/JS files
- Add CSS/JS files for other modules (analytics, chat, mail, meet, tasks, etc.)
- Remove obsolete implementation plan files
2025-12-07 09:56:27 -03:00
|
|
|
|
}
|
2026-01-16 11:29:47 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Render TSC details
|
|
|
|
|
|
*/
|
|
|
|
|
|
function renderTscDetails(category, data) {
|
|
|
|
|
|
const controls = data.controls || [];
|
|
|
|
|
|
return `
|
|
|
|
|
|
<div class="tsc-detail-header">
|
|
|
|
|
|
<h3>${category.charAt(0).toUpperCase() + category.slice(1)} Criteria</h3>
|
|
|
|
|
|
<button class="close-btn" onclick="document.querySelector('.tsc-details').classList.remove('open')">×</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="tsc-controls">
|
|
|
|
|
|
${controls
|
|
|
|
|
|
.map(
|
|
|
|
|
|
(c) => `
|
|
|
|
|
|
<div class="control-item ${c.status || "pending"}">
|
|
|
|
|
|
<span class="control-id">${c.id}</span>
|
|
|
|
|
|
<span class="control-name">${c.name}</span>
|
|
|
|
|
|
<span class="control-status">${c.status || "Pending"}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
`,
|
|
|
|
|
|
)
|
|
|
|
|
|
.join("")}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Show control remediation steps
|
|
|
|
|
|
*/
|
|
|
|
|
|
function showControlRemediation(controlId) {
|
|
|
|
|
|
const modal =
|
|
|
|
|
|
document.getElementById("remediation-modal") ||
|
|
|
|
|
|
document.getElementById("control-modal");
|
|
|
|
|
|
|
|
|
|
|
|
if (modal) {
|
|
|
|
|
|
const titleEl = modal.querySelector(".modal-title, h2, h3");
|
|
|
|
|
|
if (titleEl) {
|
|
|
|
|
|
titleEl.textContent = `Remediate ${controlId}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const contentEl = modal.querySelector(
|
|
|
|
|
|
".modal-body, .remediation-content",
|
|
|
|
|
|
);
|
|
|
|
|
|
if (contentEl) {
|
|
|
|
|
|
contentEl.innerHTML =
|
|
|
|
|
|
'<div class="loading">Loading remediation steps...</div>';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (modal.showModal) {
|
|
|
|
|
|
modal.showModal();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
modal.classList.remove("hidden");
|
|
|
|
|
|
modal.style.display = "flex";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fetch(`/api/compliance/controls/${controlId}/remediation`)
|
|
|
|
|
|
.then((r) => r.json())
|
|
|
|
|
|
.then((data) => {
|
|
|
|
|
|
if (contentEl) {
|
|
|
|
|
|
contentEl.innerHTML = `
|
|
|
|
|
|
<div class="remediation-steps">
|
|
|
|
|
|
<h4>Steps to Remediate</h4>
|
|
|
|
|
|
<ol>
|
|
|
|
|
|
${(data.steps || []).map((s) => `<li>${s}</li>`).join("")}
|
|
|
|
|
|
</ol>
|
|
|
|
|
|
${data.documentation_url ? `<a href="${data.documentation_url}" target="_blank" class="btn btn-secondary">View Documentation</a>` : ""}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
`;
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch((err) => {
|
|
|
|
|
|
console.error(`Error loading remediation for ${controlId}:`, err);
|
|
|
|
|
|
if (contentEl) {
|
|
|
|
|
|
contentEl.innerHTML =
|
|
|
|
|
|
'<div class="error">Failed to load remediation steps</div>';
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
refactor: Extract inline CSS/JS to separate files for monitoring module
- Create individual CSS files: monitoring.css, alerts.css, health.css, logs.css, metrics.css, resources.css
- Create individual JS files: monitoring.js, alerts.js, health.js, logs.js, metrics.js, resources.js
- Update HTML files to reference external CSS/JS files
- Add CSS/JS files for other modules (analytics, chat, mail, meet, tasks, etc.)
- Remove obsolete implementation plan files
2025-12-07 09:56:27 -03:00
|
|
|
|
} else {
|
2026-01-16 11:29:47 -03:00
|
|
|
|
showToast(`Loading remediation for ${controlId}...`, "info");
|
refactor: Extract inline CSS/JS to separate files for monitoring module
- Create individual CSS files: monitoring.css, alerts.css, health.css, logs.css, metrics.css, resources.css
- Create individual JS files: monitoring.js, alerts.js, health.js, logs.js, metrics.js, resources.js
- Update HTML files to reference external CSS/JS files
- Add CSS/JS files for other modules (analytics, chat, mail, meet, tasks, etc.)
- Remove obsolete implementation plan files
2025-12-07 09:56:27 -03:00
|
|
|
|
}
|
2026-01-16 11:29:47 -03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Expose for external use
|
|
|
|
|
|
window.Tools = {
|
|
|
|
|
|
updateStats,
|
|
|
|
|
|
applyFilters,
|
|
|
|
|
|
fixIssue,
|
|
|
|
|
|
exportReport,
|
|
|
|
|
|
showToast,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Expose security tool functions globally
|
|
|
|
|
|
window.configureProtectionTool = configureProtectionTool;
|
|
|
|
|
|
window.runProtectionTool = runProtectionTool;
|
|
|
|
|
|
window.updateProtectionTool = updateProtectionTool;
|
|
|
|
|
|
window.viewReport = viewReport;
|
|
|
|
|
|
window.toggleAutoAction = toggleAutoAction;
|
|
|
|
|
|
window.reindexSource = reindexSource;
|
|
|
|
|
|
window.showTscDetails = showTscDetails;
|
|
|
|
|
|
window.showControlRemediation = showControlRemediation;
|
refactor: Extract inline CSS/JS to separate files for monitoring module
- Create individual CSS files: monitoring.css, alerts.css, health.css, logs.css, metrics.css, resources.css
- Create individual JS files: monitoring.js, alerts.js, health.js, logs.js, metrics.js, resources.js
- Update HTML files to reference external CSS/JS files
- Add CSS/JS files for other modules (analytics, chat, mail, meet, tasks, etc.)
- Remove obsolete implementation plan files
2025-12-07 09:56:27 -03:00
|
|
|
|
})();
|