From 32ce4843efb487951cbc836b1021528811a272e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Sampaio?= Date: Thu, 24 Sep 2026 10:37:16 -0600 Subject: [PATCH] Persist filter and sorting state across reloads --- CHANGELOG.md | 6 +++ tasktiger_admin/__init__.py | 2 +- .../templates/tasktiger_admin/tasktiger.html | 45 +++++++++++++++++-- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd2f6d6..c5215e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changes +## v0.4.3 + +* Keep the filter and the column sort of the queue list across page reloads. + The page stores them in the URL query string (`filter`, `sort`, and + `direction`), so you can also bookmark or share a filtered, sorted view. + ## v0.4.2 * Make the task-state columns (Queued, Active, Scheduled, Error) sortable. diff --git a/tasktiger_admin/__init__.py b/tasktiger_admin/__init__.py index 1adf5e7..72ab56f 100644 --- a/tasktiger_admin/__init__.py +++ b/tasktiger_admin/__init__.py @@ -2,7 +2,7 @@ from .views import TaskTigerView -__version__ = "0.4.2" +__version__ = "0.4.3" __all__ = ["TaskTigerView", "tasktiger_admin"] tasktiger_admin = Blueprint( diff --git a/tasktiger_admin/templates/tasktiger_admin/tasktiger.html b/tasktiger_admin/templates/tasktiger_admin/tasktiger.html index 6327e9f..85be4aa 100644 --- a/tasktiger_admin/templates/tasktiger_admin/tasktiger.html +++ b/tasktiger_admin/templates/tasktiger_admin/tasktiger.html @@ -21,10 +21,10 @@

TaskTiger

- Queued - Active - Scheduled - Error + Queued + Active + Scheduled + Error @@ -67,6 +67,7 @@

TaskTiger

debounceTimeout = setTimeout(() => { filterRows(this.value); updateHeaderDisplay(); + updateUrl(); }, 300); }) @@ -104,6 +105,7 @@

TaskTiger

} applySort(); updateArrows(); + updateUrl(); }); }); @@ -172,6 +174,23 @@

TaskTiger

}); } +// Write the filter and sort state to the URL query string, so that a reload +// keeps them. replaceState does not add a browser history entry. +function updateUrl() { + const params = new URLSearchParams(); + const filterValue = document.getElementById('task_filter').value; + if (filterValue) { + params.set('filter', filterValue); + } + if (sortColumn !== null) { + const header = document.querySelector('.metrics thead tr').cells[sortColumn]; + params.set('sort', header.dataset.sortKey); + params.set('direction', sortDirection); + } + const query = params.toString(); + history.replaceState(null, '', query ? `?${query}` : window.location.pathname); +} + function filterRows(value) { const regex = new RegExp(value, 'i'); const rows = document.querySelectorAll('.searchable tr'); @@ -221,6 +240,24 @@

TaskTiger

}); } +// Restore the filter and sort state from the URL query string. +const urlParams = new URLSearchParams(window.location.search); +const initialSortHeader = Array.from(document.querySelectorAll('.sort-header')) + .find(header => header.dataset.sortKey === urlParams.get('sort')); +const initialSortDirection = urlParams.get('direction'); +if (initialSortHeader && ['asc', 'desc'].includes(initialSortDirection)) { + sortColumn = initialSortHeader.cellIndex; + sortDirection = initialSortDirection; + applySort(); + updateArrows(); +} +const initialFilter = urlParams.get('filter'); +if (initialFilter) { + document.getElementById('task_filter').value = initialFilter; + filterRows(initialFilter); + updateHeaderDisplay(); +} + document.getElementById('task_filter').focus(); {% endblock %}