v0.33.7
This commit is contained in:
1 parent
162e986d37
commit
6b937aaf85
54 files changed
+3527
-1325
No files matched your search
@@ -162,7 +162,7 @@ window.rustProxyInlineLayout = (() => {
|
||||
draft = original = null;
|
||||
}
|
||||
async function begin() {
|
||||
if (draft || opening || saving || $("overview-layout-dialog")?.open) return;
|
||||
if (draft || opening || saving || $("overview-presets-dialog")?.open) return;
|
||||
opening = true;
|
||||
unlock.disabled = true;
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
window.rustProxyDashboardLayout = (() => {
|
||||
const dialog = $("overview-presets-dialog");
|
||||
const list = $("overview-presets-list");
|
||||
const input = $("overview-presets-name");
|
||||
const message = $("overview-presets-message");
|
||||
const save = $("overview-presets-save");
|
||||
const factory = $("overview-presets-factory");
|
||||
const close = $("overview-presets-close");
|
||||
let presets = [];
|
||||
let busy = false;
|
||||
|
||||
const presetPath = name => `/api/dashboard-presets/${encodeURIComponent(name)}`;
|
||||
const nameValid = name => name.length > 0 && new TextEncoder().encode(name).length <= 64
|
||||
&& !/[\x00-\x1f\x7f/]/.test(name);
|
||||
const snapshot = () => {
|
||||
const current = window.rustProxyPreferences.current() || ADMIN_APPEARANCE_DEFAULTS;
|
||||
return {
|
||||
dashboard_widgets: [...normalizeDashboardWidgets(current.dashboard_widgets)],
|
||||
dashboard_hidden_widgets: [...normalizeHiddenDashboardWidgets(current.dashboard_hidden_widgets)],
|
||||
dashboard_widget_sizes: normalizeDashboardWidgetSizes(current.dashboard_widget_sizes),
|
||||
dashboard_density: normalizeAdminDensity(current.dashboard_density, "compact"),
|
||||
overview_samples: window.rustProxyOverviewSamples.getLimit(),
|
||||
};
|
||||
};
|
||||
const translateName = (key, name) => t(key).replace("{name}", name);
|
||||
function notify(key, isError = false) {
|
||||
message.textContent = isError ? key : t(key);
|
||||
message.classList.toggle("error", isError);
|
||||
}
|
||||
function lock(value) {
|
||||
busy = value;
|
||||
for (const control of [save, factory, close, input, ...list.querySelectorAll("button")])
|
||||
if (control) control.disabled = value;
|
||||
}
|
||||
async function run(fn) {
|
||||
if (busy) return;
|
||||
lock(true);
|
||||
try { await fn(); }
|
||||
catch (error) {
|
||||
const message = error.status === 409
|
||||
? (String(error.code || "").includes("limit (16)")
|
||||
? t("dashboardPresetsLimit") : t("dashboardPresetsConflict"))
|
||||
: (error.message || String(error));
|
||||
notify(message, true);
|
||||
}
|
||||
finally { lock(false); }
|
||||
}
|
||||
async function reload() {
|
||||
presets = await api("/api/dashboard-presets");
|
||||
render();
|
||||
}
|
||||
function entryButton(key, className, fn, presetName) {
|
||||
const button = el("button", t(key), className);
|
||||
button.type = "button";
|
||||
button.setAttribute("aria-label", `${t(key)}: ${presetName}`);
|
||||
button.dataset.presetAction = key;
|
||||
button.addEventListener("click", () => void run(fn));
|
||||
return button;
|
||||
}
|
||||
function render() {
|
||||
const elements = presets.map(preset => {
|
||||
const row = el("div", undefined, "overview-presets-row");
|
||||
row.setAttribute("role", "listitem");
|
||||
const actions = el("div", undefined, "overview-presets-actions");
|
||||
actions.append(
|
||||
entryButton("dashboardPresetsLoad", "primary", async () => {
|
||||
await apply(preset);
|
||||
dialog.close();
|
||||
toast(t("dashboardPresetsLoaded"));
|
||||
}, preset.name),
|
||||
entryButton("dashboardPresetsOverwrite", "outline", async () => {
|
||||
if (!(await appConfirm(translateName("dashboardPresetsOverwriteConfirm", preset.name)))) return;
|
||||
await api(presetPath(preset.name), { method: "PUT", body: JSON.stringify(snapshot()) });
|
||||
await reload(); notify("dashboardPresetsSaved");
|
||||
}, preset.name),
|
||||
entryButton("dashboardPresetsRename", "quiet", async () => {
|
||||
const name = input.value.trim();
|
||||
if (!nameValid(name)) { notify("dashboardPresetsNameRequired"); return; }
|
||||
if (name === preset.name) return;
|
||||
await api(presetPath(preset.name), { method: "PATCH", body: JSON.stringify({ name }) });
|
||||
input.value = "";
|
||||
await reload(); notify("dashboardPresetsRenamed");
|
||||
}, preset.name),
|
||||
entryButton("dashboardPresetsDelete", "quiet", async () => {
|
||||
if (!(await appConfirm(translateName("dashboardPresetsDeleteConfirm", preset.name), { danger: true }))) return;
|
||||
await api(presetPath(preset.name), { method: "DELETE" });
|
||||
await reload(); notify("dashboardPresetsDeleted");
|
||||
}, preset.name),
|
||||
);
|
||||
row.append(el("strong", preset.name), actions);
|
||||
return row;
|
||||
});
|
||||
list.replaceChildren(...(elements.length ? elements : [el("p", t("dashboardPresetsEmpty"), "fine")]));
|
||||
}
|
||||
async function apply(layout) {
|
||||
await window.rustProxyPreferences.update({
|
||||
dashboard_widgets: [...layout.dashboard_widgets],
|
||||
dashboard_hidden_widgets: [...layout.dashboard_hidden_widgets],
|
||||
dashboard_widget_sizes: layout.dashboard_widget_sizes === null ? null : { ...layout.dashboard_widget_sizes },
|
||||
dashboard_density: layout.dashboard_density,
|
||||
});
|
||||
window.rustProxyOverviewSamples.setLimit(layout.overview_samples, true);
|
||||
}
|
||||
async function open() {
|
||||
if (dialog?.open || busy || window.rustProxyInlineLayout?.isEditing?.()) return;
|
||||
await run(async () => {
|
||||
await window.rustProxyPreferences.load();
|
||||
await reload();
|
||||
input.value = "";
|
||||
notify("");
|
||||
dialog.showModal();
|
||||
input.focus();
|
||||
});
|
||||
}
|
||||
save?.addEventListener("click", () => void run(async () => {
|
||||
const name = input.value.trim();
|
||||
if (!nameValid(name)) { notify("dashboardPresetsNameRequired"); return; }
|
||||
if (presets.length >= 16 && !presets.some(preset => preset.name === name)) {
|
||||
notify("dashboardPresetsLimit"); return;
|
||||
}
|
||||
if (presets.some(preset => preset.name === name)
|
||||
&& !(await appConfirm(translateName("dashboardPresetsOverwriteConfirm", name)))) return;
|
||||
await api(presetPath(name), { method: "PUT", body: JSON.stringify(snapshot()) });
|
||||
input.value = "";
|
||||
await reload(); notify("dashboardPresetsSaved");
|
||||
}));
|
||||
factory?.addEventListener("click", () => void run(async () => {
|
||||
if (!(await appConfirm(t("dashboardPresetsResetConfirm")))) return;
|
||||
await apply({
|
||||
dashboard_widgets: [...ADMIN_DASHBOARD_WIDGETS],
|
||||
dashboard_hidden_widgets: [...ADMIN_DEFAULT_HIDDEN_WIDGETS],
|
||||
dashboard_widget_sizes: null,
|
||||
dashboard_density: ADMIN_DASHBOARD_DEFAULTS.dashboard_density,
|
||||
overview_samples: ADMIN_DASHBOARD_DEFAULTS.overview_samples,
|
||||
});
|
||||
dialog.close();
|
||||
toast(t("dashboardPresetsRestored"));
|
||||
}));
|
||||
close?.addEventListener("click", () => { if (!busy) dialog.close(); });
|
||||
dialog?.addEventListener("cancel", event => { if (busy) event.preventDefault(); });
|
||||
for (const id of ["overview-layout-open", "overview-layout-open-settings"])
|
||||
$(id)?.addEventListener("click", () => { void open(); });
|
||||
return { open, refresh: () => { if (dialog?.open) render(); } };
|
||||
})();
|
||||
Reference in new issue
Block a user