From f70ecb464845a06cfcc20e816b8dd8c2e7239c69 Mon Sep 17 00:00:00 2001 From: Ross Date: Mon, 23 Mar 2026 14:30:07 +0000 Subject: [PATCH] Enhance finding search functionality to support series findings and improve result display with badges --- atlas/static/atlas/js/markup_inserter.js | 15 ++++++++++++++- .../atlas/partials/_finding_search_results.html | 17 +++++++++++++---- atlas/views.py | 12 ++++++++---- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/atlas/static/atlas/js/markup_inserter.js b/atlas/static/atlas/js/markup_inserter.js index 54248101..6b4f9e77 100644 --- a/atlas/static/atlas/js/markup_inserter.js +++ b/atlas/static/atlas/js/markup_inserter.js @@ -209,7 +209,20 @@ var timer = null; input.addEventListener('input', function(){ if(timer) clearTimeout(timer); timer = setTimeout(function(){ var q = encodeURIComponent(input.value || ''); var url = window.location.origin + '/atlas/search/findings/?q=' + q + (currentCaseF ? '&case=' + currentCaseF : ''); fetch(url, {credentials:'same-origin'}).then(function(r){ return r.text(); }).then(function(html){ results.innerHTML = html; }).catch(function(e){ console.error('finding picker fetch error', e); results.innerHTML = '
Search failed
'; }); }, 300); }); - results.addEventListener('click', function(e){ var item = e.target.closest('.list-group-item'); if(!item) return; var pk = item.getAttribute('data-finding-pk'); if(!pk) return; insertAtCursor(textarea, '[['+'finding:'+pk+']]' ); if(overlay && overlay.parentNode) overlay.parentNode.removeChild(overlay); }); + results.addEventListener('click', function(e){ + var item = e.target.closest('.list-group-item'); + if(!item) return; + var sfpk = item.getAttribute('data-seriesfinding-pk'); + var fpk = item.getAttribute('data-finding-pk'); + if(sfpk){ + insertAtCursor(textarea, '[['+'seriesfinding:'+sfpk+']]' ); + } else if(fpk){ + insertAtCursor(textarea, '[['+'finding:'+fpk+']]' ); + } else { + return; + } + if(overlay && overlay.parentNode) overlay.parentNode.removeChild(overlay); + }); overlay.tabIndex = -1; overlay.focus(); function fetchInitialFindings(){ var initFindingsUrl = window.location.origin + '/atlas/search/findings/' + (currentCaseF ? '?case=' + currentCaseF : ''); fetch(initFindingsUrl).then(function(r){ return r.text(); }).then(function(html){ results.innerHTML = html; }).catch(function(){}); } fetchInitialFindings(); diff --git a/atlas/templates/atlas/partials/_finding_search_results.html b/atlas/templates/atlas/partials/_finding_search_results.html index f663d8da..45abe419 100644 --- a/atlas/templates/atlas/partials/_finding_search_results.html +++ b/atlas/templates/atlas/partials/_finding_search_results.html @@ -1,16 +1,25 @@
{% if findings %} {% for f in findings %} -
+
- {{ f.name }} + {% if f.series %}{{ f.series.id }}{% else %}Series{% endif %}{% if f.description %}: {{ f.description|truncatechars:80 }}{% endif %} {{ f.pk }}
-

{{ f.description }}

+

+ {% if f.findings.all %} + {% for sub in f.findings.all %} + {{ sub.name }} + {% endfor %} + {% endif %} + {{ f.description }} +

- View + {% if f.series %} + View series + {% endif %}
{% endfor %} diff --git a/atlas/views.py b/atlas/views.py index 56a8f561..299b2caf 100755 --- a/atlas/views.py +++ b/atlas/views.py @@ -365,16 +365,20 @@ def finding_search(request): # Allow both HTMX and standard fetch/ajax requests (don't require the HTMX header) q = request.GET.get('q', '').strip() case_id = request.GET.get('case') - qs = Finding.objects.all() + # Use SeriesFinding objects for the widget (series-scoped findings) + qs = SeriesFinding.objects.select_related('series').prefetch_related('findings') if case_id: try: cid = int(case_id) - qs = qs.filter(case__pk=cid) + # Series are linked to cases through SeriesDetail; filter SeriesFinding by linked series' case + qs = qs.filter(series__seriesdetail__case__pk=cid) except Exception: pass if q: - qs = qs.filter(name__icontains=q) - qs = qs.order_by('name')[:50] + qs = qs.filter( + Q(description__icontains=q) | Q(findings__name__icontains=q) + ) + qs = qs.order_by('-pk').distinct()[:50] html = render_to_string('atlas/partials/_finding_search_results.html', {'findings': qs}, request=request) return HttpResponse(html)