From 49fc6e06e67a30a73855d8b5798a2c22eb051542 Mon Sep 17 00:00:00 2001 From: Aaron Kimbrell Date: Sun, 27 Sep 2026 00:34:16 -0500 Subject: [PATCH] feat(dashboard): remember each user's table sort and page length Every DataTable saves its order and page length to localStorage, keyed by dashboard user, page (numeric path segments folded) and table id, and restores it on load. Stale sorts on missing or unsortable columns are dropped; storage failures are ignored. Co-Authored-By: Claude Opus 5.5 --- dDashboardServer/static/js/common.js | 33 ++++++++++++++++++++++++++++ docs/Dashboard.md | 6 +++++ 2 files changed, 39 insertions(+) diff --git a/dDashboardServer/static/js/common.js b/dDashboardServer/static/js/common.js index f4fb2ce39..29018a177 100644 --- a/dDashboardServer/static/js/common.js +++ b/dDashboardServer/static/js/common.js @@ -352,6 +352,39 @@ $.extend(true, $.fn.dataTable.defaults, { columnDefs: [{ targets: '_all', render: $.fn.dataTable.render.text() }] }); + /* + * Every table remembers how this user last sorted it and how many rows it showed, in this browser only. + * Keyed by page (numeric path segments folded, so every account page shares one choice), table id and + * username. Search and paging position are deliberately not kept. Tables without an id are skipped. + */ + var sortKey = function (settings) { + if (!settings.sTableId) return null; + var page = window.location.pathname.replace(/\/\d+(?=\/|$)/g, '/*'); + return 'dash.table:' + (DASH.username || '-') + ':' + page + ':' + settings.sTableId; + }; + $.extend($.fn.dataTable.defaults, { + stateSave: true, + stateDuration: 0, + stateSaveCallback: function (settings, data) { + var key = sortKey(settings); + if (!key) return; + try { localStorage.setItem(key, JSON.stringify({ order: data.order, length: data.length })); } catch (e) { /* storage unavailable */ } + }, + stateLoadCallback: function (settings) { + var key = sortKey(settings), saved = null; + if (!key) return null; + try { saved = JSON.parse(localStorage.getItem(key) || 'null'); } catch (e) { return null; } + if (!saved || typeof saved !== 'object') return null; + var count = settings.aoColumns.length, state = { time: Date.now() }; + // Drop sorts on columns that no longer exist or can't be sorted (the table changed since) + if (Array.isArray(saved.order)) state.order = saved.order.filter(function (o) { + return Array.isArray(o) && o[0] >= 0 && o[0] < count && settings.aoColumns[o[0]].bSortable !== false && (o[1] === 'asc' || o[1] === 'desc'); + }); + if (state.order && !state.order.length) delete state.order; + if (typeof saved.length === 'number' && (saved.length === -1 || saved.length > 0)) state.length = saved.length; + return state; + } + }); $.ajaxSetup({ headers: { 'X-Requested-With': 'dashboard' } }); $(document).on('ajaxError', function (e, xhr) { if (xhr.status === 401) window.location.href = '/login'; }); diff --git a/docs/Dashboard.md b/docs/Dashboard.md index 1302d45f6..e81cab933 100644 --- a/docs/Dashboard.md +++ b/docs/Dashboard.md @@ -25,6 +25,12 @@ dashboard_url=https://dashboard.example.com `dashboard_url` is used for links in emails and webhook alerts. +### Tables + +Every table remembers how you last sorted it and how many rows it shows per page. This is kept in your browser only +(per dashboard user), so it doesn't follow you to another browser; clearing site data resets it. Searches and the page +you were on aren't kept. + ## Files to back up Next to the server binaries, the dashboard creates: