Files

212 lines
6.1 KiB
JavaScript

// users_log.js - Activity log and active users display
let logsPollingInterval = null;
let usersPollingInterval = null;
async function fetchActiveUsers() {
try {
const res = await fetch("/api/active_users", { cache: "no-store" });
if (!res.ok) {
console.error("Failed to fetch active users:", res.status);
return;
}
const data = await res.json();
displayActiveUsers(data.users || []);
} catch (err) {
console.error("Error fetching active users:", err);
}
}
function displayActiveUsers(users) {
const container = document.getElementById("active-users-list");
if (users.length === 0) {
container.innerHTML = '<div class="no-users">No active users</div>';
return;
}
container.innerHTML = users.map(username => `
<div class="user-item">
<span class="user-indicator"></span>
<span class="user-name">${escapeHtml(username)}</span>
</div>
`).join('');
}
async function fetchActivityLogs() {
try {
const res = await fetch("/api/activity_logs?limit=200", { cache: "no-store" });
if (!res.ok) {
console.error("Failed to fetch activity logs:", res.status);
return;
}
const data = await res.json();
displayActivityLogs(data.logs || []);
} catch (err) {
console.error("Error fetching activity logs:", err);
}
}
function displayActivityLogs(logs) {
const container = document.getElementById("activity-log-container");
if (logs.length === 0) {
container.innerHTML = '<div class="no-logs">No activity logs yet</div>';
return;
}
container.innerHTML = logs.map(log => {
const time = formatTimestamp(log.timestamp);
const details = log.details ? ` - ${escapeHtml(log.details)}` : '';
return `
<div class="log-entry">
<span class="log-time">${time}</span>
<span class="log-user">${escapeHtml(log.username)}</span>
<span class="log-action">${escapeHtml(log.action)}</span>
${details ? `<span class="log-details">${details}</span>` : ''}
</div>
`;
}).join('');
// Auto-scroll to bottom on first load
if (!container.hasAttribute('data-scrolled')) {
container.scrollTop = container.scrollHeight;
container.setAttribute('data-scrolled', 'true');
}
}
function formatTimestamp(isoString) {
const date = new Date(isoString);
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${hours}:${minutes}:${seconds}`;
}
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
async function copyLogsToClipboard() {
try {
const res = await fetch("/api/activity_logs?limit=1000", { cache: "no-store" });
if (!res.ok) {
alert("Failed to fetch logs");
return;
}
const data = await res.json();
const logs = data.logs || [];
if (logs.length === 0) {
alert("No logs to copy");
return;
}
// Format logs as plain text
const logText = logs.map(log => {
const time = formatTimestamp(log.timestamp);
const details = log.details ? ` - ${log.details}` : '';
return `[${time}] ${log.username}: ${log.action}${details}`;
}).join('\n');
// Copy to clipboard
await navigator.clipboard.writeText(logText);
// Show success feedback
const btn = document.getElementById("copy-log-btn");
const originalText = btn.textContent;
btn.textContent = "Copied!";
btn.style.backgroundColor = "#4CAF50";
setTimeout(() => {
btn.textContent = originalText;
btn.style.backgroundColor = "";
}, 2000);
} catch (err) {
console.error("Error copying logs:", err);
alert("Failed to copy logs to clipboard");
}
}
function startPolling() {
// Fetch immediately
fetchActiveUsers();
fetchActivityLogs();
// Then poll at intervals
usersPollingInterval = setInterval(fetchActiveUsers, 10000); // Every 10 seconds
logsPollingInterval = setInterval(fetchActivityLogs, 5000); // Every 5 seconds
}
function stopPolling() {
if (usersPollingInterval) {
clearInterval(usersPollingInterval);
usersPollingInterval = null;
}
if (logsPollingInterval) {
clearInterval(logsPollingInterval);
logsPollingInterval = null;
}
}
async function handleLogout() {
console.log("handleLogout called");
try {
console.log("Sending logout request to /auth/logout");
const response = await fetch("/auth/logout", {
method: "POST"
});
console.log("Logout response status:", response.status);
if (response.ok) {
console.log("Logout successful, redirecting to /login");
window.location.href = "/login";
} else {
console.error("Logout failed with status:", response.status);
window.location.href = "/login";
}
} catch (error) {
console.error("Error during logout:", error);
window.location.href = "/login";
}
}
function wireUp() {
// Attach copy button handler
const copyBtn = document.getElementById("copy-log-btn");
if (copyBtn) {
copyBtn.addEventListener("click", copyLogsToClipboard);
}
// Attach logout handler
const logoutBtn = document.getElementById("logout-btn");
if (logoutBtn) {
logoutBtn.addEventListener("click", handleLogout);
}
}
// Initialize when page loads
document.addEventListener("DOMContentLoaded", () => {
wireUp();
startPolling();
});
// Stop polling when page is hidden/unloaded
document.addEventListener("visibilitychange", () => {
if (document.hidden) {
stopPolling();
} else {
startPolling();
}
});
window.addEventListener("beforeunload", () => {
stopPolling();
});