perf(launcher): instrument SWR tracing and optimize session loading flow

This commit is contained in:
Scott Idem
2026-01-30 16:21:46 -05:00
parent 66affb2a0f
commit 1dc0f0d77c
3 changed files with 108 additions and 637 deletions

View File

@@ -10,7 +10,7 @@ import { load_ae_obj_li__event_presentation } from '$lib/ae_events/ae_events__ev
const ae_promises: key_val = {};
// Updated 2026-01-30: Fixed - Removed aggressive ID overwriting
// Updated 2026-01-30: Trace-Ready SWR Pattern
export async function load_ae_obj_id__event_session({
api_cfg,
event_session_id,
@@ -41,56 +41,91 @@ export async function load_ae_obj_id__event_session({
log_lvl?: number;
}): Promise<ae_EventSession | null> {
if (log_lvl) {
console.log(`*** load_ae_obj_id__event_session() *** [V3] id=${event_session_id} (SWR)`);
console.log(`🔎 [Trace] load_ae_obj_id__event_session: START (id=${event_session_id}, try_cache=${try_cache})`);
}
// 1. FAST PATH: Return cached data immediately
if (try_cache) {
try {
const cached = await db_events.session.get(event_session_id);
if (cached) {
if (log_lvl) console.log(`✅ [Trace] load_ae_obj_id: CACHE HIT. Returning stale data for id=${event_session_id}`);
// Background refresh & nested loads (non-blocking)
_refresh_session_id_background({
api_cfg, event_session_id, view, try_cache,
inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li,
enabled, hidden, limit, offset, log_lvl: 0
enabled, hidden, limit, offset, log_lvl: log_lvl > 1 ? log_lvl : 0
});
return await _handle_nested_loads(cached, { api_cfg, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache, log_lvl: 0 });
} else if (log_lvl) {
console.log(`⏳ [Trace] load_ae_obj_id: CACHE MISS for id=${event_session_id}`);
}
} catch (e) {}
} catch (e) {
if (log_lvl) console.error(`❌ [Trace] load_ae_obj_id: Cache access error:`, e);
}
}
// 2. SLOW PATH: Wait for API
if (log_lvl) console.log(`🚀 [Trace] load_ae_obj_id: Proceeding to API path for id=${event_session_id}`);
return await _refresh_session_id_background({ api_cfg, event_session_id, view, try_cache, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, log_lvl });
}
/**
* Internal background refresh for a single session
*/
async function _refresh_session_id_background({ api_cfg, event_session_id, view, try_cache, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, log_lvl }: any) {
if (typeof navigator !== 'undefined' && !navigator.onLine) return null;
try {
if (log_lvl) console.log(`📡 [Trace] _refresh_session_id: API Fetching id=${event_session_id}`);
const result = await api.get_ae_obj_v3({ api_cfg, obj_type: 'event_session', obj_id: event_session_id, view, log_lvl });
if (result) {
const processed = await process_ae_obj__event_session_props({ obj_li: [result], log_lvl });
const processed_obj = processed[0];
if (log_lvl) console.log(`📦 [Trace] _refresh_session_id: Received from API (id=${processed_obj.id})`);
if (try_cache) {
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'session', obj_li: [processed_obj], properties_to_save, log_lvl });
if (log_lvl) console.log(`💾 [Trace] _refresh_session_id: Saved to IDB cache.`);
}
return await _handle_nested_loads(processed_obj, { api_cfg, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache: false, log_lvl });
}
} catch (e) {}
} catch (e) {
if (log_lvl) console.error(`❌ [Trace] _refresh_session_id: API error for id=${event_session_id}:`, e);
}
return null;
}
/**
* Helper to handle nested collection loads for a session
*/
async function _handle_nested_loads(session_obj: any, { api_cfg, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache, log_lvl }: any) {
const current_session_id = session_obj.id || session_obj.event_session_id;
if (!current_session_id) return session_obj;
const tasks = [];
if (inc_file_li) {
tasks.push(load_ae_obj_li__event_file({ api_cfg, for_obj_type: 'event_session', for_obj_id: current_session_id, enabled, limit: 15, try_cache, log_lvl }).then(res => session_obj.event_file_li = res));
tasks.push(load_ae_obj_li__event_file({
api_cfg, for_obj_type: 'event_session', for_obj_id: current_session_id,
enabled, limit: 15, try_cache, log_lvl
}).then(res => session_obj.event_file_li = res));
}
if (inc_presentation_li) {
tasks.push(load_ae_obj_li__event_presentation({ api_cfg, for_obj_type: 'event_session', for_obj_id: current_session_id, inc_file_li: inc_all_file_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache, log_lvl }).then(res => session_obj.event_presentation_li = res));
tasks.push(load_ae_obj_li__event_presentation({
api_cfg, for_obj_type: 'event_session', for_obj_id: current_session_id,
inc_file_li: inc_all_file_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache, log_lvl
}).then(res => session_obj.event_presentation_li = res));
}
if (tasks.length > 0) await Promise.all(tasks);
return session_obj;
}
// Updated 2026-01-30: Robust Cache Lookups with Tracing
export async function load_ae_obj_li__event_session({
api_cfg,
for_obj_type = 'event',
@@ -131,17 +166,32 @@ export async function load_ae_obj_li__event_session({
log_lvl?: number;
}): Promise<ae_EventSession[]> {
if (log_lvl) {
console.log(`*** load_ae_obj_li__event_session() *** [V3] for=${for_obj_type}:${for_obj_id} (SWR)`);
console.log(`🔎 [Trace] load_ae_obj_li__event_session: START (for=${for_obj_type}:${for_obj_id}, try_cache=${try_cache})`);
}
if (try_cache) {
try {
const cached_li = await db_events.session.where('event_location_id').equals(for_obj_id).toArray();
// Robust lookup logic
let query;
if (for_obj_type === 'event_location') query = db_events.session.where('event_location_id').equals(for_obj_id);
else if (for_obj_type === 'event') query = db_events.session.where('event_id').equals(for_obj_id);
else query = db_events.session.where('for_id').equals(for_obj_id);
const cached_li = await query.toArray();
if (cached_li && cached_li.length > 0) {
_refresh_session_li_background({ api_cfg, for_obj_type, for_obj_id, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, order_by_li, try_cache, log_lvl: 0 });
if (log_lvl) console.log(`✅ [Trace] load_ae_obj_li: CACHE HIT (${cached_li.length} items).`);
// Background refresh (non-blocking)
_refresh_session_li_background({ api_cfg, for_obj_type, for_obj_id, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, order_by_li, try_cache, log_lvl: log_lvl > 1 ? log_lvl : 0 });
return cached_li;
} else if (log_lvl) {
console.log(`⏳ [Trace] load_ae_obj_li: CACHE MISS for type=${for_obj_type} id=${for_obj_id}`);
}
} catch (e) {}
} catch (e) {
if (log_lvl) console.error(`❌ [Trace] load_ae_obj_li: Cache access error:`, e);
}
}
return await _refresh_session_li_background({ api_cfg, for_obj_type, for_obj_id, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, order_by_li, try_cache, log_lvl });
@@ -150,15 +200,22 @@ export async function load_ae_obj_li__event_session({
async function _refresh_session_li_background({ api_cfg, for_obj_type, for_obj_id, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, order_by_li, try_cache, log_lvl }: any) {
if (typeof navigator !== 'undefined' && !navigator.onLine) return [];
try {
if (log_lvl) console.log(`📡 [Trace] _refresh_session_li: API Fetching for=${for_obj_type}:${for_obj_id}`);
const result_li = await api.get_ae_obj_li_v3({ api_cfg, obj_type: 'event_session', for_obj_type, for_obj_id, enabled, hidden, limit, offset, order_by_li, log_lvl });
if (result_li) {
const processed = await process_ae_obj__event_session_props({ obj_li: result_li, log_lvl });
if (log_lvl) console.log(`📦 [Trace] _refresh_session_li: Received ${processed.length} items from API.`);
if (try_cache) {
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'session', obj_li: processed, properties_to_save, log_lvl });
if (log_lvl) console.log(`💾 [Trace] _refresh_session_li: Saved to IDB cache.`);
}
return processed;
}
} catch (e) {}
} catch (e) {
if (log_lvl) console.error(`❌ [Trace] _refresh_session_li: API error:`, e);
}
return [];
}

View File

@@ -21,6 +21,7 @@
import {
// Brain,
// House, Library,
LoaderCircle,
// RefreshCw,
Satellite
} from '@lucide/svelte';
@@ -130,15 +131,11 @@
// Event
let lq__event_obj = $derived(
liveQuery(async () => {
if (log_lvl) {
if (log_lvl > 1) {
console.log(`lq__event_obj: event_id = ${$events_slct?.event_id}`);
}
let results = await db_events.event.get($events_slct?.event_id ?? ''); // null or undefined does not reset things like '' does
if (log_lvl) {
console.log(`lq__event_obj: results = `, results);
}
// tmp_event_obj = { ...results };
// Check if results are different than the current session version stored under $events_slct
if ($events_slct.event_obj && results) {
@@ -150,12 +147,6 @@
$events_slct.event_obj
);
}
} else {
if (log_lvl) {
console.log(
`Session slct stored version has not changed for ID = ${$events_slct.event_id}`
);
}
}
}
@@ -166,32 +157,12 @@
// Event Device
let lq__event_device_obj = $derived(
liveQuery(async () => {
if (log_lvl) {
console.log(
`lq__event_device_obj: event_device_id = ${$events_slct?.event_device_id}`
);
}
let results = await db_events.device.get($events_slct.event_device_id);
if (log_lvl) {
console.log(`lq__event_device_obj: results = `, results);
}
// Check if results are different than the current session version stored under $events_slct
if ($events_slct.event_device_obj && results) {
if (JSON.stringify($events_slct.event_device_obj) !== JSON.stringify(results)) {
$events_slct.event_device_obj = { ...results };
if (log_lvl) {
console.log(
`Device slct stored version has changed for ID = ${$events_slct.event_device_id}`,
$events_slct.event_device_obj
);
}
} else {
if (log_lvl > 1) {
console.log(
`Device slct stored version has not changed for ID = ${$events_slct.event_device_id}`
);
}
}
}
@@ -247,56 +218,15 @@
// Event Session
let lq__event_session_obj = $derived(
liveQuery(async () => {
if (log_lvl) console.log(`🔍 [Trace] Launcher Layout LQ: Fetching session_id=${$events_slct.event_session_id}`);
let results = await db_events.session.get($events_slct.event_session_id);
if (log_lvl) console.log(`📦 [Trace] Launcher Layout LQ: Result=`, results?.name || 'NOT FOUND');
return results;
})
);
// let lq__event_session_obj_li = $derived(liveQuery(async () => {
// let results = await db_events.session
// // .bulkGet(event_session_id_li);
// .where('event_location_id')
// .equals($events_slct.event_location_id)
// .sortBy('name');
// return results;
// }));
// let lq__event_session_obj_li = $derived(liveQuery(async () => {
// let results = await db_events.session
// .where('event_location_id')
// .equals($events_slct.event_location_id)
// // .and((x) => (x.archive_on === null || x.archive_on > (new Date()).toISOString()))
// // .and((x) => (x.archive_on === null || x.archive_on > (new Date()).toISOString())) // null or future events only
// // .and((x) => (x.archive_on < (new Date()).toISOString())) // past events only
// // .and((x) => (x.archive_on > (new Date()).toISOString())) // future events only
// // .orderBy('updated_on')
// // .toArray()
// .reverse()
// // .limit($idaa_loc.bb.qry__limit)
// .sortBy('name');
// // .sortBy('tmp_sort_1');
// // .sortBy('updated_on');
// // .sortBy('updated_on, created_on');
// // .sortBy('[updated_on+created_on]');
// // .sortBy('[created_on+updated_on]');
// return results;
// }));
let lq__event_session_obj_li = $derived(
liveQuery(async () => {
log_lvl = 1;
if (log_lvl) {
console.log(`LQ - $lq__event_obj.cfg_json = `, $lq__event_obj?.cfg_json);
console.log(
`LQ - $events_loc.filter__category_code = `,
$events_loc.filter__category_code
);
}
if ($events_sess.session_li_trigger && !$events_sess?.session_li) {
$events_sess.session_li = null;
$events_sess.session_li_trigger = false;
@@ -305,57 +235,18 @@
let results;
if ($events_sess?.session_li && $events_sess?.session_li?.length) {
// if (log_lvl) {
// console.log(`LQ - Using $events_sess.session_li to get event sessions.`);
// }
// // $events_sess.session_li_trigger = false;
// let event_session_id_li = []; // This is to prevent the array from constantly updating and triggering the liveQuery.
// for (let i = 0; i < $events_sess?.session_li.length; i++) {
// let event_session_obj = $events_sess?.session_li[i];
// let event_session_id = event_session_obj.event_session_id;
// event_session_id_li.push(event_session_id);
// }
// // let event_session_id_li = tmp_li;
// results = await db_events.session
// .bulkGet(event_session_id_li);
// } else if ($lq__event_obj?.cfg_json?.session_group_sort === 'DESC') {
// if (log_lvl) {
// console.log(`LQ - Using DESC sort for Event Session list event_id: ${$events_slct?.event_id}`);
// }
// results = await db_events.session
// // .orderBy('updated_on')
// .where('event_id')
// .equals($events_slct?.event_id ?? '') // null or undefined does not reset things like '' does
// .reverse()
// // .sortBy('tmp_sort_2');
// .sortBy('updated_on');
// // .sortBy('title');
// } else if ($events_loc.filter__category_code && $events_loc.filter__category_code.length > 0) {
// if (log_lvl) {
// console.log(`LQ - Using category filter: ${$events_loc.filter__category_code}`);
// }
// results = await db_events.session
// .where('event_id')
// .equals($events_slct?.event_id ?? '') // null or undefined does not reset things like '' does
// .and(session => session.category_code === $events_loc.filter__category_code)
// .reverse()
// .sortBy('tmp_sort_1');
// Pre-filtered list in session storage
} else if ($events_slct.event_location_id) {
if (log_lvl) {
// console.log(`$lq__event_obj.cfg_json = `, $lq__event_obj?.cfg_json);
if (log_lvl > 1) {
console.log(
`LQ - Using default sort for Event Session list event_id: ${$events_slct?.event_id}`
`LQ - Using default sort for Event Session list location_id: ${$events_slct?.event_location_id}`
);
}
results = await db_events.session
.where('event_location_id')
.equals($events_slct.event_location_id)
// .where('event_id')
// .equals($events_slct?.event_id ?? '') // null or undefined does not reset things like '' does
.reverse()
.sortBy('name');
// .sortBy('tmp_sort_1');
// .sortBy('updated_on');
}
// Check if results are different than the current session version stored under $events_slct
@@ -364,18 +255,6 @@
JSON.stringify($events_slct.event_session_obj_li) !== JSON.stringify(results)
) {
$events_slct.event_session_obj_li = [...(results || [])];
if (log_lvl) {
console.log(
`Session slct li stored version has changed for ID = ${$events_slct.event_id}`,
$events_slct.event_session_obj_li
);
}
} else {
if (log_lvl > 1) {
console.log(
`Session slct li stored version has not changed for ID = ${$events_slct.event_id}`
);
}
}
return results;
@@ -401,7 +280,6 @@
/* *** BEGIN *** Handle WebSocket events */
function handle_ws_conn(ws_conn_status: any) {
log_lvl = 1;
if (log_lvl) {
console.log('*** handle_ws_conn() ***', ws_conn_status);
}
@@ -419,7 +297,6 @@
// This client received a WebSocket message.
// When this is called something seems to go wrong. It creates a loop when connected.
function handle_ws_recv(ws_recv_status: any) {
log_lvl = 1;
if (log_lvl) {
console.log('*** handle_ws_recv() ***', ws_recv_status);
}
@@ -447,46 +324,21 @@
if (log_lvl) {
console.log(`ae_load: ${obj_type} ${obj_id}`);
}
if (log_lvl > 1) {
console.log(cmd);
}
if (obj_type == 'event_session') {
$events_slct.event_session_id = obj_id;
// $slct_trigger = 'event_session';
// $events_sess.launcher.show_launcher_message = false;
// data.url.searchParams.set('session_id', $events_slct.event_session_id);
// let new_url = data.url.toString();
// console.log(new_url);
// goto(new_url, {replaceState: false});
// ae_promises.slct_event_session_id = events_func.load_ae_obj_id__event_session({
// api_cfg: $ae_api,
// event_session_id: $events_slct.event_session_id,
// inc_file_li: true,
// inc_presentation_li: true,
// try_cache: true,
// log_lvl: log_lvl
// })
// .then(async (load_results) => {
// });
// tick();
console.log(`Current URL`, data.url);
if (log_lvl) console.log(`[WS Trace] Current URL`, data.url);
let new_url = new URL(data.url);
new_url.pathname = `/events/${$lq__event_session_obj?.event_id}/launcher/${$lq__event_session_obj?.event_location_id}`;
new_url.searchParams.set('session_id', $events_slct.event_session_id);
console.log(`New URL: ${new_url}`);
if (log_lvl) console.log(`[WS Trace] New URL: ${new_url}`);
let new_url_str = new_url.toString();
goto(new_url_str, { replaceState: false });
}
// AE Download (event file ID)
// This does not yet work with the native app caching.
} else if (cmd.startsWith('ae_download:')) {
log_lvl = 1;
let cmd_parts = cmd.split(':');
let obj_parts = cmd_parts[1].split('=');
let obj_type = obj_parts[0];
@@ -499,9 +351,6 @@
`ae_download: ${obj_type} ${obj_id} ${obj_filename} ${obj_extension}`
);
}
if (log_lvl > 1) {
console.log(cmd);
}
ae_promises[obj_id] = api.download_hosted_file({
api_cfg: $ae_api,
@@ -522,9 +371,6 @@
if (log_lvl) {
console.log(`ae_open: ${obj_type} ${obj_id}`);
}
if (log_lvl > 1) {
console.log(cmd);
}
// NOTE: This is not finished yet.
if (obj_type == 'event_file') {
@@ -541,45 +387,18 @@
$events_sess.launcher.modal__title = $events_sess.launcher.modal__title ?? '*';
$events_sess.launcher.modal__open_event_file_id = $events_slct.event_file_id;
// $events_sess.launcher.modal__event_file_obj = event_file_obj;
// $events_sess.launcher.modal__img_src = `/event/file/${event_file_obj.event_file_id}/download`;
// $events_slct.event_file_obj = event_file_obj;
// $slct_trigger = 'event_file';
// $events_sess.launcher.event_file_open.open_status = 'open';
// $events_sess.launcher.show_launcher_message = false;
// NOTE: This is not finished yet.
// This should now trigger the Svelte component for the event launcher file container. Currently this does nothing. Need to bind to something or use the "events_sess.launcher" object?
// let as_modal_result = open_event_file_as_modal({event_file_id: event_file_obj.event_file_id, method: 'modal', filename: event_file_obj.filename, extension: event_file_obj.extension, modal_title: poster_title});
// if (as_modal_result) {
// console.log($events_sess.launcher);
// console.log(event_file_obj);
// events_sess.launcher.set({...$events_sess.launcher, ...as_modal_result});
// }
}
// NOTE: This is not finished yet.
// AE Close (event file modal)
} else if (cmd.startsWith('ae_close:')) {
console.log();
let cmd_parts = cmd.split(':');
let what = cmd_parts[1];
// let obj_type = obj_parts[0];
// let obj_id = obj_parts[1];
if (what == 'event_file_modal') {
$events_sess.launcher.modal__title = '';
$events_sess.launcher.modal__open_event_file_id = null;
$events_sess.launcher.modal__event_file_obj = null;
// $events_sess.launcher.modal__img_src = null;
// $events_slct.event_file_id = null;
// $slct_trigger = 'event_file';
// $events_sess.launcher.event_file_open.open_status = 'close';
}
clearInterval(idle_timer_interval);
@@ -588,64 +407,25 @@
// WORKING! AE Refresh (now)
} else if (cmd.startsWith('ae_refresh:')) {
console.log();
let cmd_parts = cmd.split(':');
let what = cmd_parts[1];
// let obj_type = obj_parts[0];
// let obj_id = obj_parts[1];
if (what == 'now') {
// window.localStorage.clear();
location.reload();
} else {
console.log('OOPS? What went wrong?');
}
}
} else {
if (log_lvl) {
console.log('Unrecognized WS event received. Probably just a message.');
}
}
}
// This client sent a WebSocket message.
function handle_ws_sent(ws_sent_status: any) {
console.log('*** handle_ws_sent() ***', ws_sent_status);
let command = ws_sent_status.cmd;
console.log(`CMD: ${command}`);
if (log_lvl) console.log('*** handle_ws_sent() ***', ws_sent_status);
$events_sess.launcher.controller_cmd = null;
$events_sess.launcher.controller_trigger_send = null;
}
/* *** END *** Handle WebSocket events */
$effect(() => {
if (
$slct_trigger == 'event_file' &&
$events_slct.event_file_id &&
$events_sess.launcher?.event_file_open.open_status == 'open'
) {
$slct_trigger = null;
// handle_event_file_open();
}
// if ($events_sess.launcher.trigger_open_file) {
// $events_sess.launcher.trigger_modal_open_file = false;
// handle_event_file_open();
// }
});
$effect(() => {
if (
$slct_trigger == 'event_file' &&
$events_sess.launcher?.event_file_open.open_status == 'close'
) {
$slct_trigger = null;
// Assuming just event file modal for now
// handle_event_file_close();
}
});
$effect(() => {
if (trigger_handle_ws_conn) {
let ws_conn_status = trigger_handle_ws_conn; // This a string status
@@ -670,79 +450,33 @@
}
});
async function handle_event_file_open() {
let event_file_obj;
if ($events_slct.event_file_obj && $events_slct.event_file_obj.event_file_id) {
console.log($events_slct.event_file_obj);
event_file_obj = $events_slct.event_file_obj;
} else {
console.log('Need to look up the event file details first.');
// let get_event_file_obj_result = await get_event_file_obj({event_file_id: $events_slct.event_file_id});
// event_file_obj = get_event_file_obj_result;
// console.log(event_file_obj);
}
// let as_modal_result = open_event_file_as_modal({
// event_file_id: event_file_obj.event_file_id,
// filename: event_file_obj.filename,
// extension: event_file_obj.extension,
// modal_title: ae_util.shorten_filename(event_file_obj.filename, 75)
// });
// if (as_modal_result) {
// console.log($events_sess.launcher);
// events_sess.launcher.set({...$events_sess.launcher, ...as_modal_result});
// // $events_sess.launcher.event_file_open = as_modal_result;
// }
}
async function handle_event_file_close() {
// let as_modal_result = close_event_file_as_modal({});
// if (as_modal_result) {
// events_sess.update(n => {
// n.launcher = { ...n.launcher, ...as_modal_result };
// return n;
// });
// }
}
if (!$events_loc.launcher.idle_timer) {
$events_loc.launcher.idle_timer = 5 * 60 * 1000;
}
// $events_loc.launcher.idle_timer = .25 * 60 * 1000;
if (!$events_loc.launcher.idle_cycle) {
$events_loc.launcher.idle_cycle = 5 * 1000;
}
if (!$events_loc.launcher.idle_loop_period) {
$events_loc.launcher.idle_loop_period = 3 * 60 * 1000;
}
// Safer to run this once the component has mounted and initialized???
listen({
timer: $events_loc.launcher.idle_timer, // $events_loc.launcher.idle_timer ?? 30 * 60 * 1000,
cycle: $events_loc.launcher.idle_cycle ?? 5 * 1000 // How frequently the idle status is checked
timer: $events_loc.launcher.idle_timer,
cycle: $events_loc.launcher.idle_cycle ?? 5 * 1000
});
let idle_timer_interval: any = $state();
// clearInterval(idle_timer_interval);
let saver_looping: boolean = $state(false);
function handle_idle_client() {
// Start the digital poster screen saver after additional idle time.
if ($lq__event_session_obj && $lq__event_session_obj?.type_code == 'poster') {
if (log_lvl) {
console.log(
`Turned idle! Open poster file for poster session in ${($events_loc.launcher.idle_loop_period / 60000).toPrecision(4)} minutes.`
);
}
if (saver_looping) {
console.log('Screen saver already looping.');
return false;
}
if (saver_looping) return false;
saver_looping = true;
@@ -754,20 +488,11 @@
);
}
// console.log($events_loc.launcher.screen_saver_img_kv.length());
if ($events_loc.launcher.screen_saver_img_kv) {
console.log($events_loc.launcher.screen_saver_img_kv);
let modal_title: string = '';
const rand_index = Math.floor(
Math.random() *
Object.keys($events_loc.launcher.screen_saver_img_kv).length
);
if (log_lvl) {
console.log(`Random index = ${rand_index}`);
}
let event_file_obj =
$events_loc.launcher.screen_saver_img_kv[
@@ -776,41 +501,26 @@
$events_slct.event_file_id = event_file_obj.event_file_id;
$events_slct.event_file_obj = event_file_obj;
// $slct_trigger = 'event_file';
// $events_loc.launcher.event_file_open.open_status = 'open';
$events_sess.launcher.modal__open_event_file_id = null;
// clearInterval(idle_timer_interval);
// if (!modal_title) {
// modal_title = event_file_obj.filename;
// }
$events_sess.launcher.modal__title = event_file_obj.filename ?? '*';
$events_sess.launcher.modal__open_event_file_id =
$events_slct.event_file_id;
$events_sess.launcher.modal__event_file_obj = event_file_obj;
// $events_sess.launcher.modal__img_src = `/event/file/${event_file_obj.event_file_id}/download`;
return true;
}
console.log('No screen saver images found.');
return false;
},
$events_loc.launcher.idle_loop_period ?? 2 * 60 * 1000
);
// console.log('User is no longer idle???');
} else {
console.log('Not a poster session so no screen saver.');
saver_looping = false;
return false;
}
}
onIdle(() => {
// This is called when the user has gone idle for the specified time.
// alert('USER IS IDLE');
log_lvl = 1;
if (log_lvl) {
console.log(
`User has gone idle after ${($events_loc.launcher?.idle_timer / 60000).toPrecision(4)} minutes.`,
@@ -818,23 +528,12 @@
);
}
clearInterval(idle_timer_interval);
handle_idle_client();
});
$effect(() => {
if ($idle) {
// log_lvl = 1;
// if (log_lvl) {
// console.log(`User has gone idle after ${($events_loc.launcher?.idle_timer / 60000).toPrecision(4)} minutes.`, $idle);
// }
// // clearInterval(idle_timer_interval);
// if (!saver_looping) {
// handle_idle_client();
// }
} else {
log_lvl = 1;
if (log_lvl) {
if (!$idle) {
if (log_lvl > 1) {
console.log(
`User is active again after being idle. End screen saver if active.`,
$idle
@@ -847,7 +546,6 @@
</script>
<svelte:head>
<!-- {ae_util.shorten_string({ string: $lq__event_obj?.name ?? '', max_length: 20, begin_length: 10, end_length: 4 })} -->
<title>
&AElig;:
{$lq__event_location_obj?.name ?? '-- not set --'}
@@ -856,7 +554,6 @@
</title>
</svelte:head>
<!-- outline-2 outline-red-500 -->
<div
class="
static
@@ -897,7 +594,6 @@
}}
title="Toggle Launcher menu"
>
<!-- Be sure to explain what &AElig; (Aether) means in the title text or similar! -->
<Satellite class="text-base mx-1 inline-block text-gray-500" />
<abbr title="Aether - Events Module Launcher">
Æ Launcher
@@ -934,7 +630,6 @@
{/if}
</header>
<!-- The menu should be to the left of the main session view. -->
<div
class="
h-full min-w-full w-full max-w-full
@@ -961,13 +656,6 @@
"
class:hidden={$events_loc.launcher.hide__launcher_menu}
>
<!-- overflow-y-auto -->
<!-- {#await $events_slct.id_li__event_location}
Loading location list... a
{:then event_location_obj_li} -->
<!-- {#if $lq__event_obj && $lq__event_location_obj_li && $lq__event_session_obj_li && event_location_obj_li && event_location_obj_li.length > 0} -->
<!-- {#if $lq__event_obj && $lq__event_location_obj_li} -->
<Launcher_menu
data_url={data.url}
{lq__event_obj}
@@ -992,14 +680,6 @@
$events_sess.launcher.trigger_reload__event_location_obj_li
}
></Launcher_menu>
<!-- {:else}
<div class="flex flex-row items-center justify-center">
<span class="fas fa-spinner fa-spin mx-1"></span>
<span>Loading location list...</span>
</div>
{/if} -->
<!-- {/await} -->
<!-- Root: slct Location ID: {$events_slct.event_location_id ?? '-- not set --'} -->
</section>
<section
@@ -1016,34 +696,24 @@
overflow-y-auto
"
>
<!-- {#if $events_trigger == 'load__event_session_obj' && $events_slct.event_session_id}
<Launcher_session_view
slct_event_session_id={$events_slct.event_session_id}
lq__event_location_obj={lq__event_location_obj}
lq__event_location_obj_li={lq__event_location_obj_li}
lq__event_session_obj={lq__event_session_obj}
lq__event_session_obj_li={lq__event_session_obj_li}
>
</Launcher_session_view>
{/if} -->
<!-- {$lq__event_session_obj?.name} -->
{#if !$events_slct.event_location_id}
<div class="flex flex-row items-center justify-center">
<span class="fas fa-exclamation mx-1"></span>
<span>You must select a location first</span>
<span class="fas fa-exclamation mx-1"></span>
<div class="flex flex-row items-center justify-center p-8 opacity-50">
<span class="fas fa-map-marker-alt mx-2 text-2xl"></span>
<span>Please select a location from the menu</span>
</div>
{/if}
<!-- Using the loading__session_id_status is kind of a hacky way to determine if the session is still loading or not. -->
{#if $events_slct.event_session_id && $lq__event_session_obj}
<Launcher_session_view
bind:slct__event_session_id={$events_slct.event_session_id}
{lq__event_session_obj}
bind:type_code={$lq__event_session_obj.type_code}
></Launcher_session_view>
{:else if $events_slct.event_session_id}
<div class="flex flex-col items-center justify-center p-8 opacity-50">
<LoaderCircle class="animate-spin mb-2" />
<span>Loading session details...</span>
</div>
{/if}
</section>
</div>
@@ -1051,8 +721,6 @@
{@render children?.()}
</div>
<!-- hover:z-20 -->
<!-- hover:scale-105 -->
<footer
id="Main-Footer"
class:hidden={$events_loc.launcher.hide__launcher_footer}
@@ -1075,10 +743,6 @@
transition-all duration-1000
"
>
<!-- <div>
[Help]
</div> -->
<div
class="slct_location_name transition-all duration-1000"
title="Location ID: {$lq__event_location_obj?.event_location_id} Name: {$lq__event_location_obj?.name} | Device ID: {$lq__event_device_obj?.event_device_id} Name: {$lq__event_device_obj?.name}"
@@ -1115,49 +779,12 @@
{/if}
</span>
<!-- Why does this not behave consistently???? Spent a few hours trying to make it work right. -->
<!-- {#if online.current}
online
{:else}
offline
{/if} -->
<!-- class:preset-tonal-warning={!online?.current} -->
<!-- class:preset-tonal-success={online?.current} -->
<span
class="group px-1 rounded-md transition-all duration-1000"
title="Online status = {online?.current}"
>
<!-- {@html online?.current ? '<span class="fas fa-wifi mx-1"></span> Online!' : '--'} -->
<span class="fas fa-wifi mx-1"></span>
{online?.current ? '' : 'Offline!'}
<!-- {@html online?.current ? '--' : 'No Connection'} -->
<!-- {@html online?.current ? '<span class="fas fa-wifi mx-1"></span> Online!' : '<span class="fas fa-times mx-1 text-red-700"></span> No Connection'} -->
<!-- current value data type = {online.current ? typeof(online.current) : 'null'} -->
<!-- {#if online?.current}
<span class="fas fa-wifi mx-1"></span>
<span class="hidden group-hover:inline">
Online
</span>
{:else}
<span class="fas fa-times mx-1 text-red-700"></span>
<span class="hidden group-hover:inline">
No Connection!
</span>
{/if} -->
<!-- {#if online.current === true}
<span class="fas fa-wifi mx-1"></span>
<span class="hidden group-hover:inline">
Online
</span>
{:else}
<span class="fas fa-times mx-1 text-red-700"></span>
<span class="hidden group-hover:inline">
No Connection!
</span>
{/if} -->
</span>
<span
@@ -1178,24 +805,6 @@
{/if}
</span>
<span
class:hidden={$events_loc.launcher.app_mode != 'native'}
class="group px-1 rounded-md transition-all duration-1000"
class:preset-tonal-warning={!$events_sess.launcher?.av_recording_status}
class:preset-tonal-success={$events_sess.launcher?.av_recording_status}
title="Audio/Video recording is {$events_sess.launcher?.av_recording_status
? 'active'
: 'inactive'}"
>
{#if $events_sess.launcher?.av_recording_status}
<span class="fas fa-video mx-1"></span>
<span class="hidden group-hover:inline"> AV Recording Active </span>
{:else}
<span class="fas fa-video-slash mx-1"></span>
<span class="hidden group-hover:inline"> AV Recording Inactive </span>
{/if}
</span>
<div class="current_datetime font-mono px-2 hover:font-bold hover:bg-white transition-all">
<span class="hidden md:inline">
<span class="fas fa-calendar-alt"></span>
@@ -1209,8 +818,6 @@
{:else}
{ae_util.iso_datetime_formatter($time, 'time_long')}
{/if}
<!-- <span class="fas fa-hourglass fa-spin"></span> -->
<!-- <span class="fas fa-hourglass"></span> -->
</div>
</footer>
@@ -1269,12 +876,6 @@
View Selected Session
</a>
{/if}
<!-- <button
class="btn btn-sm variant-ghost-tertiary hover:variant-filled-tertiary"
>Test 1</button> -->
<!-- <button
class="btn btn-sm variant-ghost-tertiary hover:variant-filled-tertiary"
>Test 2</button> -->
</div>
</Drawer>
@@ -1305,7 +906,6 @@
</div>
<div>
<!-- Show the launcher configuration in JSON format -->
<pre class="text-xs">
{JSON.stringify($events_loc.launcher, null, 2)}
</pre>
@@ -1316,9 +916,6 @@
</div>
</Drawer>
<!-- Main modal -->
<!-- **NOTE:** The modal size is intentionally set to "". This makes it undefined and allows the modal to be as large as the content. **NOTE** -->
<!-- title={$events_sess.launcher?.modal__title} -->
<Modal
open={$events_sess.launcher?.modal__open_event_file_id}
autoclose={false}
@@ -1335,27 +932,8 @@
bodyClass="p-0 space-y-0 overflow-y-auto flex flex-col gap-1 items-center justify-center"
headerClass={`fixed top-0 right-0 left-0 p-1 md:p-2 flex flex-row items-center ${$events_loc.launcher.controller == 'remote' ? 'hidden' : ''} bg-white dark:bg-gray-800 opacity-50 ${$events_loc.launcher.hide__modal_header_title ? 'justify-center' : 'justify-between'}`}
footerClass="text-center hidden"
on:close={async () => {
$events_sess.launcher.modal__open_event_file_id = null;
if (
$events_loc.launcher.controller == 'local_push' &&
$events_sess.launcher.ws_connect_status == 'connected'
) {
// // This should work....????
// console.log(`TEST - FAIL??? Local Push Controller Command: ae_close:event_file_modal`);
// console.log(`Before: ${$events_sess.launcher.controller_trigger_send}`);
// // $events_sess.launcher.controller_cmd = `ae_close:event_file_modal`;
// // $events_sess.launcher.controller_trigger_send = true;
// // $events_sess = $events_sess;
// // events_sess.set($events_sess);
// // tick();
// // events_sess.set($events_sess);
// console.log(`After: ${$events_sess.launcher.controller_trigger_send}`);
}
}}
>
{#snippet header()}
<!-- <div class="flex flex-row items-center justify-between"> -->
<h3
class:hidden={$events_loc.launcher.hide__modal_header_title}
class="text-lg font-semibold opacity-20 hover:opacity-100 transition-all"
@@ -1367,36 +945,18 @@
class="btn flex-row-reverse group transition-all justify-self-end"
onclick={() => {
$events_sess.launcher.modal__open_event_file_id = null;
if (
$events_loc.launcher.controller == 'local_push' &&
$events_sess.launcher.ws_connect_status == 'connected'
) {
}
}}
title="Close Modal"
>
<span class="fas fa-times my-1.5"></span>
<span class="hidden group-hover:inline"> Close</span>
</button>
<!-- </div> -->
{/snippet}
<!-- <svelte:fragment slot="header">
<div class="flex flex-row items-center justify-between">
<h3 class="text-lg font-semibold">
{$events_sess.launcher?.modal__title}
</h3>
</div>
</svelte:fragment> -->
<button
onclick={() => {
console.log(
`TEST - THIS WORKS... Local Push Controller Command: ae_close:event_file_modal`
);
// This is not terrible if we set autoclose to true.
$events_sess.launcher.controller_cmd = `ae_close:event_file_modal`;
$events_sess.launcher.controller_trigger_send = true;
// $events_sess.launcher.modal__open = false;
}}
class="
absolute top-0 right-12
@@ -1414,17 +974,13 @@
<span class="fas fa-tv"></span>
Close Remote Poster Display Only
</button>
<!-- Open: {$ae_api.base_url} {$events_sess.launcher.modal__open_event_file_id} -->
<!-- /event/file/{$events_slct.event_file_obj.event_file_id}/download?filename={$events_slct.event_file_obj.filename}&x_no_account_id_token=direct-download -->
<!-- <span class="aspect-9/16 max-h-96"> -->
{#if $events_sess.launcher.modal__open_event_file_id}
<img
src="{$ae_api.base_url}/event/file/{$events_sess.launcher
.modal__open_event_file_id}/download?filename={$events_slct.event_file_obj
.filename}&x_no_account_id_token=direct-download"
alt="Placeholder: /event/file/{$events_sess.launcher
.modal__open_event_file_id}/download?filename={$events_slct.event_file_obj
.filename}&x_no_account_id_token=direct-download"
alt="Poster"
class="min-h-28 min-w-md max-h-full max-w-full"
/>
{:else}
@@ -1434,17 +990,10 @@
</div>
{/if}
<!-- </span> -->
<button
onclick={() => {
console.log(
`TEST - THIS WORKS... Local Push Controller Command: ae_close:event_file_modal`
);
// This is not terrible if we set autoclose to true.
$events_sess.launcher.controller_cmd = `ae_close:event_file_modal`;
$events_sess.launcher.controller_trigger_send = true;
// $events_sess.launcher.modal__open = false;
}}
class="
absolute bottom-0 left-12
@@ -1463,11 +1012,8 @@
Close Remote Poster Display Only
</button>
<!-- Need to add a re-open button... -->
<button
onclick={() => {
// $events_sess.launcher.modal__open = false;
$events_sess.launcher.modal__title = '';
$events_sess.launcher.modal__open_event_file_id = null;
$events_sess.launcher.modal__event_file_obj = null;
@@ -1487,37 +1033,11 @@
>
<span class="fas fa-times m-1"></span>
<span class="fas fa-list"></span>
Close
<!-- Controller -->
<!-- Local -->
Poster
<!-- Here -->
on This Device
<!-- Only -->
Close Poster on This Device
</button>
<!-- <svelte:fragment slot="footer">
<div class="text-center w-full">
<button
on:click={() => {
$events_sess.launcher.modal__open = false;
}}
class="btn btn-sm variant-soft-warning hover:variant-ghost-warning"
>
<span class="fas fa-times m-1"></span>
Close
</button>
</div>
</svelte:fragment> -->
</Modal>
<!-- {:else}
{$events_sess.launcher.modal__open_event_file_id}
{/if} -->
{#if $events_loc.launcher.controller_group_code && $events_loc.launcher.ws_connect}
<!-- {$ae_api.base_url} -->
<Element_websocket_v2
{log_lvl}
bind:ws_connect={$events_loc.launcher.ws_connect}
@@ -1538,5 +1058,4 @@
bind:ws_recv_status={trigger_handle_ws_recv}
bind:ws_sent_status={trigger_handle_ws_sent}
/>
<!-- on:ws_recv={handle_ws_recv} -->
{/if}
{/if}

View File

@@ -67,20 +67,19 @@
if (trigger_reload__event_session_obj_id) {
if (log_lvl) {
console.log(
`trigger_reload__event_session_obj_id changed: ${trigger_reload__event_session_obj_id}`
`[UI Trace] trigger_reload__event_session_obj_id changed: ${trigger_reload__event_session_obj_id}`
);
}
let event_session_id = trigger_reload__event_session_obj_id;
let event_session_id = String(trigger_reload__event_session_obj_id);
trigger_reload__event_session_obj_id = false;
slct__event_session_id = event_session_id;
console.log(`slct__event_session_id = `, slct__event_session_id);
if (log_lvl) console.log(`[UI Trace] UI setting slct__event_session_id = ${slct__event_session_id}`);
handle_load_ae_obj_id__event_session(event_session_id);
if ($events_loc.launcher.controller == 'local_push') {
console.log(
`Local Push Controller Command: ae_load:event_session=${event_session_id}`
);
if (log_lvl) console.log(`[UI Trace] Local Push Controller Command: ae_load:event_session=${event_session_id}`);
$events_sess.launcher.controller_cmd = `ae_load:event_session=${event_session_id}`;
$events_sess.launcher.controller_trigger_send = true;
}
@@ -88,37 +87,20 @@
data_url.searchParams.set('session_id', event_session_id);
let new_url = data_url.toString();
console.log(new_url);
// goto(new_url, {replaceState: true}); // Updates the URL without adding a new entry to the history
goto(new_url, { replaceState: false }); // Updates the URL history without reloading the page
if (log_lvl) console.log(`[UI Trace] Updating URL to: ${new_url}`);
goto(new_url, { replaceState: false });
}
});
function handle_load_ae_obj_id__event_session(event_session_id: any) {
if (log_lvl) {
console.log(
`handle_load_ae_obj_id__event_session: event_session_id = `,
event_session_id
`[UI Trace] handle_load_ae_obj_id__event_session: Calling library for id=${event_session_id}`
);
}
loading__session_id_status = true;
// slct__event_session_id = null;
// slct__event_session_id = event_session_id;
// $events_slct.event_session_id = event_session_id;
// data_url.searchParams.set('session_id', event_session_id);
// let new_url = data_url.toString();
// console.log(new_url);
// loading__session_id_status = false;
// goto(new_url, {replaceState: true}); // Updates the URL without reloading the page
// goto(new_url, {replaceState: false}); // Updates the URL history without reloading the page
loading__session_id_status = 'loading';
// $events_slct.event_session_obj = event_session_obj;
ae_promises.slct__event_session_id = events_func
.load_ae_obj_id__event_session({
api_cfg: $ae_api,
@@ -129,20 +111,13 @@
log_lvl: log_lvl
})
.then(async (load_results) => {
console.log(`load_results = `, load_results);
if (log_lvl) console.log(`[UI Trace] handle_load_ae_obj_id: Library returned results.`, load_results);
if (load_results) {
$events_slct.event_session_obj = load_results;
$events_slct.event_file_obj_li = load_results.event_file_li ?? [];
$events_slct.event_presentation_obj_li = load_results.event_presentation_li ?? [];
// $events_slct.event_presenter_obj_li = load_results.event_presenter_obj_li;
}
// let new_url = data_url.toString();
// console.log(new_url);
// loading__session_id_status = false;
// // goto(new_url, {replaceState: true}); // Updates the URL without reloading the page
// goto(new_url, {replaceState: false}); // Updates the URL history without reloading the page
})
.finally(() => {
loading__session_id_status = false;
@@ -202,42 +177,6 @@
return;
}
trigger_reload__event_session_obj_id = event_session_obj?.id;
// handle_load_ae_obj_id__event_session(event_session_obj?.id);
// loading__session_id_status = true;
// slct__event_session_id = null;
// slct__event_session_id = event_session_obj?.id;
// // $events_slct.event_session_id = event_session_obj?.id;
// data_url.searchParams.set('session_id', event_session_obj?.id);
// let new_url = data_url.toString();
// console.log(new_url);
// loading__session_id_status = false;
// // goto(new_url, {replaceState: true}); // Updates the URL without reloading the page
// // goto(new_url, {replaceState: false}); // Updates the URL history without reloading the page
// loading__session_id_status = 'loading';
// $events_slct.event_session_obj = event_session_obj;
// ae_promises.slct__event_session_id = events_func.load_ae_obj_id__event_session({
// api_cfg: $ae_api,
// event_session_id: event_session_obj?.id,
// inc_file_li: true,
// inc_presentation_li: true,
// inc_presenter_li: true,
// log_lvl: log_lvl
// })
// .then(async (load_results) => {
// console.log(`load_results = `, load_results);
// // let new_url = data_url.toString();
// // console.log(new_url);
// loading__session_id_status = false;
// // // goto(new_url, {replaceState: true}); // Updates the URL without reloading the page
// // goto(new_url, {replaceState: false}); // Updates the URL history without reloading the page
// });
}, hover_timer_wait);
}}
onmouseleave={() => {
@@ -248,50 +187,6 @@
$events_slct.event_file_id = null;
$events_slct.event_file_obj = null;
// handle_load_ae_obj_id__event_session(event_session_obj?.id);
// loading__session_id_status = true;
// slct__event_session_id = null;
// // await tick();
// slct__event_session_id = event_session_obj?.id;
// // $events_slct.event_session_id = event_session_obj?.id;
// data_url.searchParams.set('session_id', event_session_obj?.id);
// let new_url = data_url.toString();
// console.log(new_url);
// // goto(new_url, {replaceState: true}); // Updates the URL without reloading the page
// // goto(new_url, {replaceState: false}); // Updates the URL history without reloading the page
// loading__session_id_status = 'loading';
// // $events_slct.event_session_id = event_session_obj?.id;
// $events_slct.event_session_obj = event_session_obj;
// ae_promises.slct__event_session_id = events_func.load_ae_obj_id__event_session({
// api_cfg: $ae_api,
// event_session_id: event_session_obj?.id,
// inc_file_li: true,
// inc_presentation_li: true,
// inc_presenter_li: true,
// log_lvl: log_lvl
// })
// .then(async (load_results) => {
// console.log(`load_results = `, load_results);
// // let new_url = data_url.toString();
// // console.log(new_url);
// loading__session_id_status = false;
// // // goto(new_url, {replaceState: true}); // Updates the URL history without reloading the page
// // goto(new_url, {replaceState: false});
// });
// if ($events_loc.launcher.controller == 'local_push') {
// console.log(`Local Push Controller Command: ae_load:event_session=${event_session_obj?.id}`);
// $events_sess.launcher.controller_cmd = `ae_load:event_session=${event_session_obj?.id}`;
// $events_sess.launcher.controller_trigger_send = true;
// }
}}
class="
btn btn-sm hover:preset-filled-primary-500
@@ -310,7 +205,7 @@
"
class:preset-filled-primary-500={slct__event_session_id ===
event_session_obj?.id}
class:preset-tonal-secondary={slct__event_session_id !=
class:preset-tonal-secondary={slct__event_session_id !=
event_session_obj?.id}
class:border-secondary-500={slct__event_session_id != event_session_obj?.id}
class:font-bold={slct__event_session_id === event_session_obj?.id}
@@ -362,4 +257,4 @@
{:else}
<div class="text-sm">No sessions found.</div>
{/if}
</div>
</div>