264 lines
8.0 KiB
JavaScript
264 lines
8.0 KiB
JavaScript
// Admin dashboard utilities
|
|
|
|
// Format JSON for display in modals
|
|
function formatJSON(json) {
|
|
try {
|
|
const parsed = typeof json === "string" ? JSON.parse(json) : json;
|
|
return JSON.stringify(parsed, null, 2);
|
|
} catch (e) {
|
|
return json;
|
|
}
|
|
}
|
|
|
|
// Initialize flatpickr for all date inputs
|
|
function initFlatpickr() {
|
|
document.querySelectorAll(".flatpickr-date").forEach(function (input) {
|
|
if (!input._flatpickr) {
|
|
flatpickr(input, {
|
|
dateFormat: "d/m/Y",
|
|
allowInput: true,
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// Submit the audit filter form with specific page/perPage/order params
|
|
function submitAuditFilter(page, perPage, order, orderBy) {
|
|
const form = document.getElementById("audit-filters-form");
|
|
if (!form) return;
|
|
|
|
// Create hidden inputs for pagination/sorting if they don't exist
|
|
let pageInput = form.querySelector('input[name="page"]');
|
|
if (!pageInput) {
|
|
pageInput = document.createElement("input");
|
|
pageInput.type = "hidden";
|
|
pageInput.name = "page";
|
|
form.appendChild(pageInput);
|
|
}
|
|
pageInput.value = page;
|
|
|
|
let perPageInput = form.querySelector('input[name="per_page"]');
|
|
if (!perPageInput) {
|
|
perPageInput = document.createElement("input");
|
|
perPageInput.type = "hidden";
|
|
perPageInput.name = "per_page";
|
|
form.appendChild(perPageInput);
|
|
}
|
|
perPageInput.value = perPage;
|
|
|
|
let orderInput = form.querySelector('input[name="order"]');
|
|
if (!orderInput) {
|
|
orderInput = document.createElement("input");
|
|
orderInput.type = "hidden";
|
|
orderInput.name = "order";
|
|
form.appendChild(orderInput);
|
|
}
|
|
orderInput.value = order;
|
|
|
|
let orderByInput = form.querySelector('input[name="order_by"]');
|
|
if (!orderByInput) {
|
|
orderByInput = document.createElement("input");
|
|
orderByInput.type = "hidden";
|
|
orderByInput.name = "order_by";
|
|
form.appendChild(orderByInput);
|
|
}
|
|
orderByInput.value = orderBy;
|
|
|
|
htmx.trigger(form, "submit");
|
|
}
|
|
|
|
// Sort by column - toggle direction if same column
|
|
function sortAuditColumn(field, currentOrder, currentOrderBy) {
|
|
const page = 1; // Reset to first page when sorting
|
|
const perPageSelect = document.getElementById("per-page-select");
|
|
const perPage = perPageSelect ? parseInt(perPageSelect.value) || 25 : 25;
|
|
let newOrder, newOrderBy;
|
|
|
|
if (currentOrderBy === field) {
|
|
// Toggle order
|
|
newOrder = currentOrder === "ASC" ? "DESC" : "ASC";
|
|
newOrderBy = field;
|
|
} else {
|
|
// New column, default to DESC
|
|
newOrder = "DESC";
|
|
newOrderBy = field;
|
|
}
|
|
|
|
submitAuditFilter(page, perPage, newOrder, newOrderBy);
|
|
}
|
|
|
|
// Clear all audit filters
|
|
function clearAuditFilters() {
|
|
const form = document.getElementById("audit-filters-form");
|
|
if (!form) return;
|
|
|
|
form.reset();
|
|
|
|
// Clear flatpickr instances
|
|
document.querySelectorAll(".flatpickr-date").forEach(function (input) {
|
|
var fp = input._flatpickr;
|
|
if (fp) fp.clear();
|
|
});
|
|
|
|
// Clear multi-select dropdowns
|
|
document.querySelectorAll(".multi-select-container").forEach(function (container) {
|
|
var hiddenInput = container.querySelector('input[type="hidden"]');
|
|
if (hiddenInput) hiddenInput.value = "";
|
|
var selectedDisplay = container.querySelector(".multi-select-selected");
|
|
if (selectedDisplay)
|
|
selectedDisplay.innerHTML = '<span class="text-subtext1">Select...</span>';
|
|
container.querySelectorAll(".multi-select-option").forEach(function (opt) {
|
|
opt.classList.remove("bg-blue", "text-mantle");
|
|
opt.classList.add("hover:bg-surface1");
|
|
});
|
|
});
|
|
|
|
// Trigger form submission with reset pagination
|
|
submitAuditFilter(1, 25, "DESC", "created_at");
|
|
}
|
|
|
|
// Toggle multi-select dropdown visibility
|
|
function toggleMultiSelect(containerId) {
|
|
var dropdown = document.getElementById(containerId + "-dropdown");
|
|
if (dropdown) {
|
|
dropdown.classList.toggle("hidden");
|
|
}
|
|
}
|
|
|
|
// Toggle multi-select option selection
|
|
function toggleMultiSelectOption(containerId, value, label) {
|
|
var container = document.getElementById(containerId);
|
|
var hiddenInput = container.querySelector('input[type="hidden"]');
|
|
var selectedDisplay = container.querySelector(".multi-select-selected");
|
|
|
|
var values = hiddenInput.value ? hiddenInput.value.split(",") : [];
|
|
var index = values.indexOf(value);
|
|
|
|
if (index > -1) {
|
|
values.splice(index, 1);
|
|
} else {
|
|
values.push(value);
|
|
}
|
|
|
|
hiddenInput.value = values.join(",");
|
|
|
|
var option = container.querySelector('[data-value="' + value + '"]');
|
|
if (option) {
|
|
if (index > -1) {
|
|
option.classList.remove("bg-blue", "text-mantle");
|
|
option.classList.add("hover:bg-surface1");
|
|
} else {
|
|
option.classList.add("bg-blue", "text-mantle");
|
|
option.classList.remove("hover:bg-surface1");
|
|
}
|
|
}
|
|
|
|
if (values.length === 0) {
|
|
selectedDisplay.innerHTML = '<span class="text-subtext1">Select...</span>';
|
|
} else if (values.length === 1) {
|
|
selectedDisplay.innerHTML = "<span>" + label + "</span>";
|
|
} else {
|
|
selectedDisplay.innerHTML = "<span>" + values.length + " selected</span>";
|
|
}
|
|
|
|
// Trigger form submission
|
|
document.getElementById("audit-filters-form").requestSubmit();
|
|
}
|
|
|
|
// Submit the users page with specific page/perPage/order params
|
|
function submitUsersPage(page, perPage, order, orderBy) {
|
|
const formData = new FormData();
|
|
formData.append("page", page);
|
|
formData.append("per_page", perPage);
|
|
formData.append("order", order);
|
|
formData.append("order_by", orderBy);
|
|
|
|
htmx.ajax("POST", "/admin/users", {
|
|
target: "#users-list-container",
|
|
swap: "outerHTML",
|
|
values: Object.fromEntries(formData),
|
|
});
|
|
}
|
|
|
|
// Sort users column - toggle direction if same column
|
|
function sortUsersColumn(field, currentOrder, currentOrderBy) {
|
|
const page = 1; // Reset to first page when sorting
|
|
const perPageSelect = document.getElementById("users-per-page-select");
|
|
const perPage = perPageSelect ? parseInt(perPageSelect.value) || 25 : 25;
|
|
let newOrder, newOrderBy;
|
|
|
|
if (currentOrderBy === field) {
|
|
// Toggle order
|
|
newOrder = currentOrder === "ASC" ? "DESC" : "ASC";
|
|
newOrderBy = field;
|
|
} else {
|
|
// New column, default to ASC
|
|
newOrder = "ASC";
|
|
newOrderBy = field;
|
|
}
|
|
|
|
submitUsersPage(page, perPage, newOrder, newOrderBy);
|
|
}
|
|
|
|
// Submit the roles page with specific page/perPage/order params
|
|
function submitRolesPage(page, perPage, order, orderBy) {
|
|
const formData = new FormData();
|
|
formData.append("page", page);
|
|
formData.append("per_page", perPage);
|
|
formData.append("order", order);
|
|
formData.append("order_by", orderBy);
|
|
|
|
htmx.ajax("POST", "/admin/roles", {
|
|
target: "#roles-list-container",
|
|
swap: "outerHTML",
|
|
values: Object.fromEntries(formData),
|
|
});
|
|
}
|
|
|
|
// Sort roles column - toggle direction if same column
|
|
function sortRolesColumn(field, currentOrder, currentOrderBy) {
|
|
const page = 1; // Reset to first page when sorting
|
|
const perPageSelect = document.getElementById("roles-per-page-select");
|
|
const perPage = perPageSelect ? parseInt(perPageSelect.value) || 25 : 25;
|
|
let newOrder, newOrderBy;
|
|
|
|
if (currentOrderBy === field) {
|
|
// Toggle order
|
|
newOrder = currentOrder === "ASC" ? "DESC" : "ASC";
|
|
newOrderBy = field;
|
|
} else {
|
|
// New column, default to ASC
|
|
newOrder = "ASC";
|
|
newOrderBy = field;
|
|
}
|
|
|
|
submitRolesPage(page, perPage, newOrder, newOrderBy);
|
|
}
|
|
|
|
// Handle HTMX navigation and initialization
|
|
// Tab navigation active state is handled by tabs.js (generic).
|
|
// This file only handles admin-specific concerns (flatpickr, multi-select).
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
// Initialize flatpickr on page load
|
|
initFlatpickr();
|
|
|
|
document.body.addEventListener("htmx:afterSwap", function (event) {
|
|
// Re-initialize flatpickr after admin content swap
|
|
if (
|
|
event.detail.target.id === "admin-content" ||
|
|
event.detail.target.id === "audit-results-container"
|
|
) {
|
|
initFlatpickr();
|
|
}
|
|
});
|
|
|
|
// Close multi-select dropdowns when clicking outside
|
|
document.addEventListener("click", function (evt) {
|
|
if (!evt.target.closest(".multi-select-container")) {
|
|
document.querySelectorAll(".multi-select-dropdown").forEach(function (d) {
|
|
d.classList.add("hidden");
|
|
});
|
|
}
|
|
});
|
|
});
|