v0.33.3
This commit is contained in:
1 parent
5a36bb0c4b
commit
78ad28ef4d
27 files changed
+1448
-234
No files matched your search
@@ -13,7 +13,7 @@ const ADMIN_DEFAULT_HIDDEN_WIDGETS = Object.freeze([...new Set([
|
||||
])]);
|
||||
const ADMIN_APPEARANCE_DEFAULTS = Object.freeze({
|
||||
theme: "dark", language: "auto", ui_scale: 100, time_format: "24h", chart_style: "default",
|
||||
button_style: "normal", corner_style: "default", table_density: "normal", dashboard_density: ADMIN_DASHBOARD_DEFAULTS.dashboard_density, dashboard_widgets: [...ADMIN_DASHBOARD_WIDGETS], dashboard_hidden_widgets: [...ADMIN_DEFAULT_HIDDEN_WIDGETS],
|
||||
button_style: "normal", corner_style: "default", table_density: "normal", dashboard_density: ADMIN_DASHBOARD_DEFAULTS.dashboard_density, dashboard_widgets: [...ADMIN_DASHBOARD_WIDGETS], dashboard_hidden_widgets: [...ADMIN_DEFAULT_HIDDEN_WIDGETS], dashboard_widget_sizes: null,
|
||||
});
|
||||
const CHART_STYLE_KEYS = Object.freeze({ default: "chartStyleDefault", soft: "chartStyleSoft", technical: "chartStyleTechnical", high_contrast: "chartStyleHighContrast", neon: "chartStyleNeon", monochrome: "chartStyleMonochrome", warm: "chartStyleWarm", cool: "chartStyleCool" });
|
||||
let adminPreferences = null, adminPreferencesLoading = null, adminPreferencesWrite = Promise.resolve(), adminPreferencesUnavailable = false;
|
||||
@@ -41,6 +41,47 @@ function normalizeHiddenDashboardWidgets(value, savedOrder = ADMIN_DASHBOARD_WID
|
||||
}
|
||||
return hidden;
|
||||
}
|
||||
// An absent map preserves the previous grouped visual order after upgrading.
|
||||
// An explicit object (even empty) opts into free ordering and card resizing.
|
||||
const DASHBOARD_WIDTHS = Object.freeze([2, 3, 4, 6, 12]);
|
||||
function dashboardAllowedWidths(id) {
|
||||
switch (dashboardWidgetType(id)) {
|
||||
case "table": return [6, 12];
|
||||
case "panel": return [4, 6, 12];
|
||||
case "chart": return [3, 4, 6, 12];
|
||||
default: return DASHBOARD_WIDTHS;
|
||||
}
|
||||
}
|
||||
function dashboardDefaultWidth(id) {
|
||||
const node = document.querySelector(`#dashboard-overview-grid [data-dashboard-widget="${id}"]`);
|
||||
if (!node) return 2;
|
||||
if (node.classList.contains("pool-card")) return 12;
|
||||
if (node.classList.contains("overview-wide-chart")) return 6;
|
||||
if (node.classList.contains("stat")) return 2;
|
||||
return 4;
|
||||
}
|
||||
function normalizeDashboardWidgetSizes(value) {
|
||||
if (value === null || value === undefined) return null;
|
||||
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
||||
const result = {};
|
||||
for (const [id, span] of Object.entries(value)) {
|
||||
if (ADMIN_DASHBOARD_BY_ID.has(id) && dashboardAllowedWidths(id).includes(span)
|
||||
&& span !== dashboardDefaultWidth(id)) result[id] = span;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function dashboardWidgetWidth(id, sizes) {
|
||||
return sizes?.[id] ?? dashboardDefaultWidth(id);
|
||||
}
|
||||
function dashboardVisualOrder(order, sizes = null) {
|
||||
const normalized = normalizeDashboardWidgets(order);
|
||||
if (sizes !== null) return normalized;
|
||||
// Preserve the old grouped appearance until the first intentional edit.
|
||||
return normalized.map((id, index) => ({ id, index }))
|
||||
.sort((a, b) => (window.rustProxyMasonry?.groupFor?.(a.id) ?? 0) -
|
||||
(window.rustProxyMasonry?.groupFor?.(b.id) ?? 0) || a.index - b.index)
|
||||
.map(item => item.id);
|
||||
}
|
||||
function browserLanguage() {
|
||||
const packs = [...languagePacks.values()], candidates = (navigator.languages || [navigator.language]).filter(Boolean).map(value => value.replaceAll("_", "-").toLowerCase());
|
||||
return candidates.map(value => packs.find(pack => pack.meta.locale.toLowerCase() === value || pack.id.replaceAll("_", "-").toLowerCase() === value) || packs.find(pack => pack.meta.locale.toLowerCase().split("-")[0] === value.split("-")[0])).find(Boolean)?.id || defaultLanguage;
|
||||
@@ -96,19 +137,25 @@ function applyAdminDashboardDensity(value) {
|
||||
const density = normalizeAdminDensity(value, "compact"); document.documentElement.dataset.dashboardDensity = density;
|
||||
const select = $("ui-dashboard-density"); if (select) select.value = density; return density;
|
||||
}
|
||||
function applyDashboardLayout(order, hidden) {
|
||||
function applyDashboardLayout(order, hidden, sizes = null) {
|
||||
const normalizedOrder = normalizeDashboardWidgets(order), hiddenSet = new Set(normalizeHiddenDashboardWidgets(hidden));
|
||||
const grid = document.querySelector("#panel-overview .stats-grid"); if (!grid) return { order: normalizedOrder, hidden: [...hiddenSet] };
|
||||
const widths = normalizeDashboardWidgetSizes(sizes);
|
||||
const grid = document.querySelector("#panel-overview .stats-grid");
|
||||
if (!grid) return { order: normalizedOrder, hidden: [...hiddenSet], sizes: widths };
|
||||
grid.dataset.overviewLayoutMode = widths === null ? "legacy" : "custom";
|
||||
const nodes = new Map([...grid.querySelectorAll("[data-dashboard-widget]")].map(node => [node.dataset.dashboardWidget, node]));
|
||||
const orderedNodes = normalizedOrder.map(id => nodes.get(id)).filter(Boolean);
|
||||
for (const node of orderedNodes) node.hidden = hiddenSet.has(node.dataset.dashboardWidget);
|
||||
for (const node of orderedNodes) {
|
||||
node.hidden = hiddenSet.has(node.dataset.dashboardWidget);
|
||||
node.dataset.dashboardSpan = String(dashboardWidgetWidth(node.dataset.dashboardWidget, widths));
|
||||
}
|
||||
const currentNodes = [...grid.querySelectorAll("[data-dashboard-widget]")];
|
||||
if (orderedNodes.some((node, index) => node !== currentNodes[index])) grid.append(...orderedNodes);
|
||||
window.rustProxyStreamDashboard?.syncVisibility?.([...hiddenSet]);
|
||||
window.rustProxyBackendDashboard?.syncVisibility?.([...hiddenSet]);
|
||||
window.rustProxyMasonry?.refresh?.();
|
||||
if (typeof latestStatus !== "undefined" && latestStatus && currentPanel === "overview") { window.rustProxyStreamDashboard?.render?.(latestStatus, [...hiddenSet], false); window.rustProxyBackendDashboard?.render?.(latestStatus, [...hiddenSet], false); window.rustProxyExtraOverview?.render?.(latestStatus, false); window.rustProxyWideOverview?.render?.(latestStatus, false); window.rustProxyWebOverview?.render?.(latestStatus, false); }
|
||||
return { order: normalizedOrder, hidden: [...hiddenSet] };
|
||||
return { order: normalizedOrder, hidden: [...hiddenSet], sizes: widths };
|
||||
}
|
||||
function dashboardWidgetLabel(id) {
|
||||
const widget = ADMIN_DASHBOARD_BY_ID.get(id);
|
||||
@@ -135,7 +182,7 @@ function renderDashboardWidgetSettings() {
|
||||
const focusedRow = document.activeElement?.closest?.("[data-dashboard-widget-setting]");
|
||||
const focusedId = focusedRow && list.contains?.(focusedRow) ? focusedRow.dataset.dashboardWidgetSetting : null;
|
||||
const focusedAction = focusedId ? document.activeElement?.dataset.dashboardWidgetAction : null;
|
||||
const current = adminPreferences || ADMIN_APPEARANCE_DEFAULTS, order = normalizeDashboardWidgets(current.dashboard_widgets), hidden = new Set(normalizeHiddenDashboardWidgets(current.dashboard_hidden_widgets));
|
||||
const current = adminPreferences || ADMIN_APPEARANCE_DEFAULTS, order = dashboardVisualOrder(current.dashboard_widgets, current.dashboard_widget_sizes), hidden = new Set(normalizeHiddenDashboardWidgets(current.dashboard_hidden_widgets));
|
||||
const rows = order.map((id, index) => {
|
||||
const row = el("div", undefined, "dashboard-widget-setting"); row.dataset.dashboardWidgetSetting = id;
|
||||
const visible = !hidden.has(id);
|
||||
@@ -152,14 +199,19 @@ function renderDashboardWidgetSettings() {
|
||||
const down = el("button", "→", "quiet"); down.type = "button"; down.dataset.dashboardWidgetAction = "down"; down.disabled = index === order.length - 1; down.setAttribute("aria-label", t("dashboardWidgetsMoveLater"));
|
||||
toggle.addEventListener("click", () => {
|
||||
const previous = [...hidden], next = new Set(hidden); if (visible) next.add(id); else next.delete(id);
|
||||
if (adminPreferences) adminPreferences.dashboard_hidden_widgets = [...next]; applyDashboardLayout(order, [...next]); renderDashboardWidgetSettings();
|
||||
void saveAppearancePreference({ dashboard_hidden_widgets: [...next] }, toggle, () => { if (adminPreferences) adminPreferences.dashboard_hidden_widgets = previous; applyDashboardLayout(order, previous); renderDashboardWidgetSettings(); });
|
||||
if (adminPreferences) adminPreferences.dashboard_hidden_widgets = [...next]; applyDashboardLayout(order, [...next], current.dashboard_widget_sizes); renderDashboardWidgetSettings();
|
||||
void saveAppearancePreference({ dashboard_hidden_widgets: [...next] }, toggle, () => { if (adminPreferences) adminPreferences.dashboard_hidden_widgets = previous; applyDashboardLayout(order, previous, current.dashboard_widget_sizes); renderDashboardWidgetSettings(); });
|
||||
});
|
||||
const move = delta => {
|
||||
const previous = [...order], next = [...order], at = next.indexOf(id), target = at + delta; if (at < 0 || target < 0 || target >= next.length) return;
|
||||
[next[at], next[target]] = [next[target], next[at]]; if (adminPreferences) adminPreferences.dashboard_widgets = next;
|
||||
applyDashboardLayout(next, [...hidden]); renderDashboardWidgetSettings();
|
||||
void saveAppearancePreference({ dashboard_widgets: next }, null, () => { if (adminPreferences) adminPreferences.dashboard_widgets = previous; applyDashboardLayout(previous, [...hidden]); renderDashboardWidgetSettings(); });
|
||||
[next[at], next[target]] = [next[target], next[at]];
|
||||
const previousSizes = current.dashboard_widget_sizes;
|
||||
if (adminPreferences) { adminPreferences.dashboard_widgets = next; adminPreferences.dashboard_widget_sizes = normalizeDashboardWidgetSizes(previousSizes) ?? {}; }
|
||||
applyDashboardLayout(next, [...hidden], current.dashboard_widget_sizes); renderDashboardWidgetSettings();
|
||||
void saveAppearancePreference({ dashboard_widgets: next, dashboard_widget_sizes: current.dashboard_widget_sizes }, null, () => {
|
||||
if (adminPreferences) { adminPreferences.dashboard_widgets = previous; adminPreferences.dashboard_widget_sizes = previousSizes; }
|
||||
applyDashboardLayout(previous, [...hidden], previousSizes); renderDashboardWidgetSettings();
|
||||
});
|
||||
};
|
||||
up.addEventListener("click", () => move(-1)); down.addEventListener("click", () => move(1)); actions.append(up, down); row.append(toggle, actions); return row;
|
||||
});
|
||||
@@ -224,14 +276,15 @@ function applyAdminPreferences(value, cache = true) {
|
||||
const editing = window.rustProxyInlineLayout?.currentDraft?.();
|
||||
const savedOrder = normalizeDashboardWidgets(value.dashboard_widgets);
|
||||
const savedHidden = normalizeHiddenDashboardWidgets(value.dashboard_hidden_widgets, value.dashboard_widgets);
|
||||
if (editing) applyDashboardLayout(editing.order, editing.hidden);
|
||||
else applyDashboardLayout(savedOrder, savedHidden);
|
||||
const savedSizes = normalizeDashboardWidgetSizes(value.dashboard_widget_sizes);
|
||||
if (editing) applyDashboardLayout(editing.order, editing.hidden, editing.sizes);
|
||||
else applyDashboardLayout(savedOrder, savedHidden, savedSizes);
|
||||
const normalized = {
|
||||
...value,
|
||||
refresh: normalizeRefreshPreferences(value.refresh),
|
||||
theme: applyAdminTheme(value.theme, cache), language: applyAdminLanguage(value.language, cache, false), ui_scale: applyAdminUiScale(value.ui_scale, cache),
|
||||
time_format: applyAdminTimeFormat(value.time_format), chart_style: applyAdminChartStyle(value.chart_style), button_style: applyAdminButtonStyle(value.button_style), corner_style: applyAdminCornerStyle(value.corner_style, cache), table_density: applyAdminTableDensity(value.table_density),
|
||||
dashboard_density: applyAdminDashboardDensity(value.dashboard_density), dashboard_widgets: savedOrder, dashboard_hidden_widgets: savedHidden,
|
||||
dashboard_density: applyAdminDashboardDensity(value.dashboard_density), dashboard_widgets: savedOrder, dashboard_hidden_widgets: savedHidden, dashboard_widget_sizes: savedSizes,
|
||||
};
|
||||
adminPreferences = normalized;
|
||||
window.rustProxyRefresh?.update(normalized.refresh);
|
||||
@@ -279,7 +332,7 @@ function updateAdminPreferences(patch) {
|
||||
next.refresh = normalizeRefreshPreferences(next.refresh);
|
||||
next.theme = normalizeAdminTheme(next.theme); next.language = normalizeAdminLanguage(next.language); next.ui_scale = normalizeAdminUiScale(next.ui_scale);
|
||||
next.time_format = normalizeAdminTimeFormat(next.time_format); next.chart_style = normalizeAdminChartStyle(next.chart_style); next.button_style = normalizeAdminButtonStyle(next.button_style); next.corner_style = normalizeAdminCornerStyle(next.corner_style); next.table_density = normalizeAdminDensity(next.table_density);
|
||||
next.dashboard_density = normalizeAdminDensity(next.dashboard_density, "compact"); next.dashboard_widgets = normalizeDashboardWidgets(next.dashboard_widgets); next.dashboard_hidden_widgets = normalizeHiddenDashboardWidgets(next.dashboard_hidden_widgets);
|
||||
next.dashboard_density = normalizeAdminDensity(next.dashboard_density, "compact"); next.dashboard_widgets = normalizeDashboardWidgets(next.dashboard_widgets); next.dashboard_hidden_widgets = normalizeHiddenDashboardWidgets(next.dashboard_hidden_widgets); next.dashboard_widget_sizes = normalizeDashboardWidgetSizes(next.dashboard_widget_sizes);
|
||||
const saved = await api("/api/preferences", { method: "PUT", body: JSON.stringify(next) });
|
||||
if (!authenticated || epoch !== authEpoch) return adminPreferences;
|
||||
return applyAdminPreferences(saved);
|
||||
@@ -378,7 +431,7 @@ $("ui-dashboard-density")?.addEventListener("change", () => {
|
||||
async function resetAppearancePatch(patch, control, messageKey = "appearanceSectionResetDone") {
|
||||
if (control) control.disabled = true; let previous = null;
|
||||
try {
|
||||
const current = await loadAdminPreferences(); previous = current ? { ...current, dashboard_widgets: [...current.dashboard_widgets], dashboard_hidden_widgets: [...current.dashboard_hidden_widgets] } : null;
|
||||
const current = await loadAdminPreferences(); previous = current ? { ...current, dashboard_widgets: [...current.dashboard_widgets], dashboard_hidden_widgets: [...current.dashboard_hidden_widgets], dashboard_widget_sizes: current.dashboard_widget_sizes === null ? null : { ...current.dashboard_widget_sizes } } : null;
|
||||
if (current) applyAdminPreferences({ ...current, ...patch }); await updateAdminPreferences(patch); toast(t(messageKey));
|
||||
} catch (error) { if (previous) applyAdminPreferences(previous); if (error.status !== 401) toast(error.message, true); }
|
||||
finally { if (control) control.disabled = false; }
|
||||
@@ -386,9 +439,9 @@ async function resetAppearancePatch(patch, control, messageKey = "appearanceSect
|
||||
document.querySelectorAll("[data-appearance-reset]").forEach(control => control.addEventListener("click", () => {
|
||||
const patches = {
|
||||
interface: { theme: "dark", language: "auto", ui_scale: 100, time_format: "24h", button_style: "normal", corner_style: "default" }, charts: { chart_style: "default" }, tables: { table_density: "normal" },
|
||||
dashboard: { dashboard_density: ADMIN_DASHBOARD_DEFAULTS.dashboard_density, dashboard_widgets: [...ADMIN_DASHBOARD_WIDGETS], dashboard_hidden_widgets: [...ADMIN_APPEARANCE_DEFAULTS.dashboard_hidden_widgets] },
|
||||
dashboard: { dashboard_density: ADMIN_DASHBOARD_DEFAULTS.dashboard_density, dashboard_widgets: [...ADMIN_DASHBOARD_WIDGETS], dashboard_hidden_widgets: [...ADMIN_APPEARANCE_DEFAULTS.dashboard_hidden_widgets], dashboard_widget_sizes: null },
|
||||
};
|
||||
void resetAppearancePatch(patches[control.dataset.appearanceReset] || {}, control);
|
||||
}));
|
||||
$("appearance-reset")?.addEventListener("click", () => void resetAppearancePatch({ ...ADMIN_APPEARANCE_DEFAULTS, dashboard_widgets: [...ADMIN_DASHBOARD_WIDGETS], dashboard_hidden_widgets: [...ADMIN_APPEARANCE_DEFAULTS.dashboard_hidden_widgets] }, $("appearance-reset"), "appearanceResetDone"));
|
||||
$("appearance-reset")?.addEventListener("click", () => void resetAppearancePatch({ ...ADMIN_APPEARANCE_DEFAULTS, dashboard_widgets: [...ADMIN_DASHBOARD_WIDGETS], dashboard_hidden_widgets: [...ADMIN_APPEARANCE_DEFAULTS.dashboard_hidden_widgets], dashboard_widget_sizes: null }, $("appearance-reset"), "appearanceResetDone"));
|
||||
refreshAppearanceUi();
|
||||
Reference in new issue
Block a user