UI improvements

This commit is contained in:
KingKDot
2026-05-30 22:44:55 -05:00
parent 5933297686
commit 2a90053eee
24 changed files with 1498 additions and 420 deletions
+106 -3
View File
@@ -5,6 +5,7 @@ import { openMenu, closeMenu, openModal, wireModalClose, menu } from "./ui.js";
import {
registerRenderer,
loadWithOptions,
renderCachedClients,
startAutoRefresh,
sendCommand,
requestPreview,
@@ -16,14 +17,18 @@ import { ThumbnailLoader } from "./thumbnail-loader.js";
const grid = document.getElementById("grid");
const totalPill = document.getElementById("total-pill");
const pageLabel = document.getElementById("page-label");
const pageTotal = document.getElementById("page-total");
const prevBtn = document.getElementById("prev");
const nextBtn = document.getElementById("next");
const pageJumpForm = document.getElementById("page-jump-form");
const pageJumpInput = document.getElementById("page-jump-input");
const searchInput = document.getElementById("search");
const sortSelect = document.getElementById("sort");
const filterStatusSelect = document.getElementById("filter-status");
const filterOsSelect = document.getElementById("filter-os");
const filterGroupSelect = document.getElementById("filter-group");
const showOfflineToggle = document.getElementById("toggle-offline");
const displayFieldsMenu = document.getElementById("display-fields-menu");
const selectAllBtn = document.getElementById("select-all");
const clearSelectionBtn = document.getElementById("clear-selection");
const logoutBtn = document.getElementById("logout-btn");
@@ -50,10 +55,38 @@ const PREF_SORT_KEY = "overlord_sort";
const PREF_FILTER_OS_KEY = "overlord_filter_os";
const PREF_FILTER_COUNTRY_KEY = "overlord_filter_country";
const PREF_FILTER_GROUP_KEY = "overlord_filter_group";
const PREF_DISPLAY_FIELDS_KEY = "overlord_display_fields";
const DEFAULT_DISPLAY_FIELDS = {
user: true,
ip: true,
hwid: false,
system: true,
version: true,
monitors: true,
group: true,
hardware: true,
battery: true,
};
let displayFields = { ...DEFAULT_DISPLAY_FIELDS };
let currentUser = null;
let contextCard = null;
let availableOsList = new Set();
let rendererInitialized = false;
let lastKnownTotalPages = 1;
window.setDashboardPageBounds = (currentPage, totalPages) => {
lastKnownTotalPages = Math.max(1, Number(totalPages) || 1);
const safeCurrentPage = Math.max(1, Number(currentPage) || 1);
if (pageLabel) pageLabel.textContent = "Page";
if (pageTotal) pageTotal.textContent = String(lastKnownTotalPages);
if (!pageJumpInput) return;
pageJumpInput.max = String(lastKnownTotalPages);
pageJumpInput.style.width = `${Math.min(8, Math.max(2, String(lastKnownTotalPages).length, String(safeCurrentPage).length)) + 2}ch`;
if (document.activeElement !== pageJumpInput) {
pageJumpInput.value = String(safeCurrentPage);
}
};
function setServerVersionLabel(version) {
if (!serverVersionText) return;
@@ -667,13 +700,69 @@ function setLayout(layout) {
applyLayoutToggleUI(next);
if (rendererSetLayout) rendererSetLayout(next);
state.lastDigest = "";
loadWithOptions({ force: true, reorder: true });
if (!renderCachedClients({ reorder: true, force: true })) {
loadWithOptions({ force: true, reorder: true });
}
}
document.querySelectorAll("#layout-toggle .layout-toggle-btn").forEach((btn) => {
btn.addEventListener("click", () => setLayout(btn.dataset.layout));
});
function loadDisplayFields() {
try {
const saved = JSON.parse(localStorage.getItem(PREF_DISPLAY_FIELDS_KEY) || "null");
if (saved && typeof saved === "object") {
displayFields = { ...DEFAULT_DISPLAY_FIELDS, ...saved };
}
} catch {
displayFields = { ...DEFAULT_DISPLAY_FIELDS };
}
}
function syncDisplayFieldInputs() {
displayFieldsMenu?.querySelectorAll("input[data-field]").forEach((input) => {
input.checked = displayFields[input.dataset.field] !== false;
});
}
function saveDisplayFields() {
localStorage.setItem(PREF_DISPLAY_FIELDS_KEY, JSON.stringify(displayFields));
}
function rerenderDisplayFields() {
state.lastDigest = "";
if (!renderCachedClients({ reorder: true, force: true })) {
loadWithOptions({ force: true, reorder: true });
}
}
loadDisplayFields();
syncDisplayFieldInputs();
displayFieldsMenu?.addEventListener("change", (e) => {
const input = e.target.closest("input[data-field]");
if (!input) return;
displayFields[input.dataset.field] = input.checked;
saveDisplayFields();
rerenderDisplayFields();
});
document.addEventListener("click", (e) => {
document.querySelectorAll(".dashboard-menu[open]").forEach((details) => {
if (!details.contains(e.target)) details.removeAttribute("open");
});
});
document.querySelectorAll(".dashboard-menu").forEach((details) => {
details.addEventListener("toggle", () => {
if (!details.open) return;
document.querySelectorAll(".dashboard-menu[open]").forEach((other) => {
if (other !== details) other.removeAttribute("open");
});
});
});
let dashboardThumbnailLoader = null;
async function isDashboardThumbnailEnabled() {
@@ -729,6 +818,8 @@ async function setupDashboardThumbnailLoader() {
}
function initializeRenderer() {
if (rendererInitialized) return;
rendererInitialized = true;
const savedLayout = localStorage.getItem(PREF_LAYOUT_KEY) || "rows";
if (grid) grid.dataset.layout = ["rows", "table", "cards"].includes(savedLayout) ? savedLayout : "rows";
applyLayoutToggleUI(grid?.dataset.layout || "rows");
@@ -750,6 +841,7 @@ function initializeRenderer() {
requestThumbnail,
pingClient: (id) => sendCommand(id, "ping"),
userRole: currentUser?.role,
getDisplayFields: () => displayFields,
});
rendererSetLayout = rSetLayout;
registerRenderer(renderMerge);
@@ -758,7 +850,7 @@ function initializeRenderer() {
loadWithOptions();
startAutoRefresh();
if (typeof anime !== "undefined") {
if (typeof anime !== "undefined" && !document.documentElement.classList.contains("large-client-set")) {
anime
.timeline({ easing: "easeOutQuad" })
.add({
@@ -874,7 +966,7 @@ import("./country-picker.js").then(({ initCountryPicker }) => {
}
const savedSort = localStorage.getItem(PREF_SORT_KEY);
const validSorts = ["stable", "last_seen_desc", "host_asc", "ping_asc", "ping_desc", "country_asc", "country_desc", "group_asc", "group_desc"];
const validSorts = ["stable", "last_seen_desc", "host_asc", "ping_asc", "ping_desc", "country_asc", "country_desc", "group_asc", "group_desc", "admin_first"];
if (savedSort && validSorts.includes(savedSort)) {
state.sort = savedSort;
if (sortSelect) sortSelect.value = savedSort;
@@ -1448,6 +1540,17 @@ nextBtn?.addEventListener("click", () => {
loadWithOptions({ force: true, reorder: true });
});
pageJumpForm?.addEventListener("submit", (e) => {
e.preventDefault();
const requested = Math.trunc(Number(pageJumpInput?.value || 1));
const targetPage = Math.min(lastKnownTotalPages, Math.max(1, Number.isFinite(requested) ? requested : 1));
if (pageJumpInput) pageJumpInput.value = String(targetPage);
if (targetPage === state.page) return;
state.page = targetPage;
state.lastDigest = "";
loadWithOptions({ force: true, reorder: true });
});
window.addEventListener("click", (e) => {
const target = e.target;
if (target.closest && target.closest(".command-btn")) return;