Commit Graph

67 Commits

Author SHA1 Message Date
Scott Idem
ce09dcd09b Removing old code. Updated dev/test doc. 2026-03-17 13:20:26 -04:00
Scott Idem
efc0f46079 style(launcher): Phase 3 — FA→Lucide icon migration across all launcher files
Replaces all FontAwesome <span class="fas/fab fa-*"> with Lucide Svelte
components across 20 launcher files. launcher_cfg_section.svelte icon prop
changed from FA string to AnyComponent (svelte:component for dynamic render).
Dynamic file-extension icon now uses ae_util.file_extension_icon_lucide().
Fixes class: directives on components (invalid in Svelte 5) → ternary class.
Removes title prop from Lucide components → wrapping <span title="...">.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 12:33:37 -04:00
Scott Idem
75e8a87713 feat(launcher): add launcher_menu/header/footer URL params to URL builder; strip after apply 2026-03-16 10:39:23 -04:00
Scott Idem
e4cb968659 fix(launcher): implement reliable click-outside-to-close for cfg drawer
Flowbite's built-in outsideclose was unreliable for this side-drawer setup.
Root cause: Flowbite's _onclick handler uses dlg.getBoundingClientRect() to
detect backdrop clicks. This works in theory for showModal() dialogs, but
something in the Svelte transition / stacking context prevented it firing.

Fix: bypass Flowbite's detection entirely.
- onclick prop on <Drawer> is spread through Flowbite's restProps chain
  to the native <dialog> element, overriding the broken _onclick handler.
  Handler: just closes the drawer unconditionally.
- A stopPropagation wrapper div around all visual panel content ensures
  that clicks INSIDE the panel never bubble up to the dialog element.
  Only genuine backdrop clicks (outside the visual panel area) reach
  the dialog and trigger the close handler.

ESC key is unaffected — it fires oncancel not onclick.
2026-03-13 15:53:01 -04:00
Scott Idem
456674cc3e fix(launcher): remove ghost Flowbite close btn; add working Close btn in footer
The Flowbite Dialog component (which Drawer wraps internally) renders a
<CloseButton type='submit'> by default when dismissable=true. Since the
Drawer does not use the form/dialog mechanism, that button appeared at the
bottom of the drawer but did nothing. Fix: dismissable={false} on the cfg
Drawer suppresses it.

launcher_cfg.svelte footer redesigned:
- Lower-left: Close button (always visible) — mirrors top-right X, useful
  when the user has scrolled down through long config sections
- Lower-right: Reload (always visible, shorter label)
- Full-width Debug Panel button (edit_mode only, below the row)

Click-outside behavior unchanged — Flowbite Dialog outsideclose defaults
to true, so tapping outside the drawer still closes it.
2026-03-13 15:07:46 -04:00
Scott Idem
ce0c8b03c9 feat(launcher): Oral/Poster Kiosk mode preset toggle + ae_mode WS command
Adds a two-button Session Mode Preset toggle in Display & App Modes cfg:
- 'Oral / Default' restores all menus/headers/iframe off
- 'Poster Kiosk'   sets iframe=true + hides menu, header, footer

When WS is connected (local_push or remote controller), tapping a preset
sends ae_mode:poster / ae_mode:oral to all connected devices so an operator
can reconfigure the whole room from one device.

ae_mode:{poster|oral} command handler added to handle_ws_recv() in
+layout.svelte — receives and applies the same preset on remote devices.
2026-03-13 13:58:37 -04:00
Scott Idem
a5a5022143 fix(launcher): remove wasted top space in iframe/menu-hidden mode; vh bottom buffer
events/+layout.svelte:
  the events nav is actually rendered. Adds pt-0 for the launcher case
  (nav never rendered there; launcher manages its own header offset).
- pb-48 (fixed 12rem) → pb-[25vh] — scrolls ~25% of viewport below
  last card on any screen size, scales properly on phone/tablet/desktop.

launcher/+layout.svelte outer wrapper:
- Static mt-4 replaced with conditional:
    mt-12 when launcher header is visible (matches h-12 header height,
           keeps content clear of the absolute overlay)
    mt-2  when launcher header is hidden (minimal breathing room only)
- Result: iframe mode + launcher_header=hide → near-zero top dead space
2026-03-13 13:24:03 -04:00
Scott Idem
e3e81226a0 feat(launcher): URL params to control iframe/menu/header/footer visibility
Allows sharing a clean link that auto-configures display state on any
device — no manual setup required, ideal for tablet PWA kiosk deployment.

All four params are optional and independent. Values persist in
localStorage so they survive reloads; the URL param always wins when
present. Read inside the existing reactive URL-sync $effect, which
fires on every SPA navigation (unlike the root onMount which only
fires once on initial load).

Supported params:
  ?iframe=true/false          — hide/show global sys & debug menus
  ?launcher_menu=hide/show    — hide/show left session/location panel
  ?launcher_header=hide/show  — hide/show 'Æ Launcher v3' header bar
  ?launcher_footer=hide/show  — hide/show the status footer

Example clean poster-kiosk link:
  /events/{id}/launcher/{loc_id}?session_id={sess_id}
    &iframe=true&launcher_menu=hide&launcher_header=hide
2026-03-13 13:16:26 -04:00
Scott Idem
b18cda98b7 feat(launcher): poster modal zoom sync, clean close buttons
- Add modal_zoom_fit state (default: fit); resets on every new poster open
- Zoom/Fit toggle button + image double-tap on controller tablet
- Both zoom triggers send ae_zoom:fit/zoom over WS to remote display (local_push)
- ae_zoom: handler added to handle_ws_recv() for remote device
- Replace 3 scattered close buttons with single bottom control bar:
    - [Zoom/Fit] always visible on controller
    - [Close Both] sends ae_close WS + clears local modal (local_push only)
    - [Back to List] clears local modal only; remote keeps showing current poster
- Bottom bar hidden on controller=remote (kiosk display-screen mode)
- native pinch-to-zoom via touch-action: pinch-zoom on img (no JS library needed)
- pb-14 on modal bodyClass prevents buttons from overlapping poster content
2026-03-12 19:57:33 -04:00
Scott Idem
0da5894529 fix: stable WS client ID + presentation name for poster modal title
- Generate and persist crypto.randomUUID() as controller_client_id on first
  launcher load (events_loc is persisted so it survives page reloads).
  Previously fell back to Date.now() on every reload.
- ae_open: handler now resolves presentation name via Dexie lookup chain:
  file.for_id -> presentation.name, falling back to file.filename.
  Remote modal now shows the presentation title instead of raw filename.
2026-03-11 19:01:21 -04:00
Scott Idem
3df09713d3 fix: poster WS remote control - push open and resolve file obj
- launcher_file_cont: poster 'Open Poster' click now sends ae_open:event_file
  command to remote display when controller=local_push and WS is connected
- +layout.svelte handle_ws_recv: ae_open: handler now looks up the file obj
  from Dexie after setting modal__open_event_file_id, so the remote modal
  has the hosted_file_id needed to render the poster image (was showing
  'No image selected' on remote device)
2026-03-11 18:54:40 -04:00
Scott Idem
5db66bc888 feat: upgrade launcher WebSocket to V3 protocol
- New element_websocket_v3.svelte:
  - URL path /v3/ws/group/{id}/client/{id}
  - Auth via ?api_key=...&jwt=... query params (browsers can't set WS headers)
  - Strict WS_Message_V3 schema: msg_type + target fields
  - 45s heartbeat to maintain Redis presence TTL
  - Self-echo detection via from_id (server-stamped)
  - Target 'group' (was 'all'), 'direct' (was 'dm')
- launcher/+layout.svelte:
  - Swap Element_websocket_v2 -> Element_websocket_v3
  - Add api_key and jwt props for V3 auth
  - Fix handle_ws_recv: type -> msg_type (V3 schema)
  - Remove unused 'type' prop passed to element
2026-03-11 17:50:08 -04:00
Scott Idem
56fd1d1760 fix: Launcher dead-code cleanup — dead else-if branch and unused handle_get_device_info
- launcher/+layout.svelte: dead {:else if $events_slct.event_session_id} branch
  (condition identical to preceding {#if}) replaced with correct
  {:else if $events_slct.event_location_id} — shows "Select a session"
  prompt when a room is chosen but no session is yet selected.

- launcher/[event_location_id]/+page.svelte: removed unreachable
  handle_get_device_info() function (never called; pre-relay pattern
  superseded by launcher_background_sync.svelte's run_device_heartbeat()).
  Cleaned up now-unused imports.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-11 12:30:41 -04:00
Scott Idem
04a8edc6d1 [Perf] Fix liveQuery reactivity, silence debug logs, add performance guidelines
- launcher/+layout.svelte: convert lq__event_session_obj from $derived to
  $derived.by() so Svelte tracks event_session_id as a dependency; the old
  pattern read the store inside the Dexie async callback where Svelte's
  tracking is off, so the liveQuery never updated on session change
- ae_events__event_file.ts: fix hardcoded log_lvl: 2 in SWR fire-and-forget
  background refresh (always-on debug logging on every cache hit) → 0
- e_app_sign_in_out.svelte: lower 6 call-site log levels (1×log_lvl:2,
  5×log_lvl:1) to 0; sign-in runs on every page load
- element_manage_hosted_file_li.svelte: log_lvl:2 → 0 in refresh call;
  remove log_lvl=1 assignment + debug block inside click handler; log_lvl:1
  → 0 in delete call
- AE__Performance_Guidelines.md: add 5 Svelte 5 runes rules covering
  $derived.by() for reactive liveQuery, liveQuery purity, cheap equality
  guards ($id+updated_on, ID-join, shallow_equal), untrack() requirement,
  and log_lvl discipline

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 15:01:42 -04:00
Scott Idem
ffc430a727 Perf: replace JSON.stringify comparisons with efficient identity checks
JSON.stringify on large store objects (ae_loc, ae_api, slct, event lists)
was running on every navigation, comparing serialized strings of potentially
deep objects. Replace with targeted comparators:

- Root +layout.svelte: add shallow_equal() helper — O(n keys) key-by-key
  identity check instead of O(serialized bytes). Used for ae_api, ae_loc,
  and slct sync guards.

- Launcher +layout.svelte: ID-list join-compare for event_location_obj_li
  and id_li__event_location (O(n) string vs O(n*m) stringify). Refactor
  liveQuery closures to be pure (data-only, no store reads/writes inside
  the async Dexie context where Svelte reactivity tracking is undefined).
  Move store sync into separate $effects that compare updated_on + id
  (O(1)) or ID-join (O(n)) rather than full object serialization.
2026-03-10 14:20:57 -04:00
Scott Idem
3447c4d4a4 launcher: fix liveQuery reactivity for location-dependent queries
The three liveQueries that depend on $events_slct.event_location_id were
plain liveQuery() calls, not $derived.by(() => liveQuery(...)). This meant
Svelte store changes did NOT cause them to re-run.

Root cause of the 'hung' bug:
- On initial load at /launcher (no location in URL), id = null
- Dexie watches the event_location_id = null index range
- User selects a location (or navigates to /launcher/{id}): store updates
- Sessions for the real location are in a DIFFERENT Dexie range
- Dexie never fires because the null range was never touched
- If sessions are already in IndexedDB cache (no new DB write), the list
  stays permanently frozen at []

Fix: convert lq__event_session_obj_li, lq__location_event_file_obj_li, and
lq__event_location_obj to $derived.by(() => liveQuery(...)). When
event_location_id changes, $derived.by creates a new Observable targeting
the correct location, which immediately queries Dexie for existing cached
data and then watches that range for further changes.

Also: remove the .reverse() before .sortBy('name') on the session query —
.sortBy() always re-sorts so .reverse() before it was a no-op.
2026-03-06 21:51:31 -05:00
Scott Idem
589ab9b652 launcher: add font size cycler to footer bar
Onsite operators may have the sys menu locked/unavailable. This button
in the always-visible launcher footer gives them direct A / A+ / A−
control that cycles $ae_loc.font_size_mode, which the root layout DOM
effect picks up and applies as html.font-size-* class.
2026-03-06 21:40:39 -05:00
Scott Idem
c0729ab4f3 a11y(launcher): dark mode, touch targets, overflow, transition speed
Shell (+layout.svelte):
- fix: header bg-slate-200 -> dark:bg-slate-800 (projector/night use)
- fix: main content bg-gray-100 -> dark:bg-gray-900
- fix: config drawer bg-orange-100 -> dark:bg-slate-800
- fix: debug drawer bg-red-100 -> dark:bg-slate-900
- fix: footer border-gray-200 -> border-gray-300 (invisible border fixed)
- fix: remove header hover:text-base (caused layout shift on hover)
- fix: remove footer hover:sm:text-sm etc. (layout shift + broken TW4 syntax)
- fix: header/footer/status spans duration-1000 -> duration-300 (too slow)
- fix: footer opacity-50 -> opacity-70 (was too dim for projector/status reading)
- fix: nav section add overflow-y-auto (sessions overflowed on short screens)
- fix: nav section remove hover:bg-surface-100-900 (confusing whole-panel hover)
- a11y: header menu toggle button class=''->'px-2 py-1 rounded...' (touch target)
- a11y: footer edit_mode button class=''->'px-1.5 py-1 rounded...' (touch target)
- a11y: footer status spans px-1 -> px-2 py-0.5 (slightly larger tap area)
- a11y: footer datetime add dark:hover:bg-slate-700
2026-03-06 20:32:57 -05:00
Scott Idem
b2fa6228a6 fix(launcher): poster session display — metadata, image modal, file paths
1. launcher_presentation_view: accept session_type prop from parent
   instead of relying on event_session_type_code on file objects (which
   is not reliably populated in Dexie). Use session_type to correctly
   set hide_meta, session_type, and open_method on the file container.

2. launcher_session_view: pass session_type={type_code} to
   Launcher_presentation_view; restore Launcher_presenter_view_posters
   in the presenter list for poster mode (hide_name=true). Some events
   store poster files at the PRESENTER level (for_id=event_presenter_id)
   — particularly group/company presenters — so both paths must render.

3. launcher/+layout.svelte: fix poster modal image 403. The img src was
   using the event_file download endpoint which requires auth headers a
   plain img tag cannot send. Switched to the hosted_file endpoint with
   key=account_id, which is browser-compatible. Also guarded on
   modal__event_file_obj.hosted_file_id for safer access.

4. launcher_cfg_screen_saver: rename section title to 'Poster Screen Saver'.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-04 19:15:32 -05:00
Scott Idem
7549749d14 Launcher: Resolved session selection hang and improved reactivity pattern. 2026-02-11 17:18:55 -05:00
Scott Idem
c5bfc140af fix(launcher): resolve 'download' filename bug and refactor data_url to global page state
- Updated 'handle_open_file' in launcher_file_cont.svelte to correctly pass filename to API.
- Fixed WebSocket ae_download command in launcher layout to include filename.
- Implemented a safety net in api_get_object.ts to extract filename from params if missing.
- Added 'download' attribute to Hosted Files download button for direct links.
- Refactored launcher menu components to use Svelte 5 global 'page' state instead of obsolete 'data_url' prop.
2026-02-10 19:12:55 -05:00
Scott Idem
72abd8034e fix(launcher): resolve session selection hang and reactive header sync
- Optimized session navigation by switching from static data_url to reactive $page.url.\n- Fixed selection hang when entering the Launcher without an initial session ID.\n- Synchronized global header and idle logic with derived layout observables.\n- Streamlined prop passing to ensure clean state transitions during session switching.
2026-02-10 18:49:31 -05:00
Scott Idem
1ab13eaf96 fix(launcher): optimize layout reactivity and implement staggered data pipeline
- Moved session observable to child component to ensure reactive header updates.\n- Implemented deferred loading for presenters and files to prevent request storms.\n- Fixed WebSocket navigation paths to use store-backed IDs.\n- Streamlined Svelte 5 component lifecycle for better performance and SWR responsiveness.
2026-02-10 17:57:28 -05:00
Scott Idem
718de1457d Fix infinite hydration loop and stabilize global store synchronization
- Refactored layouts to derive account data from stable props instead of reactive stores.
- Wrapped store updates in untrack() with deep equality guards to prevent infinite re-renders.
- Resolved duplicate untrack declarations and missing imports across the project.
- Added fetch safeguards to Element_data_store to prevent redundant API calls.
- Standardized hydration patterns to break circular dependencies during initial load.
2026-02-08 17:15:20 -05:00
Scott Idem
88bc18cf15 fix(core): resolve 68 compiler errors and stabilize Svelte 5 reactivity
- Fixed 'Captured initial value' warnings in 65+ components by implementing
  proper sync effects with 'untrack' and derived states.
- Hardened Event Settings JSON editors using a temporary string-buffer pattern
  to safely decouple object-based data from CodeMirror's string requirements.
- Resolved strict TypeScript mismatches across core routes (Accounts, Sites, etc.)
  and improved property indexing safety in views.
- Patched Flowbite-Svelte Drawer transitions for Svelte 5 compatibility using
  prop spreading.
- Added comprehensive safety comments to high-risk reactivity blocks.
- Synchronized 'ae_types.ts' with V3 backend models.
2026-02-08 16:05:35 -05:00
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
Scott Idem
49f0a888b0 refactor(ui): standardize button types and migrate file operations to V3 Action API 2026-02-03 22:54:22 -05:00
Scott Idem
0809ad3eac feat(v3-auth): modernize hosted file access with simplified bypass pattern
- Roll out platform-wide standard for unauthenticated binary access using '?key=[account_id]' query parameter.
- Update API helpers (get, post, patch) to recognize 'key' bypass and strip account context headers accordingly.
- Refactor IDAA Bulletin Board to restore inline image rendering and edit-mode previews.
- Modernize Events Launcher (Layout, Sync, Session View) to use V3 Action URLs with verified auth.
- Update HTML generators in 'ae_utils.ts' to support the new authenticated URL structure.
- Harden 'ae_comp__event_file_obj_tbl' CSV export and clipboard links with V3 standard patterns.
2026-02-03 18:37:55 -05:00
Scott Idem
cb46eec440 perf(launcher): minimize session switch latency with non-blocking SWR and stable observables 2026-01-30 16:26:38 -05:00
Scott Idem
1dc0f0d77c perf(launcher): instrument SWR tracing and optimize session loading flow 2026-01-30 16:21:46 -05:00
Scott Idem
66affb2a0f perf(events): implement non-blocking SWR pattern and optimize library loaders
- Refactored 'event_session', 'event_presentation', 'event_file', 'event_location', and 'event_presenter' libraries to follow a Stale-While-Revalidate pattern.
- Implemented non-blocking background refreshes to allow instant UI rendering from IndexedDB cache.
- Parallelized nested collection loads (files, presentations) during background tasks to eliminate UI stalls.
- Standardized ID lookups using specific indices (event_location_id, event_id) for reliable local data retrieval.
- Resolved regression where aggressive ID overwriting caused relationship inconsistencies in background loads.
- Fixed reactive access to live queries in 'session_view.svelte' using proper Svelte 5 prefixing.
2026-01-30 16:04:28 -05:00
Scott Idem
3148375eb3 feat(launcher): implement auto-collapse coordinator and overhauled configuration UI
- Introduced 'Launcher_Cfg_Section' with 3-way state support (collapsed, auto, pinned).
- Implemented 'handle_section_expand' coordinator in 'launcher_cfg.svelte' for single-active-section behavior.
- Overhauled all configuration sub-components to participate in the auto-collapse logic.
- Updated 'ae_events_stores.ts' with new persistent section states.
- Synchronized 'launcher_cfg_template.svelte' with the new pattern for future extensions.
2026-01-30 14:11:52 -05:00
Scott Idem
1d5401bbe5 First round of work on the Launcher Config. 2026-01-30 13:22:01 -05:00
Scott Idem
5a2eaa8fac feat(frontend): implement string-only ID standardization and native data cleaning
Update layout.ts to clean raw data from the native bridge. Initialize events_slct.event_device_id in launcher layout. Resort device_id prioritization in launcher_background_sync.svelte.
2026-01-30 12:38:13 -05:00
Scott Idem
79917edffc feat(launcher): implement device heartbeat and background sync engine
- Hardened 'find_object_id' in Dexie to support 'event_' prefixed IDs.
- Implemented singleton 'LauncherBackgroundSync' in root launcher layout.
- Added V3-compliant heartbeat and room refresh cycles.
- Fixed redundant component imports and Skeleton UI prop errors.
- Added 'inc_file_li' support to event API loader.
2026-01-26 11:23:12 -05:00
Scott Idem
2db2aba6f9 feat(launcher): improve Events Presentation Launcher stability and data flow
- Standardized ID usage: Migrated multiple components from '_random' variants to standard 'id' properties to align with V3 backend and Dexie patterns.
- Electron Integration: Added global 'native_app' declaration and Window interface augmentation in app.d.ts to resolve TypeScript errors.
- Type Safety: Enhanced ae_EventSession interface with missing 'event_file_li' and added runtime null checks in session loading logic.
- UI/UX: Restored missing launcher components in location-specific pages and fixed LiveQuery filter logic for session lists.
- Bug Fixes: Resolved indexing errors in location list and corrected store update patterns in layout.
2026-01-16 13:59:51 -05:00
Scott Idem
10cc435146 There have been a lot of changes. For some reason the commit is not working? Trying again. 2025-11-19 18:56:58 -05:00
Scott Idem
0987cd6ad9 style: Apply Prettier formatting with 4-space indentation
Applied consistent code formatting across the project using Prettier, now configured to use 4-space indentation instead of tabs.
2025-11-18 18:40:50 -05:00
Scott Idem
7e1eaba3bc feat: Migrate ESLint to flat config and resolve initial linting errors
Migrated the ESLint configuration to the new flat config format ()
and addressed several initial linting errors.

Key changes include:
- Updated ESLint configuration to treat  as warnings instead of errors.
- Fixed  errors in  by declaring  and .
- Corrected  error in  by using  instead of an out-of-scope .
- Resolved  error in  by replacing the undefined  directive with the  component.
- Addressed  errors in  by replacing  with  and  with .
- Fixed  errors in  by importing necessary modules (, , ) and adding missing props (, , , , ).
2025-11-17 18:46:54 -05:00
Scott Idem
e9a8f7df00 This was a lot... things are mostly working again. The changing of id_random properties caused some problems. The hosted_file_hash_sha256 is not working? There are other issues as well... This will take some time. 2025-11-13 18:38:00 -05:00
Scott Idem
de7e02b9ef Refactor: Update import paths for api.ts after moving it to src/lib/api/api.ts. 2025-11-13 16:16:18 -05:00
Scott Idem
e912c4a48a Better text sizing and flex. 2025-10-16 16:39:30 -04:00
Scott Idem
8d15a5ba0b More work on the WebSockets. Improved status and WS triggers. Better online/offline status. 2025-10-16 14:48:10 -04:00
Scott Idem
3d6b7c412c Work on tablet layout for posters 2025-10-16 11:45:33 -04:00
Scott Idem
77b250b4f3 Better handling of idle with WS messages. 2025-10-16 10:58:11 -04:00
Scott Idem
9678c5620d Lots of work on the Launcher and configuration. Looks pretty good and useful. 2025-10-15 19:01:30 -04:00
Scott Idem
b2154273e0 Reset looks better now. 2025-10-15 13:46:08 -04:00
Scott Idem
1f79ae4e19 More work on versioning for Events 2025-10-15 13:17:32 -04:00
Scott Idem
6b8f4d54ed The posters look pretty good now. A lot more is configurable. 2025-10-15 12:52:27 -04:00
Scott Idem
f459c09fbc Getting the posters ready for LCI. 2025-10-15 10:37:46 -04:00