Merge into current URL params instead of replacing them in Advanced Search (#58)

Same root pattern as the earlier chart click-to-filter bug (#29):
performAdvancedSearch() built a brand-new URLSearchParams from only the
form's own fields and navigated to it, silently dropping any active
filter the form doesn't represent (e.g. a category/type filter applied
via a dashboard quick-filter pill or stats-widget click).
populateCurrentFilters() also only read search/status back out of the
URL into the form, not the date ranges/priority range/user fields the
form does control.

Fixed performAdvancedSearch() to start from the current URL's params
and only set/clear the ones this form actually represents, leaving
everything else untouched. Also fixed populateCurrentFilters() to
restore all of those fields, not just search/status — without that,
reopening the modal and submitting without touching anything would
now silently wipe date/priority/user filters that were active but
shown blank in the form (a new foot-gun the first fix alone would have
introduced).

Verified via jsdom: category/type/sort params not represented in the
form survive a search submission; page resets to 1; and reopening the
modal with an active created_from filter correctly restores it into
the form and preserves it on a no-op resubmit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lhz7pGMaoTfL5sdYS5XiKv
This commit is contained in:
2026-09-11 14:28:12 -04:00
co-authored by Claude Sonnet 5
parent aa8173941a
commit 6d68af40e7
+32 -11
View File
@@ -61,25 +61,46 @@ function populateCurrentFilters() {
const urlParams = new URLSearchParams(window.location.search);
// Search text
if (urlParams.has('search')) {
document.getElementById('adv-search-text').value = urlParams.get('search');
}
document.getElementById('adv-search-text').value = urlParams.get('search') || '';
// Status
if (urlParams.has('status')) {
const statuses = urlParams.get('status').split(',');
const statusSelect = document.getElementById('adv-status');
Array.from(statusSelect.options).forEach(option => {
option.selected = statuses.includes(option.value);
});
}
const statuses = urlParams.has('status') ? urlParams.get('status').split(',') : [];
const statusSelect = document.getElementById('adv-status');
Array.from(statusSelect.options).forEach(option => {
option.selected = statuses.includes(option.value);
});
// Date ranges
document.getElementById('adv-created-from').value = urlParams.get('created_from') || '';
document.getElementById('adv-created-to').value = urlParams.get('created_to') || '';
document.getElementById('adv-updated-from').value = urlParams.get('updated_from') || '';
document.getElementById('adv-updated-to').value = urlParams.get('updated_to') || '';
// Priority range
document.getElementById('adv-priority-min').value = urlParams.get('priority_min') || '';
document.getElementById('adv-priority-max').value = urlParams.get('priority_max') || '';
// Users
document.getElementById('adv-created-by').value = urlParams.get('created_by') || '';
document.getElementById('adv-assigned-to').value = urlParams.get('assigned_to') || '';
}
// Perform advanced search
function performAdvancedSearch(event) {
event.preventDefault();
const params = new URLSearchParams();
// Start from the CURRENT URL's params, not a fresh set, so a filter this
// form doesn't represent (e.g. a category/type filter applied via a
// dashboard quick-filter pill or stats-widget click) isn't silently
// dropped on submit. Only the params this form actually controls are
// set/cleared below; everything else passes through untouched.
const params = new URLSearchParams(window.location.search);
const advParams = [
'search', 'created_from', 'created_to', 'updated_from', 'updated_to',
'status', 'priority_min', 'priority_max', 'created_by', 'assigned_to',
];
advParams.forEach(key => params.delete(key));
params.delete('page'); // filters changed — reset to page 1
// Search text
const searchText = document.getElementById('adv-search-text').value.trim();