From e4669cfccd81f24a1f1d52b9dcfdd73b3e3606df Mon Sep 17 00:00:00 2001 From: duffyduck Date: Sun, 31 May 2026 10:51:32 +0200 Subject: [PATCH] add live search to filter rules list Substring search across rule name, source folder, condition values and action parameters. Filters the table client-side as the user types and shows a match counter (e.g. "3 / 12"). Co-Authored-By: Claude Opus 4.7 (1M context) --- app/templates/filters.html | 50 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/app/templates/filters.html b/app/templates/filters.html index 34cee8a..bb5b605 100644 --- a/app/templates/filters.html +++ b/app/templates/filters.html @@ -191,6 +191,23 @@ async function loadFilters() { const resp = await fetch(`/api/filters/account/${accountId}`); const filters = await resp.json(); currentFilters = filters; + renderFilters(); +} + +function filterHaystack(f) { + const parts = [ + f.name || '', + f.source_folder || '', + ...(f.conditions || []).flatMap(c => [c.field, c.match_type, c.value]), + ...(f.actions || []).flatMap(a => [a.action_type, a.parameter || '']), + ]; + return parts.join(' ').toLowerCase(); +} + +function renderFilters() { + const container = document.getElementById('filters-container'); + const filters = currentFilters; + if (filters.length === 0) { container.innerHTML = `

Keine Filterregeln für dieses Konto.

@@ -198,8 +215,33 @@ async function loadFilters() { `; return; } - let html = ''; - for (const f of filters) { + + const searchTerm = (document.getElementById('filter-search')?.value || '').trim().toLowerCase(); + const visible = searchTerm + ? filters.filter(f => filterHaystack(f).includes(searchTerm)) + : filters; + + let html = ` +
+ + + ${visible.length} / ${filters.length} +
`; + + if (visible.length === 0) { + html += '

Keine Treffer.

'; + container.innerHTML = html; + // Cursor zurück ins Suchfeld, sonst verliert das Input den Fokus beim Re-render + const s = document.getElementById('filter-search'); + if (s) { s.focus(); s.setSelectionRange(searchTerm.length, searchTerm.length); } + return; + } + + html += '
PrioNameOrdnerBedingungenAktionen
'; + for (const f of visible) { const conds = f.conditions.map(c => { const fieldLabel = FIELDS.find(x => x.value === c.field)?.label || c.field; const matchLabel = ALL_MATCH_TYPES.find(x => x.value === c.match_type)?.label || c.match_type; @@ -225,6 +267,10 @@ async function loadFilters() { } html += '
PrioNameOrdnerBedingungenAktionen
'; container.innerHTML = html; + + // Cursor zurück ins Suchfeld nach Re-render + const s = document.getElementById('filter-search'); + if (s && searchTerm) { s.focus(); s.setSelectionRange(searchTerm.length, searchTerm.length); } } function addCondition(data = null) {