143 lines
7.3 KiB
JavaScript
143 lines
7.3 KiB
JavaScript
window.rustProxyDashboardLayout = (() => {
|
|
const dialog = $("overview-layout-dialog");
|
|
const nameInput = $("overview-preset-name");
|
|
const saveButton = $("overview-preset-save");
|
|
const list = $("overview-preset-list");
|
|
const empty = $("overview-preset-empty");
|
|
const count = $("overview-preset-count");
|
|
const message = $("overview-layout-message");
|
|
const closeButton = $("overview-layout-cancel");
|
|
const MAX_PRESETS = 20;
|
|
let busy = false;
|
|
let opening = false;
|
|
|
|
const current = () => window.rustProxyPreferences?.current?.() || ADMIN_APPEARANCE_DEFAULTS;
|
|
const presets = () => normalizeDashboardPresets(current().dashboard_presets);
|
|
const densityLabel = value => t({ normal: "densityNormal", compact: "densityCompact", ultra: "densityUltra" }[value] || "densityCompact");
|
|
function snapshot(name) {
|
|
const prefs = current();
|
|
const order = normalizeDashboardWidgets(prefs.dashboard_widgets);
|
|
return {
|
|
name,
|
|
dashboard_density: normalizeAdminDensity(prefs.dashboard_density, "compact"),
|
|
dashboard_widgets: order,
|
|
dashboard_hidden_widgets: normalizeHiddenDashboardWidgets(prefs.dashboard_hidden_widgets, prefs.dashboard_widgets),
|
|
dashboard_widget_sizes: normalizeDashboardWidgetSizes(prefs.dashboard_widget_sizes),
|
|
};
|
|
}
|
|
function summary(preset) {
|
|
const visible = preset.dashboard_widgets.length - preset.dashboard_hidden_widgets.length;
|
|
const widths = Object.keys(preset.dashboard_widget_sizes || {}).length;
|
|
return t("dashboardPresetSummary")
|
|
.replace("{visible}", String(visible))
|
|
.replace("{density}", densityLabel(preset.dashboard_density))
|
|
.replace("{widths}", String(widths));
|
|
}
|
|
function setBusy(value) {
|
|
busy = value;
|
|
if (nameInput) nameInput.disabled = value;
|
|
if (closeButton) closeButton.disabled = value;
|
|
render();
|
|
}
|
|
async function saveCurrent() {
|
|
const name = (nameInput?.value || "").trim();
|
|
if (busy || !name) return;
|
|
const next = presets();
|
|
const key = name.toLowerCase();
|
|
const index = next.findIndex(preset => preset.name.toLowerCase() === key);
|
|
if (index < 0 && next.length >= MAX_PRESETS) {
|
|
message.textContent = t("dashboardPresetLimitReached").replace("{max}", String(MAX_PRESETS));
|
|
return;
|
|
}
|
|
const value = snapshot(name);
|
|
if (index >= 0) next[index] = value;
|
|
else next.unshift(value);
|
|
setBusy(true);
|
|
message.textContent = t("dashboardPresetSaving");
|
|
try {
|
|
await window.rustProxyPreferences.update({ dashboard_presets: next });
|
|
if (nameInput) nameInput.value = "";
|
|
message.textContent = t(index >= 0 ? "dashboardPresetUpdated" : "dashboardPresetSavedMessage").replace("{name}", name);
|
|
toast(message.textContent);
|
|
} catch (error) { message.textContent = error.message; }
|
|
finally { setBusy(false); }
|
|
}
|
|
async function loadPreset(preset) {
|
|
if (busy) return;
|
|
setBusy(true);
|
|
message.textContent = t("dashboardPresetLoading").replace("{name}", preset.name);
|
|
try {
|
|
await window.rustProxyPreferences.update({
|
|
dashboard_density: preset.dashboard_density,
|
|
dashboard_widgets: [...preset.dashboard_widgets],
|
|
dashboard_hidden_widgets: [...preset.dashboard_hidden_widgets],
|
|
dashboard_widget_sizes: preset.dashboard_widget_sizes === null ? null : { ...preset.dashboard_widget_sizes },
|
|
});
|
|
dialog.close();
|
|
toast(t("dashboardPresetLoaded").replace("{name}", preset.name));
|
|
} catch (error) { message.textContent = error.message; }
|
|
finally { setBusy(false); }
|
|
}
|
|
async function deletePreset(preset) {
|
|
if (busy || !confirm(t("dashboardPresetDeleteConfirm").replace("{name}", preset.name))) return;
|
|
setBusy(true);
|
|
message.textContent = t("dashboardPresetDeleting").replace("{name}", preset.name);
|
|
try {
|
|
const next = presets().filter(item => item.name.toLowerCase() !== preset.name.toLowerCase());
|
|
await window.rustProxyPreferences.update({ dashboard_presets: next });
|
|
message.textContent = t("dashboardPresetDeleted").replace("{name}", preset.name);
|
|
} catch (error) { message.textContent = error.message; }
|
|
finally { setBusy(false); }
|
|
}
|
|
function presetRow(preset) {
|
|
const row = el("article", undefined, "dashboard-preset-row");
|
|
row.setAttribute("role", "listitem");
|
|
const info = el("div", undefined, "dashboard-preset-info");
|
|
info.append(el("strong", preset.name), el("small", summary(preset), "fine"));
|
|
const actions = el("div", undefined, "dashboard-preset-actions");
|
|
const load = el("button", t("dashboardPresetLoad"), "outline");
|
|
load.type = "button"; load.disabled = busy;
|
|
load.setAttribute("aria-label", `${t("dashboardPresetLoad")}: ${preset.name}`);
|
|
load.addEventListener("click", () => { void loadPreset(preset); });
|
|
const remove = el("button", t("dashboardPresetDelete"), "quiet");
|
|
remove.type = "button"; remove.disabled = busy;
|
|
remove.setAttribute("aria-label", `${t("dashboardPresetDelete")}: ${preset.name}`);
|
|
remove.addEventListener("click", () => { void deletePreset(preset); });
|
|
actions.append(load, remove);
|
|
row.append(info, actions);
|
|
return row;
|
|
}
|
|
function render() {
|
|
if (!dialog || !list) return;
|
|
const values = presets();
|
|
list.replaceChildren(...values.map(presetRow));
|
|
if (empty) empty.hidden = values.length > 0;
|
|
if (count) count.textContent = t("dashboardPresetCount").replace("{count}", String(values.length)).replace("{max}", String(MAX_PRESETS));
|
|
if (saveButton) saveButton.disabled = busy || !(nameInput?.value || "").trim();
|
|
if (nameInput) nameInput.disabled = busy;
|
|
if (closeButton) closeButton.disabled = busy;
|
|
}
|
|
async function open() {
|
|
if (dialog?.open || opening || window.rustProxyInlineLayout?.isEditing?.()) return;
|
|
opening = true;
|
|
try { await window.rustProxyPreferences?.load?.(); }
|
|
catch (error) { if (error?.status === 401) { opening = false; return; } message.textContent = error.message; }
|
|
opening = false;
|
|
if (nameInput) nameInput.value = "";
|
|
message.textContent = "";
|
|
render();
|
|
dialog.showModal();
|
|
nameInput?.focus();
|
|
}
|
|
for (const id of ["overview-layout-open", "overview-layout-open-settings"]) $(id)?.addEventListener("click", () => { void open(); });
|
|
nameInput?.addEventListener("input", render);
|
|
nameInput?.addEventListener("keydown", event => {
|
|
if (event.key === "Enter" && !saveButton?.disabled) { event.preventDefault(); void saveCurrent(); }
|
|
});
|
|
saveButton?.addEventListener("click", () => { void saveCurrent(); });
|
|
closeButton?.addEventListener("click", () => { if (!busy) dialog.close(); });
|
|
dialog?.addEventListener("cancel", event => { if (busy) event.preventDefault(); });
|
|
dialog?.addEventListener("close", () => { message.textContent = ""; });
|
|
return { open, refresh: () => { if (dialog?.open) render(); } };
|
|
})();
|