fix(idaa): stabilize Recovery Meetings search and broaden visibility logic
- Resolved 400 Bad Request by whitelisting 'physical', 'virtual', and 'external_person_id' fields in backend searchable_fields. - Broadened server-side search by removing restrictive AND filters for location types, moving the inclusive OR logic to the client-side filter layer. - Hardened handle_search_refresh error handling to clear results on category filter changes (Type, Physical, Virtual) while maintaining flicker protection strictly for text search typing. - Restored permissive visibility for Trusted users, allowing them to see hidden/disabled items regardless of Edit Mode. - Optimized plural object loading in Archives and Events modules using concurrent Promise.all. - Standardized ID handling across the search flow to prevent Dexie lookup failures. - Finalized well-commented code across IDAA modules to document search strategies and workarounds.
This commit is contained in:
@@ -192,7 +192,7 @@ export async function load_ae_obj_li__event({
|
||||
hidden = 'not_hidden',
|
||||
view = 'default',
|
||||
inc_session_li = false,
|
||||
limit = 99,
|
||||
limit = 9,
|
||||
offset = 0,
|
||||
order_by_li = { start_datetime: 'DESC' } as const,
|
||||
try_cache = true,
|
||||
@@ -307,15 +307,16 @@ export async function load_ae_obj_li__event({
|
||||
}
|
||||
|
||||
if (inc_session_li && ae_promises.load__event_obj_li) {
|
||||
for (const event_obj of ae_promises.load__event_obj_li) {
|
||||
const session_tasks = ae_promises.load__event_obj_li.map((event_obj: any) => {
|
||||
const current_event_id = event_obj.id || event_obj.event_id;
|
||||
event_obj.event_session_obj_li = await load_ae_obj_li__event_session({
|
||||
return load_ae_obj_li__event_session({
|
||||
api_cfg,
|
||||
for_obj_type: 'event',
|
||||
for_obj_id: current_event_id,
|
||||
log_lvl
|
||||
});
|
||||
}
|
||||
}).then((res) => (event_obj.event_session_obj_li = res));
|
||||
});
|
||||
await Promise.all(session_tasks);
|
||||
}
|
||||
|
||||
return ae_promises.load__event_obj_li;
|
||||
@@ -450,6 +451,16 @@ export async function update_ae_obj__event({
|
||||
}
|
||||
|
||||
// Updated 2026-01-21
|
||||
/**
|
||||
* Unified Search for Events (V3 API)
|
||||
*
|
||||
* STRATEGY: Hybrid Search/Filter
|
||||
* 1. Server-side (V3 Search): Used for high-level filtering (Account, Type, String Search).
|
||||
* This reduces the data payload significantly.
|
||||
* 2. Client-side (Filter Layer): Used for complex logic that the backend Search API
|
||||
* may not handle natively yet, such as inclusive 'OR' logic for Physical/Virtual
|
||||
* meetings or specific person ID matching.
|
||||
*/
|
||||
export async function search__event({
|
||||
api_cfg,
|
||||
for_obj_type = 'account',
|
||||
@@ -491,17 +502,35 @@ export async function search__event({
|
||||
|
||||
let result_li: ae_Event[] | null = null;
|
||||
|
||||
if (qry_str && qry_str.trim().length > 0) {
|
||||
// Option A: Active Text Search
|
||||
// Use V3 Search if ANY filter is active to ensure we query the full database
|
||||
const has_active_filters = (qry_str && qry_str.trim().length > 0) ||
|
||||
qry_physical === true ||
|
||||
qry_virtual === true ||
|
||||
(qry_type && qry_type !== 'all' && qry_type !== '') ||
|
||||
qry_person_id ||
|
||||
qry_conference !== null;
|
||||
|
||||
if (has_active_filters) {
|
||||
// Option A: Active Search (Server-side filtering)
|
||||
const search_query: any = {
|
||||
and: []
|
||||
};
|
||||
const params: key_val = {};
|
||||
|
||||
// Use default_qry_str for searching as requested
|
||||
// Using 'like' with wildcards and populating params['lk_qry'] to match working event_session logic
|
||||
search_query.and.push({ field: 'default_qry_str', op: 'like', value: `%${qry_str.trim()}%` });
|
||||
params['lk_qry'] = { 'default_qry_str': qry_str.trim() };
|
||||
if (qry_str && qry_str.trim().length > 0) {
|
||||
// Use default_qry_str for searching as requested
|
||||
// Using 'like' with wildcards and populating params['lk_qry'] to match working event_session logic
|
||||
search_query.and.push({ field: 'default_qry_str', op: 'like', value: `%${qry_str.trim()}%` });
|
||||
params['lk_qry'] = { 'default_qry_str': qry_str.trim() };
|
||||
}
|
||||
|
||||
// NOTE: We do NOT push 'physical' and 'virtual' to the server-side query here.
|
||||
// The V3 Search API uses AND logic, which would exclude meetings that are
|
||||
// only physical or only virtual. We let the Client-side Filter handle this below.
|
||||
|
||||
if (qry_type && qry_type !== 'all' && qry_type !== '') {
|
||||
search_query.and.push({ field: 'type', op: 'eq', value: qry_type });
|
||||
}
|
||||
|
||||
if (for_obj_id) {
|
||||
search_query.and.push({ field: `${for_obj_type}_id`, op: 'eq', value: for_obj_id });
|
||||
@@ -529,7 +558,7 @@ export async function search__event({
|
||||
log_lvl
|
||||
});
|
||||
} else {
|
||||
// Option B: List All (No text search active)
|
||||
// Option B: List All (No filters active)
|
||||
// Fallback to standard list retrieval to ensure we get results when the search bar is empty.
|
||||
result_li = await api.get_ae_obj_li_v3({
|
||||
api_cfg,
|
||||
@@ -572,7 +601,15 @@ export async function search__event({
|
||||
});
|
||||
}
|
||||
|
||||
// Client-side Filter Layer (Retained for complex OR logic and Person ID checks)
|
||||
/**
|
||||
* Client-side Filter Layer
|
||||
*
|
||||
* WHY: The V3 Search API defaults to 'AND' logic for its top-level filters.
|
||||
* Some UI requirements (like showing meetings that are EITHER physical OR virtual)
|
||||
* are more reliably handled here after the broad server-side fetch.
|
||||
* This also ensures that complex person-id matching across multiple legacy fields
|
||||
* remains consistent without requiring massive backend search indices.
|
||||
*/
|
||||
const filtered_obj_li = processed_obj_li.filter((ev: any) => {
|
||||
// Handle conference filter
|
||||
if (qry_conference != null) {
|
||||
|
||||
Reference in New Issue
Block a user