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 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-09-27 00:34:16 -05:00
parent f7f5d304d0
commit 49fc6e06e6
2 changed files with 39 additions and 0 deletions

View File

@@ -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'; });

View File

@@ -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: