Files
OSIT-AE-App-Svelte/src/routes/events/[event_id]/(launcher)/launcher/+layout.svelte
Scott Idem 969e5610bb refactor(launcher): standardize helper names and apply batch formatting
- Renamed internal 'preventDefault' to 'prevent_default' in launcher files.
- Fixed native 'event.preventDefault()' call in launcher_file_cont.svelte.
- Applied batch formatting (printWidth: 80) across the (launcher) module.
2026-02-06 14:48:44 -05:00

940 lines
32 KiB
Svelte

<script lang="ts">
let log_lvl: number = $state(1);
interface Props {
/** @type {import('./$types').LayoutData} */
data: any;
children?: import('svelte').Snippet;
}
let { data, children }: Props = $props();
// *** Import Svelte specific
// import { onMount, tick } from 'svelte';
import { goto } from '$app/navigation';
import { sineIn } from 'svelte/easing';
// *** Import other supporting libraries
import { liveQuery } from 'dexie';
import { Drawer, Footer, Modal } from 'flowbite-svelte';
import { listen, idle, onIdle, restartCountdown } from 'svelte-idle';
import {
// Brain,
// House, Library,
LoaderCircle,
// RefreshCw,
Satellite
} from '@lucide/svelte';
// *** Import Aether specific variables and functions
import type { key_val } from '$lib/stores/ae_stores';
import { ae_util } from '$lib/ae_utils/ae_utils';
import { api } from '$lib/api/api';
import { db_events } from '$lib/ae_events/db_events';
import {
ae_snip,
ae_loc,
ae_sess,
ae_api,
ae_trig,
slct,
slct_trigger,
time
} from '$lib/stores/ae_stores';
import {
events_loc,
events_sess,
events_slct,
events_trigger,
events_trig
} from '$lib/stores/ae_events_stores';
import { events_func } from '$lib/ae_events_functions';
import Launcher_cfg from '../launcher_cfg.svelte';
import Launcher_menu from '../launcher_menu.svelte';
import Launcher_session_view from '../launcher_session_view.svelte';
import Element_websocket_v2 from '$lib/elements/element_websocket_v2.svelte';
// *** Set initial variables
let ae_acct = data[$slct.account_id];
import { online } from 'svelte/reactivity/window';
$ae_sess.disable_sys_nav = true;
$ae_sess.disable_sys_header = true;
$ae_sess.disable_sys_footer = true;
if (!$events_loc?.launcher) {
$events_loc.launcher = {
app_mode: 'default',
controller: 'local',
controller_group_code: 'launcher-00',
ws_connect: false,
hide_drawer__cfg: true,
hide_drawer__debug: true
};
}
if (log_lvl) {
console.log(`event_id: ${data.params.event_id}`);
console.log(`event_location_id: ${data.params.event_location_id}`);
console.log(
`event_session_id: ${data.url.searchParams.get('session_id')}`
);
}
$events_slct.event_id = data.params.event_id;
$events_slct.event_location_id = data.params.event_location_id;
$events_slct.event_session_id = data.url.searchParams.get('session_id');
// String-Only ID Vision: Sync the device ID from the native environment
const native_dev = $ae_loc.native_device;
if (native_dev) {
$events_slct.event_device_id =
native_dev.event_device_id ||
native_dev.id ||
native_dev.event_device_id_random ||
native_dev.id_random;
}
$events_slct.event_location_obj_li = ae_acct.slct.event_location_obj_li ?? [
''
];
$events_slct.id_li__event_location = ae_acct.slct.id_li__event_location ?? [
''
];
// *** Functions and Logic
// Event
let lq__event_obj = liveQuery(async () => {
const id = $events_slct?.event_id;
if (!id) return null;
if (log_lvl > 1) console.log(`lq__event_obj: event_id = ${id}`);
let results = await db_events.event.get(id);
if ($events_slct.event_obj && results) {
if (
JSON.stringify($events_slct.event_obj) !==
JSON.stringify(results)
) {
$events_slct.event_obj = { ...results };
}
}
return results;
});
// Event Device
let lq__event_device_obj = liveQuery(async () => {
const id = $events_slct.event_device_id;
if (!id) return null;
let results = await db_events.device.get(id);
if ($events_slct.event_device_obj && results) {
if (
JSON.stringify($events_slct.event_device_obj) !==
JSON.stringify(results)
) {
$events_slct.event_device_obj = { ...results };
}
}
return results;
});
// Event File - For Event
let lq__event_event_file_obj_li = liveQuery(async () => {
const id = $events_slct.event_id;
if (!id) return [];
return await db_events.file
.where('for_id')
.equals(id)
.sortBy('filename');
});
// Event File - For Location
let lq__location_event_file_obj_li = liveQuery(async () => {
const id = $events_slct.event_location_id;
if (!id) return [];
return await db_events.file
.where('for_id')
.equals(id)
.sortBy('filename');
});
// Event Location
let lq__event_location_obj = liveQuery(async () => {
const id = $events_slct.event_location_id;
if (!id) return null;
return await db_events.location.get(id);
});
let lq__event_location_obj_li = liveQuery(async () => {
const id = $events_slct.event_id;
if (!id) return [];
return await db_events.location
.where('event_id')
.equals(id)
.sortBy('name');
});
// Event Session (Main View Trigger)
// Removed $derived wrapper to ensure stable observable subscription in Svelte 5
let lq__event_session_obj = liveQuery(async () => {
const id = $events_slct.event_session_id;
if (!id) return null;
if (log_lvl)
console.log(
`🔍 [Trace] Launcher Layout LQ: Fetching session_id=${id}`
);
const start = performance.now();
let results = await db_events.session.get(id);
if (log_lvl)
console.log(
`📦 [Trace] Launcher Layout LQ: Result obtained in ${(performance.now() - start).toFixed(2)}ms (Result=${results?.name || 'NOT FOUND'})`
);
return results;
});
let lq__event_session_obj_li = liveQuery(async () => {
const id = $events_slct.event_location_id;
if (!id) return [];
if (log_lvl > 1)
console.log(
`LQ - Using default sort for Event Session list location_id: ${id}`
);
let results = await db_events.session
.where('event_location_id')
.equals(id)
.reverse()
.sortBy('name');
if (
$events_slct.event_session_obj_li &&
JSON.stringify($events_slct.event_session_obj_li) !==
JSON.stringify(results)
) {
$events_slct.event_session_obj_li = [...(results || [])];
}
return results;
});
let trigger_handle_ws_conn = $state(false);
let trigger_handle_ws_recv = $state(false);
let trigger_handle_ws_sent = $state(false);
/* *** BEGIN *** Handle WebSocket events */
function handle_ws_conn(ws_conn_status: any) {
if (log_lvl) console.log('*** handle_ws_conn() ***', ws_conn_status);
if (ws_conn_status.status == 'connected') {
$events_sess.launcher.ws = { status: 'connected' };
} else {
$events_sess.launcher.ws = { status: 'disconnected' };
}
}
function handle_ws_recv(ws_recv_status: any) {
if (log_lvl) console.log('*** handle_ws_recv() ***', ws_recv_status);
if (ws_recv_status.type == 'cmd' && ws_recv_status.cmd) {
let cmd = ws_recv_status.cmd;
if ($events_loc.launcher.controller != 'remote') return;
if (cmd.startsWith('ae_load:')) {
let cmd_parts = cmd.split(':');
let obj_parts = cmd_parts[1].split('=');
let obj_type = obj_parts[0];
let obj_id = obj_parts[1];
if (obj_type == 'event_session') {
$events_slct.event_session_id = obj_id;
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
);
goto(new_url.toString(), { replaceState: false });
}
} else if (cmd.startsWith('ae_download:')) {
let cmd_parts = cmd.split(':');
let obj_parts = cmd_parts[1].split('=');
let obj_type = obj_parts[0];
let obj_id = obj_parts[1];
let obj_filename = cmd_parts[2];
api.get_object({
api_cfg: $ae_api,
endpoint: `/v3/action/hosted_file/${obj_id}/download`,
params: {
filename: obj_filename,
key: $ae_api.account_id
},
return_blob: true,
auto_download: true,
log_lvl: 1
});
} else if (cmd.startsWith('ae_open:')) {
let cmd_parts = cmd.split(':');
let obj_parts = cmd_parts[1].split('=');
let obj_id = obj_parts[1];
if (obj_parts[0] == 'event_file') {
$events_sess.launcher.modal__open_event_file_id = null;
clearInterval(idle_timer_interval);
saver_looping = false;
restartCountdown();
$events_slct.event_file_id = obj_id;
$events_sess.launcher.modal__open_event_file_id = obj_id;
}
} else if (cmd.startsWith('ae_close:')) {
if (cmd.split(':')[1] == 'event_file_modal') {
$events_sess.launcher.modal__open_event_file_id = null;
}
clearInterval(idle_timer_interval);
saver_looping = false;
restartCountdown();
} else if (cmd.startsWith('ae_refresh:')) {
if (cmd.split(':')[1] == 'now') location.reload();
}
}
}
function handle_ws_sent(ws_sent_status: any) {
$events_sess.launcher.controller_cmd = null;
$events_sess.launcher.controller_trigger_send = null;
}
$effect(() => {
if (trigger_handle_ws_conn) {
handle_ws_conn(trigger_handle_ws_conn);
trigger_handle_ws_conn = false;
}
});
$effect(() => {
if (trigger_handle_ws_recv) {
handle_ws_recv(trigger_handle_ws_recv);
trigger_handle_ws_recv = false;
}
});
$effect(() => {
if (trigger_handle_ws_sent) {
handle_ws_sent(trigger_handle_ws_sent);
trigger_handle_ws_sent = false;
}
});
if (!$events_loc.launcher.idle_timer)
$events_loc.launcher.idle_timer = 5 * 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;
listen({
timer: $events_loc.launcher.idle_timer,
cycle: $events_loc.launcher.idle_cycle
});
let idle_timer_interval: any = $state();
let saver_looping: boolean = $state(false);
function handle_idle_client() {
if (
$lq__event_session_obj &&
$lq__event_session_obj?.type_code == 'poster'
) {
if (saver_looping) return false;
saver_looping = true;
idle_timer_interval = setInterval(
() => {
if ($events_loc.launcher.screen_saver_img_kv) {
const keys = Object.keys(
$events_loc.launcher.screen_saver_img_kv
);
const rand_index = Math.floor(
Math.random() * keys.length
);
let event_file_obj =
$events_loc.launcher.screen_saver_img_kv[
keys[rand_index]
];
$events_slct.event_file_id =
event_file_obj.event_file_id;
$events_slct.event_file_obj = event_file_obj;
$events_sess.launcher.modal__open_event_file_id = null;
$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;
return true;
}
return false;
},
$events_loc.launcher.idle_loop_period ?? 2 * 60 * 1000
);
} else {
saver_looping = false;
return false;
}
}
onIdle(() => {
clearInterval(idle_timer_interval);
handle_idle_client();
});
$effect(() => {
if (!$idle) {
clearInterval(idle_timer_interval);
saver_looping = false;
}
});
</script>
<svelte:head>
<title>
&AElig;:
{$lq__event_location_obj?.name ?? '-- not set --'}
({$lq__event_session_obj?.name ?? 'Æ loading...'}) - Launcher v3 -
{$events_loc?.title}
</title>
</svelte:head>
<div
class="
static
m-auto
border-x border-gray-200 dark:border-gray-600
mt-4 mb-16 sm:mb-12
h-full
w-full max-w-7xl
transition-all
"
>
<header
id="Main-Header"
class:hidden={$events_loc.launcher.hide__launcher_header}
class="
z-20
absolute top-0 left-0 right-0
w-full max-w-7xl
h-12
p-1 px-12 m-auto
flex flex-row items-center justify-around sm:justify-between
text-sm hover:text-base
bg-slate-200
opacity-90 hover:opacity-100
transition-all duration-1000
"
>
<h3 class="h4 text-center italic text-surface-600-400">
<button
type="button"
class=""
onclick={() => {
$events_loc.launcher.hide__launcher_menu =
!$events_loc.launcher.hide__launcher_menu;
}}
title="Toggle Launcher menu"
>
<Satellite class="text-base mx-1 inline-block text-gray-500" />
<abbr title="Aether - Events Module Launcher">
Æ Launcher
<span
class="text-xs align-super font-normal"
title="Version 3">v3</span
>
</abbr>
</button>
</h3>
{#if $lq__event_obj}
<h2
class="hidden md:inline-block h3 text-center text-surface-600-400"
>
{$lq__event_obj.cfg_json?.short_name}
</h2>
<h3
class="h4 text-center italic text-surface-600-400"
title="Location ID: {$lq__event_location_obj?.event_location_id} Name: {$lq__event_location_obj?.name}"
>
<button
type="button"
class="text-base"
onclick={() => {
$ae_loc.edit_mode = !$ae_loc.edit_mode;
}}
title="Toggle Edit Mode to show location options and more"
>
<span class="fas fa-map-marker-alt"></span>
<span class="sr-only">Location:</span>
</button>
{$lq__event_location_obj?.name}
</h3>
{:else}
<div class="flex flex-row gap-1 items-center justify-center">
<span class="fas fa-spinner fa-spin mx-1"></span>
<span>Loading event...</span>
</div>
{/if}
</header>
<div
class="
h-full min-w-full w-full max-w-full
flex flex-col sm:flex-row flex-wrap sm:flex-nowrap gap-0
items-center
justify-start sm:justify-center
py-1 px-0.5
bg-gray-100
"
>
<section
id="Main-Nav-Menu"
class="event_launcher_menu
h-full
basis-1/5
min-w-56 md:min-w-64 lg:min-w-72
max-w-xs
pt-0.5 pr-0.5
flex flex-col gap-1 items-center justify-start
border-r border-gray-200 dark:border-gray-700
hover:bg-surface-100-900
"
class:hidden={$events_loc.launcher.hide__launcher_menu}
>
<Launcher_menu
data_url={data.url}
{lq__event_obj}
{lq__event_event_file_obj_li}
{lq__location_event_file_obj_li}
slct__event_file_id={$events_slct.event_file_id}
{lq__event_location_obj_li}
{lq__event_location_obj}
slct__event_location_id={$events_slct.event_location_id}
bind:loading__session_li_status={
$events_sess.launcher.loading__session_li_status
}
{lq__event_session_obj_li}
bind:loading__session_id_status={
$events_sess.launcher.loading__session_id_status
}
{lq__event_session_obj}
bind:slct__event_session_id={$events_slct.event_session_id}
bind:trigger_reload__event_session_obj_id={
$events_sess.launcher.trigger_reload__event_session_obj_id
}
bind:trigger_reload__event_session_obj_li={
$events_sess.launcher.trigger_reload__event_session_obj_li
}
bind:trigger_reload__event_location_obj_li={
$events_sess.launcher.trigger_reload__event_location_obj_li
}
></Launcher_menu>
</section>
<section
id="Main-Content"
class="event_launcher_main
h-full
min-w-xs
max-w-full
py-1 px-0.5
basis-4/5
flex flex-col gap-1
items-center
justify-center
overflow-y-auto
"
>
{#if !$events_slct.event_location_id}
<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}
{#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>
{@render children?.()}
</div>
<footer
id="Main-Footer"
class:hidden={$events_loc.launcher.hide__launcher_footer}
class="
z-20
absolute bottom-0 left-0 right-0
w-full max-w-7xl
p-1 m-auto
flex flex-row items-center justify-between
sm:flex-row md:items-center md:justify-between
text-xs hover:sm:text-sm hover:md:text-base hover:lg:text-lg
bg-gray-200 border-t border-gray-200
dark:bg-gray-800 dark:border-gray-600
opacity-50 hover:opacity-100
transition-all duration-1000
"
>
<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}"
>
<button
type="button"
class=""
onclick={() => {
$ae_loc.edit_mode = !$ae_loc.edit_mode;
}}
title="Toggle Edit Mode to show location options and more"
>
<span class="sr-only">Location:</span>
<span class="fas fa-map-marker-alt"></span>
</button>
{$lq__event_location_obj?.name}
{#if $lq__event_device_obj?.name}
<span class="fas fa-laptop mx-1"></span>
{$lq__event_device_obj?.name}
{/if}
</div>
<span
class:preset-tonal-warning={!$idle}
class:preset-tonal-success={$idle}
class="group px-1 rounded-md transition-all duration-1000"
title="The user is currently {$idle ? 'idle' : 'active'}"
>
{#if $idle}
<span class="fas fa-bed mx-1"></span>
<span class="hidden group-hover:inline"> Idle </span>
{:else}
<span class="fas fa-mouse-pointer mx-1"></span>
<span class="hidden group-hover:inline"> Active </span>
{/if}
</span>
<span
class="group px-1 rounded-md transition-all duration-1000"
title="Online status = {online?.current}"
>
<span class="fas fa-wifi mx-1"></span>
{online?.current ? '' : 'Offline!'}
</span>
<span
class:hidden={!$events_loc.launcher.ws_connect}
class:preset-tonal-warning={$events_sess.launcher.ws_connect_status !=
'connected'}
class:preset-tonal-success={$events_sess.launcher.ws_connect_status ==
'connected'}
class="group px-1 rounded-md transition-all duration-1000"
title="WebSocket is {$events_sess.launcher.ws_connect_status ==
'connected'
? 'connected'
: 'disconnected'} API: {$ae_api?.base_url}"
>
{#if $events_sess.launcher.ws_connect_status == 'connected'}
<span class="fas fa-sitemap mx-1 text-green-700"></span>
<span class="hidden group-hover:inline"> WS Connected </span>
{:else}
<span class="fas fa-times mx-1"></span>
<span class="hidden group-hover:inline"> WS Disconnected </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>
{ae_util.iso_datetime_formatter($time, 'date_full_no_year')}
</span>
<span class="hidden sm:inline">
<span class="fas fa-clock"></span>
</span>
{#if $events_loc.launcher?.time_hours == 12}
{ae_util.iso_datetime_formatter($time, 'time_12_long')}
{:else}
{ae_util.iso_datetime_formatter($time, 'time_long')}
{/if}
</div>
</footer>
<div class="absolute top-0 left-0 z-20 text-center">
<button
type="button"
onclick={() => ($events_loc.launcher.hide_drawer__cfg = false)}
class="btn btn-sm p-2.5 preset-tonal-error hover:preset-filled-error-500 transition-all duration-1000"
class:opacity-25={!$ae_loc.trusted_access}
class:hover:opacity-75={!$ae_loc.trusted_access}
>
<span class="fas fa-biohazard"></span>
<span class="hidden">Launcher Config</span>
</button>
</div>
<Drawer
class="bg-orange-100 opacity-90 hover:opacity-97 transition-all duration-1000 border border-gray-300 dark:border-gray-600 w-full md:w-96 lg:w-[32rem]"
placement="left"
transitionType="fly"
transitionParams={{
x: -520,
duration: 200,
easing: sineIn
}}
bind:hidden={$events_loc.launcher.hide_drawer__cfg}
id="sidebar1"
>
<Launcher_cfg></Launcher_cfg>
<hr class="my-2 border-gray-300 dark:border-gray-600" />
<div
class="flex flex-row flex-wrap gap-0.5 items-center justify-center max-w-md"
>
<a
href="/events/{$events_slct.event_id}"
class="btn btn-sm preset-tonal-primary hover:preset-filled-primary-500"
>
<span class="fas fa-search m-1"></span>
Session Search
</a>
{#if $events_slct?.event_location_id}
<a
href="/events/{$events_slct.event_id}/location/{$events_slct.event_location_id}"
class="btn btn-sm preset-tonal-primary hover:preset-filled-primary-500"
>
<span class="fas fa-map-marker m-1"></span>
View Selected Location
</a>
{/if}
{#if $events_slct?.event_session_id}
<a
href="/events/{$events_slct.event_id}/session/{$events_slct.event_session_id}"
class="btn btn-sm preset-tonal-primary hover:preset-filled-primary-500"
>
<span class="fas fa-chalkboard-teacher m-1"></span>
View Selected Session
</a>
{/if}
</div>
</Drawer>
<Drawer
activateClickOutside={false}
class="bg-red-100 opacity-75 hover:opacity-95 transition-all duration-1000"
placement="bottom"
transitionType="fly"
transitionParams={{
y: 320,
duration: 200,
easing: sineIn
}}
bind:hidden={$events_loc.launcher.hide_drawer__debug}
id="sidebar2"
>
<div class="flex flex-row items-center justify-between">
<h2
class="text-center mb-4 text-base font-semibold text-gray-500 dark:text-gray-400"
>
Debug
</h2>
<button
type="button"
onclick={() => ($events_loc.launcher.hide_drawer__debug = true)}
class="mb-4 dark:text-white"
>
<span class="fas fa-times"></span>
<span class="hidden">Close Debug Drawer</span>
</button>
</div>
<div>
<pre class="text-xs">
{JSON.stringify($events_loc.launcher, null, 2)}
</pre>
<hr />
<pre class="text-xs">
{JSON.stringify($ae_api, null, 2)}
</pre>
</div>
</Drawer>
<Modal
open={$events_sess.launcher?.modal__open_event_file_id}
autoclose={false}
placement="top-center"
class="
bg-gray-500/90 dark:bg-gray-800/90 text-gray-800 dark:text-gray-200
rounded-lg border-gray-200 dark:border-gray-700
divide-y divide-gray-200 dark:divide-gray-700 shadow-md
relative
flex flex-col items-center justify-center
{$events_loc.launcher.controller == 'remote' ? 'min-h-full' : ''}
min-w-full
"
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"
>
{#snippet header()}
<h3
class:hidden={$events_loc.launcher.hide__modal_header_title}
class="text-lg font-semibold opacity-20 hover:opacity-100 transition-all"
>
{$events_sess.launcher?.modal__title ?? 'Digital Poster Display'}
</h3>
<button
type="button"
class="btn flex-row-reverse group transition-all justify-self-end"
onclick={() => {
$events_sess.launcher.modal__open_event_file_id = null;
}}
title="Close Modal"
>
<span class="fas fa-times my-1.5"></span>
<span class="hidden group-hover:inline"> Close</span>
</button>
{/snippet}
<button
type="button"
onclick={() => {
$events_sess.launcher.controller_cmd = `ae_close:event_file_modal`;
$events_sess.launcher.controller_trigger_send = true;
}}
class="
absolute top-0 right-12
m-1 p-1
btn btn-sm
preset-tonal-error preset-outlined-error hover:preset-filled-success-200-800
opacity-80 hover:opacity-100 active:opactiy-100
transition-all
"
class:hidden={$events_loc.launcher.controller != 'local_push' ||
$events_sess.launcher.ws_connect_status != 'connected'}
title="Close the remote device's display of the poster"
>
<span class="fas fa-times m-1"></span>
<span class="fas fa-tv"></span>
Close Remote Poster Display Only
</button>
{#if $events_sess.launcher.modal__open_event_file_id}
<img
src="{$ae_api.base_url}/v3/action/event_file/{$events_sess.launcher
.modal__open_event_file_id}/download?filename={$events_slct
.event_file_obj.filename}&key={$ae_api.account_id}"
alt="Poster"
class="min-h-28 min-w-md max-h-full max-w-full"
/>
{:else}
<div class="flex flex-row items-center justify-center p-4">
<span class="fas fa-info-circle mx-1"></span>
<span>No image selected</span>
</div>
{/if}
<button
type="button"
onclick={() => {
$events_sess.launcher.controller_cmd = `ae_close:event_file_modal`;
$events_sess.launcher.controller_trigger_send = true;
}}
class="
absolute bottom-0 left-12
m-1 p-1
btn btn-sm
preset-tonal-error preset-outlined-error hover:preset-filled-success-200-800
opacity-80 hover:opacity-100 active:opactiy-100
transition-all
"
class:hidden={$events_loc.launcher.controller != 'local_push' ||
$events_sess.launcher.ws_connect_status != 'connected'}
title="Close the remote device's display of the poster"
>
<span class="fas fa-times m-1"></span>
<span class="fas fa-tv"></span>
Close Remote Poster Display Only
</button>
<button
type="button"
onclick={() => {
$events_sess.launcher.modal__title = '';
$events_sess.launcher.modal__open_event_file_id = null;
$events_sess.launcher.modal__event_file_obj = null;
}}
class="
absolute bottom-0 right-12
m-1 p-1
btn btn-sm
preset-tonal-success preset-outlined-success hover:preset-filled-success-200-800
opacity-80 hover:opacity-100 active:opactiy-100
transition-all
"
class:hidden={!$ae_loc.trusted_access &&
($events_loc.launcher.controller != 'local_push' ||
$events_sess.launcher.ws_connect_status != 'connected')}
title="Close this controller's local modal display of this poster"
>
<span class="fas fa-times m-1"></span>
<span class="fas fa-list"></span>
Close Poster on This Device
</button>
</Modal>
{#if $events_loc.launcher.controller_group_code && $events_loc.launcher.ws_connect}
<Element_websocket_v2
{log_lvl}
bind:ws_connect={$events_loc.launcher.ws_connect}
bind:ws_connect_status={$events_sess.launcher.ws_connect_status}
ws_server={$ae_api.fqdn}
bind:group_id={$events_loc.launcher.controller_group_code}
bind:client_id={$events_loc.launcher.controller_client_id}
bind:cmd={$events_sess.launcher.controller_cmd}
type={'cmd'}
bind:trigger_send={$events_sess.launcher.controller_trigger_send}
bind:trigger_connect={$events_sess.launcher.trigger__ws_connect}
bind:trigger_disconnect={$events_sess.launcher.trigger__ws_disconnect}
bind:hide__ws_element={$events_loc.launcher.hide__ws_element}
bind:hide__ws_form={$events_loc.launcher.hide__ws_form}
bind:hide__ws_messages={$events_loc.launcher.hide__ws_messages}
bind:hide__ws_commands={$events_loc.launcher.hide__ws_commands}
bind:ws_conn_status={trigger_handle_ws_conn}
bind:ws_recv_status={trigger_handle_ws_recv}
bind:ws_sent_status={trigger_handle_ws_sent}
/>
{/if}