fix(idaa): remove over-filtering of API text search results in recovery meetings

The secondary client-side filter was re-checking qry_str against name, description,
location_text, and default_qry_str on the API response. This silently dropped meetings
that the API correctly matched via default_qry_str (a backend-generated combined index
containing contact name/email) — because that field is not always present in the
response body.

The API's LIKE search on default_qry_str is already exact. The secondary filter should
only correct structured dimensions (type, physical/virtual OR-logic) where the backend
uses AND logic that the frontend must compensate for. Text search is left to the API.

Root cause confirmed: STORED GENERATED columns in the event table needed a rebuild;
frontend filtering was masking results that the API returned correctly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Scott Idem
2026-05-19 12:49:52 -04:00
parent 4ada5c4a8f
commit 76e21b08ff

View File

@@ -301,8 +301,16 @@ async function handle_search_refresh(qry_key: string) {
if (current_search_id === last_search_id) {
let api_results = results || [];
// SECONDARY FILTER: Ensure API results respect exact UI filters (handles backend broadness)
api_results = api_results.filter((ev: any) => {
// SECONDARY FILTER: Re-apply structured filters the API may handle loosely.
// WHY type/physical/virtual: the backend uses AND logic for body filters, so
// physical+virtual together would incorrectly exclude either-only meetings —
// we pass only one at a time and handle OR logic here.
// WHY NOT qry_str: the API already applied exact LIKE search on default_qry_str
// (a backend-generated combined index that includes contact name/email). Re-running
// text filtering client-side against the response fields silently drops meetings
// that matched only via default_qry_str (e.g., by contact name) because that
// field may not be present in the response body or may not duplicate the match.
api_results = api_results.filter((ev) => {
if (qry_type && ev.type !== qry_type) return false;
if (qry_physical || qry_virtual) {
let match = false;
@@ -310,19 +318,6 @@ async function handle_search_refresh(qry_key: string) {
if (qry_virtual && ev.virtual == true) match = true;
if (!match) return false;
}
if (qry_str && qry_str.length >= 3) {
const name = (ev.name ?? '').toLowerCase();
const desc = (ev.description ?? '').toLowerCase();
const loc = (ev.location_text ?? '').toLowerCase();
const dqs = (ev.default_qry_str ?? '').toLowerCase();
if (
!name.includes(qry_str) &&
!desc.includes(qry_str) &&
!loc.includes(qry_str) &&
!dqs.includes(qry_str)
)
return false;
}
return true;
});