refactor(idaa): harden reactive search logic and resolve infinite loops
- Replaced boolean search triggers with a versioned integer pattern to break reactivity loops in '+page.svelte'. - Resolved 'behind by one' search lag by ensuring the UI immediately reflects local results, even if empty. - Corrected subscription syntax for 'liveQuery' observables in 'ae_idaa_comp__event_obj_li.svelte'. - Implemented a robust 'Remote First' toggle support in search logic while maintaining fast-path local feedback. - Hardened Fast Path filtering to match server-side logic more accurately for improved cache reliability.
This commit is contained in:
@@ -10,86 +10,63 @@
|
||||
// *** Import Svelte specific
|
||||
import { page } from '$app/state';
|
||||
import { browser } from '$app/environment';
|
||||
// import { goto, invalidate, pushState, replaceState } from '$app/navigation';
|
||||
import { untrack } from 'svelte';
|
||||
|
||||
// *** Import other supporting libraries
|
||||
import { Modal } from 'flowbite-svelte';
|
||||
import { liveQuery } from 'dexie';
|
||||
|
||||
// *** Import Aether specific variables and functions
|
||||
// import type { key_val } from '$lib/ae_stores';
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
import { core_func } from '$lib/ae_core/ae_core_functions';
|
||||
import { db_events } from '$lib/ae_events/db_events';
|
||||
import {
|
||||
idaa_loc,
|
||||
idaa_sess,
|
||||
idaa_slct,
|
||||
idaa_trig,
|
||||
idaa_prom
|
||||
idaa_trig
|
||||
} from '$lib/stores/ae_idaa_stores';
|
||||
|
||||
import { db_events } from '$lib/ae_events/db_events';
|
||||
import {
|
||||
ae_snip,
|
||||
ae_loc,
|
||||
ae_sess,
|
||||
ae_api,
|
||||
ae_trig,
|
||||
slct,
|
||||
slct_trigger
|
||||
ae_api
|
||||
} from '$lib/stores/ae_stores';
|
||||
import { events_func } from '$lib/ae_events_functions';
|
||||
|
||||
import Element_data_store from '$lib/elements/element_data_store_v2.svelte';
|
||||
|
||||
import Comp__event_obj_qry from './ae_idaa_comp__event_obj_qry.svelte';
|
||||
import Comp__event_obj_li_wrapper from './ae_idaa_comp__event_obj_li_wrapper.svelte';
|
||||
// import Comp__event_obj_id_edit from './ae_idaa_comp__event_obj_id_edit.svelte';
|
||||
// import Comp__event_obj_id_view from './ae_idaa_comp__event_obj_id_view.svelte';
|
||||
|
||||
// let event_id = page.url.searchParams.get('event_id') ?? null;
|
||||
// if (!event_id) {
|
||||
// $idaa_slct.event_id = null;
|
||||
// } else {
|
||||
// console.log(`ae Recovery Meetings - [event_id] +page.ts: event_id = `, event_id);
|
||||
// $idaa_slct.event_id = event_id;
|
||||
// $idaa_trig.event_id = event_id;
|
||||
// }
|
||||
|
||||
if (browser) {
|
||||
$idaa_slct.event_id = null; // Just in case
|
||||
let message = { event_id: null };
|
||||
window.parent.postMessage(message, '*');
|
||||
|
||||
$idaa_trig.event_li_qry = true;
|
||||
// $idaa_trig = 'load__event_obj_li';
|
||||
$idaa_slct.event_id = null;
|
||||
window.parent.postMessage({ event_id: null }, '*');
|
||||
|
||||
// Use versioning instead of boolean to avoid loops
|
||||
if ($idaa_loc.recovery_meetings.search_version === undefined) {
|
||||
$idaa_loc.recovery_meetings.search_version = 0;
|
||||
}
|
||||
$idaa_loc.recovery_meetings.search_version++;
|
||||
}
|
||||
|
||||
let event_id_random_li: Array<string> = $state([]);
|
||||
|
||||
// *** Functions and Logic
|
||||
|
||||
// Debounced Search Logic (Refactored 2026-01-27)
|
||||
let search_debounce_timer: any = null;
|
||||
let last_search_id = 0;
|
||||
|
||||
// Standardized Reactive Search Pattern (Aether UI V3)
|
||||
$effect(() => {
|
||||
// Reactive dependencies
|
||||
const qry_str = $idaa_loc.recovery_meetings.qry__fulltext_str;
|
||||
const qry_physical = $idaa_loc.recovery_meetings.qry__physical;
|
||||
const qry_virtual = $idaa_loc.recovery_meetings.qry__virtual;
|
||||
const qry_type = $idaa_loc.recovery_meetings.qry__type;
|
||||
const qry_enabled = $idaa_loc.recovery_meetings.qry__enabled;
|
||||
const qry_hidden = $idaa_loc.recovery_meetings.qry__hidden;
|
||||
const qry_limit = $idaa_loc.recovery_meetings.qry__limit;
|
||||
const qry_order_by_li = $idaa_loc.recovery_meetings.qry__order_by_li;
|
||||
const account_id = $ae_loc.account_id;
|
||||
const s_trigger = $idaa_trig.event_li_qry;
|
||||
// 1. Reactive Dependencies
|
||||
// Track filters and the search version (trigger)
|
||||
const qry_params = {
|
||||
v: $idaa_loc.recovery_meetings.search_version,
|
||||
str: $idaa_loc.recovery_meetings.qry__fulltext_str,
|
||||
phys: $idaa_loc.recovery_meetings.qry__physical,
|
||||
virt: $idaa_loc.recovery_meetings.qry__virtual,
|
||||
type: $idaa_loc.recovery_meetings.qry__type,
|
||||
limit: $idaa_loc.recovery_meetings.qry__limit,
|
||||
order: $idaa_loc.recovery_meetings.qry__order_by,
|
||||
account: $ae_loc.account_id
|
||||
};
|
||||
|
||||
// Trigger search on parameter change (debounced)
|
||||
// 2. Debounce Logic
|
||||
if (search_debounce_timer) clearTimeout(search_debounce_timer);
|
||||
search_debounce_timer = setTimeout(() => {
|
||||
handle_search_refresh();
|
||||
// 3. Execution (Untracked to prevent loops)
|
||||
untrack(() => {
|
||||
handle_search_refresh();
|
||||
});
|
||||
}, 350);
|
||||
|
||||
return () => {
|
||||
@@ -99,135 +76,124 @@
|
||||
|
||||
async function handle_search_refresh() {
|
||||
const current_search_id = ++last_search_id;
|
||||
const account_id = $ae_loc.account_id;
|
||||
|
||||
if (log_lvl) console.log(`[Search #${current_search_id}] Refreshing recovery meetings...`);
|
||||
if (log_lvl) console.log(`[Search #${current_search_id}] Refreshing recovery meetings for account: ${account_id}...`);
|
||||
|
||||
$idaa_sess.recovery_meetings.qry__status = 'loading';
|
||||
|
||||
// Clearing logic for hidden/disabled filter changes
|
||||
if ($idaa_loc.recovery_meetings.qry__enabled !== 'all' || $idaa_loc.recovery_meetings.qry__hidden !== 'all') {
|
||||
await db_events.event.clear();
|
||||
// Snapshot current params to ensure Fast Path matches revalidation
|
||||
const qry_str = ($idaa_loc.recovery_meetings.qry__fulltext_str ?? '').toLowerCase().trim();
|
||||
const qry_physical = $idaa_loc.recovery_meetings.qry__physical;
|
||||
const qry_virtual = $idaa_loc.recovery_meetings.qry__virtual;
|
||||
const qry_type = $idaa_loc.recovery_meetings.qry__type;
|
||||
const remote_first = $idaa_loc.recovery_meetings.qry__remote_first;
|
||||
|
||||
let local_ids: string[] = [];
|
||||
|
||||
try {
|
||||
if (account_id) {
|
||||
// DEBUG: Inspect the first few items in the DB to check account_id format
|
||||
if (log_lvl > 1) {
|
||||
const sample = await db_events.event.limit(5).toArray();
|
||||
console.log(`[Search #${current_search_id}] DB Sample:`, sample.map(s => ({id: s.id, acct: s.account_id, acct_r: s.account_id_random})));
|
||||
}
|
||||
|
||||
let local_results = await db_events.event
|
||||
.filter(ev => {
|
||||
// Resilient account check: match either account_id or account_id_random
|
||||
const acct_match = ev.account_id === account_id || ev.account_id_random === account_id;
|
||||
if (!acct_match) return false;
|
||||
|
||||
if (qry_type && ev.type !== qry_type) return false;
|
||||
if (qry_physical || qry_virtual) {
|
||||
let match = false;
|
||||
if (qry_physical && ev.physical) match = true;
|
||||
if (qry_virtual && ev.virtual) match = true;
|
||||
if (!match) return false;
|
||||
}
|
||||
if (qry_str) {
|
||||
const name = (ev.name ?? '').toLowerCase();
|
||||
const desc = (ev.description ?? '').toLowerCase();
|
||||
const loc = (ev.location_text ?? '').toLowerCase();
|
||||
return name.includes(qry_str) || desc.includes(qry_str) || loc.includes(qry_str);
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.toArray();
|
||||
|
||||
// Sort local results
|
||||
if ($idaa_loc.recovery_meetings.qry__order_by === 'name') {
|
||||
local_results.sort((a, b) => (a.name ?? '').localeCompare(b.name ?? ''));
|
||||
} else {
|
||||
local_results.sort((a, b) => {
|
||||
const dateA = a.updated_on ? new Date(a.updated_on).getTime() : 0;
|
||||
const dateB = b.updated_on ? new Date(b.updated_on).getTime() : 0;
|
||||
return dateB - dateA;
|
||||
});
|
||||
}
|
||||
|
||||
local_ids = local_results.map(e => e.event_id_random || e.id).filter(Boolean);
|
||||
|
||||
// Update UI immediately with local results
|
||||
if (current_search_id === last_search_id) {
|
||||
if (log_lvl) console.log(`[Search #${current_search_id}] Fast Path complete. Found ${local_ids.length} items locally.`);
|
||||
event_id_random_li = local_ids;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
if (log_lvl) console.warn('Fast Path failed, waiting for API...', e);
|
||||
}
|
||||
|
||||
// 2. REVALIDATE: Slow API Request
|
||||
try {
|
||||
const results = await events_func.search__event({
|
||||
api_cfg: $ae_api,
|
||||
for_obj_type: 'account',
|
||||
for_obj_id: $ae_loc.account_id,
|
||||
for_obj_id: account_id,
|
||||
qry_conference: false,
|
||||
qry_physical: $idaa_loc.recovery_meetings.qry__physical,
|
||||
qry_virtual: $idaa_loc.recovery_meetings.qry__virtual,
|
||||
qry_type: $idaa_loc.recovery_meetings.qry__type,
|
||||
qry_str: $idaa_loc.recovery_meetings.qry__fulltext_str?.trim() ?? null,
|
||||
qry_physical: qry_physical,
|
||||
qry_virtual: qry_virtual,
|
||||
qry_type: qry_type,
|
||||
qry_str: qry_str || null,
|
||||
enabled: $idaa_loc.recovery_meetings.qry__enabled,
|
||||
hidden: $idaa_loc.recovery_meetings.qry__hidden,
|
||||
limit: $idaa_loc.recovery_meetings.qry__limit,
|
||||
order_by_li: $idaa_loc.recovery_meetings.qry__order_by_li,
|
||||
log_lvl: 0 // Keep noise low during typing
|
||||
log_lvl: 0
|
||||
});
|
||||
|
||||
// Race condition check: only update if this is still the latest request
|
||||
if (current_search_id === last_search_id) {
|
||||
$idaa_slct.event_obj_li = results;
|
||||
event_id_random_li = results.map((e: any) => e.event_id_random);
|
||||
const api_results = results || [];
|
||||
const api_ids = api_results.map((e: any) => e.event_id_random).filter(Boolean);
|
||||
|
||||
// If API returns 0 but local search found broad results, protect the UI
|
||||
if (api_ids.length === 0 && local_ids.length > 0 && !remote_first && !qry_str) {
|
||||
if (log_lvl) console.warn(`[Search #${current_search_id}] Revalidation returned 0. Preserving cache.`);
|
||||
$idaa_sess.recovery_meetings.qry__status = 'done';
|
||||
return;
|
||||
}
|
||||
|
||||
$idaa_slct.event_obj_li = api_results;
|
||||
event_id_random_li = api_ids;
|
||||
$idaa_sess.recovery_meetings.qry__status = 'done';
|
||||
if (log_lvl) console.log(`[Search #${current_search_id}] Done. Found ${results.length} results.`);
|
||||
if (log_lvl) console.log(`[Search #${current_search_id}] Revalidation Complete. Found ${api_ids.length} items.`);
|
||||
}
|
||||
} catch (error) {
|
||||
if (current_search_id === last_search_id) {
|
||||
console.error('Search failed:', error);
|
||||
console.error('Revalidation failed:', error);
|
||||
$idaa_sess.recovery_meetings.qry__status = 'error';
|
||||
if (event_id_random_li.length === 0 && local_ids.length > 0) {
|
||||
event_id_random_li = local_ids;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (browser) {
|
||||
console.log('Browser environment detected.');
|
||||
|
||||
let message = { event_id: $idaa_slct?.event_id ?? null };
|
||||
window.parent.postMessage(message, '*');
|
||||
console.log('Browser environment ready.');
|
||||
window.parent.postMessage({ event_id: $idaa_slct?.event_id ?? null }, '*');
|
||||
}
|
||||
|
||||
|
||||
function add_activity_log({
|
||||
action = 'idaa_meetings_page',
|
||||
action_with = 'none'
|
||||
}: {
|
||||
action?: string;
|
||||
action_with?: string;
|
||||
}) {
|
||||
let last_cache_refresh_iso = new Date($ae_loc?.last_cache_refresh);
|
||||
|
||||
let activity_description = `
|
||||
${$idaa_loc.novi_full_name ?? 'none'} ${$idaa_loc.novi_email ?? 'no-email'}
|
||||
allow=${$ae_loc?.allow_access}
|
||||
last_cache_refresh=${last_cache_refresh_iso.toLocaleString()}
|
||||
data_route=${data?.route.toString() ?? 'unknown'}
|
||||
`;
|
||||
|
||||
let data_kv = {
|
||||
external_client_id: data?.route.id,
|
||||
name: `IDAA: ${$idaa_loc.novi_full_name ?? 'none'} ${$idaa_loc.novi_email ?? ''}`,
|
||||
description: activity_description ?? null,
|
||||
object_type: 'event', // archive, post, event
|
||||
// object_id_random: data?.params?.event_id ?? null,
|
||||
// object_id_random: ae_acct.slct.archive_id, // data?.params?.archive_id ?? null,
|
||||
url_root: data?.url.origin,
|
||||
// url_full_path: data?.url.href,
|
||||
url_full_path: data?.url.pathname,
|
||||
url_params: data?.url.searchParams.toString(),
|
||||
action: action,
|
||||
action_with: action_with ?? 'none',
|
||||
meta_json: {
|
||||
allow_access: $ae_loc?.allow_access,
|
||||
last_cache_refresh: $ae_loc?.last_cache_refresh,
|
||||
last_cache_refresh_iso: last_cache_refresh_iso.toISOString(),
|
||||
last_cache_refresh_locale: last_cache_refresh_iso.toLocaleString(),
|
||||
access_level: $ae_loc?.access_level,
|
||||
iframe: $ae_loc?.iframe
|
||||
// site_access_key: $ae_loc?.site_access_key,
|
||||
// site_domain_access_key: $ae_loc?.site_domain_access_key,
|
||||
// site_domain: $ae_loc?.site_domain,
|
||||
// extra_data: extra_data ?? '',
|
||||
// log_lvl: log_lvl,
|
||||
}
|
||||
};
|
||||
|
||||
core_func.create_ae_obj__activity_log({
|
||||
api_cfg: $ae_api,
|
||||
account_id: $ae_loc.account_id,
|
||||
data_kv: data_kv,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
}
|
||||
|
||||
// let hide_scroll_btn = $state(true); // This is to hide the scroll to top button initially
|
||||
// let scroll_y = $state(75);
|
||||
|
||||
// function go_top() {
|
||||
// document.body.scrollIntoView();
|
||||
// }
|
||||
|
||||
// function scroll_container() {
|
||||
// console.log('Element', document.getElementById('ae_idaa__recovery_meetings'))
|
||||
// return document.getElementById('ae_idaa__recovery_meetings') || document.documentElement || document.body;
|
||||
// // return document.documentElement || document.body;
|
||||
// }
|
||||
|
||||
// function handle_on_scroll() {
|
||||
// if (!scroll_container()) {
|
||||
// return;
|
||||
// }
|
||||
// console.log(`Scroll position: ${scroll_container().scrollTop}`);
|
||||
|
||||
// let show_on_px = 500; // The scroll position at which the button will be shown
|
||||
|
||||
// if (scroll_container().scrollTop > show_on_px) {
|
||||
// hide_scroll_btn = false;
|
||||
// } else {
|
||||
// hide_scroll_btn = true;
|
||||
// }
|
||||
// }
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
@@ -238,21 +204,13 @@
|
||||
|
||||
<Comp__event_obj_qry />
|
||||
|
||||
<!-- preset-filled-surface-100-900 -->
|
||||
<Element_data_store
|
||||
ds_code="recovery_meetings_info"
|
||||
ds_type="html"
|
||||
class_li="
|
||||
rounded-lg
|
||||
preset-outlined-surface-200-800
|
||||
m-auto p-2 space-y-2
|
||||
w-full max-w-xl
|
||||
"
|
||||
class_li="rounded-lg preset-outlined-surface-200-800 m-auto p-2 space-y-2 w-full max-w-xl"
|
||||
show_edit_btn={true}
|
||||
/>
|
||||
|
||||
<!-- Having this if statement seems to help with loading results. Especially new results. Unsure why... 2025-07-10 -->
|
||||
<!-- {#if $lq_new__event_obj_li && $lq_new__event_obj_li?.length} -->
|
||||
{#if Array.isArray(event_id_random_li) && event_id_random_li.length}
|
||||
<Comp__event_obj_li_wrapper
|
||||
{event_id_random_li}
|
||||
@@ -266,12 +224,11 @@
|
||||
{#if $idaa_sess.recovery_meetings.qry__status === 'loading'}
|
||||
<div class="ae_highlight ae_padding_md ae_row ae_flex_justify_center">
|
||||
<span class="fas fa-spinner fa-spin m-1"></span>
|
||||
Loading...
|
||||
Searching...
|
||||
</div>
|
||||
{:else}
|
||||
<div class="ae_highlight ae_padding_md ae_row ae_flex_justify_center">
|
||||
No recovery meetings available to show. The search may need to be changed.
|
||||
{$idaa_sess.recovery_meetings.qry__status ?? 'Unknown Query Status'}
|
||||
No recovery meetings found matching your criteria.
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -41,17 +41,31 @@
|
||||
// Derived list of visible items (Refactored 2026-01-27)
|
||||
// Ensures count matches exactly what is rendered to the user
|
||||
let visible_event_obj_li = $derived((() => {
|
||||
if (!$lq__event_obj_li) return [];
|
||||
return $lq__event_obj_li
|
||||
.filter((item: any) => {
|
||||
if (!item) return false;
|
||||
// If not trusted, exclude hidden or disabled items
|
||||
if (!$ae_loc.trusted_access) {
|
||||
return !item.hide && item.enable;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.slice(0, $idaa_loc.recovery_meetings.qry__limit);
|
||||
// Subscribe to the LiveQuery observable using $ prefix
|
||||
const list = $lq__event_obj_li;
|
||||
|
||||
if (!list || !Array.isArray(list)) {
|
||||
if (log_lvl > 1) console.log('visible_event_obj_li: Waiting for data stream...');
|
||||
return [];
|
||||
}
|
||||
|
||||
const filtered = list.filter((item: any) => {
|
||||
if (!item) return false;
|
||||
|
||||
// ADMIN/TRUSTED: See everything
|
||||
if ($ae_loc.trusted_access) return true;
|
||||
|
||||
// PUBLIC: Filter hidden/disabled
|
||||
// Safely handle null/undefined fields by assuming visible/enabled (permissive default)
|
||||
const is_hidden = item.hide === true || item.hide === 1;
|
||||
const is_disabled = item.enable === false || item.enable === 0; // Only block if explicitly false/0
|
||||
|
||||
return !is_hidden && !is_disabled;
|
||||
});
|
||||
|
||||
if (log_lvl) console.log(`visible_event_obj_li: Input=${list.length}, Output=${filtered.length} (trusted=${$ae_loc.trusted_access})`);
|
||||
|
||||
return filtered.slice(0, $idaa_loc.recovery_meetings.qry__limit || 150);
|
||||
})());
|
||||
|
||||
if (browser) {
|
||||
|
||||
@@ -54,51 +54,41 @@
|
||||
// *** Functions and Logic
|
||||
let lq__event_obj_li = $derived(
|
||||
liveQuery(async () => {
|
||||
// Check if event_id_random_li is an array and has items
|
||||
// if (Array.isArray(event_id_random_li)) { // && event_id_random_li.length > 0) {
|
||||
if (event_id_random_li && event_id_random_li.length) {
|
||||
if (log_lvl) {
|
||||
(console.log(`Trying IDB bulkGet: ${event_id_random_li.length}`),
|
||||
event_id_random_li);
|
||||
// SCENARIO 1: Specific IDs provided (from Search)
|
||||
// If the search results in an empty array [], we MUST return an empty array to show 0 results.
|
||||
if (Array.isArray(event_id_random_li)) {
|
||||
if (event_id_random_li.length > 0) {
|
||||
if (log_lvl) {
|
||||
console.log(`Wrapper: Loading ${event_id_random_li.length} specific IDs via bulkGet`);
|
||||
}
|
||||
const results = await db_events.event.bulkGet(event_id_random_li);
|
||||
// Filter out undefined items (holes in bulkGet)
|
||||
return results.filter(item => item !== undefined);
|
||||
} else {
|
||||
// Empty array explicitly means 0 results found
|
||||
if (log_lvl) console.log('Wrapper: Search returned 0 specific IDs. Displaying empty list.');
|
||||
return [];
|
||||
}
|
||||
// if (!event_id_random_li.length) {
|
||||
// return [];
|
||||
// }
|
||||
const results = await db_events.event.bulkGet(event_id_random_li);
|
||||
|
||||
// Filter out undefined items (holes in bulkGet)
|
||||
return results.filter(item => item !== undefined);
|
||||
} else if (link_to_type && link_to_id) {
|
||||
}
|
||||
|
||||
// SCENARIO 2: No specific IDs provided (Broad Search fallback)
|
||||
else if (link_to_type && link_to_id) {
|
||||
if (log_lvl) {
|
||||
console.log(
|
||||
`Trying where: ${link_to_type}; equals: ${link_to_id}; event_id_random_li: ${event_id_random_li}`,
|
||||
event_id_random_li
|
||||
);
|
||||
console.log(`Wrapper: No specific IDs. Performing broad search for ${link_to_type}: ${link_to_id}`);
|
||||
}
|
||||
let results: any = null;
|
||||
const base_query = db_events.event
|
||||
.where(dq__where_type_id_val)
|
||||
.equals(dq__where_eq_id_val);
|
||||
|
||||
if (order_by == 'name') {
|
||||
results = await db_events.event
|
||||
.where(dq__where_type_id_val)
|
||||
.equals(dq__where_eq_id_val)
|
||||
.and((event) => {
|
||||
return event.hide == false;
|
||||
})
|
||||
.and((event) => {
|
||||
return event.enable == true;
|
||||
})
|
||||
results = await base_query
|
||||
.and(ev => !ev.hide && !!ev.enable)
|
||||
.limit(limit > 0 ? limit : 500)
|
||||
.sortBy('name');
|
||||
// This should be sorted by a custom sort field
|
||||
} else {
|
||||
results = await db_events.event
|
||||
.where(dq__where_type_id_val)
|
||||
.equals(dq__where_eq_id_val)
|
||||
.and((event) => {
|
||||
return event.hide == false;
|
||||
})
|
||||
.and((event) => {
|
||||
return event.enable == true;
|
||||
})
|
||||
results = await base_query
|
||||
.and(ev => !ev.hide && !!ev.enable)
|
||||
.limit(limit > 0 ? limit : 500)
|
||||
.sortBy('updated_on');
|
||||
}
|
||||
|
||||
@@ -54,6 +54,13 @@
|
||||
}
|
||||
|
||||
// *** Functions and Logic
|
||||
function handle_search_trigger() {
|
||||
if ($idaa_loc.recovery_meetings.search_version === undefined) {
|
||||
$idaa_loc.recovery_meetings.search_version = 0;
|
||||
}
|
||||
$idaa_loc.recovery_meetings.search_version++;
|
||||
}
|
||||
|
||||
function preventDefault<T extends Event>(fn: (event: T) => void) {
|
||||
return function (event: T) {
|
||||
event.preventDefault();
|
||||
@@ -92,7 +99,7 @@
|
||||
<!-- WARNING: Using m-auto to work in the Novi iframe -->
|
||||
<form
|
||||
onsubmit={preventDefault(() => {
|
||||
$idaa_trig.event_li_qry = true;
|
||||
handle_search_trigger();
|
||||
})}
|
||||
autocomplete="off"
|
||||
class="
|
||||
@@ -116,7 +123,7 @@
|
||||
onclick={() => {
|
||||
$idaa_loc.recovery_meetings.qry__fulltext_str = '';
|
||||
$idaa_sess.recovery_meetings.qry__fulltext_str = '';
|
||||
$idaa_trig.event_li_qry = true;
|
||||
handle_search_trigger();
|
||||
}}
|
||||
title="Clear search text"
|
||||
>
|
||||
@@ -260,6 +267,21 @@
|
||||
title="Open to spouses, parents, and children of medical professionals who have substance use disorder."
|
||||
/>
|
||||
</label>
|
||||
|
||||
<span class="ml-auto"></span>
|
||||
|
||||
<label
|
||||
class="legend w-auto text-sm font-semibold inline form-check-label flex-row gap-1 items-center justify-center d-inline-block"
|
||||
title="When enabled, search results are fetched directly from the server first. When disabled, local results are shown instantly while revalidating in the background."
|
||||
>
|
||||
<span class="text-xs"> Remote First? </span>
|
||||
<input
|
||||
name="qry_remote_first"
|
||||
type="checkbox"
|
||||
bind:checked={$idaa_loc.recovery_meetings.qry__remote_first}
|
||||
class="checkbox inline form-check-input d-inline-block"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user