Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
2 changes: 1 addition & 1 deletion tasktiger_admin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from .views import TaskTigerView

__version__ = "0.4.2"
__version__ = "0.4.3"
__all__ = ["TaskTigerView", "tasktiger_admin"]

tasktiger_admin = Blueprint(
Expand Down
45 changes: 41 additions & 4 deletions tasktiger_admin/templates/tasktiger_admin/tasktiger.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ <h2>TaskTiger</h2>
<thead>
<tr>
<th></th>
<th class="sort-header">Queued <span class="sort-arrow"></span></th>
<th class="sort-header">Active <span class="sort-arrow"></span></th>
<th class="sort-header">Scheduled <span class="sort-arrow"></span></th>
<th class="sort-header">Error <span class="sort-arrow"></span></th>
<th class="sort-header" data-sort-key="queued">Queued <span class="sort-arrow"></span></th>
<th class="sort-header" data-sort-key="active">Active <span class="sort-arrow"></span></th>
<th class="sort-header" data-sort-key="scheduled">Scheduled <span class="sort-arrow"></span></th>
<th class="sort-header" data-sort-key="error">Error <span class="sort-arrow"></span></th>
</tr>
</thead>
<tbody class="searchable">
Expand Down Expand Up @@ -67,6 +67,7 @@ <h2>TaskTiger</h2>
debounceTimeout = setTimeout(() => {
filterRows(this.value);
updateHeaderDisplay();
updateUrl();
}, 300);
})

Expand Down Expand Up @@ -104,6 +105,7 @@ <h2>TaskTiger</h2>
}
applySort();
updateArrows();
updateUrl();
});
});

Expand Down Expand Up @@ -172,6 +174,23 @@ <h2>TaskTiger</h2>
});
}

// 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');
Expand Down Expand Up @@ -221,6 +240,24 @@ <h2>TaskTiger</h2>
});
}

// 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();
</script>
{% endblock %}
Loading