User Log and Persistent Faction Information

This commit is contained in:
2026-01-27 14:48:46 -05:00
parent 4ae3a9eb17
commit 4850c16b87
39 changed files with 782 additions and 71 deletions

View File

@@ -23,6 +23,21 @@ function toInt(v) {
return Number.isNaN(n) ? null : n;
}
// ---------------------------
// Activity logging
// ---------------------------
async function logAction(action, details = "") {
try {
await fetch("/api/log_action", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ action, details })
});
} catch (err) {
console.error("Failed to log action:", err);
}
}
// ---------------------------
// Status CSS helpers
// ---------------------------
@@ -428,6 +443,11 @@ function setupDropZones() {
if (prev) prev.removeChild(member.domElement);
zone.appendChild(member.domElement);
}
// Log the assignment
if (member) {
await logAction("Assigned Member to Group", `${member.name} (${kind}) -> Group ${groupKey}`);
}
} else {
console.warn("Unexpected zone id format", zone.id);
}
@@ -443,6 +463,11 @@ function setupDropZones() {
if (prev) prev.removeChild(member.domElement);
container.appendChild(member.domElement);
}
// Log the removal
if (member) {
await logAction("Removed Member from Group", `${member.name} (${kind})`);
}
}
});
@@ -516,6 +541,9 @@ async function populateFriendly() {
// Refresh assignments & status UI
await loadMembers("enemy"); // in case population changed cross lists
await pollAssignments();
// Log the action
await logAction("Populated Friendly Faction", `Faction ID: ${id}, Members: ${data.members ? data.members.length : 0}`);
} catch (err) {
console.error("populateFriendly error:", err);
}
@@ -583,6 +611,9 @@ async function populateEnemy() {
// Refresh assignments & status UI
await loadMembers("friendly");
await pollAssignments();
// Log the action
await logAction("Populated Enemy Faction", `Faction ID: ${id}, Members: ${data.members ? data.members.length : 0}`);
} catch (err) {
console.error("populateEnemy error:", err);
}
@@ -620,6 +651,9 @@ async function toggleFriendlyStatus() {
btn.textContent = "Start";
btn.dataset.running = "false";
btn.style.backgroundColor = "";
// Notify server that status refresh stopped
await fetch("/api/stop_friendly_status", { method: "POST" });
await logAction("Stopped Friendly Status Refresh");
return;
}
@@ -637,6 +671,7 @@ async function toggleFriendlyStatus() {
btn.textContent = "Stop";
btn.dataset.running = "true";
btn.style.backgroundColor = "#ff6b6b";
await logAction("Started Friendly Status Refresh", `Interval: ${interval}s`);
}
async function toggleEnemyStatus() {
@@ -647,6 +682,9 @@ async function toggleEnemyStatus() {
btn.textContent = "Start";
btn.dataset.running = "false";
btn.style.backgroundColor = "";
// Notify server that status refresh stopped
await fetch("/api/stop_enemy_status", { method: "POST" });
await logAction("Stopped Enemy Status Refresh");
return;
}
@@ -664,6 +702,7 @@ async function toggleEnemyStatus() {
btn.textContent = "Stop";
btn.dataset.running = "true";
btn.style.backgroundColor = "#ff6b6b";
await logAction("Started Enemy Status Refresh", `Interval: ${interval}s`);
}
// ---------------------------
@@ -694,6 +733,9 @@ async function toggleBotControl() {
btn.style.backgroundColor = data.bot_running ? "#ff4444" : "#4CAF50";
console.log(`Bot ${data.bot_running ? "started" : "stopped"}`);
// Log the action
await logAction(data.bot_running ? "Started Bot" : "Stopped Bot");
} catch (err) {
console.error("toggleBotControl error:", err);
}
@@ -707,6 +749,8 @@ async function resetGroups() {
await clearAssignmentsOnServer();
// reload assignments & UI
await pollAssignments();
// Log the action
await logAction("Reset All Groups");
}
// ---------------------------
@@ -765,6 +809,104 @@ async function handleLogout() {
}
}
// ---------------------------
// Restore dashboard state from server
// ---------------------------
async function restoreDashboardState() {
try {
const res = await fetch("/api/dashboard_state", { cache: "no-store" });
if (!res.ok) {
console.log("No dashboard state to restore");
return;
}
const state = await res.json();
console.log("Restoring dashboard state:", state);
// Restore friendly faction
if (state.friendly_faction_id && state.friendly_members && state.friendly_members.length > 0) {
document.getElementById("friendly-id").value = state.friendly_faction_id;
// Load members into UI
for (const m of state.friendly_members) {
const newMember = {
id: m.id,
name: m.name,
level: m.level,
estimate: m.estimate,
status: m.status || "Unknown",
hits: m.hits || 0,
domElement: null
};
friendlyMembers.set(m.id, newMember);
const card = createMemberCard(newMember, "friendly");
friendlyContainer.appendChild(card);
}
console.log(`Restored ${state.friendly_members.length} friendly members`);
// Restore status refresh if it was running
if (state.friendly_status_running) {
const interval = state.friendly_status_interval || 10;
document.getElementById("friendly-refresh-interval").value = interval;
const btn = document.getElementById("friendly-status-btn");
friendlyStatusIntervalHandle = setInterval(() => refreshStatus("friendly"), interval * 1000);
refreshStatus("friendly");
btn.textContent = "Stop";
btn.dataset.running = "true";
btn.style.backgroundColor = "#ff6b6b";
console.log(`Restored friendly status refresh (${interval}s)`);
}
}
// Restore enemy faction
if (state.enemy_faction_id && state.enemy_members && state.enemy_members.length > 0) {
document.getElementById("enemy-id").value = state.enemy_faction_id;
// Load members into UI
for (const m of state.enemy_members) {
const newMember = {
id: m.id,
name: m.name,
level: m.level,
estimate: m.estimate,
status: m.status || "Unknown",
hits: m.hits || 0,
domElement: null
};
enemyMembers.set(m.id, newMember);
const card = createMemberCard(newMember, "enemy");
enemyContainer.appendChild(card);
}
console.log(`Restored ${state.enemy_members.length} enemy members`);
// Restore status refresh if it was running
if (state.enemy_status_running) {
const interval = state.enemy_status_interval || 10;
document.getElementById("enemy-refresh-interval").value = interval;
const btn = document.getElementById("enemy-status-btn");
enemyStatusIntervalHandle = setInterval(() => refreshStatus("enemy"), interval * 1000);
refreshStatus("enemy");
btn.textContent = "Stop";
btn.dataset.running = "true";
btn.style.backgroundColor = "#ff6b6b";
console.log(`Restored enemy status refresh (${interval}s)`);
}
}
// Refresh assignments after restoring members
if ((state.friendly_members && state.friendly_members.length > 0) ||
(state.enemy_members && state.enemy_members.length > 0)) {
await pollAssignments();
}
} catch (err) {
console.error("Error restoring dashboard state:", err);
console.error("Error stack:", err.stack);
}
}
// ---------------------------
// Initial load
// ---------------------------
@@ -772,9 +914,9 @@ document.addEventListener("DOMContentLoaded", async () => {
console.log(">>> DOMContentLoaded fired");
wireUp();
// DON'T load members on initial page load - wait for user to click Populate
// This prevents showing stale data from server STATE
// Restore previous state from server (faction IDs, members, status refresh)
await restoreDashboardState();
// Start polling for assignments (but there won't be any until members are populated)
// Start polling for assignments
startAssignmentsPolling();
});