246 Commits

Author SHA1 Message Date
Scott Idem
a4ae1db497 WIP: Prepared for SkeletonLabs v3 to v4 migration with temporary v3 dependencies. Proceed to rollback to 90ee6bb1 on main branch for re-verification. 2025-12-08 15:37:00 -05:00
Scott Idem
90ee6bb156 All packages have now been updated. This includes the skeletonlabs packages. Everything seems to be working. (Except for some unrelated known bugs. Why did the badge search stop working (AGAIN)?) 2025-12-05 17:00:54 -05:00
Scott Idem
83cd8d851d The tailwind-variants is now updated to 3.x and seems to be working....The last things are the skeletonlabs. They keep breaking things.... 2025-12-05 16:33:44 -05:00
Scott Idem
50936f56d7 Vite updated to 7.x...!? Seems to be working still. 2025-12-05 16:30:26 -05:00
Scott Idem
fd73ad2e0f More package updates 2025-12-05 16:28:40 -05:00
Scott Idem
d447de4073 Another another snapshot... 2025-12-05 16:19:50 -05:00
Scott Idem
9d95b5eac9 Another snapshot. 2025-12-05 16:18:18 -05:00
Scott Idem
3a544a2086 Taking a snapshot while I update packages in batches.... At least things are working again. 2025-12-05 16:04:05 -05:00
Scott Idem
1fc58eb18f Seems to be working still... Trying to update packages. 2025-12-05 14:50:06 -05:00
Scott Idem
b3bad26d8f Things seems to be working. It pulls the example moderator group list from Novi using their API. The moderator check is working. It still needs to handle more than one Novi Group. 2025-12-05 12:56:08 -05:00
Scott Idem
3f0ff46f51 First version of moving the Jitsi code to a new IDAA module under video_conferences. 2025-12-05 12:15:24 -05:00
Scott Idem
2403b41529 More work on Jitsi for IDAA 2025-12-04 19:57:35 -05:00
Scott Idem
484ea8c36c The Jitsi meetings and most settings are working well enough for IDAA members to use for now. 2025-12-04 15:37:04 -05:00
Scott Idem
c1a440df6c Quick save of changes for IDAA 2025-12-04 11:24:39 -05:00
Scott Idem
0fcd4e4cdf Work on Jitsi settings 2025-12-02 19:07:55 -05:00
Scott Idem
b91d79c175 fix: Resolve props_invalid_value error and add each block keys\n\n- Initialized .files.upload_complete in src/routes/hosted_files/video_util/+page.svelte to prevent props_invalid_value error.\n- Removed commented-out, unused each blocks from several components.\n- Added each keys to improve reactivity and resolve svelte/require-each-key errors in several components. 2025-11-20 20:21:06 -05:00
Scott Idem
a68d5439bd feat: Remove legacy files and fix first svelte/no-at-html-tags error\n\n- Moved legacy files from src/routes/legacy to backups/legacy/src/routes/legacy.\n- Removed the empty src/routes/legacy directory.\n- Fixed a svelte/no-at-html-tags error in src/routes/idaa/(idaa)/archives/[archive_id]/+page.svelte by replacing '{@html ?.name ?? 'Archive'}' with '{?.name ?? 'Archive'}'.\n- Addressed a misidentified '{@html}' tag in src/lib/ae_core/ae_comp__hosted_files_clip_video.svelte by removing commented-out code that might have caused false positives. 2025-11-20 19:46:17 -05:00
Scott Idem
266363b85f feat(event_badge): Improve event_id handling in badge data processing
Refactor how  is ensured in badge objects when fetched from the API and cached locally.

Previously,  directly injected  into results, creating an inconsistency with other data fetching functions. This change centralizes the  injection logic within .

- Updated  to accept an optional  parameter.
- Added logic within the processor to set  and  on badge objects if they are missing, using the provided  context.
- Modified call sites (, , ) to pass the  to the  function.

This ensures consistent and robust handling of the  across badge-related data operations, aligning with the project's data processing patterns.
2025-11-20 17:44:21 -05:00
Scott Idem
359d5d47f9 Working on event_id and event_id_random are both showing as undefined. badge_id and badge_id_random work in this file though. 2025-11-20 17:11:02 -05:00
Scott Idem
a1a33f794d More fixes related to id_random vs id. 2025-11-20 16:56:13 -05:00
Scott Idem
f164caf65f Another id_random bug fix. 2025-11-20 16:40:44 -05:00
Scott Idem
0da470e7dc More bug fixes related to incorrect paths. I am sure there are mote around. 2025-11-20 16:31:01 -05:00
Scott Idem
ce5a3535cc Restoring old files just in case. Style fix. 2025-11-20 16:13:20 -05:00
Scott Idem
ee9d9a0aca Trying to commit these changes so they are not lost. This is right after Gemini tried to move the Pres Mgmt files into a new sub directory. Everything seems to be working but I am sure something was missed. 2025-11-20 16:13:20 -05:00
Scott Idem
8223b964e1 Quickly saving lots of changes before they might be lost. 2025-11-20 16:13:20 -05:00
Scott Idem
064942c647 docs: Reorganize documentation files
- Centralize project-wide documentation into a new /documentation directory.
- Remove old, deprecated README guideline files.
- Create a comprehensive AETHER_API_OBJECTS.md file detailing all API data models.
2025-11-20 14:26:30 -05:00
Scott Idem
65b793f663 Fixed bug where trusted_access value changes were not working. 2025-11-20 12:43:30 -05:00
Scott Idem
d24e6c0400 docs: Update README.md with AE Events - Exhibit Leads module 2025-11-19 23:02:44 -05:00
Scott Idem
4b1db3afff docs: Add and update READMEs for new v3 event modules
- Added new README.md for the v3 Event Leads module at `src/routes/events/[event_id]/(leads)/README.md`, adapting content from its legacy counterpart.
- Created placeholder README.md files for the main v3 Events module (`src/routes/events/[event_id]/README.md`), the v3 Launcher module (`src/routes/events/[event_id]/(launcher)/README.md`), and the v3 Badges module (`src/routes/events/[event_id]/(badges)/README.md`).
2025-11-19 22:47:28 -05:00
Scott Idem
d1021e2822 feat: Refactor event modules for Svelte 5 and new routing structure
- Moved legacy event modules (`events_badges`, `events_leads`) to `src/routes/legacy/` and renamed them to `events_badges_v2` and `events_leads_v2` respectively.
- Created new directory structures for Svelte 5 and SvelteKit-based event modules under `src/routes/events/[event_id]/`:
    - `(launcher)`
    - `(badges)`
    - `(leads)`
- Updated `src/routes/events_leads/README.md` (now `src/routes/legacy/events_leads_v2/README.md`) with comprehensive documentation for the legacy lead retrieval module, reflecting its features, data model, routing, components, and technical implementation details, incorporating project conventions.
2025-11-19 22:45:50 -05:00
Scott Idem
bd4bd360f7 docs: Update project documentation and session notes
- Updates `GEMINI.md` with a detailed summary of the days debugging session for the v3 Badges page.
- Updates `TODO.md` to mark recent bug fixes as complete and adds new tasks for outstanding issues (e.g., `order_by_li` fix).
- Updates `ARCHITECTURE.md` to reflect the current state of the tech stack (Tailwind v4, component library status).
- Creates `README.md` files for the new v3 Badges module and the legacy Lead Retrieval module to clarify their purpose and status.
2025-11-19 19:05:06 -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
b3c0446440 fix(badges): Resolve badge search API error and UI bugs
This commit addresses several critical issues preventing the new v3 badge search page from functioning correctly.

- **Fixes API Fetch Error:** Resolves a `TypeError: NetworkError` that occurred during badge searches. The error was caused by an incorrect `order_by_li` parameter being sent to the API. The parameter is now temporarily commented out in `ae_events__event_badge.ts` to allow searches to succeed.

- **Fixes Svelte 5 Binding Error:** Implements a defensive initialization for badge search filter properties directly in the `(badges)/badges/+page.svelte` script. This prevents a `props_invalid_value` runtime error by ensuring that bound store values are not `undefined` when the child search component is rendered.

- **Fixes Invalid Attribute Name Error:** Corrects the `onsubmit|preventDefault` syntax in the new badge creation and upload forms. The `preventDefault` logic is now handled inside the respective submit handler functions.

- **Restores Site-wide Styles:** Re-adds the global Skeleton UI CSS imports to `app.css` to fix numerous "unknown utility class" errors (e.g., `preset-tonal-*`) and restores button styles in the legacy leads list.

- **Refactors Badge Search Component:** Updates the `ae_comp__badge_search.svelte` component to use its own reactive props for state management instead of relying on global stores, and removes obsolete/conflicting logic.
2025-11-19 18:54:46 -05:00
Scott Idem
79da9acd2f fix(badges): Resolve build errors and restore site styles
This commit addresses several critical issues that were preventing the application from building and rendering correctly.

- **Restores Skeleton UI CSS:** Re-adds the global Skeleton UI CSS imports to `app.css`. This fixes numerous "unknown utility class" errors (e.g., `preset-tonal-secondary`) across the site, allowing components to render with their intended styles again.

- **Fixes Invalid Attribute Name Error:** Corrects the `onsubmit|preventDefault` syntax in the new badge creation and upload forms (`ae_comp__badge_create_form.svelte`, `ae_comp__badge_upload_form.svelte`). The `preventDefault` logic is now handled inside the respective submit handler functions, resolving the Svelte v5 parsing error.

- **Fixes Svelte 5 Binding Error:** Implements a defensive initialization for badge search filter properties directly in the `(badges)/badges/+page.svelte` script. This prevents a `props_invalid_value` runtime error by ensuring that bound store values are not `undefined` when the child search component is rendered.

- **Fixes Invalid CSS Classes:** Replaces incorrect `preset-tonal-*` classes in the legacy `leads_list.svelte` component with standard Tailwind CSS utility classes to prevent further styling-related errors.
2025-11-19 18:21:40 -05:00
Scott Idem
8029034e37 style: Apply Prettier formatting to codebase 2025-11-19 13:38:45 -05:00
Scott Idem
8f49edc1b3 Various fixes. One being yet another id_random issue. 2025-11-19 13:34:15 -05:00
Scott Idem
b16413c3c0 fix(svelte): resolve props_invalid_value and dexie DataError
- Initialize ds_loaded properties in ae_stores.ts to fix svelte binding error.
- Make db_save_ae_obj_li__ae_obj in core__idb_dexie.ts schema-aware to fix Dexie DataError when saving to tables with non-'id' primary keys.
2025-11-19 13:29:47 -05:00
Scott Idem
f25b9ccd8f feat: migration to Svelte 5 2025-11-19 12:38:03 -05:00
Scott Idem
d99e9ee1b0 refactor(events): Centralize editable fields for event objects
- Implemented a whitelist for editable fields for the 'event' object type to prevent sending read-only fields in POST/PATCH requests.
- Created a new file  to define the editable fields.
- Modified  and  to use this whitelist.
- Removed the temporary cleaning logic from the event settings page.
- Corrected Svelte 5  to  in event settings components.
- Updated Dexie interfaces for badge, badge_template, and device to use string IDs.
2025-11-19 12:12:29 -05:00
Scott Idem
2e70ce312b docs: Update GEMINI.md with summary of event settings page
Added a summary of the new event settings page to GEMINI.md, documenting the form-based UI, collapsible sections, view toggles, and Svelte 5 reactivity improvements.
2025-11-18 20:13:32 -05:00
Scott Idem
9691ceca43 feat: Add form-based UIs and view toggles for event settings
This commit introduces form-based UI components for 'mod_badges_json' and 'mod_abstracts_json', and expands the form for 'mod_pres_mgmt_json'. It also adds view toggles to switch between form and raw JSON editing for each of these sections, providing greater flexibility for the user.
2025-11-18 20:10:01 -05:00
Scott Idem
c06f50c21e feat: Add basic event fields and collapsible sections to settings page
This commit introduces a new component for editing basic event fields and adds collapsible sections to the event settings page for better organization. The new fields include code, conference, name, summary, description, timezone, start/end datetimes, and notes.
2025-11-18 19:42:15 -05:00
Scott Idem
1d0620085f docs: Update GEMINI.md with Svelte 5 and ID guidelines
Added a new 'Development Guidelines' section to GEMINI.md to provide clear instructions on Svelte v5 conventions and the project's 'id' vs 'id_random' usage. This will serve as a reminder to avoid common pitfalls and ensure code consistency.
2025-11-18 19:32:14 -05:00
Scott Idem
74140f41db fix: Update event settings forms for Svelte 5 reactivity
Corrected event settings components to use Svelte 5 bindable props for two-way data binding. This ensures that changes in child form components (ae_comp__event_settings_form.svelte, ae_comp__event_settings_pres_mgmt_form.svelte) are reactively reflected in the parent page (settings/+page.svelte) and properly handled during save operations.
2025-11-18 19:23:33 -05:00
Scott Idem
f7d1f304fe feat: Add form-based UI for event settings
This commit introduces form-based UI components for editing the 'cfg_json' and 'mod_pres_mgmt_json' fields on the event settings page. This provides a more user-friendly experience than editing the raw JSON directly. It also fixes an issue where the JSON objects were being displayed as '[object Object]'.
2025-11-18 19:17:27 -05:00
Scott Idem
0be878c8c1 feat: Add basic event settings management page
This commit introduces a new page at /events/[event_id]/settings that allows users to view and edit the JSON configuration fields for an event. The page provides textareas for each config field and a 'Save' button to persist the changes.
2025-11-18 18:59:49 -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
6d1f9989d0 config: Configure Prettier to use 4 spaces for indentation
Updated .prettierrc to set 'useTabs' to false and 'tabWidth' to 4, ensuring that Prettier formats code with 4-space indentation instead of tabs, as per user preference.
2025-11-18 18:39:35 -05:00
Scott Idem
6aa97a9f6b This is now actually fixed. Gemini did not fix the links correctly. 2025-11-18 18:34:59 -05:00
Scott Idem
9ea6b17617 feat: Fix event list and add module links
This commit fixes the event list on the /events page by correcting the data fetching logic. It also adds links to the 'Pres Mgmt', 'Badges', 'Leads', and 'Launcher' modules for each event, and updates the main event link to use the random string ID.
2025-11-18 18:18:25 -05:00
Scott Idem
c8c19a35a6 refactor: Use random IDs as primary keys in IDB
This commit refactors the IndexedDB schema to use the string-based random IDs as primary keys instead of the numeric auto-incrementing IDs. This change affects the 'badge' table and all related components that interact with it. The badge detail page and list component have been updated to use the new primary key for more efficient and consistent data retrieval.
2025-11-18 17:49:16 -05:00
Scott Idem
97d41adb12 fix: Use random IDs for badge links and detail page
This commit updates the badge list to use the string-based random IDs for badge links. It also updates the badge detail page to correctly fetch the badge data using the random ID from the URL.
2025-11-18 17:37:48 -05:00
Scott Idem
69c34fa4bc fix: Resolve badge search reactivity and SSR issues
This commit fixes several issues with the new badge search functionality. It resolves a 500 Internal Error by moving the Dexie liveQuery into an onMount block to prevent server-side execution. It also fixes a Svelte 5 reactivity issue by using a more explicit subscription pattern for the liveQuery and by correctly accessing state variables in the template. The badge search results are now correctly displayed.
2025-11-18 17:30:57 -05:00
Scott Idem
d678f97324 style: Apply Prettier formatting
Applied consistent code formatting across the project using Prettier, addressing minor style inconsistencies introduced in recent changes.
2025-11-18 14:25:21 -05:00
Scott Idem
691b20fd54 refactor: Rename CodeMirror wrapper and fix editor buttons
Renamed Tiptap_editor to CodeMirror_wrapper and updated all usages. Renamed the wrapper file to element_codemirror_editor_wrapper.svelte. Fixed a TypeError in the CodeMirror editor buttons by using EditorSelection.range() to correctly create selection ranges.
2025-11-18 14:14:24 -05:00
Scott Idem
95412dd0ad feat: CodeMirror integration and bug fixes
This commit addresses several issues related to the migration from TipTap to CodeMirror:

- **CodeMirror Initialization Fixes:**
  - Resolved 'Unrecognized extension value' errors by refactoring  to explicitly import individual CodeMirror extensions instead of relying on . This ensures proper singleton usage and prevents module duplication issues.
  - Updated  and  to utilize these individual extensions.

- **Text Wrapping Enabled:**
  - Added  to the extensions in  and  to enable text wrapping in the CodeMirror editors.

- **Content Saving Fixes:**
  - Corrected content binding for CodeMirror editor instances in various IDAA components:
    -  (description, location_text, attend_text)
    -  (content, notes)
    -  (content)
    -  (description, notes)
    -  (description, notes)
  - Ensured that the  prop of  is correctly bound to the respective state variables in the parent components, and these state variables are initialized with existing content.

- **Save Button Enablement:**
  - Fixed an issue in  where the Save button was not enabling on content changes. The  logic now directly compares the  and  with the original object's content, ensuring reactivity.
2025-11-18 13:27:42 -05:00
Scott Idem
e521bea448 Taking some notes since I can't sleep. 2025-11-18 03:44:36 -05:00
Scott Idem
d627e59bf6 Updated packages and fixed CodeMirror import error. 2025-11-17 22:30:32 -05:00
Scott Idem
390bbcb6e8 DOCS: Update GEMINI.md with Tiptap to CodeMirror migration details 2025-11-17 21:26:51 -05:00
Scott Idem
4f262149cd FEAT: Replace Tiptap editor with CodeMirror
Replaced the Tiptap-based rich text editor with CodeMirror for basic markdown formatting.

- Removed  directory.
- Removed all  and  dependencies from .
- Renamed  to .
- Updated  to use  and removed Tiptap-specific logic.
- Updated all Svelte components that were importing the old Tiptap wrapper to import the new CodeMirror wrapper and removed unsupported props (, , , ).
- Ran
up to date, audited 492 packages in 1s

92 packages are looking for funding
  run `npm fund` for details

8 low severity vulnerabilities

To address issues that do not require attention, run:
  npm audit fix

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details. and
> osit-aether-app-svelte@3.9.6 format
> prettier --write .

.eslintrc.cjs 18ms (unchanged)
.prettierrc 4ms (unchanged)
.vscode/settings.json 2ms (unchanged)
ae_app_svelte_tailwind_skeleton.code-workspace 1ms (unchanged)
ARCHITECTURE.md 22ms (unchanged)
components.json 1ms (unchanged)
COMPONENTS.md 9ms (unchanged)
DATA_STRUCTURES.md 7ms (unchanged)
eslint.config.js 4ms (unchanged)
GEMINI.md 5ms (unchanged)
jsconfig.json 1ms (unchanged)
NAMING_CONVENTIONS.md 8ms (unchanged)
OLD_README_guidelines_ui_ux.md 6ms (unchanged)
OLD_README_guidelines_v1.md 8ms (unchanged)
OLD_README_guidelines_v2.md 26ms (unchanged)
package.json 1ms (unchanged)
playwright.config.ts 3ms (unchanged)
README.md 6ms (unchanged)
src/ae-c-idaa-light.css 14ms (unchanged)
src/ae-c-lci.css 9ms (unchanged)
src/ae-osit-default.css 9ms (unchanged)
src/aeclci_v1.css 7ms (unchanged)
src/app.css 16ms (unchanged)
src/app.d.ts 1ms (unchanged)
src/app.html 11ms (unchanged)
src/index.test.ts 1ms (unchanged)
src/lib/ae_api/api_delete_object.ts 10ms (unchanged)
src/lib/ae_api/api_get__crud_obj_id.ts 9ms (unchanged)
src/lib/ae_api/api_get__crud_obj_li_v1.ts 7ms (unchanged)
src/lib/ae_api/api_get__crud_obj_li_v2.ts 6ms (unchanged)
src/lib/ae_api/api_get_object_v1.ts 19ms (unchanged)
src/lib/ae_api/api_get_object.ts 9ms (unchanged)
src/lib/ae_api/api_patch_object.ts 5ms (unchanged)
src/lib/ae_api/api_post_object.ts 10ms (unchanged)
src/lib/ae_archives/ae_archives__archive_content.ts 12ms (unchanged)
src/lib/ae_archives/ae_archives__archive.ts 14ms (unchanged)
src/lib/ae_archives/ae_archives_functions.ts 1ms (unchanged)
src/lib/ae_archives/db_archives.ts 4ms (unchanged)
src/lib/ae_archives/README.md 2ms (unchanged)
src/lib/ae_core/ae_comp__hosted_files_clip_video_li.svelte 33ms (unchanged)
src/lib/ae_core/ae_comp__hosted_files_clip_video_v1.svelte 25ms (unchanged)
src/lib/ae_core/ae_comp__hosted_files_clip_video.svelte 21ms (unchanged)
src/lib/ae_core/ae_comp__hosted_files_download_button.svelte 10ms (unchanged)
src/lib/ae_core/ae_comp__hosted_files_upload.svelte 13ms (unchanged)
src/lib/ae_core/ae_core_functions.ts 10ms (unchanged)
src/lib/ae_core/core__account.ts 1ms (unchanged)
src/lib/ae_core/core__activity_log.ts 7ms (unchanged)
src/lib/ae_core/core__api_helpers.ts 2ms (unchanged)
src/lib/ae_core/core__check_hosted_file_obj_w_hash.ts 1ms (unchanged)
src/lib/ae_core/core__countries.ts 2ms (unchanged)
src/lib/ae_core/core__country_subdivisions.ts 2ms (unchanged)
src/lib/ae_core/core__crud_generic.ts 6ms (unchanged)
src/lib/ae_core/core__data_store.ts 2ms (unchanged)
src/lib/ae_core/core__hosted_files.ts 6ms (unchanged)
src/lib/ae_core/core__idb_dexie.ts 4ms (unchanged)
src/lib/ae_core/core__person.ts 16ms (unchanged)
src/lib/ae_core/core__qr_code.ts 6ms (unchanged)
src/lib/ae_core/core__site_domain.ts 2ms (unchanged)
src/lib/ae_core/core__site.ts 1ms (unchanged)
src/lib/ae_core/core__time_zones.ts 2ms (unchanged)
src/lib/ae_core/core__user.ts 6ms (unchanged)
src/lib/ae_core/db_core.ts 3ms (unchanged)
src/lib/ae_events_functions.ts 2ms (unchanged)
src/lib/ae_events/ae_events__event_badge_template.ts 9ms (unchanged)
src/lib/ae_events/ae_events__event_badge.ts 13ms (unchanged)
src/lib/ae_events/ae_events__event_device.ts 16ms (unchanged)
src/lib/ae_events/ae_events__event_file.ts 14ms (unchanged)
src/lib/ae_events/ae_events__event_location.ts 12ms (unchanged)
src/lib/ae_events/ae_events__event_presentation.ts 10ms (unchanged)
src/lib/ae_events/ae_events__event_presenter.ts 11ms (unchanged)
src/lib/ae_events/ae_events__event_session.ts 18ms (unchanged)
src/lib/ae_events/ae_events__event.ts 17ms (unchanged)
src/lib/ae_events/ae_events__exhibit.ts 10ms (unchanged)
src/lib/ae_events/db_events.ts 10ms (unchanged)
src/lib/ae_journals/ae_journals__journal_entry.ts 13ms (unchanged)
src/lib/ae_journals/ae_journals__journal.ts 15ms (unchanged)
src/lib/ae_journals/ae_journals_functions.ts 1ms (unchanged)
src/lib/ae_journals/ae_journals_stores.ts 3ms (unchanged)
src/lib/ae_journals/db_journals.ts 6ms (unchanged)
src/lib/ae_posts/ae_posts__post_comment.ts 8ms (unchanged)
src/lib/ae_posts/ae_posts__post.ts 12ms (unchanged)
src/lib/ae_posts/ae_posts_functions.ts 1ms (unchanged)
src/lib/ae_posts/db_posts.ts 2ms (unchanged)
src/lib/ae_posts/README.md 2ms (unchanged)
src/lib/ae_sponsorships/ae_sponsorships_functions.ts 7ms (unchanged)
src/lib/ae_sponsorships/db_sponsorships.ts 2ms (unchanged)
src/lib/ae_sponsorships/README.md 2ms (unchanged)
src/lib/ae_utils/ae_utils__crypto.ts 5ms (unchanged)
src/lib/ae_utils/ae_utils__datetime_format.ts 3ms (unchanged)
src/lib/ae_utils/ae_utils__extract_prefixed_form_data.ts 3ms (unchanged)
src/lib/ae_utils/ae_utils__file_extension_icon.ts 1ms (unchanged)
src/lib/ae_utils/ae_utils__files.ts 2ms (unchanged)
src/lib/ae_utils/ae_utils__get_obj_li_w_match_prop.ts 1ms (unchanged)
src/lib/ae_utils/ae_utils__is_datetime_recent.ts 1ms (unchanged)
src/lib/ae_utils/ae_utils__perm_checks.ts 3ms (unchanged)
src/lib/ae_utils/ae_utils__process_data_string.ts 2ms (unchanged)
src/lib/ae_utils/ae_utils__return_obj_type_path.ts 2ms (unchanged)
src/lib/ae_utils/ae_utils__set_obj_prop_display_name.ts 2ms (unchanged)
src/lib/ae_utils/ae_utils__to_title_case.ts 2ms (unchanged)
src/lib/ae_utils/ae_utils.ts 5ms (unchanged)
src/lib/api/api.ts 14ms (unchanged)
src/lib/app_components/analytics.svelte 3ms (unchanged)
src/lib/app_components/e_app_access_type.svelte 26ms (unchanged)
src/lib/app_components/e_app_cfg.svelte 12ms (unchanged)
src/lib/app_components/e_app_clipboard.svelte 6ms (unchanged)
src/lib/app_components/e_app_codemirror_v5.svelte 8ms (unchanged)
src/lib/app_components/e_app_debug_menu.svelte 7ms (unchanged)
src/lib/app_components/e_app_help_tech.svelte 26ms (unchanged)
src/lib/app_components/e_app_sign_in_out.svelte 32ms (unchanged)
src/lib/app_components/e_app_sys_menu.svelte 25ms (unchanged)
src/lib/app_components/e_app_theme.svelte 9ms (unchanged)
src/lib/components/ui/button/button.svelte 6ms (unchanged)
src/lib/components/ui/button/index.js 1ms (unchanged)
src/lib/components/ui/button/index.ts 1ms (unchanged)
src/lib/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte 5ms (unchanged)
src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte 2ms (unchanged)
src/lib/components/ui/dropdown-menu/dropdown-menu-group-heading.svelte 2ms (unchanged)
src/lib/components/ui/dropdown-menu/dropdown-menu-item.svelte 2ms (unchanged)
src/lib/components/ui/dropdown-menu/dropdown-menu-label.svelte 2ms (unchanged)
src/lib/components/ui/dropdown-menu/dropdown-menu-radio-item.svelte 3ms (unchanged)
src/lib/components/ui/dropdown-menu/dropdown-menu-separator.svelte 2ms (unchanged)
src/lib/components/ui/dropdown-menu/dropdown-menu-shortcut.svelte 2ms (unchanged)
src/lib/components/ui/dropdown-menu/dropdown-menu-sub-content.svelte 2ms (unchanged)
src/lib/components/ui/dropdown-menu/dropdown-menu-sub-trigger.svelte 2ms (unchanged)
src/lib/components/ui/dropdown-menu/index.js 1ms (unchanged)
src/lib/components/ui/dropdown-menu/index.ts 1ms (unchanged)
src/lib/components/ui/input/index.js 0ms (unchanged)
src/lib/components/ui/input/index.ts 0ms (unchanged)
src/lib/components/ui/input/input.svelte 2ms (unchanged)
src/lib/components/ui/popover/index.js 0ms (unchanged)
src/lib/components/ui/popover/index.ts 1ms (unchanged)
src/lib/components/ui/popover/popover-content.svelte 2ms (unchanged)
src/lib/components/ui/separator/index.js 0ms (unchanged)
src/lib/components/ui/separator/index.ts 1ms (unchanged)
src/lib/components/ui/separator/separator.svelte 2ms (unchanged)
src/lib/components/ui/tooltip/index.js 0ms (unchanged)
src/lib/components/ui/tooltip/index.ts 1ms (unchanged)
src/lib/components/ui/tooltip/tooltip-content.svelte 2ms (unchanged)
src/lib/electron/electron_native.js 33ms (unchanged)
src/lib/electron/electron_relay.js 6ms (unchanged)
src/lib/electron/README.md 4ms (unchanged)
src/lib/element_qr_scanner_v2.svelte 15ms (unchanged)
src/lib/elements/element_ae_crud_v2.svelte 22ms (unchanged)
src/lib/elements/element_ae_crud.svelte 20ms (unchanged)
src/lib/elements/element_codemirror_editor.svelte 4ms (unchanged)
src/lib/elements/element_codemirror_wrapper.svelte 1ms (unchanged)
src/lib/elements/element_data_store_v2.svelte 38ms (unchanged)
src/lib/elements/element_data_store.svelte 29ms (unchanged)
src/lib/elements/element_input_file.svelte 13ms (unchanged)
src/lib/elements/element_input_files_tbl.svelte 13ms (unchanged)
src/lib/elements/element_input_v2.svelte 59ms (unchanged)
src/lib/elements/element_manage_event_file_li_all.svelte 2ms (unchanged)
src/lib/elements/element_manage_event_file_li_direct.svelte 2ms (unchanged)
src/lib/elements/element_manage_event_file_li.svelte 45ms (unchanged)
src/lib/elements/element_manage_hosted_file_li_all.svelte 8ms (unchanged)
src/lib/elements/element_manage_hosted_file_li.svelte 15ms (unchanged)
src/lib/elements/element_obj_tbl_row.svelte 11ms (unchanged)
src/lib/elements/element_sql_qry.svelte 6ms (unchanged)
src/lib/elements/element_tiptap_editor.scss 2ms (unchanged)
src/lib/elements/element_websocket_v2.svelte 16ms (unchanged)
src/lib/stores/ae_events_stores.ts 6ms (unchanged)
src/lib/stores/ae_idaa_stores.ts 2ms (unchanged)
src/lib/stores/ae_stores.ts 6ms (unchanged)
src/lib/utils/ae_string_snippets.ts 1ms (unchanged)
src/lib/utils/index.ts 0ms (unchanged)
src/lib/utils/utils.ts 1ms (unchanged)
src/parent_iframe.html 5ms (unchanged)
src/routes/+layout.svelte 31ms (unchanged)
src/routes/+layout.ts 5ms (unchanged)
src/routes/+page.svelte 7ms (unchanged)
src/routes/admin/+layout.svelte 6ms (unchanged)
src/routes/admin/+page.svelte 8ms (unchanged)
src/routes/core/+layout.svelte 3ms (unchanged)
src/routes/core/+page.svelte 15ms (unchanged)
src/routes/core/+page.ts 0ms (unchanged)
src/routes/core/ae_comp__person_obj_tbl.svelte 9ms (unchanged)
src/routes/core/not_used+layout.ts 1ms (unchanged)
src/routes/core/person_view.svelte 55ms (unchanged)
src/routes/core/person/[person_id]/+page.svelte 13ms (unchanged)
src/routes/core/person/[person_id]/+page.ts 2ms (unchanged)
src/routes/core/README.md 2ms (unchanged)
src/routes/events_badges/+layout.svelte 7ms (unchanged)
src/routes/events_badges/+layout.ts 1ms (unchanged)
src/routes/events_badges/+page.svelte 2ms (unchanged)
src/routes/events_badges/+page.ts 0ms (unchanged)
src/routes/events_badges/README.md 3ms (unchanged)
src/routes/events_badges/review/+layout.ts 1ms (unchanged)
src/routes/events_badges/review/+page.svelte 35ms (unchanged)
src/routes/events_badges/stats/+layout.ts 1ms (unchanged)
src/routes/events_badges/stats/+page.svelte 33ms (unchanged)
src/routes/events_leads/+layout.svelte 2ms (unchanged)
src/routes/events_leads/+layout.ts 1ms (unchanged)
src/routes/events_leads/+page.svelte 8ms (unchanged)
src/routes/events_leads/+page.ts 1ms (unchanged)
src/routes/events_leads/exhibit/[slug]/+page.svelte 36ms (unchanged)
src/routes/events_leads/exhibit/[slug]/+page.ts 2ms (unchanged)
src/routes/events_leads/exhibit/[slug]/leads_add_scan.svelte 37ms (unchanged)
src/routes/events_leads/exhibit/[slug]/leads_list.svelte 25ms (unchanged)
src/routes/events_leads/exhibit/[slug]/leads_manage.svelte 40ms (unchanged)
src/routes/events_leads/exhibit/[slug]/leads_payment.svelte 10ms (unchanged)
src/routes/events_leads/exhibit/[slug]/leads_view_lead.svelte 42ms (unchanged)
src/routes/events_leads/README.md 4ms (unchanged)
src/routes/events/[event_id]/(badges)/badges/[badge_id]/+page.svelte 5ms (unchanged)
src/routes/events/[event_id]/(badges)/badges/[badge_id]/ae_comp__badge_obj_view.svelte 41ms (unchanged)
src/routes/events/[event_id]/(badges)/badges/+layout.svelte 3ms (unchanged)
src/routes/events/[event_id]/(badges)/badges/+page.svelte 5ms (unchanged)
src/routes/events/[event_id]/(badges)/badges/ae_comp__badge_obj_li.svelte 9ms (unchanged)
src/routes/events/[event_id]/(badges)/badges/ae_comp__badge_search.svelte 15ms (unchanged)
src/routes/events/[event_id]/(launcher)/launcher_cfg.svelte 26ms (unchanged)
src/routes/events/[event_id]/(launcher)/launcher_file_cont.svelte 32ms (unchanged)
src/routes/events/[event_id]/(launcher)/launcher_menu.svelte 12ms (unchanged)
src/routes/events/[event_id]/(launcher)/launcher_presenter_view_posters.svelte 6ms (unchanged)
src/routes/events/[event_id]/(launcher)/launcher_presenter_view.svelte 6ms (unchanged)
src/routes/events/[event_id]/(launcher)/launcher_session_view.svelte 17ms (unchanged)
src/routes/events/[event_id]/(launcher)/launcher/[event_location_id]/+page.svelte 4ms (unchanged)
src/routes/events/[event_id]/(launcher)/launcher/[event_location_id]/+page.ts 2ms (unchanged)
src/routes/events/[event_id]/(launcher)/launcher/+layout.svelte 45ms (unchanged)
src/routes/events/[event_id]/(launcher)/launcher/+layout.ts 2ms (unchanged)
src/routes/events/[event_id]/(launcher)/launcher/+page.svelte 0ms (unchanged)
src/routes/events/[event_id]/(launcher)/launcher/+page.ts 0ms (unchanged)
src/routes/events/[event_id]/(launcher)/menu_location_list.svelte 6ms (unchanged)
src/routes/events/[event_id]/(launcher)/menu_session_list.svelte 10ms (unchanged)
src/routes/events/[event_id]/+layout.svelte 2ms (unchanged)
src/routes/events/[event_id]/+layout.ts 1ms (unchanged)
src/routes/events/[event_id]/+page.svelte 20ms (unchanged)
src/routes/events/[event_id]/+page.ts 1ms (unchanged)
src/routes/events/[event_id]/device/ae_comp__event_device_obj_li_wrapper.svelte 2ms (unchanged)
src/routes/events/[event_id]/device/ae_comp__event_device_obj_li.svelte 28ms (unchanged)
src/routes/events/[event_id]/event_page_menu.svelte 37ms (unchanged)
src/routes/events/[event_id]/location/[event_location_id]/+page.svelte 11ms (unchanged)
src/routes/events/[event_id]/location/[event_location_id]/+page.ts 2ms (unchanged)
src/routes/events/[event_id]/location/[event_location_id]/location_page_menu.svelte 26ms (unchanged)
src/routes/events/[event_id]/location/[event_location_id]/location_view.svelte 27ms (unchanged)
src/routes/events/[event_id]/locations/+page.svelte 5ms (unchanged)
src/routes/events/[event_id]/locations/ae_comp__event_location_obj_li.svelte 18ms (unchanged)
src/routes/events/[event_id]/locations/locations_page_menu.svelte 11ms (unchanged)
src/routes/events/[event_id]/presenter/[presenter_id]/+page.svelte 17ms (unchanged)
src/routes/events/[event_id]/presenter/[presenter_id]/+page.ts 1ms (unchanged)
src/routes/events/[event_id]/presenter/[presenter_id]/ae_comp__event_presenter_form_agree.svelte 13ms (unchanged)
src/routes/events/[event_id]/presenter/[presenter_id]/presenter_page_menu.svelte 30ms (unchanged)
src/routes/events/[event_id]/presenter/[presenter_id]/presenter_view.svelte 108ms (unchanged)
src/routes/events/[event_id]/presenter/ae_comp__event_presenter_obj_li_wrapper.svelte 3ms (unchanged)
src/routes/events/[event_id]/presenter/ae_comp__event_presenter_obj_li.svelte 22ms (unchanged)
src/routes/events/[event_id]/presenter/ae_comp__event_presenter_obj_tbl_wrapper.svelte 4ms (unchanged)
src/routes/events/[event_id]/presenter/ae_comp__event_presenter_obj_tbl.svelte 15ms (unchanged)
src/routes/events/[event_id]/reports/+page.svelte 66ms (unchanged)
src/routes/events/[event_id]/reports/event_reports_page_menu.svelte 16ms (unchanged)
src/routes/events/[event_id]/reports/reports_files.svelte 14ms (unchanged)
src/routes/events/[event_id]/reports/reports_presenters.svelte 9ms (unchanged)
src/routes/events/[event_id]/reports/reports_sessions.svelte 10ms (unchanged)
src/routes/events/[event_id]/session/[session_id]/+page.svelte 16ms (unchanged)
src/routes/events/[event_id]/session/[session_id]/+page.ts 2ms (unchanged)
src/routes/events/[event_id]/session/[session_id]/ae_comp__event_session_poc_form_agree.svelte 17ms (unchanged)
src/routes/events/[event_id]/session/[session_id]/ae_comp__event_session_poc_profile.svelte 9ms (unchanged)
src/routes/events/[event_id]/session/[session_id]/session_page_menu.svelte 30ms (unchanged)
src/routes/events/[event_id]/session/[session_id]/session_view.svelte 59ms (unchanged)
src/routes/events/[event_id]/session/ae_comp__event_session_alert.svelte 9ms (unchanged)
src/routes/events/[event_id]/sign_in_out.svelte 7ms (unchanged)
src/routes/events/+layout.svelte 11ms (unchanged)
src/routes/events/+layout.ts 1ms (unchanged)
src/routes/events/+page.svelte 7ms (unchanged)
src/routes/events/+page.ts 1ms (unchanged)
src/routes/events/ae_comp__event_file_obj_tbl_wrapper.svelte 3ms (unchanged)
src/routes/events/ae_comp__event_file_obj_tbl.svelte 31ms (unchanged)
src/routes/events/ae_comp__event_files_upload.svelte 10ms (unchanged)
src/routes/events/ae_comp__event_presentation_obj_li.svelte 27ms (unchanged)
src/routes/events/ae_comp__event_session_obj_li_wrapper.svelte 2ms (unchanged)
src/routes/events/ae_comp__event_session_obj_li.svelte 31ms (unchanged)
src/routes/events/ae_comp__event_session_obj_tbl_wrapper.svelte 3ms (unchanged)
src/routes/events/ae_comp__event_session_obj_tbl.svelte 5ms (unchanged)
src/routes/events/ae_comp__events_menu_nav.svelte 5ms (unchanged)
src/routes/events/ae_comp__events_menu_opts.svelte 25ms (unchanged)
src/routes/events/README.md 3ms (unchanged)
src/routes/hosted_files/+layout.svelte 2ms (unchanged)
src/routes/hosted_files/+layout.ts 1ms (unchanged)
src/routes/hosted_files/+page.svelte 3ms (unchanged)
src/routes/hosted_files/video_util/+page.svelte 8ms (unchanged)
src/routes/hosted_files/video_util/hold_video_util.svelte 7ms (unchanged)
src/routes/idaa/(idaa)/+layout.svelte 6ms (unchanged)
src/routes/idaa/(idaa)/archives/[archive_id]/+page.svelte 12ms (unchanged)
src/routes/idaa/(idaa)/archives/[archive_id]/+page.ts 2ms (unchanged)
src/routes/idaa/(idaa)/archives/[archive_id]/ae_idaa_comp__archive_content_obj_id_edit.svelte 32ms (unchanged)
src/routes/idaa/(idaa)/archives/[archive_id]/ae_idaa_comp__archive_content_obj_li.svelte 15ms (unchanged)
src/routes/idaa/(idaa)/archives/[archive_id]/ae_idaa_comp__archive_obj_id_edit.svelte 19ms (unchanged)
src/routes/idaa/(idaa)/archives/[archive_id]/ae_idaa_comp__archive_obj_id_view.svelte 10ms (unchanged)
src/routes/idaa/(idaa)/archives/[archive_id]/ae_idaa_comp__modal_media_player.svelte 4ms (unchanged)
src/routes/idaa/(idaa)/archives/[archive_id]/not_used+layout.ts 0ms (unchanged)
src/routes/idaa/(idaa)/archives/+layout.svelte 1ms (unchanged)
src/routes/idaa/(idaa)/archives/+layout.ts 1ms (unchanged)
src/routes/idaa/(idaa)/archives/+page.svelte 5ms (unchanged)
src/routes/idaa/(idaa)/archives/ae_idaa_comp__archive_obj_li.svelte 5ms (unchanged)
src/routes/idaa/(idaa)/archives/ae_idaa_comp__media_player.svelte 6ms (unchanged)
src/routes/idaa/(idaa)/bb/[post_id]/+page.svelte 7ms (unchanged)
src/routes/idaa/(idaa)/bb/[post_id]/+page.ts 1ms (unchanged)
src/routes/idaa/(idaa)/bb/+layout.svelte 2ms (unchanged)
src/routes/idaa/(idaa)/bb/+layout.ts 1ms (unchanged)
src/routes/idaa/(idaa)/bb/+page.svelte 7ms (unchanged)
src/routes/idaa/(idaa)/bb/+page.ts 2ms (unchanged)
src/routes/idaa/(idaa)/bb/ae_idaa_comp__post_comment_obj_id_edit.svelte 26ms (unchanged)
src/routes/idaa/(idaa)/bb/ae_idaa_comp__post_obj_id_edit.svelte 38ms (unchanged)
src/routes/idaa/(idaa)/bb/ae_idaa_comp__post_obj_id_view.svelte 17ms (unchanged)
src/routes/idaa/(idaa)/bb/ae_idaa_comp__post_obj_li.svelte 9ms (unchanged)
src/routes/idaa/(idaa)/bb/ae_idaa_comp__post_options.svelte 8ms (unchanged)
src/routes/idaa/(idaa)/hold_+page.svelte 0ms (unchanged)
src/routes/idaa/(idaa)/hold_app.pcss 7ms (unchanged)
src/routes/idaa/(idaa)/recovery_meetings/[event_id]/+page.svelte 8ms (unchanged)
src/routes/idaa/(idaa)/recovery_meetings/[event_id]/+page.ts 1ms (unchanged)
src/routes/idaa/(idaa)/recovery_meetings/+layout.svelte 2ms (unchanged)
src/routes/idaa/(idaa)/recovery_meetings/+layout.ts 1ms (unchanged)
src/routes/idaa/(idaa)/recovery_meetings/+page.svelte 9ms (unchanged)
src/routes/idaa/(idaa)/recovery_meetings/ae_idaa_comp__event_obj_id_edit.svelte 80ms (unchanged)
src/routes/idaa/(idaa)/recovery_meetings/ae_idaa_comp__event_obj_id_view.svelte 34ms (unchanged)
src/routes/idaa/(idaa)/recovery_meetings/ae_idaa_comp__event_obj_li_wrapper.svelte 3ms (unchanged)
src/routes/idaa/(idaa)/recovery_meetings/ae_idaa_comp__event_obj_li.svelte 24ms (unchanged)
src/routes/idaa/(idaa)/recovery_meetings/ae_idaa_comp__event_obj_qry.svelte 27ms (unchanged)
src/routes/idaa/(idaa)/recovery_meetings/not_used+page.ts 0ms (unchanged)
src/routes/idaa/+layout.svelte 9ms (unchanged)
src/routes/idaa/README.md 3ms (unchanged)
src/routes/journals/[journal_id]/+layout.svelte 12ms (unchanged)
src/routes/journals/[journal_id]/+layout.ts 2ms (unchanged)
src/routes/journals/[journal_id]/+page.svelte 8ms (unchanged)
src/routes/journals/[journal_id]/+page.ts 1ms (unchanged)
src/routes/journals/[journal_id]/entry/[journal_entry_id]/+page.svelte 6ms (unchanged)
src/routes/journals/[journal_id]/entry/[journal_entry_id]/+page.ts 1ms (unchanged)
src/routes/journals/+layout.svelte 14ms (unchanged)
src/routes/journals/+layout.ts 1ms (unchanged)
src/routes/journals/+page.svelte 8ms (unchanged)
src/routes/journals/+page.ts 1ms (unchanged)
src/routes/journals/ae_comp__journal_entry_obj_file_li.svelte 12ms (unchanged)
src/routes/journals/ae_comp__journal_entry_obj_id_view.svelte 102ms (unchanged)
src/routes/journals/ae_comp__journal_entry_obj_li.svelte 34ms (unchanged)
src/routes/journals/ae_comp__journal_entry_obj_qry.svelte 7ms (unchanged)
src/routes/journals/ae_comp__journal_obj_id_edit.svelte 39ms (unchanged)
src/routes/journals/ae_comp__journal_obj_id_view.svelte 9ms (unchanged)
src/routes/journals/ae_comp__journal_obj_li.svelte 6ms (unchanged)
src/routes/journals/ae_comp__obj_core_props.svelte 12ms (unchanged)
src/routes/journals/modal_journals_config.svelte 12ms (unchanged)
src/routes/journals/README.md 2ms (unchanged)
src/routes/testing/+layout.ts 0ms (unchanged)
src/routes/testing/+page.svelte 4ms (unchanged)
static/idaa_novi_iframe_archives.html 4ms (unchanged)
static/idaa_novi_iframe_bulletin_board.html 3ms (unchanged)
static/idaa_novi_iframe_jitsi_meeting.html 3ms (unchanged)
static/idaa_novi_iframe_recovery_meetings.html 3ms (unchanged)
static/jitsi_iframe_api.html 4ms (unchanged)
static/manifest.json 1ms (unchanged)
SVELTE_DEXIE_GUIDE.md 8ms (unchanged)
svelte.config.js 1ms (unchanged)
test-results/.last-run.json 0ms (unchanged)
tests/example.test.ts 1ms (unchanged)
TODO.md 18ms (unchanged)
tsconfig.json 1ms (unchanged)
vite.config.ts 1ms (unchanged)
vitest.config.ts 0ms (unchanged) to clean up dependencies and fix formatting.
2025-11-17 21:24:57 -05:00
Scott Idem
5c67421d7e feat: Add README files for various modules and routes 2025-11-17 20:28:34 -05:00
Scott Idem
3a0d901a05 Fix: Resolve parsing error and svelte/no-at-html-tags linting issues
Resolved a critical parsing error in leads_view_lead.svelte due to incorrect Svelte class directive syntax.

Addressed multiple svelte/no-at-html-tags linting errors across the following files to mitigate potential XSS vulnerabilities and improve code safety:
- src/routes/events_leads/exhibit/[slug]/leads_add_scan.svelte
- src/routes/events_leads/exhibit/[slug]/leads_manage.svelte
- src/routes/events_leads/exhibit/[slug]/leads_view_lead.svelte

Replaced {@html} blocks with safer Svelte conditional rendering ({#if}) and direct interpolation ({value}) for static and dynamic content where appropriate. Removed commented-out {@html} tags that were still triggering linting errors.
2025-11-17 19:11:01 -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
b99e85f1db fix(events): Correct data fetching for session child objects
This commit fixes a bug where presentations, presenters, and files related to a session were not being displayed. The issues were caused by incorrect property names ( suffix) and improper use of Svelte 5 features after a recent refactoring.
2025-11-17 17:47:24 -05:00
Scott Idem
a3b37a5df4 refactor: Standardize data processing and update to Svelte 5 runes
This commit introduces a major refactoring of the data processing logic across multiple modules (events, archives, posts, sponsorships) to use a standardized pattern with . This improves consistency and maintainability.

Key changes:
- Replaced module-specific data processing with a generic helper.
- Removed deprecated  functions.
- Updated Svelte components to leverage the new Svelte 5 runes, simplifying state management.
- Fixed linting errors and updated test configurations.
- Added .
2025-11-17 16:38:54 -05:00
Scott Idem
c4fa35e86e Saving the new documentation for Svelte and Dexie made by Gemini. Saving changes made by Gemini to fix various things. 2025-11-17 14:09:33 -05:00
Scott Idem
02169f1cb9 fix(events): correct presentation query 2025-11-13 21:43:20 -05:00
Scott Idem
92ef08ce1f fix(events): correct presentation query and props 2025-11-13 21:38:47 -05:00
Scott Idem
d554696c8e fix(events): correct presentation query and props 2025-11-13 21:33:00 -05:00
Scott Idem
66c42a52f9 Reapply "fix(events): correct reactive props in session view"
This reverts commit 97e9f35ea1.
2025-11-13 21:28:12 -05:00
Scott Idem
97e9f35ea1 Revert "fix(events): correct reactive props in session view"
This reverts commit b03376e136.
2025-11-13 21:28:07 -05:00
Scott Idem
b03376e136 fix(events): correct reactive props in session view
This commit fixes a bug where the session view was not displaying correctly due to incorrect usage of reactive props.

- In , the  prefix was added to the props passed to the  component to make them reactive.
- In , the  prefix was removed from the  variables in the template, as they are already reactive when using Svelte 5 runes.
- The  block for  was corrected to use the resolved value.
2025-11-13 21:17:49 -05:00
Scott Idem
7ded0fd9a6 fix(events): correct presentation query in session view
This commit fixes a bug where presentations were not being displayed correctly within the event session view. The issue was caused by an incorrect query that was using the standard session ID to filter presentations, instead of the random session ID.

The liveQuery in  has been updated to use the  from the  derived variable. This ensures that the query correctly fetches all presentations associated with the session.
2025-11-13 20:38:21 -05:00
Scott Idem
e19b448238 Updates to fixed processed_obj. Fixed other things with find and replace and regular expressions. 2025-11-13 20:29:30 -05:00
Scott Idem
3104304fdb Updates to common enabled and hidden properties. 2025-11-13 20:16:22 -05:00
Scott Idem
88d36d512d Update to all catch functions. 2025-11-13 20:15:09 -05:00
Scott Idem
7cd59bfaac Another round of lots of updates to fix little bugs here there and everywhere. 2025-11-13 20:03:51 -05:00
Scott Idem
13869b40bd Trying to remove some more _random suffixes. Ideally they will all eventually go away and we will just use .id or example.example_id or example.linked_obj_name_id 2025-11-13 19:28:52 -05:00
Scott Idem
a87fa02bc6 Revert: Legacy launcher link changes
Reverted changes to legacy launcher links in various components. These links are intentionally structured to work with nginx location aliases and should not be modified to conform to SvelteKit routing.
2025-11-13 19:15:55 -05:00
Scott Idem
aef34dc79b Fix: Correctly load session content in new launcher
The session content was not loading in the new Events Launcher because the loaded session data was not being correctly assigned to the events store.

This commit fixes the issue by correctly assigning the loaded session object and its nested properties to the events store.
2025-11-13 19:03:43 -05:00
Scott Idem
0e960ba955 Fixing id_random vs id for links and other things. Fixed the hash SHA256 error. 2025-11-13 18:59:27 -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
a84d06a28d Refactor: Update import paths for elements after moving them to src/lib/elements/. 2025-11-13 16:37:24 -05:00
Scott Idem
6e00502d3d Refactor: Update import paths for app_components after moving them to src/lib/app_components/. 2025-11-13 16:19:09 -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
94832c2471 Refactor: Organize src/lib into subdirectories and move files accordingly. 2025-11-13 16:09:03 -05:00
Scott Idem
6d8089bdbd Revert: Remove remaining codemirror-toolbar imports and extensions from e_app_codemirror_v5.svelte. 2025-11-13 16:03:44 -05:00
Scott Idem
14a69ca433 Revert: Rollback codemirror-toolbar integration and uninstall packages due to module resolution error. 2025-11-13 15:59:25 -05:00
Scott Idem
2f83aefd22 Feat: Integrate codemirror-toolbar with markdownItems into e_app_codemirror_v5.svelte for basic rich text editing. 2025-11-13 15:44:05 -05:00
Scott Idem
81e4d83c2d Docs: Update ARCHITECTURE.md and COMPONENTS.md to reflect ShadCN removal and CodeMirror emphasis. 2025-11-13 15:40:56 -05:00
Scott Idem
03a6661360 Cleaned up MarkDown again 2025-11-13 15:36:45 -05:00
Scott Idem
882b9b5bc7 Docs: Create ARCHITECTURE.md, COMPONENTS.md, and DATA_STRUCTURES.md for comprehensive project documentation. 2025-11-13 15:33:39 -05:00
Scott Idem
cfed92e8a5 Formatting clean up 2025-11-13 15:23:49 -05:00
Scott Idem
853219ce16 Docs: Rename old README_guidelines files to OLD_README_guidelines for historical purposes. 2025-11-13 15:23:12 -05:00
Scott Idem
514dfe913c Docs: Create NAMING_CONVENTIONS.md to standardize naming across the Aether project. 2025-11-13 15:20:19 -05:00
Scott Idem
fd083faac5 More documentation for the AIs to read. 2025-11-13 15:19:05 -05:00
Scott Idem
4093afe4fc Missed one 2025-11-13 15:12:17 -05:00
Scott Idem
fb634268c1 Refactor: Standardize naming conventions in ae_core module to snake_case and remove deprecated functions. 2025-11-13 15:11:25 -05:00
Scott Idem
d4ead978f9 Remove redundant/backup element_qr_scanner and old_e_app_codemirror files. 2025-11-13 14:50:15 -05:00
Scott Idem
4b4c3c5552 Fixed MarkDown formatting 2025-11-13 14:38:30 -05:00
Scott Idem
4d6c10cbad Quick save before more big changes. 2025-11-13 14:26:04 -05:00
Scott Idem
a995711335 Update TODO.md and GEMINI.md to reflect temporary rollback of ae_core_functions.ts and module-by-module refactoring plan. 2025-11-13 14:24:05 -05:00
Scott Idem
bc10075314 I think we are done with the first big rounds of changes by Gemini. 2025-11-13 12:52:46 -05:00
Scott Idem
389f0c855f Starting another round of changes by Gemini. Saving things in a working state. 2025-11-13 12:47:57 -05:00
Scott Idem
db8c0e0d05 Quick snapshot again as Gemini is working. 2025-11-13 12:44:28 -05:00
Scott Idem
dfaa27384b Saving a quick snapshot after Gemini changes to Dexie function and processing functions. 2025-11-13 12:12:58 -05:00
Scott Idem
848a3e9a4b First realish round of updates by Gemini... 2025-11-13 11:12:06 -05:00
Scott Idem
e793db8d3b feat: Initialize branch for AI-driven development
This commit introduces the initial setup for the `ae_app_3x_llm` branch.
The purpose of this branch is to explore and implement more direct
collaboration with AI Large Language Models (LLMs) for complex code
changes, including the creation of new function libraries and the
modification of existing code.

This initial commit includes:
- GEMINI.md: A file to provide context to the AI about the project.
- TODO.md: A to-do list for upcoming development tasks, created in
  collaboration with the AI.
2025-11-04 21:59:33 -05:00
Scott Idem
35031d3193 Added new topic for IDAA BB 2025-11-03 18:04:47 -05:00
Scott Idem
616d6a4404 Another moderator 2025-11-03 17:51:48 -05:00
Scott Idem
d9887aba93 Making things look nicer 2025-10-17 18:14:09 -04:00
Scott Idem
fab1a4916d Clean up of the event search page options menu and related. 2025-10-17 17:27:18 -04:00
Scott Idem
bb993a1028 Last minute clean up before LCI. 2025-10-17 16:22:23 -04:00
Scott Idem
d1c0148c75 Sort of bug fix for version reload. Does it need the alert() to work correctly??? 2025-10-16 21:43:08 -04:00
Scott Idem
e912c4a48a Better text sizing and flex. 2025-10-16 16:39:30 -04:00
Scott Idem
8b22c0fc34 The Launcher works pretty well. Except for the native app... 2025-10-16 16:07:37 -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
c2ccf0c06d Fix for disabling and hiding event file purpose options. 2025-10-16 10:04:12 -04:00
Scott Idem
c170358681 Quick icon change. 2025-10-15 19:04:56 -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
a6058efaf0 Good saving point. Version reset looks good now. 2025-10-15 14:12:04 -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
Scott Idem
0bc04bf899 Things are looking and working better. Note the Modal size is set to "". This allows it to stretch to the full width of the screen. 2025-10-13 18:17:32 -04:00
Scott Idem
8f7c1bf428 More work on the posters and Websockets 2025-10-13 17:19:32 -04:00
Scott Idem
de071dae49 Work on the Launder and Websockets. It needs work. 2025-10-13 15:41:55 -04:00
Scott Idem
5b9dacd291 Better logic for lengths. Keep them more equal. 2025-10-10 17:54:49 -04:00
Scott Idem
8c2241e610 Work on badge rendering. 2025-10-10 17:40:35 -04:00
Scott Idem
74cc5c5d0d Work on badge printing and the actual badge layout. 2025-10-09 19:26:35 -04:00
Scott Idem
0f05fd708f Minor bug fix. 2025-10-08 19:19:35 -04:00
Scott Idem
41d20a3bcf Minor clean up getting ready for LCI and demo for AAPOR. 2025-10-08 16:41:57 -04:00
Scott Idem
bad5da3ddc More serious work on badge printing. Working on the templates and actually implementing the printable badge. 2025-10-07 19:39:53 -04:00
Scott Idem
28cb8e2bf2 Testing 2025-10-07 03:35:45 -04:00
Scott Idem
11334a17b1 Minor 2025-10-07 03:32:20 -04:00
Scott Idem
b24262b4ab Could not sleep. Working on the search for badges. 2025-10-07 03:25:02 -04:00
Scott Idem
e1a04d5eda Not sure 2025-10-06 18:56:16 -04:00
Scott Idem
00ff9554d8 Trying to simplify things 2025-10-06 18:54:11 -04:00
Scott Idem
d8b7ad61b3 Significant work on getting badges ready again. 2025-10-06 18:43:33 -04:00
Scott Idem
88e4ab119d More updates related to the IDB table name changes for events. 2025-10-06 14:25:52 -04:00
Scott Idem
c3992d8711 Removing old code. Standardizing the event related IDB table names. Getting badge printing ready again.... 2025-10-06 14:04:46 -04:00
Scott Idem
cd03d9e488 Updating the badge printing module. It needs a bit of work. Removing the old versions of functions. 2025-10-06 13:54:20 -04:00
Scott Idem
9fa7247204 Note on changes to QR code function. 2025-10-03 17:44:43 -04:00
Scott Idem
c4115adfd6 Wrapping up for the week. Version bump. 2025-10-03 17:42:11 -04:00
Scott Idem
af9c4a82f0 Making the QR codes work again. Also making things look better. 2025-10-03 17:41:35 -04:00
Scott Idem
c949581429 Moving older event_speakers and sponsorships modules to backups. 2025-10-03 14:49:17 -04:00
Scott Idem
a2f2742f30 More clean up. Making this live now. 2025-10-03 14:44:18 -04:00
Scott Idem
bcee6c5281 More work on the alerts for sessions. I think they are pretty good now. 2025-10-03 14:29:24 -04:00
Scott Idem
75f7ed54a5 Cleaning up the new session alerts 2025-10-03 14:01:25 -04:00
Scott Idem
c70abc46f3 Finally using the alerts for sessions!! 2025-10-03 13:27:12 -04:00
Scott Idem
b85d2ee98c The new event files reports has been cleaned up and more configurable. 2025-10-02 12:57:37 -04:00
Scott Idem
03f831de8a Quick bug fix for sorting 2025-10-02 11:07:25 -04:00
Scott Idem
b5a6c15059 Bug fix for file report sorting 2025-10-02 10:34:50 -04:00
Scott Idem
4aeded3a12 Working on making sure notifications are being sent to IDAA staff when a post or post comment is created or updated. It looks like it is working.... 2025-10-01 13:03:16 -04:00
Scott Idem
f96a14107a More work on using the new Element_ae_crud_v2 component 2025-09-30 13:11:52 -04:00
Scott Idem
99fe486842 Work on auto reload and related single property updates. Also bug fix for saving searched sessions. 2025-09-30 12:05:55 -04:00
Scott Idem
53a03f971f Added new auto reload for most object types with new v2 function and element. 2025-09-30 03:43:29 -04:00
Scott Idem
0c01eed5c8 More work on new CRUD element. Now able to update the session location in the list. 2025-09-29 18:58:54 -04:00
Scott Idem
22d7c4728d More work on the CRUD element 2025-09-29 14:17:27 -04:00
Scott Idem
24ba3940f8 Work on updating the custom CRUD element. 2025-09-29 14:06:47 -04:00
Scott Idem
f5e035318a Bug fix for saving location in session view 2025-09-29 10:55:51 -04:00
Scott Idem
c42ab0bfa0 Temporary bug fix for the file type reports. Minor update for IDAA and Jitsi iframe. 2025-09-24 18:00:12 -04:00
Scott Idem
abed17f5da Mostly cosmetic styles 2025-09-24 17:43:40 -04:00
Scott Idem
1ba9cd1c03 Lots of work on getting the Launcher actually working well. 2025-09-24 16:56:32 -04:00
Scott Idem
4220a354be Now with all reports broken out by type and things generally cleaned up. 2025-09-24 12:18:15 -04:00
Scott Idem
6f4f54a0c9 Mostly working with event file reports being moved out. 2025-09-24 10:50:28 -04:00
Scott Idem
08bc3142e6 Updates for Jitsi and IDAA 2025-09-23 14:41:06 -04:00
Scott Idem
2f4800f995 Adding notify/alert/message staff link to Google Form for IDAA. 2025-09-23 13:16:38 -04:00
Scott Idem
5bf231c468 Adding new Jitsi meeting links and related. 2025-09-23 12:41:14 -04:00
Scott Idem
7490545ba7 Work on Jitsi for IDAA 2025-09-23 11:23:05 -04:00
Scott Idem
43d64696d5 Sort of bug fix for hiding the header and footer at the right time. 2025-09-19 18:10:23 -04:00
Scott Idem
231c2eea17 Hiding scroll right button 2025-09-19 17:16:01 -04:00
Scott Idem
79c0c90eae Bug fix for scroll to end. 2025-09-19 16:50:14 -04:00
Scott Idem
5b7aa320e2 Getting rid of old code. Wrapping up for the day and week. 2025-09-19 16:23:39 -04:00
Scott Idem
f06358439f Making things look good. Now with scroll to top and bottom for Journals and Events. 2025-09-19 16:18:36 -04:00
Scott Idem
86fbbfdfb5 Never ending work on styles. Trying to make absolute positioned headers and footers work. Also added scroll to top for Journals. 2025-09-19 15:05:56 -04:00
Scott Idem
59b6577d68 Minor updates and version bump. 2025-09-19 10:40:08 -04:00
Scott Idem
fc4e59dd8c More work on styles... flex wraps everywhere. 2025-09-19 10:32:08 -04:00
Scott Idem
5527bce327 Saving changes from last night related to Jitsi. 2025-09-19 09:30:13 -04:00
Scott Idem
7a0ba7d571 More work on proof of concept for Jitsi meetings in IDAA's Novi site. 2025-09-18 18:47:25 -04:00
Scott Idem
811876e36a This new Jitsi page is working well. Now with URL params. 2025-09-18 16:54:46 -04:00
Scott Idem
7fd3ef4f63 Work on Jitsi for IDAA in the Novi site. 2025-09-18 15:52:45 -04:00
Scott Idem
8ff9f2439f Flex wrap... 2025-09-18 12:09:23 -04:00
Scott Idem
d6204d983a More work on scrolling. 2025-09-18 12:02:36 -04:00
Scott Idem
623b62f716 I think things are scrolling better. Other style clean up for dark mode. 2025-09-18 10:44:01 -04:00
Scott Idem
4f36d3eab3 Trying to at least make things scroll as well as they did yesterday... 2025-09-18 10:05:34 -04:00
Scott Idem
64f6b290ad This is not working... 2025-09-18 09:20:44 -04:00
Scott Idem
46a89c36fe Working on general styles 2025-09-17 19:21:01 -04:00
Scott Idem
6b6418b753 Making things look good. 2025-09-17 18:04:10 -04:00
Scott Idem
60fbfc434e More work on the Launcher and related 2025-09-17 16:36:04 -04:00
Scott Idem
c9e9fbec79 Lots of work on the Launcher. Still mostly just cleaning things up. 2025-09-17 15:15:50 -04:00
Scott Idem
186923671d Finally working on the Launcher piece again. Getting it updated to match the standards for everything else. 2025-09-17 13:40:57 -04:00
Scott Idem
b1aae55900 Oops forgot to add the column 2025-09-16 19:21:04 -04:00
Scott Idem
f1b3820fde Minor changes 2025-09-16 18:59:01 -04:00
Scott Idem
c670778ff3 The session reports look good now. Need to work on the file related reports next. 2025-09-16 18:57:34 -04:00
Scott Idem
15e0e423f2 Saving work on reports. Trying separate out the session specific reports. 2025-09-16 18:37:50 -04:00
Scott Idem
c7b8d49730 Lots of style improvements. Dark mode is mostly useable now. Work on reports. 2025-09-16 12:59:20 -04:00
Scott Idem
32b6f59245 Work on report config options and export of presenters 2025-09-16 10:14:58 -04:00
Scott Idem
c530ff8683 Work on AI related. 2025-09-15 18:09:37 -04:00
Scott Idem
fd3105b4e1 General clean up. Make things configurable. More AI stuff. 2025-09-12 16:20:50 -04:00
Scott Idem
0931b960b6 More query limit options. 2025-09-12 13:27:16 -04:00
Scott Idem
662e19b091 Work on event reports. Making them easier to manage. 2025-09-12 13:12:50 -04:00
Scott Idem
01273c3c4d Package updates and minor fixes 2025-09-11 19:01:59 -04:00
Scott Idem
b78cb8eac2 Now with basic AI summary for Journal Entries 2025-09-11 18:41:16 -04:00
Scott Idem
bbf9411213 More work on encryption related content and history. 2025-09-11 15:44:07 -04:00
Scott Idem
db95ed88a3 Code clean up. Version update. 2025-09-10 21:00:06 -04:00
Scott Idem
084e52be15 Wrapping up for the night. Lots of work on encryption related. 2025-09-10 20:58:10 -04:00
Scott Idem
cc6186467a Bug fixes and clean up for the recent history of Journal Entries. 2025-09-10 17:31:04 -04:00
Scott Idem
efa7833fb3 Style updates 2025-09-08 19:13:48 -04:00
Scott Idem
f842392aac More work on reports and config options 2025-09-08 17:43:30 -04:00
Scott Idem
438d366b98 Work on reports for LCI 2025-09-08 17:12:44 -04:00
Scott Idem
88c4f4e891 Bug fix for access denied message. Better formatting and extra Cancel edit button 2025-09-08 15:21:43 -04:00
Scott Idem
92a00ddee9 Sort of bug fix related to Novi linking. 2025-09-08 15:09:32 -04:00
Scott Idem
9e78ba970b Bug fix for restricted access message showing. 2025-09-05 17:41:27 -04:00
Scott Idem
5a0b13700f Finally better responsive reports again. 2025-09-04 19:31:27 -04:00
Scott Idem
bd964cac80 Still working on reports... Why are they not more responsive? 2025-09-04 18:50:50 -04:00
Scott Idem
f72a77ba60 More work related to reports and them refreshing correctly 2025-09-04 12:58:06 -04:00
Scott Idem
390bcf05a4 Work on Event reports. 2025-09-04 12:30:32 -04:00
Scott Idem
4fcf28f303 Bug fix for searching event sessions. 2025-09-04 09:57:06 -04:00
Scott Idem
84b18a33ed Hide menu by default... not testing. 2025-09-03 18:30:04 -04:00
Scott Idem
9869c695f7 General clean up. Show menu instead of link to all journals list. For now it just includes the most recent Entries loaded. 2025-09-03 18:27:24 -04:00
Scott Idem
66510c8ff1 Mostly style improvements for mobile sized 2025-09-03 16:19:54 -04:00
Scott Idem
7364ce5527 Remove debug code!! 2025-09-03 15:06:55 -04:00
Scott Idem
a6ae701e0f Minor update to logic 2025-09-03 14:52:53 -04:00
Scott Idem
711e24a7d0 Bug fixes and general code clean up related to the IDAA Archives. 2025-09-03 14:35:44 -04:00
Scott Idem
acb96729d1 Hide the Journal description by default 2025-08-22 15:57:35 -04:00
Scott Idem
7136eb04d8 Improvement to search progress and status and style 2025-08-22 15:51:08 -04:00
Scott Idem
7bb4e20ce7 Mostly style improvements. 2025-08-22 15:28:35 -04:00
Scott Idem
8a9864771b Minor improvements and fixes for Journals searching and styles. 2025-08-22 14:35:15 -04:00
Scott Idem
f3ee4ee987 Minor fixes. Better dark mode style. 2025-08-21 18:28:40 -04:00
Scott Idem
6d2c3cb056 Work on making the Entry search query work correctly. Moved things around. Hopefully easier to read and understand. 2025-08-21 18:00:32 -04:00
Scott Idem
33c6cb862e Trying to improve the sign in and passcode logic. Also related bug fixes with focus. Made Journal Entries marked as public visible to others. 2025-08-21 13:55:23 -04:00
Scott Idem
edfe9dee7a Finally work on the Journals to fix some bugs. Now with much better append and prepend to Journal Entry. 2025-08-19 18:50:23 -04:00
Scott Idem
ebaba77fe3 Version bump and package updates. 2025-08-19 15:57:28 -04:00
Scott Idem
6dec20d932 Bug fix to allow the Session POC to be null. Minor changes. 2025-08-19 13:53:54 -04:00
Scott Idem
35b6662b5b Styles... 2025-08-12 19:43:26 -04:00
Scott Idem
6f5b40d5ab Bug fix for Journal Entry view 2025-08-12 19:12:33 -04:00
Scott Idem
565712b818 Never ending work on styles 2025-08-12 18:59:01 -04:00
Scott Idem
0446822779 Minor alignment fix 2025-08-12 18:06:54 -04:00
Scott Idem
231462e3ad Working to make the dark mode look better. Work on the help tech component. General clean up. 2025-08-12 17:59:37 -04:00
Scott Idem
496eea48ee Version bump 2025-08-12 14:20:12 -04:00
Scott Idem
05d7e78444 Bug fixes 2025-08-12 14:19:54 -04:00
Scott Idem
1e20539b1a Creating a new branch and updating the version number to reflect the changes. 2025-08-12 13:45:02 -04:00
499 changed files with 91128 additions and 91611 deletions

View File

@@ -1,31 +1,31 @@
/** @type { import("eslint").Linter.Config } */
module.exports = {
root: true,
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:svelte/recommended',
'prettier'
],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020,
extraFileExtensions: ['.svelte']
},
env: {
browser: true,
es2017: true,
node: true
},
overrides: [
{
files: ['*.svelte'],
parser: 'svelte-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser'
}
}
]
root: true,
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:svelte/recommended',
'prettier'
],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020,
extraFileExtensions: ['.svelte']
},
env: {
browser: true,
es2017: true,
node: true
},
overrides: [
{
files: ['*.svelte'],
parser: 'svelte-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser'
}
}
]
};

View File

@@ -1,8 +1,9 @@
{
"useTabs": true,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100,
"plugins": ["prettier-plugin-svelte"],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
"useTabs": false,
"tabWidth": 4,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100,
"plugins": ["prettier-plugin-svelte"],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
}

241
.vscode/settings.json vendored
View File

@@ -1,121 +1,122 @@
{
"prettier.documentSelectors": [
"**/*.svelte"
],
"tailwindCSS.classAttributes": [
"class",
"accent",
"active",
"animIndeterminate",
"aspectRatio",
"background",
"badge",
"bgBackdrop",
"bgDark",
"bgDrawer",
"bgLight",
"blur",
"border",
"button",
"buttonAction",
"buttonBack",
"buttonClasses",
"buttonComplete",
"buttonDismiss",
"buttonNeutral",
"buttonNext",
"buttonPositive",
"buttonTextCancel",
"buttonTextConfirm",
"buttonTextFirst",
"buttonTextLast",
"buttonTextNext",
"buttonTextPrevious",
"buttonTextSubmit",
"caretClosed",
"caretOpen",
"chips",
"color",
"controlSeparator",
"controlVariant",
"cursor",
"display",
"element",
"fill",
"fillDark",
"fillLight",
"flex",
"flexDirection",
"gap",
"gridColumns",
"height",
"hover",
"inactive",
"indent",
"justify",
"meter",
"padding",
"position",
"regionAnchor",
"regionBackdrop",
"regionBody",
"regionCaption",
"regionCaret",
"regionCell",
"regionChildren",
"regionChipList",
"regionChipWrapper",
"regionCone",
"regionContent",
"regionControl",
"regionDefault",
"regionDrawer",
"regionFoot",
"regionFootCell",
"regionFooter",
"regionHead",
"regionHeadCell",
"regionHeader",
"regionIcon",
"regionInput",
"regionInterface",
"regionInterfaceText",
"regionLabel",
"regionLead",
"regionLegend",
"regionList",
"regionListItem",
"regionNavigation",
"regionPage",
"regionPanel",
"regionRowHeadline",
"regionRowMain",
"regionSummary",
"regionSymbol",
"regionTab",
"regionTrail",
"ring",
"rounded",
"select",
"shadow",
"slotDefault",
"slotFooter",
"slotHeader",
"slotLead",
"slotMessage",
"slotMeta",
"slotPageContent",
"slotPageFooter",
"slotPageHeader",
"slotSidebarLeft",
"slotSidebarRight",
"slotTrail",
"spacing",
"text",
"track",
"transition",
"width",
"zIndex"
],
"explorer.fileNesting.enabled": false
}
"prettier.documentSelectors": ["**/*.svelte"],
"tailwindCSS.classAttributes": [
"class",
"accent",
"active",
"animIndeterminate",
"aspectRatio",
"background",
"badge",
"bgBackdrop",
"bgDark",
"bgDrawer",
"bgLight",
"blur",
"border",
"button",
"buttonAction",
"buttonBack",
"buttonClasses",
"buttonComplete",
"buttonDismiss",
"buttonNeutral",
"buttonNext",
"buttonPositive",
"buttonTextCancel",
"buttonTextConfirm",
"buttonTextFirst",
"buttonTextLast",
"buttonTextNext",
"buttonTextPrevious",
"buttonTextSubmit",
"caretClosed",
"caretOpen",
"chips",
"color",
"controlSeparator",
"controlVariant",
"cursor",
"display",
"element",
"fill",
"fillDark",
"fillLight",
"flex",
"flexDirection",
"gap",
"gridColumns",
"height",
"hover",
"inactive",
"indent",
"justify",
"meter",
"padding",
"position",
"regionAnchor",
"regionBackdrop",
"regionBody",
"regionCaption",
"regionCaret",
"regionCell",
"regionChildren",
"regionChipList",
"regionChipWrapper",
"regionCone",
"regionContent",
"regionControl",
"regionDefault",
"regionDrawer",
"regionFoot",
"regionFootCell",
"regionFooter",
"regionHead",
"regionHeadCell",
"regionHeader",
"regionIcon",
"regionInput",
"regionInterface",
"regionInterfaceText",
"regionLabel",
"regionLead",
"regionLegend",
"regionList",
"regionListItem",
"regionNavigation",
"regionPage",
"regionPanel",
"regionRowHeadline",
"regionRowMain",
"regionSummary",
"regionSymbol",
"regionTab",
"regionTrail",
"ring",
"rounded",
"select",
"shadow",
"slotDefault",
"slotFooter",
"slotHeader",
"slotLead",
"slotMessage",
"slotMeta",
"slotPageContent",
"slotPageFooter",
"slotPageHeader",
"slotSidebarLeft",
"slotSidebarRight",
"slotTrail",
"spacing",
"text",
"track",
"transition",
"width",
"zIndex"
],
"explorer.fileNesting.enabled": false,
"cSpell.words": [
"prejoin"
]
}

216
GEMINI.md Normal file
View File

@@ -0,0 +1,216 @@
# Aether (AE) SvelteKit Application
This project is a Svelte and SvelteKit based application, part of the Aether (AE) system. It uses Tailwind CSS and Skeleton for styling and some elements. This is the frontend UI/UX. The backend API uses Python FastAPI.
Core Aether modules
- accounts - client account, not user account
- hosted_files
- people
- users
- sites and site_domains
Additional Aether modules
- events
- presentation management - import the program data (events, session, presentations, presenters, event files, locations/rooms, devices)
- launcher - Technically this is used with presentation management. It is part of the native app that uses Electron. One of the libraries is for functions that only work when the site is opened in an Electron app. For example the regular browser can not move files around on the local computer or run local commands.
- badge printing
- lead retrieval - attendee tracking; QR codes
- journals - journal, documentation, notes, diary, blog, etc
- idaa - One of my clients
## Documentation
- TODO.md
- Svelte - Introducing runes - https://svelte.dev/blog/runes
- Svelte - Breaking changes in runes mode - https://svelte.dev/docs/svelte/v5-migration-guide#Breaking-changes-in-runes-mode
- Dexie.js - Getting Started - https://dexie.org/docs/Tutorial/Getting-started
- Dexie.js - API Quick Reference - https://dexie.org/docs/API-Reference#quick-reference
## Ignored Directories
The following directories are ignored for various operations (e.g., search, file listing) to focus on relevant source code:
- `build`
- `node_modules`
- `tests`
## Development Guidelines
### Svelte v5 and SvelteKit
This project uses Svelte v5 with runes enabled. This introduces significant differences from Svelte v4. It is critical to adhere to v5 conventions to avoid bugs.
- **Reactivity:** State is managed with `$state` and `$derived`. Props can be made two-way bindable with `$bindable`. Avoid direct mutation of props.
- **Event Handling (Updated 2025-11-20):**
- **DOM Events:** Use the lowercase `onevent` attribute (e.g., `onclick`, `oninput`). Event modifiers like `|preventDefault` may not work as expected; handle prevention logic inside the function (e.g., `event.preventDefault()`).
- **Component Events:** Continue to use the `on:eventname` directive for events dispatched from child components.
- **Stores and `liveQuery`:**
- To access the value of a store in Svelte v5, you must use the `$store_name` syntax (e.g., `$ae_api`).
- Dexie `liveQuery` returns an observable. To use it in a component, you must subscribe to it within `onMount` to avoid SSR errors. The value from the subscription should then be assigned to a `$state` variable.
- **Migration Guide:** For a comprehensive overview of the changes, refer to the official [Svelte 5 Migration Guide](https://svelte.dev/docs/svelte/v5-migration-guide).
### ID Convention: `id` vs. `id_random`
- **Always use `id_random`:** The API returns both a numeric `id` and a string-based `[obj_type]_id_random`. For all frontend operations (routing, data fetching, local storage), you **must** use the `_id_random` string.
- **Local Storage:** When saving an object to the local IndexedDB (Dexie), the `id_random` value should be aliased to both `id` (as the primary key) and `[obj_type]_id`. This ensures consistency with Dexie's expectations and the rest of the application's data access patterns.
---
## Refactoring Notes
### Data Fetching & Processing Pattern (2025-11-20)
A standard pattern for fetching, processing, and caching data has been established to ensure consistency and separation of concerns.
1. **API Function (`load_*`, `search_*`, etc.):** This function is responsible for interacting with the API. It takes parameters needed for the API call (e.g., `event_id`, search strings).
2. **Data Processor (`process_ae_obj__*_props`):** The API function's results are immediately passed to this dedicated processor function for the specific object type.
- The API function MUST pass any necessary contextual data (like a parent `event_id`) to the processor.
- The processor is responsible for all data shaping and enrichment before the data is cached.
3. **Handling API Inconsistencies:** The processor is the designated location for handling any inconsistencies in the data returned by the API.
- **Example (`event_badge`):** The `search__event_badge` API endpoint does not include the `event_id` in its results. The `process_ae_obj__event_badge_props` function now accepts the `event_id` as a parameter and injects it into each badge object before it's saved. This centralizes the fix and keeps the API-calling function clean.
4. **Database Caching (`db_save_ae_obj_li__ae_obj`):** After processing, the clean and consistent data is passed to the generic `db_save` function to be cached in IndexedDB.
This pattern isolates API logic from data shaping logic, making the code more modular, predictable, and easier to debug.
### `process_ae_obj__*_props()` Refactoring (2025-11-13)
The `process_ae_obj__*_props()` family of functions, which are responsible for transforming API data for frontend use, have been refactored to standardize their structure and improve maintainability.
The refactoring strategy involved creating a local, non-exported `_process_generic_props` helper function within each module (`ae_journals`, `ae_events`, `ae_archives`, `ae_posts`, `ae_core`). This approach was chosen to avoid altering the module import graph, which had previously caused a critical `InternalError: module record has unexpected status: New` in the SvelteKit development server when a shared utility file was introduced.
**Key aspects of the refactoring:**
- **In-file Generic Helper (`_process_generic_props`):** This function handles common data transformations:
- **`*_random` ID Aliasing:** It automatically iterates over object keys and creates a non-suffixed alias for any key ending in `_random` (e.g., `person_id_random` becomes `person_id`). This is crucial for client-side logic that expects standard ID fields.
- **`tmp_sort` Field Generation:** It creates a set of basic `tmp_sort` fields for client-side sorting.
- **`specific_processor` Callback:** Module-specific logic is handled by a `specific_processor` callback function passed to the `_process_generic_props` helper. This allows for:
- **Unique `tmp_sort` Logic:** Modules can override the default `tmp_sort` fields with their own specific sorting requirements.
- **Content Processing:** Asynchronous operations like Markdown parsing (using `marked.parse`) are handled within the `specific_processor` for the relevant modules (e.g., `ae_journals__journal_entry.ts`).
- **Other Special Cases:** Any other module-specific data transformations are handled in this callback.
- **`core__crud_generic.ts` Cleanup:** The generic CRUD functions in `src/lib/ae_core/core__crud_generic.ts` were simplified:
- The `process_ae_obj__props` function in this file was deprecated.
- All calls to `process_ae_obj__props` and `db_save_ae_obj_li__ae_obj` were removed from the generic CRUD functions (`load_ae_obj_id`, `load_ae_obj_li`, etc.).
- These functions are now responsible only for API interaction, delegating all data processing and caching to the module-specific functions that call them. This enforces a cleaner separation of concerns.
### Tiptap to CodeMirror Migration (2025-11-17)
The rich text editor component, previously based on Tiptap (`shad-editor`), has been replaced with a CodeMirror-based solution. This change was driven by the complexity of Tiptap and its compatibility issues with Tailwind CSS, aiming for a simpler, markdown-focused editing experience.
**Key aspects of the migration:**
- **Removal of Tiptap:** All `@tiptap/*` and `svelte-tiptap` dependencies were removed from `package.json`, and the `src/lib/components/shad-editor/` directory was deleted.
- **CodeMirror Integration:** A new CodeMirror component (`src/lib/elements/element_codemirror_editor.svelte`) was created, providing basic markdown formatting capabilities.
- **Wrapper Component Update:** The existing editor wrapper (`src/lib/elements/element_tiptap_editor.svelte`) was renamed to `src/lib/elements/element_codemirror_wrapper.svelte` and refactored to utilize the new CodeMirror component. Tiptap-specific logic and props were removed.
- **Component Usage Updates:** All Svelte components that previously imported and used the Tiptap wrapper were updated to import `element_codemirror_wrapper.svelte`. Unsupported props such as `default_minimal`, `show_button_kv`, `bind:new_html`, and `bind:changed` were removed from their usage.
- **Dependency Cleanup:** `npm install` was run to remove unneeded packages, and `npm run format` was executed to ensure consistent code style.
### CodeMirror Bug Fixes (2025-11-18)
Following the initial migration to CodeMirror, several issues were identified and resolved:
- **Initialization Errors:** An "Unrecognized extension value" error was fixed by refactoring `codemirror_modules.ts` to explicitly import individual CodeMirror extensions instead of relying on the `basicSetup` bundle. This ensures proper singleton usage and prevents module duplication.
- **Text Wrapping:** The `EditorView.lineWrapping` extension was added to `element_codemirror_editor.svelte` and `e_app_codemirror_v5.svelte` to enable text wrapping.
- **Content Saving:** Content binding issues were resolved in various IDAA components by correctly binding the `html_text` prop of the CodeMirror wrapper to the corresponding state variables.
- **Save Button Enablement:** The logic for enabling the "Save" button was fixed in `ae_idaa_comp__post_obj_id_edit.svelte` to correctly detect changes in the CodeMirror editor.
- **Editor Buttons:** A `TypeError` in the editor's formatting buttons was fixed by using `EditorSelection.range()` to correctly create selection ranges.
- **Component Renaming:** The `Tiptap_editor` component alias was renamed to `CodeMirror_wrapper` across the project for clarity, and the wrapper file was renamed to `element_codemirror_editor_wrapper.svelte`.
### Badge Search Refactoring (2025-11-18)
The new Badge Search functionality was refactored to resolve several issues related to Svelte 5 reactivity and IndexedDB schema design.
- **Svelte 5 Reactivity Fixes:**
- A `store_invalid_shape` error was fixed by removing the `$` prefix from Svelte 5 state variables in templates.
- A Svelte 5 compilation error (`illegal variable name`) was resolved by using `$derived` to create a local reactive variable from a store.
- A 500 Internal Error was resolved by moving Dexie `liveQuery` calls into an `onMount` block to ensure they only run on the client-side.
- **IndexedDB Schema Refactoring:**
- The primary key for the `badge` table was changed from a numeric `id` to the string-based `event_badge_id_random`.
- All related components were updated to use the new primary key for data retrieval, allowing for more efficient lookups using `get()` and `bulkGet()`.
- **Data Flow Simplification:**
- The badge search data flow was refactored to pass full badge objects from the search component to the list component, simplifying the logic and resolving reactivity issues.
- **Link Generation:**
- Badge links were updated to use the string-based random IDs for both the event and the badge, ensuring consistency and avoiding the exposure of internal numeric IDs.
### Event Settings Page (2025-11-18)
A new event settings page was created at `/events/[event_id]/settings` to provide a user-friendly interface for managing event configurations.
**Key features:**
- **Form-Based UI:** Instead of raw JSON editing, the page uses form-based components for editing event properties. This includes basic event fields (name, code, dates, etc.) and the JSON configuration fields (`cfg_json`, `mod_pres_mgmt_json`, `mod_badges_json`, `mod_abstracts_json`).
- **Collapsible Sections:** Each configuration section is wrapped in a `<details>` element, allowing them to be collapsed and expanded for better organization.
- **View Toggling:** For the JSON configuration fields, a toggle switch allows the user to switch between the form-based UI and a raw JSON editor (using CodeMirror), providing flexibility for both simple and advanced editing.
- **Svelte 5 Reactivity:** The components were built using Svelte 5's `bindable` props to ensure proper two-way data binding between the parent page and the child form components. This corrected an issue where changes in the child components were not being reflected in the parent's state.
### API Payload Cleaning (2025-11-19)
To address issues with the Aether API's strict handling of `POST` and `PATCH` request payloads, a more robust solution for cleaning data on the frontend has been implemented.
- **Svelte 5 Event Handlers:** Corrected the use of `on:click` to `onclick` in the event settings components to align with Svelte 5 conventions.
- **Payload Cleaning:**
- The `update_ae_obj__event` function in `src/lib/ae_events/ae_events__event.ts` was modified to remove read-only fields (`id`, `event_id`, `created_on`, `updated_on`, etc.) from the payload before sending it to the API.
- The function now also correctly renames `account_id` to `account_id_random` to match the API's expectations.
- **Editable Fields Whitelist:**
- A new file, `src/lib/ae_events/ae_events__event.editable_fields.ts`, was created to define a whitelist of fields that are allowed to be sent in `POST` and `PATCH` requests for an event.
- The `create_ae_obj__event` and `update_ae_obj__event` functions now use this whitelist to filter the `data_kv` object, ensuring only allowed fields are sent to the API. This provides a more maintainable and less error-prone way to manage which fields are sent to the API.
- **Component Cleanup:** The temporary pre-cleaning logic from the `handle_save` function in `src/routes/events/[event_id]/settings/+page.svelte` has been removed, as the filtering is now handled centrally in `ae_events__event.ts`.
- **Future Work:** This pattern of using a whitelist for editable fields will be applied to all other Aether object types to ensure consistent and correct API interactions across the application.
### Badge Search v3 Bug-Fixing Session (2025-11-19)
This session focused on resolving a series of cascading build and runtime errors that prevented the new "Badges v3" feature from loading and functioning correctly.
- **Initial State:** The page was failing with a `Cannot use <!-- Import failed: variant - ENOENT: no such file or directory, access '/home/scott/OSIT_dev/ae_app_svelte_tailwind_skeleton/variant' --> with unknown variant: md` error, caused by a conflict between Skeleton UI's CSS and the project's Tailwind CSS v4 configuration.
- **Misguided Fix & Reversal:** An initial attempt to fix this by removing all global Skeleton UI CSS imports from `app.css` resolved the `@variant` error but broke site-wide styling, causing errors like `Cannot apply unknown utility class 'preset-tonal-secondary'`. The Skeleton imports were subsequently restored to stabilize the application.
- **Svelte v5 Event Syntax:** A significant amount of time was spent incorrectly attempting to "fix" Svelte v5 event handlers. The correct understanding was eventually established:
- **DOM Events:** Use the `onevent` prefix (e.g., `onclick`).
- **Component Events:** Continue to use the `on:event` directive (e.g., `on:success`).
- **Invalid Attribute Name Error:** An error (`'onsubmit|preventDefault' is not a valid attribute name`) was discovered in the new badge forms. This was resolved by removing the `|preventDefault` modifier from the `onsubmit` attribute and instead calling `event.preventDefault()` inside the handler function. This appears to be a nuance or bug in how the Svelte v5 compiler handles modifiers with the new `on` prefix.
- **Svelte 5 Binding Error:** A runtime error, `props_invalid_value: Cannot do bind:prop={undefined}`, was fixed. It was caused by binding a parent component's `undefined` store value to a child component's prop that had a fallback. The fix involved adding a defensive initialization check directly in the parent component's `<script>` block to ensure the store value was not `undefined` before rendering. Using `onMount` was attempted first but proved incorrect as it runs too late in the lifecycle.
- **API Fetch Error:** The final blocker was a `TypeError: NetworkError` during badge searches. This was traced to the `order_by_li` parameter being sent to the API in a format that was causing the `fetch` request to be aborted by the browser (likely due to a CORS preflight failure). The immediate fix, identified by the user, was to comment out the `order_by_li` parameter in the `search__event_badge` function call within `src/lib/ae_events/ae_events__event_badge.ts`.
- **Git Issues:** A strange issue was encountered where `git add` commands were not successfully staging files, leading to multiple failed commit attempts. This resolved itself without a clear cause.
## UI Library Compatibility Re-evaluation (Current Focus - 2025-12-08)
**Context:** The project has been rolled back to a commit (`90ee6bb1`) where the application was "mostly working" with updated `skeletonlabs` packages. Previous attempts to update `tailwindcss` to v4 and `flowbite-svelte` alongside `skeletonlabs` led to dependency conflicts and build failures.
**New Strategy:** Instead of immediately abandoning existing UI libraries (Skeleton, Flowbite), we will re-evaluate their compatibility with the current Svelte v5 and Tailwind CSS v4 setup in a phased, cautious manner.
**Phase 1: Re-evaluate SkeletonLabs Compatibility (Primary Focus)**
**Rationale:** Skeleton UI appears to be the most deeply integrated UI library in the project. If it can be made to work, it will significantly reduce the need for custom component development.
1. **Create a new Git branch:** Name it `feature/re_evaluate_ui_libs`. (Pending)
2. **Identify latest compatible `@skeletonlabs/skeleton` and `skeleton-svelte` versions:**
* Consult their official documentation, release notes, and GitHub issues for compatibility with **Svelte v5** and **Tailwind CSS v4**.
* Determine if there's a specific version range that is known to work.
3. **Attempt to update SkeletonLabs packages (one at a time, or as a pair if tightly coupled):**
* Modify `package.json` to specify the identified compatible versions of `@skeletonlabs/skeleton` and `@skeletonlabs/skeleton-svelte`.
* Run `npm install`.
* Run `npm run build` and `npm run dev`.
* **Crucially:** Thoroughly check for *all* types of errors:
* Terminal errors (build, compilation, server-side).
* Browser console errors (client-side JS, hydration).
* Visual regressions or missing styles.
* **Document findings:** Note down exact errors or success status.
4. **If successful:** If SkeletonLabs works without major issues, proceed to Phase 2.
5. **If unsuccessful:** If significant conflicts or errors persist, revert changes on the branch and document the specific incompatibilities. This would then lead to immediately pursuing custom UI component implementation.
**Phase 2: Address Other UI Library Needs (Conditional, based on Phase 1 outcome)**
1. **If SkeletonLabs is working:**
* Re-evaluate the need for `flowbite-svelte`. Is its functionality still required, or is it covered by Skeleton UI or can be easily done with pure Tailwind?
* If still needed, attempt to update `flowbite-svelte` to the latest version, following the same cautious approach as with SkeletonLabs (package.json update, `npm install`, full testing).
2. **If SkeletonLabs (and/or Flowbite) cannot be made to work with Svelte v5 / Tailwind v4:**
* **Prioritize Custom Component Implementation:** Immediately proceed with implementing custom replacements, starting with critical components. The `element_modal_v1.svelte` (which was partially developed before the rollback) is a prime candidate for immediate completion and integration.
* **Identify other critical missing UI components:** Systematically list other essential components (e.g., dropdowns, tabs, accordions, cards, forms elements) that were previously provided by these libraries and prioritize their custom implementation using pure Tailwind CSS and native Svelte. Consider headless UI libraries (e.g., Headless UI, Radix UI) for complex components where accessibility and functionality are key without dictating styling.
## User Request Confirmation
- **Incompatibility of essential packages:** Confirmed. `flowbite-svelte` and `skeletonlabs/skeleton` were incompatible with Svelte v5 / Tailwind v4 in our previous attempts. We *will* safely double-check this as part of Phase 1 and 2.
- **CSS and missing style issues:** Confirmed. This was the direct consequence of removing the UI libraries.
- **`<Modal>` component replacement:** Confirmed. This was our immediate focus for custom replacement if existing libraries fail.

View File

@@ -0,0 +1,38 @@
# Flowbite-Svelte Upgrade Notes (December 2025)
## Overview
This document tracks the process of upgrading the Flowbite-Svelte UI library within the Aether SvelteKit project. The primary goal is to determine if a compatible version exists for Svelte 5 and Tailwind CSS v4, and to plan for its integration or replacement if necessary.
## Current Status (Pre-Upgrade)
- **Flowbite-Svelte Version:** v1.28.1 (as per `package.json` at commit `90ee6bb1`)
- **Target Version:** v1.30.0 (or newest compatible)
- **Initial Issue (Pre-Rollback):** Previous attempts to update `flowbite-svelte` (and other packages) indicated peer dependency conflicts. Earlier versions of `flowbite-svelte` (compatible with Tailwind v3) required Svelte v4, which conflicted with the project's Svelte v5.
- **Current Re-evaluation:** After rolling back to commit `90ee6bb1` and updating SkeletonLabs (which failed the build due to other reasons), `npm install` succeeded with `flowbite-svelte@1.28.1` present in `package.json`. This implies it *can install* alongside Svelte 5 and Tailwind 4. However, its runtime compatibility and rendering correctness with Svelte 5 (runes mode) and Tailwind CSS v4 remain untested.
- **Svelte Version:** Svelte 5 (runes mode)
- **Tailwind CSS Version:** v4.1.10
## Phase 1: Research and Planning (No Code Changes Yet)
### Goal
Determine if Flowbite-Svelte has a version that is explicitly compatible with Svelte 5 (runes mode) and Tailwind CSS v4, and to identify any breaking changes or migration paths.
### Steps
1. **Thoroughly Review Flowbite-Svelte Changelog:**
* **Link:** `https://github.com/themesberg/flowbite-svelte/blob/main/CHANGELOG.md`
* **Action:** Read the changelog for versions from `1.28.1` up to the latest stable release (e.g., `1.30.0` or newer).
* **Goal:** Look for specific mentions of Svelte 5 support, "runes mode" compatibility, or compatibility with Tailwind CSS v4. Note any breaking changes or migration instructions related to Svelte version or component API changes.
### Expected Outcome of Phase 1
A clear understanding of Flowbite-Svelte's compatibility with our current stack. This will inform the decision on whether to attempt an upgrade or if abandoning it (and creating custom replacements) is necessary. The expectation is that if a version is compatible, any breaking changes to component APIs (like renaming `Modal` to `Dialog`) will be identified.
## Phase 2: Execution (After Approval)
### Steps (To be detailed after Phase 1)
1. **If a compatible version exists:**
* Update `package.json` to the compatible version.
* Run `npm install`.
* Run `npm run build` and `npm run dev` and thoroughly check for errors and visual regressions.
* Apply any necessary code changes based on identified breaking changes (e.g., component name changes like `Modal` to `Dialog`).
2. **If no compatible version exists or issues persist:**
* **Decision:** Abandon Flowbite-Svelte.
* **Action:** Systematically replace its components with custom-built Svelte/Tailwind components, starting with critical ones like `Modal` (using our `element_modal_v1.svelte` if not using Skeleton's `Dialog`).

View File

@@ -0,0 +1,48 @@
# SkeletonLabs Upgrade Notes (December 2025)
## Overview
This document tracks the process of upgrading the SkeletonLabs UI library (from v3 to v4.7.4) within the Aether SvelteKit project. The primary goal is to resolve build issues caused by incompatibility with Svelte 5 and Tailwind CSS v4, and to integrate the updated library correctly.
## Current Status (Pre-Upgrade)
- **SkeletonLabs Version:** v3.2.2 (as per `package.json` at commit `90ee6bb1`)
- **Target Version:** v4.7.4
- **Issue:** Previous attempts to upgrade SkeletonLabs to v4.7.4 resulted in a persistent, blocking build error: `[@tailwindcss/vite:generate:build] Cannot use `@variant` with unknown variant: md` originating from `node_modules/@skeletonlabs/skeleton/src/index.css`. This indicates a fundamental incompatibility in how Tailwind CSS v4 processes SkeletonLabs' pre-compiled CSS.
- **Svelte Version:** Svelte 5 (runes mode)
- **Tailwind CSS Version:** v4.1.10
## Phase 1: Research and Planning (No Code Changes Yet)
### Goal
Understand the required migration steps from Skeleton v3 to v4 as per official documentation, specifically to address the `@variant` build error and ensure compatibility with Svelte 5 and Tailwind CSS v4.
### Steps
1. **Thoroughly Review Skeleton v3 to v4 Migration Guide:**
* **Link:** `https://www.skeleton.dev/docs/svelte/get-started/migrate-from-v3`
* **Action:** Read the guide carefully to identify all breaking changes related to:
* Tailwind CSS plugin setup in `tailwind.config.ts`.
* Required changes to `app.css` or any other global CSS files.
* Changes in component class names, especially theme-related classes (`preset-*`, `variant-*`, etc.), which could be related to the `@variant` error.
* The new `Dialog` component and how it replaces any previous modal-like components.
* **Deliverable:** Summarize the required code changes based on this guide.
2. **Review Skeleton v4.0 Launch Discussion:**
* **Link:** `https://github.com/skeletonlabs/skeleton/discussions/3920`
* **Action:** Look for community insights, common issues, and suggested solutions related to upgrading.
3. **Review Skeleton Dialog Documentation:**
* **Link:** `https://www.skeleton.dev/docs/svelte/framework-components/dialog`
* **Action:** Understand the API and usage of Skeleton's native dialog component, as this will be the preferred replacement for any missing `<Modal>` components.
### Expected Outcome of Phase 1
A detailed, step-by-step plan for migrating SkeletonLabs from v3 to v4, specifically targeting the resolution of the `@variant` build error and outlining the new usage of its UI components. This plan will be presented for approval before any code changes are made.
## Phase 2: Execution (After Approval)
### Steps (To be detailed after Phase 1)
1. **Update `package.json`:** Set `@skeletonlabs/skeleton` and `@skeletonlabs/skeleton-svelte` to `4.7.4`.
2. **Adjust `tailwind.config.ts`:** Apply changes as per migration guide (e.g., plugin configuration).
3. **Adjust `src/app.css`:** Apply changes as per migration guide (e.g., CSS imports, custom theme definitions).
4. **Run `npm install`**.
5. **Run `npm run build` and `npm run dev`** to verify the build and functionality.
6. **Replace `Modal` components:** Update existing components that used an older `<Modal>` (e.g., from `flowbite-svelte` or previous custom efforts) with Skeleton's new `Dialog` component.
7. **Address Svelte 5 reactivity warnings:** Fix any warnings related to data handling or non-reactive updates.

71
GEMINI_debug_notes.md Normal file
View File

@@ -0,0 +1,71 @@
# Skeleton/Tailwind Build Debugging Log
This file tracks the troubleshooting steps taken to resolve the build and dev server errors after updating packages.
## Initial State (Pre-Rollback to 90ee6bb1)
- **Packages Updated:** Attempted to update `@skeletonlabs/skeleton` to `4.7.4`, `tailwindcss` to `4.1.10`, and `flowbite-svelte` (version not explicitly stated in previous logs but was part of the update attempts).
- **`dev` Error:** `Cannot apply unknown utility class 'preset-tonal-secondary'`
- **`build` Error:** `Cannot use @variant with unknown variant: md`
- **Dependency Conflicts:** Persistent `ERESOLVE` errors, primarily due to:
- `flowbite-svelte` versions compatible with Tailwind v3 requiring `svelte@^4.0.0` (while project is Svelte v5).
- `@skeletonlabs/skeleton` versions requiring `tailwindcss@^4.0.0` (while attempting to use Tailwind v3 for `flowbite-svelte` compatibility).
- **Conclusion:** A fundamental incompatibility between Svelte v5, Tailwind v4, and the existing versions of UI component libraries (Skeleton, Flowbite-Svelte) when trying to achieve a stable `npm install`.
## Troubleshooting Steps (Pre-Rollback)
(Summarized from previous extensive debugging logs)
- Multiple attempts to downgrade/upgrade Tailwind, Skeleton, and Flowbite-Svelte led to a "dependency nightmare."
- Identified that Flowbite-Svelte was the primary blocker for maintaining Svelte v5 compatibility while also using an older Tailwind.
- Attempted a strategy to remove *all* pre-built UI component libraries (Skeleton, Flowbite-Svelte) to achieve a clean Svelte v5 + Tailwind v4 base. This led to:
- `ReferenceError: Modal is not defined` due to the removal of the underlying `Modal` component.
- `</form>` syntax error due to incorrect commenting out of the `<Modal>` component's block.
- Server-side `500 Internal Error` (diagnosis interrupted by rollback decision).
## Current State (Post-Rollback to 90ee6bb1)
- **Commit:** `90ee6bb1 - All packages have now been updated. This includes the skeletonlabs packages. Everything seems to be working. (Except for some unrelated known bugs. Why did the badge search stop working (AGAIN)?)`
- **Status:** Application is confirmed to be "mostly working" at this commit. This provides a stable baseline.
- **Key Observation from Commit Message:** "All packages have now been updated. This includes the skeletonlabs packages. Everything seems to be working." This implies that at this point, the `skeletonlabs` packages *were* working with some configuration of Svelte and Tailwind.
## Revised Path Forward: Re-evaluate UI Library Compatibility
**Context:** The previous issues stemmed from an inability to reconcile `skeletonlabs/skeleton` (requiring Tailwind v4), `flowbite-svelte` (preferring Svelte v4 for Tailwind v3 compatibility), and the project's Svelte v5 base. Before attempting to re-implement all UI components from scratch, we will re-evaluate if the latest versions of these libraries have resolved their internal conflicts or if a stable configuration now exists.
**Phase 1: Re-evaluate SkeletonLabs Compatibility (Primary Focus)**
**Rationale:** Skeleton UI appears to be the most deeply integrated UI library in the project. If it can be made to work, it will significantly reduce the need for custom component development.
1. **Update `GEMINI.md` and related notes:** (Completed in this step) Document this new strategy and the decision to re-evaluate packages.
2. **Create a new Git branch:** Name it `feature/re_evaluate_ui_libs`. (Pending)
3. **Identify latest compatible `@skeletonlabs/skeleton` and `skeleton-svelte` versions:**
* Consult their official documentation, release notes, and GitHub issues for compatibility with **Svelte v5** and **Tailwind CSS v4**.
* Determine if there's a specific version range that is known to work.
4. **Attempt to update SkeletonLabs packages (one at a time, or as a pair if tightly coupled):**
* Modify `package.json` to specify the identified compatible versions of `@skeletonlabs/skeleton` and `@skeletonlabs/skeleton-svelte`.
* Run `npm install`.
* Run `npm run build` and `npm run dev`.
* **Crucially:** Thoroughly check for *all* types of errors:
* Terminal errors (build, compilation, server-side).
* Browser console errors (client-side JS, hydration).
* Visual regressions or missing styles.
* **Document findings:** Note down exact errors or success status.
5. **If successful:** If SkeletonLabs works without major issues, proceed to Phase 2.
6. **If unsuccessful:** If significant conflicts or errors persist, revert changes on the branch and document the specific incompatibilities. This would then lead to immediately pursuing custom UI component implementation.
**Phase 2: Address Other UI Library Needs (Conditional, based on Phase 1 outcome)**
1. **If SkeletonLabs is working:**
* Re-evaluate the need for `flowbite-svelte`. Is its functionality still required, or is it covered by Skeleton UI or can be easily done with pure Tailwind?
* If still needed, attempt to update `flowbite-svelte` to the latest version, following the same cautious approach as with SkeletonLabs (package.json update, `npm install`, full testing).
2. **If SkeletonLabs (and/or Flowbite) cannot be made to work with Svelte v5 / Tailwind v4:**
* **Prioritize Custom Component Implementation:** Immediately proceed with implementing custom replacements, starting with critical components. The `element_modal_v1.svelte` (which was partially developed before the rollback) is a prime candidate for immediate completion and integration.
* **Identify other critical missing UI components:** Systematically list other essential components (e.g., dropdowns, tabs, accordions, cards, forms elements) that were previously provided by these libraries and prioritize their custom implementation using pure Tailwind CSS and native Svelte. Consider headless UI libraries (e.g., Headless UI, Radix UI) for complex components where accessibility and functionality are key without dictating styling.
## User Request Confirmation
- **Incompatibility of essential packages:** Confirmed. `flowbite-svelte` and `skeletonlabs/skeleton` were incompatible with Svelte v5 / Tailwind v4 in our previous attempts. We *will* safely double-check this as part of Phase 1 and 2.
- **CSS and missing style issues:** Confirmed. This was the direct consequence of removing the UI libraries.
- **`<Modal>` component replacement:** Confirmed. This was our immediate focus for custom replacement.
**The immediate next steps are to update my internal `GEMINI.md` for this project with this new plan and create the `feature/re_evaluate_ui_libs` branch.**

View File

@@ -2,38 +2,53 @@
This uses SvelteKit version 2.x with Svelte version 5.x, TailwindCSS 4.1, and Skelton.
# Current Modules
## AE Events - Speakers (/events_speakers)
### Components
* +page.svelte - The main page for the Events - Speakers module
* 10_edit_modal__event_presenter_obj.svelte - The modal for editing a presenter
* 10_list__event_presenter_obj.svelte - The list of presenters/speakers
* 10_view_modal__event_presenter_obj.svelte - The modal for viewing a presenter
- +page.svelte - The main page for the Events - Speakers module
- 10_edit_modal\_\_event_presenter_obj.svelte - The modal for editing a presenter
- 10_list\_\_event_presenter_obj.svelte - The list of presenters/speakers
- 10_view_modal\_\_event_presenter_obj.svelte - The modal for viewing a presenter
### Path [slug]
* +page.svelte - The main page for the presenter ID [slug]
- +page.svelte - The main page for the presenter ID [slug]
## AE Sponsorships (/sponsorships)
* +page.svelte - The main page for the Sponsorships module
* 10_edit_modal__sponsorship_obj.svelte - The modal for editing a sponsorship
* 10_list__sponsorship_obj.svelte - The list of sponsorships
* 10_view_modal__sponsorship_obj.svelte - The modal for viewing a sponsorship
- +page.svelte - The main page for the Sponsorships module
- 10_edit_modal\_\_sponsorship_obj.svelte - The modal for editing a sponsorship
- 10_list\_\_sponsorship_obj.svelte - The list of sponsorships
- 10_view_modal\_\_sponsorship_obj.svelte - The modal for viewing a sponsorship
### Path [slug]
* +page.svelte - The main page for the sponsorship ID [slug]
# Future Modules
## AE Events - Badges (/events_badges)
* +page.svelte - The main page for the Events - Badges module
* 10_list__event_badge_obj.svelte - The list of badges
* 10_view_modal__event_badge_obj.svelte - The modal for viewing a badge
- +page.svelte - The main page for the sponsorship ID [slug]
## AE Events - Exhibit Leads (/events_exhibit_leads)
### Components
- +page.svelte - The main page for the Events - Exhibit Leads module
- 10_list\_\_event_exhibit_lead_obj.svelte - The list of exhibit leads
- 10_edit_modal\_\_event_exhibit_lead_obj.svelte - The modal for editing an exhibit lead
- 10_view_modal\_\_event_exhibit_lead_obj.svelte - The modal for viewing an exhibit lead
# Future Modules
## AE Events - Badges (/events_badges)
- +page.svelte - The main page for the Events - Badges module
- 10_list\_\_event_badge_obj.svelte - The list of badges
- 10_view_modal\_\_event_badge_obj.svelte - The modal for viewing a badge
## AE Events - Presentation Management (/events_pres_mgmt)
# How to build and deploy SvelteKit:
Copy the contents of the "build" directory to ./npm_deploy/build/
```bash
@@ -41,6 +56,7 @@ npm run build
```
If this is just a quick build update then only the build directory needs to be copied (rsync).
```bash
rsync -vhrz --exclude 'node_modules' ~/OSIT_dev/ae_app_svelte_tailwind_skeleton/build/ ~/OSIT_dev/ae_env_node_app/npm_deploy/build/ --delete
@@ -50,6 +66,7 @@ rsync -vhrz ~/OSIT_dev/ae_env_node_app/npm_deploy/build/ scott@linode.oneskyit.c
If this includes package updates (not development) we need to copy the new package.json. Manually copy the new package.json file to ./npm_deploy/. This also needs to be copied to the server. Copy the package.json even though not really used.
Run the --omit dev to clear out the node_modules directory. Copy the root node_modules directory to ./npm_deploy/build/node_modules/ after running te omit dev command.
```bash
npm ci --omit dev
@@ -63,10 +80,10 @@ npm install
Everything should be ready to run on the development server and production server.
# Rebuild the node_modules directory and manually install extra Svelte packages
Run the npm update to fix the node_modules directory and package.json
```bash
npm list
npm outdated
@@ -77,6 +94,7 @@ npm list
Other installs?:
Are both still needed? I know at least one of these is. 2024-07-23
```bash
npm install --save-dev svelte-highlight
npm install --save-dev typescript-svelte-plugin
@@ -96,13 +114,15 @@ npm install flowbite flowbite-svelte tailwind-merge @popperjs/core
I am slowly switching from Font-Awesome to Lucide
## Tiptap Editor
* Eventually use Edra? https://edra.tsuzat.com/
* Best Rich Text Editor, made for Svelte Developers with Tiptap
* ShadEditor is "evolving" to be Edra.
* ShadCN is still stuck on Tailwind 3. Waiting to upgrade to Tailwind 4.x. Tailwind 4.x was released in late January 2025. ShadCN is still being worked on as of late March 2025.
* [https://github.com/huntabyte/shadcn-svelte/issues/1643](https://github.com/huntabyte/shadcn-svelte/issues/1643)
- Eventually use Edra? https://edra.tsuzat.com/
- Best Rich Text Editor, made for Svelte Developers with Tiptap
- ShadEditor is "evolving" to be Edra.
- ShadCN is still stuck on Tailwind 3. Waiting to upgrade to Tailwind 4.x. Tailwind 4.x was released in late January 2025. ShadCN is still being worked on as of late March 2025.
- [https://github.com/huntabyte/shadcn-svelte/issues/1643](https://github.com/huntabyte/shadcn-svelte/issues/1643)
Need to install ShadCN and Lucide for the Tiptap editor.
```bash
npm install shadcn-svelte
npm install lucide-svelte
@@ -110,6 +130,7 @@ npm install mode-watcher
```
Now we initialize the ShadCN and ShadEditor packages. Follow the command line instructions.
```bash
npx shadcn-svelte@next init
npx shadcn-svelte@next add dropdown-menu button tooltip input popover separator
@@ -117,6 +138,7 @@ npx shadeditor init
```
More packages related to the Tiptap editor???
```bash
npm install @tiptap/extension-link @tiptap/extension-bullet-list @tiptap/extension-history @tiptap/extension-typography @tiptap/extension-underline
```
@@ -124,23 +146,31 @@ npm install @tiptap/extension-link @tiptap/extension-bullet-list @tiptap/extensi
## Build
## Environment file
### ".env"
This is the default used if others are not found when when "npm run dev" or "npm run build" is run.
### ".env.local"
This is used when "npm run dev" is run. This is not used in the production build.
### ".env.production"
This is used when "npm run build" is run. This is not used in the development build.
### ".env:prod"
This is modified to allow for a staging environment and production environment built.
### ".env:staging"
This is modified to allow for a staging environment and production environment built.
### Example Important Values when running in dev:
Note: Environment values need to be updated when our home IP address changes. Be sure to check the Aether Container Environment and Aether Node App (SvelteKit) Environment files for the correct IP address. The Node Docker environment needs to be updated here and in the .env file that Docker will read. This needs to be improved later...
```bash
DOCKER_AE_API_DEV_SERVER_EXTRA_HOST=dev-api.oneskyit.com:108.48.200.147
@@ -150,7 +180,6 @@ PUBLIC_AE_API_SERVER=api.oneskyit.com
PUBLIC_AE_API_BAK_SERVER=bak-api.oneskyit.com
```
# create-svelte
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).

379
TODO.md Normal file
View File

@@ -0,0 +1,379 @@
# One Sky IT's Aether UI/UX Project TODO
This is a list of tasks to be completed before the next event/show/conference.
---
## Recent Accomplishments
- [x] **Badges v3:** Resolved a series of cascading build and runtime errors on the new badge search page. This involved restoring Skeleton CSS, fixing Svelte 5 event handler syntax (`onsubmit|preventDefault`), resolving a prop binding error (`props_invalid_value`), and temporarily disabling a problematic `order_by_li` API parameter to fix a network fetch error.
- [x] **Refactoring:** Standardized data processing in `events`, `archives`, `posts`, and `sponsorships` modules using a new generic pattern.
- [x] **Bug Fix:** Corrected data fetching logic for session-related presentations and files that were not displaying correctly due to `id` vs `id_random` issues.
- [x] **Core:** Defined `Account`, `Site`, and `Site_Domain` interfaces in new files under `src/lib/ae_core/`.
- [x] **Journals:** Improve the empty state message in `src/routes/journals/+page.svelte`.
- [x] **Journals:** Add a loading indicator to the main journals page.
- [x] **IDAA:** Add a loading indicator to the archives page (`src/routes/idaa/(idaa)/archives/+page.svelte`).
- [x] **Events:** Add pagination to the main event list in `src/routes/events/+page.svelte`.
---
## Big Picture Goals
- Everything needs to work with Svelte 5.x and SvelteKit 2.x.
- Able to cache data and mostly work offline.
- The new Events Launcher must be able to work offline and query the API for changes to data.
- The new Events Launcher must be able to run inside an Electron app and have access to local files and OS shell commands and applications. This includes loading a special library that only works in Electron.
---
## Codebase Standardization
### 1. Naming Conventions
- [ ] **Goal:** Enforce a single, consistent naming standard across the entire codebase.
- [ ] **Files:**
- Logic: `ae_<module>__<concept>.ts`
- DB Definitions: `db_<module>.ts`
- Svelte Stores: `ae_<module>_stores.ts`
- Consolidate helper files (e.g., `ae_core_functions.ts`) into the above files.
- [ ] **Functions & Variables:**
- [x] Enforce `snake_case` for all function and variable names.
- [x] Deprecate and remove `camelCase`.
- [x] Deprecate and refactor ambiguous `handle_` prefixes.
- [ ] **Object & Property Naming:**
- Use singular nouns for objects and properties (e.g., `example.id`, not `examples.id`).
- [ ] **List Suffixes:**
- Use `_li` for simple, unordered arrays.
- Use `_kv` for key-value objects/maps.
- [ ] **Process:**
- Refactor one module at a time to ensure internal consistency before moving to the next. Start with `ae_core`.
- **Update 2025-11-13:** `ae_core_functions.ts` has been temporarily restored to resolve a critical issue. The refactoring of `process_ae_obj__*_props()` functions will now proceed module by module, ensuring stability at each step.
### 2. Component Standardization
- [x] **CodeMirror Migration:** Replaced all instances of the old Tiptap editor with a new CodeMirror wrapper. This includes fixing initialization errors, enabling text wrapping, and ensuring content is correctly saved.
- [ ] **Component Review:** Audit third-party components to understand their conventions and isolate them from internal standards.
### 3. Aether Object Field Definitions
- [ ] **Goal:** Create a common way to define which fields can be sent in when creating or updating a record for all Aether objects.
- [ ] **Process:**
- For each Aether object type, create a `ae_<module>__<object>.editable_fields.ts` file that exports a whitelist of editable fields.
- Modify the `create` and `update` functions for each object type to use this whitelist to filter the data before sending it to the API.
- Start with the `event` object type as a proof of concept. (DONE)
- Apply this pattern to all other Aether object types.
---
## Priority Tasks (Easy & Quick)
- [ ] **API:** Properly investigate and fix the `order_by_li` parameter in the `search__event_badge` function. The parameter is currently commented out as a temporary workaround to prevent a network fetch error.
- [ ] **Formatting:** Run `npm run format` to fix code style issues across the project.
---
## Critical Functions for Review
These functions are frequently used and critical to the application's data flow. Reviewing and cleaning them up will significantly improve the codebase.
1. **`get_ae_obj_li_for_obj_id_crud_v2()`** (from `src/lib/ae_api/api_get__crud_obj_li_v2.ts`)
- **Why:** This is the main function for fetching lists of data from the backend, used extensively across all modules.
- **Cleanup:** Review parameters and return types for consistency, improve error handling, and add more detailed logging for debugging.
2. **`db_save_ae_obj_li__ae_obj()`** (from `src/lib/ae_core/core__idb_dexie.ts`)
- **Why:** This function is the single point of entry for saving data to the local Dexie database, critical for performance and reliability.
- **Cleanup:** Optimize for bulk operations, add robust error handling and logging, and ensure correct handling of updates to existing objects.
3. **The `process_ae_obj__*_props()` family of functions** (e.g., `process_ae_obj__journal_props()` from `src/lib/ae_journals/ae_journals__journal.ts`)
- **Why:** These functions transform API data for the frontend and are a common source of bugs and inconsistencies.
- **Cleanup:** Standardize their structure across all modules, ensure they are pure functions, and add unit tests for correctness.
- **Update 2025-11-13 (Temporary Rollback):** The previous refactoring of these functions has been temporarily rolled back due to an `InternalError`. `ae_core_functions.ts` has been restored. The new plan is to refactor these functions module by module, ensuring stability at each step. The generic CRUD functions in `core__crud_generic.ts` were simplified to remove data processing and caching, delegating those responsibilities to the module-specific functions. The deprecated `process_ae_obj__props` function in that file was left in place but is no longer used by the generic CRUD functions.
- **Update 2025-11-20 (Successful Refactor):** The `event_badge` module has been successfully refactored to use the new "API Function -> Processor -> DB Save" pattern. The `process_ae_obj__event_badge_props` function now handles inconsistencies in the API search results (i.e., a missing `event_id`) by accepting the `event_id` as a parameter and injecting it. This serves as a successful proof-of-concept for this architectural pattern.
4. **Usage of `liveQuery` from Dexie**
- **Why:** `liveQuery` is powerful for reactive UIs, but current usage suggests complexity and potential issues.
- **Cleanup:** Review `liveQuery` usage throughout the application, simplify queries, and investigate reactivity issues. Consider wrapping `liveQuery` in a custom Svelte store for a more predictable interface.
---
- [x] Improve the `e_app_codemirror_v5.svelte` component and plan the migration from Tiptap to CodeMirror for rich text editing. The migration is complete, and the component has been improved to handle individual extensions and fix various bugs.
---
## Core Module Improvements
### 1. Core Module Dashboard
- [ ] Create a central dashboard at `/core` to provide an overview and links to all core data management pages.
### 2. Account Management
- [ ] **Route:** Create a new route at `/core/accounts`.
- [ ] **Data:** Define the `Account` interface in a new file `src/lib/ae_core/core__account.ts`.
- [ ] **API:** Implement functions in `core__account.ts` for CRUD operations on accounts.
- [ ] **UI:**
- [ ] Create a `+page.svelte` to list all accounts.
- [ ] Create a `[account_id]` dynamic route to view and edit account details.
### 3. Site & Domain Management
- [ ] **Route:** Create a new route at `/core/sites`.
- [ ] **Data:** Define `Site` and `Site_Domain` interfaces in a new file `src/lib/ae_core/core__site.ts`.
- [ ] **API:** Implement functions in `core__site.ts` for CRUD operations on sites and domains.
- [ ] **UI:**
- [ ] Create a `+page.svelte` to list all sites.
- [ ] Create a `[site_id]` dynamic route to view and edit site details and manage associated domains.
### 4. Person Management
- [ ] **Enhance:** Improve the existing person management components under `/core/person`.
- [ ] **UI:**
- [ ] Create a dedicated page for creating new person records.
- [ ] Add search and filtering capabilities to the person list.
### 5. User Management
- [ ] **Route:** Create a new route at `/core/users`.
- [ ] **UI:**
- [ ] Create a `+page.svelte` to list all users.
- [ ] Create a `[user_id]` dynamic route to view and edit user details, including permissions.
- [ ] Implement a component to link users to person records.
### 6. Hosted File Management
- [ ] **Route:** Create a new route at `/core/hosted_files`.
- [ ] **UI:**
- [ ] Create a `+page.svelte` to list all hosted files with filters (e.g., by file type, uploader).
- [ ] Implement a file viewer for common file types.
- [ ] Add functionality to upload new files and associate them with other objects (e.g., a person, a journal entry).
### 7. Shared Lookup Lists
- [ ] **Route:** Create a new route at `/core/lookups`.
- [ ] **UI:**
- [ ] Create a simple UI to view and manage the shared lookup lists (e.g., `countries`, `time_zones`).
---
## Journals Module Improvements
### Code Cleanup & Refactoring
- [ ] **Consolidate Data Functions:** Refactor `ae_journals__journal.ts` and `ae_journals__journal_entry.ts` to reduce code duplication, especially in data loading and processing functions.
- [ ] **Remove Dead Code:** Clean up commented-out code blocks and unused variables across the module.
- [ ] **Logging:** Implement a more structured logging solution to replace the widespread use of `console.log`.
- [ ] **Promise Handling:** Standardize promise handling to use `async/await` consistently and remove mixed `.then()` and `async/await` syntax.
- [ ] **Type Safety:** Replace `any` types with more specific interfaces, particularly in function parameters and API responses.
### Features & Enhancements
- [ ] **Offline Support:** Improve offline capabilities by pre-fetching and caching more data. Review the current Dexie implementation for optimizations.
- [ ] **Search & Filtering:** Enhance the UI with more advanced search and filtering options for journals and entries (e.g., by date range, content, tags).
- [ ] **User Experience (UX):**
- Implement better loading indicators and skeleton loaders.
- Provide clearer empty state messages (e.g., "No journals found, create one!").
- Improve error handling and provide more informative error messages to the user.
- [ ] **Encryption:** Review and enhance the encryption implementation for journal entries to ensure it is secure and user-friendly.
- [ ] **Templates:** Fully implement and document the "templates" feature for creating new journals and entries.
### Bug Fixes & Potential Issues
- [ ] **Reactivity:** Investigate potential reactivity issues between Svelte stores and Dexie's `liveQuery`.
- [ ] **Data Sync:** Add logic to handle data synchronization conflicts between the local database and the server.
- [ ] **Performance:** Profile the application with a large number of journals and entries to identify and address any performance bottlenecks.
---
## IDAA Modules Improvements
### General
- [ ] **Component Refactoring:** Audit the `ae_idaa_comp__` components and refactor them to be more generic and reusable where possible.
- [ ] **State Management:** Simplify state management by reducing the number of stores and triggers, and relying more on derived state and component props.
### Archives Module (`/idaa/archives`)
- [ ] **UI/UX:**
- [ ] Add a loading indicator while archives are being fetched.
- [ ] Implement a more engaging "empty state" when no archives are available.
- [ ] **Performance:**
- [ ] Implement pagination or infinite scrolling for the archive list.
### Bulletin Board Module (`/idaa/bb`)
- [ ] **UI/UX:**
- [ ] Improve the UI for creating and editing posts and comments.
- [x] Add a rich text editor for a better writing experience.
- [ ] **Features:**
- [ ] Implement user-specific features, such as editing their own posts and comments.
### Recovery Meetings Module (`/idaa/recovery_meetings`)
- [ ] **Refactoring:**
- [ ] Simplify the search and filtering logic. The current implementation with `setInterval` is complex and could be replaced with a more modern approach using debouncing or reactive statements.
- [ ] **UI/UX:**
- [ ] Make the search and filtering interface more intuitive and responsive.
- [ ] Provide instant feedback to the user as they type in the search box.
- [ ] **Performance:**
- [ ] Optimize the search query to be faster and more efficient.
---
## Aether Events Module Improvements
### General
- [ ] **Dashboard:** Create a central dashboard for each event at `/events/[event_id]` that provides an overview of the event and links to all the management pages.
- [ ] **Component Refactoring:** The module has a large number of `ae_comp__` components. Audit and refactor them to be more modular and reusable.
- [ ] **UI/UX Consistency:** Ensure a consistent look and feel across all the different event management pages.
### Core Event Management
- [ ] **Event List (`/events`):**
- [ ] Add search and filtering capabilities to the main event list.
- [ ] Implement pagination for the event list.
- [ ] **Event Creation/Editing:**
- [ ] Create a dedicated page or modal for creating and editing events.
### Sub-modules (`/events/[event_id]/...`)
- [ ] **Sessions, Presentations, Presenters, etc.:**
- [ ] For each sub-module (sessions, presentations, etc.), implement a consistent set of features:
- [ ] List view with search and filtering.
- [ ] Detail view.
- [ ] Create and edit forms.
- [ ] Delete functionality with confirmation.
- [ ] **File Management:**
- [ ] Improve the file upload component (`ae_comp__event_files_upload.svelte`) with features like drag-and-drop and progress bars.
- [ ] Enhance the file list view with more details and actions.
- [ ] \*\*Launcher (`/events/[event_id]/launcher`):
- [ ] Add documentation to explain the purpose and usage of the launcher.
- [ ] Improve the UI to make it more intuitive for users.
- [ ] \*\*Badges (`/events/[event_id]/badges`):
- [ ] Enhance the badge printing interface with more customization options.
- [ ] Add a preview of the badge before printing.
### Performance
- [ ] **Live Queries:** Review the use of `liveQuery` throughout the module and optimize for performance, especially on pages with a large amount of data.
- [ ] **Data Loading:** Implement more efficient data loading strategies to avoid fetching unnecessary data.
---
## UI/UX Consistency
- [ ] **Broad UI/UX Review:** Conduct a comprehensive review of UI elements across the application to ensure consistency. This includes, but is not limited to:
- Buttons (style, placement, wording)
- Lists (style, actions)
- Links vs. Buttons (correct semantic usage)
- Menus (style, options)
- Debug components and other developer-facing UI.
- **Wording:** Standardize the text used in common UI elements (e.g., "Save", "Cancel", "Delete", "Add New").
- **Scope:** This should be done on a per-module basis to ensure local consistency, with a goal of achieving global consistency where possible.
- **Note on IDAA:** The `idaa` modules are semi-custom for a client and may have their own specific UI/UX requirements. Their consistency should be evaluated separately, keeping the client's needs in mind.
- [ ] **Component Migration:** Replace remaining Skeleton UI classes (e.g., `preset-tonal-*`, `variant-filled-*`) with standard Tailwind CSS to avoid CSS conflicts and dependency issues.
---
## Scott's Quick Notes
These are just quick notes, thoughts, ideas, and reminders for myself.
- I need to explain the purpose and thought behind the data_store element or component and how it works. The short version: It is a hierarchy of database results, but only the last result is returned. The results are filtered by data store key/code, then by account_id, and then by for_type and for_id. This allows for shared data among accounts, but also account specific overrides. Finally, it allows for object specific overrides.
- Use old Events Leads module as reference for new one
- Use old Events Badges module as reference for new one
- Use old Events Launcher module as reference for new one
- The Launcher will need some work to make it work offline and in Electron
- Events Leads: mobile first, but still works on desktop
- Need to be able to enable and disable modules per event (e.g., some events may not need Leads or Badges)
- In theory session codes should be unique per event. This depends somewhat on the client's data and needs.
- The codes for locations/rooms should also be unique per event.
- The codes for devices should also be unique per event.
- Reports are manually created and shared among events and clients. We need to be able to enable/disable reports per event. Each report will have its own Svelte page.
### Events modules and main landing pages
- **Presentation Management**
- Manage
- Session Search
- View Session
- View Presenter
- Locations List
- View Location
- Devices List
- View Device
- Reports
- **Launcher** (desktop first; tablet second; mobile last)
- Manage - Various admin and configuration options
- Menu Section - Event; Location; Sessions; Show/Hide
- Content Section - Shows session specific files; Shows session specific presentations; presentation specific presenters are shown per presentation; presenter specific files are shown per presenter
- Header Section - Event Name; Location Name; Current Time; Offline/Online Status; Sync Status
- Footer Section - Other status indicators; sync button
- **Badge Printing**
- Manage
- Print Badges
- View Badge (show full preview before printing)
- Review Badge (attendee confirms key info before printing; agree/disagree to terms; agree/disagree to lead retrieval and tracking)
- Manually add Badge
- Reports
- **Lead Retrieval**
- Manage
- View Leads
- Add Lead (Scan or Manual Entry)
- License Management and Payment (Stripe)
- **Admin or Manage or Configure Event**
### New Directory Structure?
- src/lib/ - Shared libraries and components
- src/routes/core/ - Core Aether management module
- sub-directories for:
- accounts
- account (by ID)
- sites
- site (by ID)
- site_domains
- site_domain (by ID)
- people
- person (by ID)
- users
- user (by ID)
- hosted_files
- hosted_file (by ID or partial hash match???)
- lookups
- (countries)
- (state_provinces)
- (time_zones)
- src/routes/events/ - Events main landing page and event management
- src/routes/events/[event_id]/(presentations)/ - Event presentation management module
- sub-directories for:
- sessions
- session (by ID or code)
- presentations
- presenters
- presenter (by ID or code???)
- event_files
- locations
- location (by ID or code)
- devices
- device (by ID or code)
- reports
- report (by name of report)
- src/routes/events/[event_id]/(launcher)/ - Event launcher module
- src/routes/events/[event_id]/(badges)/ - Event badge printing module
- src/routes/events/[event_id]/(leads)/ - Event lead retrieval module
- src/routes/events/[event_id]/+page.svelte - Event main dashboard
- [event_id]/exhibit/[exhibit_id]/ - Exhibitor specific lead retrieval pages
- src/routes/journals/ - Journals module
- src/routes/idaa/ - IDAA custom modules
- (archives)/ - Archives module
- (bb)/ - Bulletin Board module
- (recovery_meetings)/ - Recovery Meetings module
- src/lib/ae_core/ - Core Aether logic and data models
- src/lib/ae_events/ - Events module logic and data models
- src/lib/ae_journals/ - Journals module logic and data models
- src/lib/ae_idaa/ - IDAA custom modules logic and data models
- src/lib/components/ - Shared Svelte components
- src/lib/stores/ - Shared Svelte stores
- src/assets/ - Assets like CSS, Tailwind config, etc.???
- static/ - Static assets like images, fonts, etc.

View File

@@ -1,14 +1,12 @@
{
"folders": [
{
"path": "."
}
],
"settings": {
"cSpell.words": [
"filelist"
],
"git.autofetch": true,
"editor.defaultFormatter": "svelte.svelte-vscode"
}
}
"folders": [
{
"path": "."
}
],
"settings": {
"cSpell.words": ["filelist"],
"git.autofetch": true,
"editor.defaultFormatter": "svelte.svelte-vscode"
}
}

View File

@@ -1,17 +1,17 @@
{
"$schema": "https://next.shadcn-svelte.com/schema.json",
"style": "default",
"tailwind": {
"config": "tailwind.config.ts",
"css": "src/app.css",
"baseColor": "gray"
},
"aliases": {
"components": "$lib/components",
"utils": "$lib/utils",
"ui": "$lib/components/ui",
"hooks": "$lib/hooks"
},
"typescript": true,
"registry": "https://next.shadcn-svelte.com/registry"
"$schema": "https://next.shadcn-svelte.com/schema.json",
"style": "default",
"tailwind": {
"config": "tailwind.config.ts",
"css": "src/app.css",
"baseColor": "gray"
},
"aliases": {
"components": "$lib/components",
"utils": "$lib/utils",
"ui": "$lib/components/ui",
"hooks": "$lib/hooks"
},
"typescript": true,
"registry": "https://next.shadcn-svelte.com/registry"
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,142 @@
# Aether Project Architecture
This document outlines the overall architecture and key technologies used in the Aether SvelteKit frontend project.
## 1. Project Overview
The Aether project is a Svelte and SvelteKit based application, utilizing Tailwind CSS and Skeleton for styling and UI elements. It serves as the frontend UI/UX for the Aether system, which interacts with a Python FastAPI backend.
## 2. Core Technologies
- **Frontend Framework:** Svelte 5 and SvelteKit v2
- **Routing:** SvelteKit's file-system based routing.
- **Styling:** Tailwind CSS v4
- **UI Component Libraries:**
- Skeleton (Design System, Tailwind Components, Functional Components - being phased out due to conflicts with Tailwind CSS v4)
- Flowbite (Tailwind Components)
- Custom Components (a growing library of `ae_comp__*` and `element_*` components)
- **Text/Code Editors:**
- CodeMirror 6.x (primary text and code editor, planned for rich text editing)
- Edra (TipTap based Rich Text Editor)
- **Note:** ShadEditor TipTap is present but marked for removal, with CodeMirror being the preferred solution for all text editing needs.
- **Icons:** Lucide Icons (SVG Icons)
- **Markdown Parsing:** `marked` library
- **State Management:** Svelte stores, potentially with `liveQuery` from Dexie for reactive IndexedDB interactions.
## 3. Module Structure
The Aether project is organized into several modules, categorized as Core, Extended, and Custom.
### 3.1. Official Modules
#### Core Modules
These are foundational modules essential for the application's basic functionality.
- **Accounts:** Minimal implementation.
- **Files:** Manages hosted files.
- **People:** Minimal implementation for person records.
- **Sites:** Minimal implementation for site configurations.
- **Users:** Minimal implementation for user management.
#### Extended Modules
These modules provide additional features and functionalities.
- **Archives:** Minimal implementation.
- **Events:** Includes features for Badges and Presentation Management.
- **Posts:** Minimal implementation.
- **Journals:** Manages journal entries.
#### Custom Modules
These modules are tailored for specific client needs.
- **IDAA:** Includes Archives, Bulletin Board (BB), and Recovery Meetings functionalities.
## 4. Data Storage Mechanisms
### 4.1. Local Storage
Used for client-side persistence of various application states and configurations.
- `api`: API-related settings.
- `app`: Global application settings.
- `core`: Settings and data specific to core modules.
- `<module>`: Settings and data specific to extended modules.
- `<custom>`: Settings and data specific to custom modules.
### 4.2. IndexedDB (Dexie.js)
Used for more structured client-side data storage, often for caching and offline capabilities.
- `ae_core_db`: Core database instance.
- `<module>`: Module-specific database instances.
- `<custom>`: Custom module-specific database instances (none currently defined).
## 5. Data Sorting
Standardized sorting orders are applied across various data lists.
- **Default/General:** `group > priority > sort > updated_on/created_on`
- **Specific (e.g., Events):** `type > start_date/time > code or name`
## 6. Object Properties and Fields
A set of standardized field names and types are used across Aether objects.
### 6.1. Core Standard Fields
These fields are expected to be present in most Aether objects.
- `id`: Primary key for an object (internal use, often a UUID).
- `id_random`: Randomly generated ID for an object (often used for external exposure or URL parameters).
- `<object_type>_id_random`: Specific random ID for an object (e.g., `person_id_random`).
- `code`: Short, unique identifier.
- `name`: Display name.
- `enable`: Boolean for active/inactive status.
- `hide`: Boolean for visibility.
- `priority`: Numeric value for ordering.
- `sort`: Numeric value for ordering.
- `group`: Categorization string.
- `notes`: General notes/comments.
- `created_on`: Timestamp of creation.
- `updated_on`: Timestamp of last update.
### 6.2. Special Use Fields
Fields with specific purposes or conditional usage.
- `for_type`: Indicates the type of object this object is linked to.
- `for_id`: The ID of the object this object is linked to.
- `archive_on`: Timestamp for archiving.
- `passcode`: Password or access code.
- `external_id`: ID from an external system.
### 6.3. Configuration and JSON Fields
Fields designed to store JSON data.
- `cfg_json`: Configuration data in JSON format.
- `data_json`: General data in JSON format.
- `linked_li_json`: List of linked items in JSON format.
### 6.4. Special Generated Fields (Client-side)
Fields generated on the client-side, primarily for sorting or UI logic.
- `tmp_sort_1`
- `tmp_sort_2`
- `tmp_sort_3`
### 6.5. Future Standard Fields
A list of potential future standard fields, often prefixed with `obj_`. These are currently conceptual and not yet fully integrated.
- `obj_id`, `obj_ext_uid`, `obj_ext_id`, `obj_import_id`, `obj_code`, `obj_account_id`, `obj_passcode`, `obj_type`, `obj_type_ver_id`, `obj_name`, `obj_summary`, `obj_outline`, `obj_description`, `obj_enable`, `obj_enable_on`, `obj_archive_on`, `obj_hide`, `obj_priority`, `obj_sort`, `obj_group`, `obj_cfg_json`, `obj_notes`, `obj_created_on`, `obj_updated_on`.
## 7. IndexedDB LiveQuery Usage
- `lq__xyz_obj`: Used for general read-only access to liveQuery results.
- `lqw__xyz_obj`: Used for forms and binding values, representing a writable snapshot of liveQuery results.
- **Note:** Care must be taken when binding to `lqw__xyz_obj` to manage updates and potential conflicts with the underlying liveQuery.

148
documentation/COMPONENTS.md Normal file
View File

@@ -0,0 +1,148 @@
# Aether Project Components
This document details the various UI components used throughout the Aether SvelteKit frontend project, categorized by their scope and functionality.
## 1. Aether Components (UI/UX)
### 1.1. System Components
These components are part of the core application shell and provide global functionalities.
- **`header`**: Application-wide header.
- **`main/module`s**: Main content area for modules.
- **`footer`**: Application-wide footer.
- **`app`**: Provides global application functionalities such as:
- Refresh application state.
- Clear IndexedDB.
- Clear local storage (settings).
- Toggle iframe visibility (also updates URL parameter).
- Copy current URL.
- Generate and display QR codes.
- **`menu`**: Various menus for different purposes:
- **`mode`**: Edit mode toggle, more options (all or details).
- **`access_type`**: Passcode input, clear access.
- **`user`**: Sign in/out, reset password, email link, change username and email.
- **`theme`**: Mode (light/dark), name (theme list).
- **`debug`**: Developer-facing tools:
- Toggle debug mode (also updates URL parameter).
- Show core and module storages.
- Manually set initial timestamp.
- **`scroll_to`**: Navigation controls for scrolling:
- Scroll to top of the page.
- Scroll page up.
- Scroll page down.
- Scroll to bottom of the page.
### 1.2. Core Components
These are reusable components that provide common functionalities across different modules.
- **`copy_btn`**: A button to copy content to the clipboard.
- Properties: `clipboard`, `bind:value`, `btn_text`, `btn_html`.
- **`txt_editor`**: A basic text area editor.
- **`md_editor`**: Markdown editor.
- Uses CodeMirror (planned for rich text editing).
- **Note:** ShadEditor TipTap is present but marked for removal. ShadCN components are also being phased out in favor of CodeMirror for text editing.
- **`html_editor`**: HTML editor.
- **`media_player`**: Component for playing media files.
- Properties: `hosted_file`, `archive_content`, `media_player`.
- Bindings: `bind:host_id`, `bind:media_type`.
- Status: `stopped`, `paused`, `playing`.
- **`hosted_file_li`**: Manages a list of hosted files, making them available for selection.
- **`hosted_file_link_to`**: Lists links per object, with bindings to add/remove links.
- **`upload_to_host`**: Component for uploading files to the host.
- Handles multiple files.
- Properties: `link_type`, `link_id`, `inner fragment` (label html).
- Bindings: `bind:trigger`, `bind:show_spinner`, `bind:show_percent`.
- Status: `started`, `uploading`, `finished`.
- **`upload_file_tbl`**: Table for uploaded files, includes checks for duplicate file hashes and removal from the list.
- **`download_from_host`**: Component for downloading files from the host.
- Bindings: `bind:host_file_id`, `bind:filename`, `bind:file_ext`.
- Properties: `btn inner fragment`.
- Bindings: `bind:trigger`, `bind:show_spinner`, `bind:show_percent`.
- Status: `started`, `downloading`, `finished`.
- **`data_store`**: Component for interacting with data stores.
- **`ae_crud`**: Generic CRUD (Create, Read, Update, Delete) component.
- **Note:** Needs simplification.
- Properties: `obj`, `prop`, `current_value`.
- Bindings: `bind:value`, `bind:trigger`, `inner fragment`.
- **`ae_obj_prop_val`**: A wrapper for a function to manage object property values.
- Bindings: `bind:obj_type`, `bind:obj_id`, `bind:obj_prop`, `bind:obj_value`, `bind:obj_new_value`, `bind:trigger`, `bind:show_spinner`, `bind:show_percent`.
- Status: `status`, `result`.
- **`sql_qry`**: Component for executing SQL queries.
- **`obj_tbl`**: Object SQL results table or similar.
- **`qr_scanner`**: Component for scanning QR codes.
- **`websocket`**: Component for WebSocket communication.
### 1.3. Main / Module Components
These are components specific to main application sections or individual modules.
- **`menu`**:
- **`options`**: Various settings, show/hide content and options, limit, sorting options.
- **`actions`**: Various actions, sign in/out, email.
### 1.4. Object Menu
A standardized menu for interacting with objects.
- **Properties Displayed:** `id`, `name`, `group`, `priority`, `sort`, `alert`, `hide`, `enable`, `note`.
- **Future Properties:** `ext_id`, `ext_sys_id`, `code` (not yet ready).
- **Actions:** `create`, `view`, `edit`, `update`, `hide`, `disable`, `delete`, `alert` (message), `archive` (not yet ready).
- **Future Actions:** `copy`, `import`.
- **Sort Options:**
- `[default]`: `group > priority > sort (ASC/DESC) > alert > name`
- `[sort_updated]`: `group > priority > sort (ASC/DESC) > alert > updated_on > created_on`
- `[priority_updated]`: `group > priority > updated_on (ASC/DESC) > created_on`
- `[priority_name]`: `group > priority > name (ASC/DESC) > sort > alert > updated_on > created_on`
- `[name]`: `priority > name (ASC/DESC) > sort > alert > updated_on > created_on`
- `[created_on]`: `priority > created_on (ASC/DESC)`
- `[updated_on]`: `priority > updated_on (ASC/DESC) > created_on`
## 2. Pop-ups
Standardized structure for various types of pop-up elements.
- **`modal_header`**:
- `title`
- `close` button
- **`modal_main`**: Main content area of the modal.
- **`modal_meta`**: Meta-information section.
- **`modal_footer`**:
- `close` button
- **`Pop-up Modal (blocking)`**: A modal that blocks interaction with the rest of the page.
- `modal position`
- **`Pop-up Modal Inline`**: A modal that appears inline with content.
- `inline`, `inline-block`, `block` display options.
- **`Pop-up Dialog`**: A dialog box.
- `dialog position`
## 3. Containers
Generic container types used for layout and grouping.
### 3.1. Navigation
- `link`
- `download`
### 3.2. Forms
- `save` button/action
- `clear value` action
- `set null value` action
### 3.3. Other Containers
- `help`: Blue themed container.
- `info`: Blue themed container.
- `alert`: Yellow themed container.
- `warning`: Orange themed container.
- `error`: Red themed container.
- `message`: Green themed container.
## 4. CSS Styling for UI Elements
- **Warning/Hide Buttons:** `variant-soft-warning hover:variant-filled-warning`
- **Error/Delete/Disable Buttons:** `variant-soft-error hover:variant-filled-error`
- **Submenu:** `flex flex-row items-center justify-center gap-1`

View File

@@ -0,0 +1,90 @@
# Aether Project Data Structures
This document outlines the key data structures and their properties used within the Aether SvelteKit frontend project. It covers object properties, field definitions, and how data is managed.
## 1. Object Properties and Fields
### 1.1. Core Standard Fields
These fields are expected to be present in most Aether objects, providing a consistent base structure.
- `id`: Primary key for an object (internal use, often a UUID).
- `id_random`: Randomly generated ID for an object (often used for external exposure or URL parameters).
- `<object_type>_id_random`: Specific random ID for an object (e.g., `person_id_random`).
- `code`: Short, unique identifier.
- `name`: Display name.
- `enable`: Boolean for active/inactive status.
- `hide`: Boolean for visibility.
- `priority`: Numeric value for ordering.
- `sort`: Numeric value for ordering.
- `group`: Categorization string.
- `notes`: General notes/comments.
- `created_on`: Timestamp of creation.
- `updated_on`: Timestamp of last update.
### 1.2. Special Use Fields
Fields with specific purposes or conditional usage across different object types.
- `for_type`: Indicates the type of object this object is linked to (e.g., 'account', 'event').
- `for_id`: The ID of the object this object is linked to.
- `archive_on`: Timestamp indicating when an object was archived.
- `passcode`: A password or access code associated with an object.
- `external_id`: An identifier from an external system.
### 1.3. Configuration and JSON Fields
Fields designed to store structured data in JSON format.
- `cfg_json`: Configuration data for an object, stored as a JSON string.
- `data_json`: General purpose data for an object, stored as a JSON string.
- `linked_li_json`: A list of linked items, stored as a JSON string.
### 1.4. Special Generated Fields (Client-side)
These fields are generated on the client-side, primarily for facilitating UI logic, such as sorting. They are not typically stored in the backend database.
- `tmp_sort_1`: Temporary sort field 1.
- `tmp_sort_2`: Temporary sort field 2.
- `tmp_sort_3`: Temporary sort field 3.
### 1.5. Future Standard Fields
A list of potential future standard fields, often prefixed with `obj_`. These are conceptual and represent planned expansions to the data model.
- `obj_id`, `obj_ext_uid`, `obj_ext_id`, `obj_import_id`, `obj_code`, `obj_account_id`, `obj_passcode`, `obj_type`, `obj_type_ver_id`, `obj_name`, `obj_summary`, `obj_outline`, `obj_description`, `obj_enable`, `obj_enable_on`, `obj_archive_on`, `obj_hide`, `obj_priority`, `obj_sort`, `obj_group`, `obj_cfg_json`, `obj_notes`, `obj_created_on`, `obj_updated_on`.
## 2. Data Sorting
Standardized sorting orders are applied across various data lists to ensure consistent presentation.
- **Default/General Sorting:** `group > priority > sort > updated_on/created_on`
- **Specific Sorting (e.g., for time-based events):** `type > start_date/time > code or name`
## 3. Data Storage Mechanisms
### 3.1. Local Storage
Used for client-side persistence of various application states and configurations.
- `api`: Stores API-related settings and tokens.
- `app`: Stores global application settings and preferences.
- `core`: Stores settings and data specific to core modules.
- `<module>`: Stores settings and data specific to extended modules (e.g., `journals`, `events`).
- `<custom>`: Stores settings and data specific to custom modules (e.g., `idaa`).
### 3.2. IndexedDB (Dexie.js)
Used for more structured client-side data storage, often for caching, offline capabilities, and larger datasets.
- `ae_core_db`: The primary Dexie database instance for core application data.
- `<module>`: Module-specific database instances (e.g., `db_journals` for journal data).
- `<custom>`: Custom module-specific database instances (none currently defined, but reserved for future use).
### 3.3. IndexedDB LiveQuery Usage
Dexie's `liveQuery` is used to provide reactive data streams from IndexedDB.
- `lq__xyz_obj`: Represents a read-only liveQuery result for a single object.
- `lqw__xyz_obj`: Represents a writable liveQuery result, typically used for forms and data binding.
- **Note:** When using `lqw__xyz_obj`, developers must carefully manage updates to avoid conflicts with the underlying liveQuery and ensure data integrity.

View File

@@ -0,0 +1,93 @@
# Aether Project Naming Conventions
## 1. General Principles
- **Clarity:** Names should clearly convey their purpose and meaning.
- **Consistency:** Adhere strictly to these guidelines across the entire codebase.
- **Readability:** Prioritize names that are easy to read and understand.
- **Conciseness:** Avoid unnecessary verbosity, but not at the expense of clarity.
## 2. File Naming
- **Logic/Service Files:** `ae_<module>__<concept>.ts` (e.g., `ae_core__account.ts`, `ae_events__event.ts`)
- **Database Definition Files:** `db_<module>.ts` (e.g., `db_core.ts`, `db_journals.ts`)
- **Svelte Store Files:** `ae_<module>_stores.ts` (e.g., `ae_core_stores.ts`, `ae_journals_stores.ts`)
- **Svelte Components:**
- **Module-specific components:** `ae_comp__<module>__<component_name>.svelte` (e.g., `ae_comp__events__event_card.svelte`)
- **Generic/reusable components:** `element_<component_name>.svelte` (e.g., `element_input_file.svelte`, `element_qr_scanner_v2.svelte`)
- **SvelteKit Routes:** Follow SvelteKit's standard routing conventions (e.g., `+page.svelte`, `+layout.svelte`, `[id]/+page.svelte`).
- **CSS Files:** `ae-<module>-<purpose>.css` (e.g., `ae-c-idaa-light.css`, `ae-osit-default.css`)
## 3. Function and Variable Naming
- **Style:** Strictly `snake_case` for all function and variable names.
- **Deprecated:** `camelCase` should be refactored to `snake_case`.
- **Prefixes:**
- `load_ae_obj_id__<object_type>`: For loading a single Aether object by ID.
- `load_ae_obj_li__<object_type>`: For loading a list of Aether objects.
- `create_ae_obj__<object_type>`: For creating an Aether object.
- `update_ae_obj__<object_type>`: For updating an Aether object.
- `delete_ae_obj_id__<object_type>`: For deleting an Aether object by ID.
- `db_save_ae_obj_li__<object_type>`: For saving a list of Aether objects to IndexedDB.
- `db_update_ae_obj_id__<object_type>`: For updating an Aether object in IndexedDB.
- `process_ae_obj__<object_type>_props`: For module-specific data transformation functions.
- **Deprecated:** Ambiguous `handle_` prefixes should be replaced with more descriptive `snake_case` names (e.g., `handle_submit_form` -> `submit_form`).
## 4. Object and Property Naming
- **Singularity:** Use singular nouns for objects and properties (e.g., `example.id`, not `examples.id`).
- **IDs:**
- `id`: Primary key for an object (internal use, often a UUID).
- `<object_type>_id`: Specific ID for an object (e.g., `person_id`).
- `<object_type>_id_random`: Randomly generated ID for an object (often used for external exposure or URL parameters).
- `account_id`, `site_id`, `user_id`, etc.: Foreign keys.
- **Common Properties:**
- `code`: Short, unique identifier.
- `name`: Display name.
- `description`: Longer text description.
- `enable`: Boolean for active/inactive status.
- `hide`: Boolean for visibility.
- `priority`: Numeric value for ordering.
- `sort`: Numeric value for ordering.
- `group`: Categorization string.
- `notes`: General notes/comments.
- `created_on`: Timestamp of creation.
- `updated_on`: Timestamp of last update.
- **Special Use Properties:** `for_type`, `for_id`, `archive_on`, `passcode`, `external_id`.
- **Config/JSON Properties:** `cfg_json`, `data_json`, `linked_li_json`.
- **Special Generated Fields (Client-side):** `tmp_sort_1`, `tmp_sort_2`, `tmp_sort_3` (for client-side sorting).
## 5. List Suffixes
- **Simple Arrays:** Use `_li` suffix for simple, unordered arrays (e.g., `user_li`, `hosted_file_id_li`).
- **Key-Value Maps/Objects:** Use `_kv` suffix for key-value objects/maps (e.g., `user_kv`, `hosted_file_obj_kv`).
## 6. Interface and Type Naming
- **Style:** Use `PascalCase` for interface and type names (e.g., `Account`, `HostedFile`, `GenericCrudArgs`).
## 7. Constants
- **Style:** Use `SCREAMING_SNAKE_CASE` for constants (e.g., `MAX_RETRIES`, `DEFAULT_TIMEOUT`).
## 8. CSS Classes and IDs
- **Style:** Use `kebab-case` for CSS classes and IDs (e.g., `my-component-class`, `main-header-id`).
## 9. Data Sorting
- **Standard Order:** `group > priority > sort > updated_on/created_on`
- **Specific Order:** `type > start_date/time > code or name`
## 10. Local Storage and IndexedDB Keys
- **Local Storage:**
- `api`
- `app` (global)
- `core` (core modules)
- `<module>` (extended modules)
- `<custom>` (custom modules)
- **IndexedDB:**
- `ae_core_db`
- `<module>`
- `<custom>`

View File

@@ -0,0 +1,137 @@
# AE UI Components, Layout, and Style Standards (HTML/CSS)
## Aether Components
### System Components
- [header]
- [main/module]s
- [footer]
- [app] refresh, clear IDB, clear local storage (settings), iframe toggle (also updates URL param), copy URL, generate and show QR
- [menu][mode] edit, more (all or details)
- [menu][access_type] passcode input, clear
- [menu][user] sign in/out, reset password, email link, change username and email
- [menu][theme] mode (light/dark), name (theme list)
- [debug] toggle (also updates URL param), show core and module storages, manually set init timestamp
- [scroll_to] top, page up, page down, bottom
### Core Components
- [copy_btn] clipboard, bind:value, btn_text, btn_html
- [txt_editor] textarea
- [md_editor] CodeMirror, ShadEditor TipTap (need to remove)
- [html_editor]
- [media_player]
- hosted_file archive_content media_player,
- bind:host_id,
- bind:media_type
- status - stopped, paused, playing
- [hosted_file_li] manage_hosted_file_li, make available for selection
- [hosted_file_link_to] list links per object, bind:add link, bind:remove link
- [upload_to_host] - input_hosted_file; needs to handle multiple files
- link_type,
- link_id,
- inner fragment - label html
- bind:trigger
- bind:show_spinner
- bind:show_percent
- status
- result - started, uploading, finished
- [upload_file_tbl] input_hosted_file_tbl, check for dup file hash, remove from list
- [download_from_host]
- bind:host_file_id
- bind:filename
- bind:file_ext
- btn inner fragment
- bind:trigger
- bind:show_spinner
- bind:show_percent
- status
- result - started, downloading, finished
- [data_store]
- [ae_crud] need to simplify! obj, prop, current_value, bind:value, bind:trigger, inner fragment
- [ae_obj_prop_val] - essentially a wrapper for the function
- bind:obj_type
- bind:obj_id
- bind:obj_prop
- bind:obj_value
- bind:obj_new_value
- bind:trigger
- bind:show_spinner
- bind:show_percent
- status
- result
- [sql_qry]
- [obj_tbl] obj sql results tbl or similar
- [qr_scanner]
- [websocket]
### Main / Module Components
- [menu][options] various settings, show/hide content and options, limit, sorting options, etc
- [menu][actions] various actions, sign in/out, email
### Object Menu
- properties: id, name, group, priority, sort, alert, hide, enable, note
- future properties: ext_id (not ready yet), ext_sys_id (not ready yet), code (not ready yet)
- actions: create, view, edit, update, hide, disable, delete, alert (message), archive (not ready yet)
- future actions: copy, import
- sort options:
- [default] group > priority > sort (ASC/DESC) > alert > name
- [sort_updated] group > priority > sort (ASC/DESC) > alert > updated_on > created_on
- [priority_updated] group > priority > updated_on (ASC/DESC) > created_on
- [priority_name] group > priority > name (ASC/DESC) > sort > alert > updated_on > created_on
- [name] priority > name (ASC/DESC) > sort > alert > updated_on > created_on
- [created_on] priority > created_on (ASC/DESC)
- [updated_on] priority > updated_on (ASC/DESC) > created_on
### Pop-ups:
- modal_header
- title
- close
- modal_main
- modal_meta
- modal_footer
- close
#### Pop-up Modal (blocking)
- modal position
#### Pop-up Modal Inline
- inline, inline-block, block
#### Pop-up Dialog
- dialog position
## Containers
### Navigation
- link
- download
### Forms
- save
- clear value
- set null value
### Other Containers
- help - blue
- info - blue
- alert - yellow
- warning - orange
- error - red
- message - green
---
## Need to organize:
- lu: id, account_id, for_obj_id, code, name, description, group, sort, priority, enable, perm_level

View File

@@ -1,13 +1,17 @@
# One Sky IT's Aether App - UI and UX Guidelines and Rules
## General
### Events
#### layout header
#### layout footer
### Journals
#### buttons
##### alert
##### info
@@ -15,52 +19,62 @@
##### priority, flag
##### warning, hide
```css
variant-soft-warning hover:variant-filled-warning
```
##### error, delete, disable
```css
variant-soft-error hover:variant-filled-error
```
#### new root layout header
#### submenu
```css
flex flex-row items-center justify-center gap-1
```
#### new layout footer
#### new layout footer
## Svelte 5 and SvelteKit v2 (framework and routing)
## Tailwind 3.x CSS (styles)
Waiting to upgrade to 4.x when ShadCN is ready. ShadCN is still being worked on as of late March 2025.
* https://ui.shadcn.com/docs/tailwind-v4
Waiting to upgrade to 4.x when ShadCN is ready. ShadCN is still being worked on as of late March 2025.
- https://ui.shadcn.com/docs/tailwind-v4
## CodeMirror 6.x (text and code editor)
* https://codemirror.net
- https://codemirror.net
## ShadCN (Tailwind Components)
* https://ui.shadcn.com/docs
* https://github.com/shadcn-ui/ui
- https://ui.shadcn.com/docs
- https://github.com/shadcn-ui/ui
## Skeleton (Design System, Tailwind Components, Functional Components)
Waiting to upgrade to Skeleton v3. Mostly because of the Tailwind 4.x upgrade needed for ShadCN.
* https://www.skeleton.dev/docs/get-started/migrate-from-v2
- https://www.skeleton.dev/docs/get-started/migrate-from-v2
## Flowbite (Tailwind Components)
## Lucide Icons (SVG Icons)
* https://lucide.dev/icons/
- https://lucide.dev/icons/
## Markdown
Using marked for Markdown parsing.
* https://marked.js.org/
Using marked for Markdown parsing.
- https://marked.js.org/
## Edra (TipTap based Rich Text Editor)
* https://edra.tsuzat.com/
- https://edra.tsuzat.com/

View File

@@ -0,0 +1,173 @@
# AE Svelte and SvelteKit Technical Standards
## Official Modules
### Core
- Accounts - Minimal
- Files
- People - Minimal
- Sites - Minimal
- Users - Minimal
### Extended
Archives - Minimal, Events - Badges, Events - Presentation Management, Posts - Minimal, Journals
### Custom
IDAA - Archives, IDAA - BB, IDAA - Recovery Meetings
---
## localStorage:
- api
- app - global
- core - core modules
- [module] - extended modules
- [custom] - custom modules
---
## Indexed DB
- ae_core_db
- [module]
- [custom] - custom modules: none currently
---
## Data Sorting
- group > priority > sort > updated/created on
- type > start date/time > code or name
---
## Objects
### Function - Obj Prop Update
- obj_type
- obj_id
- obj_prop
- obj_value
### Core
### Extended
### Custom
---
## Object Properties or Fields
### Core
Expected standard field names: id, id_random, [obj-type]\_id_random, code, name, enable, hide, priority, sort, group, notes, created_on, updated_on
Special use field names: for_type, for_id, archive_on, passcode, external_id
### Configs and Fields with JSON
- cfg_json
- data_json
- linked_li_json
### Special Generated Fields
tmp_sort_1, tmp_sort_2,
### Future standard fields!!!
obj_id?: null|string;
obj_ext_uid?: null|string; // Probably not needed for journals
obj_ext_id?: null|string; // Probably not needed for journals
obj_import_id?: null|string; // Probably not needed for journals
obj_code?: null|string;
obj_account_id?: null|string;
obj_passcode?: null|string;
obj_type?: null|string; // Should always be 'journal' in this case
obj_type_ver_id?: null|string; // The ID from the table for the object type
obj_name?: null|string;
obj_summary?: null|string; // LLM (AI) generated summary...???
obj_outline?: null|string; // LLM (AI) generated outline...???
obj_description?: null|string; // Probably not needed for journals
obj_enable?: null|boolean;
obj_enable_on?: null|Date;
obj_archive_on?: null|Date;
obj_hide?: null|boolean;
obj_priority?: null|number;
obj_sort?: null|number;
obj_group?: null|string;
obj_cfg_json?: null|string;
obj_notes?: null|string;
obj_created_on?: Date;
obj_updated_on?: null|Date;
## Dixie IDB liveQuery with Select Objects (slct) and Lists of Objects (slct_x_li)
Use this method below to create a read/write snapshot of the current liveQuery results. This allows you to use it as part of a form and binding values. It might make since to call this something like "lqw**x_obj" and "lqw**x_obj_li". lqw = liveQuery writable
lq**xyz_obj - Use for general read only
lqw**xyz_obj - Use for forms and binding values. What happens if the actual LQ obj is updated after the bind?
$slct or $lqw ?
Sort of related.... more permission/security though: Create a new table that will be attached to every v\_ view in the DB. This new table would be a field permission list. It could work similar to the data_store table and related view. This seems like a good idea????? 2025-08-11
```ts
let lq__post_obj = $derived(
liveQuery(async () => {
if (log_lvl) {
console.log(`lq__post_obj: post_id = ${$idaa_slct?.post_id}`);
}
let results = await db_posts.post.get($idaa_slct.post_id ?? ''); // null or undefined does not reset things like '' does
// Check if results are different than the current $idaa_slct.post_obj
if ($idaa_slct.post_obj && results) {
if (JSON.stringify($idaa_slct.post_obj) !== JSON.stringify(results)) {
$idaa_slct.post_obj = { ...results };
if (log_lvl) {
console.log(`$idaa_slct.post_obj = `, $idaa_slct.post_obj);
}
} else {
if (log_lvl) {
console.log(`Post object has not changed for post_id: ${$idaa_slct.post_id}`);
}
}
}
return results;
})
);
let lq__post_comment_obj_li = $derived(
liveQuery(async () => {
let results = await db_posts.comment
.where('post_id')
.equals($idaa_slct.post_id ?? '') // null or undefined does not reset things like '' does
.reverse()
.sortBy('updated_on');
// .sortBy('title');
if (
$idaa_slct.post_comment_obj_li &&
JSON.stringify($idaa_slct.post_comment_obj_li) !== JSON.stringify(results)
) {
$idaa_slct.post_comment_obj_li = [...results];
if (log_lvl) {
console.log(`$idaa_slct.post_comment_obj_li = `, $idaa_slct.post_comment_obj_li);
}
} else {
if (log_lvl) {
console.log(
`Post comment object list has not changed for post_id: ${$idaa_slct.post_id}`
);
}
}
return results;
})
);
```

View File

@@ -0,0 +1,108 @@
# Svelte and Dexie.js Integration Guide
This document provides a guide to integrating Svelte (with a focus on Runes) and Dexie.js for building reactive web applications. It covers key concepts and best practices for managing reactivity between Svelte components and the Dexie.js database.
## Svelte 5 Migration Guide
Svelte 5 introduces "runes" as a new way to manage reactivity. This is a major change from previous versions of Svelte, and it's important to understand the breaking changes before migrating.
### Key Breaking Changes
- **`let` is no longer reactive:** In Svelte 4, any `let` variable declared in the top-level scope of a component was automatically reactive. In Svelte 5, you must explicitly declare reactive state using the `$state` rune.
- **`$:` is replaced by `$derived` and `$effect`:** The `$` label is no longer used for reactive statements. Instead, you should use the `$derived` rune for computed values and the `$effect` rune for side effects.
- **`export let` is replaced by `$props`:** Component props are now declared using the `$props` rune, which provides a more flexible and explicit way to define component APIs.
- **Event handling:** The `on:` directive is replaced by event attributes (e.g., `onclick`). Component events are now handled using callback props instead of `createEventDispatcher`.
- **Slots are replaced by snippets:** The `<slot>` element is replaced by the `{#snippet ...}` block, which provides a more powerful and flexible way to pass content to components.
For a complete list of breaking changes, refer to the [Svelte 5 migration guide](https://svelte.dev/docs/svelte/v5-migration-guide).
## Dexie.js Quick Reference
Dexie.js is a lightweight, minimalistic wrapper for IndexedDB that makes it easier to work with client-side databases.
### Key Classes and Methods
- **`Dexie`:** The main class for creating and managing IndexedDB databases.
- `new Dexie(databaseName)`: Creates a new database instance.
- `version(versionNumber).stores({ ... })`: Defines the database schema.
- **`Table`:** Represents an object store (table) in the database.
- `add(item)`: Adds a new item to the table.
- `put(item)`: Adds or updates an item in the table.
- `update(key, changes)`: Updates an existing item.
- `delete(key)`: Deletes an item by its primary key.
- `get(key)`: Retrieves an item by its primary key.
- `where(index)`: Starts a query using an index.
- `toArray()`: Retrieves all items from the table as an array.
- **`Collection`:** Represents a collection of items resulting from a query.
- `toArray()`: Retrieves all items in the collection as an array.
- `first()`: Retrieves the first item in the collection.
- `last()`: Retrieves the last item in the collection.
- `each(callback)`: Iterates over each item in the collection.
- `modify(changes)`: Updates all items in the collection.
- `delete()`: Deletes all items in the collection.
For a complete list of API methods, refer to the [Dexie.js API Reference](https://dexie.org/docs/API-Reference).
## Integrating Svelte Runes and Dexie.js
The combination of Svelte Runes and Dexie.js allows for the creation of highly reactive and efficient web applications.
### The `liveQuery` Function
Dexie.js provides a `liveQuery` function that returns an observable of the query result. This observable can be used to automatically update the UI whenever the data in the database changes.
### Using `liveQuery` with Svelte Runes
To use `liveQuery` with Svelte Runes, you can create a custom readable store that wraps the `liveQuery` observable. This store can then be used in your Svelte components to display and interact with the data.
**1. Create a `liveQuery` store:**
```typescript
import { liveQuery } from 'dexie';
import { readable } from 'svelte/store';
import { db } from './db'; // Your Dexie database instance
export function createLiveQueryStore<T>(query: () => T | Promise<T>) {
return readable<T | undefined>(undefined, (set) => {
const subscription = liveQuery(query).subscribe({
next: (result) => set(result),
error: (error) => console.error(error)
});
return () => subscription.unsubscribe();
});
}
```
**2. Use the `createLiveQueryStore` in your component:**
```html
<script>
import { createLiveQueryStore } from './stores';
import { db } from './db';
const friends = createLiveQueryStore(() => db.friends.toArray());
</script>
<ul>
{#if $friends} {#each $friends as friend}
<li>{friend.name}</li>
{/each} {/if}
</ul>
```
The `createLiveQueryStore` function creates a readable store that automatically updates whenever the data in the `friends` table changes. The `$friends` variable in the component will always contain the latest data from the database.
## Current Data Flow in `ae_journals` Module
The `ae_journals` module currently uses a manual, API-first caching strategy. It does not use Dexie.js's `liveQuery` function for reactivity.
### Data Flow
1. **Fetch from API:** The `load_ae_obj_id__journal` and `load_ae_obj_li__journal` functions are used to fetch data from the API.
2. **Process Data:** The `process_ae_obj__journal_props` and `process_ae_obj__journal_entry_props` functions are used to process the data before it's saved to the database. This includes parsing Markdown, creating temporary sorting fields, and combining passcodes.
3. **Save to IndexedDB:** The `db_save_ae_obj_li__ae_obj` function is used to save the processed data to the `journal` and `journal_entry` tables in the `ae_journals_db` IndexedDB database.
4. **Manual Store Updates:** The Svelte stores in `src/lib/ae_journals/ae_journals_stores.ts` are manually updated with the fetched data.
### Future Improvements
The current implementation could be improved by refactoring it to use Dexie.js's `liveQuery` function. This would simplify the code, reduce boilerplate, and improve the reactivity of the application. By using `liveQuery`, the UI would automatically update whenever the data in the IndexedDB database changes, without the need for manual store updates.

38
eslint.config.js Normal file
View File

@@ -0,0 +1,38 @@
// @ts-check
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
import svelte from 'eslint-plugin-svelte';
import prettier from 'eslint-config-prettier';
import globals from 'globals';
export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.recommended,
svelte.configs['flat/recommended'],
prettier,
{
languageOptions: {
globals: {
...globals.browser,
...globals.node
}
}
},
{
files: ['**/*.svelte'],
languageOptions: {
parserOptions: {
parser: tseslint.parser
}
}
},
{
ignores: ['build/', '.svelte-kit/', 'node_modules/']
},
{
rules: {
'@typescript-eslint/no-unused-vars': 'warn'
}
}
);

View File

@@ -1,7 +1,7 @@
{
"compilerOptions": {
"paths": {
"$lib/*": ["./src/lib/*"]
"$lib/*": ["./src/lib/*"]
}
}
}
}

16390
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,116 +1,118 @@
{
"name": "ae-app-svelte5",
"version": "0.2.711",
"private": true,
"scripts": {
"dev": "vite dev",
"build": "vite build",
"build:prod": "cp .env.prod .env.production && vite build",
"build:staging": "cp .env.staging .env.production && vite build",
"preview": "vite preview",
"test": "npm run test:integration && npm run test:unit",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check . && eslint .",
"format": "prettier --write .",
"test:integration": "playwright test",
"test:unit": "vitest"
},
"devDependencies": {
"@playwright/test": "^1.28.1",
"@skeletonlabs/skeleton": "^3.1.3",
"@skeletonlabs/skeleton-svelte": "^1.2.3",
"@sveltejs/adapter-auto": "^6.0.0",
"@sveltejs/adapter-node": "^5.0.0",
"@sveltejs/adapter-static": "^3.0.1",
"@sveltejs/kit": "^2.5.0",
"@sveltejs/vite-plugin-svelte": "^5.0.0",
"@tailwindcss/forms": "^0.5.7",
"@tailwindcss/typography": "^0.5.10",
"@tiptap/core": "^2.10.3",
"@tiptap/extension-bubble-menu": "^2.10.3",
"@tiptap/extension-code-block-lowlight": "^2.10.3",
"@tiptap/extension-color": "^2.10.3",
"@tiptap/extension-highlight": "^2.10.3",
"@tiptap/extension-image": "^2.10.3",
"@tiptap/extension-link": "^2.10.3",
"@tiptap/extension-subscript": "^2.10.3",
"@tiptap/extension-superscript": "^2.10.3",
"@tiptap/extension-table": "^2.10.3",
"@tiptap/extension-table-cell": "^2.10.3",
"@tiptap/extension-table-header": "^2.10.3",
"@tiptap/extension-table-row": "^2.10.3",
"@tiptap/extension-task-item": "^2.10.3",
"@tiptap/extension-task-list": "^2.10.3",
"@tiptap/extension-text": "^2.10.3",
"@tiptap/extension-text-align": "^2.10.3",
"@tiptap/extension-text-style": "^2.10.3",
"@tiptap/extension-typography": "^2.10.3",
"@tiptap/extension-underline": "^2.10.3",
"@tiptap/pm": "^2.10.3",
"@tiptap/starter-kit": "^2.10.3",
"@types/eslint": "^9.0.0",
"@types/node": "^24.0.0",
"@typescript-eslint/eslint-plugin": "^8.0.0",
"@typescript-eslint/parser": "^8.0.0",
"bits-ui": "^2.0.0",
"clsx": "^2.1.1",
"eslint": "^9.0.0",
"eslint-config-prettier": "^10.0.0",
"eslint-plugin-svelte": "^3.0.0",
"flowbite": "^3.0.0",
"highlight.js": "^11.10.0",
"lowlight": "^3.2.0",
"mode-watcher": "^1.0.0",
"prettier": "^3.1.1",
"prettier-plugin-svelte": "^3.1.2",
"sass-embedded": "^1.81.0",
"svelte": "^5.0.0",
"svelte-awesome-color-picker": "^4.0.0",
"svelte-check": "^4.0.0",
"svelte-highlight": "^7.8.3",
"svelte-idle": "^3.0.1",
"svelte-tiptap": "^2.1.0",
"tailwind-merge": "^3.0.0",
"tailwind-variants": "^2.1.0",
"tailwindcss": "^4.1.10",
"tailwindcss-animate": "^1.0.7",
"tslib": "^2.4.1",
"typescript": "^5.0.0",
"typescript-svelte-plugin": "^0.3.47",
"vite": "^6.0.0",
"vitest": "^3.0.0"
},
"type": "module",
"dependencies": {
"@codemirror/commands": "^6.8.1",
"@codemirror/gutter": "^0.19.9",
"@codemirror/lang-css": "^6.3.1",
"@codemirror/lang-html": "^6.4.9",
"@codemirror/lang-javascript": "^6.2.3",
"@codemirror/lang-json": "^6.0.1",
"@codemirror/lang-markdown": "^6.3.2",
"@codemirror/language": "^6.11.0",
"@codemirror/language-data": "^6.5.1",
"@codemirror/theme-one-dark": "^6.1.2",
"@codemirror/view": "^6.36.8",
"@floating-ui/dom": "^1.6.0",
"@lucide/svelte": "^0.539.0",
"@popperjs/core": "^2.11.0",
"@tailwindcss/vite": "^4.1.10",
"@tiptap/extension-bullet-list": "^2.10.2",
"@tiptap/extension-document": "^2.10.2",
"@tiptap/extension-history": "^2.10.2",
"@tiptap/extension-paragraph": "^2.10.2",
"axios": "^1.7.0",
"codemirror": "^6.0.1",
"dayjs": "^1.11.10",
"dexie": "^4.0.0",
"flowbite-svelte": "^1.7.0",
"html5-qrcode": "^2.3.8",
"lucide-svelte": "^0.539.0",
"marked": "^16.0.0",
"shadcn-svelte": "^1.0.0",
"svelte-persisted-store": "^0.12.0"
}
"name": "osit-aether-app-svelte",
"version": "3.11.18",
"description": "One Sky IT's Aether App created with Svelte, SvelteKit, Tailwind CSS, Lucide, Font Awesome, and Skeleton UI. -Scott Idem",
"homepage": "https://oneskyit.com/",
"private": true,
"scripts": {
"dev": "vite dev",
"build": "vite build",
"build:prod": "cp .env.prod .env.production && vite build",
"build:staging": "cp .env.staging .env.production && vite build",
"preview": "vite preview",
"test": "npm run test:integration && npm run test:unit",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check . && eslint .",
"format": "prettier --write .",
"test:integration": "playwright test",
"test:unit": "vitest"
},
"devDependencies": {
"@eslint/js": "^9.39.1",
"@playwright/test": "^1.56.1",
"@skeletonlabs/skeleton": "3.2.2",
"@skeletonlabs/skeleton-svelte": "1.5.3",
"@sveltejs/adapter-auto": "^7.0.0",
"@sveltejs/adapter-node": "^5.0.0",
"@sveltejs/adapter-static": "^3.0.1",
"@sveltejs/kit": "^2.48.5",
"@sveltejs/vite-plugin-svelte": "^6.0.0",
"@tailwindcss/forms": "^0.5.7",
"@tailwindcss/typography": "^0.5.10",
"@types/eslint": "^9.0.0",
"@types/node": "^24.0.0",
"@types/qrcode": "^1.5.5",
"@typescript-eslint/eslint-plugin": "^8.47.0",
"@typescript-eslint/parser": "^8.47.0",
"bits-ui": "^2.14.3",
"clsx": "^2.1.1",
"eslint": "^9.0.0",
"eslint-config-prettier": "^10.0.0",
"eslint-plugin-svelte": "^3.13.0",
"flowbite": "^4.0.0",
"globals": "^16.5.0",
"highlight.js": "^11.10.0",
"lowlight": "^3.2.0",
"mode-watcher": "^1.0.0",
"prettier": "^3.6.2",
"prettier-plugin-svelte": "^3.2.6",
"sass-embedded": "^1.81.0",
"svelte": "^5.43.10",
"svelte-awesome-color-picker": "^4.0.0",
"svelte-check": "^4.0.0",
"svelte-highlight": "^7.8.4",
"svelte-idle": "^3.0.1",
"tailwind-merge": "^3.0.0",
"tailwind-variants": "^3.*.*",
"tailwindcss": "^4.1.10",
"tailwindcss-animate": "^1.0.7",
"tslib": "^2.4.1",
"typescript": "^5.5.0",
"typescript-svelte-plugin": "^0.3.50",
"vite": "^7.0.0",
"vitest": "^4.0.0"
},
"vitest": {
"exclude": [
"tests"
]
},
"type": "module",
"overrides": {
"@codemirror/state": "^6.5.2",
"@codemirror/view": "^6.38.8",
"@codemirror/language": "^6.11.3",
"@codemirror/commands": "^6.10.0",
"@codemirror/lang-markdown": "^6.5.0",
"@codemirror/autocomplete": "^6.20.0",
"@codemirror/search": "^6.5.11",
"@codemirror/lint": "^6.9.2",
"@lezer/common": "^1.4.0",
"@lezer/highlight": "^1.2.3",
"@lezer/lr": "^1.4.4"
},
"dependencies": {
"@codemirror/autocomplete": "^6.20.0",
"@codemirror/commands": "^6.10.0",
"@codemirror/lang-css": "^6.3.1",
"@codemirror/lang-html": "^6.4.9",
"@codemirror/lang-javascript": "^6.2.3",
"@codemirror/lang-json": "^6.0.1",
"@codemirror/lang-markdown": "^6.5.0",
"@codemirror/language": "^6.11.3",
"@codemirror/language-data": "^6.5.1",
"@codemirror/lint": "^6.9.2",
"@codemirror/search": "^6.5.11",
"@codemirror/state": "^6.5.2",
"@codemirror/theme-one-dark": "^6.1.2",
"@codemirror/view": "^6.38.8",
"@floating-ui/dom": "^1.6.0",
"@lucide/svelte": "^0.*.0",
"@popperjs/core": "^2.11.0",
"@tailwindcss/vite": "^4.1.10",
"axios": "^1.7.0",
"dayjs": "^1.11.10",
"dexie": "^4.0.0",
"flowbite-svelte": "^1.28.1",
"html5-qrcode": "^2.3.8",
"lucide-svelte": "^0.*.0",
"marked": "^17.0.0",
"openai": "^6.10.0",
"qrcode": "^1.5.4",
"shadcn-svelte": "^1.0.11",
"svelte-persisted-store": "^0.12.0",
"typescript-eslint": "^8.47.0"
}
}

View File

@@ -1,12 +1,23 @@
import type { PlaywrightTestConfig } from '@playwright/test';
const config: PlaywrightTestConfig = {
webServer: {
command: 'npm run build && npm run preview',
port: 4173
},
testDir: 'tests',
testMatch: /(.+\.)?(test|spec)\.[jt]s/
webServer: {
command: 'npm run build && npm run preview',
port: 4173
// url: 'http://scott.localhost:5173',
// reuseExistingServer: true,
// stderr: 'pipe',
// stdout: 'pipe',
},
testDir: 'tests',
testMatch: /(.+\.)?(test|spec)\.[jt]s/,
reporter: 'list',
use: {
// Collect trace when retrying the failed test.
trace: 'on-first-retry'
}
// grep: /@node_modules/,
// grepInverse: /@node_modules/,
};
export default config;

View File

@@ -1,205 +1,166 @@
[data-theme='AE_c_IDAA_light'] {
--text-scaling: 1.067;
--base-font-color: var(--color-surface-950);
--text-scaling: 1.067;
--base-font-color: var(--color-surface-950);
--base-font-family: system-ui, sans-serif;
--base-font-size: inherit;
--base-line-height: inherit;
--base-font-weight: normal;
--base-font-style: normal;
--base-letter-spacing: 0em;
--heading-font-color: inherit;
--base-font-family: system-ui, sans-serif;
--base-font-size: inherit;
--base-line-height: inherit;
--base-font-weight: normal;
--base-font-style: normal;
--base-letter-spacing: 0em;
--heading-font-color: inherit;
--heading-font-family: inherit;
--heading-font-weight: bold;
--heading-font-style: normal;
--heading-letter-spacing: inherit;
--anchor-font-color: var(--color-primary-600);
--heading-font-family: inherit;
--heading-font-weight: bold;
--heading-font-style: normal;
--heading-letter-spacing: inherit;
--anchor-font-color: var(--color-primary-600);
--anchor-font-family: inherit;
--anchor-font-size: inherit;
--anchor-line-height: inherit;
--anchor-font-weight: inherit;
--anchor-font-style: inherit;
--anchor-letter-spacing: inherit;
--anchor-text-decoration: none;
--anchor-text-decoration-hover: underline;
--anchor-text-decoration-active: none;
--anchor-text-decoration-focus: none;
--spacing: 0.25rem;
--radius-base: 0.375rem;
--radius-container: 0.75rem;
--default-border-width: 1px;
--default-divide-width: 1px;
--default-ring-width: 1px;
--body-background-color: var(--color-surface-50);
--anchor-font-family: inherit;
--anchor-font-size: inherit;
--anchor-line-height: inherit;
--anchor-font-weight: inherit;
--anchor-font-style: inherit;
--anchor-letter-spacing: inherit;
--anchor-text-decoration: none;
--anchor-text-decoration-hover: underline;
--anchor-text-decoration-active: none;
--anchor-text-decoration-focus: none;
--spacing: 0.25rem;
--radius-base: 0.375rem;
--radius-container: 0.75rem;
--default-border-width: 1px;
--default-divide-width: 1px;
--default-ring-width: 1px;
--body-background-color: var(--color-surface-50);
--color-primary-50: oklch(85.73% 0.07 251.8deg);
--color-primary-100: oklch(78.5% 0.09 252.03deg);
--color-primary-200: oklch(71.06% 0.1 253.6deg);
--color-primary-300: oklch(63.76% 0.12 253.85deg);
--color-primary-400: oklch(56.32% 0.14 255.25deg);
--color-primary-500: oklch(49.23% 0.15 256.36deg);
--color-primary-600: oklch(43.11% 0.14 258.86deg);
--color-primary-700: oklch(36.85% 0.14 261.54deg);
--color-primary-800: oklch(30.41% 0.13 263.99deg);
--color-primary-900: oklch(23.91% 0.12 265.91deg);
--color-primary-950: oklch(16.96% 0.12 264.05deg);
--color-primary-50: oklch(85.73% 0.07 251.8deg);
--color-primary-100: oklch(78.5% 0.09 252.03deg);
--color-primary-200: oklch(71.06% 0.1 253.6deg);
--color-primary-300: oklch(63.76% 0.12 253.85deg);
--color-primary-400: oklch(56.32% 0.14 255.25deg);
--color-primary-500: oklch(49.23% 0.15 256.36deg);
--color-primary-600: oklch(43.11% 0.14 258.86deg);
--color-primary-700: oklch(36.85% 0.14 261.54deg);
--color-primary-800: oklch(30.41% 0.13 263.99deg);
--color-primary-900: oklch(23.91% 0.12 265.91deg);
--color-primary-950: oklch(16.96% 0.12 264.05deg);
--color-primary-contrast-light: var(--color-primary-50);
--color-primary-contrast-light: var(--color-primary-50);
--color-primary-contrast-500: var(--color-primary-contrast-light);
--color-primary-contrast-600: var(--color-primary-contrast-light);
--color-primary-contrast-700: var(--color-primary-contrast-light);
--color-primary-contrast-800: var(--color-primary-contrast-light);
--color-primary-contrast-900: var(--color-primary-contrast-light);
--color-primary-contrast-950: var(--color-primary-contrast-light);
--color-secondary-50: oklch(96.26% 0.06 196.24deg);
--color-secondary-100: oklch(89.14% 0.07 220.79deg);
--color-secondary-200: oklch(82.13% 0.08 234.87deg);
--color-secondary-300: oklch(75.03% 0.11 245.33deg);
--color-secondary-400: oklch(68.15% 0.14 250.72deg);
--color-secondary-500: oklch(61.37% 0.16 255.34deg);
--color-secondary-600: oklch(55.1% 0.16 256.81deg);
--color-secondary-700: oklch(48.64% 0.15 258.4deg);
--color-secondary-800: oklch(41.84% 0.15 260.39deg);
--color-secondary-900: oklch(35.05% 0.14 262.03deg);
--color-secondary-950: oklch(28.12% 0.14 262.47deg);
--color-secondary-contrast-light: var(--color-secondary-50);
--color-secondary-contrast-600: var(--color-secondary-contrast-light);
--color-secondary-contrast-700: var(--color-secondary-contrast-light);
--color-secondary-contrast-800: var(--color-secondary-contrast-light);
--color-secondary-contrast-900: var(--color-secondary-contrast-light);
--color-secondary-contrast-950: var(--color-secondary-contrast-light);
--color-tertiary-50: oklch(100% 0 none);
--color-tertiary-100: oklch(96.07% 0.01 251.15deg);
--color-tertiary-200: oklch(91.88% 0.03 252.69deg);
--color-tertiary-300: oklch(87.99% 0.05 253.24deg);
--color-tertiary-400: oklch(83.81% 0.06 253.57deg);
--color-tertiary-500: oklch(79.93% 0.08 253.32deg);
--color-tertiary-600: oklch(72.53% 0.08 251.75deg);
--color-tertiary-700: oklch(64.93% 0.08 249.75deg);
--color-tertiary-800: oklch(57.14% 0.09 247.99deg);
--color-tertiary-900: oklch(49.18% 0.09 246.55deg);
--color-tertiary-950: oklch(41.1% 0.09 246.54deg);
--color-tertiary-contrast-light: var(--color-tertiary-50);
--color-primary-contrast-500: var(--color-primary-contrast-light);
--color-primary-contrast-600: var(--color-primary-contrast-light);
--color-primary-contrast-700: var(--color-primary-contrast-light);
--color-primary-contrast-800: var(--color-primary-contrast-light);
--color-primary-contrast-900: var(--color-primary-contrast-light);
--color-primary-contrast-950: var(--color-primary-contrast-light);
--color-secondary-50: oklch(96.26% 0.06 196.24deg);
--color-secondary-100: oklch(89.14% 0.07 220.79deg);
--color-secondary-200: oklch(82.13% 0.08 234.87deg);
--color-secondary-300: oklch(75.03% 0.11 245.33deg);
--color-secondary-400: oklch(68.15% 0.14 250.72deg);
--color-secondary-500: oklch(61.37% 0.16 255.34deg);
--color-secondary-600: oklch(55.1% 0.16 256.81deg);
--color-secondary-700: oklch(48.64% 0.15 258.4deg);
--color-secondary-800: oklch(41.84% 0.15 260.39deg);
--color-secondary-900: oklch(35.05% 0.14 262.03deg);
--color-secondary-950: oklch(28.12% 0.14 262.47deg);
--color-tertiary-contrast-800: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-900: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-950: var(--color-tertiary-contrast-light);
--color-success-50: oklch(95.82% 0.06 184.52deg);
--color-success-100: oklch(91.55% 0.08 172.29deg);
--color-success-200: oklch(87.44% 0.11 165.22deg);
--color-success-300: oklch(83.26% 0.13 161.2deg);
--color-success-400: oklch(79.56% 0.16 157.13deg);
--color-success-500: oklch(76.12% 0.18 153.61deg);
--color-success-600: oklch(69.31% 0.17 151.81deg);
--color-success-700: oklch(62.07% 0.16 149.95deg);
--color-success-800: oklch(54.9% 0.15 147.65deg);
--color-success-900: oklch(47.26% 0.14 145.54deg);
--color-success-950: oklch(39.64% 0.13 143.79deg);
--color-secondary-contrast-light: var(--color-secondary-50);
--color-success-contrast-light: var(--color-success-50);
--color-success-contrast-800: var(--color-success-contrast-light);
--color-success-contrast-900: var(--color-success-contrast-light);
--color-success-contrast-950: var(--color-success-contrast-light);
--color-warning-50: oklch(98.26% 0.1 108.02deg);
--color-warning-100: oklch(95.84% 0.12 104.66deg);
--color-warning-200: oklch(93.48% 0.13 102.21deg);
--color-warning-300: oklch(91.49% 0.15 100.17deg);
--color-warning-400: oklch(89.28% 0.16 98.19deg);
--color-warning-500: oklch(87.14% 0.17 96.01deg);
--color-warning-600: oklch(79.88% 0.16 96.31deg);
--color-warning-700: oklch(72.35% 0.14 95.62deg);
--color-warning-800: oklch(64.73% 0.13 95.92deg);
--color-warning-900: oklch(56.77% 0.11 94.87deg);
--color-warning-950: oklch(48.63% 0.1 95.22deg);
--color-warning-contrast-light: var(--color-warning-50);
--color-warning-contrast-800: var(--color-warning-contrast-light);
--color-warning-contrast-900: var(--color-warning-contrast-light);
--color-warning-contrast-950: var(--color-warning-contrast-light);
--color-error-50: oklch(81.88% 0.1 38.14deg);
--color-error-100: oklch(75.88% 0.13 31.15deg);
--color-error-200: oklch(70.29% 0.16 27.32deg);
--color-error-300: oklch(65.15% 0.19 25.65deg);
--color-error-400: oklch(60.98% 0.21 25.56deg);
--color-error-500: oklch(57.86% 0.22 26.62deg);
--color-error-600: oklch(52.52% 0.2 26.86deg);
--color-error-700: oklch(46.81% 0.18 27.02deg);
--color-error-800: oklch(41.15% 0.16 27.63deg);
--color-error-900: oklch(35.01% 0.14 27.9deg);
--color-error-950: oklch(28.69% 0.12 29.23deg);
--color-error-contrast-light: var(--color-error-50);
--color-error-contrast-400: var(--color-error-contrast-light);
--color-error-contrast-500: var(--color-error-contrast-light);
--color-error-contrast-600: var(--color-error-contrast-light);
--color-error-contrast-700: var(--color-error-contrast-light);
--color-error-contrast-800: var(--color-error-contrast-light);
--color-error-contrast-900: var(--color-error-contrast-light);
--color-error-contrast-950: var(--color-error-contrast-light);
--color-surface-50: oklch(100% 0 none);
--color-surface-100: oklch(93.98% 0 105.57deg);
--color-surface-200: oklch(87.66% 0 67.88deg);
--color-surface-300: oklch(81.35% 0 106.1deg);
--color-surface-400: oklch(74.79% 0 84.45deg);
--color-surface-500: oklch(68.29% 0 91.36deg);
--color-surface-600: oklch(60.99% 0 91.38deg);
--color-surface-700: oklch(53.5% 0 84.49deg);
--color-surface-800: oklch(46.03% 0 91.43deg);
--color-surface-900: oklch(37.94% 0 84.52deg);
--color-surface-950: oklch(29.34% 0 84.54deg);
--color-secondary-contrast-600: var(--color-secondary-contrast-light);
--color-secondary-contrast-700: var(--color-secondary-contrast-light);
--color-secondary-contrast-800: var(--color-secondary-contrast-light);
--color-secondary-contrast-900: var(--color-secondary-contrast-light);
--color-secondary-contrast-950: var(--color-secondary-contrast-light);
--color-tertiary-50: oklch(100% 0 none);
--color-tertiary-100: oklch(96.07% 0.01 251.15deg);
--color-tertiary-200: oklch(91.88% 0.03 252.69deg);
--color-tertiary-300: oklch(87.99% 0.05 253.24deg);
--color-tertiary-400: oklch(83.81% 0.06 253.57deg);
--color-tertiary-500: oklch(79.93% 0.08 253.32deg);
--color-tertiary-600: oklch(72.53% 0.08 251.75deg);
--color-tertiary-700: oklch(64.93% 0.08 249.75deg);
--color-tertiary-800: oklch(57.14% 0.09 247.99deg);
--color-tertiary-900: oklch(49.18% 0.09 246.55deg);
--color-tertiary-950: oklch(41.1% 0.09 246.54deg);
--color-surface-contrast-light: var(--color-surface-50);
--color-tertiary-contrast-light: var(--color-tertiary-50);
--color-tertiary-contrast-800: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-900: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-950: var(--color-tertiary-contrast-light);
--color-success-50: oklch(95.82% 0.06 184.52deg);
--color-success-100: oklch(91.55% 0.08 172.29deg);
--color-success-200: oklch(87.44% 0.11 165.22deg);
--color-success-300: oklch(83.26% 0.13 161.2deg);
--color-success-400: oklch(79.56% 0.16 157.13deg);
--color-success-500: oklch(76.12% 0.18 153.61deg);
--color-success-600: oklch(69.31% 0.17 151.81deg);
--color-success-700: oklch(62.07% 0.16 149.95deg);
--color-success-800: oklch(54.9% 0.15 147.65deg);
--color-success-900: oklch(47.26% 0.14 145.54deg);
--color-success-950: oklch(39.64% 0.13 143.79deg);
--color-success-contrast-light: var(--color-success-50);
--color-success-contrast-800: var(--color-success-contrast-light);
--color-success-contrast-900: var(--color-success-contrast-light);
--color-success-contrast-950: var(--color-success-contrast-light);
--color-warning-50: oklch(98.26% 0.1 108.02deg);
--color-warning-100: oklch(95.84% 0.12 104.66deg);
--color-warning-200: oklch(93.48% 0.13 102.21deg);
--color-warning-300: oklch(91.49% 0.15 100.17deg);
--color-warning-400: oklch(89.28% 0.16 98.19deg);
--color-warning-500: oklch(87.14% 0.17 96.01deg);
--color-warning-600: oklch(79.88% 0.16 96.31deg);
--color-warning-700: oklch(72.35% 0.14 95.62deg);
--color-warning-800: oklch(64.73% 0.13 95.92deg);
--color-warning-900: oklch(56.77% 0.11 94.87deg);
--color-warning-950: oklch(48.63% 0.1 95.22deg);
--color-warning-contrast-light: var(--color-warning-50);
--color-warning-contrast-800: var(--color-warning-contrast-light);
--color-warning-contrast-900: var(--color-warning-contrast-light);
--color-warning-contrast-950: var(--color-warning-contrast-light);
--color-error-50: oklch(81.88% 0.1 38.14deg);
--color-error-100: oklch(75.88% 0.13 31.15deg);
--color-error-200: oklch(70.29% 0.16 27.32deg);
--color-error-300: oklch(65.15% 0.19 25.65deg);
--color-error-400: oklch(60.98% 0.21 25.56deg);
--color-error-500: oklch(57.86% 0.22 26.62deg);
--color-error-600: oklch(52.52% 0.2 26.86deg);
--color-error-700: oklch(46.81% 0.18 27.02deg);
--color-error-800: oklch(41.15% 0.16 27.63deg);
--color-error-900: oklch(35.01% 0.14 27.9deg);
--color-error-950: oklch(28.69% 0.12 29.23deg);
--color-error-contrast-light: var(--color-error-50);
--color-error-contrast-400: var(--color-error-contrast-light);
--color-error-contrast-500: var(--color-error-contrast-light);
--color-error-contrast-600: var(--color-error-contrast-light);
--color-error-contrast-700: var(--color-error-contrast-light);
--color-error-contrast-800: var(--color-error-contrast-light);
--color-error-contrast-900: var(--color-error-contrast-light);
--color-error-contrast-950: var(--color-error-contrast-light);
--color-surface-50: oklch(100% 0 none);
--color-surface-100: oklch(93.98% 0 105.57deg);
--color-surface-200: oklch(87.66% 0 67.88deg);
--color-surface-300: oklch(81.35% 0 106.1deg);
--color-surface-400: oklch(74.79% 0 84.45deg);
--color-surface-500: oklch(68.29% 0 91.36deg);
--color-surface-600: oklch(60.99% 0 91.38deg);
--color-surface-700: oklch(53.5% 0 84.49deg);
--color-surface-800: oklch(46.03% 0 91.43deg);
--color-surface-900: oklch(37.94% 0 84.52deg);
--color-surface-950: oklch(29.34% 0 84.54deg);
--color-surface-contrast-light: var(--color-surface-50);
--color-surface-contrast-700: var(--color-surface-contrast-light);
--color-surface-contrast-800: var(--color-surface-contrast-light);
--color-surface-contrast-900: var(--color-surface-contrast-light);
--color-surface-contrast-950: var(--color-surface-contrast-light);
}
--color-surface-contrast-700: var(--color-surface-contrast-light);
--color-surface-contrast-800: var(--color-surface-contrast-light);
--color-surface-contrast-900: var(--color-surface-contrast-light);
--color-surface-contrast-950: var(--color-surface-contrast-light);
}

View File

@@ -1,205 +1,205 @@
[data-theme='AE_c_LCI'] {
--text-scaling: 1.067;
--base-font-color: var(--color-surface-950);
--base-font-color-dark: var(--color-surface-50);
--base-font-family: system-ui, sans-serif;
--base-font-size: inherit;
--base-line-height: inherit;
--base-font-weight: normal;
--base-font-style: normal;
--base-letter-spacing: 0em;
--heading-font-color: inherit;
--heading-font-color-dark: inherit;
--heading-font-family: inherit;
--heading-font-weight: bold;
--heading-font-style: normal;
--heading-letter-spacing: inherit;
--anchor-font-color: var(--color-primary-500);
--anchor-font-color-dark: var(--color-primary-500);
--anchor-font-family: inherit;
--anchor-font-size: inherit;
--anchor-line-height: inherit;
--anchor-font-weight: inherit;
--anchor-font-style: inherit;
--anchor-letter-spacing: inherit;
--anchor-text-decoration: none;
--anchor-text-decoration-hover: underline;
--anchor-text-decoration-active: none;
--anchor-text-decoration-focus: none;
--spacing: 0.25rem;
--radius-base: 0.375rem;
--radius-container: 0.75rem;
--default-border-width: 1px;
--default-divide-width: 1px;
--default-ring-width: 1px;
--body-background-color: var(--color-surface-50);
--body-background-color-dark: var(--color-surface-950);
--color-primary-50: oklch(85.1% 0.07 265.19deg);
--color-primary-100: oklch(77.89% 0.08 264.31deg);
--color-primary-200: oklch(70.32% 0.08 264.44deg);
--color-primary-300: oklch(62.86% 0.09 263.87deg);
--color-primary-400: oklch(54.96% 0.1 263.8deg);
--color-primary-500: oklch(47.12% 0.11 262.88deg);
--color-primary-600: oklch(40.9% 0.1 264.73deg);
--color-primary-700: oklch(34.53% 0.1 267.34deg);
--color-primary-800: oklch(28.16% 0.09 268.81deg);
--color-primary-900: oklch(21.29% 0.09 271.12deg);
--color-primary-950: oklch(12.88% 0.09 264.05deg);
--color-primary-contrast-dark: var(--color-primary-950);
--color-primary-contrast-light: var(--color-primary-50);
--color-primary-contrast-50: var(--color-primary-contrast-dark);
--color-primary-contrast-100: var(--color-primary-contrast-dark);
--color-primary-contrast-200: var(--color-primary-contrast-dark);
--color-primary-contrast-300: var(--color-primary-contrast-dark);
--color-primary-contrast-400: var(--color-primary-contrast-dark);
--color-primary-contrast-500: var(--color-primary-contrast-light);
--color-primary-contrast-600: var(--color-primary-contrast-light);
--color-primary-contrast-700: var(--color-primary-contrast-light);
--color-primary-contrast-800: var(--color-primary-contrast-light);
--color-primary-contrast-900: var(--color-primary-contrast-light);
--color-primary-contrast-950: var(--color-primary-contrast-light);
--color-secondary-50: oklch(96.14% 0.06 196.21deg);
--color-secondary-100: oklch(89.81% 0.07 212.45deg);
--color-secondary-200: oklch(83.71% 0.08 223.06deg);
--color-secondary-300: oklch(77.42% 0.1 231.73deg);
--color-secondary-400: oklch(71.44% 0.12 237.59deg);
--color-secondary-500: oklch(65.39% 0.14 243.22deg);
--color-secondary-600: oklch(58.93% 0.13 245.07deg);
--color-secondary-700: oklch(52.09% 0.12 248.03deg);
--color-secondary-800: oklch(45.27% 0.12 250.54deg);
--color-secondary-900: oklch(38.01% 0.11 254.24deg);
--color-secondary-950: oklch(30.67% 0.11 256.73deg);
--color-secondary-contrast-dark: var(--color-secondary-950);
--color-secondary-contrast-light: var(--color-secondary-50);
--color-secondary-contrast-50: var(--color-secondary-contrast-dark);
--color-secondary-contrast-100: var(--color-secondary-contrast-dark);
--color-secondary-contrast-200: var(--color-secondary-contrast-dark);
--color-secondary-contrast-300: var(--color-secondary-contrast-dark);
--color-secondary-contrast-400: var(--color-secondary-contrast-dark);
--color-secondary-contrast-500: var(--color-secondary-contrast-dark);
--color-secondary-contrast-600: var(--color-secondary-contrast-dark);
--color-secondary-contrast-700: var(--color-secondary-contrast-light);
--color-secondary-contrast-800: var(--color-secondary-contrast-light);
--color-secondary-contrast-900: var(--color-secondary-contrast-light);
--color-secondary-contrast-950: var(--color-secondary-contrast-light);
--color-tertiary-50: oklch(87.75% 0.12 326.52deg);
--color-tertiary-100: oklch(80.92% 0.13 323.93deg);
--color-tertiary-200: oklch(73.87% 0.14 321.55deg);
--color-tertiary-300: oklch(66.9% 0.15 319.41deg);
--color-tertiary-400: oklch(59.72% 0.16 317.25deg);
--color-tertiary-500: oklch(52.73% 0.17 315.13deg);
--color-tertiary-600: oklch(46.6% 0.16 314.18deg);
--color-tertiary-700: oklch(40.43% 0.14 312.8deg);
--color-tertiary-800: oklch(33.85% 0.13 309.88deg);
--color-tertiary-900: oklch(27.23% 0.12 306.83deg);
--color-tertiary-950: oklch(19.83% 0.1 302.7deg);
--color-tertiary-contrast-dark: var(--color-tertiary-950);
--color-tertiary-contrast-light: var(--color-tertiary-50);
--color-tertiary-contrast-50: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-100: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-200: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-300: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-400: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-500: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-600: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-700: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-800: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-900: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-950: var(--color-tertiary-contrast-light);
--color-success-50: oklch(95.23% 0.07 195.99deg);
--color-success-100: oklch(90.22% 0.09 189.46deg);
--color-success-200: oklch(85.11% 0.1 186.03deg);
--color-success-300: oklch(80.35% 0.12 181.75deg);
--color-success-400: oklch(75.55% 0.12 178.92deg);
--color-success-500: oklch(71.19% 0.13 174.73deg);
--color-success-600: oklch(64.29% 0.12 173.65deg);
--color-success-700: oklch(57.46% 0.11 171.75deg);
--color-success-800: oklch(50.18% 0.1 170.68deg);
--color-success-900: oklch(42.87% 0.09 167.65deg);
--color-success-950: oklch(34.91% 0.07 164.42deg);
--color-success-contrast-dark: var(--color-success-950);
--color-success-contrast-light: var(--color-success-50);
--color-success-contrast-50: var(--color-success-contrast-dark);
--color-success-contrast-100: var(--color-success-contrast-dark);
--color-success-contrast-200: var(--color-success-contrast-dark);
--color-success-contrast-300: var(--color-success-contrast-dark);
--color-success-contrast-400: var(--color-success-contrast-dark);
--color-success-contrast-500: var(--color-success-contrast-dark);
--color-success-contrast-600: var(--color-success-contrast-dark);
--color-success-contrast-700: var(--color-success-contrast-light);
--color-success-contrast-800: var(--color-success-contrast-light);
--color-success-contrast-900: var(--color-success-contrast-light);
--color-success-contrast-950: var(--color-success-contrast-light);
--color-warning-50: oklch(95.67% 0.05 84.56deg);
--color-warning-100: oklch(92.83% 0.06 82.16deg);
--color-warning-200: oklch(90.12% 0.08 80.33deg);
--color-warning-300: oklch(87.59% 0.1 80.01deg);
--color-warning-400: oklch(85.03% 0.12 78.35deg);
--color-warning-500: oklch(82.46% 0.14 76.71deg);
--color-warning-600: oklch(76.34% 0.13 72.25deg);
--color-warning-700: oklch(70.34% 0.13 68.09deg);
--color-warning-800: oklch(63.99% 0.13 63.18deg);
--color-warning-900: oklch(57.91% 0.13 57.97deg);
--color-warning-950: oklch(51.69% 0.13 51.44deg);
--color-warning-contrast-dark: var(--color-warning-950);
--color-warning-contrast-light: var(--color-warning-50);
--color-warning-contrast-50: var(--color-warning-contrast-dark);
--color-warning-contrast-100: var(--color-warning-contrast-dark);
--color-warning-contrast-200: var(--color-warning-contrast-dark);
--color-warning-contrast-300: var(--color-warning-contrast-dark);
--color-warning-contrast-400: var(--color-warning-contrast-dark);
--color-warning-contrast-500: var(--color-warning-contrast-dark);
--color-warning-contrast-600: var(--color-warning-contrast-light);
--color-warning-contrast-700: var(--color-warning-contrast-light);
--color-warning-contrast-800: var(--color-warning-contrast-light);
--color-warning-contrast-900: var(--color-warning-contrast-light);
--color-warning-contrast-950: var(--color-warning-contrast-light);
--color-error-50: oklch(84.29% 0.09 46.91deg);
--color-error-100: oklch(78.63% 0.12 39.19deg);
--color-error-200: oklch(72.92% 0.14 34.35deg);
--color-error-300: oklch(67.88% 0.17 31.48deg);
--color-error-400: oklch(63.09% 0.19 30.02deg);
--color-error-500: oklch(59.32% 0.21 29.47deg);
--color-error-600: oklch(53.56% 0.19 29.25deg);
--color-error-700: oklch(47.75% 0.17 29.2deg);
--color-error-800: oklch(41.51% 0.15 28.7deg);
--color-error-900: oklch(35.35% 0.14 28.7deg);
--color-error-950: oklch(28.69% 0.12 29.23deg);
--color-error-contrast-dark: var(--color-error-950);
--color-error-contrast-light: var(--color-error-50);
--color-error-contrast-50: var(--color-error-contrast-dark);
--color-error-contrast-100: var(--color-error-contrast-dark);
--color-error-contrast-200: var(--color-error-contrast-dark);
--color-error-contrast-300: var(--color-error-contrast-dark);
--color-error-contrast-400: var(--color-error-contrast-dark);
--color-error-contrast-500: var(--color-error-contrast-light);
--color-error-contrast-600: var(--color-error-contrast-light);
--color-error-contrast-700: var(--color-error-contrast-light);
--color-error-contrast-800: var(--color-error-contrast-light);
--color-error-contrast-900: var(--color-error-contrast-light);
--color-error-contrast-950: var(--color-error-contrast-light);
--color-surface-50: oklch(100% 0 none);
--color-surface-100: oklch(97.02% 0 none);
--color-surface-200: oklch(94.01% 0 none);
--color-surface-300: oklch(91.12% 0 196.34deg);
--color-surface-400: oklch(88.07% 0 196.37deg);
--color-surface-500: oklch(84.99% 0 196.4deg);
--color-surface-600: oklch(77.78% 0 196.47deg);
--color-surface-700: oklch(70.09% 0 196.54deg);
--color-surface-800: oklch(62.51% 0 196.61deg);
--color-surface-900: oklch(54.34% 0 196.68deg);
--color-surface-950: oklch(46.22% 0 196.73deg);
--color-surface-contrast-dark: var(--color-surface-950);
--color-surface-contrast-light: var(--color-surface-50);
--color-surface-contrast-50: var(--color-surface-contrast-dark);
--color-surface-contrast-100: var(--color-surface-contrast-dark);
--color-surface-contrast-200: var(--color-surface-contrast-dark);
--color-surface-contrast-300: var(--color-surface-contrast-dark);
--color-surface-contrast-400: var(--color-surface-contrast-dark);
--color-surface-contrast-500: var(--color-surface-contrast-dark);
--color-surface-contrast-600: var(--color-surface-contrast-dark);
--color-surface-contrast-700: var(--color-surface-contrast-dark);
--color-surface-contrast-800: var(--color-surface-contrast-dark);
--color-surface-contrast-900: var(--color-surface-contrast-light);
--color-surface-contrast-950: var(--color-surface-contrast-light);
}
--text-scaling: 1.067;
--base-font-color: var(--color-surface-950);
--base-font-color-dark: var(--color-surface-50);
--base-font-family: system-ui, sans-serif;
--base-font-size: inherit;
--base-line-height: inherit;
--base-font-weight: normal;
--base-font-style: normal;
--base-letter-spacing: 0em;
--heading-font-color: inherit;
--heading-font-color-dark: inherit;
--heading-font-family: inherit;
--heading-font-weight: bold;
--heading-font-style: normal;
--heading-letter-spacing: inherit;
--anchor-font-color: var(--color-primary-500);
--anchor-font-color-dark: var(--color-primary-500);
--anchor-font-family: inherit;
--anchor-font-size: inherit;
--anchor-line-height: inherit;
--anchor-font-weight: inherit;
--anchor-font-style: inherit;
--anchor-letter-spacing: inherit;
--anchor-text-decoration: none;
--anchor-text-decoration-hover: underline;
--anchor-text-decoration-active: none;
--anchor-text-decoration-focus: none;
--spacing: 0.25rem;
--radius-base: 0.375rem;
--radius-container: 0.75rem;
--default-border-width: 1px;
--default-divide-width: 1px;
--default-ring-width: 1px;
--body-background-color: var(--color-surface-50);
--body-background-color-dark: var(--color-surface-950);
--color-primary-50: oklch(85.1% 0.07 265.19deg);
--color-primary-100: oklch(77.89% 0.08 264.31deg);
--color-primary-200: oklch(70.32% 0.08 264.44deg);
--color-primary-300: oklch(62.86% 0.09 263.87deg);
--color-primary-400: oklch(54.96% 0.1 263.8deg);
--color-primary-500: oklch(47.12% 0.11 262.88deg);
--color-primary-600: oklch(40.9% 0.1 264.73deg);
--color-primary-700: oklch(34.53% 0.1 267.34deg);
--color-primary-800: oklch(28.16% 0.09 268.81deg);
--color-primary-900: oklch(21.29% 0.09 271.12deg);
--color-primary-950: oklch(12.88% 0.09 264.05deg);
--color-primary-contrast-dark: var(--color-primary-950);
--color-primary-contrast-light: var(--color-primary-50);
--color-primary-contrast-50: var(--color-primary-contrast-dark);
--color-primary-contrast-100: var(--color-primary-contrast-dark);
--color-primary-contrast-200: var(--color-primary-contrast-dark);
--color-primary-contrast-300: var(--color-primary-contrast-dark);
--color-primary-contrast-400: var(--color-primary-contrast-dark);
--color-primary-contrast-500: var(--color-primary-contrast-light);
--color-primary-contrast-600: var(--color-primary-contrast-light);
--color-primary-contrast-700: var(--color-primary-contrast-light);
--color-primary-contrast-800: var(--color-primary-contrast-light);
--color-primary-contrast-900: var(--color-primary-contrast-light);
--color-primary-contrast-950: var(--color-primary-contrast-light);
--color-secondary-50: oklch(96.14% 0.06 196.21deg);
--color-secondary-100: oklch(89.81% 0.07 212.45deg);
--color-secondary-200: oklch(83.71% 0.08 223.06deg);
--color-secondary-300: oklch(77.42% 0.1 231.73deg);
--color-secondary-400: oklch(71.44% 0.12 237.59deg);
--color-secondary-500: oklch(65.39% 0.14 243.22deg);
--color-secondary-600: oklch(58.93% 0.13 245.07deg);
--color-secondary-700: oklch(52.09% 0.12 248.03deg);
--color-secondary-800: oklch(45.27% 0.12 250.54deg);
--color-secondary-900: oklch(38.01% 0.11 254.24deg);
--color-secondary-950: oklch(30.67% 0.11 256.73deg);
--color-secondary-contrast-dark: var(--color-secondary-950);
--color-secondary-contrast-light: var(--color-secondary-50);
--color-secondary-contrast-50: var(--color-secondary-contrast-dark);
--color-secondary-contrast-100: var(--color-secondary-contrast-dark);
--color-secondary-contrast-200: var(--color-secondary-contrast-dark);
--color-secondary-contrast-300: var(--color-secondary-contrast-dark);
--color-secondary-contrast-400: var(--color-secondary-contrast-dark);
--color-secondary-contrast-500: var(--color-secondary-contrast-dark);
--color-secondary-contrast-600: var(--color-secondary-contrast-dark);
--color-secondary-contrast-700: var(--color-secondary-contrast-light);
--color-secondary-contrast-800: var(--color-secondary-contrast-light);
--color-secondary-contrast-900: var(--color-secondary-contrast-light);
--color-secondary-contrast-950: var(--color-secondary-contrast-light);
--color-tertiary-50: oklch(87.75% 0.12 326.52deg);
--color-tertiary-100: oklch(80.92% 0.13 323.93deg);
--color-tertiary-200: oklch(73.87% 0.14 321.55deg);
--color-tertiary-300: oklch(66.9% 0.15 319.41deg);
--color-tertiary-400: oklch(59.72% 0.16 317.25deg);
--color-tertiary-500: oklch(52.73% 0.17 315.13deg);
--color-tertiary-600: oklch(46.6% 0.16 314.18deg);
--color-tertiary-700: oklch(40.43% 0.14 312.8deg);
--color-tertiary-800: oklch(33.85% 0.13 309.88deg);
--color-tertiary-900: oklch(27.23% 0.12 306.83deg);
--color-tertiary-950: oklch(19.83% 0.1 302.7deg);
--color-tertiary-contrast-dark: var(--color-tertiary-950);
--color-tertiary-contrast-light: var(--color-tertiary-50);
--color-tertiary-contrast-50: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-100: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-200: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-300: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-400: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-500: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-600: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-700: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-800: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-900: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-950: var(--color-tertiary-contrast-light);
--color-success-50: oklch(95.23% 0.07 195.99deg);
--color-success-100: oklch(90.22% 0.09 189.46deg);
--color-success-200: oklch(85.11% 0.1 186.03deg);
--color-success-300: oklch(80.35% 0.12 181.75deg);
--color-success-400: oklch(75.55% 0.12 178.92deg);
--color-success-500: oklch(71.19% 0.13 174.73deg);
--color-success-600: oklch(64.29% 0.12 173.65deg);
--color-success-700: oklch(57.46% 0.11 171.75deg);
--color-success-800: oklch(50.18% 0.1 170.68deg);
--color-success-900: oklch(42.87% 0.09 167.65deg);
--color-success-950: oklch(34.91% 0.07 164.42deg);
--color-success-contrast-dark: var(--color-success-950);
--color-success-contrast-light: var(--color-success-50);
--color-success-contrast-50: var(--color-success-contrast-dark);
--color-success-contrast-100: var(--color-success-contrast-dark);
--color-success-contrast-200: var(--color-success-contrast-dark);
--color-success-contrast-300: var(--color-success-contrast-dark);
--color-success-contrast-400: var(--color-success-contrast-dark);
--color-success-contrast-500: var(--color-success-contrast-dark);
--color-success-contrast-600: var(--color-success-contrast-dark);
--color-success-contrast-700: var(--color-success-contrast-light);
--color-success-contrast-800: var(--color-success-contrast-light);
--color-success-contrast-900: var(--color-success-contrast-light);
--color-success-contrast-950: var(--color-success-contrast-light);
--color-warning-50: oklch(95.67% 0.05 84.56deg);
--color-warning-100: oklch(92.83% 0.06 82.16deg);
--color-warning-200: oklch(90.12% 0.08 80.33deg);
--color-warning-300: oklch(87.59% 0.1 80.01deg);
--color-warning-400: oklch(85.03% 0.12 78.35deg);
--color-warning-500: oklch(82.46% 0.14 76.71deg);
--color-warning-600: oklch(76.34% 0.13 72.25deg);
--color-warning-700: oklch(70.34% 0.13 68.09deg);
--color-warning-800: oklch(63.99% 0.13 63.18deg);
--color-warning-900: oklch(57.91% 0.13 57.97deg);
--color-warning-950: oklch(51.69% 0.13 51.44deg);
--color-warning-contrast-dark: var(--color-warning-950);
--color-warning-contrast-light: var(--color-warning-50);
--color-warning-contrast-50: var(--color-warning-contrast-dark);
--color-warning-contrast-100: var(--color-warning-contrast-dark);
--color-warning-contrast-200: var(--color-warning-contrast-dark);
--color-warning-contrast-300: var(--color-warning-contrast-dark);
--color-warning-contrast-400: var(--color-warning-contrast-dark);
--color-warning-contrast-500: var(--color-warning-contrast-dark);
--color-warning-contrast-600: var(--color-warning-contrast-light);
--color-warning-contrast-700: var(--color-warning-contrast-light);
--color-warning-contrast-800: var(--color-warning-contrast-light);
--color-warning-contrast-900: var(--color-warning-contrast-light);
--color-warning-contrast-950: var(--color-warning-contrast-light);
--color-error-50: oklch(84.29% 0.09 46.91deg);
--color-error-100: oklch(78.63% 0.12 39.19deg);
--color-error-200: oklch(72.92% 0.14 34.35deg);
--color-error-300: oklch(67.88% 0.17 31.48deg);
--color-error-400: oklch(63.09% 0.19 30.02deg);
--color-error-500: oklch(59.32% 0.21 29.47deg);
--color-error-600: oklch(53.56% 0.19 29.25deg);
--color-error-700: oklch(47.75% 0.17 29.2deg);
--color-error-800: oklch(41.51% 0.15 28.7deg);
--color-error-900: oklch(35.35% 0.14 28.7deg);
--color-error-950: oklch(28.69% 0.12 29.23deg);
--color-error-contrast-dark: var(--color-error-950);
--color-error-contrast-light: var(--color-error-50);
--color-error-contrast-50: var(--color-error-contrast-dark);
--color-error-contrast-100: var(--color-error-contrast-dark);
--color-error-contrast-200: var(--color-error-contrast-dark);
--color-error-contrast-300: var(--color-error-contrast-dark);
--color-error-contrast-400: var(--color-error-contrast-dark);
--color-error-contrast-500: var(--color-error-contrast-light);
--color-error-contrast-600: var(--color-error-contrast-light);
--color-error-contrast-700: var(--color-error-contrast-light);
--color-error-contrast-800: var(--color-error-contrast-light);
--color-error-contrast-900: var(--color-error-contrast-light);
--color-error-contrast-950: var(--color-error-contrast-light);
--color-surface-50: oklch(100% 0 none);
--color-surface-100: oklch(97.02% 0 none);
--color-surface-200: oklch(94.01% 0 none);
--color-surface-300: oklch(91.12% 0 196.34deg);
--color-surface-400: oklch(88.07% 0 196.37deg);
--color-surface-500: oklch(84.99% 0 196.4deg);
--color-surface-600: oklch(77.78% 0 196.47deg);
--color-surface-700: oklch(70.09% 0 196.54deg);
--color-surface-800: oklch(62.51% 0 196.61deg);
--color-surface-900: oklch(54.34% 0 196.68deg);
--color-surface-950: oklch(46.22% 0 196.73deg);
--color-surface-contrast-dark: var(--color-surface-950);
--color-surface-contrast-light: var(--color-surface-50);
--color-surface-contrast-50: var(--color-surface-contrast-dark);
--color-surface-contrast-100: var(--color-surface-contrast-dark);
--color-surface-contrast-200: var(--color-surface-contrast-dark);
--color-surface-contrast-300: var(--color-surface-contrast-dark);
--color-surface-contrast-400: var(--color-surface-contrast-dark);
--color-surface-contrast-500: var(--color-surface-contrast-dark);
--color-surface-contrast-600: var(--color-surface-contrast-dark);
--color-surface-contrast-700: var(--color-surface-contrast-dark);
--color-surface-contrast-800: var(--color-surface-contrast-dark);
--color-surface-contrast-900: var(--color-surface-contrast-light);
--color-surface-contrast-950: var(--color-surface-contrast-light);
}

View File

@@ -1,205 +1,205 @@
[data-theme='AE_OSIT_default'] {
--text-scaling: 1.067;
--base-font-color: var(--color-surface-950);
--base-font-color-dark: var(--color-surface-50);
--base-font-family: system-ui, sans-serif;
--base-font-size: inherit;
--base-line-height: inherit;
--base-font-weight: normal;
--base-font-style: normal;
--base-letter-spacing: 0em;
--heading-font-color: inherit;
--heading-font-color-dark: inherit;
--heading-font-family: inherit;
--heading-font-weight: bold;
--heading-font-style: normal;
--heading-letter-spacing: inherit;
--anchor-font-color: var(--color-primary-600);
--anchor-font-color-dark: var(--color-primary-400);
--anchor-font-family: inherit;
--anchor-font-size: inherit;
--anchor-line-height: inherit;
--anchor-font-weight: inherit;
--anchor-font-style: inherit;
--anchor-letter-spacing: inherit;
--anchor-text-decoration: none;
--anchor-text-decoration-hover: underline;
--anchor-text-decoration-active: none;
--anchor-text-decoration-focus: none;
--spacing: 0.25rem;
--radius-base: 0.375rem;
--radius-container: 0.75rem;
--default-border-width: 1px;
--default-divide-width: 1px;
--default-ring-width: 1px;
--body-background-color: var(--color-surface-50);
--body-background-color-dark: var(--color-surface-950);
--color-primary-50: oklch(85.73% 0.07 251.8deg);
--color-primary-100: oklch(78.5% 0.09 252.03deg);
--color-primary-200: oklch(71.06% 0.1 253.6deg);
--color-primary-300: oklch(63.76% 0.12 253.85deg);
--color-primary-400: oklch(56.32% 0.14 255.25deg);
--color-primary-500: oklch(49.23% 0.15 256.36deg);
--color-primary-600: oklch(43.11% 0.14 258.86deg);
--color-primary-700: oklch(36.85% 0.14 261.54deg);
--color-primary-800: oklch(30.41% 0.13 263.99deg);
--color-primary-900: oklch(23.91% 0.12 265.91deg);
--color-primary-950: oklch(16.96% 0.12 264.05deg);
--color-primary-contrast-dark: var(--color-primary-950);
--color-primary-contrast-light: var(--color-primary-50);
--color-primary-contrast-50: var(--color-primary-contrast-dark);
--color-primary-contrast-100: var(--color-primary-contrast-dark);
--color-primary-contrast-200: var(--color-primary-contrast-dark);
--color-primary-contrast-300: var(--color-primary-contrast-dark);
--color-primary-contrast-400: var(--color-primary-contrast-dark);
--color-primary-contrast-500: var(--color-primary-contrast-light);
--color-primary-contrast-600: var(--color-primary-contrast-light);
--color-primary-contrast-700: var(--color-primary-contrast-light);
--color-primary-contrast-800: var(--color-primary-contrast-light);
--color-primary-contrast-900: var(--color-primary-contrast-light);
--color-primary-contrast-950: var(--color-primary-contrast-light);
--color-secondary-50: oklch(96.26% 0.06 196.24deg);
--color-secondary-100: oklch(89.14% 0.07 220.79deg);
--color-secondary-200: oklch(82.13% 0.08 234.87deg);
--color-secondary-300: oklch(75.03% 0.11 245.33deg);
--color-secondary-400: oklch(68.15% 0.14 250.72deg);
--color-secondary-500: oklch(61.37% 0.16 255.34deg);
--color-secondary-600: oklch(55.1% 0.16 256.81deg);
--color-secondary-700: oklch(48.64% 0.15 258.4deg);
--color-secondary-800: oklch(41.84% 0.15 260.39deg);
--color-secondary-900: oklch(35.05% 0.14 262.03deg);
--color-secondary-950: oklch(28.12% 0.14 262.47deg);
--color-secondary-contrast-dark: var(--color-secondary-950);
--color-secondary-contrast-light: var(--color-secondary-50);
--color-secondary-contrast-50: var(--color-secondary-contrast-dark);
--color-secondary-contrast-100: var(--color-secondary-contrast-dark);
--color-secondary-contrast-200: var(--color-secondary-contrast-dark);
--color-secondary-contrast-300: var(--color-secondary-contrast-dark);
--color-secondary-contrast-400: var(--color-secondary-contrast-dark);
--color-secondary-contrast-500: var(--color-secondary-contrast-dark);
--color-secondary-contrast-600: var(--color-secondary-contrast-light);
--color-secondary-contrast-700: var(--color-secondary-contrast-light);
--color-secondary-contrast-800: var(--color-secondary-contrast-light);
--color-secondary-contrast-900: var(--color-secondary-contrast-light);
--color-secondary-contrast-950: var(--color-secondary-contrast-light);
--color-tertiary-50: oklch(100% 0 none);
--color-tertiary-100: oklch(96.07% 0.01 251.15deg);
--color-tertiary-200: oklch(91.88% 0.03 252.69deg);
--color-tertiary-300: oklch(87.99% 0.05 253.24deg);
--color-tertiary-400: oklch(83.81% 0.06 253.57deg);
--color-tertiary-500: oklch(79.93% 0.08 253.32deg);
--color-tertiary-600: oklch(72.53% 0.08 251.75deg);
--color-tertiary-700: oklch(64.93% 0.08 249.75deg);
--color-tertiary-800: oklch(57.14% 0.09 247.99deg);
--color-tertiary-900: oklch(49.18% 0.09 246.55deg);
--color-tertiary-950: oklch(41.1% 0.09 246.54deg);
--color-tertiary-contrast-dark: var(--color-tertiary-950);
--color-tertiary-contrast-light: var(--color-tertiary-50);
--color-tertiary-contrast-50: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-100: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-200: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-300: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-400: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-500: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-600: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-700: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-800: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-900: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-950: var(--color-tertiary-contrast-light);
--color-success-50: oklch(95.82% 0.06 184.52deg);
--color-success-100: oklch(91.55% 0.08 172.29deg);
--color-success-200: oklch(87.44% 0.11 165.22deg);
--color-success-300: oklch(83.26% 0.13 161.2deg);
--color-success-400: oklch(79.56% 0.16 157.13deg);
--color-success-500: oklch(76.12% 0.18 153.61deg);
--color-success-600: oklch(69.31% 0.17 151.81deg);
--color-success-700: oklch(62.07% 0.16 149.95deg);
--color-success-800: oklch(54.9% 0.15 147.65deg);
--color-success-900: oklch(47.26% 0.14 145.54deg);
--color-success-950: oklch(39.64% 0.13 143.79deg);
--color-success-contrast-dark: var(--color-success-950);
--color-success-contrast-light: var(--color-success-50);
--color-success-contrast-50: var(--color-success-contrast-dark);
--color-success-contrast-100: var(--color-success-contrast-dark);
--color-success-contrast-200: var(--color-success-contrast-dark);
--color-success-contrast-300: var(--color-success-contrast-dark);
--color-success-contrast-400: var(--color-success-contrast-dark);
--color-success-contrast-500: var(--color-success-contrast-dark);
--color-success-contrast-600: var(--color-success-contrast-dark);
--color-success-contrast-700: var(--color-success-contrast-dark);
--color-success-contrast-800: var(--color-success-contrast-light);
--color-success-contrast-900: var(--color-success-contrast-light);
--color-success-contrast-950: var(--color-success-contrast-light);
--color-warning-50: oklch(98.26% 0.1 108.02deg);
--color-warning-100: oklch(95.84% 0.12 104.66deg);
--color-warning-200: oklch(93.48% 0.13 102.21deg);
--color-warning-300: oklch(91.49% 0.15 100.17deg);
--color-warning-400: oklch(89.28% 0.16 98.19deg);
--color-warning-500: oklch(87.14% 0.17 96.01deg);
--color-warning-600: oklch(79.88% 0.16 96.31deg);
--color-warning-700: oklch(72.35% 0.14 95.62deg);
--color-warning-800: oklch(64.73% 0.13 95.92deg);
--color-warning-900: oklch(56.77% 0.11 94.87deg);
--color-warning-950: oklch(48.63% 0.1 95.22deg);
--color-warning-contrast-dark: var(--color-warning-950);
--color-warning-contrast-light: var(--color-warning-50);
--color-warning-contrast-50: var(--color-warning-contrast-dark);
--color-warning-contrast-100: var(--color-warning-contrast-dark);
--color-warning-contrast-200: var(--color-warning-contrast-dark);
--color-warning-contrast-300: var(--color-warning-contrast-dark);
--color-warning-contrast-400: var(--color-warning-contrast-dark);
--color-warning-contrast-500: var(--color-warning-contrast-dark);
--color-warning-contrast-600: var(--color-warning-contrast-dark);
--color-warning-contrast-700: var(--color-warning-contrast-dark);
--color-warning-contrast-800: var(--color-warning-contrast-light);
--color-warning-contrast-900: var(--color-warning-contrast-light);
--color-warning-contrast-950: var(--color-warning-contrast-light);
--color-error-50: oklch(81.88% 0.1 38.14deg);
--color-error-100: oklch(75.88% 0.13 31.15deg);
--color-error-200: oklch(70.29% 0.16 27.32deg);
--color-error-300: oklch(65.15% 0.19 25.65deg);
--color-error-400: oklch(60.98% 0.21 25.56deg);
--color-error-500: oklch(57.86% 0.22 26.62deg);
--color-error-600: oklch(52.52% 0.2 26.86deg);
--color-error-700: oklch(46.81% 0.18 27.02deg);
--color-error-800: oklch(41.15% 0.16 27.63deg);
--color-error-900: oklch(35.01% 0.14 27.9deg);
--color-error-950: oklch(28.69% 0.12 29.23deg);
--color-error-contrast-dark: var(--color-error-950);
--color-error-contrast-light: var(--color-error-50);
--color-error-contrast-50: var(--color-error-contrast-dark);
--color-error-contrast-100: var(--color-error-contrast-dark);
--color-error-contrast-200: var(--color-error-contrast-dark);
--color-error-contrast-300: var(--color-error-contrast-dark);
--color-error-contrast-400: var(--color-error-contrast-light);
--color-error-contrast-500: var(--color-error-contrast-light);
--color-error-contrast-600: var(--color-error-contrast-light);
--color-error-contrast-700: var(--color-error-contrast-light);
--color-error-contrast-800: var(--color-error-contrast-light);
--color-error-contrast-900: var(--color-error-contrast-light);
--color-error-contrast-950: var(--color-error-contrast-light);
--color-surface-50: oklch(100% 0 none);
--color-surface-100: oklch(93.98% 0 105.57deg);
--color-surface-200: oklch(87.66% 0 67.88deg);
--color-surface-300: oklch(81.35% 0 106.1deg);
--color-surface-400: oklch(74.79% 0 84.45deg);
--color-surface-500: oklch(68.29% 0 91.36deg);
--color-surface-600: oklch(60.99% 0 91.38deg);
--color-surface-700: oklch(53.5% 0 84.49deg);
--color-surface-800: oklch(46.03% 0 91.43deg);
--color-surface-900: oklch(37.94% 0 84.52deg);
--color-surface-950: oklch(29.34% 0 84.54deg);
--color-surface-contrast-dark: var(--color-surface-950);
--color-surface-contrast-light: var(--color-surface-50);
--color-surface-contrast-50: var(--color-surface-contrast-dark);
--color-surface-contrast-100: var(--color-surface-contrast-dark);
--color-surface-contrast-200: var(--color-surface-contrast-dark);
--color-surface-contrast-300: var(--color-surface-contrast-dark);
--color-surface-contrast-400: var(--color-surface-contrast-dark);
--color-surface-contrast-500: var(--color-surface-contrast-dark);
--color-surface-contrast-600: var(--color-surface-contrast-dark);
--color-surface-contrast-700: var(--color-surface-contrast-light);
--color-surface-contrast-800: var(--color-surface-contrast-light);
--color-surface-contrast-900: var(--color-surface-contrast-light);
--color-surface-contrast-950: var(--color-surface-contrast-light);
}
--text-scaling: 1.067;
--base-font-color: var(--color-surface-950);
--base-font-color-dark: var(--color-surface-50);
--base-font-family: system-ui, sans-serif;
--base-font-size: inherit;
--base-line-height: inherit;
--base-font-weight: normal;
--base-font-style: normal;
--base-letter-spacing: 0em;
--heading-font-color: inherit;
--heading-font-color-dark: inherit;
--heading-font-family: inherit;
--heading-font-weight: bold;
--heading-font-style: normal;
--heading-letter-spacing: inherit;
--anchor-font-color: var(--color-primary-600);
--anchor-font-color-dark: var(--color-primary-400);
--anchor-font-family: inherit;
--anchor-font-size: inherit;
--anchor-line-height: inherit;
--anchor-font-weight: inherit;
--anchor-font-style: inherit;
--anchor-letter-spacing: inherit;
--anchor-text-decoration: none;
--anchor-text-decoration-hover: underline;
--anchor-text-decoration-active: none;
--anchor-text-decoration-focus: none;
--spacing: 0.25rem;
--radius-base: 0.375rem;
--radius-container: 0.75rem;
--default-border-width: 1px;
--default-divide-width: 1px;
--default-ring-width: 1px;
--body-background-color: var(--color-surface-50);
--body-background-color-dark: var(--color-surface-950);
--color-primary-50: oklch(85.73% 0.07 251.8deg);
--color-primary-100: oklch(78.5% 0.09 252.03deg);
--color-primary-200: oklch(71.06% 0.1 253.6deg);
--color-primary-300: oklch(63.76% 0.12 253.85deg);
--color-primary-400: oklch(56.32% 0.14 255.25deg);
--color-primary-500: oklch(49.23% 0.15 256.36deg);
--color-primary-600: oklch(43.11% 0.14 258.86deg);
--color-primary-700: oklch(36.85% 0.14 261.54deg);
--color-primary-800: oklch(30.41% 0.13 263.99deg);
--color-primary-900: oklch(23.91% 0.12 265.91deg);
--color-primary-950: oklch(16.96% 0.12 264.05deg);
--color-primary-contrast-dark: var(--color-primary-950);
--color-primary-contrast-light: var(--color-primary-50);
--color-primary-contrast-50: var(--color-primary-contrast-dark);
--color-primary-contrast-100: var(--color-primary-contrast-dark);
--color-primary-contrast-200: var(--color-primary-contrast-dark);
--color-primary-contrast-300: var(--color-primary-contrast-dark);
--color-primary-contrast-400: var(--color-primary-contrast-dark);
--color-primary-contrast-500: var(--color-primary-contrast-light);
--color-primary-contrast-600: var(--color-primary-contrast-light);
--color-primary-contrast-700: var(--color-primary-contrast-light);
--color-primary-contrast-800: var(--color-primary-contrast-light);
--color-primary-contrast-900: var(--color-primary-contrast-light);
--color-primary-contrast-950: var(--color-primary-contrast-light);
--color-secondary-50: oklch(96.26% 0.06 196.24deg);
--color-secondary-100: oklch(89.14% 0.07 220.79deg);
--color-secondary-200: oklch(82.13% 0.08 234.87deg);
--color-secondary-300: oklch(75.03% 0.11 245.33deg);
--color-secondary-400: oklch(68.15% 0.14 250.72deg);
--color-secondary-500: oklch(61.37% 0.16 255.34deg);
--color-secondary-600: oklch(55.1% 0.16 256.81deg);
--color-secondary-700: oklch(48.64% 0.15 258.4deg);
--color-secondary-800: oklch(41.84% 0.15 260.39deg);
--color-secondary-900: oklch(35.05% 0.14 262.03deg);
--color-secondary-950: oklch(28.12% 0.14 262.47deg);
--color-secondary-contrast-dark: var(--color-secondary-950);
--color-secondary-contrast-light: var(--color-secondary-50);
--color-secondary-contrast-50: var(--color-secondary-contrast-dark);
--color-secondary-contrast-100: var(--color-secondary-contrast-dark);
--color-secondary-contrast-200: var(--color-secondary-contrast-dark);
--color-secondary-contrast-300: var(--color-secondary-contrast-dark);
--color-secondary-contrast-400: var(--color-secondary-contrast-dark);
--color-secondary-contrast-500: var(--color-secondary-contrast-dark);
--color-secondary-contrast-600: var(--color-secondary-contrast-light);
--color-secondary-contrast-700: var(--color-secondary-contrast-light);
--color-secondary-contrast-800: var(--color-secondary-contrast-light);
--color-secondary-contrast-900: var(--color-secondary-contrast-light);
--color-secondary-contrast-950: var(--color-secondary-contrast-light);
--color-tertiary-50: oklch(100% 0 none);
--color-tertiary-100: oklch(96.07% 0.01 251.15deg);
--color-tertiary-200: oklch(91.88% 0.03 252.69deg);
--color-tertiary-300: oklch(87.99% 0.05 253.24deg);
--color-tertiary-400: oklch(83.81% 0.06 253.57deg);
--color-tertiary-500: oklch(79.93% 0.08 253.32deg);
--color-tertiary-600: oklch(72.53% 0.08 251.75deg);
--color-tertiary-700: oklch(64.93% 0.08 249.75deg);
--color-tertiary-800: oklch(57.14% 0.09 247.99deg);
--color-tertiary-900: oklch(49.18% 0.09 246.55deg);
--color-tertiary-950: oklch(41.1% 0.09 246.54deg);
--color-tertiary-contrast-dark: var(--color-tertiary-950);
--color-tertiary-contrast-light: var(--color-tertiary-50);
--color-tertiary-contrast-50: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-100: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-200: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-300: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-400: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-500: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-600: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-700: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-800: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-900: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-950: var(--color-tertiary-contrast-light);
--color-success-50: oklch(95.82% 0.06 184.52deg);
--color-success-100: oklch(91.55% 0.08 172.29deg);
--color-success-200: oklch(87.44% 0.11 165.22deg);
--color-success-300: oklch(83.26% 0.13 161.2deg);
--color-success-400: oklch(79.56% 0.16 157.13deg);
--color-success-500: oklch(76.12% 0.18 153.61deg);
--color-success-600: oklch(69.31% 0.17 151.81deg);
--color-success-700: oklch(62.07% 0.16 149.95deg);
--color-success-800: oklch(54.9% 0.15 147.65deg);
--color-success-900: oklch(47.26% 0.14 145.54deg);
--color-success-950: oklch(39.64% 0.13 143.79deg);
--color-success-contrast-dark: var(--color-success-950);
--color-success-contrast-light: var(--color-success-50);
--color-success-contrast-50: var(--color-success-contrast-dark);
--color-success-contrast-100: var(--color-success-contrast-dark);
--color-success-contrast-200: var(--color-success-contrast-dark);
--color-success-contrast-300: var(--color-success-contrast-dark);
--color-success-contrast-400: var(--color-success-contrast-dark);
--color-success-contrast-500: var(--color-success-contrast-dark);
--color-success-contrast-600: var(--color-success-contrast-dark);
--color-success-contrast-700: var(--color-success-contrast-dark);
--color-success-contrast-800: var(--color-success-contrast-light);
--color-success-contrast-900: var(--color-success-contrast-light);
--color-success-contrast-950: var(--color-success-contrast-light);
--color-warning-50: oklch(98.26% 0.1 108.02deg);
--color-warning-100: oklch(95.84% 0.12 104.66deg);
--color-warning-200: oklch(93.48% 0.13 102.21deg);
--color-warning-300: oklch(91.49% 0.15 100.17deg);
--color-warning-400: oklch(89.28% 0.16 98.19deg);
--color-warning-500: oklch(87.14% 0.17 96.01deg);
--color-warning-600: oklch(79.88% 0.16 96.31deg);
--color-warning-700: oklch(72.35% 0.14 95.62deg);
--color-warning-800: oklch(64.73% 0.13 95.92deg);
--color-warning-900: oklch(56.77% 0.11 94.87deg);
--color-warning-950: oklch(48.63% 0.1 95.22deg);
--color-warning-contrast-dark: var(--color-warning-950);
--color-warning-contrast-light: var(--color-warning-50);
--color-warning-contrast-50: var(--color-warning-contrast-dark);
--color-warning-contrast-100: var(--color-warning-contrast-dark);
--color-warning-contrast-200: var(--color-warning-contrast-dark);
--color-warning-contrast-300: var(--color-warning-contrast-dark);
--color-warning-contrast-400: var(--color-warning-contrast-dark);
--color-warning-contrast-500: var(--color-warning-contrast-dark);
--color-warning-contrast-600: var(--color-warning-contrast-dark);
--color-warning-contrast-700: var(--color-warning-contrast-dark);
--color-warning-contrast-800: var(--color-warning-contrast-light);
--color-warning-contrast-900: var(--color-warning-contrast-light);
--color-warning-contrast-950: var(--color-warning-contrast-light);
--color-error-50: oklch(81.88% 0.1 38.14deg);
--color-error-100: oklch(75.88% 0.13 31.15deg);
--color-error-200: oklch(70.29% 0.16 27.32deg);
--color-error-300: oklch(65.15% 0.19 25.65deg);
--color-error-400: oklch(60.98% 0.21 25.56deg);
--color-error-500: oklch(57.86% 0.22 26.62deg);
--color-error-600: oklch(52.52% 0.2 26.86deg);
--color-error-700: oklch(46.81% 0.18 27.02deg);
--color-error-800: oklch(41.15% 0.16 27.63deg);
--color-error-900: oklch(35.01% 0.14 27.9deg);
--color-error-950: oklch(28.69% 0.12 29.23deg);
--color-error-contrast-dark: var(--color-error-950);
--color-error-contrast-light: var(--color-error-50);
--color-error-contrast-50: var(--color-error-contrast-dark);
--color-error-contrast-100: var(--color-error-contrast-dark);
--color-error-contrast-200: var(--color-error-contrast-dark);
--color-error-contrast-300: var(--color-error-contrast-dark);
--color-error-contrast-400: var(--color-error-contrast-light);
--color-error-contrast-500: var(--color-error-contrast-light);
--color-error-contrast-600: var(--color-error-contrast-light);
--color-error-contrast-700: var(--color-error-contrast-light);
--color-error-contrast-800: var(--color-error-contrast-light);
--color-error-contrast-900: var(--color-error-contrast-light);
--color-error-contrast-950: var(--color-error-contrast-light);
--color-surface-50: oklch(100% 0 none);
--color-surface-100: oklch(93.98% 0 105.57deg);
--color-surface-200: oklch(87.66% 0 67.88deg);
--color-surface-300: oklch(81.35% 0 106.1deg);
--color-surface-400: oklch(74.79% 0 84.45deg);
--color-surface-500: oklch(68.29% 0 91.36deg);
--color-surface-600: oklch(60.99% 0 91.38deg);
--color-surface-700: oklch(53.5% 0 84.49deg);
--color-surface-800: oklch(46.03% 0 91.43deg);
--color-surface-900: oklch(37.94% 0 84.52deg);
--color-surface-950: oklch(29.34% 0 84.54deg);
--color-surface-contrast-dark: var(--color-surface-950);
--color-surface-contrast-light: var(--color-surface-50);
--color-surface-contrast-50: var(--color-surface-contrast-dark);
--color-surface-contrast-100: var(--color-surface-contrast-dark);
--color-surface-contrast-200: var(--color-surface-contrast-dark);
--color-surface-contrast-300: var(--color-surface-contrast-dark);
--color-surface-contrast-400: var(--color-surface-contrast-dark);
--color-surface-contrast-500: var(--color-surface-contrast-dark);
--color-surface-contrast-600: var(--color-surface-contrast-dark);
--color-surface-contrast-700: var(--color-surface-contrast-light);
--color-surface-contrast-800: var(--color-surface-contrast-light);
--color-surface-contrast-900: var(--color-surface-contrast-light);
--color-surface-contrast-950: var(--color-surface-contrast-light);
}

View File

@@ -1,205 +1,205 @@
[data-theme='aeclci'] {
--text-scaling: 1.067;
--base-font-color: var(--color-surface-950);
--base-font-color-dark: var(--color-surface-50);
--base-font-family: system-ui, sans-serif;
--base-font-size: inherit;
--base-line-height: inherit;
--base-font-weight: normal;
--base-font-style: normal;
--base-letter-spacing: 0em;
--heading-font-color: inherit;
--heading-font-color-dark: inherit;
--heading-font-family: inherit;
--heading-font-weight: bold;
--heading-font-style: normal;
--heading-letter-spacing: inherit;
--anchor-font-color: var(--color-primary-500);
--anchor-font-color-dark: var(--color-primary-500);
--anchor-font-family: inherit;
--anchor-font-size: inherit;
--anchor-line-height: inherit;
--anchor-font-weight: inherit;
--anchor-font-style: inherit;
--anchor-letter-spacing: inherit;
--anchor-text-decoration: none;
--anchor-text-decoration-hover: underline;
--anchor-text-decoration-active: none;
--anchor-text-decoration-focus: none;
--spacing: 0.25rem;
--radius-base: 0.375rem;
--radius-container: 0.75rem;
--default-border-width: 1px;
--default-divide-width: 1px;
--default-ring-width: 1px;
--body-background-color: var(--color-surface-50);
--body-background-color-dark: var(--color-surface-950);
--color-primary-50: oklch(85.1% 0.07 265.19deg);
--color-primary-100: oklch(77.89% 0.08 264.31deg);
--color-primary-200: oklch(70.32% 0.08 264.44deg);
--color-primary-300: oklch(62.86% 0.09 263.87deg);
--color-primary-400: oklch(54.96% 0.1 263.8deg);
--color-primary-500: oklch(47.12% 0.11 262.88deg);
--color-primary-600: oklch(40.9% 0.1 264.73deg);
--color-primary-700: oklch(34.53% 0.1 267.34deg);
--color-primary-800: oklch(28.16% 0.09 268.81deg);
--color-primary-900: oklch(21.29% 0.09 271.12deg);
--color-primary-950: oklch(12.88% 0.09 264.05deg);
--color-primary-contrast-dark: var(--color-primary-950);
--color-primary-contrast-light: var(--color-primary-50);
--color-primary-contrast-50: var(--color-primary-contrast-dark);
--color-primary-contrast-100: var(--color-primary-contrast-dark);
--color-primary-contrast-200: var(--color-primary-contrast-dark);
--color-primary-contrast-300: var(--color-primary-contrast-dark);
--color-primary-contrast-400: var(--color-primary-contrast-dark);
--color-primary-contrast-500: var(--color-primary-contrast-light);
--color-primary-contrast-600: var(--color-primary-contrast-light);
--color-primary-contrast-700: var(--color-primary-contrast-light);
--color-primary-contrast-800: var(--color-primary-contrast-light);
--color-primary-contrast-900: var(--color-primary-contrast-light);
--color-primary-contrast-950: var(--color-primary-contrast-light);
--color-secondary-50: oklch(73.24% 0.12 278.78deg);
--color-secondary-100: oklch(65.76% 0.12 276.12deg);
--color-secondary-200: oklch(58.15% 0.12 273.33deg);
--color-secondary-300: oklch(50.59% 0.12 270.28deg);
--color-secondary-400: oklch(42.65% 0.12 267.23deg);
--color-secondary-500: oklch(34.53% 0.12 264.22deg);
--color-secondary-600: oklch(30.3% 0.11 264.59deg);
--color-secondary-700: oklch(25.96% 0.09 265.69deg);
--color-secondary-800: oklch(21.25% 0.08 267.5deg);
--color-secondary-900: oklch(16.42% 0.06 269.55deg);
--color-secondary-950: oklch(8.85% 0.06 264.05deg);
--color-secondary-contrast-dark: var(--color-secondary-950);
--color-secondary-contrast-light: var(--color-secondary-50);
--color-secondary-contrast-50: var(--color-secondary-contrast-dark);
--color-secondary-contrast-100: var(--color-secondary-contrast-dark);
--color-secondary-contrast-200: var(--color-secondary-contrast-dark);
--color-secondary-contrast-300: var(--color-secondary-contrast-light);
--color-secondary-contrast-400: var(--color-secondary-contrast-light);
--color-secondary-contrast-500: var(--color-secondary-contrast-light);
--color-secondary-contrast-600: var(--color-secondary-contrast-light);
--color-secondary-contrast-700: var(--color-secondary-contrast-light);
--color-secondary-contrast-800: var(--color-secondary-contrast-light);
--color-secondary-contrast-900: var(--color-secondary-contrast-light);
--color-secondary-contrast-950: var(--color-secondary-contrast-light);
--color-tertiary-50: oklch(87.75% 0.12 326.52deg);
--color-tertiary-100: oklch(80.92% 0.13 323.93deg);
--color-tertiary-200: oklch(73.87% 0.14 321.55deg);
--color-tertiary-300: oklch(66.9% 0.15 319.41deg);
--color-tertiary-400: oklch(59.72% 0.16 317.25deg);
--color-tertiary-500: oklch(52.73% 0.17 315.13deg);
--color-tertiary-600: oklch(46.6% 0.16 314.18deg);
--color-tertiary-700: oklch(40.43% 0.14 312.8deg);
--color-tertiary-800: oklch(33.85% 0.13 309.88deg);
--color-tertiary-900: oklch(27.23% 0.12 306.83deg);
--color-tertiary-950: oklch(19.83% 0.1 302.7deg);
--color-tertiary-contrast-dark: var(--color-tertiary-950);
--color-tertiary-contrast-light: var(--color-tertiary-50);
--color-tertiary-contrast-50: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-100: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-200: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-300: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-400: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-500: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-600: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-700: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-800: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-900: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-950: var(--color-tertiary-contrast-light);
--color-success-50: oklch(95.23% 0.07 195.99deg);
--color-success-100: oklch(90.22% 0.09 189.46deg);
--color-success-200: oklch(85.11% 0.1 186.03deg);
--color-success-300: oklch(80.35% 0.12 181.75deg);
--color-success-400: oklch(75.55% 0.12 178.92deg);
--color-success-500: oklch(71.19% 0.13 174.73deg);
--color-success-600: oklch(64.29% 0.12 173.65deg);
--color-success-700: oklch(57.46% 0.11 171.75deg);
--color-success-800: oklch(50.18% 0.1 170.68deg);
--color-success-900: oklch(42.87% 0.09 167.65deg);
--color-success-950: oklch(34.91% 0.07 164.42deg);
--color-success-contrast-dark: var(--color-success-950);
--color-success-contrast-light: var(--color-success-50);
--color-success-contrast-50: var(--color-success-contrast-dark);
--color-success-contrast-100: var(--color-success-contrast-dark);
--color-success-contrast-200: var(--color-success-contrast-dark);
--color-success-contrast-300: var(--color-success-contrast-dark);
--color-success-contrast-400: var(--color-success-contrast-dark);
--color-success-contrast-500: var(--color-success-contrast-dark);
--color-success-contrast-600: var(--color-success-contrast-dark);
--color-success-contrast-700: var(--color-success-contrast-light);
--color-success-contrast-800: var(--color-success-contrast-light);
--color-success-contrast-900: var(--color-success-contrast-light);
--color-success-contrast-950: var(--color-success-contrast-light);
--color-warning-50: oklch(95.67% 0.05 84.56deg);
--color-warning-100: oklch(92.83% 0.06 82.16deg);
--color-warning-200: oklch(90.12% 0.08 80.33deg);
--color-warning-300: oklch(87.59% 0.1 80.01deg);
--color-warning-400: oklch(85.03% 0.12 78.35deg);
--color-warning-500: oklch(82.46% 0.14 76.71deg);
--color-warning-600: oklch(76.34% 0.13 72.25deg);
--color-warning-700: oklch(70.34% 0.13 68.09deg);
--color-warning-800: oklch(63.99% 0.13 63.18deg);
--color-warning-900: oklch(57.91% 0.13 57.97deg);
--color-warning-950: oklch(51.69% 0.13 51.44deg);
--color-warning-contrast-dark: var(--color-warning-950);
--color-warning-contrast-light: var(--color-warning-50);
--color-warning-contrast-50: var(--color-warning-contrast-dark);
--color-warning-contrast-100: var(--color-warning-contrast-dark);
--color-warning-contrast-200: var(--color-warning-contrast-dark);
--color-warning-contrast-300: var(--color-warning-contrast-dark);
--color-warning-contrast-400: var(--color-warning-contrast-dark);
--color-warning-contrast-500: var(--color-warning-contrast-dark);
--color-warning-contrast-600: var(--color-warning-contrast-light);
--color-warning-contrast-700: var(--color-warning-contrast-light);
--color-warning-contrast-800: var(--color-warning-contrast-light);
--color-warning-contrast-900: var(--color-warning-contrast-light);
--color-warning-contrast-950: var(--color-warning-contrast-light);
--color-error-50: oklch(84.29% 0.09 46.91deg);
--color-error-100: oklch(78.63% 0.12 39.19deg);
--color-error-200: oklch(72.92% 0.14 34.35deg);
--color-error-300: oklch(67.88% 0.17 31.48deg);
--color-error-400: oklch(63.09% 0.19 30.02deg);
--color-error-500: oklch(59.32% 0.21 29.47deg);
--color-error-600: oklch(53.56% 0.19 29.25deg);
--color-error-700: oklch(47.75% 0.17 29.2deg);
--color-error-800: oklch(41.51% 0.15 28.7deg);
--color-error-900: oklch(35.35% 0.14 28.7deg);
--color-error-950: oklch(28.69% 0.12 29.23deg);
--color-error-contrast-dark: var(--color-error-950);
--color-error-contrast-light: var(--color-error-50);
--color-error-contrast-50: var(--color-error-contrast-dark);
--color-error-contrast-100: var(--color-error-contrast-dark);
--color-error-contrast-200: var(--color-error-contrast-dark);
--color-error-contrast-300: var(--color-error-contrast-dark);
--color-error-contrast-400: var(--color-error-contrast-dark);
--color-error-contrast-500: var(--color-error-contrast-light);
--color-error-contrast-600: var(--color-error-contrast-light);
--color-error-contrast-700: var(--color-error-contrast-light);
--color-error-contrast-800: var(--color-error-contrast-light);
--color-error-contrast-900: var(--color-error-contrast-light);
--color-error-contrast-950: var(--color-error-contrast-light);
--color-surface-50: oklch(100% 0 none);
--color-surface-100: oklch(97.02% 0 none);
--color-surface-200: oklch(94.01% 0 none);
--color-surface-300: oklch(91.12% 0 196.34deg);
--color-surface-400: oklch(88.07% 0 196.37deg);
--color-surface-500: oklch(84.99% 0 196.4deg);
--color-surface-600: oklch(77.78% 0 196.47deg);
--color-surface-700: oklch(70.09% 0 196.54deg);
--color-surface-800: oklch(62.51% 0 196.61deg);
--color-surface-900: oklch(54.34% 0 196.68deg);
--color-surface-950: oklch(46.22% 0 196.73deg);
--color-surface-contrast-dark: var(--color-surface-950);
--color-surface-contrast-light: var(--color-surface-50);
--color-surface-contrast-50: var(--color-surface-contrast-dark);
--color-surface-contrast-100: var(--color-surface-contrast-dark);
--color-surface-contrast-200: var(--color-surface-contrast-dark);
--color-surface-contrast-300: var(--color-surface-contrast-dark);
--color-surface-contrast-400: var(--color-surface-contrast-dark);
--color-surface-contrast-500: var(--color-surface-contrast-dark);
--color-surface-contrast-600: var(--color-surface-contrast-dark);
--color-surface-contrast-700: var(--color-surface-contrast-dark);
--color-surface-contrast-800: var(--color-surface-contrast-dark);
--color-surface-contrast-900: var(--color-surface-contrast-light);
--color-surface-contrast-950: var(--color-surface-contrast-light);
}
--text-scaling: 1.067;
--base-font-color: var(--color-surface-950);
--base-font-color-dark: var(--color-surface-50);
--base-font-family: system-ui, sans-serif;
--base-font-size: inherit;
--base-line-height: inherit;
--base-font-weight: normal;
--base-font-style: normal;
--base-letter-spacing: 0em;
--heading-font-color: inherit;
--heading-font-color-dark: inherit;
--heading-font-family: inherit;
--heading-font-weight: bold;
--heading-font-style: normal;
--heading-letter-spacing: inherit;
--anchor-font-color: var(--color-primary-500);
--anchor-font-color-dark: var(--color-primary-500);
--anchor-font-family: inherit;
--anchor-font-size: inherit;
--anchor-line-height: inherit;
--anchor-font-weight: inherit;
--anchor-font-style: inherit;
--anchor-letter-spacing: inherit;
--anchor-text-decoration: none;
--anchor-text-decoration-hover: underline;
--anchor-text-decoration-active: none;
--anchor-text-decoration-focus: none;
--spacing: 0.25rem;
--radius-base: 0.375rem;
--radius-container: 0.75rem;
--default-border-width: 1px;
--default-divide-width: 1px;
--default-ring-width: 1px;
--body-background-color: var(--color-surface-50);
--body-background-color-dark: var(--color-surface-950);
--color-primary-50: oklch(85.1% 0.07 265.19deg);
--color-primary-100: oklch(77.89% 0.08 264.31deg);
--color-primary-200: oklch(70.32% 0.08 264.44deg);
--color-primary-300: oklch(62.86% 0.09 263.87deg);
--color-primary-400: oklch(54.96% 0.1 263.8deg);
--color-primary-500: oklch(47.12% 0.11 262.88deg);
--color-primary-600: oklch(40.9% 0.1 264.73deg);
--color-primary-700: oklch(34.53% 0.1 267.34deg);
--color-primary-800: oklch(28.16% 0.09 268.81deg);
--color-primary-900: oklch(21.29% 0.09 271.12deg);
--color-primary-950: oklch(12.88% 0.09 264.05deg);
--color-primary-contrast-dark: var(--color-primary-950);
--color-primary-contrast-light: var(--color-primary-50);
--color-primary-contrast-50: var(--color-primary-contrast-dark);
--color-primary-contrast-100: var(--color-primary-contrast-dark);
--color-primary-contrast-200: var(--color-primary-contrast-dark);
--color-primary-contrast-300: var(--color-primary-contrast-dark);
--color-primary-contrast-400: var(--color-primary-contrast-dark);
--color-primary-contrast-500: var(--color-primary-contrast-light);
--color-primary-contrast-600: var(--color-primary-contrast-light);
--color-primary-contrast-700: var(--color-primary-contrast-light);
--color-primary-contrast-800: var(--color-primary-contrast-light);
--color-primary-contrast-900: var(--color-primary-contrast-light);
--color-primary-contrast-950: var(--color-primary-contrast-light);
--color-secondary-50: oklch(73.24% 0.12 278.78deg);
--color-secondary-100: oklch(65.76% 0.12 276.12deg);
--color-secondary-200: oklch(58.15% 0.12 273.33deg);
--color-secondary-300: oklch(50.59% 0.12 270.28deg);
--color-secondary-400: oklch(42.65% 0.12 267.23deg);
--color-secondary-500: oklch(34.53% 0.12 264.22deg);
--color-secondary-600: oklch(30.3% 0.11 264.59deg);
--color-secondary-700: oklch(25.96% 0.09 265.69deg);
--color-secondary-800: oklch(21.25% 0.08 267.5deg);
--color-secondary-900: oklch(16.42% 0.06 269.55deg);
--color-secondary-950: oklch(8.85% 0.06 264.05deg);
--color-secondary-contrast-dark: var(--color-secondary-950);
--color-secondary-contrast-light: var(--color-secondary-50);
--color-secondary-contrast-50: var(--color-secondary-contrast-dark);
--color-secondary-contrast-100: var(--color-secondary-contrast-dark);
--color-secondary-contrast-200: var(--color-secondary-contrast-dark);
--color-secondary-contrast-300: var(--color-secondary-contrast-light);
--color-secondary-contrast-400: var(--color-secondary-contrast-light);
--color-secondary-contrast-500: var(--color-secondary-contrast-light);
--color-secondary-contrast-600: var(--color-secondary-contrast-light);
--color-secondary-contrast-700: var(--color-secondary-contrast-light);
--color-secondary-contrast-800: var(--color-secondary-contrast-light);
--color-secondary-contrast-900: var(--color-secondary-contrast-light);
--color-secondary-contrast-950: var(--color-secondary-contrast-light);
--color-tertiary-50: oklch(87.75% 0.12 326.52deg);
--color-tertiary-100: oklch(80.92% 0.13 323.93deg);
--color-tertiary-200: oklch(73.87% 0.14 321.55deg);
--color-tertiary-300: oklch(66.9% 0.15 319.41deg);
--color-tertiary-400: oklch(59.72% 0.16 317.25deg);
--color-tertiary-500: oklch(52.73% 0.17 315.13deg);
--color-tertiary-600: oklch(46.6% 0.16 314.18deg);
--color-tertiary-700: oklch(40.43% 0.14 312.8deg);
--color-tertiary-800: oklch(33.85% 0.13 309.88deg);
--color-tertiary-900: oklch(27.23% 0.12 306.83deg);
--color-tertiary-950: oklch(19.83% 0.1 302.7deg);
--color-tertiary-contrast-dark: var(--color-tertiary-950);
--color-tertiary-contrast-light: var(--color-tertiary-50);
--color-tertiary-contrast-50: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-100: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-200: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-300: var(--color-tertiary-contrast-dark);
--color-tertiary-contrast-400: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-500: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-600: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-700: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-800: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-900: var(--color-tertiary-contrast-light);
--color-tertiary-contrast-950: var(--color-tertiary-contrast-light);
--color-success-50: oklch(95.23% 0.07 195.99deg);
--color-success-100: oklch(90.22% 0.09 189.46deg);
--color-success-200: oklch(85.11% 0.1 186.03deg);
--color-success-300: oklch(80.35% 0.12 181.75deg);
--color-success-400: oklch(75.55% 0.12 178.92deg);
--color-success-500: oklch(71.19% 0.13 174.73deg);
--color-success-600: oklch(64.29% 0.12 173.65deg);
--color-success-700: oklch(57.46% 0.11 171.75deg);
--color-success-800: oklch(50.18% 0.1 170.68deg);
--color-success-900: oklch(42.87% 0.09 167.65deg);
--color-success-950: oklch(34.91% 0.07 164.42deg);
--color-success-contrast-dark: var(--color-success-950);
--color-success-contrast-light: var(--color-success-50);
--color-success-contrast-50: var(--color-success-contrast-dark);
--color-success-contrast-100: var(--color-success-contrast-dark);
--color-success-contrast-200: var(--color-success-contrast-dark);
--color-success-contrast-300: var(--color-success-contrast-dark);
--color-success-contrast-400: var(--color-success-contrast-dark);
--color-success-contrast-500: var(--color-success-contrast-dark);
--color-success-contrast-600: var(--color-success-contrast-dark);
--color-success-contrast-700: var(--color-success-contrast-light);
--color-success-contrast-800: var(--color-success-contrast-light);
--color-success-contrast-900: var(--color-success-contrast-light);
--color-success-contrast-950: var(--color-success-contrast-light);
--color-warning-50: oklch(95.67% 0.05 84.56deg);
--color-warning-100: oklch(92.83% 0.06 82.16deg);
--color-warning-200: oklch(90.12% 0.08 80.33deg);
--color-warning-300: oklch(87.59% 0.1 80.01deg);
--color-warning-400: oklch(85.03% 0.12 78.35deg);
--color-warning-500: oklch(82.46% 0.14 76.71deg);
--color-warning-600: oklch(76.34% 0.13 72.25deg);
--color-warning-700: oklch(70.34% 0.13 68.09deg);
--color-warning-800: oklch(63.99% 0.13 63.18deg);
--color-warning-900: oklch(57.91% 0.13 57.97deg);
--color-warning-950: oklch(51.69% 0.13 51.44deg);
--color-warning-contrast-dark: var(--color-warning-950);
--color-warning-contrast-light: var(--color-warning-50);
--color-warning-contrast-50: var(--color-warning-contrast-dark);
--color-warning-contrast-100: var(--color-warning-contrast-dark);
--color-warning-contrast-200: var(--color-warning-contrast-dark);
--color-warning-contrast-300: var(--color-warning-contrast-dark);
--color-warning-contrast-400: var(--color-warning-contrast-dark);
--color-warning-contrast-500: var(--color-warning-contrast-dark);
--color-warning-contrast-600: var(--color-warning-contrast-light);
--color-warning-contrast-700: var(--color-warning-contrast-light);
--color-warning-contrast-800: var(--color-warning-contrast-light);
--color-warning-contrast-900: var(--color-warning-contrast-light);
--color-warning-contrast-950: var(--color-warning-contrast-light);
--color-error-50: oklch(84.29% 0.09 46.91deg);
--color-error-100: oklch(78.63% 0.12 39.19deg);
--color-error-200: oklch(72.92% 0.14 34.35deg);
--color-error-300: oklch(67.88% 0.17 31.48deg);
--color-error-400: oklch(63.09% 0.19 30.02deg);
--color-error-500: oklch(59.32% 0.21 29.47deg);
--color-error-600: oklch(53.56% 0.19 29.25deg);
--color-error-700: oklch(47.75% 0.17 29.2deg);
--color-error-800: oklch(41.51% 0.15 28.7deg);
--color-error-900: oklch(35.35% 0.14 28.7deg);
--color-error-950: oklch(28.69% 0.12 29.23deg);
--color-error-contrast-dark: var(--color-error-950);
--color-error-contrast-light: var(--color-error-50);
--color-error-contrast-50: var(--color-error-contrast-dark);
--color-error-contrast-100: var(--color-error-contrast-dark);
--color-error-contrast-200: var(--color-error-contrast-dark);
--color-error-contrast-300: var(--color-error-contrast-dark);
--color-error-contrast-400: var(--color-error-contrast-dark);
--color-error-contrast-500: var(--color-error-contrast-light);
--color-error-contrast-600: var(--color-error-contrast-light);
--color-error-contrast-700: var(--color-error-contrast-light);
--color-error-contrast-800: var(--color-error-contrast-light);
--color-error-contrast-900: var(--color-error-contrast-light);
--color-error-contrast-950: var(--color-error-contrast-light);
--color-surface-50: oklch(100% 0 none);
--color-surface-100: oklch(97.02% 0 none);
--color-surface-200: oklch(94.01% 0 none);
--color-surface-300: oklch(91.12% 0 196.34deg);
--color-surface-400: oklch(88.07% 0 196.37deg);
--color-surface-500: oklch(84.99% 0 196.4deg);
--color-surface-600: oklch(77.78% 0 196.47deg);
--color-surface-700: oklch(70.09% 0 196.54deg);
--color-surface-800: oklch(62.51% 0 196.61deg);
--color-surface-900: oklch(54.34% 0 196.68deg);
--color-surface-950: oklch(46.22% 0 196.73deg);
--color-surface-contrast-dark: var(--color-surface-950);
--color-surface-contrast-light: var(--color-surface-50);
--color-surface-contrast-50: var(--color-surface-contrast-dark);
--color-surface-contrast-100: var(--color-surface-contrast-dark);
--color-surface-contrast-200: var(--color-surface-contrast-dark);
--color-surface-contrast-300: var(--color-surface-contrast-dark);
--color-surface-contrast-400: var(--color-surface-contrast-dark);
--color-surface-contrast-500: var(--color-surface-contrast-dark);
--color-surface-contrast-600: var(--color-surface-contrast-dark);
--color-surface-contrast-700: var(--color-surface-contrast-dark);
--color-surface-contrast-800: var(--color-surface-contrast-dark);
--color-surface-contrast-900: var(--color-surface-contrast-light);
--color-surface-contrast-950: var(--color-surface-contrast-light);
}

View File

@@ -1,7 +1,7 @@
@import 'tailwindcss';
@import "@skeletonlabs/skeleton";
@import "@skeletonlabs/skeleton/optional/presets";
@import '@skeletonlabs/skeleton';
/* Register Preset Themes */
/* @import '@skeletonlabs/skeleton/themes/{theme-name}'; */
@@ -15,6 +15,7 @@
@import '@skeletonlabs/skeleton/themes/terminus';
@import '@skeletonlabs/skeleton/themes/vintage';
@import '@skeletonlabs/skeleton/themes/wintry';
/* @import '@skeletonlabs/skeleton/themes/ae_c_osit'; */
/* @import '@skeletonlabs/skeleton/themes/ae_c_lci'; */
@import './ae-osit-default.css';
@@ -23,18 +24,15 @@
@source '../node_modules/@skeletonlabs/skeleton-svelte/dist';
/* Add your theme import for your theme: "osit-custom-theme" here */
/* @plugin '@tailwindcss/forms'; */
/* @plugin '@tailwindcss/typography'; */
/* @import "tailwindcss/theme.css" layer(theme); */
/* @import "tailwindcss/preflight"; */
@import "tailwindcss/utilities.css" layer(utilities);
@import 'tailwindcss/utilities.css' layer(utilities);
/*@tailwind utilities;*/
/* Register a Custom Themes */
/* Make sure to resolve the relative path. */
/* Note the .css extension is optional. */
@@ -45,40 +43,39 @@
/* https://www.skeleton.dev/docs/guides/cookbook/light-switch */
/* @custom-variant dark (&:where([data-mode="dark"], [data-mode="dark"] *)); */
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 224 71.4% 4.1%;
--muted: 220 14.3% 95.9%;
--muted-foreground: 220 8.9% 46.1%;
--popover: 0 0% 100%;
--popover-foreground: 224 71.4% 4.1%;
--card: 0 0% 100%;
--card-foreground: 224 71.4% 4.1%;
--border: 220 13% 91%;
--input: 220 13% 91%;
--primary: 220.9 39.3% 11%;
--primary-foreground: 210 20% 98%;
--secondary: 220 14.3% 95.9%;
--secondary-foreground: 220.9 39.3% 11%;
--accent: 220 14.3% 95.9%;
--accent-foreground: 220.9 39.3% 11%;
--destructive: 0 72.2% 50.6%;
--destructive-foreground: 210 20% 98%;
--ring: 224 71.4% 4.1%;
--radius: 0.5rem;
--sidebar-background: 0 0% 98%;
--sidebar-foreground: 240 5.3% 26.1%;
--sidebar-primary: 240 5.9% 10%;
--sidebar-primary-foreground: 0 0% 98%;
--sidebar-accent: 240 4.8% 95.9%;
--sidebar-accent-foreground: 240 5.9% 10%;
--sidebar-border: 220 13% 91%;
--sidebar-ring: 217.2 91.2% 59.8%;
}
:root {
--background: 0 0% 100%;
--foreground: 224 71.4% 4.1%;
--muted: 220 14.3% 95.9%;
--muted-foreground: 220 8.9% 46.1%;
--popover: 0 0% 100%;
--popover-foreground: 224 71.4% 4.1%;
--card: 0 0% 100%;
--card-foreground: 224 71.4% 4.1%;
--border: 220 13% 91%;
--input: 220 13% 91%;
--primary: 220.9 39.3% 11%;
--primary-foreground: 210 20% 98%;
--secondary: 220 14.3% 95.9%;
--secondary-foreground: 220.9 39.3% 11%;
--accent: 220 14.3% 95.9%;
--accent-foreground: 220.9 39.3% 11%;
--destructive: 0 72.2% 50.6%;
--destructive-foreground: 210 20% 98%;
--ring: 224 71.4% 4.1%;
--radius: 0.5rem;
--sidebar-background: 0 0% 98%;
--sidebar-foreground: 240 5.3% 26.1%;
--sidebar-primary: 240 5.9% 10%;
--sidebar-primary-foreground: 0 0% 98%;
--sidebar-accent: 240 4.8% 95.9%;
--sidebar-accent-foreground: 240 5.9% 10%;
--sidebar-border: 220 13% 91%;
--sidebar-ring: 217.2 91.2% 59.8%;
}
/* .dark {
/* .dark {
--background: 224 71.4% 4.1%;
--foreground: 210 20% 98%;
--muted: 215 27.9% 16.9%;
@@ -110,18 +107,15 @@
}
@layer base {
* {
border-color: hsl(var(--border));
}
body {
background-color: hsl(var(--background));
color: hsl(var(--foreground));
}
* {
border-color: hsl(var(--border));
}
body {
background-color: hsl(var(--background));
color: hsl(var(--foreground));
}
}
/* There are no more Tailwind layers. */
html,
@@ -163,11 +157,11 @@ html.trusted_access #appShell {
}
/* :root [data-theme='modern'] { */
/* --theme-rounded-base: 20px;
/* --theme-rounded-base: 20px;
--theme-rounded-container: 4px; */
/* --theme-font-family-base: 'Liberation Sans', sans-serif; */
/* --theme-font-family-heading: 'Liberation Sans', sans-serif; */
/* --theme-font-family-base: 'Liberation Sans', sans-serif; */
/* --theme-font-family-heading: 'Liberation Sans', sans-serif; */
/* } */
/* Using Skeleton Tailwind Presets */
@@ -281,10 +275,10 @@ html.trusted_access #appShell {
/* Buttons default to the tonal presets */
/* Buttons based on Skeleton Tailwind preset classes */
.ae_btn_neutral {
@apply preset-tonal hover:preset-outlined border transition-all;
/* @apply preset-tonal hover:preset-outlined border transition-all; */
}
.ae_btn_primary {
@apply preset-tonal-primary border border-primary-500 transition-all;
/* @apply preset-tonal-primary border border-primary-500 transition-all; */
}
.ae_btn_secondary {
@apply preset-tonal-secondary border border-secondary-500 transition-all;
@@ -346,7 +340,6 @@ html.trusted_access #appShell {
@apply border text-cyan-950 dark:text-cyan-50 bg-cyan-50 dark:bg-cyan-950 border-cyan-200 dark:border-cyan-800 transition-all;
}
/* Containers customized for Aether using Skeleton Tailwind preset classes */
.ae_container_system_menu {
@apply container;
@@ -368,7 +361,7 @@ html.trusted_access #appShell {
.ae_module_header {
/* LCI request 3a5997 */
/* bg-gray-300 */
@apply preset-tonal-surface rounded-md flex flex-row gap-0.25 items-center justify-between w-full p-1 px-2;
@apply preset-tonal-surface rounded-md flex flex-col md:flex-row flex-wrap gap-0.25 items-center justify-between w-full max-w-7xl p-1 px-2;
}
[data-theme='AE_c_LCI'] .ae_module_header {
@@ -385,12 +378,11 @@ html.trusted_access #appShell {
@apply container;
}
.ae_container_module_menu {
@apply w-full flex flex-col items-center justify-center gap-1 p-1
@apply w-full max-w-7xl flex flex-col items-center justify-center gap-1 p-1
border rounded-md border-gray-200 dark:border-gray-800 hover:bg-gray-100 dark:hover:bg-gray-900 transition-all duration-700 hover:duration-300;
}
.ae_container_module_options {
@apply
text-cyan-950 dark:text-cyan-50
@apply text-cyan-950 dark:text-cyan-50
bg-cyan-50 dark:bg-cyan-950 hover:bg-cyan-100 dark:hover:bg-cyan-900
border border-cyan-200 dark:border-cyan-800 hover:border-cyan-400 dark:hover:border-cyan-600
rounded-md
@@ -400,8 +392,7 @@ html.trusted_access #appShell {
transition-all;
}
.ae_container_module_help {
@apply
text-yellow-950 dark:text-yellow-50
@apply text-yellow-950 dark:text-yellow-50
bg-yellow-50 dark:bg-yellow-950 hover:bg-yellow-100 dark:hover:bg-yellow-900
border border-yellow-200 dark:border-yellow-800 hover:border-yellow-400 dark:hover:border-yellow-600
rounded-md
@@ -434,8 +425,7 @@ html.trusted_access #appShell {
@apply container;
}
.ae_container_help {
@apply
text-yellow-950 dark:text-yellow-50
@apply text-yellow-950 dark:text-yellow-50
bg-yellow-50 dark:bg-yellow-950 hover:bg-yellow-100 dark:hover:bg-yellow-900
border border-yellow-200 dark:border-yellow-800 hover:border-yellow-400 dark:hover:border-yellow-600
rounded-md
@@ -445,8 +435,7 @@ html.trusted_access #appShell {
/* bg-yellow-100 border border-yellow-400 p-2 rounded-md max-w-xl */
}
.ae_container_info {
@apply
text-cyan-950 dark:text-cyan-50
@apply text-cyan-950 dark:text-cyan-50
bg-cyan-50 dark:bg-cyan-950 hover:bg-cyan-100 dark:hover:bg-cyan-900
border border-cyan-200 dark:border-cyan-800 hover:border-cyan-400 dark:hover:border-cyan-600
rounded-md
@@ -477,7 +466,6 @@ html.trusted_access #appShell {
@apply container;
}
/* Standard Aether object properties:
* - id
* - name
@@ -489,29 +477,24 @@ html.trusted_access #appShell {
* - notes
*/
.card-footer {
border-top: 1px solid hsla(0, 0%, 0%, 0.5);
margin-top: 1em;
padding-top: 1em;
opacity: .5;
opacity: 0.5;
}
/* Tailwind: This "fixes" Tailwind's default group button styles that do not seem to allow hiding buttons. */
.btn-group a.hidden, .btn-group button.hidden {
.btn-group a.hidden,
.btn-group button.hidden {
display: none;
}
.ae_d_none {
display: none;
}
/* Allow content to scroll horizontal if too wide */
.ae_h_scrollfix {
max-width: 100%;
@@ -524,7 +507,6 @@ html.trusted_access #appShell {
overflow-y: auto;
max-height: 96vh;
/* max-height: 99%; */
}
.ae_debug {
@@ -536,12 +518,11 @@ html.trusted_access #appShell {
}
.ae_debug:hover {
/* A darker pink outline */
outline-color: hsla(0, 100%, 50%, 0.50);
outline-color: hsla(0, 100%, 50%, 0.5);
/* A light pink background color */
background-color: hsla(0, 100%, 50%, 0.40);
background-color: hsla(0, 100%, 50%, 0.4);
}
/* Deal with being in an iframe */
#appShell #shell-header.iframe {
display: none;
@@ -551,22 +532,23 @@ html.trusted_access #appShell {
display: none;
}
.iframe .module_header, .iframe .module_footer{
.iframe .module_header,
.iframe .module_footer {
display: none;
}
/* Remove the background from the body in all cases */
/* body[data-theme] { */
/* background: none; */
/* background-image: none; */
/* background: none; */
/* background-image: none; */
/* } */
/* Remove the background from the body if using iframes */
/* body[data-theme]:has(#page.iframe) { */
/* background: none; */
/* background-image: none; */
/* background-image: url('https://static.oneskyit.com/c/CHOW/images/CHOW_2024_yellow_background.png'); */
/* background-size: cover; */
/* background: none; */
/* background-image: none; */
/* background-image: url('https://static.oneskyit.com/c/CHOW/images/CHOW_2024_yellow_background.png'); */
/* background-size: cover; */
/* } */
main {
@@ -574,10 +556,10 @@ main {
background-color: hsla(0, 0%, 100%, 0.92); */
}
main>section {
main > section {
background: none;
background-color: hsla(0, 0%, 100%, 0.92);
padding: .5em;
padding: 0.5em;
}
/* @media (min-width: 640px) {
@@ -612,7 +594,6 @@ pre.pre_wrap {
overflow-x: auto;
}
input.required {
/* border-right: solid medium var(--color-warning-500); */
/* color: var(--color-warning-500); */
@@ -648,17 +629,17 @@ input:required {
position: relative;
/* top: 0em; */
left: .25em;
left: 0.25em;
}
/* Make the group a flex row by default */
/* div.btn-group { */
/* display: flex; */
/* gap: 0; */
/* flex-direction: row; */
/* justify-content: space-around; */
/* align-items: center; */
/* margin: 0;
/* display: flex; */
/* gap: 0; */
/* flex-direction: row; */
/* justify-content: space-around; */
/* align-items: center; */
/* margin: 0;
padding: 0; */
/* } */
@@ -686,18 +667,15 @@ div.btn-group button:last-child {
} */
.ae_obj_prop .label {
}
.ae_obj_prop .value {
font-weight: bold;
}
.ae_md_hide {
/* outline: medium dashed green; */
/* display: none; */
}
@media (max-width: 767px) {
@@ -713,9 +691,6 @@ div.btn-group button:last-child {
}
}
/* Use the div.ae_quick_modal_container to block background clicks when using the section.ae_quick_popover. */
div.ae_quick_modal_container {
position: fixed;
@@ -724,7 +699,7 @@ div.ae_quick_modal_container {
width: 100%;
height: 100%;
z-index: 100;
background-color: hsla(0, 0%, 0%, .5);
background-color: hsla(0, 0%, 0%, 0.5);
}
/* The section.ae_quick_popover should be above the rest of the content and centered on the page. */
@@ -734,10 +709,10 @@ section.ae_quick_popover {
left: 50%;
transform: translate(-50%, -50%);
z-index: 100;
background-color: hsla(0, 0%, 100%, .95);
background-color: hsla(0, 0%, 100%, 0.95);
padding: 1rem;
border-radius: .5rem;
box-shadow: 0 0 1rem hsla(0, 0%, 0%, .5);
border-radius: 0.5rem;
box-shadow: 0 0 1rem hsla(0, 0%, 0%, 0.5);
min-height: 98%;
min-width: 98%;
@@ -749,10 +724,10 @@ section.ae_quick_popover_small {
left: 50%;
transform: translate(-50%, 0%);
z-index: 100;
background-color: hsla(0, 0%, 100%, .95);
background-color: hsla(0, 0%, 100%, 0.95);
padding: 1rem;
border-radius: .5rem;
box-shadow: 0 0 1rem hsla(0, 0%, 0%, .5);
border-radius: 0.5rem;
box-shadow: 0 0 1rem hsla(0, 0%, 0%, 0.5);
min-height: 24rem;
max-height: 95%;
@@ -760,7 +735,6 @@ section.ae_quick_popover_small {
max-width: 95%;
}
.fade_50 {
opacity: 0.5;
}
@@ -768,7 +742,6 @@ section.ae_quick_popover_small {
opacity: 1;
}
.auth_view_only {
display: none;
}
@@ -776,8 +749,6 @@ section.ae_quick_popover_small {
display: initial;
}
img.qr_code {
/* outline: solid thin hsla(30, 100%, 50%, .1); */
/* width: 1.50in; */
@@ -793,18 +764,27 @@ img.qr_code:focus {
/* width: 2.50in; */
}
.dim {
opacity: 0.5;
color: hsla(0, 0%, 50%, .95);
color: hsla(0, 0%, 50%, 0.95);
}
.dim_warning {
opacity: 0.5;
/* color: hsla(0, 100%, 50%, .95); */
/* background should be hash marks */
background-image: repeating-linear-gradient(-45deg, hsla(0, 100%, 50%, .25), hsla(0, 100%, 50%, .25) 10px, transparent 10px, transparent 20px);
background-image: repeating-linear-gradient(
-45deg,
hsla(0, 100%, 50%, 0.25),
hsla(0, 100%, 50%, 0.25) 10px,
transparent 10px,
transparent 20px
);
}
.alert {
/* background-color: hsla(0, 100%, 50%, .1); */
outline: dashed thin hsla(0, 100%, 50%, 0.5);
}
@media (max-width: 767px) {
.sk_header.hide_sm {
@@ -832,7 +812,7 @@ img.qr_code:focus {
/* We need to reset many of the styles for the reset_css class. */
.reset_css p {
margin: .75em 0;
margin: 0.75em 0;
}
.reset_css ol {
list-style-type: decimal;
@@ -849,11 +829,10 @@ img.qr_code:focus {
text-decoration: underline;
}
.reset_css a:hover {
color: hsla(210, 100%, 50%, .75);
color: hsla(210, 100%, 50%, 0.75);
text-decoration: none;
}
/* .ae_btn.btn-danger,
.ae_btn.btn-info,
.ae_btn.btn-warning {
@@ -881,8 +860,13 @@ img.qr_code:focus {
border-radius: 60px;
/* border-color: hsla(0, 0%, 50%, .5); */
/* border-color: hsla(0, 0%, 0%, .15); */
}
.iframe .novi_m0 {
margin: 0;
}
.iframe .novi_p0 {
padding: 0;
}
.iframe .dark .novi_label {
@@ -916,19 +900,15 @@ img.qr_code:focus {
background-color: hsla(0, 0%, 20%, 1);
}
.iframe .novi_bg_light {
background-color: hsla(0, 0%, 0%, .15);
background-color: hsla(0, 0%, 0%, 0.15);
color: hsla(0, 0%, 20%, 1);
}
.iframe .novi_bg_dark {
background-color: hsla(0, 0%, 0%, .25);
background-color: hsla(0, 0%, 0%, 0.25);
color: hsla(0, 0%, 95%, 1);
}
.iframe .novi_margin_sm {
/* margin: 0.5em; */
}
@@ -950,15 +930,13 @@ img.qr_code:focus {
.iframe button.ae_smaller,
.iframe .btn.ae_smaller,
.iframe button.novi_smaller,
.iframe .btn.novi_smaller
{
.iframe .btn.novi_smaller {
font-size: 0.8rem;
}
.iframe button.ae_smallest,
.iframe .btn.ae_smallest,
.iframe button.novi_smallest,
.iframe .btn.novi_smallest
{
.iframe .btn.novi_smallest {
font-size: 0.65rem;
}

8
src/app.d.ts vendored
View File

@@ -2,8 +2,8 @@
// for information about these interfaces
// and what to do when importing types
declare namespace App {
// interface Locals {}
// interface PageData {}
// interface Error {}
// interface Platform {}
// interface Locals {}
// interface PageData {}
// interface Error {}
// interface Platform {}
}

View File

@@ -1,27 +1,43 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en" class="light" data-theme="">
<head>
<meta charset="utf-8" >
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" >
<link rel="manifest" href="%sveltekit.assets%/manifest.json">
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<link rel="manifest" href="%sveltekit.assets%/manifest.json" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" >
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.gstatic.com">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Noto+Serif:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap" rel="stylesheet">
<link rel="preconnect" href="https://fonts.gstatic.com" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link
href="https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,400;0,700;1,400;1,700&display=swap"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css2?family=Noto+Serif:ital,wght@0,400;0,700;1,400;1,700&display=swap"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" integrity="sha512-1ycn6IcaQQ40/MKBW2W4Rhis/DbILU74C1vSrLJxCq57o941Ym01SwNsOMqvEBFlcgUa6xLiPY/NS5R+E6ztJQ==" crossorigin="anonymous" referrerpolicy="no-referrer" >
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css"
integrity="sha512-1ycn6IcaQQ40/MKBW2W4Rhis/DbILU74C1vSrLJxCq57o941Ym01SwNsOMqvEBFlcgUa6xLiPY/NS5R+E6ztJQ=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
<!-- <link href="app.css" rel="stylesheet"> -->
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover" class="h-full w-full overflow-auto">
<!-- h-full w-full overflow-auto -->
<!-- overflow-x-scroll -->
<body data-sveltekit-preload-data="hover" class="h-full w-full">
<div style="display: contents" class="">%sveltekit.body%</div>
</body>
</html>

View File

@@ -1,546 +0,0 @@
@import "tailwindcss/preflight";
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 224 71.4% 4.1%;
--muted: 220 14.3% 95.9%;
--muted-foreground: 220 8.9% 46.1%;
--popover: 0 0% 100%;
--popover-foreground: 224 71.4% 4.1%;
--card: 0 0% 100%;
--card-foreground: 224 71.4% 4.1%;
--border: 220 13% 91%;
--input: 220 13% 91%;
--primary: 220.9 39.3% 11%;
--primary-foreground: 210 20% 98%;
--secondary: 220 14.3% 95.9%;
--secondary-foreground: 220.9 39.3% 11%;
--accent: 220 14.3% 95.9%;
--accent-foreground: 220.9 39.3% 11%;
--destructive: 0 72.2% 50.6%;
--destructive-foreground: 210 20% 98%;
--ring: 224 71.4% 4.1%;
--radius: 0.5rem;
--sidebar-background: 0 0% 98%;
--sidebar-foreground: 240 5.3% 26.1%;
--sidebar-primary: 240 5.9% 10%;
--sidebar-primary-foreground: 0 0% 98%;
--sidebar-accent: 240 4.8% 95.9%;
--sidebar-accent-foreground: 240 5.9% 10%;
--sidebar-border: 220 13% 91%;
--sidebar-ring: 217.2 91.2% 59.8%;
}
.dark {
--background: 224 71.4% 4.1%;
--foreground: 210 20% 98%;
--muted: 215 27.9% 16.9%;
--muted-foreground: 217.9 10.6% 64.9%;
--popover: 224 71.4% 4.1%;
--popover-foreground: 210 20% 98%;
--card: 224 71.4% 4.1%;
--card-foreground: 210 20% 98%;
--border: 215 27.9% 16.9%;
--input: 215 27.9% 16.9%;
--primary: 210 20% 98%;
--primary-foreground: 220.9 39.3% 11%;
--secondary: 215 27.9% 16.9%;
--secondary-foreground: 210 20% 98%;
--accent: 215 27.9% 16.9%;
--accent-foreground: 210 20% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 20% 98%;
--ring: 216 12.2% 83.9%;
--sidebar-background: 240 5.9% 10%;
--sidebar-foreground: 240 4.8% 95.9%;
--sidebar-primary: 224.3 76.3% 48%;
--sidebar-primary-foreground: 0 0% 100%;
--sidebar-accent: 240 3.7% 15.9%;
--sidebar-accent-foreground: 240 4.8% 95.9%;
--sidebar-border: 240 3.7% 15.9%;
--sidebar-ring: 217.2 91.2% 59.8%;
}
}
@layer base {
* {
border-color: hsl(var(--border));
}
body {
background-color: hsl(var(--background));
color: hsl(var(--foreground));
}
}
/* There are no more Tailwind layers. */
html,
body {
@apply h-full overflow-hidden;
/* font-family: 'Liberation Sans', sans-serif; */
/* font-family: 'Noto Sans', sans-serif; */
}
html.super_access #appShell {
background-color: hsla(0, 100%, 50%, 0.5);
}
html.manager_access #appShell {
background-color: hsla(0, 50%, 75%, 0.5);
}
html.administrator_access #appShell {
background-color: hsla(40, 50%, 85%, 0.25);
}
html.trusted_access #appShell {
background-color: hsla(20, 50%, 85%, 0.25);
}
/* default theme */
/* @font-face {
font-family: 'Liberation Sans', sans-serif;
font-family: 'Noto Sans', sans-serif;
src: url('/fonts/liberation/LiberationSans-Regular.ttf');
src: url('/fonts/noto/NotoSans-Regular.ttf');
font-display: swap;
} */
/* modern theme */
@font-face {
font-family: 'Quicksand';
src: url('/fonts/Quicksand.ttf');
font-display: swap;
}
/* :root [data-theme='modern'] { */
/* --theme-rounded-base: 20px;
--theme-rounded-container: 4px; */
/* --theme-font-family-base: 'Liberation Sans', sans-serif; */
/* --theme-font-family-heading: 'Liberation Sans', sans-serif; */
/* } */
.card-footer {
border-top: 1px solid hsla(0, 0%, 0%, 0.5);
margin-top: 1em;
padding-top: 1em;
opacity: .5;
}
/* Tailwind: This "fixes" Tailwind's default group button styles that do not seem to allow hiding buttons. */
.btn-group a.hidden, .btn-group button.hidden {
display: none;
}
.ae_d_none {
display: none;
}
/* Allow content to scroll horizontal if too wide */
.ae_h_scrollfix {
max-width: 100%;
overflow-x: auto;
}
/* These helps with the Skeleton Tailwind modal utility. */
.ae_modal_scrollfix {
/* Allow modal content to scroll if it's too long */
overflow-y: auto;
max-height: 96vh;
/* max-height: 99%; */
}
.ae_debug {
/* A darker pink outline */
outline: thin dashed;
outline-color: hsla(0, 100%, 50%, 0.15);
/* A light pink background color */
background-color: hsla(0, 100%, 50%, 0.15);
}
.ae_debug:hover {
/* A darker pink outline */
outline-color: hsla(0, 100%, 50%, 0.50);
/* A light pink background color */
background-color: hsla(0, 100%, 50%, 0.40);
}
/* Deal with being in an iframe */
#appShell #shell-header.iframe {
display: none;
}
#appShell #shell-footer.iframe {
display: none;
}
/* Remove the background from the body in all cases */
/* body[data-theme] { */
/* background: none; */
/* background-image: none; */
/* } */
/* Remove the background from the body if using iframes */
/* body[data-theme]:has(#page.iframe) { */
/* background: none; */
/* background-image: none; */
/* background-image: url('https://static.oneskyit.com/c/CHOW/images/CHOW_2024_yellow_background.png'); */
/* background-size: cover; */
/* } */
main {
/* background: none;
background-color: hsla(0, 0%, 100%, 0.92); */
}
main>section {
background: none;
background-color: hsla(0, 0%, 100%, 0.92);
padding: .5em;
}
/* @media (min-width: 640px) {
main>div, main>section {
padding: 0;
max-width: 100%;
}
} */
/* @media (min-width: 768px) {
main>div, main>section {
padding: 0;
max-width: 100%;
}
} */
.ae_sponsorships {
/* background: none; */
/* background-color: hsla(0, 0%, 100%, 0.92); */
/* background-image: url('https://static.oneskyit.com/c/CHOW/images/CHOW_2024_yellow_background.png'); */
/* background-size: cover; */
}
pre.pre_wrap {
white-space: pre-wrap;
word-break: normal;
word-wrap: normal;
border: none;
max-width: 100%;
overflow-x: auto;
}
input.required {
/* border-right: solid medium var(--color-warning-500); */
/* color: var(--color-warning-500); */
}
input:required {
/* background-color: var(--alert-color-lightest); */
/* border: solid 2px red; */
/* outline: dashed thin var(--alert-color-lighter); */
/* border-right: solid medium var(--alert-color-mid); */
/* border-right: solid medium var(--warning-color-mid); */
/* border-right: solid medium var(--error-color-mid); */
}
/* input:required:hover {
background-color: var(--alert-color-lighter);
border-right: solid thick var(--alert-color-darker);
} */
/* input:required::before {
display: block;
content: '*';
color: var(--warning-color-darker);
top: 5px;
left: 5px;
} */
.input_required::after {
content: '*';
color: rgb(var(--color-error-500) / 0.9);
position: relative;
/* top: 0em; */
left: .25em;
}
/* Make the group a flex row by default */
/* div.btn-group { */
/* display: flex; */
/* gap: 0; */
/* flex-direction: row; */
/* justify-content: space-around; */
/* align-items: center; */
/* margin: 0;
padding: 0; */
/* } */
/* Make all button elements except for the the first button element not rounded on the left. */
/* Make all button elements except for the fhe last button element not rounded on the right. */
/* These helps with the Skeleton (Tailwind?) button group element. */
.btn-group button {
border-radius: 0;
border: none;
}
/* .md:btn-group button,
.lg:btn-group button {
border-radius: 0;
border: none;
} */
/* div.btn-group button:first-child {
border-top-left-radius: .25rem;
border-bottom-left-radius: .25rem;
}
div.btn-group button:last-child {
border-top-right-radius: .25rem;
border-bottom-right-radius: .25rem;
} */
.ae_obj_prop .label {
}
.ae_obj_prop .value {
font-weight: bold;
}
.ae_md_hide {
/* outline: medium dashed green; */
/* display: none; */
}
@media (max-width: 767px) {
.ae_md_hide {
/* outline: medium dashed red; */
display: none;
}
}
@media (min-width: 768px) {
.ae_lg_hide {
/* outline: medium dashed blue; */
display: none;
}
}
/* Use the div.ae_quick_modal_container to block background clicks when using the section.ae_quick_popover. */
div.ae_quick_modal_container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 100;
background-color: hsla(0, 0%, 0%, .5);
}
/* The section.ae_quick_popover should be above the rest of the content and centered on the page. */
section.ae_quick_popover {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 100;
background-color: hsla(0, 0%, 100%, .95);
padding: 1rem;
border-radius: .5rem;
box-shadow: 0 0 1rem hsla(0, 0%, 0%, .5);
min-height: 98%;
min-width: 98%;
}
section.ae_quick_popover_small {
position: fixed;
top: 1em;
left: 50%;
transform: translate(-50%, 0%);
z-index: 100;
background-color: hsla(0, 0%, 100%, .95);
padding: 1rem;
border-radius: .5rem;
box-shadow: 0 0 1rem hsla(0, 0%, 0%, .5);
min-height: 24rem;
max-height: 95%;
min-width: 50%;
max-width: 95%;
}
.fade_50 {
opacity: 0.5;
}
.fade_50:hover {
opacity: 1;
}
.auth_view_only {
display: none;
}
.ae_root--auth_access .auth_view_only {
display: initial;
}
img.qr_code {
/* outline: solid thin hsla(30, 100%, 50%, .1); */
/* width: 1.50in; */
}
img.qr_code:hover {
/* outline: solid thin green; */
/* width: 2.50in; */
}
img.qr_code:focus {
/* outline: solid thin red; */
/* width: 2.50in; */
}
.dim {
opacity: 0.5;
color: hsla(0, 0%, 50%, .95);
}
.dim_warning {
opacity: 0.5;
/* color: hsla(0, 100%, 50%, .95); */
/* background should be hash marks */
background-image: repeating-linear-gradient(-45deg, hsla(0, 100%, 50%, .25), hsla(0, 100%, 50%, .25) 10px, transparent 10px, transparent 20px);
}
@media (max-width: 767px) {
.sk_header.hide_sm {
display: none;
}
.sk_header.show_sm {
display: initial;
}
.sk_header.show_md {
display: none;
}
}
@media (min-width: 768px) {
.sk_header.hide_md {
display: none;
}
.sk_header.show_md {
display: initial;
}
.sk_header.show_sm {
display: none;
}
}
/* We need to reset many of the styles for the reset_css class. */
.reset_css p {
margin: .75em 0;
}
.reset_css ol {
list-style-type: decimal;
}
.reset_css ul {
list-style-type: disc;
}
.reset_css li {
margin-left: 1.5em;
}
/* Reset anchor tags to the default color and underline. */
.reset_css a {
color: hsla(210, 100%, 50%, 1);
text-decoration: underline;
}
.reset_css a:hover {
color: hsla(210, 100%, 50%, .75);
text-decoration: none;
}
/* .ae_btn.btn-danger,
.ae_btn.btn-info,
.ae_btn.btn-warning {
border-radius: 60px;
} */
/* .ae_margin_xs {
margin: 0.25em;
}
.ae_margin_sm {
margin: 0.5em;
}
.ae_margin_md {
margin: 0.75em;
}
.ae_margin_lg {
margin: 1em;
}
.ae_margin_lg {
margin: 1.25em;
} */
/* BEGIN: Overrides and fixes specific to Novi and IDAA */
.iframe .novi_btn {
border-radius: 60px;
border-color: hsla(0, 0%, 50%, .5);
}
.iframe .novi_margin_sm {
/* margin: 0.5em; */
}
.iframe .novi_text_wrap {
/* white-space: normal; */
white-space: pre-wrap;
word-break: break-word;
}
/* END: Overrides and fixes specific to Novi and IDAA */
.iframe button.ae_normal,
.iframe .btn.ae_normal {
/* font: normal 1em sans-serif; */
font-size: 1rem;
}
.iframe button.ae_smaller,
.iframe .btn.ae_smaller,
.iframe button.novi_smaller,
.iframe .btn.novi_smaller
{
font-size: 0.8rem;
}
.iframe button.ae_smallest,
.iframe .btn.ae_smallest,
.iframe button.novi_smallest,
.iframe .btn.novi_smallest
{
font-size: 0.65rem;
}

View File

@@ -1,7 +1,7 @@
import { describe, it, expect } from 'vitest';
describe('sum test', () => {
it('adds 1 + 2 to equal 3', () => {
expect(1 + 2).toBe(3);
});
it('adds 1 + 2 to equal 3', () => {
expect(1 + 2).toBe(3);
});
});

View File

@@ -1,25 +1,23 @@
// import axios from 'axios';
// Updated 2024-05-23
export let delete_object = async function delete_object(
{
api_cfg = null,
endpoint = '',
params = {},
data = {},
return_meta = false,
log_lvl = 0,
retry_count = 5 // Number of retry attempts
}: {
api_cfg: any,
endpoint: string,
params?: any,
data?: any,
return_meta?: boolean,
log_lvl?: number,
retry_count?: number
}
) {
export const delete_object = async function delete_object({
api_cfg = null,
endpoint = '',
params = {},
data = {},
return_meta = false,
log_lvl = 0,
retry_count = 5 // Number of retry attempts
}: {
api_cfg: any;
endpoint: string;
params?: any;
data?: any;
return_meta?: boolean;
log_lvl?: number;
retry_count?: number;
}) {
if (log_lvl) {
console.log(`*** delete_object() *** Endpoint: ${endpoint}`);
console.log('Params:', params);
@@ -35,12 +33,12 @@ export let delete_object = async function delete_object(
// Construct the URL with query parameters
const url = new URL(endpoint, api_cfg['base_url']);
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
Object.keys(params).forEach((key) => url.searchParams.append(key, params[key]));
// Clean the headers
let headers_cleaned: Record<string, string> = {};
const headers_cleaned: Record<string, string> = {};
for (const prop in api_cfg['headers']) {
let prop_cleaned = prop.replaceAll('_', '-');
const prop_cleaned = prop.replaceAll('_', '-');
headers_cleaned[prop_cleaned] = api_cfg['headers'][prop];
}
@@ -101,7 +99,6 @@ export let delete_object = async function delete_object(
}
}
// https://stackoverflow.com/questions/51069552/axios-delete-request-with-body-and-headers
// let axios_api = axios.create({
@@ -117,7 +114,7 @@ export let delete_object = async function delete_object(
// console.log(response.data);
// return response.data;
// })
// .catch(function (error) {
// .catch(function (error: any) {
// if (error.response && error.response.status === 404) {
// return null; // Returning null since there were no results
// }
@@ -130,4 +127,4 @@ export let delete_object = async function delete_object(
// console.log(response_data);
// }
// return response_data;
}
};

View File

@@ -1,50 +1,48 @@
import type { key_val } from '$lib/ae_stores';
import type { key_val } from '$lib/stores/ae_stores';
import { get_object } from './api_get_object';
// Updated 2023-12-01
export async function get_ae_obj_id_crud(
{
api_cfg,
no_account_id = false,
obj_type,
obj_id,
use_alt_table = false,
use_alt_base = false,
inc = {},
enabled = 'enabled',
hidden = 'not_hidden',
limit = 999999,
offset = 0,
data = {},
// key,
// jwt = null,
headers = {},
params = {},
timeout = 25000,
return_meta = false,
log_lvl = 0
}: {
api_cfg: any,
no_account_id?: boolean,
obj_type: string,
obj_id: string,
use_alt_table?: boolean,
use_alt_base?: boolean,
inc?: any,
enabled?: string,
hidden?: string,
limit?: number,
offset?: number,
data?: any,
// key: string,
// jwt?: string,
headers?: any,
params?: key_val,
timeout?: number,
return_meta?: boolean,
log_lvl?: number
}
) {
export async function get_ae_obj_id_crud({
api_cfg,
no_account_id = false,
obj_type,
obj_id,
use_alt_table = false,
use_alt_base = false,
inc = {},
enabled = 'enabled',
hidden = 'not_hidden',
limit = 999999,
offset = 0,
data = {},
// key,
// jwt = null,
headers = {},
params = {},
timeout = 25000,
return_meta = false,
log_lvl = 0
}: {
api_cfg: any;
no_account_id?: boolean;
obj_type: string;
obj_id: string;
use_alt_table?: boolean;
use_alt_base?: boolean;
inc?: any;
enabled?: 'enabled' | 'all' | 'not_enabled' | undefined;
hidden?: 'hidden' | 'all' | 'not_hidden' | undefined;
limit?: number;
offset?: number;
data?: any;
// key: string,
// jwt?: string,
headers?: any;
params?: key_val;
timeout?: number;
return_meta?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log('*** get_ae_obj_id_crud() ***');
}
@@ -121,8 +119,8 @@ export async function get_ae_obj_id_crud(
endpoint = `/crud/sponsorship/cfg/${obj_id}`;
} else if (obj_type == 'sponsorship') {
endpoint = `/crud/sponsorship/${obj_id}`;
// } else if (obj_type == 'user') {
// endpoint = `/crud/user/${obj_id}`;
// } else if (obj_type == 'user') {
// endpoint = `/crud/user/${obj_id}`;
} else {
console.log(`Unknown object type: ${obj_type}`);
return false;
@@ -155,15 +153,14 @@ export async function get_ae_obj_id_crud(
// headers['x-no-account-id-token'] = 'Nothing to See Here'; // get_object() will fix the underscores to dashes
}
let object_obj_get_promise = await get_object({
const object_obj_get_promise = await get_object({
api_cfg: api_cfg,
endpoint: endpoint,
headers: headers,
params: params,
timeout: timeout,
log_lvl: log_lvl
})
.catch(function (error) {
}).catch(function (error: any) {
console.log('API GET CRUD object ID request failed.', error);
});
@@ -172,4 +169,4 @@ export async function get_ae_obj_id_crud(
}
return object_obj_get_promise;
}
}

View File

@@ -1,53 +1,51 @@
import type { key_val } from '$lib/ae_stores';
import type { key_val } from '$lib/stores/ae_stores';
import { get_object } from './api_get_object';
// The lookup "obj_type" should broken out into a separate function. - 2024-08-07
// Updated 2023-11-15
export async function get_ae_obj_li_for_obj_id_crud(
{
api_cfg,
obj_type,
for_obj_type,
for_obj_id, // NOTE: Changed 2023-12-06 to no longer required
use_alt_table = false,
use_alt_base = false,
// inc = {},
enabled = 'enabled',
hidden = 'not_hidden',
order_by_li = null,
limit = 999999,
offset = 0,
// key,
// jwt = null,
headers = {},
params_json = null, // NOTE: This is a JSON object that needs to be safely converted to a string for the params. This is used for the API endpoint. Example: { "fulltext_search": { "default_qry_str": "Search string for default", "address_default_qry_str": "Search string for address", "contact_1_default_qry_str": "Search string for contact_1" } }
// json_obj = null, // NOTE: This is a JSON object that needs to be safely converted to a string for the params. This is used for the search endpoint.
params = {},
return_meta = false,
log_lvl = 0
}: {
api_cfg: any,
obj_type: string,
for_obj_type: null|string,
for_obj_id?: string,
use_alt_table?: boolean,
use_alt_base?: boolean,
// inc?: key_val
enabled?: string,
hidden?: string,
order_by_li?: any,
limit?: number,
offset?: number,
// key: string,
// jwt?: string,
headers?: any,
params_json?: any,
// json_obj?: any,
params?: key_val,
return_meta?: boolean,
log_lvl?: number
}
) {
export async function get_ae_obj_li_for_obj_id_crud({
api_cfg,
obj_type,
for_obj_type,
for_obj_id, // NOTE: Changed 2023-12-06 to no longer required
use_alt_table = false,
use_alt_base = false,
// inc = {},
enabled = 'enabled',
hidden = 'not_hidden',
order_by_li = null,
limit = 999999,
offset = 0,
// key,
// jwt = null,
headers = {},
params_json = null, // NOTE: This is a JSON object that needs to be safely converted to a string for the params. This is used for the API endpoint. Example: { "fulltext_search": { "default_qry_str": "Search string for default", "address_default_qry_str": "Search string for address", "contact_1_default_qry_str": "Search string for contact_1" } }
// json_obj = null, // NOTE: This is a JSON object that needs to be safely converted to a string for the params. This is used for the search endpoint.
params = {},
return_meta = false,
log_lvl = 0
}: {
api_cfg: any;
obj_type: string;
for_obj_type: null | string;
for_obj_id?: string;
use_alt_table?: boolean;
use_alt_base?: boolean;
// inc?: key_val
enabled?: 'enabled' | 'all' | 'not_enabled' | undefined;
hidden?: 'hidden' | 'all' | 'not_hidden' | undefined;
order_by_li?: any;
limit?: number;
offset?: number;
// key: string,
// jwt?: string,
headers?: any;
params_json?: any;
// json_obj?: any,
params?: key_val;
return_meta?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** get_ae_obj_li_for_obj_id_crud() *** [${obj_type}]`);
}
@@ -124,8 +122,8 @@ export async function get_ae_obj_li_for_obj_id_crud(
endpoint = `/crud/sponsorship/cfg/list`;
} else if (obj_type == 'sponsorship') {
endpoint = `/crud/sponsorship/list`;
// } else if (obj_type == 'user') {
// endpoint = `/crud/user/list`;
// } else if (obj_type == 'user') {
// endpoint = `/crud/user/list`;
} else if (obj_type == 'lu' && for_obj_type == 'country_subdivision') {
endpoint = `/crud/lu/country_subdivision/list`;
for_obj_type = null;
@@ -155,13 +153,13 @@ export async function get_ae_obj_li_for_obj_id_crud(
/* Need to deal with inc params here */
let allowed_enabled_list = ['all', 'enabled', 'not_enabled']
if (allowed_enabled_list.includes(enabled) ) {
const allowed_enabled_list = ['all', 'enabled', 'not_enabled'];
if (allowed_enabled_list.includes(enabled)) {
params['enabled'] = enabled;
}
let allowed_hidden_list = ['all', 'hidden', 'not_hidden'];
if (allowed_hidden_list.includes(hidden) ) {
const allowed_hidden_list = ['all', 'hidden', 'not_hidden'];
if (allowed_hidden_list.includes(hidden)) {
params['hidden'] = hidden;
}
@@ -192,7 +190,9 @@ export async function get_ae_obj_li_for_obj_id_crud(
// NOTE: "jp" stands for "JSON Params"
params['jp'] = encodeURIComponent(JSON.stringify(params_json));
if (params['jp'].length > 2083) {
console.log(`The JSON object is too large to be used as a GET parameter. The overall max URL length is 2083 characters. Please use the POST endpoint instead. Length = ${params['jp'].length} [THIS DOES NOT EXIST YET]`);
console.log(
`The JSON object is too large to be used as a GET parameter. The overall max URL length is 2083 characters. Please use the POST endpoint instead. Length = ${params['jp'].length} [THIS DOES NOT EXIST YET]`
);
return false;
}
}
@@ -212,18 +212,18 @@ export async function get_ae_obj_li_for_obj_id_crud(
console.log('Params:', params);
}
let object_li_get_promise = await get_object({
const object_li_get_promise = await get_object({
api_cfg: api_cfg,
endpoint: endpoint,
headers: headers,
params: params,
return_meta: return_meta,
log_lvl: log_lvl
});
});
if (log_lvl > 1) {
console.log(object_li_get_promise);
}
return object_li_get_promise;
}
}

View File

@@ -1,246 +1,174 @@
import type { key_val } from '$lib/ae_stores';
import type { key_val } from '$lib/stores/ae_stores';
import { get_object } from './api_get_object';
// The lookup "obj_type" should broken out into a separate function. - 2024-08-07
// Updated 2023-11-15
export async function get_ae_obj_li_for_obj_id_crud_v2(
{
api_cfg,
obj_type,
for_obj_type,
for_obj_id, // NOTE: Changed 2023-12-06 to no longer required
use_alt_tbl = false, // Alternate table or view name
use_alt_mdl = false, // Alternate model name
use_alt_exp = false, // Alternate export table or view name
inc = {},
enabled = 'enabled',
hidden = 'not_hidden',
order_by_li = null,
limit = 999999,
offset = 0,
// key,
// jwt = null,
headers = {},
params_json = null, // NOTE: This is a JSON object that needs to be safely converted to a string for the params. This is used for the API endpoint. Example: { "fulltext_search": { "default_qry_str": "Search string for default", "address_default_qry_str": "Search string for address", "contact_1_default_qry_str": "Search string for contact_1" } }
// json_obj = null, // NOTE: This is a JSON object that needs to be safely converted to a string for the params. This is used for the search endpoint.
params = {},
// return_meta = false,
log_lvl = 0
}: {
api_cfg: any,
obj_type: string,
for_obj_type: string,
for_obj_id?: string,
use_alt_tbl?: boolean|string,
use_alt_mdl?: boolean|string,
use_alt_exp?: boolean|string,
inc?: key_val
enabled?: string,
hidden?: string,
order_by_li?: any,
limit?: number,
offset?: number,
// key: string,
// jwt?: string,
headers?: any,
params_json?: any,
// json_obj?: any,
params?: key_val,
// return_meta?: boolean,
log_lvl?: number
}
) {
// Refactored 2025-11-13 to use a lookup map for endpoints.
const objTypeToEndpointMap: Record<string, string> = {
account: '/crud/account/list',
address: '/crud/address/list',
archive: '/crud/archive/list',
archive_content: '/crud/archive/content/list',
contact: '/crud/contact/list',
data_store: '/crud/data_store/list',
event: '/crud/event/list',
event_abstract: '/crud/event/abstract/list',
event_badge: '/crud/event/badge/list',
event_badge_template: '/crud/event/badge/template/list',
event_device: '/crud/event/device/list',
event_exhibit: '/crud/event/exhibit/list',
event_exhibit_tracking: '/crud/event/exhibit/tracking/list',
event_file: '/crud/event/file/list',
event_location: '/crud/event/location/list',
event_person: '/crud/event/person/list',
event_presentation: '/crud/event/presentation/list',
event_presenter: '/crud/event/presenter/list',
event_session: '/crud/event/session/list',
event_track: '/crud/event/track/list',
grant: '/crud/grant/list',
hosted_file: '/crud/hosted_file/list',
journal: '/crud/journal/list',
journal_entry: '/crud/journal/entry/list',
order: '/crud/order/list',
order_line: '/crud/order/line/list',
page: '/crud/page/list',
person: '/crud/person/list',
post: '/crud/post/list',
post_comment: '/crud/post/comment/list',
site: '/crud/site/list',
sponsorship_cfg: '/crud/sponsorship/cfg/list',
sponsorship: '/crud/sponsorship/list',
// user: '/crud/user/list',
'lu-country_subdivision': '/crud/lu/country_subdivision/list',
'lu-country': '/crud/lu/country/list',
'lu-time_zone': '/crud/lu/time_zone/list'
};
function getEndpointForObjType(obj_type: string, for_obj_type?: string): string {
if (obj_type === 'lu' && for_obj_type) {
const key = `lu-${for_obj_type}`;
const endpoint = objTypeToEndpointMap[key];
if (endpoint) return endpoint;
}
const endpoint = objTypeToEndpointMap[obj_type];
if (endpoint) return endpoint;
throw new Error(`Unknown object type: ${obj_type}`);
}
type OrderBy = { [key: string]: 'ASC' | 'DESC' };
interface GetAeObjLiForObjIdCrudV2Params {
api_cfg: any; // Consider defining a specific type for api_cfg
obj_type: string;
for_obj_type: string;
for_obj_id?: string;
use_alt_tbl?: boolean | string;
use_alt_mdl?: boolean | string;
use_alt_exp?: boolean | string;
inc?: key_val;
enabled?: 'all' | 'enabled' | 'not_enabled';
hidden?: 'all' | 'hidden' | 'not_hidden';
order_by_li?: OrderBy[] | null;
limit?: number;
offset?: number;
headers?: Record<string, string>;
params_json?: any;
params?: key_val;
log_lvl?: number;
}
export async function get_ae_obj_li_for_obj_id_crud_v2({
api_cfg,
obj_type,
for_obj_type,
for_obj_id,
use_alt_tbl = false,
use_alt_mdl = false,
use_alt_exp = false,
enabled = 'enabled',
hidden = 'not_hidden',
order_by_li = null,
limit = 999999,
offset = 0,
headers = {},
params_json = null,
params = {},
log_lvl = 0
}: GetAeObjLiForObjIdCrudV2Params) {
if (log_lvl) {
console.log('*** get_ae_obj_li_for_obj_id_crud() ***');
console.log('*** get_ae_obj_li_for_obj_id_crud_v2() ***');
}
// data = {};
// data['super_key'] = key;
// data['jwt'] = jwt;
// NOTE: The key and or JWT should be in the header of the DELETE, GET, PATCH, POST
// const endpoint = `/crud/${obj_type}/list`;
let endpoint = '';
if (obj_type == 'account') {
endpoint = `/crud/account/list`;
} else if (obj_type == 'address') {
endpoint = `/crud/address/list`;
} else if (obj_type == 'archive') {
endpoint = `/crud/archive/list`;
} else if (obj_type == 'archive_content') {
endpoint = `/crud/archive/content/list`;
} else if (obj_type == 'contact') {
endpoint = `/crud/contact/list`;
} else if (obj_type == 'data_store') {
endpoint = `/crud/data_store/list`;
} else if (obj_type == 'event') {
endpoint = `/crud/event/list`;
} else if (obj_type == 'event_abstract') {
endpoint = `/crud/event/abstract/list`;
} else if (obj_type == 'event_badge') {
endpoint = `/crud/event/badge/list`;
} else if (obj_type == 'event_device') {
endpoint = `/crud/event/device/list`;
} else if (obj_type == 'event_exhibit') {
endpoint = `/crud/event/exhibit/list`;
} else if (obj_type == 'event_exhibit_tracking') {
endpoint = `/crud/event/exhibit/tracking/list`;
} else if (obj_type == 'event_file') {
endpoint = `/crud/event/file/list`;
} else if (obj_type == 'event_location') {
endpoint = `/crud/event/location/list`;
} else if (obj_type == 'event_person') {
endpoint = `/crud/event/person/list`;
} else if (obj_type == 'event_presentation') {
endpoint = `/crud/event/presentation/list`;
} else if (obj_type == 'event_presenter') {
endpoint = `/crud/event/presenter/list`;
} else if (obj_type == 'event_session') {
endpoint = `/crud/event/session/list`;
} else if (obj_type == 'event_track') {
endpoint = `/crud/event/track/list`;
} else if (obj_type == 'grant') {
endpoint = `/crud/grant/list`;
} else if (obj_type == 'hosted_file') {
endpoint = `/crud/hosted_file/list`;
} else if (obj_type == 'journal') {
endpoint = `/crud/journal/list`;
} else if (obj_type == 'journal_entry') {
endpoint = `/crud/journal/entry/list`;
} else if (obj_type == 'order') {
endpoint = `/crud/order/list`;
} else if (obj_type == 'order_line') {
endpoint = `/crud/order/line/list`;
} else if (obj_type == 'page') {
endpoint = `/crud/page/list`;
} else if (obj_type == 'person') {
endpoint = `/crud/person/list`;
} else if (obj_type == 'post') {
endpoint = `/crud/post/list`;
} else if (obj_type == 'post_comment') {
endpoint = `/crud/post/comment/list`;
} else if (obj_type == 'site') {
endpoint = `/crud/site/list`;
} else if (obj_type == 'sponsorship_cfg') {
endpoint = `/crud/sponsorship/cfg/list`;
} else if (obj_type == 'sponsorship') {
endpoint = `/crud/sponsorship/list`;
// } else if (obj_type == 'user') {
// endpoint = `/crud/user/list`;
} else if (obj_type == 'lu' && for_obj_type == 'country_subdivision') {
endpoint = `/crud/lu/country_subdivision/list`;
// for_obj_type = null;
} else if (obj_type == 'lu' && for_obj_type == 'country') {
endpoint = `/crud/lu/country/list`;
// for_obj_type = null;
} else if (obj_type == 'lu' && for_obj_type == 'time_zone') {
endpoint = `/crud/lu/time_zone/list`;
// for_obj_type = null;
} else {
console.log(`Unknown object type: ${obj_type}`);
return false;
}
endpoint = `/v2${endpoint}`;
if (log_lvl) {
console.log('Endpoint:', endpoint);
}
// We need to remove a few parameters from the params object that are not allowed.
delete params['qry__enabled'];
delete params['qry__hidden'];
delete params['qry__limit'];
delete params['qry__offset'];
if (for_obj_type) {
params['for_obj_type'] = for_obj_type;
}
if (for_obj_id) {
params['for_obj_id'] = for_obj_id;
}
if (use_alt_tbl === true) {
params['tbl_alt'] = 'alt'; // Use alternate table or view name
}
if (use_alt_mdl === true) {
params['mdl_alt'] = 'alt'; // Use alternate model name
}
if (use_alt_exp === true) {
params['exp_alt'] = 'alt'; // Use alternate export table or view name
}
// Need to deal with inc params here???
let allowed_enabled_list = ['all', 'enabled', 'not_enabled']
if (allowed_enabled_list.includes(enabled) ) {
params['enabled'] = enabled;
}
let allowed_hidden_list = ['all', 'hidden', 'not_hidden'];
if (allowed_hidden_list.includes(hidden) ) {
params['hidden'] = hidden;
}
// NOTE: The order_by_li variable is in the "headers" because if is a the URL GET params do not handle multiple values very well. Maybe base64 encore in the future or something? Reminder that GET requests should not have a body (no JSON).
// NOTE: The order_by_li should be a key value pair of the property/DB field to sort and how to sort (ASC or DESC)
if (order_by_li) {
// headers['order_by_li'] = order_by_li;
headers['order_by_li'] = JSON.stringify(order_by_li);
}
if (limit >= 0) {
params['limit'] = limit;
}
if (offset >= 0) {
params['offset'] = offset;
}
if (params_json) {
// NOTE: This is a JSON object that needs to be safely converted to a string for the params. This is used for the search endpoint.
// Max characters for a GET request is 2083. This is a limitation of the browser (Microsoft IE and Edge).
try {
const endpoint = `/v2${getEndpointForObjType(obj_type, for_obj_type)}`;
if (log_lvl) {
console.log('JSON Object:', params_json);
console.log(JSON.stringify(params_json));
console.log('Endpoint:', endpoint);
}
// NOTE: "jp" stands for "JSON Params"
params['jp'] = encodeURIComponent(JSON.stringify(params_json));
if (params['jp'].length > 2083) {
console.log(`The JSON object is too large to be used as a GET parameter. The overall max URL length is 2083 characters. Please use the POST endpoint instead. Length = ${params['jp'].length} [THIS DOES NOT EXIST YET]`);
return false;
// We need to remove a few parameters from the params object that are not allowed.
delete params['qry__enabled'];
delete params['qry__hidden'];
delete params['qry__limit'];
delete params['qry__offset'];
if (for_obj_type) params['for_obj_type'] = for_obj_type;
if (for_obj_id) params['for_obj_id'] = for_obj_id;
if (use_alt_tbl === true) params['tbl_alt'] = 'alt';
if (use_alt_mdl === true) params['mdl_alt'] = 'alt';
if (use_alt_exp === true) params['exp_alt'] = 'alt';
const allowed_enabled_list = ['all', 'enabled', 'not_enabled'];
if (allowed_enabled_list.includes(enabled)) {
params['enabled'] = enabled;
}
}
// if (json_obj) {
// // NOTE: This is a JSON object that needs to be safely converted to a string for the params. This is used for the search endpoint.
// // Max characters for a GET request is 2083. This is a limitation of the browser (Microsoft IE and Edge).
// console.log('JSON Object:', json_obj);
// params['json_str'] = encodeURIComponent(JSON.stringify(json_obj));
// if (params['json_str'].length > 2083) {
// console.log(`The JSON object is too large to be used as a GET parameter. The overall max URL length is 2083 characters. Please use the POST endpoint instead. Length = ${params['json_str'].length} [THIS DOES NOT EXIST YET]`);
// return false;
// }
// }
const allowed_hidden_list = ['all', 'hidden', 'not_hidden'];
if (allowed_hidden_list.includes(hidden)) {
params['hidden'] = hidden;
}
if (log_lvl) {
console.log('Params:', params);
}
// NOTE: The order_by_li variable is in the "headers" because URL GET params do not handle complex objects very well.
if (order_by_li) {
headers['order_by_li'] = JSON.stringify(order_by_li);
}
let object_li_get_promise = await get_object({
api_cfg: api_cfg,
endpoint: endpoint,
headers: headers,
params: params,
// return_meta: return_meta,
log_lvl: log_lvl
if (limit > 0) params['limit'] = limit;
if (offset > 0) params['offset'] = offset;
if (params_json) {
// NOTE: "jp" stands for "JSON Params". This is a JSON object that needs to be safely converted to a string for the params.
// Max characters for a GET request is ~2000. This is a limitation of the browser.
const json_params_str = encodeURIComponent(JSON.stringify(params_json));
if (json_params_str.length > 2083) {
// Using console.error instead of throwing an error to avoid crashing the app for a known limitation.
console.error(
`The JSON object is too large to be used as a GET parameter. Max length is 2083 characters. Length = ${json_params_str.length}`
);
return false;
}
params['jp'] = json_params_str;
}
if (log_lvl) {
console.log('Params:', params);
}
const object_li_get_promise = await get_object({
api_cfg: api_cfg,
endpoint: endpoint,
headers: headers,
params: params,
log_lvl: log_lvl
});
if (log_lvl > 1) {
console.log(object_li_get_promise);
}
if (log_lvl > 1) {
console.log(object_li_get_promise);
}
return object_li_get_promise;
}
return object_li_get_promise;
} catch (error) {
console.error('Error in get_ae_obj_li_for_obj_id_crud_v2:', error);
return false; // Or handle the error as appropriate
}
}

View File

@@ -1,45 +1,43 @@
import type { key_val } from '$lib/ae_stores';
import type { key_val } from '$lib/stores/ae_stores';
export let temp_get_blob_percent_completed = 0;
export let get_blob_percent_completed = temp_get_blob_percent_completed;
export const get_blob_percent_completed = temp_get_blob_percent_completed;
export let temp_get_object_percent_completed = 0;
export let get_object_percent_completed = temp_get_object_percent_completed;
export const temp_get_object_percent_completed = 0;
export const get_object_percent_completed = temp_get_object_percent_completed;
export let get_object = async function get_object(
{
api_cfg = null,
endpoint = '',
headers = {},
params = {},
data = {},
timeout = 60000,
// return_meta = false,
return_blob = false,
filename = '',
auto_download = false,
as_list = false, // Is this still really needed?
// The task_id value should be a random string that is unique to the task. This is used to identify the task in the message event.
task_id = crypto.randomUUID(),
log_lvl = 0,
retry_count = 5 // Number of retry attempts
}: {
api_cfg: any,
endpoint: string,
headers?: any,
params?: any,
data?: any,
timeout?: number,
// return_meta?: boolean,
return_blob?: boolean,
filename?: null | string,
auto_download?: boolean,
as_list?: boolean,
task_id?: string,
log_lvl?: number,
retry_count?: number
}
) {
export const get_object = async function get_object({
api_cfg = null,
endpoint = '',
headers = {},
params = {},
data = {},
timeout = 60000,
return_meta = false,
return_blob = false,
filename = '',
auto_download = false,
as_list = false, // Is this still really needed?
// The task_id value should be a random string that is unique to the task. This is used to identify the task in the message event.
task_id = crypto.randomUUID(),
log_lvl = 0,
retry_count = 5 // Number of retry attempts
}: {
api_cfg: any;
endpoint: string;
headers?: any;
params?: any;
data?: any;
timeout?: number;
return_meta?: boolean;
return_blob?: boolean;
filename?: null | string;
auto_download?: boolean;
as_list?: boolean;
task_id?: string;
log_lvl?: number;
retry_count?: number;
}) {
if (log_lvl) {
console.log(`*** get_object() *** Endpoint: ${endpoint} AE Task ID: ${task_id}`);
console.log('Params:', params);
@@ -54,20 +52,23 @@ export let get_object = async function get_object(
}
const url = new URL(endpoint, api_cfg['base_url']);
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
Object.keys(params).forEach((key) => url.searchParams.append(key, params[key]));
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
// Remove a header parameter if it is set to null
if (api_cfg['headers'].hasOwnProperty('x-no-account-id') && api_cfg['headers']['x-no-account-id'] === null) {
if (
api_cfg['headers'].hasOwnProperty('x-no-account-id') &&
api_cfg['headers']['x-no-account-id'] === null
) {
delete api_cfg['headers']['x-no-account-id'];
}
// Clean the headers
let headers_cleaned: key_val = {};
const headers_cleaned: key_val = {};
for (const prop in headers) {
let prop_cleaned = prop.replaceAll('_', '-');
const prop_cleaned = prop.replaceAll('_', '-');
if (typeof headers[prop] != 'string') {
headers[prop] = JSON.stringify(headers[prop]);
}
@@ -104,22 +105,32 @@ export let get_object = async function get_object(
for (let attempt = 1; attempt <= retry_count; attempt++) {
try {
const response = await fetch_method(url.toString(), fetchOptions)
.catch(function (error) {
console.log('API GET Object *fetch* request was aborted or failed in an unexpected way.', error);
const response = await fetch_method(url.toString(), fetchOptions).catch(function (
error: any
) {
console.log(
'API GET Object *fetch* request was aborted or failed in an unexpected way.',
error
);
});
clearTimeout(timeoutId);
if (!response) {
if (log_lvl > 1) {
console.log('API GET Object: Something went wrong with *fetch* request. Returning false? Throwing an error!');
console.log(
'API GET Object: Something went wrong with *fetch* request. Returning false? Throwing an error!'
);
}
throw new Error(`HTTP fetch request was aborted or failed in an unexpected way! URL = ${url.toString()}`); // This will allow it to retry
throw new Error(
`HTTP fetch request was aborted or failed in an unexpected way! URL = ${url.toString()}`
); // This will allow it to retry
// return false; // This will stop the retries
}
if (log_lvl) {
console.log(`Response: status=${response.status} statusText=${response.statusText} url=${response.url} attempt=${attempt}`);
console.log(
`Response: status=${response.status} statusText=${response.statusText} url=${response.url} attempt=${attempt}`
);
}
if (log_lvl > 1) {
console.log('Response:', response);
@@ -159,23 +170,35 @@ export let get_object = async function get_object(
const percent_completed = Math.round((receivedLength * 100) / contentLength);
if (log_lvl > 1) {
console.log('GET Blob Progress:', percent_completed, 'Total:', contentLength, 'Loaded:', receivedLength, 'Percent Completed', percent_completed);
console.log(
'GET Blob Progress:',
percent_completed,
'Total:',
contentLength,
'Loaded:',
receivedLength,
'Percent Completed',
percent_completed
);
}
temp_get_blob_percent_completed = percent_completed;
try {
if (typeof window !== 'undefined') {
window.postMessage({
type: 'api_download_blob',
status: 'downloading',
task_id: task_id,
endpoint: endpoint,
filename: filename,
size_total: contentLength,
size_loaded: receivedLength,
percent_completed: percent_completed
}, '*');
window.postMessage(
{
type: 'api_download_blob',
status: 'downloading',
task_id: task_id,
endpoint: endpoint,
filename: filename,
size_total: contentLength,
size_loaded: receivedLength,
percent_completed: percent_completed
},
'*'
);
}
} catch (e) {
console.error('Error posting message:', e);
@@ -210,4 +233,4 @@ export let get_object = async function get_object(
}
}
}
};
};

View File

@@ -1,48 +1,46 @@
import axios from 'axios';
import type { key_val } from '$lib/ae_stores';
import type { key_val } from '$lib/stores/ae_stores';
export let temp_get_blob_percent_completed = 0;
// export let get_blob_percent_completed = readable(temp_get_blob_percent_completed);
export let get_blob_percent_completed = temp_get_blob_percent_completed;
export const get_blob_percent_completed = temp_get_blob_percent_completed;
export let temp_get_object_percent_completed = 0;
// export let get_object_percent_completed = readable(temp_get_object_percent_completed);
export let get_object_percent_completed = temp_get_object_percent_completed;
export const get_object_percent_completed = temp_get_object_percent_completed;
// Updated 2024-05-23
export let get_object = async function get_object(
{
api_cfg=null,
endpoint='',
headers={},
params={},
data={},
timeout=60000,
return_meta=false,
return_blob=false,
filename='',
auto_download=false,
as_list=false,
// The task_id value should be a random string that is unique to the task. This is used to identify the task in the message event.
task_id=crypto.randomUUID(),
log_lvl=0
}: {
api_cfg: any,
endpoint: string,
headers?: any,
params?: any,
data?: any,
timeout?: number,
return_meta?: boolean,
return_blob?: boolean,
filename?: null|string,
auto_download?: boolean,
as_list?: boolean,
task_id?: string,
log_lvl?: number
}
) {
export const get_object = async function get_object({
api_cfg = null,
endpoint = '',
headers = {},
params = {},
data = {},
timeout = 60000,
return_meta = false,
return_blob = false,
filename = '',
auto_download = false,
as_list = false,
// The task_id value should be a random string that is unique to the task. This is used to identify the task in the message event.
task_id = crypto.randomUUID(),
log_lvl = 0
}: {
api_cfg: any;
endpoint: string;
headers?: any;
params?: any;
data?: any;
timeout?: number;
return_meta?: boolean;
return_blob?: boolean;
filename?: null | string;
auto_download?: boolean;
as_list?: boolean;
task_id?: string;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** get_object() *** Endpoint: ${endpoint} AE Task ID: ${task_id}`);
console.log('Params:', params);
@@ -52,7 +50,9 @@ export let get_object = async function get_object(
console.log('API Config:', api_cfg);
}
if (log_lvl > 2) {
console.log(`Return Meta: ${return_meta}; Return Blob: ${return_blob}; Filename: ${filename}; Auto Download: ${auto_download}`);
console.log(
`Return Meta: ${return_meta}; Return Blob: ${return_blob}; Filename: ${filename}; Auto Download: ${auto_download}`
);
}
}
@@ -61,9 +61,9 @@ export let get_object = async function get_object(
return false;
}
let axios_api = axios.create({
const axios_api = axios.create({
baseURL: api_cfg['base_url'],
timeout: timeout, // in milliseconds; 60000 = 60 seconds
timeout: timeout // in milliseconds; 60000 = 60 seconds
/* other custom settings */
});
axios_api.defaults.headers = api_cfg['headers'];
@@ -73,10 +73,10 @@ export let get_object = async function get_object(
}
// console.log('Clean the headers. No _underscores_!')
let headers_cleaned: key_val = {};
const headers_cleaned: key_val = {};
for (const prop in headers) {
// No underscores allowed in the header parameters!
let prop_cleaned = prop.replaceAll('_', '-');
const prop_cleaned = prop.replaceAll('_', '-');
// The value must be a string for the header!
if (typeof headers[prop] != 'string') {
@@ -101,133 +101,82 @@ export let get_object = async function get_object(
if (log_lvl > 1) {
console.log(`URL param: ${prop}: ${params[prop]}`);
}
if (params[prop] === null ) {
if (params[prop] === null) {
params[prop] = 'null';
}
}
// Handle the case where there is no Blob expected to be returned. Mainly JSON and text data.
if (!return_blob) {
let response_data_promise = await axios_api.get(
endpoint,
{
headers: headers,
params: params,
onDownloadProgress: (progressEvent) => {
let percent_completed = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
const response_data_promise = await axios_api
.get(endpoint, {
headers: headers,
params: params,
onDownloadProgress: (progressEvent) => {
const percent_completed = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
if (log_lvl > 1) {
console.log(
'GET Data Progress:',
progressEvent.progress,
'Total:',
progressEvent.total,
'Loaded:',
progressEvent.loaded,
'Percent Completed',
percent_completed
);
if (log_lvl > 1) {
console.log('GET Data Progress:', progressEvent.progress, 'Total:', progressEvent.total, 'Loaded:', progressEvent.loaded, 'Percent Completed', percent_completed);
}
}
temp_get_object_percent_completed = percent_completed;
temp_get_object_percent_completed = percent_completed;
// WARNING: This needs to be tied to an object type and ID. This is a temporary solution.
try {
// Check if window is defined. This is to prevent errors in SvelteKit.
if (typeof window !== 'undefined') {
window.postMessage({
type: 'api_download_data',
status: 'downloading',
task_id: task_id,
endpoint: endpoint,
filename: filename,
size_total: progressEvent.total,
size_loaded: progressEvent.loaded,
percent_completed: percent_completed,
// WARNING: This needs to be tied to an object type and ID. This is a temporary solution.
try {
// Check if window is defined. This is to prevent errors in SvelteKit.
if (typeof window !== 'undefined') {
window.postMessage(
{
type: 'api_download_data',
status: 'downloading',
task_id: task_id,
endpoint: endpoint,
filename: filename,
size_total: progressEvent.total,
size_loaded: progressEvent.loaded,
percent_completed: percent_completed
},
'*'
);
}
} catch (error) {
console.log('Error posting message to window:', error);
}
} catch (error) {
console.log('Error posting message to window:', error);
}
}
)
.then(function (response) {
if (log_lvl) {
console.log(`GET Response: status=${response.status} statusText=${response.statusText} baseURL=${response.config.baseURL} url=${response.config.url} method=${response.config.method} headers=${response.config.headers} params=${JSON.stringify(response.config.params)}`);
}
if (log_lvl > 1) {
console.log('GET Response:', response);
}
// Post file download message
try {
if (typeof window !== 'undefined') {
window.postMessage({
type: 'api_download_data',
status: 'complete',
task_id: task_id,
endpoint: endpoint,
filename: filename,
size_total: 0,
size_loaded: 0,
percent_completed: 100,
},
'*'
);
}
} catch (error) {
console.log('Error posting message to window:', error);
}
if (!Array.isArray(response.data['data']) && as_list) {
})
.then(function (response) {
if (log_lvl) {
console.log('Data result is a dictionary/object, not an array/list. Forcing return as an array/list');
}
let return_data = [];
return_data.push(response.data['data']);
return return_data;
} else if (response.data['data']) {
let return_data = response.data['data'];
if (log_lvl) {
if (Array.isArray(return_data)) {
console.log(`Data result is an array/list. Array length: ${return_data.length}`);
} else {
console.log(`Data result is a dictionary/object, not an array/list.`);
}
}
return return_data;
} else {
let return_data = response.data;
if (log_lvl) {
if (Array.isArray(return_data)) {
console.log(`Not a standard response from Aether's API. Data result is an array/list. Array length: ${return_data.length}`);
} else {
console.log(`Not a standard response from Aether's API. Data result is a dictionary/object, not an array/list.`);
}
}
return return_data;
}
})
.catch(function (error) {
// Handle the common and expected 404 "error" first
if (error.response && error.response.status === 404) {
if (log_lvl) {
console.log('The response was a 404 not found "error". Returning null.');
console.log(
`GET Response: status=${response.status} statusText=${response.statusText} baseURL=${response.config.baseURL} url=${response.config.url} method=${response.config.method} headers=${response.config.headers} params=${JSON.stringify(response.config.params)}`
);
}
if (log_lvl > 1) {
console.log(error.response);
}
if (log_lvl > 2) {
console.log(error);
console.log('GET Response:', response);
}
// Post file download message
try {
if (typeof window !== 'undefined') {
window.postMessage({
type: 'api_download_data',
status: 'complete',
task_id: task_id,
endpoint: endpoint,
filename: filename,
size_total: 0,
size_loaded: 0,
percent_completed: 0,
window.postMessage(
{
type: 'api_download_data',
status: 'complete',
task_id: task_id,
endpoint: endpoint,
filename: filename,
size_total: 0,
size_loaded: 0,
percent_completed: 100
},
'*'
);
@@ -235,44 +184,115 @@ export let get_object = async function get_object(
} catch (error) {
console.log('Error posting message to window:', error);
}
return null; // Returning null since there were no results
}
if (log_lvl) {
console.log(`Base URL: ${api_cfg['base_url']} | Endpoint: ${endpoint}`);
console.log('Error Message:', error.message); // Is this needed here or below in the in the else portion???
if (error.response) {
// The request was made and the server responded with a status code that falls out of the range of 2xx
console.log('Error Response Data', error.response.data);
console.log('Error Response Status', error.response.status);
console.log('Error Response Headers', error.response.headers);
} else if (error.request) {
// The request was made but no response was received `error.request` is an instance of XMLHttpRequest in the browser and an instance of http.ClientRequest in node.js
if (log_lvl > 1) {
console.log('Error Request', error.request);
if (!Array.isArray(response.data['data']) && as_list) {
if (log_lvl) {
console.log(
'Data result is a dictionary/object, not an array/list. Forcing return as an array/list'
);
}
const return_data = [];
return_data.push(response.data['data']);
return return_data;
} else if (response.data['data']) {
const return_data = response.data['data'];
if (log_lvl) {
if (Array.isArray(return_data)) {
console.log(
`Data result is an array/list. Array length: ${return_data.length}`
);
} else {
console.log(`Data result is a dictionary/object, not an array/list.`);
}
}
return return_data;
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error Message', error.message);
const return_data = response.data;
if (log_lvl) {
if (Array.isArray(return_data)) {
console.log(
`Not a standard response from Aether's API. Data result is an array/list. Array length: ${return_data.length}`
);
} else {
console.log(
`Not a standard response from Aether's API. Data result is a dictionary/object, not an array/list.`
);
}
}
return return_data;
}
}
if (log_lvl > 2) {
console.log('Error:', error);
console.log(error.config);
}
})
.catch(function (error: any) {
// Handle the common and expected 404 "error" first
if (error.response && error.response.status === 404) {
if (log_lvl) {
console.log('The response was a 404 not found "error". Returning null.');
}
if (log_lvl > 1) {
console.log(error.response);
}
if (log_lvl > 2) {
console.log(error);
}
if (error.code === 'ECONNABORTED') {
// Timeout Error (You can implement retry here where suitable)
console.log('Timeout Error: ', error.message);
}
if (log_lvl) {
console.log('The response was an error. Returning false.');
}
// Post file download message
try {
if (typeof window !== 'undefined') {
window.postMessage(
{
type: 'api_download_data',
status: 'complete',
task_id: task_id,
endpoint: endpoint,
filename: filename,
size_total: 0,
size_loaded: 0,
percent_completed: 0
},
'*'
);
}
} catch (error) {
console.log('Error posting message to window:', error);
}
return null; // Returning null since there were no results
}
return false; // Returning false since something may have gone wrong. This includes timeouts. Also more in line with what the API returns.
// return error;
});
if (log_lvl) {
console.log(`Base URL: ${api_cfg['base_url']} | Endpoint: ${endpoint}`);
console.log('Error Message:', error.message); // Is this needed here or below in the in the else portion???
if (error.response) {
// The request was made and the server responded with a status code that falls out of the range of 2xx
console.log('Error Response Data', error.response.data);
console.log('Error Response Status', error.response.status);
console.log('Error Response Headers', error.response.headers);
} else if (error.request) {
// The request was made but no response was received `error.request` is an instance of XMLHttpRequest in the browser and an instance of http.ClientRequest in node.js
if (log_lvl > 1) {
console.log('Error Request', error.request);
}
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error Message', error.message);
}
}
if (log_lvl > 2) {
console.log('Error:', error);
console.log(error.config);
}
if (error.code === 'ECONNABORTED') {
// Timeout Error (You can implement retry here where suitable)
console.log('Timeout Error: ', error.message);
}
if (log_lvl) {
console.log('The response was an error. Returning false.');
}
return false; // Returning false since something may have gone wrong. This includes timeouts. Also more in line with what the API returns.
// return error;
});
if (log_lvl > 1) {
// console.log(`Response Data: ${response_data_promise}`);
@@ -299,124 +319,86 @@ export let get_object = async function get_object(
Promise.reject(new Error('fail')).then(resolved, rejected);
}
// Handle the case where a Blob is expected to be returned.
// Handle the case where a Blob is expected to be returned.
} else {
// console.log('Expecting a Blob to be returned...');
let response_data_promise = await axios_api.get(
endpoint,
{
params: params,
responseType: 'blob',
onDownloadProgress: (progressEvent) => {
let percent_completed = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
console.log('GET Blob Progress:', progressEvent.progress, 'Total:', progressEvent.total, 'Loaded:', progressEvent.loaded, 'Percent Completed', percent_completed);
const response_data_promise = await axios_api
.get(endpoint, {
params: params,
responseType: 'blob',
onDownloadProgress: (progressEvent) => {
const percent_completed = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
console.log(
'GET Blob Progress:',
progressEvent.progress,
'Total:',
progressEvent.total,
'Loaded:',
progressEvent.loaded,
'Percent Completed',
percent_completed
);
temp_get_blob_percent_completed = percent_completed;
temp_get_blob_percent_completed = percent_completed;
// WARNING: This needs to be tied to an object type and ID. This is a temporary solution.
try {
if (typeof window !== 'undefined') {
window.postMessage({
type: 'api_download_blob',
status: 'downloading',
task_id: task_id,
endpoint: endpoint,
filename: filename,
size_total: progressEvent.total,
size_loaded: progressEvent.loaded,
percent_completed: percent_completed,
// WARNING: This needs to be tied to an object type and ID. This is a temporary solution.
try {
if (typeof window !== 'undefined') {
window.postMessage(
{
type: 'api_download_blob',
status: 'downloading',
task_id: task_id,
endpoint: endpoint,
filename: filename,
size_total: progressEvent.total,
size_loaded: progressEvent.loaded,
percent_completed: percent_completed
},
'*'
);
}
} catch (error) {
console.log('Error posting message to window:', error);
}
} catch (error) {
console.log('Error posting message to window:', error);
}
}
)
.then(function (response) {
if (log_lvl) {
console.log(`GET (blob) Response: status=${response.status} statusText=${response.statusText} baseURL=${response.config.baseURL} url=${response.config.url} method=${response.config.method} headers=${response.config.headers} params=${response.config.params}`);
}
if (log_lvl > 1) {
console.log('GET (blob) Response:', response);
}
const { data, headers } = response;
// Careful if this download filename needs to be changed to a different file extension. The browser/client may not know how to handle it.
if (filename) {
} else if (headers['content-disposition']) {
filename = headers['content-disposition'].replace(/\w+;filename=(.*)/, '$1');
} else {
filename = 'unknown_file.ext';
}
// WARNING: This needs to be tied to an object type and ID. This is a temporary solution.
try {
if (typeof window !== 'undefined') {
window.postMessage({
type: 'api_download_blob',
status: 'complete',
task_id: task_id,
endpoint: endpoint,
filename: filename,
size_total: 0,
size_loaded: 0,
percent_completed: 100,
},
'*'
);
}
} catch (error) {
console.log('Error posting message to window:', error);
}
if (auto_download) {
})
.then(function (response) {
if (log_lvl) {
console.log(`Auto Download: ${filename}`);
}
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', filename);
document.body.appendChild(link);
link.click();
return true;
} else {
return response;
}
})
.catch(function (error) {
// Handle the common and expected 404 "error" first
if (error.response && error.response.status === 404) {
if (log_lvl) {
console.log('The response was a 404 not found "error". Returning null.');
console.log(
`GET (blob) Response: status=${response.status} statusText=${response.statusText} baseURL=${response.config.baseURL} url=${response.config.url} method=${response.config.method} headers=${response.config.headers} params=${response.config.params}`
);
}
if (log_lvl > 1) {
console.log(error.response);
}
if (log_lvl > 2) {
console.log(error);
console.log('GET (blob) Response:', response);
}
// Post file download message
const { data, headers } = response;
// Careful if this download filename needs to be changed to a different file extension. The browser/client may not know how to handle it.
if (filename) {
} else if (headers['content-disposition']) {
filename = headers['content-disposition'].replace(/\w+;filename=(.*)/, '$1');
} else {
filename = 'unknown_file.ext';
}
// WARNING: This needs to be tied to an object type and ID. This is a temporary solution.
try {
if (typeof window !== 'undefined') {
window.postMessage({
type: 'api_download_blob',
status: 'complete',
task_id: task_id,
endpoint: endpoint,
filename: filename,
size_total: 0,
size_loaded: 0,
percent_completed: 0,
window.postMessage(
{
type: 'api_download_blob',
status: 'complete',
task_id: task_id,
endpoint: endpoint,
filename: filename,
size_total: 0,
size_loaded: 0,
percent_completed: 100
},
'*'
);
@@ -424,41 +406,90 @@ export let get_object = async function get_object(
} catch (error) {
console.log('Error posting message to window:', error);
}
return null; // Returning null since there were no results
}
if (log_lvl) {
console.log(`Base URL: ${api_cfg['base_url']} | Endpoint: ${endpoint}`);
console.log('Error Message:', error.message); // Is this needed here or below in the in the else portion???
if (error.response) {
// The request was made and the server responded with a status code that falls out of the range of 2xx
console.log('Error Response Data', error.response.data);
console.log('Error Response Status', error.response.status);
console.log('Error Response Headers', error.response.headers);
} else if (error.request) {
// The request was made but no response was received `error.request` is an instance of XMLHttpRequest in the browser and an instance of http.ClientRequest in node.js
if (log_lvl > 1) {
console.log('Error Request', error.request);
if (auto_download) {
if (log_lvl) {
console.log(`Auto Download: ${filename}`);
}
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', filename);
document.body.appendChild(link);
link.click();
return true;
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error Message', error.message);
return response;
}
}
})
.catch(function (error: any) {
// Handle the common and expected 404 "error" first
if (error.response && error.response.status === 404) {
if (log_lvl) {
console.log('The response was a 404 not found "error". Returning null.');
}
if (log_lvl > 1) {
console.log(error.response);
}
if (log_lvl > 2) {
console.log(error);
}
if (error.code === 'ECONNABORTED') {
// Timeout Error (You can implement retry here where suitable)
console.log('Timeout Error: ', error.message);
}
// Post file download message
try {
if (typeof window !== 'undefined') {
window.postMessage(
{
type: 'api_download_blob',
status: 'complete',
task_id: task_id,
endpoint: endpoint,
filename: filename,
size_total: 0,
size_loaded: 0,
percent_completed: 0
},
'*'
);
}
} catch (error) {
console.log('Error posting message to window:', error);
}
return null; // Returning null since there were no results
}
if (log_lvl) {
console.log('The response was an error. Returning false.');
}
if (log_lvl) {
console.log(`Base URL: ${api_cfg['base_url']} | Endpoint: ${endpoint}`);
console.log('Error Message:', error.message); // Is this needed here or below in the in the else portion???
return false; // Returning false since something may have gone wrong. This includes timeouts. Also more in line with what the API returns.
// return error;
});
if (error.response) {
// The request was made and the server responded with a status code that falls out of the range of 2xx
console.log('Error Response Data', error.response.data);
console.log('Error Response Status', error.response.status);
console.log('Error Response Headers', error.response.headers);
} else if (error.request) {
// The request was made but no response was received `error.request` is an instance of XMLHttpRequest in the browser and an instance of http.ClientRequest in node.js
if (log_lvl > 1) {
console.log('Error Request', error.request);
}
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error Message', error.message);
}
}
if (error.code === 'ECONNABORTED') {
// Timeout Error (You can implement retry here where suitable)
console.log('Timeout Error: ', error.message);
}
if (log_lvl) {
console.log('The response was an error. Returning false.');
}
return false; // Returning false since something may have gone wrong. This includes timeouts. Also more in line with what the API returns.
// return error;
});
if (response_data_promise) {
// The most common and expected response.
@@ -484,8 +515,7 @@ export let get_object = async function get_object(
Promise.reject(new Error('fail')).then(resolved, rejected);
}
}
}
};
function resolved(result: any) {
console.log('Resolved');
@@ -493,4 +523,4 @@ function resolved(result: any) {
function rejected(result: any) {
console.error(result);
}
}

View File

@@ -1,25 +1,23 @@
// import axios from 'axios';
// Updated 2024-05-23
export let patch_object = async function patch_object(
{
api_cfg = null,
endpoint = '',
params = {},
data = {},
return_meta = false,
log_lvl = 0,
retry_count = 5 // Number of retry attempts
}: {
api_cfg: any,
endpoint: string,
params?: any,
data?: any,
return_meta?: boolean,
log_lvl?: number,
retry_count?: number
}
) {
export const patch_object = async function patch_object({
api_cfg = null,
endpoint = '',
params = {},
data = {},
return_meta = false,
log_lvl = 0,
retry_count = 5 // Number of retry attempts
}: {
api_cfg: any;
endpoint: string;
params?: any;
data?: any;
return_meta?: boolean;
log_lvl?: number;
retry_count?: number;
}) {
if (log_lvl) {
console.log(`*** patch_object() *** Endpoint: ${endpoint}`);
console.log('Params:', params);
@@ -35,12 +33,12 @@ export let patch_object = async function patch_object(
// Construct the URL with query parameters
const url = new URL(endpoint, api_cfg['base_url']);
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
Object.keys(params).forEach((key) => url.searchParams.append(key, params[key]));
// Clean the headers
let headers_cleaned: Record<string, string> = {};
const headers_cleaned: Record<string, string> = {};
for (const prop in api_cfg['headers']) {
let prop_cleaned = prop.replaceAll('_', '-');
const prop_cleaned = prop.replaceAll('_', '-');
headers_cleaned[prop_cleaned] = api_cfg['headers'][prop];
}
@@ -101,8 +99,6 @@ export let patch_object = async function patch_object(
}
}
// let axios_api = axios.create({
// baseURL: api_cfg['base_url'],
// /* other custom settings */
@@ -145,5 +141,4 @@ export let patch_object = async function patch_object(
// }
// }
// return response_data;
}
};

View File

@@ -1,42 +1,39 @@
// import axios from 'axios';
export let temp_post_blob_percent_completed = 0;
export let post_blob_percent_completed = temp_post_blob_percent_completed;
export let temp_post_object_percent_completed = 0;
export let post_object_percent_completed = temp_post_object_percent_completed;
export const temp_post_blob_percent_completed = 0;
export const post_blob_percent_completed = temp_post_blob_percent_completed;
export const temp_post_object_percent_completed = 0;
export const post_object_percent_completed = temp_post_object_percent_completed;
// Updated 2024-05-23
export let post_object = async function post_object(
{
api_cfg = null,
endpoint = '',
params = {},
data = {},
form_data = null,
return_meta = false,
return_blob = false,
filename = '',
auto_download = false,
// The task_id value should be a random string that is unique to the task. This is used to identify the task in the message event.
task_id = crypto.randomUUID(),
log_lvl = 0,
retry_count = 5
}: {
api_cfg: any,
endpoint: string,
params?: any,
data?: any,
form_data?: any,
return_meta?: boolean,
return_blob?: boolean,
filename?: string,
auto_download?: boolean,
task_id?: string,
log_lvl?: number,
retry_count?: number
}
) {
export const post_object = async function post_object({
api_cfg = null,
endpoint = '',
params = {},
data = {},
form_data = null,
return_meta = false,
return_blob = false,
filename = '',
auto_download = false,
// The task_id value should be a random string that is unique to the task. This is used to identify the task in the message event.
task_id = crypto.randomUUID(),
log_lvl = 0,
retry_count = 5
}: {
api_cfg: any;
endpoint: string;
params?: any;
data?: any;
form_data?: any;
return_meta?: boolean;
return_blob?: boolean;
filename?: string;
auto_download?: boolean;
task_id?: string;
log_lvl?: number;
retry_count?: number;
}) {
if (log_lvl) {
console.log(`*** post_object() *** Endpoint: ${endpoint} Task ID: ${task_id}`);
console.log('Params:', params);
@@ -66,15 +63,15 @@ export let post_object = async function post_object(
// Construct the URL with query parameters
const url = new URL(endpoint, api_cfg['base_url']);
if (params) {
Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
Object.keys(params).forEach((key) => url.searchParams.append(key, params[key]));
}
// console.log('HERE!! API POST 2');
// Clean the headers
let headers_cleaned: Record<string, string> = {};
const headers_cleaned: Record<string, string> = {};
for (const prop in api_cfg['headers']) {
let prop_cleaned = prop.replaceAll('_', '-');
const prop_cleaned = prop.replaceAll('_', '-');
headers_cleaned[prop_cleaned] = api_cfg['headers'][prop];
}
@@ -133,17 +130,20 @@ export let post_object = async function post_object(
// Post a message to the window indicating the upload is complete
try {
window.postMessage({
type: 'api_post_json_form',
status: 'complete',
task_id: task_id,
endpoint: endpoint,
size_total: 0,
size_loaded: 0,
percent_completed: 100,
progress: 100,
rate: 0
}, '*');
window.postMessage(
{
type: 'api_post_json_form',
status: 'complete',
task_id: task_id,
endpoint: endpoint,
size_total: 0,
size_loaded: 0,
percent_completed: 100,
progress: 100,
rate: 0
},
'*'
);
} catch (error) {
console.error('Error posting message to window:', error);
}
@@ -182,8 +182,6 @@ export let post_object = async function post_object(
}
}
// let axios_api = axios.create({
// baseURL: api_cfg['base_url'],
// /* other custom settings */
@@ -200,7 +198,6 @@ export let post_object = async function post_object(
// axios_api.defaults.headers['content-type'] = 'application/json';
// }
// if (!return_blob) {
// let response_data = await axios_api.post(
// endpoint,
@@ -266,7 +263,7 @@ export let post_object = async function post_object(
// }
// //return response.data;
// })
// .catch(function (error) {
// .catch(function (error: any) {
// if (error.response && error.response.status === 404) {
// return null; // Returning null since there were no results
// }
@@ -343,8 +340,7 @@ export let post_object = async function post_object(
// Promise.reject(new Error('fail')).then(resolved, rejected);
// }
// }
}
};
// function resolved(result: any) {
// console.log('Resolved');
@@ -352,4 +348,4 @@ export let post_object = async function post_object(
// function rejected(result: any) {
// console.error(result);
// }
// }

View File

@@ -0,0 +1,28 @@
# Aether (AE) Archives Module
The Archives module is a system for storing and retrieving archived data. It is composed of two main data structures: `Archive` and `Archive_Content`.
## Data Structures
### Archive
An `Archive` is a container for a collection of `Archive_Content` items. It has a name, description, and other metadata.
### Archive Content
An `Archive_Content` item represents a single piece of content within an `Archive`. This can be text, a file, a URL, or other data.
## Functionality
This module provides the following functionality:
- **CRUD Operations:** Create, Read, Update, and Delete operations for both `Archive` and `Archive_Content` objects.
- **Local Caching:** Uses Dexie.js to cache data in the browser's IndexedDB for offline access and faster load times.
- **API Interaction:** All data operations are synced with the backend API.
## Files
- `ae_archives__archive.ts`: Contains functions for managing `Archive` objects.
- `ae_archives__archive_content.ts`: Contains functions for managing `Archive_Content` objects.
- `ae_archives_functions.ts`: Exports all the functions from the module for easy use in other parts of the application.
- `db_archives.ts`: Defines the IndexedDB schema for the archives module using Dexie.js.

File diff suppressed because it is too large Load Diff

View File

@@ -1,214 +1,223 @@
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api';
import type { key_val } from '$lib/stores/ae_stores';
import { api } from '$lib/api/api';
import { db_save_ae_obj_li__ae_obj } from "$lib/ae_core/core__idb_dexie";
import { db_archives } from "$lib/ae_archives/db_archives";
let ae_promises: key_val = {};
import { db_save_ae_obj_li__ae_obj } from '$lib/ae_core/core__idb_dexie';
import { db_archives } from '$lib/ae_archives/db_archives';
const ae_promises: key_val = {};
// TESTING NOTE: I changed these to all use async and await. Not sure if this helps or hurts things. Mainly this is related to the Dexie DB changes. 2024-11-08
// Updated 2024-09-25
export async function load_ae_obj_id__archive_content(
{
api_cfg,
archive_content_id,
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
archive_content_id: string,
try_cache?: boolean,
log_lvl?: number
}
) {
export async function load_ae_obj_id__archive_content({
api_cfg,
archive_content_id,
// enabled = 'enabled',
// hidden = 'not_hidden',
// limit = 99,
// offset = 0,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
archive_content_id: string;
// enabled?: "enabled" | "all" | "not_enabled" | undefined,
// hidden?: "hidden" | "all" | "not_hidden" | undefined,
// limit?: number,
// offset?: number,
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** load_ae_obj_id__archive_content() *** archive_content_id=${archive_content_id}`);
console.log(
`*** load_ae_obj_id__archive_content() *** archive_content_id=${archive_content_id}`
);
}
let params = {};
ae_promises.load__archive_content_obj = await api.get_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'archive_content',
obj_id: archive_content_id, // NOTE: This is the FQDN, not normally the ID.
use_alt_table: false, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value
params: params,
log_lvl: log_lvl
ae_promises.load__archive_content_obj = await api
.get_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'archive_content',
obj_id: archive_content_id,
use_alt_table: false,
use_alt_base: false,
params: params,
log_lvl: log_lvl
})
.then(async function (archive_content_obj_get_result) {
if (archive_content_obj_get_result) {
if (try_cache) {
// Process the results first
let processed_obj_li = await process_ae_obj__archive_content_props({
obj_li: [archive_content_obj_get_result],
log_lvl: log_lvl,
.then(async function (archive_content_obj_get_result) {
if (archive_content_obj_get_result) {
if (try_cache) {
// Process the results first
const processed_obj_li = await process_ae_obj__archive_content_props({
obj_li: [archive_content_obj_get_result],
log_lvl: log_lvl
});
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
// Save the updated results list to the database
if (log_lvl) {
console.log('Saving to DB...');
}
await db_save_ae_obj_li__ae_obj({
db_instance: db_archives,
table_name: 'content',
obj_li: processed_obj_li,
properties_to_save: properties_to_save,
log_lvl: log_lvl,
});
if (log_lvl) {
console.log('DB save completed.');
}
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
// Save the updated results list to the database
if (log_lvl) {
console.log('Saving to DB...');
}
await db_save_ae_obj_li__ae_obj({
db_instance: db_archives,
table_name: 'content',
obj_li: processed_obj_li,
properties_to_save: properties_to_save,
log_lvl: log_lvl
});
if (log_lvl) {
console.log('DB save completed.');
}
// // This is expecting a list
// await db_save_ae_obj_li__archive_content({
// obj_type: 'archive_content',
// obj_li: [archive_content_obj_get_result]
// // This is expecting a list
// await db_save_ae_obj_li__archive_content({
// obj_type: 'archive_content',
// obj_li: [archive_content_obj_get_result]
// });
// });
}
return archive_content_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
return archive_content_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
return ae_promises.load__archive_content_obj;
}
// Updated 2024-11-20
export async function load_ae_obj_li__archive_content(
{
api_cfg,
for_obj_type = 'archive',
for_obj_id,
enabled = 'enabled',
hidden = 'not_hidden',
limit = 99,
offset = 0,
order_by_li = {'priority': 'DESC', 'sort': 'DESC', 'original_datetime': 'ASC', 'name': 'ASC', 'updated_on': 'DESC', 'created_on': 'DESC'},
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
for_obj_type: string,
for_obj_id: string,
enabled?: string,
hidden?: string,
limit?: number,
offset?: number,
order_by_li?: key_val,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
export async function load_ae_obj_li__archive_content({
api_cfg,
for_obj_type = 'archive',
for_obj_id,
enabled = 'enabled',
hidden = 'not_hidden',
limit = 99,
offset = 0,
order_by_li = {
priority: 'DESC',
sort: 'DESC',
original_datetime: 'ASC',
name: 'ASC',
updated_on: 'DESC',
created_on: 'DESC'
},
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
for_obj_type: string;
for_obj_id: string;
enabled?: 'enabled' | 'all' | 'not_enabled' | undefined;
hidden?: 'hidden' | 'all' | 'not_hidden' | undefined;
limit?: number;
offset?: number;
order_by_li?: key_val;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** load_ae_obj_li__archive_content() *** for_obj_type=${for_obj_type} for_obj_id=${for_obj_id}`);
console.log(
`*** load_ae_obj_li__archive_content() *** for_obj_type=${for_obj_type} for_obj_id=${for_obj_id}`
);
}
// let enabled: string = (params.qry__enabled ?? 'enabled'); // all, disabled, enabled
// let hidden: string = (params.qry__hidden ?? 'not_hidden'); // all, hidden, not_hidden
// let limit: number = (params.qry__limit ?? 99); // 99
// let offset: number = (params.qry__offset ?? 0); // 0
let params_json: key_val = {};
const params_json: key_val = {};
// console('params_json:', params_json);
ae_promises.load__archive_content_obj_li = await api.get_ae_obj_li_for_obj_id_crud_v2({
api_cfg: api_cfg,
obj_type: 'archive_content',
for_obj_type: for_obj_type,
for_obj_id: for_obj_id,
use_alt_tbl: false,
use_alt_mdl: false,
use_alt_exp: false,
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
ae_promises.load__archive_content_obj_li = await api
.get_ae_obj_li_for_obj_id_crud_v2({
api_cfg: api_cfg,
obj_type: 'archive_content',
for_obj_type: for_obj_type,
for_obj_id: for_obj_id,
use_alt_tbl: false,
use_alt_mdl: false,
use_alt_exp: false,
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
})
.then(async function (archive_content_obj_li_get_result) {
if (archive_content_obj_li_get_result) {
if (try_cache) {
// Process the results first
let processed_obj_li = await process_ae_obj__archive_content_props({
obj_li: archive_content_obj_li_get_result,
log_lvl: log_lvl,
.then(async function (archive_content_obj_li_get_result) {
if (archive_content_obj_li_get_result) {
if (try_cache) {
// Process the results first
const processed_obj_li = await process_ae_obj__archive_content_props({
obj_li: archive_content_obj_li_get_result,
log_lvl: log_lvl
});
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
// Save the updated results list to the database
if (log_lvl) {
console.log('Saving to DB...');
}
await db_save_ae_obj_li__ae_obj({
db_instance: db_archives,
table_name: 'content',
obj_li: processed_obj_li,
properties_to_save: properties_to_save,
log_lvl: log_lvl,
});
if (log_lvl) {
console.log('DB save completed.');
}
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
// Save the updated results list to the database
if (log_lvl) {
console.log('Saving to DB...');
}
await db_save_ae_obj_li__ae_obj({
db_instance: db_archives,
table_name: 'content',
obj_li: processed_obj_li,
properties_to_save: properties_to_save,
log_lvl: log_lvl
});
if (log_lvl) {
console.log('DB save completed.');
}
// await db_save_ae_obj_li__archive_content({
// obj_type: 'archive_content', obj_li: archive_content_obj_li_get_result
// });
// await db_save_ae_obj_li__archive_content({
// obj_type: 'archive_content', obj_li: archive_content_obj_li_get_result
// });
}
return archive_content_obj_li_get_result;
} else {
return [];
}
return archive_content_obj_li_get_result;
} else {
return [];
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
if (log_lvl) {
console.log('ae_promises.load__archive_content_obj_li:', ae_promises.load__archive_content_obj_li);
console.log(
'ae_promises.load__archive_content_obj_li:',
ae_promises.load__archive_content_obj_li
);
}
return ae_promises.load__archive_content_obj_li;
}
// Updated 2025-06-23
export async function create_ae_obj__archive_content(
{
api_cfg,
archive_id,
data_kv,
params={},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
archive_id: string,
data_kv: key_val,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
export async function create_ae_obj__archive_content({
api_cfg,
archive_id,
data_kv,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
archive_id: string;
data_kv: key_val;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** create_ae_obj__archive_content() *** archive_id=${archive_id}`);
}
@@ -218,58 +227,59 @@ export async function create_ae_obj__archive_content(
return false;
}
ae_promises.create__archive_content = await api.create_ae_obj_crud({
api_cfg: api_cfg,
obj_type: 'archive_content',
fields: {
archive_id_random: archive_id,
...data_kv
ae_promises.create__archive_content = await api
.create_ae_obj_crud({
api_cfg: api_cfg,
obj_type: 'archive_content',
fields: {
archive_id_random: archive_id,
...data_kv
},
key: api_cfg.api_crud_super_key,
params: params,
return_obj: true,
log_lvl: log_lvl
})
.then(async function (archive_content_obj_create_result) {
if (archive_content_obj_create_result) {
if (try_cache) {
// Process the results first
let processed_obj_li = await process_ae_obj__archive_content_props({
obj_li: [archive_content_obj_create_result],
log_lvl: log_lvl,
key: api_cfg.api_crud_super_key,
params: params,
return_obj: true,
log_lvl: log_lvl
})
.then(async function (archive_content_obj_create_result) {
if (archive_content_obj_create_result) {
if (try_cache) {
// Process the results first
const processed_obj_li = await process_ae_obj__archive_content_props({
obj_li: [archive_content_obj_create_result],
log_lvl: log_lvl
});
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
// Save the updated results list to the database
if (log_lvl) {
console.log('Saving to DB...');
}
await db_save_ae_obj_li__ae_obj({
db_instance: db_archives,
table_name: 'content',
obj_li: processed_obj_li,
properties_to_save: properties_to_save,
log_lvl: log_lvl,
});
if (log_lvl) {
console.log('DB save completed.');
}
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
// Save the updated results list to the database
if (log_lvl) {
console.log('Saving to DB...');
}
await db_save_ae_obj_li__ae_obj({
db_instance: db_archives,
table_name: 'content',
obj_li: processed_obj_li,
properties_to_save: properties_to_save,
log_lvl: log_lvl
});
if (log_lvl) {
console.log('DB save completed.');
}
// await db_save_ae_obj_li__archive_content(
// {
// obj_type: 'archive_content',
// obj_li: [archive_content_obj_create_result]
// });
// await db_save_ae_obj_li__archive_content(
// {
// obj_type: 'archive_content',
// obj_li: [archive_content_obj_create_result]
// });
}
return archive_content_obj_create_result;
} else {
return null;
}
return archive_content_obj_create_result;
} else {
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
if (log_lvl) {
console.log('ae_promises.create__archive_content:', ae_promises.create__archive_content);
@@ -277,78 +287,83 @@ export async function create_ae_obj__archive_content(
return ae_promises.create__archive_content;
}
// Updated 2024-11-08
export async function delete_ae_obj_id__archive_content(
{
api_cfg,
archive_content_id,
method = 'delete', // 'delete', 'disable', 'hide'
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
archive_content_id: string,
method?: string,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
export async function delete_ae_obj_id__archive_content({
api_cfg,
archive_content_id,
method = 'delete', // 'delete', 'disable', 'hide'
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
archive_content_id: string;
method?: string;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** delete_ae_obj_id__archive_content() *** archive_content_id=${archive_content_id}`);
console.log(
`*** delete_ae_obj_id__archive_content() *** archive_content_id=${archive_content_id}`
);
}
ae_promises.delete__archive_content_obj = await api.delete_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'archive_content',
obj_id: archive_content_id,
key: api_cfg.api_crud_super_key,
params: params,
method: method,
log_lvl: log_lvl
ae_promises.delete__archive_content_obj = await api
.delete_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'archive_content',
obj_id: archive_content_id,
key: api_cfg.api_crud_super_key,
params: params,
method: method,
log_lvl: log_lvl
})
.catch(function (error) {
console.log('No results returned or failed.', error);
})
.finally(function () {
if (try_cache) {
if (log_lvl) {
console.log(`Attempting to remove IDB entry for archive_content_id=${archive_content_id}`);
.catch(function (error: any) {
console.log('No results returned or failed.', error);
})
.finally(function () {
if (try_cache) {
if (log_lvl) {
console.log(
`Attempting to remove IDB entry for archive_content_id=${archive_content_id}`
);
}
db_archives.content.delete(archive_content_id); // Delete from the DB no matter what.
}
db_archives.content.delete(archive_content_id); // Delete from the DB no matter what.
}
});
});
if (log_lvl) {
console.log('ae_promises.delete__archive_content_obj:', ae_promises.delete__archive_content_obj);
console.log(
'ae_promises.delete__archive_content_obj:',
ae_promises.delete__archive_content_obj
);
}
return ae_promises.delete__archive_content_obj;
}
// Updated 2025-06-23
export async function update_ae_obj__archive_content(
{
api_cfg,
archive_content_id,
data_kv,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
archive_content_id: string,
data_kv: key_val,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
export async function update_ae_obj__archive_content({
api_cfg,
archive_content_id,
data_kv,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
archive_content_id: string;
data_kv: key_val;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** update_ae_obj__archive_content() *** archive_content_id=${archive_content_id}`, data_kv);
console.log(
`*** update_ae_obj__archive_content() *** archive_content_id=${archive_content_id}`,
data_kv
);
}
// Perform the API update
@@ -360,17 +375,17 @@ export async function update_ae_obj__archive_content(
key: api_cfg.api_crud_super_key,
params: params,
return_obj: true,
log_lvl: log_lvl,
log_lvl: log_lvl
});
// Handle the result
if (result) {
if (try_cache) {
// Process the results first
let processed_obj_li = await process_ae_obj__archive_content_props({
const processed_obj_li = await process_ae_obj__archive_content_props({
obj_li: [result],
log_lvl: log_lvl,
});
log_lvl: log_lvl
});
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
@@ -383,7 +398,7 @@ export async function update_ae_obj__archive_content(
table_name: 'content',
obj_li: processed_obj_li,
properties_to_save: properties_to_save,
log_lvl: log_lvl,
log_lvl: log_lvl
});
if (log_lvl) {
console.log('DB save completed.');
@@ -402,99 +417,6 @@ export async function update_ae_obj__archive_content(
}
}
// This function will loop through the archive_content_obj_li and save each one to the DB.
// Updated 2024-09-25
export async function db_save_ae_obj_li__archive_content(
{
obj_type,
obj_li,
log_lvl = 0
}: {
obj_type: string,
obj_li: any,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** db_save_ae_obj_li__archive_content() ***`);
}
if (obj_li && obj_li.length) {
obj_li.forEach(async function (obj: any) {
if (log_lvl) {
console.log(`ae_obj ${obj_type}:`, obj);
}
try {
const id_random = await db_archives.content.put({
id: obj.archive_content_id_random,
archive_content_id: obj.archive_content_id_random,
archive_id: obj.archive_id_random,
archive_content_type: obj.archive_content_type,
name: obj.name,
description: obj.description,
content_html: obj.content_html,
content_json: obj.content_json,
url: obj.url,
url_text: obj.url_text,
hosted_file_id: obj.hosted_file_id_random,
file_path: obj.file_path,
filename: obj.filename,
file_extension: obj.file_extension,
original_datetime: obj.original_datetime,
original_timezone: obj.original_timezone,
original_location: obj.original_location,
original_url: obj.original_url,
original_url_text: obj.original_url_text,
enable_for_public: obj.enable_for_public,
cfg_json: obj.cfg_json,
enable: obj.enable,
hide: obj.hide,
priority: obj.priority,
sort: obj.sort,
group: obj.group,
notes: obj.notes,
created_on: obj.created_on,
updated_on: obj.updated_on,
// Generated fields for sorting locally only
tmp_sort_1: `${obj.original_datetime}_${obj.group}_${obj.priority}_${obj.sort}`,
tmp_sort_2: `${obj.group}_${obj.original_datetime}_${obj.priority}_${obj.sort}`,
// From SQL view
archive_code: obj.archive_code,
archive_name: obj.archive_name,
hash_sha256: obj.hosted_file_hash_sha256
});
// console.log(`Put obj with ID: ${obj.archive_content_id_random} or ${id_random}`);
} catch (error) {
let status = `Failed to put ${obj.archive_content_id_random}: ${error}`;
console.log(status);
}
// const id_random = await db_archives.content.put(obj);
// console.log(`Put obj with ID: ${obj.archive_content_id_random}`);
});
return true;
}
}
// Updated 2025-06-04
export const properties_to_save = [
'id',
@@ -555,91 +477,101 @@ export const properties_to_save = [
'hash_sha256'
];
// Updated 2025-06-04
export async function process_ae_obj__archive_content_props({
/**
* NON-EXPORTED LOCAL HELPER
* Processes a list of Aether objects by applying common and specific transformations.
*/
async function _process_generic_props<T extends Record<string, any>>({
obj_li,
obj_type,
log_lvl = 0,
specific_processor
}: {
obj_li: any[];
obj_li: T[];
obj_type: string;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** process_ae_obj__archive_content_props() ***`, obj_li);
specific_processor?: (obj: T) => Promise<T> | T;
}): Promise<T[]> {
if (log_lvl > 0) {
console.log(
`*** _process_generic_props: Processing ${obj_li.length} objects of type "${obj_type}" ***`
);
}
if (!obj_li || obj_li.length === 0) {
if (log_lvl) console.log('No objects to process.');
if (log_lvl > 0) console.log('No objects to process.');
return [];
}
const processed_obj_li = [];
const processed_obj_li: T[] = [];
for (const obj of obj_li) {
if (log_lvl) console.log(`Processing ae_obj archive_content:`, obj);
for (const original_obj of obj_li) {
let processed_obj = { ...original_obj };
let processed_obj = {
id: obj.archive_content_id_random,
archive_content_id: obj.archive_content_id_random,
// archive_content_id_random: obj.archive_content_id_random,
// --- Common Transformations ---
archive_id: obj.archive_id_random,
// archive_id_random: obj.archive_id_random,
// 1. Standardize ID and other '_random' fields
// The API often returns fields like 'person_id_random', which need to be aliased to 'person_id'.
for (const key in processed_obj) {
if (key.endsWith('_random')) {
const newKey = key.slice(0, -7); // Remove '_random' suffix
processed_obj[newKey] = processed_obj[key];
}
}
// Ensure 'id' is set from '[obj_type]_id_random'
const randomIdKey = `${obj_type}_id_random`;
if (processed_obj[randomIdKey]) {
(processed_obj as any).id = processed_obj[randomIdKey];
}
archive_content_type: obj.archive_content_type,
// 2. Create common computed properties for client-side sorting.
const group = processed_obj.group ?? '0';
const priority = processed_obj.priority ? 1 : 0;
const sort = processed_obj.sort ?? '0';
const updated = processed_obj.updated_on ?? processed_obj.created_on;
const name = processed_obj.name ?? '';
name: obj.name,
description: obj.description,
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
content_html: obj.content_html,
content_json: obj.content_json,
// --- Specific Transformations ---
if (specific_processor) {
processed_obj = await Promise.resolve(specific_processor(processed_obj));
}
url: obj.url,
url_text: obj.url_text,
hosted_file_id: obj.hosted_file_id_random,
hosted_file_id_random: obj.hosted_file_id_random,
file_path: obj.file_path,
filename: obj.filename,
file_extension: obj.file_extension,
original_datetime: obj.original_datetime,
original_timezone: obj.original_timezone,
original_location: obj.original_location,
original_url: obj.original_url,
original_url_text: obj.original_url_text,
enable_for_public: obj.enable_for_public,
cfg_json: obj.cfg_json,
enable: obj.enable,
hide: obj.hide,
priority: obj.priority,
sort: obj.sort,
group: obj.group,
notes: obj.notes,
created_on: obj.created_on,
updated_on: obj.updated_on,
// Generated fields for sorting locally only
tmp_sort_1: `${obj.group ?? ''}_${obj.priority ? '1' : '0'}_${obj.sort?.toString().padStart(3, '0') ?? ''}_${obj.original_datetime ?? ''}`,
tmp_sort_2: `${obj.group ?? ''}_${obj.original_datetime ?? ''}_${obj.priority ? '1' : '0'}_${obj.sort?.toString().padStart(3, '0') ?? ''}`,
tmp_sort_3: `${obj.original_datetime ?? ''}_${obj.group ?? ''}_${obj.priority ? '1' : '0'}_${obj.sort?.toString().padStart(3, '0') ?? ''}`,
// tmp_sort_a: `${obj.group}_${obj.priority}_${obj.sort}_${obj.updated_on ?? obj.created_on}`,
// tmp_sort_b: `${obj.group}_${obj.priority}_${obj.sort}_${obj.updated_on}_${obj.created_on}`,
// From SQL view
archive_code: obj.archive_code,
archive_name: obj.archive_name,
hash_sha256: obj.hosted_file_hash_sha256
};
processed_obj_li.push(processed_obj);
processed_obj_li.push(processed_obj as T);
}
return processed_obj_li;
}
// Updated 2025-06-04
export async function process_ae_obj__archive_content_props({
obj_li,
log_lvl = 0
}: {
obj_li: any[];
log_lvl?: number;
}) {
return _process_generic_props({
obj_li,
obj_type: 'archive_content',
log_lvl,
specific_processor: (obj) => {
// Archive content-specific computed sort fields, overriding generic ones if needed
obj.tmp_sort_1 = `${obj.group ?? ''}_${obj.priority ? '1' : '0'}_${
obj.sort?.toString().padStart(3, '0') ?? ''
}_${obj.original_datetime ?? ''}`;
obj.tmp_sort_2 = `${obj.group ?? ''}_${obj.original_datetime ?? ''}_${
obj.priority ? '1' : '0'
}_${obj.sort?.toString().padStart(3, '0') ?? ''}`;
obj.tmp_sort_3 = `${obj.original_datetime ?? ''}_${obj.group ?? ''}_${
obj.priority ? '1' : '0'
}_${obj.sort?.toString().padStart(3, '0') ?? ''}`;
obj.hash_sha256 = obj.hosted_file_hash_sha256;
return obj;
}
});
}

View File

@@ -5,36 +5,28 @@ import {
load_ae_obj_li__archive,
create_ae_obj__archive,
delete_ae_obj_id__archive,
update_ae_obj__archive,
// qry__archive,
db_save_ae_obj_li__archive,
} from "$lib/ae_archives/ae_archives__archive";
update_ae_obj__archive
} from '$lib/ae_archives/ae_archives__archive';
import {
load_ae_obj_id__archive_content,
load_ae_obj_li__archive_content,
create_ae_obj__archive_content,
delete_ae_obj_id__archive_content,
update_ae_obj__archive_content,
// qry__archive_content,
db_save_ae_obj_li__archive_content,
} from "$lib/ae_archives/ae_archives__archive_content";
update_ae_obj__archive_content
} from '$lib/ae_archives/ae_archives__archive_content';
let export_obj = {
const export_obj = {
load_ae_obj_id__archive: load_ae_obj_id__archive,
load_ae_obj_li__archive: load_ae_obj_li__archive,
create_ae_obj__archive: create_ae_obj__archive,
delete_ae_obj_id__archive: delete_ae_obj_id__archive,
update_ae_obj__archive: update_ae_obj__archive,
db_save_ae_obj_li__archive: db_save_ae_obj_li__archive,
load_ae_obj_id__archive_content: load_ae_obj_id__archive_content,
load_ae_obj_li__archive_content: load_ae_obj_li__archive_content,
create_ae_obj__archive_content: create_ae_obj__archive_content,
delete_ae_obj_id__archive_content: delete_ae_obj_id__archive_content,
update_ae_obj__archive_content: update_ae_obj__archive_content,
db_save_ae_obj_li__archive_content: db_save_ae_obj_li__archive_content,
update_ae_obj__archive_content: update_ae_obj__archive_content
};
export let archives_func = export_obj;
export const archives_func = export_obj;

View File

@@ -1,6 +1,6 @@
import Dexie, { type Table } from 'dexie';
import type { key_val } from '../ae_stores';
import type { key_val } from '$lib/stores/ae_stores';
// li = list
// kv = key value list
@@ -12,7 +12,7 @@ export interface Archive {
archive_id: string;
// archive_id_random: string;
code?: null|string;
code?: null | string;
account_id: string;
// account_id_random: string;
@@ -22,40 +22,40 @@ export interface Archive {
// type: string;
name: string;
// summary?: null|string;
description?: null|string;
description?: null | string;
content_html?: null|string;
content_json?: null|string;
content_url?: null|string;
content_url_text?: null|string;
content_html?: null | string;
content_json?: null | string;
content_url?: null | string;
content_url_text?: null | string;
original_datetime?: Date;
original_timezone?: null|string;
original_location?: null|string;
original_timezone?: null | string;
original_location?: null | string;
original_url?: null|string;
original_url_text?: null|string;
original_url?: null | string;
original_url_text?: null | string;
// meta_data?: null|string;
// access_key?: null|string; /// Rename this to "passcode" if used later
sort_by?: null|string;
sort_by_desc?: null|string;
sort_by?: null | string;
sort_by_desc?: null | string;
cfg_json?: null|key_val;
cfg_json?: null | key_val;
enable: null|boolean;
hide?: null|boolean;
priority?: null|boolean
sort?: null|number;
group?: null|string;
notes?: null|string;
enable: null | boolean;
hide?: null | boolean;
priority?: null | boolean;
sort?: null | number;
group?: null | string;
notes?: null | string;
created_on: Date;
updated_on?: null|Date;
updated_on?: null | Date;
// Generated fields for sorting locally only
tmp_sort_1?: null|string;
tmp_sort_2?: null|string;
tmp_sort_1?: null | string;
tmp_sort_2?: null | string;
// Additional fields for convenience (database views)
// archive_content_count?: number;
@@ -76,57 +76,56 @@ export interface Archive_Content {
archive_content_type: string;
name: string;
description?: null|string;
description?: null | string;
content_html?: null|string;
content_json?: null|string;
content_html?: null | string;
content_json?: null | string;
// linked_li_json?: null|string; // For future use? linked content list instead of one content item
url?: null|string;
url_text?: null|string;
url?: null | string;
url_text?: null | string;
hosted_file_id?: string;
file_path?: null|string;
file_path?: null | string;
filename?: null|string;
file_extension?: null|string;
filename?: null | string;
file_extension?: null | string;
original_datetime?: Date;
original_timezone?: null|string;
original_location?: null|string;
original_url?: null|string;
original_url_text?: null|string;
original_timezone?: null | string;
original_location?: null | string;
original_url?: null | string;
original_url_text?: null | string;
// meta_data?: null|string;
// access_key?: null|string; /// Rename this to "passcode" if used later
enable_for_public?: boolean;
cfg_json?: null|key_val;
cfg_json?: null | key_val;
enable: null|boolean;
hide?: null|boolean;
priority?: null|boolean
sort?: null|number;
group?: null|string;
notes?: null|string;
enable: null | boolean;
hide?: null | boolean;
priority?: null | boolean;
sort?: null | number;
group?: null | string;
notes?: null | string;
created_on: Date;
updated_on?: null|Date;
updated_on?: null | Date;
// Generated fields for sorting locally only
tmp_sort_1?: null|string;
tmp_sort_2?: null|string;
tmp_sort_1?: null | string;
tmp_sort_2?: null | string;
// Additional fields for convenience (database views)
archive_code?: null|string;
archive_name?: null|string;
archive_code?: null | string;
archive_name?: null | string;
hash_sha256?: null|string;
hash_sha256?: null | string;
}
// Updated 2024-09-25
export class MySubClassedDexie extends Dexie {
// We just tell the typing system this is the case
@@ -153,14 +152,14 @@ export class MySubClassedDexie extends Dexie {
original_datetime, original_timezone, original_location,
[group+original_datetime],
tmp_sort_1, tmp_sort_2,
enable, hide, priority, sort, group, notes, created_on, updated_on, [group+priority+sort+updated_on]`,
});
enable, hide, priority, sort, group, notes, created_on, updated_on, [group+priority+sort+updated_on]`
});
// file_path,
// filename, file_extension,
// original_datetime, original_timezone, original_location, original_url, original_url_text,
// enable_for_public,
// file_path,
// filename, file_extension,
// original_datetime, original_timezone, original_location, original_url, original_url_text,
// enable_for_public,
}
}
export const db_archives = new MySubClassedDexie();
export const db_archives = new MySubClassedDexie();

View File

@@ -1,367 +1,415 @@
<script lang="ts">
import { preventDefault } from 'svelte/legacy';
import { preventDefault } from 'svelte/legacy';
// Imports
// Import components and elements
// import Element_input_files_tbl from '$lib/element_input_files_tbl.svelte';
// Imports
// Import components and elements
// import Element_input_files_tbl from '$lib/element_input_files_tbl.svelte';
// Import storage, functions, and libraries
import type { key_val } from '$lib/ae_stores';
// Import storage, functions, and libraries
import type { key_val } from '$lib/stores/ae_stores';
import { api } from '$lib/api';
import { ae_util } from '$lib/ae_utils/ae_utils';
import { ae_snip, ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
import { api } from '$lib/api/api';
import { ae_util } from '$lib/ae_utils/ae_utils';
import {
ae_snip,
ae_loc,
ae_sess,
ae_api,
ae_trig,
slct,
slct_trigger
} from '$lib/stores/ae_stores';
// Exports
// Exports
// export let input_name = 'file_list';
// export let multiple: boolean = true;
// export let required: boolean = true;
// export let input_name = 'file_list';
// export let multiple: boolean = true;
// export let required: boolean = true;
// export let input_class_li: string[] = ['file_drop_area'];
interface Props {
log_lvl?: number;
// Expecting these for link_to_type: 'event', 'event_location', 'archive_content', etc
link_to_type: string;
link_to_id: string;
// export let accept: string = 'audio/*, image/*, video/*, .bak, .cfg, .css, .csv, .doc, .docx, .gz, .htm, .html, .ini, .iso, .j2, .json, .key, .keynote, .md, .pdf, .ppt, .pptx, .rar, .rtf, .sql, .svelte, ttf, .txt, .xls, .xlsx, .xz, .zip, .bin, .dmg, .exe, .js, .msi, .php, .py, .sh';
class_li_default?: string;
class_li?: string;
// export let table_class_li: string[] = ['table', 'table-sm', 'table-striped', 'table-hover' , 'text-sm'];
clip_complete?: boolean;
// export let upload_complete: boolean = false;
submit_status?: null | string;
// hosted_file_id_li?: string[];
// hosted_file_obj_li?: any[];
hosted_file_obj_kv?: key_val;
video_clip_file_kv?: key_val;
}
// export let input_class_li: string[] = ['file_drop_area'];
let {
log_lvl = $bindable(0),
link_to_type = $bindable(),
link_to_id = $bindable(),
class_li_default = 'flex flex-col gap-1 items-center justify-center w-full max-w-2xl mx-auto my-1',
class_li = $bindable(''),
clip_complete = $bindable(false),
submit_status = $bindable(null),
// hosted_file_id_li = [],
// hosted_file_obj_li = [],
hosted_file_obj_kv = $bindable({}),
video_clip_file_kv = $bindable({})
}: Props = $props();
// Local Variables
let task_id = link_to_id;
// let input_file_list: any = null;
let ae_promises: key_val = $state({});
// let ae_promises_clipping: key_val = {};
// let ae_triggers: key_val = {};
interface Props {
log_lvl?: number;
// Expecting these for link_to_type: 'event', 'event_location', 'archive_content', etc
link_to_type: string;
link_to_id: string;
// export let accept: string = 'audio/*, image/*, video/*, .bak, .cfg, .css, .csv, .doc, .docx, .gz, .htm, .html, .ini, .iso, .j2, .json, .key, .keynote, .md, .pdf, .ppt, .pptx, .rar, .rtf, .sql, .svelte, ttf, .txt, .xls, .xlsx, .xz, .zip, .bin, .dmg, .exe, .js, .msi, .php, .py, .sh';
class_li_default?: string;
class_li?: string;
// export let table_class_li: string[] = ['table', 'table-sm', 'table-striped', 'table-hover' , 'text-sm'];
clip_complete?: boolean;
// export let upload_complete: boolean = false;
submit_status?: null|string;
// hosted_file_id_li?: string[];
// hosted_file_obj_li?: any[];
hosted_file_obj_kv?: key_val;
video_clip_file_kv?: key_val;
}
// let input_element_id = 'ae_comp__hosted_files_upload__input';
let {
log_lvl = $bindable(0),
link_to_type = $bindable(),
link_to_id = $bindable(),
class_li_default = 'flex flex-col gap-1 items-center justify-center w-full max-w-2xl mx-auto my-1',
class_li = $bindable(''),
clip_complete = $bindable(false),
submit_status = $bindable(null),
// hosted_file_id_li = [],
// hosted_file_obj_li = [],
hosted_file_obj_kv = $bindable({}),
video_clip_file_kv = $bindable({})
}: Props = $props();
// let form_kv: key_val = {
// start_time: null,
// end_time: null,
// reencode: null,
// video_file: null,
// };
// let download_clip_src: string;
// let download_clip_filename: string;
// Local Variables
let task_id = link_to_id;
// let input_file_list: any = null;
let ae_promises: key_val = $state({});
// let ae_promises_clipping: key_val = {};
// let ae_triggers: key_val = {};
// let input_element_id = 'ae_comp__hosted_files_upload__input';
// let form_kv: key_val = {
// start_time: null,
// end_time: null,
// reencode: null,
// video_file: null,
// };
// let download_clip_src: string;
// let download_clip_filename: string;
$ae_sess.files.obj = {
obj: null,
};
// *** Functions and Logic
function handle_clip_video(event) {
console.log('*** handle_clip_video() ***');
submit_status = 'clipping';
clip_complete = false;
let hosted_file_id = event.target.hosted_file_id.value;
$ae_sess.files.processed_file_kv[hosted_file_id] = {};
$ae_sess.files.processed_file_kv[hosted_file_id].submit_status = 'clipping';
$ae_sess.files.processed_file_kv[hosted_file_id].clip_complete = false;
// $ae_sess.files.disable_submit__hosted_file_obj = true;
$ae_loc.files.processed_file_kv[hosted_file_id] = {};
$ae_loc.files.processed_file_kv[hosted_file_id].submit_status = 'clipping';
$ae_loc.files.processed_file_kv[hosted_file_id].start_time = event.target.start_time.value;
$ae_loc.files.processed_file_kv[hosted_file_id].end_time = event.target.end_time.value;
$ae_loc.files.processed_file_kv[hosted_file_id].reencode = event.target.reencode.value;
$ae_loc.files.processed_file_kv[hosted_file_id].scale_down = event.target.scale_down.value;
$ae_loc.files.processed_file_kv[hosted_file_id].new_filename = event.target.new_filename.value;
$ae_loc.files.processed_file_kv[hosted_file_id].clip_complete = false;
let endpoint = `/hosted_file/${hosted_file_id}/clip_video`;
let params = {
link_to_type: link_to_type,
link_to_id: link_to_id,
filename_no_ext: event.target.new_filename.value.replace('.mp4', ''),
from_type: 'mp4', // Video file type being converted
to_type: 'mp4', // Video file type to convert to
start_time: event.target.start_time.value,
end_time: event.target.end_time.value,
reencode: event.target.reencode.value,
scale_down: event.target.scale_down.value,
$ae_sess.files.obj = {
obj: null
};
ae_promises[hosted_file_id] = {};
// .convert__hosted_file_obj
ae_promises[hosted_file_id] = api.get_object({
api_cfg: $ae_api,
endpoint: endpoint,
params: params,
timeout: 300000, // 5 minutes
// return_blob: true,
// filename: event.target.new_filename.value,
// auto_download: false,
task_id: task_id,
log_lvl: log_lvl
})
.then(function (result) {
console.log(result);
// *** Functions and Logic
function handle_clip_video(event: Event) {
console.log('*** handle_clip_video() ***');
video_clip_file_kv[result.hosted_file_id_random] = {};
video_clip_file_kv[result.hosted_file_id_random] = result;
submit_status = 'clipping';
clip_complete = false;
// $ae_loc.files.video_clip_file_kv[result.hosted_file_id_random] = {};
// $ae_loc.files.video_clip_file_kv[result.hosted_file_id_random] = result;
let hosted_file_id = event.target.hosted_file_id.value;
$ae_sess.files.processed_file_kv[hosted_file_id].submit_status = 'clipped';
$ae_sess.files.processed_file_kv[hosted_file_id].clip_complete = true;
$ae_sess.files.processed_file_kv[hosted_file_id] = {};
$ae_sess.files.processed_file_kv[hosted_file_id].submit_status = 'clipping';
$ae_sess.files.processed_file_kv[hosted_file_id].clip_complete = false;
$ae_loc.files.processed_file_kv[hosted_file_id].submit_status = 'clipped';
$ae_loc.files.processed_file_kv[hosted_file_id].clip_complete = true;
// $ae_sess.files.disable_submit__hosted_file_obj = true;
$ae_loc.files.processed_file_kv[hosted_file_id] = {};
$ae_loc.files.processed_file_kv[hosted_file_id].submit_status = 'clipping';
$ae_loc.files.processed_file_kv[hosted_file_id].start_time = event.target.start_time.value;
$ae_loc.files.processed_file_kv[hosted_file_id].end_time = event.target.end_time.value;
$ae_loc.files.processed_file_kv[hosted_file_id].reencode = event.target.reencode.value;
$ae_loc.files.processed_file_kv[hosted_file_id].scale_down = event.target.scale_down.value;
$ae_loc.files.processed_file_kv[hosted_file_id].new_filename =
event.target.new_filename.value;
$ae_loc.files.processed_file_kv[hosted_file_id].clip_complete = false;
submit_status = 'clipped';
clip_complete = true;
let endpoint = `/hosted_file/${hosted_file_id}/clip_video`;
// let file_blob = new Blob([result.data]);
// // console.log(file_blob);
// let file_obj_url = window.URL.createObjectURL(file_blob); // The img src
// // const url = window.URL.createObjectURL(new Blob([result.data]));
// download_clip_src = file_obj_url;
// // download_filename = file_obj_url;
let params = {
link_to_type: link_to_type,
link_to_id: link_to_id,
filename_no_ext: event.target.new_filename.value.replace('.mp4', ''),
from_type: 'mp4', // Video file type being converted
to_type: 'mp4', // Video file type to convert to
start_time: event.target.start_time.value,
end_time: event.target.end_time.value,
reencode: event.target.reencode.value,
scale_down: event.target.scale_down.value
};
return true;
});
ae_promises[hosted_file_id] = {};
// .convert__hosted_file_obj
ae_promises[hosted_file_id] = api
.get_object({
api_cfg: $ae_api,
endpoint: endpoint,
params: params,
timeout: 300000, // 5 minutes
// return_blob: true,
// filename: event.target.new_filename.value,
// auto_download: false,
task_id: task_id,
log_lvl: log_lvl
})
.then(function (result) {
console.log(result);
}
video_clip_file_kv[result.hosted_file_id_random] = {};
video_clip_file_kv[result.hosted_file_id_random] = result;
// $ae_loc.files.video_clip_file_kv[result.hosted_file_id_random] = {};
// $ae_loc.files.video_clip_file_kv[result.hosted_file_id_random] = result;
$ae_sess.files.processed_file_kv[hosted_file_id].submit_status = 'clipped';
$ae_sess.files.processed_file_kv[hosted_file_id].clip_complete = true;
$ae_loc.files.processed_file_kv[hosted_file_id].submit_status = 'clipped';
$ae_loc.files.processed_file_kv[hosted_file_id].clip_complete = true;
submit_status = 'clipped';
clip_complete = true;
// let file_blob = new Blob([result.data]);
// // console.log(file_blob);
// let file_obj_url = window.URL.createObjectURL(file_blob); // The img src
// // const url = window.URL.createObjectURL(new Blob([result.data]));
// download_clip_src = file_obj_url;
// // download_filename = file_obj_url;
return true;
});
}
</script>
<section class="{class_li_default} {class_li}">
<h3 class="h3">
{Object.entries(hosted_file_obj_kv).length}× files uploaded
</h3>
<section
class="{class_li_default} {class_li}"
>
<!-- <h3 class="h3">{hosted_file_obj_li.length}&times; files uploaded</h3>
{#each hosted_file_obj_li as hosted_file_obj, i} -->
<h3
class="h3"
>
{Object.entries(hosted_file_obj_kv).length}× files uploaded
</h3>
{#each Object.entries(hosted_file_obj_kv) as [hosted_file_id, hosted_file_obj]}
<div class="border border-gray-300 rounded-lg p-2 m-2">
<!-- {#if $ae_sess.files[hosted_file_id].upload_complete}
{#each Object.entries(hosted_file_obj_kv) as [hosted_file_id, hosted_file_obj]}
<div class="border border-gray-300 rounded-lg p-2 m-2">
<!-- {#if $ae_sess.files[hosted_file_id].upload_complete}
<a href="/hosted_file/{hosted_file_id}/download?x_no_account_id_token=direct-download" download={$ae_sess.files[hosted_file_id].new_filename} class="ae_btn btn_lg btn_primary"><span class="fas fa-download"></span> Ready to Download</a>
{/if} -->
<div class="flex flex-row flex-wrap gap-1 justify-center items-center w-full">
<!-- Remove from uploaded file kv list -->
<button
type="button"
onclick={() => {
// This (uploaded_file_kv) is referenced by other AE components. Currently it is only used with the manage hosted file list and clip video components.
console.log(`Removed hosted file ID: ${hosted_file_id}`, $ae_loc.files.uploaded_file_kv);
// delete $ae_sess.files.uploaded_file_kv[hosted_file_id];
delete $ae_loc.files.uploaded_file_kv[hosted_file_id];
$ae_loc.files.uploaded_file_kv = {...$ae_loc.files.uploaded_file_kv};
delete hosted_file_obj_kv[hosted_file_id];
hosted_file_obj_kv = {...hosted_file_obj_kv};
// delete $ae_loc.files.uploaded_file_kv[hosted_file_obj.hosted_file_id];
console.log(`Removed hosted file ID: ${hosted_file_obj.hosted_file_id}`, $ae_loc.files.uploaded_file_kv);
}}
class="btn btn-sm preset-tonal-warning hover:preset-filled-warning-500"
title={`Remove this file from list of videos:\n${hosted_file_obj.filename}\n[API] SHA256: ${hosted_file_obj?.hash_sha256?.slice(0, 10)}... Hosted ID: ${hosted_file_obj.hosted_file_id_random}`}
>
<span class="fas fa-minus-circle m-1"></span>
<span class="">Remove</span>
</button>
<div class="flex flex-row flex-wrap gap-1 justify-center items-center w-full">
<!-- Remove from uploaded file kv list -->
<button
type="button"
onclick={() => {
// This (uploaded_file_kv) is referenced by other AE components. Currently it is only used with the manage hosted file list and clip video components.
console.log(
`Removed hosted file ID: ${hosted_file_id}`,
$ae_loc.files.uploaded_file_kv
);
// delete $ae_sess.files.uploaded_file_kv[hosted_file_id];
delete $ae_loc.files.uploaded_file_kv[hosted_file_id];
$ae_loc.files.uploaded_file_kv = { ...$ae_loc.files.uploaded_file_kv };
delete hosted_file_obj_kv[hosted_file_id];
hosted_file_obj_kv = { ...hosted_file_obj_kv };
// delete $ae_loc.files.uploaded_file_kv[hosted_file_obj.hosted_file_id];
console.log(
`Removed hosted file ID: ${hosted_file_obj.hosted_file_id}`,
$ae_loc.files.uploaded_file_kv
);
}}
class="btn btn-sm preset-tonal-warning hover:preset-filled-warning-500"
title={`Remove this file from list of videos:\n${hosted_file_obj.filename}\n[API] SHA256: ${hosted_file_obj?.hash_sha256?.slice(0, 10)}... Hosted ID: ${hosted_file_obj.hosted_file_id_random}`}
>
<span class="fas fa-minus-circle m-1"></span>
<span class="">Remove</span>
</button>
<!-- Download the file -->
<button
type="button"
disabled={!$ae_loc.trusted_access}
onclick={() => {
ae_promises[hosted_file_id] = api.download_hosted_file({
api_cfg: $ae_api,
hosted_file_id: hosted_file_id,
return_file: true,
filename: hosted_file_obj.filename,
auto_download: true,
log_lvl: 0
});
<!-- Download the file -->
<button
type="button"
disabled={!$ae_loc.trusted_access}
onclick={() => {
ae_promises[hosted_file_id] = api.download_hosted_file({
api_cfg: $ae_api,
hosted_file_id: hosted_file_id,
return_file: true,
filename: hosted_file_obj.filename,
auto_download: true,
log_lvl: 0
});
// window.postMessage({ type: 'download_event_file', hosted_file_id: idaa_archive_content_obj.hosted_file_id, filename: idaa_archive_content_obj.filename, auto_download: true }, '*');
}}
class:hidden={!$ae_loc.edit_mode}
class="novi_btn btn btn-sm lg:btn-md preset-tonal-primary hover:preset-filled-primary-500 min-w-72 lg:min-w-96"
title={`Download this file:\n${hosted_file_obj.filename}\n[API] SHA256: ${hosted_file_obj?.hash_sha256?.slice(0, 10)}... Hosted ID: ${hosted_file_obj.hosted_file_id_random}`}
>
{#await ae_promises[hosted_file_id]}
<span class="fas fa-spinner fa-spin mx-1"></span>
{#if submit_status == 'clipping'}
<span class="">Clipping</span>
{:else}
<span class="">
Downloading
{#if $ae_sess.api_download_kv[hosted_file_id]}
{$ae_sess.api_download_kv[hosted_file_id].percent_completed}%
// window.postMessage({ type: 'download_event_file', hosted_file_id: idaa_archive_content_obj.hosted_file_id, filename: idaa_archive_content_obj.filename, auto_download: true }, '*');
}}
class:hidden={!$ae_loc.edit_mode}
class="novi_btn btn btn-sm lg:btn-md preset-tonal-primary hover:preset-filled-primary-500 min-w-72 lg:min-w-96"
title={`Download this file:\n${hosted_file_obj.filename}\n[API] SHA256: ${hosted_file_obj?.hash_sha256?.slice(0, 10)}... Hosted ID: ${hosted_file_obj.hosted_file_id_random}`}
>
{#await ae_promises[hosted_file_id]}
<span class="fas fa-spinner fa-spin mx-1"></span>
{#if submit_status == 'clipping'}
<span class="">Clipping</span>
{:else}
<span class="">
Downloading
{#if $ae_sess.api_download_kv[hosted_file_id]}
{$ae_sess.api_download_kv[hosted_file_id].percent_completed}%
{/if}
:
</span>
{/if}
:
{:then}
<span
class="fas fa-{ae_util.file_extension_icon(
hosted_file_obj?.file_extension
)}"
></span>
{/await}
<span class="grow">
{ae_util.shorten_filename({
filename: hosted_file_obj?.filename,
max_length: 30
})}
</span>
{/if}
{:then}
<span class="fas fa-{ae_util.file_extension_icon(hosted_file_obj?.file_extension)}"></span>
{/await}
<span class="grow">
{ae_util.shorten_filename({filename: hosted_file_obj?.filename, max_length: 30})}
</span>
</button>
<span>{ae_util.shorten_filename({filename: hosted_file_obj?.filename, max_length: 30})}</span>
<span>
<span class="text-sm font-bold">
File ID:
</span>
{hosted_file_obj.hosted_file_id_random}</span>
<span>
<span class="text-sm font-bold">
Type:
</span>
{hosted_file_obj.extension}</span>
<!-- <span>{hosted_file_obj.filename}</span> -->
</div>
<form
onsubmit={preventDefault(handle_clip_video)}
class="{class_li_default} {class_li}"
>
<!-- {$ae_sess?.files[hosted_file_obj?.hosted_file_id_random ?? 'obj'].submit_status ?? 'not set'} -->
<input type="hidden" name="hosted_file_id" value="{hosted_file_obj.hosted_file_id_random}" />
<div class="flex flex-row gap-1 justify-center items-center w-full">
<span class="text-xs font-bold w-32">New Filename:</span>
<input type="text" class="input w-full text-sm" name="new_filename" value={hosted_file_obj.filename} />
</div>
<div class="max-w-(--breakpoint-sm) flex flex-row gap-1 justify-center items-center w-full">
<label class="label w-48"
title="The start time of the clip. This is the time in the video where the clip will start. You may need to subtract a few seconds to get the exact start time."
</button>
<span
>{ae_util.shorten_filename({
filename: hosted_file_obj?.filename,
max_length: 30
})}</span
>
<span class="text-xs font-bold">Start time (HH:MM:SS)</span>
<input type="text" name="start_time"
value={($ae_loc.files.processed_file_kv && $ae_loc.files.processed_file_kv[hosted_file_id] && $ae_loc.files.processed_file_kv[hosted_file_id].start_time) ? $ae_loc.files.processed_file_kv[hosted_file_id].start_time : '00:00:00'}
placeholder="HH:MM:SS (00:01:30)" class="input w-32" />
</label>
<label class="label w-48"
title="The end time of the clip. This is the time in the video where the clip will end. You may need to add a few seconds to get the exact end time."
<span>
<span class="text-sm font-bold"> File ID: </span>
{hosted_file_obj.hosted_file_id_random}</span
>
<span class="text-xs font-bold">End time (HH:MM:SS)</span>
<input type="text" name="end_time"
value={($ae_loc.files.processed_file_kv && $ae_loc.files.processed_file_kv[hosted_file_id] && $ae_loc.files.processed_file_kv[hosted_file_id].end_time) ? $ae_loc.files.processed_file_kv[hosted_file_id].end_time : '00:45:59'}
placeholder="HH:MM:SS (01:05:25)" class="input w-32" />
</label>
<span class="flex flex-col gap-1 items-center justify-center"
title="Re-encode the video file? This does cause some minor quality loss. Re-encoding is useful if the audio or video seems to be chopped off at the beginning or end of the clip. It can also help with partially corrupted files."
<span>
<span class="text-sm font-bold"> Type: </span>
{hosted_file_obj.extension}</span
>
<span class="text-xs font-bold">
Re-encode?
</span>
<label class="inline-block">
<input type="radio" name="reencode" value="true" class="radio" checked />
True
</label>
<label class="inline-block">
<input type="radio" name="reencode" value="false" class="radio" />
False
</label>
</span>
<!-- <span>{hosted_file_obj.filename}</span> -->
</div>
<span class="flex flex-col gap-1 items-center justify-center"
title="Scale the video file down to 1920x1080? This does cause some minor quality loss. Re-encoding is useful if the audio or video seems to be chopped off at the beginning or end of the clip. It can also help with partially corrupted files."
>
<span class="text-xs font-bold">
Scale down?
</span>
<label class="inline-block">
<input type="radio" name="scale_down" value="true" class="radio" checked />
True
</label>
<label class="inline-block">
<input type="radio" name="scale_down" value="false" class="radio" />
False
</label>
</span>
</div>
<button
type="submit"
class="btn btn-lg btn-primary preset-tonal-primary border border-primary-500"
disabled={submit_status == 'clipping'}
<form
onsubmit={preventDefault(handle_clip_video)}
class="{class_li_default} {class_li}"
>
<!-- {#await ae_promises[hosted_file_id]} -->
{#if $ae_loc.files.processed_file_kv[hosted_file_id] && $ae_loc.files.processed_file_kv[hosted_file_id].submit_status == 'clipping'}
<span class="fas fa-spinner fa-spin m-1"></span>
<span class="highlight">Clipping...</span>
{:else}
<!-- {#if ae_promises[hosted_file_id]} -->
{#if $ae_loc.files.processed_file_kv[hosted_file_id] && $ae_loc.files.processed_file_kv[hosted_file_id].submit_status == 'clipped'}
<span class="fas fa-check m-1"></span>
Clipped
{:else}
<span class="fas fa-cut m-1"></span>
Clip Video
{/if}
{/if}
<!-- <span class="fas fa-cut m-1"></span>
<!-- {$ae_sess?.files[hosted_file_obj?.hosted_file_id_random ?? 'obj'].submit_status ?? 'not set'} -->
<input
type="hidden"
name="hosted_file_id"
value={hosted_file_obj.hosted_file_id_random}
/>
<div class="flex flex-row gap-1 justify-center items-center w-full">
<span class="text-xs font-bold w-32">New Filename:</span>
<input
type="text"
class="input w-full text-sm"
name="new_filename"
value={hosted_file_obj.filename}
/>
</div>
<div
class="max-w-(--breakpoint-sm) flex flex-row gap-1 justify-center items-center w-full"
>
<label
class="label w-48"
title="The start time of the clip. This is the time in the video where the clip will start. You may need to subtract a few seconds to get the exact start time."
>
<span class="text-xs font-bold">Start time (HH:MM:SS)</span>
<input
type="text"
name="start_time"
value={$ae_loc.files.processed_file_kv &&
$ae_loc.files.processed_file_kv[hosted_file_id] &&
$ae_loc.files.processed_file_kv[hosted_file_id].start_time
? $ae_loc.files.processed_file_kv[hosted_file_id].start_time
: '00:00:00'}
placeholder="HH:MM:SS (00:01:30)"
class="input w-32"
/>
</label>
<label
class="label w-48"
title="The end time of the clip. This is the time in the video where the clip will end. You may need to add a few seconds to get the exact end time."
>
<span class="text-xs font-bold">End time (HH:MM:SS)</span>
<input
type="text"
name="end_time"
value={$ae_loc.files.processed_file_kv &&
$ae_loc.files.processed_file_kv[hosted_file_id] &&
$ae_loc.files.processed_file_kv[hosted_file_id].end_time
? $ae_loc.files.processed_file_kv[hosted_file_id].end_time
: '00:45:59'}
placeholder="HH:MM:SS (01:05:25)"
class="input w-32"
/>
</label>
<span
class="flex flex-col gap-1 items-center justify-center"
title="Re-encode the video file? This does cause some minor quality loss. Re-encoding is useful if the audio or video seems to be chopped off at the beginning or end of the clip. It can also help with partially corrupted files."
>
<span class="text-xs font-bold"> Re-encode? </span>
<label class="inline-block">
<input
type="radio"
name="reencode"
value="true"
class="radio"
checked
/>
True
</label>
<label class="inline-block">
<input type="radio" name="reencode" value="false" class="radio" />
False
</label>
</span>
<span
class="flex flex-col gap-1 items-center justify-center"
title="Scale the video file down to 1920x1080? This does cause some minor quality loss. Re-encoding is useful if the audio or video seems to be chopped off at the beginning or end of the clip. It can also help with partially corrupted files."
>
<span class="text-xs font-bold"> Scale down? </span>
<label class="inline-block">
<input
type="radio"
name="scale_down"
value="true"
class="radio"
checked
/>
True
</label>
<label class="inline-block">
<input type="radio" name="scale_down" value="false" class="radio" />
False
</label>
</span>
</div>
<button
type="submit"
class="btn btn-lg btn-primary preset-tonal-primary border border-primary-500"
disabled={submit_status == 'clipping'}
>
<!-- {#await ae_promises[hosted_file_id]} -->
{#if $ae_loc.files.processed_file_kv[hosted_file_id] && $ae_loc.files.processed_file_kv[hosted_file_id].submit_status == 'clipping'}
<span class="fas fa-spinner fa-spin m-1"></span>
<span class="highlight">Clipping...</span>
{:else}
<!-- {#if ae_promises[hosted_file_id]} -->
{#if $ae_loc.files.processed_file_kv[hosted_file_id] && $ae_loc.files.processed_file_kv[hosted_file_id].submit_status == 'clipped'}
<span class="fas fa-check m-1"></span>
Clipped
{:else}
<span class="fas fa-cut m-1"></span>
Clip Video
{/if}
{/if}
<!-- <span class="fas fa-cut m-1"></span>
Clip Video -->
</button>
</button>
</form>
</form>
{#await ae_promises[hosted_file_id]}
<span class="fas fa-spinner fa-spin m-1"></span>
<span class="highlight">Processing... This may take a few minutes.</span>
{:then}
{#if ae_promises[hosted_file_id]}
<span class="fas fa-download"></span> Ready to download below!
{:else}
<!-- <p>Fill out the form and select the video file to clip.</p> -->
{/if}
{/await}
</div>
{/each}
{#await ae_promises[hosted_file_id]}
<span class="fas fa-spinner fa-spin m-1"></span>
<span class="highlight">Processing... This may take a few minutes.</span>
{:then}
{#if ae_promises[hosted_file_id]}
<span class="fas fa-download"></span> Ready to download below!
{:else}
<!-- <p>Fill out the form and select the video file to clip.</p> -->
{/if}
{/await}
</div>
{/each}
<!-- <hr />
<!-- <hr />
{#await ae_promises.upload__hosted_file_obj}
<span class="fas fa-spinner fa-spin m-1"></span>
@@ -373,5 +421,4 @@ function handle_clip_video(event) {
<p>Fill out the form and select the video file to clip.</p>
{/if}
{/await} -->
</section>
</section>

View File

@@ -1,47 +1,51 @@
<script lang="ts">
// Imports
// Import components and elements
// Imports
// Import components and elements
// Import storage, functions, and libraries
import type { key_val } from '$lib/stores/ae_stores';
// Import storage, functions, and libraries
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api/api';
import { ae_util } from '$lib/ae_utils/ae_utils';
import {
ae_snip,
ae_loc,
ae_sess,
ae_api,
ae_trig,
slct,
slct_trigger
} from '$lib/stores/ae_stores';
import { api } from '$lib/api';
import { ae_util } from '$lib/ae_utils/ae_utils';
import { ae_snip, ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
// Exports
// Exports
// export let hosted_file_id_li: string[] = [];
// export let hosted_file_obj_li: any[] = [];
// export let hosted_file_id_li: string[] = [];
// export let hosted_file_obj_li: any[] = [];
interface Props {
log_lvl?: number;
// export let hosted_file_obj_kv: key_val = {};
video_clip_file_kv?: key_val;
class_li_default?: string;
class_li?: string;
link_to_type: string;
link_to_id: string;
}
interface Props {
log_lvl?: number;
// export let hosted_file_obj_kv: key_val = {};
video_clip_file_kv?: key_val;
class_li_default?: string;
class_li?: string;
link_to_type: string;
link_to_id: string;
}
let {
log_lvl = 0,
video_clip_file_kv = $bindable({}),
class_li_default = 'flex flex-row flex-wrap gap-2 items-center justify-center w-full max-w-2xl p-2 mx-auto my-1 border border-gray-300 rounded-lg',
class_li = '',
link_to_type,
link_to_id
}: Props = $props();
let ae_promises: key_val = $state({});
let {
log_lvl = 0,
video_clip_file_kv = $bindable({}),
class_li_default = 'flex flex-row flex-wrap gap-2 items-center justify-center w-full max-w-2xl p-2 mx-auto my-1 border border-gray-300 rounded-lg',
class_li = '',
link_to_type,
link_to_id
}: Props = $props();
let ae_promises: key_val = $state({});
</script>
<h3 class="h3">{Object.entries($ae_loc.files).length}× files clipped</h3>
<div class="{class_li_default} {class_li} ">
{#each Object.entries(video_clip_file_kv) as [hosted_file_id, hosted_file_obj]}
<button
type="button"
@@ -60,8 +64,7 @@ let ae_promises: key_val = $state({});
}}
class="novi_btn btn btn-sm lg:btn-md preset-tonal-primary hover:preset-filled-primary-500 min-w-72 lg:min-w-96"
title={`Download this file:\n${hosted_file_obj.filename}\n[API] SHA256: ${hosted_file_obj?.hash_sha256?.slice(0, 10)}... Hosted ID: ${hosted_file_obj.hosted_file_id_random}`}
>
>
{#await ae_promises[hosted_file_id]}
<span class="fas fa-spinner fa-spin mx-1"></span>
<span class="">
@@ -72,17 +75,17 @@ let ae_promises: key_val = $state({});
:
</span>
{:then}
<span class="fas fa-{ae_util.file_extension_icon(hosted_file_obj?.file_extension)}"></span>
<span class="fas fa-{ae_util.file_extension_icon(hosted_file_obj?.file_extension)}"
></span>
{/await}
<span class="grow">
{ae_util.shorten_filename({filename: hosted_file_obj?.filename, max_length: 30})}
{ae_util.shorten_filename({ filename: hosted_file_obj?.filename, max_length: 30 })}
</span>
<span class="shrink">
{ae_util.format_bytes(hosted_file_obj?.size)}
</span>
</button>
{/each}
</div>
</div>

View File

@@ -1,382 +1,423 @@
<script lang="ts">
export let log_lvl: number = 0;
import { preventDefault } from 'svelte/legacy';
// Imports
// Import components and elements
import Element_input_files_tbl from '$lib/element_input_files_tbl.svelte';
// Imports
// Import components and elements
import Element_input_files_tbl from '$lib/elements/element_input_files_tbl.svelte';
// Import storage, functions, and libraries
import type { key_val } from '$lib/ae_stores';
// Import storage, functions, and libraries
import type { key_val } from '$lib/stores/ae_stores';
import { api } from '$lib/api';
import { ae_snip, ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
import { api } from '$lib/api/api';
import {
ae_snip,
ae_loc,
ae_sess,
ae_api,
ae_trig,
slct,
slct_trigger
} from '$lib/stores/ae_stores';
// Exports
// Expecting these for link_to_type: 'event', 'event_location', 'archive_content', etc
export let link_to_type: string;
export let link_to_id: string;
// Exports
export let input_name = 'file_list';
export let multiple: boolean = true;
export let required: boolean = true;
export let accept: string = 'audio/*, image/*, video/*, .bak, .cfg, .css, .csv, .doc, .docx, .gz, .htm, .html, .ini, .iso, .j2, .json, .key, .keynote, .md, .pdf, .ppt, .pptx, .rar, .rtf, .sql, .svelte, ttf, .txt, .xls, .xlsx, .xz, .zip, .bin, .dmg, .exe, .js, .msi, .php, .py, .sh';
interface Props {
log_lvl?: number;
// Expecting these for link_to_type: 'event', 'event_location', 'archive_content', etc
link_to_type: string;
link_to_id: string;
input_name?: string;
multiple?: boolean;
required?: boolean;
accept?: string;
class_li_default?: string;
class_li?: string;
input_class_li?: string[];
table_class_li?: string[];
upload_complete?: boolean;
submit_status?: null | string;
hosted_file_id_li?: string[];
hosted_file_obj_li?: any[];
label?: import('svelte').Snippet;
}
export let class_li_default: string = 'flex flex-col gap-1 items-center justify-center w-full max-w-2xl mx-auto my-1';
export let class_li: string = '';
export let input_class_li: string[] = ['file_drop_area'];
export let table_class_li: string[] = ['table', 'table-sm', 'table-striped', '' , 'text-sm'];
let {
log_lvl = 0,
link_to_type,
link_to_id,
input_name = 'file_list',
multiple = true,
required = true,
accept = 'audio/*, image/*, video/*, .bak, .cfg, .css, .csv, .doc, .docx, .gz, .htm, .html, .ini, .iso, .j2, .json, .key, .keynote, .md, .pdf, .ppt, .pptx, .rar, .rtf, .sql, .svelte, ttf, .txt, .xls, .xlsx, .xz, .zip, .bin, .dmg, .exe, .js, .msi, .php, .py, .sh',
class_li_default = 'flex flex-col gap-1 items-center justify-center w-full max-w-2xl mx-auto my-1',
class_li = '',
input_class_li = ['file_drop_area'],
table_class_li = ['table', 'table-sm', 'table-striped', '', 'text-sm'],
upload_complete = $bindable(false),
submit_status = $bindable(null),
hosted_file_id_li = $bindable([]),
hosted_file_obj_li = $bindable([]),
label
}: Props = $props();
export let upload_complete: boolean = false;
export let submit_status: null|string = null;
// Local Variables
let task_id = $state(link_to_id);
let input_file_list: any = $state(null);
let ae_promises: key_val = $state({}); // Promise<any>;
let ae_triggers: key_val = {};
export let hosted_file_id_li: string[] = [];
export let hosted_file_obj_li: any[] = [];
let input_element_id = 'ae_comp__hosted_files_upload__input';
// Local Variables
let task_id = link_to_id;
let input_file_list: any = null;
let ae_promises: key_val = {}; // Promise<any>;
let ae_triggers: key_val = {};
let input_element_id = 'ae_comp__hosted_files_upload__input';
let form_kv: key_val = {
start_time: null,
end_time: null,
reencode: null,
video_file: null,
};
let download_clip_src: string;
let download_clip_filename: string;
// *** Functions and Logic
async function handle_submit_form_files(event) {
console.log('*** handle_submit_form() ***');
$ae_sess.files.disable_submit__hosted_file_obj = true;
$ae_sess.files.submit_status = 'saving';
submit_status = 'saving';
upload_complete = false;
hosted_file_id_li = [];
hosted_file_obj_li = [];
let hosted_file_results;
form_kv = {
start_time: event.target.start_time.value,
end_time: event.target.end_time.value,
reencode: event.target.reencode.value,
video_file: event.target.file_list.files[0],
let form_kv: key_val = {
start_time: null,
end_time: null,
reencode: null,
video_file: null
};
let download_clip_src: string = $state();
let download_clip_filename: string;
// *** Functions and Logic
async function handle_submit_form_files(event: SubmitEvent) {
console.log('*** handle_submit_form() ***');
// const form_data = new FormData();
$ae_sess.files.disable_submit__hosted_file_obj = true;
$ae_sess.files.submit_status = 'saving';
submit_status = 'saving';
upload_complete = false;
// form_data.append('start_time', event.target.start_time.value);
// form_data.append('end_time', event.target.end_time.value);
hosted_file_id_li = [];
hosted_file_obj_li = [];
// if (event.target.reencode.value == '1' || event.target.reencode.value == 'true') {
// form_data.append('reencode', 'true');
// } else {
// form_data.append('reencode', 'false');
// }
// form_data.append('reencode', event.target.reencode.value);
let hosted_file_results;
// form_data.append(`video_file`, event.target.video_file.files[0]);
form_kv = {
start_time: event.target.start_time.value,
end_time: event.target.end_time.value,
reencode: event.target.reencode.value,
video_file: event.target.file_list.files[0]
};
// let download_filename = `clipped_file_test.mp4`;
// const form_data = new FormData();
// let params = null;
// form_data.append('start_time', event.target.start_time.value);
// form_data.append('end_time', event.target.end_time.value);
// let endpoint = '/hosted_file/clip_video';
// if (event.target.reencode.value == '1' || event.target.reencode.value == 'true') {
// form_data.append('reencode', 'true');
// } else {
// form_data.append('reencode', 'false');
// }
// form_data.append('reencode', event.target.reencode.value);
// console.log(form_data);
// form_data.append(`video_file`, event.target.video_file.files[0]);
// params = null;
// let download_filename = `clipped_file_test.mp4`;
// let params = null;
if (event.target[input_element_id].files.length > 0) {
task_id = link_to_id; // Ideally this should be the file hash, but we may be uploading multiple files at once. This should be done with a loop instead?
// let endpoint = '/hosted_file/clip_video';
// Loop through each file and upload them individually in event.target[input_element_id].files
// The task_id should be the file hash.
// processed_file_list[i] has the file hash_sha256, hash_sha256_match, warnings, uploaded, uploaded_bytes, filename, and file_size_bytes.
for (let i = 0; i < event.target[input_element_id].files.length; i++) {
let tmp_file = event.target[input_element_id].files[i];
// console.log(form_data);
task_id = $ae_sess.files.processed_file_list[i].hash_sha256;
// params = null;
hosted_file_results = await handle_input_upload_files([tmp_file], form_kv, task_id);
if (event.target[input_element_id].files.length > 0) {
task_id = link_to_id; // Ideally this should be the file hash, but we may be uploading multiple files at once. This should be done with a loop instead?
if (hosted_file_results) {
console.log(`hosted_file_results:`, hosted_file_results);
} else {
console.log(`hosted_file_results:`, hosted_file_results);
// Loop through each file and upload them individually in event.target[input_element_id].files
// The task_id should be the file hash.
// processed_file_list[i] has the file hash_sha256, hash_sha256_match, warnings, uploaded, uploaded_bytes, filename, and file_size_bytes.
for (let i = 0; i < event.target[input_element_id].files.length; i++) {
let tmp_file = event.target[input_element_id].files[i];
task_id = $ae_sess.files.processed_file_list[i].hash_sha256;
hosted_file_results = await handle_input_upload_files([tmp_file], form_kv, task_id);
if (hosted_file_results) {
console.log(`hosted_file_results:`, hosted_file_results);
} else {
console.log(`hosted_file_results:`, hosted_file_results);
}
}
// hosted_file_results = await handle_input_upload_files(event.target[input_element_id].files, task_id);
$ae_sess.files.processed_file_list = [];
$ae_sess = $ae_sess;
event.target.reset();
// await tick();
if (log_lvl) {
console.log(`hosted_file_id_li: ${hosted_file_id_li}`, hosted_file_id_li);
} else if (log_lvl > 1) {
console.log('hosted_file_results:', hosted_file_results);
}
}
// hosted_file_results = await handle_input_upload_files(event.target[input_element_id].files, task_id);
$ae_sess.files.processed_file_list = [];
$ae_sess = $ae_sess;
event.target.reset();
// await tick();
if (log_lvl) {
console.log(`hosted_file_id_li: ${hosted_file_id_li}`, hosted_file_id_li);
} else if (log_lvl > 1) {
console.log('hosted_file_results:', hosted_file_results);
$ae_sess.files.disable_submit__hosted_file_obj = false;
$ae_sess.files.submit_status = 'saved';
submit_status = 'saved';
upload_complete = true;
}
async function handle_input_upload_files(input_upload_files, form_kv, task_id) {
console.log('*** handle_input_upload_files() ***');
console.log(input_upload_files);
console.log(form_kv);
const form_data = new FormData();
// form_data.append('account_id', $ae_loc.account_id);
// form_data.append('link_to_type', link_to_type);
// form_data.append('link_to_id', link_to_id);
form_data.append('start_time', form_kv.start_time);
form_data.append('end_time', form_kv.end_time);
if (form_kv.reencode == '1' || form_kv.reencode == 'true') {
form_data.append('reencode', 'true');
} else {
form_data.append('reencode', 'false');
}
// There should really only be one file uploaded at a time for now.
for (let i = 0; i < input_upload_files.length; i++) {
form_data.append(`video_file`, input_upload_files[i]);
}
// hash_sha256, uploaded, uploaded_bytes
// $ae_sess.files.processed_file_list[i] = {
// ...$ae_sess.files.processed_file_list[i],
// uploaded: $ae_sess.api_upload_kv[link_to_id].percent_completed,
// uploaded_bytes: $ae_sess.api_upload_kv[link_to_id].uploaded_bytes,
// };
let params = null;
let endpoint = '/hosted_file/clip_video';
console.log(form_data);
params = null;
// Uncomment and the post_promise is not seen by the "await" below
// post_promise = await api.post_object({api_cfg: $cfg.api, endpoint: endpoint, params: params, data:form_data});
// Uncomment so that the post_promise is not seen by the "await" below
ae_promises.upload__hosted_file_obj = api
.post_object({
api_cfg: $ae_api,
endpoint: endpoint,
params: params,
form_data: form_data,
return_blob: true,
filename: 'clipped_video_test.mp4',
auto_download: false,
task_id: task_id,
log_lvl: log_lvl
// retry_count: 1,
})
.then(async function (result) {
console.log(result);
let file_blob = new Blob([result.data]);
// console.log(file_blob);
let file_obj_url = window.URL.createObjectURL(file_blob); // The img src
// const url = window.URL.createObjectURL(new Blob([result.data]));
download_clip_src = file_obj_url;
// download_filename = file_obj_url;
return true;
// // WARNING!!!! ONLY ONE FILE IS EXPECTED TO BE UPLOADED AT A TIME!!!
// // NOTE: The /hosted_file/upload_files endpoint will always return a list of successful files uploaded. In this case we are only uploading one file and expecting a list of one item.
// let x = 0;
// console.log(result[x]);
// let hosted_file_obj = result[x];
// let hosted_file_id = hosted_file_obj.hosted_file_id_random;
// hosted_file_id_li.push(hosted_file_id);
// hosted_file_obj_li.push(hosted_file_obj);
// let hosted_file_data: key_val = {};
// hosted_file_data['hosted_file_id_random'] = hosted_file_id;
// hosted_file_data['for_type'] = link_to_type;
// hosted_file_data['for_id_random'] = link_to_id;
// hosted_file_data['filename'] = hosted_file_obj.filename;
// hosted_file_data['extension'] = hosted_file_obj.extension;
// hosted_file_data['enable'] = true;
// console.log(hosted_file_data);
// return hosted_file_data;
// $ae_sess.files.new_upload_list[i].uploaded_bytes = 10; // fake 10 bytes at least...
// let event_file_id = await events_func.create_hosted_file_obj_from_hosted_file_async({
// api_cfg: $ae_api,
// hosted_file_id: hosted_file_id,
// data: event_file_data,
// log_lvl: log_lvl
// })
// .then(function (create_result) {
// console.log(create_result); // NOTE: This should be the event_file_id string
// // let event_file_id = create_result;
// return create_result;
// });
// return event_file_id;
})
// .then(function (hosted_file_data) {
// return hosted_file_data;
// })
.catch(function (error: any) {
console.log('Something went wrong.');
console.log(error);
return false;
})
.finally(function () {
// $slct_trigger = 'load__hosted_file_obj_li';
});
console.log(ae_promises.upload__hosted_file_obj);
let hosted_file_result = ae_promises.upload__hosted_file_obj;
return hosted_file_result;
}
$ae_sess.files.disable_submit__hosted_file_obj = false;
$ae_sess.files.submit_status = 'saved';
submit_status = 'saved';
upload_complete = true;
}
async function handle_input_upload_files(input_upload_files, form_kv, task_id) {
console.log('*** handle_input_upload_files() ***');
console.log(input_upload_files);
console.log(form_kv);
const form_data = new FormData();
// form_data.append('account_id', $ae_loc.account_id);
// form_data.append('link_to_type', link_to_type);
// form_data.append('link_to_id', link_to_id);
form_data.append('start_time', form_kv.start_time);
form_data.append('end_time', form_kv.end_time);
if (form_kv.reencode == '1' || form_kv.reencode == 'true') {
form_data.append('reencode', 'true');
} else {
form_data.append('reencode', 'false');
}
// There should really only be one file uploaded at a time for now.
for (let i = 0; i < input_upload_files.length; i++) {
form_data.append(`video_file`, input_upload_files[i]);
}
// hash_sha256, uploaded, uploaded_bytes
// $ae_sess.files.processed_file_list[i] = {
// ...$ae_sess.files.processed_file_list[i],
// uploaded: $ae_sess.api_upload_kv[link_to_id].percent_completed,
// uploaded_bytes: $ae_sess.api_upload_kv[link_to_id].uploaded_bytes,
// };
let params = null;
let endpoint = '/hosted_file/clip_video';
console.log(form_data);
params = null;
// Uncomment and the post_promise is not seen by the "await" below
// post_promise = await api.post_object({api_cfg: $cfg.api, endpoint: endpoint, params: params, data:form_data});
// Uncomment so that the post_promise is not seen by the "await" below
ae_promises.upload__hosted_file_obj = api.post_object({
api_cfg: $ae_api,
endpoint: endpoint,
params: params,
form_data: form_data,
return_blob: true,
filename: 'clipped_video_test.mp4',
auto_download: false,
task_id: task_id,
log_lvl: log_lvl,
// retry_count: 1,
})
.then(async function (result) {
console.log(result);
let file_blob = new Blob([result.data]);
// console.log(file_blob);
let file_obj_url = window.URL.createObjectURL(file_blob); // The img src
// const url = window.URL.createObjectURL(new Blob([result.data]));
download_clip_src = file_obj_url;
// download_filename = file_obj_url;
return true;
// // WARNING!!!! ONLY ONE FILE IS EXPECTED TO BE UPLOADED AT A TIME!!!
// // NOTE: The /hosted_file/upload_files endpoint will always return a list of successful files uploaded. In this case we are only uploading one file and expecting a list of one item.
// let x = 0;
// console.log(result[x]);
// let hosted_file_obj = result[x];
// let hosted_file_id = hosted_file_obj.hosted_file_id_random;
// hosted_file_id_li.push(hosted_file_id);
// hosted_file_obj_li.push(hosted_file_obj);
// let hosted_file_data: key_val = {};
// hosted_file_data['hosted_file_id_random'] = hosted_file_id;
// hosted_file_data['for_type'] = link_to_type;
// hosted_file_data['for_id_random'] = link_to_id;
// hosted_file_data['filename'] = hosted_file_obj.filename;
// hosted_file_data['extension'] = hosted_file_obj.extension;
// hosted_file_data['enable'] = true;
// console.log(hosted_file_data);
// return hosted_file_data;
// $ae_sess.files.new_upload_list[i].uploaded_bytes = 10; // fake 10 bytes at least...
// let event_file_id = await events_func.create_hosted_file_obj_from_hosted_file_async({
// api_cfg: $ae_api,
// hosted_file_id: hosted_file_id,
// data: event_file_data,
// log_lvl: log_lvl
// })
// .then(function (create_result) {
// console.log(create_result); // NOTE: This should be the event_file_id string
// // let event_file_id = create_result;
// return create_result;
// });
// return event_file_id;
})
// .then(function (hosted_file_data) {
// return hosted_file_data;
// })
.catch(function (error) {
console.log('Something went wrong.');
console.log(error);
return false;
})
.finally( function () {
// $slct_trigger = 'load__hosted_file_obj_li';
});
console.log(ae_promises.upload__hosted_file_obj);
let hosted_file_result = ae_promises.upload__hosted_file_obj;
return hosted_file_result;
}
</script>
<div>
<!-- class:hidden={!$ae_loc.trusted_access} -->
<form
on:submit|preventDefault={handle_submit_form_files}
class="{class_li_default} {class_li}"
>
<!-- class:hidden={!$ae_loc.trusted_access} -->
<form onsubmit={preventDefault(handle_submit_form_files)} class="{class_li_default} {class_li}">
<label class="label"
>Start time (HH:MM:SS) <input
type="text"
name="start_time"
value="00:00:00"
placeholder="HH:MM:SS (00:01:30)"
class="input w-32"
/></label
>
<label class="label"
>End time (HH:MM:SS) <input
type="text"
name="end_time"
value="00:01:15"
placeholder="HH:MM:SS (01:05:25)"
class="input w-32"
/></label
>
<label class="label">Start time (HH:MM:SS) <input type="text" name="start_time" value="00:00:00" placeholder="HH:MM:SS (00:01:30)" class="input w-32" /></label>
<label class="label">End time (HH:MM:SS) <input type="text" name="end_time" value="00:01:15" placeholder="HH:MM:SS (01:05:25)" class="input w-32" /></label>
<label class="label"
>Re-encode (true or false) <input
type="text"
name="reencode"
value="false"
placeholder="true"
class="input w-32"
/></label
>
<label class="label">Re-encode (true or false) <input type="text" name="reencode" value="false" placeholder="true" class="input w-32" /></label>
{#await ae_promises.upload__hosted_file_obj}
<div class="text-lg flex flex-row gap-1 items-center justify-center">
<span class="fas fa-spinner fa-spin m-1"></span>
<span class="">
Uploading
{#if $ae_sess.api_upload_kv[task_id]}
{$ae_sess.api_upload_kv[task_id].percent_completed}%
{/if}
</span>
</div>
{/await}
<label
for="ae_comp__hosted_files_upload__input"
class="svelte_input_file_label text-center"
class:hidden={$ae_sess.files.disable_submit__hosted_file_obj}
>
{#if label}{@render label()}{:else}
<div>
<span class="fas fa-upload"></span>
<!-- Select files to upload -->
<!-- <span class="fas fa-file-archive"></span> -->
<strong class="bg-blue-300 p-1">Upload files</strong>
<!-- (drag and drop) -->
</div>
<span class="text-sm text-gray-600 dark:text-gray-400 italic">
<strong>Video files only</strong><br />
(mp4 or mkv)
</span>
{/if}
</label>
<input
id={input_element_id}
type="file"
bind:files={input_file_list}
{multiple}
{required}
{accept}
name={input_name}
class="svelte_input_file_element file-dropzone-input block w-full text-lg text-gray-900 border border-gray-300 rounded-lg cursor-pointer bg-gray-50 dark:text-gray-400 focus:outline-hidden dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 {input_class_li.join(
' '
)}"
class:hidden={$ae_sess.files.disable_submit__hosted_file_obj}
/>
<Element_input_files_tbl
bind:input_file_list
bind:file_list_status={$ae_sess.files.status__file_list}
bind:processed_file_list={$ae_sess.files.processed_file_list}
{table_class_li}
/>
<button
type="submit"
class="btn btn-lg btn-primary preset-tonal-primary border border-primary-500 hover:preset-tonal-success border border-success-500 w-54"
disabled={$ae_sess.files.disable_submit__hosted_file_obj ||
$ae_sess.files.status__file_list != 'ready'}
>
{#await ae_promises.upload__hosted_file_obj}
<span class="fas fa-spinner fa-spin m-1"></span>
<span class="">
Uploading
{#if $ae_sess.api_upload_kv[task_id]}
{$ae_sess.api_upload_kv[task_id].percent_completed}%
{/if}
</span>
{:then}
<span class="fas fa-upload m-1"></span>
<span class="text-sm"> Upload? </span>
<!-- <span class="fas fa-save m-1"></span> -->
<span class="grow font-bold">
{#if $ae_sess.files.processed_file_list?.length > 0}
{$ae_sess.files.processed_file_list.length == 1
? `${$ae_sess.files.processed_file_list.length} file`
: `${$ae_sess.files.processed_file_list.length} files`}
{:else}
<span class="text-xs"> No files selected </span>
{/if}
<!-- Files -->
</span>
{/await}
</button>
</form>
<hr />
{#await ae_promises.upload__hosted_file_obj}
<div class="text-lg flex flex-row gap-1 items-center justify-center">
<span class="fas fa-spinner fa-spin m-1"></span>
<span class="">
Uploading
{#if $ae_sess.api_upload_kv[task_id]}
{$ae_sess.api_upload_kv[task_id].percent_completed}%
{/if}
</span>
</div>
<p class="highlight">Converting... This may take a few minutes.</p>
{:then}
{#if ae_promises.upload__hosted_file_obj}
<a
href={download_clip_src}
download={download_clip_filename}
class="ae_btn btn_lg btn_primary"
><span class="fas fa-download"></span> Ready to Download</a
>
{:else}
<p>Fill out the form and select the video file to clip.</p>
{/if}
{/await}
<label
for="ae_comp__hosted_files_upload__input"
class="svelte_input_file_label text-center"
class:hidden={$ae_sess.files.disable_submit__hosted_file_obj}
>
<slot name="label">
<div>
<span class="fas fa-upload"></span>
<!-- Select files to upload -->
<!-- <span class="fas fa-file-archive"></span> -->
<strong class="bg-blue-300 p-1">Upload files</strong>
<!-- (drag and drop) -->
</div>
<span class="text-sm text-gray-600 dark:text-gray-400 italic">
<strong>Video files only</strong><br>
(mp4 or mkv)
</span>
</slot>
</label>
<input
id={input_element_id}
type="file"
bind:files={input_file_list}
{multiple}
{required}
{accept}
name={input_name}
class="svelte_input_file_element file-dropzone-input block w-full text-lg text-gray-900 border border-gray-300 rounded-lg cursor-pointer bg-gray-50 dark:text-gray-400 focus:outline-hidden dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 {input_class_li.join(' ')}"
class:hidden={$ae_sess.files.disable_submit__hosted_file_obj}
/>
<Element_input_files_tbl
bind:input_file_list={input_file_list}
bind:file_list_status={$ae_sess.files.status__file_list}
bind:processed_file_list={$ae_sess.files.processed_file_list}
table_class_li={table_class_li}
/>
<button
type="submit"
class="btn btn-lg btn-primary preset-tonal-primary border border-primary-500 hover:preset-tonal-success border border-success-500 w-54"
disabled={$ae_sess.files.disable_submit__hosted_file_obj || $ae_sess.files.status__file_list != 'ready'}
>
{#await ae_promises.upload__hosted_file_obj}
<span class="fas fa-spinner fa-spin m-1"></span>
<span class="">
Uploading
{#if $ae_sess.api_upload_kv[task_id]}
{$ae_sess.api_upload_kv[task_id].percent_completed}%
{/if}
</span>
{:then}
<span class="fas fa-upload m-1"></span>
<span class="text-sm">
Upload?
</span>
<!-- <span class="fas fa-save m-1"></span> -->
<span class="grow font-bold">
{#if $ae_sess.files.processed_file_list?.length > 0}
<!-- {#each $ae_sess.files.processed_file_list as file_obj, index}
<span class="text-xs">
{file_obj.filename}
</span>
{/each} -->
{$ae_sess.files.processed_file_list.length == 1 ? `${$ae_sess.files.processed_file_list.length} file` : `${$ae_sess.files.processed_file_list.length} files`}
{:else}
<span class="text-xs">
No files selected
</span>
{/if}
<!-- Files -->
</span>
{/await}
</button>
</form>
<hr />
{#await ae_promises.upload__hosted_file_obj}
<span class="fas fa-spinner fa-spin m-1"></span>
<p class="highlight">Converting... This may take a few minutes.</p>
{:then}
{#if ae_promises.upload__hosted_file_obj}
<a href={download_clip_src} download={download_clip_filename} class="ae_btn btn_lg btn_primary"><span class="fas fa-download"></span> Ready to Download</a>
{:else}
<p>Fill out the form and select the video file to clip.</p>
{/if}
{/await}
</div>
</div>

View File

@@ -1,152 +1,156 @@
<script lang="ts">
// *** Import Svelte specific
// *** Import Svelte specific
// Eventually this should use Lucide icons instead of FontAwesome
// import {
// ArrowDown01, ArrowDown10, ArrowDownUp,
// BookHeart, BriefcaseBusiness,
// CalendarClock, CalendarOff, Clock, CodeXml, Copy,
// Eye, EyeOff,
// Flag, FlagOff, FileX, Fingerprint,
// Globe, Group,
// Hash, History,
// LockKeyhole, LockKeyholeOpen,
// MessageSquareWarning, Menu, Minus,
// NotebookPen, NotebookText, NotepadTextDashed,
// Pencil, PenLine, Plus,
// RemoveFormatting,
// Search, Settings,
// Shapes, Share2, ShieldCheck, ShieldMinus, Siren, Skull,
// SquareLibrary,
// Tags, Trash2, TypeOutline,
// X
// } from '@lucide/svelte';
// Eventually this should use Lucide icons instead of FontAwesome
// import {
// ArrowDown01, ArrowDown10, ArrowDownUp,
// BookHeart, BriefcaseBusiness,
// CalendarClock, CalendarOff, Clock, CodeXml, Copy,
// Eye, EyeOff,
// Flag, FlagOff, FileX, Fingerprint,
// Globe, Group,
// Hash, History,
// LockKeyhole, LockKeyholeOpen,
// MessageSquareWarning, Menu, Minus,
// NotebookPen, NotebookText, NotepadTextDashed,
// Pencil, PenLine, Plus,
// RemoveFormatting,
// Search, Settings,
// Shapes, Share2, ShieldCheck, ShieldMinus, Siren, Skull,
// SquareLibrary,
// Tags, Trash2, TypeOutline,
// X
// } from '@lucide/svelte';
// *** Import Aether specific variables and functions
import type { key_val } from '$lib/ae_stores';
import { ae_util } from '$lib/ae_utils/ae_utils';
import { api } from '$lib/api';
import { ae_snip, ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
// *** 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 {
ae_snip,
ae_loc,
ae_sess,
ae_api,
ae_trig,
slct,
slct_trigger
} from '$lib/stores/ae_stores';
interface Props {
log_lvl?: number;
hosted_file_id: null|string;
hosted_file_obj: null|key_val;
filename?: null|string;
max_length?: number;
auto_download?: boolean;
linked_to_type?: null|string;
linked_to_id?: null|string;
download_complete?: null|boolean;
download_percent?: number;
download_status_msg?: string;
classes?: string;
}
let {
log_lvl = 0,
hosted_file_id,
hosted_file_obj,
filename = $bindable(null),
max_length = $bindable(30),
auto_download = true,
linked_to_type = $bindable(null),
linked_to_id = $bindable(null),
download_complete = $bindable(),
download_percent = $bindable(),
download_status_msg = $bindable('Not started'),
classes = 'btn btn-sm lg:btn-md preset-tonal-tertiary border border-tertiary-500 hover:preset-filled-tertiary-500 min-w-48'
}: Props = $props();
if (log_lvl) {
console.log(`ae_comp__hosted_files_download_button.svelte hosted_file_id=${hosted_file_id}`, hosted_file_obj);
}
let ae_promises: key_val = $state({});
$effect(() => {
if ($ae_sess?.api_download_kv[hosted_file_obj?.hosted_file_id_random]?.percent_completed) {
download_percent = $ae_sess.api_download_kv[hosted_file_obj?.hosted_file_id_random].percent_completed;
interface Props {
log_lvl?: number;
hosted_file_id: null | string;
hosted_file_obj: null | key_val;
filename?: null | string;
max_length?: number;
auto_download?: boolean;
linked_to_type?: null | string;
linked_to_id?: null | string;
download_complete?: null | boolean;
download_percent?: number;
download_status_msg?: string;
classes?: string;
}
});
let {
log_lvl = 0,
hosted_file_id,
hosted_file_obj,
filename = $bindable(null),
max_length = $bindable(30),
auto_download = true,
linked_to_type = $bindable(null),
linked_to_id = $bindable(null),
download_complete = $bindable(),
download_percent = $bindable(),
download_status_msg = $bindable('Not started'),
classes = 'btn btn-sm lg:btn-md preset-tonal-tertiary border border-tertiary-500 hover:preset-filled-tertiary-500 min-w-48'
}: Props = $props();
if (log_lvl) {
console.log(
`ae_comp__hosted_files_download_button.svelte hosted_file_id=${hosted_file_id}`,
hosted_file_obj
);
}
let ae_promises: key_val = $state({});
$effect(() => {
if ($ae_sess?.api_download_kv[hosted_file_obj?.hosted_file_id_random]?.percent_completed) {
download_percent =
$ae_sess.api_download_kv[hosted_file_obj?.hosted_file_id_random].percent_completed;
}
});
</script>
{#if hosted_file_id && hosted_file_obj}
<button
type="button"
disabled={!$ae_loc.trusted_access}
class="{classes ?? 'btn'}"
onclick={() => {
download_complete = false;
download_status_msg = 'Downloading...';
ae_promises[hosted_file_obj.hosted_file_id_random] = api.download_hosted_file({
api_cfg: $ae_api,
hosted_file_id: hosted_file_obj.hosted_file_id_random,
return_file: true,
filename: filename ?? hosted_file_obj.filename,
auto_download: auto_download,
log_lvl: log_lvl
})
.then((result) => {
if (result === null) {
console.log('File not found (404)');
download_complete = null;
download_status_msg = 'File not found';
} else if (result === false) {
console.log('Possible error with API server (check network and server status)');
download_complete = false;
download_status_msg = 'Failed to download';
} else {
// console.log('File found and downloaded');
download_complete = true;
download_status_msg = 'File downloaded';
}
return result;
});
}}
title={`Download this file:\n${filename ?? hosted_file_obj?.filename}\n[API] SHA256: ${hosted_file_obj?.hash_sha256?.slice(0, 10)}...\nHosted ID: ${hosted_file_obj?.hosted_file_id_random}\n Linked to: ${linked_to_type} ID: ${linked_to_id}`}
<button
type="button"
disabled={!$ae_loc.trusted_access}
class={classes ?? 'btn'}
onclick={() => {
download_complete = false;
download_status_msg = 'Downloading...';
ae_promises[hosted_file_obj.hosted_file_id_random] = api
.download_hosted_file({
api_cfg: $ae_api,
hosted_file_id: hosted_file_obj.hosted_file_id_random,
return_file: true,
filename: filename ?? hosted_file_obj.filename,
auto_download: auto_download,
log_lvl: log_lvl
})
.then((result) => {
if (result === null) {
console.log('File not found (404)');
download_complete = null;
download_status_msg = 'File not found';
} else if (result === false) {
console.log(
'Possible error with API server (check network and server status)'
);
download_complete = false;
download_status_msg = 'Failed to download';
} else {
// console.log('File found and downloaded');
download_complete = true;
download_status_msg = 'File downloaded';
}
return result;
});
}}
title={`Download this file:\n${filename ?? hosted_file_obj?.filename}\n[API] SHA256: ${hosted_file_obj?.hash_sha256?.slice(0, 10)}...\nHosted ID: ${hosted_file_obj?.hosted_file_id_random}\n Linked to: ${linked_to_type} ID: ${linked_to_id}`}
>
{#await ae_promises[hosted_file_obj.hosted_file_id_random]}
<span class="fas fa-spinner fa-spin mx-1"></span>
<span class="">
Downloading
{#if $ae_sess.api_download_kv[hosted_file_obj.hosted_file_id_random]}
{$ae_sess.api_download_kv[hosted_file_obj.hosted_file_id_random].percent_completed}%
{/if}
:
{#await ae_promises[hosted_file_obj.hosted_file_id_random]}
<span class="fas fa-spinner fa-spin mx-1"></span>
<span class="">
Downloading
{#if $ae_sess.api_download_kv[hosted_file_obj.hosted_file_id_random]}
{$ae_sess.api_download_kv[hosted_file_obj.hosted_file_id_random]
.percent_completed}%
{/if}
:
</span>
{:then}
<span class="fas fa-{ae_util.file_extension_icon(hosted_file_obj?.extension)}"></span>
{/await}
{#if download_complete === null}
<span class="text-red-800 dark:text-red-200">File not found</span>
{:else if download_complete === false}
<span class="text-red-800 dark:text-red-200">Failed to download!</span>
{/if}
<span class="grow">
{ae_util.shorten_filename({
filename: filename ?? hosted_file_obj?.filename,
max_length: max_length
})}
</span>
{:then}
<span class="fas fa-{ae_util.file_extension_icon(hosted_file_obj?.extension)}"></span>
{/await}
{#if download_complete === null}
<span class="text-red-800 dark:text-red-200">File not found</span>
{:else if download_complete === false}
<span class="text-red-800 dark:text-red-200">Failed to download!</span>
{/if}
<span class="grow">
{ae_util.shorten_filename({filename: filename ?? hosted_file_obj?.filename, max_length: max_length})}
</span>
</button>
</button>
{:else}
<button
type="button"
disabled
class="{classes ?? 'btn'}"
title="No file selected"
>
<span class="fas fa-{ae_util.file_extension_icon(hosted_file_obj?.extension)}"></span>
<span class="grow">
No file info
</span>
</button>
{/if}
<button type="button" disabled class={classes ?? 'btn'} title="No file selected">
<span class="fas fa-{ae_util.file_extension_icon(hosted_file_obj?.extension)}"></span>
<span class="grow"> No file info </span>
</button>
{/if}

View File

@@ -1,264 +1,289 @@
<script lang="ts">
export let log_lvl: number = 0;
import { preventDefault } from 'svelte/legacy';
// Imports
// Import components and elements
import Element_input_files_tbl from '$lib/element_input_files_tbl.svelte';
// Imports
// Import components and elements
import Element_input_files_tbl from '$lib/elements/element_input_files_tbl.svelte';
// Import storage, functions, and libraries
import type { key_val } from '$lib/ae_stores';
// Import storage, functions, and libraries
import type { key_val } from '$lib/stores/ae_stores';
import { api } from '$lib/api';
import { ae_snip, ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
import { api } from '$lib/api/api';
import {
ae_snip,
ae_loc,
ae_sess,
ae_api,
ae_trig,
slct,
slct_trigger
} from '$lib/stores/ae_stores';
// Exports
// Expecting these for link_to_type: 'event', 'event_location', 'archive_content', etc
export let link_to_type: string;
export let link_to_id: string;
// Exports
export let input_name = 'file_list';
export let multiple: boolean = true;
export let required: boolean = true;
export let accept: string = 'audio/*, image/*, video/*, .bak, .cfg, .css, .csv, .doc, .docx, .gz, .htm, .html, .ini, .iso, .j2, .json, .key, .keynote, .md, .pdf, .ppt, .pptx, .rar, .rtf, .sql, .svelte, ttf, .txt, .xls, .xlsx, .xz, .zip, .bin, .dmg, .exe, .js, .msi, .php, .py, .sh';
export let class_li_default: string = 'flex flex-col gap-1 items-center justify-center w-full max-w-2xl mx-auto my-1';
export let class_li: string = '';
export let input_class_li: string[] = ['file_drop_area'];
export let table_class_li: string[] = ['table', 'table-sm', 'table-striped', '' , 'text-sm'];
export let upload_complete: boolean = false;
export let submit_status: null|string = null;
export let hosted_file_id_li: string[] = [];
export let hosted_file_obj_li: any[] = [];
export let hosted_file_obj_kv: key_val = {};
// Local Variables
let task_id = link_to_id;
let input_file_list: any = null;
let ae_promises: key_val = {}; // Promise<any>;
let ae_triggers: key_val = {};
let input_element_id = 'ae_comp__hosted_files_upload__input';
// *** Functions and Logic
async function handle_submit_form_files(event: SubmitEvent) {
console.log('*** handle_submit_form() ***');
if (!event) {
return;
interface Props {
log_lvl?: number;
// Expecting these for link_to_type: 'event', 'event_location', 'archive_content', etc
link_to_type: string;
link_to_id: string;
input_name?: string;
multiple?: boolean;
required?: boolean;
accept?: string;
class_li_default?: string;
class_li?: string;
input_class_li?: string[];
table_class_li?: string[];
upload_complete?: boolean;
submit_status?: null | string;
hosted_file_id_li?: string[];
hosted_file_obj_li?: any[];
hosted_file_obj_kv?: key_val;
label?: import('svelte').Snippet;
}
$ae_sess.files.disable_submit__hosted_file_obj = true;
$ae_sess.files.submit_status = 'saving';
submit_status = 'saving';
upload_complete = false;
let {
log_lvl = 0,
link_to_type,
link_to_id,
input_name = 'file_list',
multiple = true,
required = true,
accept = 'audio/*, image/*, video/*, .bak, .cfg, .css, .csv, .doc, .docx, .gz, .htm, .html, .ini, .iso, .j2, .json, .key, .keynote, .md, .pdf, .ppt, .pptx, .rar, .rtf, .sql, .svelte, ttf, .txt, .xls, .xlsx, .xz, .zip, .bin, .dmg, .exe, .js, .msi, .php, .py, .sh',
class_li_default = 'flex flex-col gap-1 items-center justify-center w-full max-w-2xl mx-auto my-1',
class_li = '',
input_class_li = ['file_drop_area'],
table_class_li = ['table', 'table-sm', 'table-striped', '', 'text-sm'],
upload_complete = $bindable(false),
submit_status = $bindable(null),
hosted_file_id_li = $bindable([]),
hosted_file_obj_li = $bindable([]),
hosted_file_obj_kv = $bindable({}),
label
}: Props = $props();
hosted_file_id_li = [];
hosted_file_obj_li = [];
hosted_file_obj_kv = {};
// Local Variables
let task_id = $state(link_to_id);
let input_file_list: any = $state(null);
let ae_promises: key_val = $state({}); // Promise<any>;
let ae_triggers: key_val = {};
let hosted_file_results;
let input_element_id = 'ae_comp__hosted_files_upload__input';
const target = event.target as HTMLFormElement;
if (target && target[input_element_id] && (target[input_element_id] as HTMLInputElement)?.files && (target[input_element_id] as HTMLInputElement).files.length > 0) {
task_id = link_to_id; // Ideally this should be the file hash, but we may be uploading multiple files at once. This should be done with a loop instead?
// *** Functions and Logic
async function handle_submit_form_files(event: SubmitEvent) {
console.log('*** handle_submit_form() ***');
// Loop through each file and upload them individually in event.target[input_element_id].files
// The task_id should be the file hash.
// processed_file_list[i] has the file hash_sha256, hash_sha256_match, warnings, uploaded, uploaded_bytes, filename, and file_size_bytes.
for (let i = 0; i < event.target[input_element_id].files.length; i++) {
let tmp_file = event.target[input_element_id].files[i];
if (!event) {
return;
}
task_id = $ae_sess.files.processed_file_list[i].hash_sha256;
$ae_sess.files.disable_submit__hosted_file_obj = true;
$ae_sess.files.submit_status = 'saving';
submit_status = 'saving';
upload_complete = false;
// hosted_file_results = await handle_input_upload_files([tmp_file], task_id);
hosted_file_results = await handle_input_upload_files({
hosted_file_id_li = [];
hosted_file_obj_li = [];
hosted_file_obj_kv = {};
let hosted_file_results;
const target = event.target as HTMLFormElement;
if (
target &&
target[input_element_id] &&
(target[input_element_id] as HTMLInputElement)?.files &&
(target[input_element_id] as HTMLInputElement).files.length > 0
) {
task_id = link_to_id; // Ideally this should be the file hash, but we may be uploading multiple files at once. This should be done with a loop instead?
// Loop through each file and upload them individually in event.target[input_element_id].files
// The task_id should be the file hash.
// processed_file_list[i] has the file hash_sha256, hash_sha256_match, warnings, uploaded, uploaded_bytes, filename, and file_size_bytes.
for (let i = 0; i < event.target[input_element_id].files.length; i++) {
let tmp_file = event.target[input_element_id].files[i];
task_id = $ae_sess.files.processed_file_list[i].hash_sha256;
// hosted_file_results = await handle_input_upload_files([tmp_file], task_id);
hosted_file_results = await handle_input_upload_files({
input_upload_files: [tmp_file],
task_id: task_id
});
if (hosted_file_results) {
console.log(`hosted_file_results:`, hosted_file_results);
} else {
console.log(`hosted_file_results:`, hosted_file_results);
if (hosted_file_results) {
console.log(`hosted_file_results:`, hosted_file_results);
} else {
console.log(`hosted_file_results:`, hosted_file_results);
}
}
// hosted_file_results = await handle_input_upload_files(event.target[input_element_id].files, task_id);
$ae_sess.files.processed_file_list = [];
$ae_sess = $ae_sess; // Is this needed? 2025-03-17
event.target.reset();
// await tick();
if (log_lvl) {
console.log(`hosted_file_id_li: ${hosted_file_id_li}`, hosted_file_id_li);
} else if (log_lvl > 1) {
console.log('hosted_file_results:', hosted_file_results);
}
}
// hosted_file_results = await handle_input_upload_files(event.target[input_element_id].files, task_id);
$ae_sess.files.processed_file_list = [];
$ae_sess = $ae_sess; // Is this needed? 2025-03-17
event.target.reset();
// await tick();
if (log_lvl) {
console.log(`hosted_file_id_li: ${hosted_file_id_li}`, hosted_file_id_li);
} else if (log_lvl > 1) {
console.log('hosted_file_results:', hosted_file_results);
}
$ae_sess.files.disable_submit__hosted_file_obj = false;
$ae_sess.files.submit_status = 'saved';
submit_status = 'saved';
upload_complete = true;
}
$ae_sess.files.disable_submit__hosted_file_obj = false;
$ae_sess.files.submit_status = 'saved';
submit_status = 'saved';
upload_complete = true;
}
async function handle_input_upload_files({
input_upload_files,
task_id
}: {
input_upload_files: any[];
task_id: string;
}) {
console.log('*** handle_input_upload_files() ***');
const form_data = new FormData();
async function handle_input_upload_files(
{
input_upload_files,
task_id
} : {
input_upload_files: any[],
task_id: string
form_data.append('account_id', $ae_loc.account_id);
form_data.append('link_to_type', link_to_type);
form_data.append('link_to_id', link_to_id);
for (let i = 0; i < input_upload_files.length; i++) {
form_data.append(`file_list`, input_upload_files[i]);
}
) {
console.log('*** handle_input_upload_files() ***');
const form_data = new FormData();
// hash_sha256, uploaded, uploaded_bytes
// $ae_sess.files.processed_file_list[i] = {
// ...$ae_sess.files.processed_file_list[i],
// uploaded: $ae_sess.api_upload_kv[link_to_id].percent_completed,
// uploaded_bytes: $ae_sess.api_upload_kv[link_to_id].uploaded_bytes,
// };
form_data.append('account_id', $ae_loc.account_id);
form_data.append('link_to_type', link_to_type);
form_data.append('link_to_id', link_to_id);
let params = null;
for (let i = 0; i < input_upload_files.length; i++) {
form_data.append(`file_list`, input_upload_files[i]);
let endpoint = '/hosted_file/upload_files';
console.log(form_data);
params = null;
// Uncomment and the post_promise is not seen by the "await" below
// post_promise = await api.post_object({api_cfg: $cfg.api, endpoint: endpoint, params: params, data:form_data});
// Uncomment so that the post_promise is not seen by the "await" below
ae_promises.upload__hosted_file_obj = api
.post_object({
api_cfg: $ae_api,
endpoint: endpoint,
// params: params,
form_data: form_data,
task_id: task_id,
log_lvl: log_lvl
// retry_count: 1,
})
.then(async function (result) {
// WARNING!!!! ONLY ONE FILE IS EXPECTED TO BE UPLOADED AT A TIME!!!
// NOTE: The /hosted_file/upload_files endpoint will always return a list of successful files uploaded. In this case we are only uploading one file and expecting a list of one item.
let x = 0;
console.log(result[x]);
let hosted_file_obj = result[x];
let hosted_file_id = hosted_file_obj.hosted_file_id_random;
hosted_file_id_li.push(hosted_file_id);
hosted_file_obj_li.push(hosted_file_obj);
let hosted_file_data: key_val = {};
hosted_file_data['id'] = hosted_file_id;
hosted_file_data['hosted_file_id'] = hosted_file_id;
hosted_file_data['hosted_file_id_random'] = hosted_file_id;
hosted_file_data['for_type'] = link_to_type;
hosted_file_data['for_id'] = link_to_id;
hosted_file_data['for_id_random'] = link_to_id;
hosted_file_data['hash_sha256'] = hosted_file_obj.hash_sha256;
hosted_file_data['filename'] = hosted_file_obj.filename;
hosted_file_data['extension'] = hosted_file_obj.extension;
hosted_file_data['content_type'] = hosted_file_obj.content_type;
hosted_file_data['size'] = hosted_file_obj.size;
hosted_file_data['enable'] = true;
hosted_file_data['created_on'] = hosted_file_obj.created_on;
hosted_file_data['updated_on'] = hosted_file_obj.updated_on;
console.log(hosted_file_data);
hosted_file_obj_kv[hosted_file_id] = hosted_file_data;
return hosted_file_data;
// $ae_sess.files.new_upload_list[i].uploaded_bytes = 10; // fake 10 bytes at least...
// let event_file_id = await events_func.create_hosted_file_obj_from_hosted_file_async({
// api_cfg: $ae_api,
// hosted_file_id: hosted_file_id,
// data: event_file_data,
// log_lvl: log_lvl
// })
// .then(function (create_result) {
// console.log(create_result); // NOTE: This should be the event_file_id string
// // let event_file_id = create_result;
// return create_result;
// });
// return event_file_id;
})
.then(function (hosted_file_data) {
return hosted_file_data;
})
.catch(function (error: any) {
console.log('Something went wrong.');
console.log(error);
return false;
})
.finally(function () {
$slct_trigger = 'load__hosted_file_obj_li';
});
console.log(ae_promises.upload__hosted_file_obj);
let hosted_file_result = ae_promises.upload__hosted_file_obj;
return hosted_file_result;
}
// hash_sha256, uploaded, uploaded_bytes
// $ae_sess.files.processed_file_list[i] = {
// ...$ae_sess.files.processed_file_list[i],
// uploaded: $ae_sess.api_upload_kv[link_to_id].percent_completed,
// uploaded_bytes: $ae_sess.api_upload_kv[link_to_id].uploaded_bytes,
// };
let params = null;
let endpoint = '/hosted_file/upload_files';
console.log(form_data);
params = null;
// Uncomment and the post_promise is not seen by the "await" below
// post_promise = await api.post_object({api_cfg: $cfg.api, endpoint: endpoint, params: params, data:form_data});
// Uncomment so that the post_promise is not seen by the "await" below
ae_promises.upload__hosted_file_obj = api.post_object({
api_cfg: $ae_api,
endpoint: endpoint,
// params: params,
form_data: form_data,
task_id: task_id,
log_lvl: log_lvl,
// retry_count: 1,
})
.then(async function (result) {
// WARNING!!!! ONLY ONE FILE IS EXPECTED TO BE UPLOADED AT A TIME!!!
// NOTE: The /hosted_file/upload_files endpoint will always return a list of successful files uploaded. In this case we are only uploading one file and expecting a list of one item.
let x = 0;
console.log(result[x]);
let hosted_file_obj = result[x];
let hosted_file_id = hosted_file_obj.hosted_file_id_random;
hosted_file_id_li.push(hosted_file_id);
hosted_file_obj_li.push(hosted_file_obj);
let hosted_file_data: key_val = {};
hosted_file_data['id'] = hosted_file_id;
hosted_file_data['hosted_file_id'] = hosted_file_id;
hosted_file_data['hosted_file_id_random'] = hosted_file_id;
hosted_file_data['for_type'] = link_to_type;
hosted_file_data['for_id'] = link_to_id;
hosted_file_data['for_id_random'] = link_to_id;
hosted_file_data['hash_sha256'] = hosted_file_obj.hash_sha256;
hosted_file_data['filename'] = hosted_file_obj.filename;
hosted_file_data['extension'] = hosted_file_obj.extension;
hosted_file_data['content_type'] = hosted_file_obj.content_type;
hosted_file_data['size'] = hosted_file_obj.size;
hosted_file_data['enable'] = true;
hosted_file_data['created_on'] = hosted_file_obj.created_on;
hosted_file_data['updated_on'] = hosted_file_obj.updated_on;
console.log(hosted_file_data);
hosted_file_obj_kv[hosted_file_id] = hosted_file_data;
return hosted_file_data;
// $ae_sess.files.new_upload_list[i].uploaded_bytes = 10; // fake 10 bytes at least...
// let event_file_id = await events_func.create_hosted_file_obj_from_hosted_file_async({
// api_cfg: $ae_api,
// hosted_file_id: hosted_file_id,
// data: event_file_data,
// log_lvl: log_lvl
// })
// .then(function (create_result) {
// console.log(create_result); // NOTE: This should be the event_file_id string
// // let event_file_id = create_result;
// return create_result;
// });
// return event_file_id;
})
.then(function (hosted_file_data) {
return hosted_file_data;
})
.catch(function (error) {
console.log('Something went wrong.');
console.log(error);
return false;
})
.finally( function () {
$slct_trigger = 'load__hosted_file_obj_li';
});
console.log(ae_promises.upload__hosted_file_obj);
let hosted_file_result = ae_promises.upload__hosted_file_obj;
return hosted_file_result;
}
</script>
<!-- class:hidden={!$ae_loc.trusted_access} -->
<form
on:submit|preventDefault={handle_submit_form_files}
class="{class_li_default} {class_li}"
>
<form onsubmit={preventDefault(handle_submit_form_files)} class="{class_li_default} {class_li}">
{#await ae_promises.upload__hosted_file_obj}
<div class="text-lg flex flex-row gap-1 items-center justify-center">
<span class="fas fa-spinner fa-spin m-1"></span>
<span class="">
Uploading
{#if $ae_sess.api_upload_kv[task_id]}
{$ae_sess.api_upload_kv[task_id].percent_completed}%
{/if}
</span>
</div>
<div class="text-lg flex flex-row gap-1 items-center justify-center">
<span class="fas fa-spinner fa-spin m-1"></span>
<span class="">
Uploading
{#if $ae_sess.api_upload_kv[task_id]}
{$ae_sess.api_upload_kv[task_id].percent_completed}%
{/if}
</span>
</div>
{/await}
<label
for="ae_comp__hosted_files_upload__input"
class="svelte_input_file_label text-center"
class:hidden={$ae_sess.files.disable_submit__hosted_file_obj}
>
<slot name="label">
<div>
<span class="fas fa-upload"></span>
<!-- Select files to upload -->
<!-- <span class="fas fa-file-archive"></span> -->
<strong class="bg-blue-300 p-1">Upload files</strong>
<!-- (drag and drop) -->
</div>
<span class="text-sm text-gray-600 dark:text-gray-400 italic">
<strong>Presentation related files only</strong><br>
(PowerPoint, Keynote, PDF, mp4, Word Doc, Excel, txt, etc)
</span>
</slot>
>
{#if label}{@render label()}{:else}
<div>
<span class="fas fa-upload"></span>
<!-- Select files to upload -->
<!-- <span class="fas fa-file-archive"></span> -->
<strong class="bg-blue-300 p-1">Upload files</strong>
<!-- (drag and drop) -->
</div>
<span class="text-sm text-gray-600 dark:text-gray-400 italic">
<strong>Presentation related files only</strong><br />
(PowerPoint, Keynote, PDF, mp4, Word Doc, Excel, txt, etc)
</span>
{/if}
</label>
<input
@@ -269,23 +294,33 @@ async function handle_input_upload_files(
{required}
{accept}
name={input_name}
class="svelte_input_file_element file-dropzone-input block w-full text-lg text-gray-900 border border-gray-300 rounded-lg cursor-pointer bg-gray-50 dark:text-gray-400 focus:outline-hidden dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 {input_class_li.join(' ')}"
class="
svelte_input_file_element
file-dropzone-input
px-1
block w-full text-lg
text-gray-900
border border-gray-300 rounded-lg
cursor-pointer b
g-gray-50 dark:text-gray-400 focus:outline-hidden dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400
{input_class_li.join(' ')}
"
class:hidden={$ae_sess.files.disable_submit__hosted_file_obj}
/>
/>
<Element_input_files_tbl
bind:input_file_list={input_file_list}
bind:input_file_list
bind:file_list_status={$ae_sess.files.status__file_list}
bind:processed_file_list={$ae_sess.files.processed_file_list}
table_class_li={table_class_li}
/>
{table_class_li}
/>
<button
type="submit"
class="btn btn-lg btn-primary preset-tonal-primary border border-primary-500 hover:preset-tonal-success border border-success-500 w-54"
disabled={$ae_sess.files.disable_submit__hosted_file_obj || $ae_sess.files.status__file_list != 'ready'}
>
disabled={$ae_sess.files.disable_submit__hosted_file_obj ||
$ae_sess.files.status__file_list != 'ready'}
>
{#await ae_promises.upload__hosted_file_obj}
<span class="fas fa-spinner fa-spin m-1"></span>
<span class="">
@@ -296,22 +331,16 @@ async function handle_input_upload_files(
</span>
{:then}
<span class="fas fa-upload m-1"></span>
<span class="text-sm">
Upload?
</span>
<span class="text-sm"> Upload? </span>
<!-- <span class="fas fa-save m-1"></span> -->
<span class="grow font-bold">
{#if $ae_sess.files.processed_file_list?.length > 0}
<!-- {#each $ae_sess.files.processed_file_list as file_obj, index}
<span class="text-xs">
{file_obj.filename}
</span>
{/each} -->
{$ae_sess.files.processed_file_list.length == 1 ? `${$ae_sess.files.processed_file_list.length} file` : `${$ae_sess.files.processed_file_list.length} files`}
{$ae_sess.files.processed_file_list.length == 1
? `${$ae_sess.files.processed_file_list.length} file`
: `${$ae_sess.files.processed_file_list.length} files`}
{:else}
<span class="text-xs">
No files selected
</span>
<span class="text-xs"> No files selected </span>
{/if}
<!-- Files -->
</span>

View File

@@ -1,56 +1,46 @@
import { browser } from '$app/environment';
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api';
import type { key_val } from '$lib/stores/ae_stores';
import { api } from '$lib/api/api';
import {
load_ae_obj_id__activity_log,
load_ae_obj_li__activity_log,
create_ae_obj__activity_log,
update_ae_obj__activity_log,
update_ae_obj__activity_log
// db_save_ae_obj_li__activity_log
} from "$lib/ae_core/core__activity_log";
} from '$lib/ae_core/core__activity_log';
import {
load_ae_obj_id__person,
load_ae_obj_li__person,
create_ae_obj__person,
delete_ae_obj_id__person,
update_ae_obj__person,
update_ae_obj__person
// db_save_ae_obj_li__person
} from "$lib/ae_core/core__person";
} from '$lib/ae_core/core__person';
import {
auth_ae_obj__username_password,
auth_ae_obj__user_id_user_auth_key,
send_email_auth_ae_obj__user_id,
qry_ae_obj_li__user_email,
auth_ae_obj__user_id_change_password,
auth_ae_obj__user_id_change_password
// handle_load_ae_obj_id__user,
// handle_load_ae_obj_li__user,
// handle_create_ae_obj__user,
// handle_update_ae_obj__user,
// handle_db_save_ae_obj_li__user
} from "$lib/ae_core/core__user";
} from '$lib/ae_core/core__user';
import {
generate_qr_code,
} from "$lib/ae_core/core__qr_code";
import { generate_qr_code, js_generate_qr_code } from '$lib/ae_core/core__qr_code';
import {
check_hosted_file_obj_w_hash
} from "$lib/ae_core/core__check_hosted_file_obj_w_hash";
import { check_hosted_file_obj_w_hash } from '$lib/ae_core/core__check_hosted_file_obj_w_hash';
import {
load_ae_obj_li__time_zone
} from "$lib/ae_core/core__time_zones";
import { load_ae_obj_li__time_zone } from '$lib/ae_core/core__time_zones';
import {
load_ae_obj_li__country
} from "$lib/ae_core/core__countries";
import { load_ae_obj_li__country } from '$lib/ae_core/core__countries';
import {
load_ae_obj_li__country_subdivision
} from "$lib/ae_core/core__country_subdivisions";
import { load_ae_obj_li__country_subdivision } from '$lib/ae_core/core__country_subdivisions';
import {
load_ae_obj_id__hosted_file,
@@ -58,40 +48,33 @@ import {
delete_ae_obj_id__hosted_file,
db_save_ae_obj_li__hosted_file,
db_update_ae_obj_id__hosted_file
} from "$lib/ae_core/core__hosted_files";
} from '$lib/ae_core/core__hosted_files';
// This has more generic general purpose functions that can eventually replace the custom ones per object type.
import {
db_save_ae_obj_li__ae_obj,
} from "$lib/ae_core/core__idb_dexie";
import { db_save_ae_obj_li__ae_obj } from '$lib/ae_core/core__idb_dexie';
import {
add_url_params,
clean_headers,
} from "$lib/ae_core/core__api_helpers";
let ae_promises: key_val = {}; // Promise<any>;
import { add_url_params, clean_headers } from '$lib/ae_core/core__api_helpers';
const ae_promises: key_val = {}; // Promise<any>;
// Updated 2024-03-29
async function handle_load_ae_obj_id__site_domain(
{
api_cfg,
fqdn,
try_cache = false,
timeout = 7000,
log_lvl = 0
}: {
api_cfg: any,
fqdn: string,
try_cache?: boolean,
timeout?: number,
log_lvl?: number
}
) {
async function load_ae_obj_id__site_domain({
api_cfg,
fqdn,
try_cache = false,
timeout = 7000,
log_lvl = 0
}: {
api_cfg: any;
fqdn: string;
try_cache?: boolean;
timeout?: number;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** handle_load_ae_obj_id__site_domain() *** api.base_url=${api_cfg.base_url}, fqdn=${fqdn}, timeout=${timeout}`);
console.log(
`*** load_ae_obj_id__site_domain() *** api.base_url=${api_cfg.base_url}, fqdn=${fqdn}, timeout=${timeout}`
);
}
let no_account_id = false;
@@ -101,68 +84,66 @@ async function handle_load_ae_obj_id__site_domain(
}
no_account_id = true;
let params = {};
const params = {};
// ae_sess.hub.site_domain_id_qry_status = 'loading';
ae_promises.load__site_domain_obj = api.get_ae_obj_id_crud({
api_cfg: api_cfg,
no_account_id: no_account_id,
obj_type: 'site_domain',
obj_id: fqdn, // NOTE: This is the FQDN, not normally the ID.
use_alt_table: true, // NOTE: This will use the table_name_alt value (v_site_domain_fqdn_id) instead of the table_name value in the API config.
use_alt_base: true, // NOTE: This will use the base_name_alt value (Site_Domain_FQDN_ID_Base) instead of the base_name value in the API config.
params: params,
timeout: timeout,
log_lvl: log_lvl
// ae_sess.hub.site_domain_id_qry_status = 'loading';
ae_promises.load__site_domain_obj = api
.get_ae_obj_id_crud({
api_cfg: api_cfg,
no_account_id: no_account_id,
obj_type: 'site_domain',
obj_id: fqdn, // NOTE: This is the FQDN, not normally the ID.
use_alt_table: true, // NOTE: This will use the table_name_alt value (v_site_domain_fqdn_id) instead of the table_name value in the API config.
use_alt_base: true, // NOTE: This will use the base_name_alt value (Site_Domain_FQDN_ID_Base) instead of the base_name value in the API config.
params: params,
timeout: timeout,
log_lvl: log_lvl
})
.then(function (site_domain_obj_get_result) {
if (site_domain_obj_get_result) {
// slct.site_domain_obj = site_domain_obj_get_result;
// console.log(`site_domain object:`, get(slct).site_domain_obj);
.then(function (site_domain_obj_get_result) {
if (site_domain_obj_get_result) {
// slct.site_domain_obj = site_domain_obj_get_result;
// console.log(`site_domain object:`, get(slct).site_domain_obj);
// ae_loc.account_id = $slct.site_domain_obj.account_id_random;
// ae_loc.site_id = $slct.site_domain_obj.site_id_random;
// ae_loc.site_domain_id = $slct.site_domain_obj.site_domain_id_random;
return site_domain_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
// ae_loc.account_id = $slct.site_domain_obj.account_id_random;
// ae_loc.site_id = $slct.site_domain_obj.site_id_random;
// ae_loc.site_domain_id = $slct.site_domain_obj.site_domain_id_random;
return site_domain_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
return ae_promises.load__site_domain_obj;
}
// Updated 2024-03-29
async function handle_load_ae_obj_code__data_store(
{
api_cfg,
code,
data_type = 'text',
for_type = null,
for_id = null,
try_cache = true,
save_idb = false,
timeout = 9000,
log_lvl = 0
}: {
api_cfg: any,
code: string,
data_type?: string,
for_type?: string|null,
for_id?: string|null,
try_cache?: boolean,
save_idb?: boolean,
timeout?: number,
log_lvl?: number
}
) {
async function load_ae_obj_code__data_store({
api_cfg,
code,
data_type = 'text',
for_type = null,
for_id = null,
try_cache = true,
save_idb = false,
timeout = 9000,
log_lvl = 0
}: {
api_cfg: any;
code: string;
data_type?: string;
for_type?: string | null;
for_id?: string | null;
try_cache?: boolean;
save_idb?: boolean;
timeout?: number;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** handle_get_data_store_obj_w_code() *** code=${code}`);
console.log(`*** load_ae_obj_code__data_store() *** code=${code}`);
}
if (!code) {
@@ -175,28 +156,28 @@ async function handle_load_ae_obj_code__data_store(
return false;
}
ae_promises.load__data_store_obj = api.get_data_store_obj_w_code({
api_cfg: api_cfg,
data_store_code: code,
data_type: data_type,
timeout: timeout,
log_lvl: log_lvl
ae_promises.load__data_store_obj = api
.get_data_store_obj_w_code({
api_cfg: api_cfg,
data_store_code: code,
data_type: data_type,
timeout: timeout,
log_lvl: log_lvl
})
.then(function (get_ds_result) {
let return_this = null;
if (get_ds_result) {
if (log_lvl) {
console.log(`*ae_func* Got a result for code ${code}`);
}
.then(function (get_ds_result) {
let return_this = null;
if (get_ds_result) {
if (log_lvl) {
console.log(`*ae_func* Got a result for code ${code}`);
}
if (!get_ds_result.data_store_id_random) {
console.log('*ae_func* Something went wrong? No data store ID found.');
return false;
}
if (!get_ds_result.data_store_id_random) {
console.log('*ae_func* Something went wrong? No data store ID found.');
return false;
}
// let ae_ds_tmp: key_val = {};
let ds_code_obj =
{
// let ae_ds_tmp: key_val = {};
const ds_code_obj = {
id: null,
account_id: null,
code: code,
@@ -213,178 +194,410 @@ async function handle_load_ae_obj_code__data_store(
text: null,
updated_on: null,
chk_account_id: api_cfg.account_id,
loaded_on: new Date().toISOString(),
loaded_on: new Date().toISOString()
};
let val_json: key_val;
let val_html: key_val;
let val_md: key_val;
let val_sql: key_val;
let val_text: string;
let val_json: key_val;
let val_html: key_val;
let val_md: key_val;
let val_sql: key_val;
let val_text: string;
// Set the loaded_on datetime to the current time for reference later. This will be used to determine if the data store is stale.
// ds_code_obj.loaded_on = new Date().toISOString();
// Set the chk_account_id as a backup check to make sure the data store belongs to the account for the current site. This should not be needed, but here we are...
// ds_code_obj.chk_account_id = api_cfg.account_id;
// Set the loaded_on datetime to the current time for reference later. This will be used to determine if the data store is stale.
// ds_code_obj.loaded_on = new Date().toISOString();
// Set the chk_account_id as a backup check to make sure the data store belongs to the account for the current site. This should not be needed, but here we are...
// ds_code_obj.chk_account_id = api_cfg.account_id;
ds_code_obj.id = get_ds_result.data_store_id_random;
ds_code_obj.account_id = get_ds_result.account_id_random;
ds_code_obj.code = get_ds_result.code; // This will overwrite whatever was passed in.
ds_code_obj.name = get_ds_result.name;
ds_code_obj.type = get_ds_result.type; // This will overwrite whatever was passed in.
if (data_type == 'html') {
ds_code_obj.html = get_ds_result.text;
val_html = get_ds_result.text;
return_this = get_ds_result.html;
} else if (data_type == 'json') {
ds_code_obj.json = get_ds_result.json;
val_json = get_ds_result.json;
return_this = get_ds_result.json;
} else if (data_type == 'md') {
ds_code_obj.text = get_ds_result.text;
val_md = get_ds_result.text;
return_this = get_ds_result.text;
} else if (data_type == 'sql') {
ds_code_obj.text = get_ds_result.text;
val_sql = get_ds_result.text;
return_this = get_ds_result.text;
} else {
ds_code_obj.text = get_ds_result.text;
val_text = get_ds_result.text;
return_this = get_ds_result.text;
}
// if (data_type == 'text') {
// // console.log(get_ds_result.text);
// return_this = get_ds_result.text;
// } else if (data_type == 'json') {
// // console.log(get_ds_result.json);
// return_this = get_ds_result.json;
// }
if (save_idb) {
if (browser) {
let key_prefix = 'ae_ds__';
if (log_lvl) {
console.log(`*ae_func* localStorage key: ${code}, value:`, get_ds_result);
}
localStorage.setItem(`${key_prefix}${code}`, JSON.stringify(get_ds_result));
ds_code_obj.id = get_ds_result.data_store_id_random;
ds_code_obj.account_id = get_ds_result.account_id_random;
ds_code_obj.code = get_ds_result.code; // This will overwrite whatever was passed in.
ds_code_obj.name = get_ds_result.name;
ds_code_obj.type = get_ds_result.type; // This will overwrite whatever was passed in.
if (data_type == 'html') {
ds_code_obj.html = get_ds_result.text;
val_html = get_ds_result.text;
return_this = get_ds_result.html;
} else if (data_type == 'json') {
ds_code_obj.json = get_ds_result.json;
val_json = get_ds_result.json;
return_this = get_ds_result.json;
} else if (data_type == 'md') {
ds_code_obj.text = get_ds_result.text;
val_md = get_ds_result.text;
return_this = get_ds_result.text;
} else if (data_type == 'sql') {
ds_code_obj.text = get_ds_result.text;
val_sql = get_ds_result.text;
return_this = get_ds_result.text;
} else {
if (log_lvl) {
console.log('*ae_func* No browser! Can not use localStorage to save data store object.');
ds_code_obj.text = get_ds_result.text;
val_text = get_ds_result.text;
return_this = get_ds_result.text;
}
// if (data_type == 'text') {
// // console.log(get_ds_result.text);
// return_this = get_ds_result.text;
// } else if (data_type == 'json') {
// // console.log(get_ds_result.json);
// return_this = get_ds_result.json;
// }
if (save_idb) {
if (browser) {
const key_prefix = 'ae_ds__';
if (log_lvl) {
console.log(
`*ae_func* localStorage key: ${code}, value:`,
get_ds_result
);
}
localStorage.setItem(`${key_prefix}${code}`, JSON.stringify(get_ds_result));
} else {
if (log_lvl) {
console.log(
'*ae_func* No browser! Can not use localStorage to save data store object.'
);
}
}
}
} else {
console.log('*ae_func* No results returned.');
return_this = null;
}
} else {
console.log('*ae_func* No results returned.');
return_this = null;
}
return return_this;
})
.catch(function (error) {
console.log('*ae_func* No results returned or failed.', error);
});
return return_this;
})
.catch(function (error: any) {
console.log('*ae_func* No results returned or failed.', error);
});
return ae_promises.load__data_store_obj;
}
// Updated 2024-03-27
async function handle_update_ae_obj_id_crud(
{
api_cfg,
object_type,
object_id,
field_name,
new_field_value,
params={},
try_cache=false,
log_lvl=0
}: {
api_cfg: any,
object_type: string,
object_id: string,
field_name: string,
new_field_value: any,
params: any|key_val,
try_cache: boolean,
log_lvl: number
}) {
async function update_ae_obj_id_crud({
api_cfg,
object_type,
object_id,
object_reload = false,
field_name,
new_field_value,
params = {},
try_cache = false,
log_lvl = 0
}: {
api_cfg: any;
object_type: string;
object_id: string;
object_reload?: boolean;
field_name: string;
new_field_value: any;
params: any | key_val;
try_cache: boolean;
log_lvl: number;
}) {
let patch_result: any = null;
ae_promises.api_update__ae_obj = api.update_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: object_type,
obj_id: object_id,
field_name: field_name,
field_value: new_field_value,
// fields: data,
key: api_cfg.api_crud_super_key,
// jwt: null,
// params: params,
// data: patch_data,
log_lvl: log_lvl
ae_promises.api_update__ae_obj = api
.update_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: object_type,
obj_id: object_id,
field_name: field_name,
field_value: new_field_value,
// fields: data,
key: api_cfg.api_crud_super_key,
// jwt: null,
// params: params,
// data: patch_data,
log_lvl: log_lvl
})
.then(function (results) {
console.log('PATCH Promise', results);
.then(function (results) {
console.log('PATCH Promise', results);
if (results) {
console.log(`Patched - Field Name: ${field_name} with new Field Value: ${new_field_value}`);
patch_result = 'PATCH complete';
} else {
console.log(`Not Patched - Field Name: ${field_name} with new Field Value: ${new_field_value}; Account ID: ${api_cfg.account_id}`);
patch_result = 'PATCH failed';
if (results) {
console.log(
`Patched - Field Name: ${field_name} with new Field Value: ${new_field_value}`
);
patch_result = 'PATCH complete';
} else {
console.log(
`Not Patched - Field Name: ${field_name} with new Field Value: ${new_field_value}; Account ID: ${api_cfg.account_id}`
);
patch_result = 'PATCH failed';
return false;
}
return true;
})
.catch(function (error: any) {
console.log('Something went wrong patching the record.');
console.log(error);
return false;
}
return true;
})
.catch(function (error) {
console.log('Something went wrong patching the record.');
console.log(error);
return false;
})
.finally(function () {
console.log('PATCH Promise finally');
});
})
.finally(function () {
console.log('PATCH Promise finally');
});
return ae_promises.api_update__ae_obj;
}
// Core - Already imported above
// import { load_ae_obj_id__person } from "$lib/ae_core/core__person";
// import { load_ae_obj_id__user } from "$lib/ae_core/core__user";
async function handle_download_export__obj_type(
{
api_cfg,
get_obj_type, // The type of object to return: event_badge, event_presenter, sponsorship, etc.
for_obj_type, // Usually for an account, event, event_exhibit, or sponsorship_cfg
for_obj_id, // The ID of the object
exp_alt = null, // Export name (idaa, other, not 'default')
file_type = 'CSV', // 'CSV' or 'Excel'
return_file = true,
filename = 'no_filename.csv',
auto_download = false,
limit = 5000,
params = {}, // key value object is expected
log_lvl = 0
}: {
api_cfg: any,
get_obj_type: string,
for_obj_type: string,
for_obj_id: string,
exp_alt?: null|string,
file_type?: string,
return_file?: boolean,
filename?: string,
auto_download?: boolean,
limit?: number,
params?: key_val,
log_lvl?: number
// Additional Modules
import { load_ae_obj_id__archive } from '$lib/ae_archives/ae_archives__archive';
import { load_ae_obj_id__archive_content } from '$lib/ae_archives/ae_archives__archive_content';
import { load_ae_obj_id__event } from '$lib/ae_events/ae_events__event';
// import { load_ae_obj_id__event_badge } from "$lib/ae_events/ae_events__event_badge";
import { load_ae_obj_id__event_device } from '$lib/ae_events/ae_events__event_device';
// import { load_ae_obj_id__event_exhibit } from "$lib/ae_events/ae_events__event_exhibit";
import { load_ae_obj_id__event_file } from '$lib/ae_events/ae_events__event_file';
import { load_ae_obj_id__event_location } from '$lib/ae_events/ae_events__event_location';
import { load_ae_obj_id__event_presentation } from '$lib/ae_events/ae_events__event_presentation';
import { load_ae_obj_id__event_presenter } from '$lib/ae_events/ae_events__event_presenter';
import { load_ae_obj_id__event_session } from '$lib/ae_events/ae_events__event_session';
import { load_ae_obj_id__journal } from '$lib/ae_journals/ae_journals__journal';
import { load_ae_obj_id__journal_entry } from '$lib/ae_journals/ae_journals__journal_entry';
import { load_ae_obj_id__post } from '$lib/ae_posts/ae_posts__post';
import { load_ae_obj_id__post_comment } from '$lib/ae_posts/ae_posts__post_comment';
// Updated 2025-09-30
async function update_ae_obj_id_crud_v2({
api_cfg,
object_type,
object_id,
object_reload = false,
field_name,
new_field_value,
params = {},
try_cache = false,
log_lvl = 0
}: {
api_cfg: any;
object_type: string;
object_id: string;
object_reload?: boolean;
field_name: string;
new_field_value: any;
params?: any | key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(
`*** update_ae_obj_id_crud_v2() *** object_type=${object_type}, object_id=${object_id}, object_reload=${object_reload}, field_name=${field_name}, new_field_value=`,
new_field_value
);
}
) {
console.log('*** ae_core_functions.js: handle_download_export__obj_type() ***');
let patch_result: any = null;
let task_id = for_obj_id;
ae_promises.api_update__ae_obj = await api
.update_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: object_type,
obj_id: object_id,
field_name: field_name,
field_value: new_field_value,
// fields: data,
key: api_cfg.api_crud_super_key,
// jwt: null,
// params: params,
// data: patch_data,
log_lvl: log_lvl
})
.then(function (results) {
console.log('PATCH Promise', results);
if (results) {
console.log(
`Patched - Field Name: ${field_name} with new Field Value: ${new_field_value}`
);
patch_result = 'PATCH complete';
if (object_reload) {
if (log_lvl) {
console.log(`Reloading the object after patching...`);
}
// Reload the object to get the latest data. There is a special case for each type.
if (object_type == 'person') {
const load_person_obj = load_ae_obj_id__person({
api_cfg: api_cfg,
person_id: object_id,
log_lvl: log_lvl
});
return load_person_obj;
}
// if (object_type == 'user') {
// let load_user_obj = load_ae_obj_id__user({
// api_cfg: api_cfg,
// user_id: object_id,
// log_lvl: log_lvl
// });
// return load_user_obj;
// }
if (object_type == 'archive') {
const load_archive_obj = load_ae_obj_id__archive({
api_cfg: api_cfg,
archive_id: object_id,
log_lvl: log_lvl
});
return load_archive_obj;
}
if (object_type == 'archive_content') {
const load_archive_content_obj = load_ae_obj_id__archive_content({
api_cfg: api_cfg,
archive_content_id: object_id,
log_lvl: log_lvl
});
return load_archive_content_obj;
}
if (object_type == 'journal') {
const load_journal_obj = load_ae_obj_id__journal({
api_cfg: api_cfg,
journal_id: object_id,
log_lvl: log_lvl
});
return load_journal_obj;
}
if (object_type == 'journal_entry') {
const load_journal_entry_obj = load_ae_obj_id__journal_entry({
api_cfg: api_cfg,
journal_entry_id: object_id,
log_lvl: log_lvl
});
return load_journal_entry_obj;
}
if (object_type == 'event') {
const load_event_obj = load_ae_obj_id__event({
api_cfg: api_cfg,
event_id: object_id,
log_lvl: log_lvl
});
return load_event_obj;
}
if (object_type == 'event_device') {
const load_event_device_obj = load_ae_obj_id__event_device({
api_cfg: api_cfg,
event_device_id: object_id,
log_lvl: log_lvl
});
return load_event_device_obj;
}
if (object_type == 'event_file') {
const load_event_file_obj = load_ae_obj_id__event_file({
api_cfg: api_cfg,
event_file_id: object_id,
log_lvl: log_lvl
});
return load_event_file_obj;
}
if (object_type == 'event_location') {
const load_event_location_obj = load_ae_obj_id__event_location({
api_cfg: api_cfg,
event_location_id: object_id,
log_lvl: log_lvl
});
return load_event_location_obj;
}
if (object_type == 'event_presentation') {
const load_event_presentation_obj = load_ae_obj_id__event_presentation({
api_cfg: api_cfg,
event_presentation_id: object_id,
log_lvl: log_lvl
});
return load_event_presentation_obj;
}
if (object_type == 'event_presenter') {
const load_event_presenter_obj = load_ae_obj_id__event_presenter({
api_cfg: api_cfg,
event_presenter_id: object_id,
log_lvl: log_lvl
});
return load_event_presenter_obj;
}
if (object_type == 'event_session') {
const load_event_session_obj = load_ae_obj_id__event_session({
api_cfg: api_cfg,
event_session_id: object_id,
log_lvl: log_lvl
});
return load_event_session_obj;
}
if (object_type == 'post') {
const load_post_obj = load_ae_obj_id__post({
api_cfg: api_cfg,
post_id: object_id,
log_lvl: log_lvl
});
return load_post_obj;
}
if (object_type == 'post_comment') {
const load_post_comment_obj = load_ae_obj_id__post_comment({
api_cfg: api_cfg,
post_comment_id: object_id,
log_lvl: log_lvl
});
return load_post_comment_obj;
}
}
} else {
console.log(
`Not Patched - Field Name: ${field_name} with new Field Value: ${new_field_value}; Account ID: ${api_cfg.account_id}`
);
patch_result = 'PATCH failed';
return false;
}
return true;
})
.catch(function (error: any) {
console.log('Something went wrong patching the record.');
console.log(error);
return false;
})
.finally(function () {
console.log('PATCH Promise finally');
});
return ae_promises.api_update__ae_obj;
}
async function download_export__obj_type({
api_cfg,
get_obj_type, // The type of object to return: event_badge, event_presenter, sponsorship, etc.
for_obj_type, // Usually for an account, event, event_exhibit, or sponsorship_cfg
for_obj_id, // The ID of the object
exp_alt = null, // Export name (idaa, other, not 'default')
file_type = 'CSV', // 'CSV' or 'Excel'
return_file = true,
filename = 'no_filename.csv',
auto_download = false,
limit = 5000,
params = {}, // key value object is expected
log_lvl = 0
}: {
api_cfg: any;
get_obj_type: string;
for_obj_type: string;
for_obj_id: string;
exp_alt?: null | string;
file_type?: string;
return_file?: boolean;
filename?: string;
auto_download?: boolean;
limit?: number;
params?: key_val;
log_lvl?: number;
}) {
console.log('*** ae_core_functions.js: download_export__obj_type() ***');
const task_id = for_obj_id;
const endpoint = `/v2/crud/${get_obj_type}/list`;
params['for_obj_type'] = for_obj_type;
@@ -403,7 +616,7 @@ async function handle_download_export__obj_type(
// let clean_filename = filename.replace(/[^a-z0-9]/gi, '_');
// let clean_filename = filename.replace(/[^a-z0-9\[\]-]/gi, '_');
let clean_filename = filename.replace(/[^a-zA-Z0-9\[\]-_.]/gi, '_');
const clean_filename = filename.replace(/[^a-zA-Z0-9\[\]-_.]/gi, '_');
// let clean_filename = filename.replace(/[^a-zA-Z0-9\[\]-\._ ]/gi, '_');
if (limit >= 0) {
@@ -426,8 +639,7 @@ async function handle_download_export__obj_type(
return ae_promises.download__export_file;
}
let export_obj = {
const export_obj = {
check_hosted_file_obj_w_hash: check_hosted_file_obj_w_hash,
load_ae_obj_li__time_zone: load_ae_obj_li__time_zone,
@@ -446,8 +658,8 @@ let export_obj = {
add_url_params: add_url_params,
clean_headers: clean_headers,
handle_load_ae_obj_id__site_domain: handle_load_ae_obj_id__site_domain,
handle_load_ae_obj_code__data_store: handle_load_ae_obj_code__data_store,
load_ae_obj_id__site_domain: load_ae_obj_id__site_domain,
load_ae_obj_code__data_store: load_ae_obj_code__data_store,
load_ae_obj_id__activity_log: load_ae_obj_id__activity_log,
load_ae_obj_li__activity_log: load_ae_obj_li__activity_log,
@@ -466,8 +678,10 @@ let export_obj = {
qry_ae_obj_li__user_email: qry_ae_obj_li__user_email,
auth_ae_obj__user_id_change_password: auth_ae_obj__user_id_change_password,
handle_update_ae_obj_id_crud: handle_update_ae_obj_id_crud,
handle_download_export__obj_type: handle_download_export__obj_type,
generate_qr_code: generate_qr_code
update_ae_obj_id_crud: update_ae_obj_id_crud,
update_ae_obj_id_crud_v2: update_ae_obj_id_crud_v2,
download_export__obj_type: download_export__obj_type,
generate_qr_code: generate_qr_code,
js_generate_qr_code: js_generate_qr_code
};
export let core_func = export_obj;
export const core_func = export_obj;

View File

@@ -0,0 +1,23 @@
export interface Account {
id: string;
// id_random: string;
account_id: string;
account_id_random: string;
code?: string;
name: string;
short_name?: null | string;
description?: null | string;
enable: null | boolean;
enable_from?: null | Date;
enable_to?: null | Date;
hide?: null | boolean;
priority?: null | boolean;
sort?: null | number;
group?: null | string;
notes?: null | string;
created_on: Date;
updated_on?: null | Date;
}

View File

@@ -1,56 +1,54 @@
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api';
let ae_promises: key_val = {};
import type { key_val } from '$lib/stores/ae_stores';
import { api } from '$lib/api/api';
const ae_promises: key_val = {};
// Updated 2024-10-23
export async function load_ae_obj_id__activity_log(
{
api_cfg,
activity_log_id,
// inc_other_li = false,
try_cache = false,
log_lvl = 0
}: {
api_cfg: any,
activity_log_id: string,
// inc_other_li?: boolean,
try_cache?: boolean,
log_lvl?: number
}
) {
export async function load_ae_obj_id__activity_log({
api_cfg,
activity_log_id,
// inc_other_li = false,
try_cache = false,
log_lvl = 0
}: {
api_cfg: any;
activity_log_id: string;
// inc_other_li?: boolean,
try_cache?: boolean;
log_lvl?: number;
}) {
console.log(`*** load_ae_obj_id__activity_log() *** activity_log_id=${activity_log_id}`);
let params = {};
const params = {};
ae_promises.load__activity_log_obj = await api.get_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'activity_log',
obj_id: activity_log_id, // NOTE: This is the FQDN, not normally the ID.
use_alt_table: true, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value in the API config.
params: params,
log_lvl: log_lvl
ae_promises.load__activity_log_obj = await api
.get_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'activity_log',
obj_id: activity_log_id, // NOTE: This is the FQDN, not normally the ID.
use_alt_table: true, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value in the API config.
params: params,
log_lvl: log_lvl
})
.then(function (activity_log_obj_get_result) {
if (activity_log_obj_get_result) {
// if (try_cache) {
// // This is expecting a list
// db_save_ae_obj_li__activity_log({
// obj_type: 'activity_log',
// obj_li: [activity_log_obj_get_result]
// });
// }
return activity_log_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
.then(function (activity_log_obj_get_result) {
if (activity_log_obj_get_result) {
// if (try_cache) {
// // This is expecting a list
// db_save_ae_obj_li__activity_log({
// obj_type: 'activity_log',
// obj_li: [activity_log_obj_get_result]
// });
// }
return activity_log_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
if (log_lvl) {
console.log('ae_promises.load__activity_log_obj:', ae_promises.load__activity_log_obj);
@@ -59,128 +57,134 @@ export async function load_ae_obj_id__activity_log(
return ae_promises.load__activity_log_obj;
}
// Updated 2024-10-23
export async function load_ae_obj_li__activity_log(
{
api_cfg,
for_obj_type = 'account',
for_obj_id,
// inc_other_li = false,
order_by_li = {'priority': 'DESC', 'sort': 'DESC', 'name': 'ASC', 'updated_on': 'DESC', 'created_on': 'DESC'},
params = {},
try_cache = false,
log_lvl = 0
}: {
api_cfg: any,
for_obj_type: string,
for_obj_id: string,
// inc_other_li?: boolean,
order_by_li?: key_val,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
console.log(`*** load_ae_obj_li__activity_log() *** for_obj_type=${for_obj_type} for_obj_id=${for_obj_id}`);
export async function load_ae_obj_li__activity_log({
api_cfg,
for_obj_type = 'account',
for_obj_id,
// inc_other_li = false,
order_by_li = {
priority: 'DESC',
sort: 'DESC',
name: 'ASC',
updated_on: 'DESC',
created_on: 'DESC'
},
params = {},
try_cache = false,
log_lvl = 0
}: {
api_cfg: any;
for_obj_type: string;
for_obj_id: string;
// inc_other_li?: boolean,
order_by_li?: key_val;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
console.log(
`*** load_ae_obj_li__activity_log() *** for_obj_type=${for_obj_type} for_obj_id=${for_obj_id}`
);
let enabled: string = (params.qry__enabled ?? 'enabled'); // all, disabled, enabled
let hidden: string = (params.qry__hidden ?? 'not_hidden'); // all, hidden, not_hidden
let limit: number = (params.qry__limit ?? 99); // 99
let offset: number = (params.qry__offset ?? 0); // 0
const enabled: string = params.qry__enabled ?? 'enabled'; // all, disabled, enabled
const hidden: string = params.qry__hidden ?? 'not_hidden'; // all, hidden, not_hidden
const limit: number = params.qry__limit ?? 99; // 99
const offset: number = params.qry__offset ?? 0; // 0
let params_json: key_val = {};
const params_json: key_val = {};
// console.log('params_json:', params_json);
ae_promises.load__activity_log_obj_li = await api.get_ae_obj_li_for_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'activity_log',
for_obj_type: for_obj_type,
for_obj_id: for_obj_id,
use_alt_table: true, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
ae_promises.load__activity_log_obj_li = await api
.get_ae_obj_li_for_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'activity_log',
for_obj_type: for_obj_type,
for_obj_id: for_obj_id,
use_alt_table: true, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
})
.then(function (activity_log_obj_li_get_result) {
if (activity_log_obj_li_get_result) {
// if (try_cache) {
// db_save_ae_obj_li__activity_log({
// obj_type: 'activity_log',
// obj_li: activity_log_obj_li_get_result
// });
// }
return activity_log_obj_li_get_result;
} else {
return [];
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
.then(function (activity_log_obj_li_get_result) {
if (activity_log_obj_li_get_result) {
// if (try_cache) {
// db_save_ae_obj_li__activity_log({
// obj_type: 'activity_log',
// obj_li: activity_log_obj_li_get_result
// });
// }
return activity_log_obj_li_get_result;
} else {
return [];
}
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
if (log_lvl) {
console.log('ae_promises.load__activity_log_obj_li:', ae_promises.load__activity_log_obj_li);
console.log(
'ae_promises.load__activity_log_obj_li:',
ae_promises.load__activity_log_obj_li
);
}
return ae_promises.load__activity_log_obj_li;
}
// Updated 2024-10-23
export async function create_ae_obj__activity_log(
{
api_cfg,
account_id,
data_kv,
params = {},
log_lvl = 0
}: {
api_cfg: any,
account_id: string,
data_kv: key_val,
params?: key_val,
log_lvl?: number
}
) {
export async function create_ae_obj__activity_log({
api_cfg,
account_id,
data_kv,
params = {},
log_lvl = 0
}: {
api_cfg: any;
account_id: string;
data_kv: key_val;
params?: key_val;
log_lvl?: number;
}) {
console.log(`*** create_ae_obj__activity_log() *** account_id=${account_id}`);
ae_promises.create__activity_log = await api.create_ae_obj_crud({
api_cfg: api_cfg,
obj_type: 'activity_log',
fields: {
account_id_random: account_id,
...data_kv
ae_promises.create__activity_log = await api
.create_ae_obj_crud({
api_cfg: api_cfg,
obj_type: 'activity_log',
fields: {
account_id_random: account_id,
...data_kv
},
key: api_cfg.api_crud_super_key,
params: params,
return_obj: true,
log_lvl: log_lvl
})
.then(function (activity_log_obj_create_result) {
if (activity_log_obj_create_result) {
// db_save_ae_obj_li__activity_log(
// {
// obj_type: 'activity_log',
// obj_li: [activity_log_obj_create_result]
// });
return activity_log_obj_create_result;
} else {
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
})
.finally(function () {
});
key: api_cfg.api_crud_super_key,
params: params,
return_obj: true,
log_lvl: log_lvl
})
.then(function (activity_log_obj_create_result) {
if (activity_log_obj_create_result) {
// db_save_ae_obj_li__activity_log(
// {
// obj_type: 'activity_log',
// obj_li: [activity_log_obj_create_result]
// });
return activity_log_obj_create_result;
} else {
return null;
}
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
})
.finally(function () {});
if (log_lvl) {
console.log('ae_promises.create__activity_log:', ae_promises.create__activity_log);
@@ -188,55 +192,55 @@ export async function create_ae_obj__activity_log(
return ae_promises.create__activity_log;
}
// Updated 2024-10-23
export async function update_ae_obj__activity_log(
{
api_cfg,
activity_log_id,
data_kv,
params = {},
try_cache = false,
log_lvl = 0
}: {
api_cfg: any,
activity_log_id: string,
data_kv: key_val,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
export async function update_ae_obj__activity_log({
api_cfg,
activity_log_id,
data_kv,
params = {},
try_cache = false,
log_lvl = 0
}: {
api_cfg: any;
activity_log_id: string;
data_kv: key_val;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** update_ae_obj__activity_log() *** activity_log_id=${activity_log_id}`, data_kv);
console.log(
`*** update_ae_obj__activity_log() *** activity_log_id=${activity_log_id}`,
data_kv
);
}
ae_promises.update__activity_log_obj = await api.update_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'activity_log',
obj_id: activity_log_id,
fields: data_kv,
key: api_cfg.api_crud_super_key,
params: params,
return_obj: true,
log_lvl: log_lvl
ae_promises.update__activity_log_obj = await api
.update_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'activity_log',
obj_id: activity_log_id,
fields: data_kv,
key: api_cfg.api_crud_super_key,
params: params,
return_obj: true,
log_lvl: log_lvl
})
.then(function (activity_log_obj_update_result) {
if (activity_log_obj_update_result) {
// if (try_cache) {
// db_save_ae_obj_li__activity_log({
// obj_type: 'activity_log', obj_li: [activity_log_obj_update_result]
// });
// }
return activity_log_obj_update_result;
} else {
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
})
.finally(function () {
});
.then(function (activity_log_obj_update_result) {
if (activity_log_obj_update_result) {
// if (try_cache) {
// db_save_ae_obj_li__activity_log({
// obj_type: 'activity_log', obj_li: [activity_log_obj_update_result]
// });
// }
return activity_log_obj_update_result;
} else {
return null;
}
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
})
.finally(function () {});
if (log_lvl) {
console.log('ae_promises.update__activity_log_obj:', ae_promises.update__activity_log_obj);
@@ -244,46 +248,45 @@ export async function update_ae_obj__activity_log(
return ae_promises.update__activity_log_obj;
}
// This new function is using CRUD v2. This should allow for more flexibility in the queries.
// Updated 2024-10-23
export async function qry__activity_log(
{
api_cfg,
activity_log_id,
qry_str,
qry_files,
qry_start_datetime, // Example greater than: '2024-10-24'
enabled = 'enabled',
hidden = 'not_hidden',
limit = 50,
offset = 0,
params = {},
try_cache = false,
log_lvl = 0
}: {
api_cfg: any,
activity_log_id: any,
qry_str?: string,
qry_files?: null|boolean,
qry_start_datetime?: null|string, // Greater than this datetime
enabled?: string, // all, disabled, enabled
hidden?: string, // all, hidden, not_hidden
limit?: number,
offset?: number,
params?: any,
try_cache?: boolean,
log_lvl?: number
}
) {
console.log(`*** qry__activity_log() *** activity_log_id=${activity_log_id} qry_str=${qry_str}`);
export async function qry__activity_log({
api_cfg,
activity_log_id,
qry_str,
qry_files,
qry_start_datetime, // Example greater than: '2024-10-24'
enabled = 'enabled',
hidden = 'not_hidden',
limit = 50,
offset = 0,
params = {},
try_cache = false,
log_lvl = 0
}: {
api_cfg: any;
activity_log_id: any;
qry_str?: string;
qry_files?: null | boolean;
qry_start_datetime?: null | string; // Greater than this datetime
enabled?: 'enabled' | 'all' | 'not_enabled' | undefined; // all, disabled, enabled
hidden?: 'hidden' | 'all' | 'not_hidden' | undefined; // all, hidden, not_hidden
limit?: number;
offset?: number;
params?: any;
try_cache?: boolean;
log_lvl?: number;
}) {
console.log(
`*** qry__activity_log() *** activity_log_id=${activity_log_id} qry_str=${qry_str}`
);
// let enabled: string = (params.qry__enabled ?? 'enabled'); // all, disabled, enabled
// let hidden: string = (params.qry__hidden ?? 'not_hidden'); // all, hidden, not_hidden
// let limit: number = (params.qry__limit ?? 25); // 99
// let offset: number = (params.qry__offset ?? 0); // 0
let params_json: key_val = {};
const params_json: key_val = {};
// if (qry_str && qry_str.length > 2) {
// params_json['ft_qry'] = {};
@@ -293,69 +296,77 @@ export async function qry__activity_log(
params_json['qry'] = [];
if (qry_files === true) {
let qry_param =
{
type: "AND",
field: "file_count_all",
operator: ">",
value: 0
};
const qry_param = {
type: 'AND',
field: 'file_count_all',
operator: '>',
value: 0
};
params_json['qry'].push(qry_param);
} else if (qry_files === false) {
let qry_param =
{
type: "AND",
field: "file_count_all",
operator: "IS",
value: null
};
const qry_param = {
type: 'AND',
field: 'file_count_all',
operator: 'IS',
value: null
};
params_json['qry'].push(qry_param);
}
if (qry_start_datetime) {
let qry_param =
{
type: "AND",
field: "start_datetime",
operator: ">",
value: qry_start_datetime
};
const qry_param = {
type: 'AND',
field: 'start_datetime',
operator: '>',
value: qry_start_datetime
};
params_json['qry'].push(qry_param);
}
let order_by_li = {'priority': 'DESC', 'sort': 'DESC', 'start_datetime': 'ASC', 'name': 'ASC', 'updated_on': 'DESC', 'created_on': 'DESC'};
const order_by_li: { [key: string]: 'ASC' | 'DESC' }[] = [
{ priority: 'DESC' },
{ sort: 'DESC' },
{ start_datetime: 'ASC' },
{ name: 'ASC' },
{ updated_on: 'DESC' },
{ created_on: 'DESC' }
];
ae_promises.load__activity_log_obj_li = await api.get_ae_obj_li_for_obj_id_crud_v2({
api_cfg: api_cfg,
obj_type: 'activity_log',
for_obj_type: 'account',
for_obj_id: activity_log_id,
use_alt_tbl: true, // NOTE: We want to use the alt table for activity_log searching
use_alt_mdl: false,
use_alt_exp: false,
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
ae_promises.load__activity_log_obj_li = await api
.get_ae_obj_li_for_obj_id_crud_v2({
api_cfg: api_cfg,
obj_type: 'activity_log',
for_obj_type: 'account',
for_obj_id: activity_log_id,
use_alt_tbl: true, // NOTE: We want to use the alt table for activity_log searching
use_alt_mdl: false,
use_alt_exp: false,
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
})
.then(function (activity_log_obj_li_get_result) {
if (activity_log_obj_li_get_result) {
// db_save_ae_obj_li__activity_log({
// obj_type: 'activity_log',
// obj_li: activity_log_obj_li_get_result
// });
return activity_log_obj_li_get_result;
} else {
return [];
}
});
.then(function (activity_log_obj_li_get_result) {
if (activity_log_obj_li_get_result) {
// db_save_ae_obj_li__activity_log({
// obj_type: 'activity_log',
// obj_li: activity_log_obj_li_get_result
// });
return activity_log_obj_li_get_result;
} else {
return [];
}
});
if (log_lvl) {
console.log('ae_promises.load__activity_log_obj_li:', ae_promises.load__activity_log_obj_li);
console.log(
'ae_promises.load__activity_log_obj_li:',
ae_promises.load__activity_log_obj_li
);
}
return ae_promises.load__activity_log_obj_li;
}

View File

@@ -1,27 +1,24 @@
import type { key_val } from '$lib/ae_stores';
import type { key_val } from '$lib/stores/ae_stores';
// Updated 2025-01-28
export function add_url_params(
{
base_url = '',
endpoint,
params,
log_lvl = 0
}: {
base_url?: string,
endpoint: string,
params: key_val,
log_lvl?: number
}
) {
export function add_url_params({
base_url = '',
endpoint,
params,
log_lvl = 0
}: {
base_url?: string;
endpoint: string;
params: key_val;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** add_url_params() *** base_url=${base_url} endpoint=${endpoint}`, params);
}
const url_obj = new URL(endpoint, base_url);
Object.keys(params).forEach(key => url_obj.searchParams.append(key, params[key]));
Object.keys(params).forEach((key) => url_obj.searchParams.append(key, params[key]));
if (log_lvl) {
console.log('New URL:', url_obj.toString());
@@ -31,25 +28,16 @@ export function add_url_params(
// return 'test';
}
// This is used to clean the header property names. Not underscores allowed in the header names.
// Updated 2025-01-28
export function clean_headers(
{
headers,
log_lvl = 0
}: {
headers: any,
log_lvl?: number
}
) {
export function clean_headers({ headers, log_lvl = 0 }: { headers: any; log_lvl?: number }) {
if (log_lvl) {
console.log(`*** clean_headers() ***`, headers);
}
let headers_cleaned: key_val = {};
const headers_cleaned: key_val = {};
for (const prop in headers) {
let prop_cleaned = prop.replaceAll('_', '-');
const prop_cleaned = prop.replaceAll('_', '-');
if (typeof headers[prop] != 'string') {
headers[prop] = JSON.stringify(headers[prop]);
}

View File

@@ -1,32 +1,29 @@
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api';
import type { key_val } from '$lib/stores/ae_stores';
import { api } from '$lib/api/api';
// Updated 2024-10-02
export async function check_hosted_file_obj_w_hash(
{
api_cfg,
hosted_file_hash,
check_for_local = true, // Forces a check on the host server for the file.
params = {},
return_meta = false,
log_lvl = 0
} : {
api_cfg: any,
hosted_file_hash: string,
check_for_local?: boolean,
params?: key_val,
return_meta?: boolean,
log_lvl?: number
}
) {
export async function check_hosted_file_obj_w_hash({
api_cfg,
hosted_file_hash,
check_for_local = true, // Forces a check on the host server for the file.
params = {},
return_meta = false,
log_lvl = 0
}: {
api_cfg: any;
hosted_file_hash: string;
check_for_local?: boolean;
params?: key_val;
return_meta?: boolean;
log_lvl?: number;
}) {
console.log('*** stores_event_api.js: check_hosted_file_obj_w_hash() ***');
const endpoint = `/hosted_file/hash/${hosted_file_hash}`;
if (check_for_local) {
params['check_for_local'] = true;
}
let check_hosted_file_obj_w_hash_get_promise = await api.get_object({
const check_hosted_file_obj_w_hash_get_promise = await api.get_object({
api_cfg: api_cfg,
endpoint: endpoint,
params: params,
@@ -34,4 +31,4 @@ export async function check_hosted_file_obj_w_hash(
log_lvl: log_lvl
});
return check_hosted_file_obj_w_hash_get_promise;
}
}

View File

@@ -1,72 +1,70 @@
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api';
import type { key_val } from '$lib/stores/ae_stores';
import { api } from '$lib/api/api';
import { db_core } from "$lib/ae_core/db_core";
let ae_promises: key_val = {};
import { db_core } from '$lib/ae_core/db_core';
const ae_promises: key_val = {};
// Updated 2024-10-14
export async function load_ae_obj_li__country(
{
api_cfg,
// account_id,
enabled = 'enabled',
hidden = 'not_hidden',
limit = 299,
offset = 0,
order_by_li = {'sort': 'DESC', 'english_short_name': 'ASC', 'alpha_2_code': 'ASC'},
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
// account_id: string,
enabled?: string,
hidden?: string,
limit?: number,
offset?: number,
order_by_li?: key_val
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
export async function load_ae_obj_li__country({
api_cfg,
// account_id,
enabled = 'enabled',
hidden = 'not_hidden',
limit = 299,
offset = 0,
order_by_li = { sort: 'DESC', english_short_name: 'ASC', alpha_2_code: 'ASC' },
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
// account_id: string,
enabled?: 'enabled' | 'all' | 'not_enabled' | undefined;
hidden?: 'hidden' | 'all' | 'not_hidden' | undefined;
limit?: number;
offset?: number;
order_by_li?: key_val;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** load_ae_obj_li__country() ***`);
}
let params_json: key_val = {};
const params_json: key_val = {};
// console.log('params_json:', params_json);
ae_promises.load__country_li = await api.get_ae_obj_li_for_obj_id_crud_v2({
api_cfg: api_cfg,
obj_type: 'lu',
for_obj_type: 'country',
// for_obj_id: account_id,
use_alt_tbl: false,
use_alt_mdl: false,
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
ae_promises.load__country_li = await api
.get_ae_obj_li_for_obj_id_crud_v2({
api_cfg: api_cfg,
obj_type: 'lu',
for_obj_type: 'country',
// for_obj_id: account_id,
use_alt_tbl: false,
use_alt_mdl: false,
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
})
.then(function (country_li_get_result) {
if (country_li_get_result) {
// handle_db_save_ae_obj_li__country({obj_type: 'country', obj_li: country_li_get_result});
return country_li_get_result;
} else {
return [];
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
.then(function (country_li_get_result) {
if (country_li_get_result) {
// handle_db_save_ae_obj_li__country({obj_type: 'country', obj_li: country_li_get_result});
return country_li_get_result;
} else {
return [];
}
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
console.log('ae_promises.load__country_li:', ae_promises.load__country_li);
return ae_promises.load__country_li;

View File

@@ -1,73 +1,74 @@
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api';
import type { key_val } from '$lib/stores/ae_stores';
import { api } from '$lib/api/api';
import { db_core } from "$lib/ae_core/db_core";
let ae_promises: key_val = {};
import { db_core } from '$lib/ae_core/db_core';
const ae_promises: key_val = {};
// Updated 2024-10-14
export async function load_ae_obj_li__country_subdivision(
{
api_cfg,
// account_id,
enabled = 'enabled',
hidden = 'not_hidden',
limit = 399,
offset = 0,
order_by_li = {'sort': 'DESC', 'name': 'ASC', 'code': 'ASC'},
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
// account_id: string,
enabled?: string,
hidden?: string,
limit?: number,
offset?: number,
order_by_li?: key_val
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
export async function load_ae_obj_li__country_subdivision({
api_cfg,
// account_id,
enabled = 'enabled',
hidden = 'not_hidden',
limit = 399,
offset = 0,
order_by_li = { sort: 'DESC', name: 'ASC', code: 'ASC' },
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
// account_id: string,
enabled?: 'enabled' | 'all' | 'not_enabled' | undefined;
hidden?: 'hidden' | 'all' | 'not_hidden' | undefined;
limit?: number;
offset?: number;
order_by_li?: key_val;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** load_ae_obj_li__country_subdivision() ***`);
}
let params_json: key_val = {};
const params_json: key_val = {};
// console.log('params_json:', params_json);
ae_promises.load__country_subdivision_li = await api.get_ae_obj_li_for_obj_id_crud_v2({
api_cfg: api_cfg,
obj_type: 'lu',
for_obj_type: 'country_subdivision',
// for_obj_id: account_id,
use_alt_tbl: false,
use_alt_mdl: false,
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
ae_promises.load__country_subdivision_li = await api
.get_ae_obj_li_for_obj_id_crud_v2({
api_cfg: api_cfg,
obj_type: 'lu',
for_obj_type: 'country_subdivision',
// for_obj_id: account_id,
use_alt_tbl: false,
use_alt_mdl: false,
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
})
.then(function (country_subdivision_li_get_result) {
if (country_subdivision_li_get_result) {
// handle_db_save_ae_obj_li__country_subdivision({obj_type: 'country_subdivision', obj_li: country_subdivision_li_get_result});
return country_subdivision_li_get_result;
} else {
return [];
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
.then(function (country_subdivision_li_get_result) {
if (country_subdivision_li_get_result) {
// handle_db_save_ae_obj_li__country_subdivision({obj_type: 'country_subdivision', obj_li: country_subdivision_li_get_result});
return country_subdivision_li_get_result;
} else {
return [];
}
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
console.log('ae_promises.load__country_subdivision_li:', ae_promises.load__country_subdivision_li);
console.log(
'ae_promises.load__country_subdivision_li:',
ae_promises.load__country_subdivision_li
);
return ae_promises.load__country_subdivision_li;
}

View File

@@ -1,9 +1,9 @@
import { marked } from 'marked';
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api';
import type { key_val } from '$lib/stores/ae_stores';
import { api } from '$lib/api/api';
import { db_save_ae_obj_li__ae_obj } from "$lib/ae_core/core__idb_dexie";
import { db_save_ae_obj_li__ae_obj } from '$lib/ae_core/core__idb_dexie';
// Define generic CRUD args
export interface GenericCrudArgs {
@@ -25,7 +25,6 @@ export interface GenericCrudArgs {
inc_site_domain_li?: boolean;
inc_user_li?: boolean;
// Flags to include related other object models
inc_archive_li?: boolean;
inc_archive_entry_li?: boolean;
@@ -50,16 +49,14 @@ export interface GenericCrudArgs {
}
// Generic function: Load single object by ID
export async function load_ae_obj_id(
args: GenericCrudArgs
): Promise<any> {
const { api_cfg, obj_type, obj_id, db_instance, db_field_li, inc_obj_type_li, try_cache = true, log_lvl = 0 } = args;
export async function load_ae_obj_id(args: GenericCrudArgs): Promise<any> {
const { api_cfg, obj_type, obj_id, log_lvl = 0 } = args;
if (log_lvl) {
console.log(`*** load_ae_obj_id() *** obj_type=${obj_type} obj_id=${obj_id}`);
}
let result = await api.get_ae_obj_id_crud({
const result = await api.get_ae_obj_id_crud({
api_cfg,
obj_type,
obj_id,
@@ -67,93 +64,16 @@ export async function load_ae_obj_id(
log_lvl
});
let idb_db_instance = null; // You must inject the correct DB instance per module
let idb_tbl_name = obj_type;
let properties_to_save: string[] = [];
if (obj_type === 'journal') {
idb_db_instance = 'ae_journals_db';
// idb_tbl_name = 'journal';
result.id = result.journal_id_random; // Ensure we use the correct ID field
result.journal_id = result.journal_id_random;
result.account_id = result.account_id_random;
result.person_id = result.person_id_random;
// WARNING: This works to populate most of the IDB table fields but it is not ideal. It is sort of a safety net.
properties_to_save = Object.keys(db_instance.table('journal').schema.idxByName);
}
if (obj_type === 'journal_entry') {
idb_db_instance = 'ae_journals_db';
// idb_tbl_name = 'entry';
result.id = result.journal_entry_id_random; // Ensure we use the correct ID field
result.journal_entry_id = result.journal_entry_id_random; // Ensure we use the correct ID field
result.journal_id = result.journal_id_random;
// WARNING: This works to populate most of the IDB table fields but it is not ideal. It is sort of a safety net.
properties_to_save = Object.keys(db_instance.table('journal_entry').schema.idxByName);
}
properties_to_save = [
...db_field_li
];
// if (log_lvl) {
// console.log('IDB DB Instance:', db_instance);
// console.log(db_instance.journal_entry.core.schema);
// console.log(db_instance.table('journal_entry'));
// console.log(db_instance.table('journal_entry').schema.idxByName);
// // Show only the keys of the indexes
// console.log(Object.keys(db_instance.table('journal_entry').schema.idxByName));
// }
if (try_cache && result) {
// Process and save to DB
const processed = await process_ae_obj__props({ obj_li: [result], log_lvl });
await db_save_ae_obj_li__ae_obj({
db_instance: db_instance, // You must inject the correct DB instance per module
table_name: idb_tbl_name,
obj_li: processed,
properties_to_save: properties_to_save,
log_lvl
});
}
if (inc_obj_type_li) {
// Load related objects if specified
for (const inc_obj_type of inc_obj_type_li) {
if (log_lvl) {
console.log(`Loading related objects of type: ${inc_obj_type}`);
}
const related_objects = await load_ae_obj_li({
api_cfg,
obj_type: inc_obj_type,
for_obj_type: obj_type,
for_obj_id: obj_id,
enabled: 'enabled',
hidden: 'not_hidden',
limit: 99,
try_cache,
log_lvl
});
result[`${inc_obj_type}_li`] = related_objects;
}
}
return result;
}
// Generic function: Load list of objects
export async function load_ae_obj_li(
args: GenericCrudArgs
): Promise<any> {
export async function load_ae_obj_li(args: GenericCrudArgs): Promise<any> {
const {
api_cfg,
obj_type,
for_obj_type = '',
for_obj_id,
db_instance,
db_field_li,
inc_obj_type_li,
enabled = 'enabled',
hidden = 'not_hidden',
@@ -166,12 +86,14 @@ export async function load_ae_obj_li(
} = args;
if (log_lvl) {
console.log(`*** load_ae_obj_li() *** obj_type=${obj_type} for_obj_type=${for_obj_type} for_obj_id=${for_obj_id}`);
console.log(
`*** load_ae_obj_li() *** obj_type=${obj_type} for_obj_type=${for_obj_type} for_obj_id=${for_obj_id}`
);
}
let params_json: key_val = {};
const params_json: key_val = {};
let result = await api.get_ae_obj_li_for_obj_id_crud_v2({
const result = await api.get_ae_obj_li_for_obj_id_crud_v2({
api_cfg,
obj_type,
for_obj_type,
@@ -186,63 +108,18 @@ export async function load_ae_obj_li(
log_lvl
});
// Loop through results a
let idb_db_instance = null; // You must inject the correct DB instance per module
let idb_tbl_name = obj_type;
let properties_to_save: string[] = [];
if (obj_type === 'journal') {
idb_db_instance = 'ae_journals_db';
// idb_tbl_name = 'journal';
result.id = result.journal_id_random; // Ensure we use the correct ID field
result.journal_id = result.journal_id_random;
result.account_id = result.account_id_random;
result.person_id = result.person_id_random;
// WARNING: This works to populate most of the IDB table fields but it is not ideal. It is sort of a safety net.
properties_to_save = Object.keys(db_instance.table('journal').schema.idxByName);
}
if (obj_type === 'journal_entry') {
idb_db_instance = 'ae_journals_db';
// idb_tbl_name = 'entry';
result.id = result.journal_entry_id_random; // Ensure we use the correct ID field
result.journal_entry_id = result.journal_entry_id_random; // Ensure we use the correct ID field
result.journal_id = result.journal_id_random;
// WARNING: This works to populate most of the IDB table fields but it is not ideal. It is sort of a safety net.
properties_to_save = Object.keys(db_instance.table('journal_entry').schema.idxByName);
}
if (try_cache && result) {
// Process and save to DB
const processed = await process_ae_obj__props({ obj_li: result, log_lvl });
await db_save_ae_obj_li__ae_obj({
db_instance: db_instance,
table_name: idb_tbl_name,
obj_li: processed,
properties_to_save: [],
log_lvl
});
}
return result;
}
// Generic function: Create object
export async function create_ae_obj(
args: GenericCrudArgs
): Promise<any> {
const { api_cfg, obj_type, data_kv, try_cache = true, log_lvl = 0 } = args;
export async function create_ae_obj(args: GenericCrudArgs): Promise<any> {
const { api_cfg, obj_type, data_kv, log_lvl = 0 } = args;
if (log_lvl) {
console.log(`*** create_ae_obj() *** obj_type=${obj_type}`, data_kv);
}
let result = await api.create_ae_obj_crud({
const result = await api.create_ae_obj_crud({
api_cfg,
obj_type,
fields: data_kv,
@@ -252,31 +129,18 @@ export async function create_ae_obj(
log_lvl
});
if (try_cache && result) {
const processed = await process_ae_obj__props({ obj_li: [result], log_lvl });
await db_save_ae_obj_li__ae_obj({
db_instance: null,
table_name: obj_type,
obj_li: processed,
properties_to_save: [],
log_lvl
});
}
return result;
}
// Generic function: Update object
export async function update_ae_obj(
args: GenericCrudArgs
): Promise<any> {
const { api_cfg, obj_type, obj_id, data_kv, try_cache = true, log_lvl = 0 } = args;
export async function update_ae_obj(args: GenericCrudArgs): Promise<any> {
const { api_cfg, obj_type, obj_id, data_kv, log_lvl = 0 } = args;
if (log_lvl) {
console.log(`*** update_ae_obj() *** obj_type=${obj_type} obj_id=${obj_id}`, data_kv);
}
let result = await api.update_ae_obj_id_crud({
const result = await api.update_ae_obj_id_crud({
api_cfg,
obj_type,
obj_id,
@@ -287,31 +151,18 @@ export async function update_ae_obj(
log_lvl
});
if (try_cache && result) {
const processed = await process_ae_obj__props({ obj_li: [result], log_lvl });
await db_save_ae_obj_li__ae_obj({
db_instance: null,
table_name: obj_type,
obj_li: processed,
properties_to_save: [],
log_lvl
});
}
return result;
}
// Generic function: Delete object
export async function delete_ae_obj_id(
args: GenericCrudArgs
): Promise<any> {
const { api_cfg, obj_type, obj_id, method = 'delete', try_cache = true, log_lvl = 0 } = args;
export async function delete_ae_obj_id(args: GenericCrudArgs): Promise<any> {
const { api_cfg, obj_type, obj_id, method = 'delete', log_lvl = 0 } = args;
if (log_lvl) {
console.log(`*** delete_ae_obj_id() *** obj_type=${obj_type} obj_id=${obj_id}`);
}
let result = await api.delete_ae_obj_id_crud({
const result = await api.delete_ae_obj_id_crud({
api_cfg,
obj_type,
obj_id,
@@ -321,123 +172,164 @@ export async function delete_ae_obj_id(
log_lvl
});
if (try_cache) {
// Remove from DB regardless of success/failure
try {
// db_<module>.<obj_type>.delete(obj_id); // You must inject the correct DB here
} catch (err) {
console.error(`Failed to delete ${obj_id}:`, err);
}
}
return result;
}
// Additional Modules that might be needed for reloads
import { load_ae_obj_id__archive } from '$lib/ae_archives/ae_archives__archive';
import { load_ae_obj_id__archive_content } from '$lib/ae_archives/ae_archives__archive_content';
import { load_ae_obj_id__event } from '$lib/ae_events/ae_events__event';
import { load_ae_obj_id__event_device } from '$lib/ae_events/ae_events__event_device';
import { load_ae_obj_id__event_file } from '$lib/ae_events/ae_events__event_file';
import { load_ae_obj_id__event_location } from '$lib/ae_events/ae_events__event_location';
import { load_ae_obj_id__event_presentation } from '$lib/ae_events/ae_events__event_presentation';
import { load_ae_obj_id__event_presenter } from '$lib/ae_events/ae_events__event_presenter';
import { load_ae_obj_id__event_session } from '$lib/ae_events/ae_events__event_session';
import { load_ae_obj_id__journal } from '$lib/ae_journals/ae_journals__journal';
import { load_ae_obj_id__journal_entry } from '$lib/ae_journals/ae_journals__journal_entry';
import { load_ae_obj_id__post } from '$lib/ae_posts/ae_posts__post';
import { load_ae_obj_id__post_comment } from '$lib/ae_posts/ae_posts__post_comment';
import { load_ae_obj_id__person } from '$lib/ae_core/core__person';
// Generic processor with dynamic field detection
export async function process_ae_obj__props({
obj_li,
log_lvl = 0,
export async function update_ae_obj_id_crud_v2({
api_cfg,
object_type,
object_id,
object_reload = false,
field_name,
new_field_value,
log_lvl = 0
}: {
obj_li: any[];
api_cfg: any;
object_type: string;
object_id: string;
object_reload?: boolean;
field_name: string;
new_field_value: any;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** process_ae_obj__props() ***`, obj_li);
console.log(
`*** update_ae_obj_id_crud_v2() *** object_type=${object_type}, object_id=${object_id}, object_reload=${object_reload}, field_name=${field_name}, new_field_value=`,
new_field_value
);
}
if (!obj_li || obj_li.length === 0) {
return [];
try {
const results = await api.update_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: object_type,
obj_id: object_id,
field_name: field_name,
field_value: new_field_value,
key: api_cfg.api_crud_super_key,
log_lvl: log_lvl
});
if (!results) {
console.log(
`Not Patched - Field Name: ${field_name} with new Field Value: ${new_field_value}; Account ID: ${api_cfg.account_id}`
);
return false;
}
console.log(`Patched - Field Name: ${field_name} with new Field Value: ${new_field_value}`);
if (object_reload) {
if (log_lvl) console.log(`Reloading the object after patching...`);
const reload_fns: { [key: string]: (args: any) => Promise<any> } = {
person: load_ae_obj_id__person,
archive: load_ae_obj_id__archive,
archive_content: load_ae_obj_id__archive_content,
journal: load_ae_obj_id__journal,
journal_entry: load_ae_obj_id__journal_entry,
event: load_ae_obj_id__event,
event_device: load_ae_obj_id__event_device,
event_file: load_ae_obj_id__event_file,
event_location: load_ae_obj_id__event_location,
event_presentation: load_ae_obj_id__event_presentation,
event_presenter: load_ae_obj_id__event_presenter,
event_session: load_ae_obj_id__event_session,
post: load_ae_obj_id__post,
post_comment: load_ae_obj_id__post_comment
};
const reload_fn = reload_fns[object_type];
if (reload_fn) {
const id_key = `${object_type}_id`;
return await reload_fn({ api_cfg, [id_key]: object_id, log_lvl });
}
}
return true;
} catch (error) {
console.log('Something went wrong patching the record.', error);
return false;
}
}
export async function download_export_li({
api_cfg,
get_obj_type,
for_obj_type,
for_obj_id,
exp_alt = null,
file_type = 'CSV',
return_file = true,
filename = 'no_filename.csv',
auto_download = false,
limit = 5000,
params = {},
log_lvl = 0
}: {
api_cfg: any;
get_obj_type: string;
for_obj_type: string;
for_obj_id: string;
exp_alt?: null | string;
file_type?: string;
return_file?: boolean;
filename?: string;
auto_download?: boolean;
limit?: number;
params?: key_val;
log_lvl?: number;
}) {
if (log_lvl) console.log('*** download_export_li() ***');
const endpoint = `/v2/crud/${get_obj_type}/list`;
params['for_obj_type'] = for_obj_type;
params['for_obj_id'] = for_obj_id;
if (file_type === 'CSV' || file_type === 'Excel') {
params['file_type'] = file_type;
}
params['return_file'] = true;
params['mdl_alt'] = 'out';
if (exp_alt) {
params['exp_alt'] = exp_alt;
}
const processed = obj_li.map(obj => {
// Extract fields with fallbacks and detect existence
const group = obj.group || '';
const priority = obj.priority !== undefined ? obj.priority : 0;
const sort = obj.sort !== undefined ? obj.sort : 0;
const created_on = obj.created_on || '';
const updated_on = obj.updated_on || '';
const name = obj.name || '';
const clean_filename = filename.replace(/[^a-zA-Z0-9\[\]-_.]/gi, '_');
// const description = obj.description || '';
// // Handle special case with description that has markdown
// // Remove the most common zerowidth characters from the start of the file
// const description_cleaned: string = obj.description.replace(/^[\u200B\u200C\u200D\u200E\u200F\uFEFF]/,"");
// const description_md_html: null|string = marked.parse(description_cleaned ?? '') ?? null;
// // Add processed description
// obj.description_md_html = description_md_html;
if (limit >= 0) {
params['limit'] = limit;
}
// Handle special case with content that has markdown
// Remove the most common zerowidth characters from the start of the file
const has_content = obj.content !== undefined && obj.content !== null;
if (has_content) {
const content_cleaned: string = obj.content.replace(/^[\u200B\u200C\u200D\u200E\u200F\uFEFF]/,"");
const content_md_html: null|string = marked.parse(content_cleaned ?? '') ?? null;
// Add processed content
obj.content_md_html = content_md_html;
}
// Check which fields actually exist for this object
const has_group = obj.group !== undefined && obj.group !== null;
const has_priority = obj.priority !== undefined && obj.priority !== null;
const has_sort = obj.sort !== undefined && obj.sort !== null;
const has_created = obj.created_on !== undefined && obj.created_on !== null;
const has_updated = obj.updated_on !== undefined && obj.updated_on !== null;
const has_name = obj.name !== undefined && obj.name !== null;
// Generate standardized tmp_sort fields with proper zero-padding
const sort_str = sort?.toString().padStart(3, '0') ?? '000';
// Build dynamic sorting combinations based on what exists
let tmp_sort_1 = '';
let tmp_sort_2 = '';
let tmp_sort_3 = '';
// Build based on existing fields
if (has_group && has_priority && has_sort) {
tmp_sort_1 = `${group}_${priority}_${sort_str}`;
tmp_sort_2 = `${group}_${priority}_${sort_str}_${name || ''}`;
tmp_sort_3 = `${priority}_${sort_str}_${group}`;
} else if (has_priority && has_sort) {
tmp_sort_1 = `${priority}_${sort_str}`;
tmp_sort_2 = `${priority}_${sort_str}_${name || ''}`;
tmp_sort_3 = `${priority}_${sort_str}`;
} else if (has_sort) {
tmp_sort_1 = `${sort_str}`;
tmp_sort_2 = `${sort_str}_${name || ''}`;
tmp_sort_3 = `${sort_str}`;
} else {
// Fallback for minimal data
tmp_sort_1 = `${created_on || ''}`;
tmp_sort_2 = `${created_on || ''}_${name || ''}`;
tmp_sort_3 = `${updated_on || ''}`;
}
// Add time-based sorting for better ordering
if (has_created && has_updated) {
tmp_sort_1 += `_${created_on}_${updated_on}`;
tmp_sort_2 += `_${created_on}_${updated_on}`;
tmp_sort_3 += `_${updated_on}`;
} else if (has_created) {
tmp_sort_1 += `_${created_on}`;
tmp_sort_2 += `_${created_on}`;
tmp_sort_3 += `_${created_on}`;
}
// Return processed object with standardized fields
return {
...obj,
tmp_sort_1,
tmp_sort_2,
tmp_sort_3
};
const download_result = await api.get_object({
api_cfg: api_cfg,
endpoint: endpoint,
params: params,
timeout: 90000,
return_blob: return_file,
filename: clean_filename,
auto_download: auto_download,
task_id: for_obj_id,
log_lvl: log_lvl
});
if (log_lvl) {
console.log(`Processed objects:`, processed);
}
return processed;
if (log_lvl) console.log('download_result:', download_result);
return download_result;
}

View File

@@ -0,0 +1,112 @@
import { browser } from '$app/environment';
import type { key_val } from '$lib/stores/ae_stores';
import { api } from '$lib/api/api';
export interface Data_Store {
id: string;
account_id: string;
code: string;
name: string;
type: string;
for_type?: string | null;
for_id?: string | null;
access_read?: string | null;
access_write?: string | null;
access_delete?: string | null;
html?: string | null;
json?: key_val | null;
md?: string | null;
text?: string | null;
updated_on?: string | null;
chk_account_id?: string;
loaded_on?: string;
}
/**
* Fetches a data_store object by its unique code.
*
* @param api_cfg - The API configuration object.
* @param code - The code of the data store to fetch.
* @param data_type - The expected data type ('text', 'json', 'html', 'md', 'sql').
* @param save_idb - Whether to save the fetched data to localStorage.
* @param timeout - The request timeout in milliseconds.
* @param log_lvl - The logging level.
* @returns The data from the data store (e.g., text content or JSON object).
*/
export async function load_ae_obj_by_code__data_store({
api_cfg,
code,
data_type = 'text',
save_idb = false,
timeout = 9000,
log_lvl = 0
}: {
api_cfg: any;
code: string;
data_type?: string;
save_idb?: boolean;
timeout?: number;
log_lvl?: number;
}): Promise<any> {
if (log_lvl) {
console.log(`*** load_ae_obj_by_code__data_store() *** code=${code}`);
}
if (!code) {
console.log(`*ae_func* No code provided!`);
return null;
}
if (!api_cfg.account_id) {
console.log(`*ae_func* No account_id found in API config!`);
return null;
}
try {
const get_ds_result = await api.get_data_store_obj_w_code({
api_cfg: api_cfg,
data_store_code: code,
data_type: data_type,
timeout: timeout,
log_lvl: log_lvl
});
if (!get_ds_result) {
console.log('*ae_func* No results returned.');
return null;
}
if (log_lvl) {
console.log(`*ae_func* Got a result for code ${code}`);
}
if (!get_ds_result.data_store_id_random) {
console.log('*ae_func* Something went wrong? No data store ID found.');
return null;
}
let return_this: any = null;
// Simplified data extraction
if (data_type === 'html') {
return_this = get_ds_result.html;
} else if (data_type === 'json') {
return_this = get_ds_result.json;
} else {
return_this = get_ds_result.text;
}
if (save_idb && browser) {
const key_prefix = 'ae_ds__';
if (log_lvl) {
console.log(`*ae_func* localStorage key: ${code}, value:`, get_ds_result);
}
localStorage.setItem(`${key_prefix}${code}`, JSON.stringify(get_ds_result));
}
return return_this;
} catch (error) {
console.log('*ae_func* No results returned or failed.', error);
return null;
}
}

View File

@@ -1,92 +1,105 @@
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api';
import type { key_val } from '$lib/stores/ae_stores';
import { api } from '$lib/api/api';
import { db_core } from "$lib/ae_core/db_core";
let ae_promises: key_val = {};
import { db_core } from '$lib/ae_core/db_core';
const ae_promises: key_val = {};
// Updated 2024-06-14
export async function load_ae_obj_id__hosted_file(
{
api_cfg,
hosted_file_id,
try_cache = false,
log_lvl = 0
}: {
api_cfg: any,
hosted_file_id: string,
try_cache?: boolean,
log_lvl?: number
}
) {
export async function load_ae_obj_id__hosted_file({
api_cfg,
hosted_file_id,
try_cache = false,
log_lvl = 0
}: {
api_cfg: any;
hosted_file_id: string;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** load_ae_obj_id__hosted_file() *** hosted_file_id=${hosted_file_id}`);
}
let params = {};
const params = {};
ae_promises.load__hosted_file_obj = await api.get_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'hosted_file',
obj_id: hosted_file_id, // NOTE: This is the FQDN, not normally the ID.
use_alt_table: false, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value
params: params,
log_lvl: log_lvl
ae_promises.load__hosted_file_obj = await api
.get_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'hosted_file',
obj_id: hosted_file_id, // NOTE: This is the FQDN, not normally the ID.
use_alt_table: false, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value
params: params,
log_lvl: log_lvl
})
.then(function (hosted_file_obj_get_result) {
if (hosted_file_obj_get_result) {
// This is expecting a list
db_save_ae_obj_li__hosted_file({obj_type: 'hosted_file', obj_li: [hosted_file_obj_get_result]});
return hosted_file_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
.then(function (hosted_file_obj_get_result) {
if (hosted_file_obj_get_result) {
// This is expecting a list
db_save_ae_obj_li__hosted_file({
obj_type: 'hosted_file',
obj_li: [hosted_file_obj_get_result]
});
return hosted_file_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
return ae_promises.load__hosted_file_obj;
}
// Updated 2024-07-03
export async function load_ae_obj_li__hosted_file(
{
api_cfg,
for_obj_type,
for_obj_id,
enabled = 'enabled',
hidden = 'not_hidden',
limit = 99,
offset = 0,
order_by_li = {'priority': 'DESC', 'sort': 'DESC', 'updated_on': 'DESC', 'created_on': 'DESC'},
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
for_obj_type: string,
for_obj_id: string,
enabled?: string,
hidden?: string,
limit?: number,
offset?: number,
order_by_li?: key_val,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
export async function load_ae_obj_li__hosted_file({
api_cfg,
for_obj_type,
for_obj_id,
enabled = 'enabled',
hidden = 'not_hidden',
limit = 99,
offset = 0,
order_by_li = { priority: 'DESC', sort: 'DESC', updated_on: 'DESC', created_on: 'DESC' },
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
for_obj_type: string;
for_obj_id: string;
enabled?: 'enabled' | 'all' | 'not_enabled' | undefined;
hidden?: 'hidden' | 'all' | 'not_hidden' | undefined;
limit?: number;
offset?: number;
order_by_li?: key_val;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** load_ae_obj_li__hosted_file() *** for_obj_type=${for_obj_type} for_obj_id=${for_obj_id}`);
console.log(
`*** load_ae_obj_li__hosted_file() *** for_obj_type=${for_obj_type} for_obj_id=${for_obj_id}`
);
}
// Check if for_obj_type is in the list of valid Aether object types:
let valid_for_obj_types = ['account', 'archive', 'archive_content', 'event', 'event_session', 'event_presentation', 'event_presenter', 'event_location', 'journal', 'journal_entry', 'post', 'post_comment'];
const valid_for_obj_types = [
'account',
'archive',
'archive_content',
'event',
'event_session',
'event_presentation',
'event_presenter',
'event_location',
'journal',
'journal_entry',
'post',
'post_comment'
];
if (!valid_for_obj_types.includes(for_obj_type)) {
console.log(`Invalid for_obj_type: ${for_obj_type}`);
return [];
@@ -97,45 +110,46 @@ export async function load_ae_obj_li__hosted_file(
// let limit: number = (params.qry__limit ?? 99); // 99
// let offset: number = (params.qry__offset ?? 0); // 0
let params_json: key_val = {};
const params_json: key_val = {};
// console.log('params_json:', params_json);
ae_promises.load__hosted_file_obj_li = await api.get_ae_obj_li_for_obj_id_crud_v2({
api_cfg: api_cfg,
obj_type: 'hosted_file',
for_obj_type: for_obj_type,
for_obj_id: for_obj_id,
use_alt_tbl: false,
use_alt_mdl: false,
use_alt_exp: false,
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
ae_promises.load__hosted_file_obj_li = await api
.get_ae_obj_li_for_obj_id_crud_v2({
api_cfg: api_cfg,
obj_type: 'hosted_file',
for_obj_type: for_obj_type,
for_obj_id: for_obj_id,
use_alt_tbl: false,
use_alt_mdl: false,
use_alt_exp: false,
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
})
.then(function (hosted_file_obj_li_get_result) {
if (hosted_file_obj_li_get_result) {
if (try_cache) {
db_save_ae_obj_li__hosted_file({
obj_type: 'hosted_file',
obj_li: hosted_file_obj_li_get_result,
log_lvl: log_lvl
});
.then(function (hosted_file_obj_li_get_result) {
if (hosted_file_obj_li_get_result) {
if (try_cache) {
db_save_ae_obj_li__hosted_file({
obj_type: 'hosted_file',
obj_li: hosted_file_obj_li_get_result,
log_lvl: log_lvl
});
}
return hosted_file_obj_li_get_result;
} else {
console.log('No results returned.');
return [];
}
return hosted_file_obj_li_get_result;
} else {
console.log('No results returned.');
return [];
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
if (log_lvl) {
console.log('ae_promises.load__hosted_file_obj_li:', ae_promises.load__hosted_file_obj_li);
@@ -143,31 +157,28 @@ export async function load_ae_obj_li__hosted_file(
return ae_promises.load__hosted_file_obj_li;
}
// Updated 2024-11-07
export async function delete_ae_obj_id__hosted_file(
{
api_cfg,
hosted_file_id,
link_to_type, // Ideally this should be required...
link_to_id, // Ideally this should be required...
rm_orphan = false,
fake_delete = false, // Fake the delete result to "true"
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
hosted_file_id: string,
link_to_type: string,
link_to_id: string,
rm_orphan?: boolean,
fake_delete?: boolean,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
export async function delete_ae_obj_id__hosted_file({
api_cfg,
hosted_file_id,
link_to_type, // Ideally this should be required...
link_to_id, // Ideally this should be required...
rm_orphan = false,
fake_delete = false, // Fake the delete result to "true"
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
hosted_file_id: string;
link_to_type: string;
link_to_id: string;
rm_orphan?: boolean;
fake_delete?: boolean;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** delete_ae_obj_id__hosted_file() *** hosted_file_id=${hosted_file_id}`);
}
@@ -187,30 +198,33 @@ export async function delete_ae_obj_id__hosted_file(
return ae_promises.delete__hosted_file_obj;
}
ae_promises.delete__hosted_file_obj = await api.delete_object({
api_cfg: api_cfg,
endpoint: endpoint,
params: params,
// return_meta: return_meta,
log_lvl: log_lvl
})
.then(function (hosted_file_obj_li_get_result) {
if (hosted_file_obj_li_get_result) {
if (try_cache) {
if (log_lvl) {
console.log(`Attempting to remove IDB entry for hosted_file_id=${hosted_file_id}`);
ae_promises.delete__hosted_file_obj = await api
.delete_object({
api_cfg: api_cfg,
endpoint: endpoint,
params: params,
// return_meta: return_meta,
log_lvl: log_lvl
})
.then(function (hosted_file_obj_li_get_result) {
if (hosted_file_obj_li_get_result) {
if (try_cache) {
if (log_lvl) {
console.log(
`Attempting to remove IDB entry for hosted_file_id=${hosted_file_id}`
);
}
db_core.file.delete(hosted_file_id); // Delete from the DB no matter what.
}
db_core.file.delete(hosted_file_id); // Delete from the DB no matter what.
return hosted_file_obj_li_get_result;
} else {
console.log('No results returned.');
return [];
}
return hosted_file_obj_li_get_result;
} else {
console.log('No results returned.');
return [];
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
if (log_lvl) {
console.log('ae_promises.delete__hosted_file_obj:', ae_promises.delete__hosted_file_obj);
@@ -219,21 +233,17 @@ export async function delete_ae_obj_id__hosted_file(
return ae_promises.delete__hosted_file_obj;
}
// This function will loop through the hosted_file_obj_li and save each one to the DB.
// Updated 2025-01-07
export function db_save_ae_obj_li__hosted_file(
{
obj_type,
obj_li,
log_lvl = 0
}: {
obj_type: string,
obj_li: any,
log_lvl?: number
}
) {
export function db_save_ae_obj_li__hosted_file({
obj_type,
obj_li,
log_lvl = 0
}: {
obj_type: string;
obj_li: any;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** db_save_ae_obj_li__hosted_file() ***`);
}
@@ -274,11 +284,11 @@ export function db_save_ae_obj_li__hosted_file(
updated_on: obj.updated_on,
filename_no_ext: obj.filename_no_ext,
filename_w_ext: obj.filename_w_ext,
filename_w_ext: obj.filename_w_ext
});
// console.log(`Put obj with ID: ${obj.hosted_file_id_random} or ${id_random}`);
} catch (error) {
let status = `Failed to put ${obj.hosted_file_id_random}: ${error}`;
const status = `Failed to put ${obj.hosted_file_id_random}: ${error}`;
console.log(status);
}
@@ -291,21 +301,18 @@ export function db_save_ae_obj_li__hosted_file(
return false;
}
// Updated 2025-01-07
export function db_update_ae_obj_id__hosted_file(
{
obj_type,
obj_id,
data_kv,
log_lvl = 0
}: {
obj_type: string,
obj_id: string,
data_kv: key_val,
log_lvl?: number
}
) {
export function db_update_ae_obj_id__hosted_file({
obj_type,
obj_id,
data_kv,
log_lvl = 0
}: {
obj_type: string;
obj_id: string;
data_kv: key_val;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** db_update_ae_obj_id__hosted_file() ***`);
}
@@ -315,37 +322,35 @@ export function db_update_ae_obj_id__hosted_file(
try {
// db_core.file.update(obj_id, data_kv);
db_core.file.update(obj_id,
{
// for_type: data_kv.for_type,
// for_id: data_kv.for_id_id_random,
// for_id_random: data_kv.for_id_random,
db_core.file.update(obj_id, {
// for_type: data_kv.for_type,
// for_id: data_kv.for_id_id_random,
// for_id_random: data_kv.for_id_random,
filename: data_kv.filename,
extension: data_kv.extension,
content_type: data_kv.content_type,
size: data_kv.size,
filename: data_kv.filename,
extension: data_kv.extension,
content_type: data_kv.content_type,
size: data_kv.size,
// enable: data_kv.enable,
// hide: data_kv.hide,
// priority: data_kv.priority,
// sort: data_kv.sort,
// group: data_kv.group,
// notes: data_kv.notes,
// created_on: data_kv.created_on,
// updated_on: data_kv.updated_on,
// enable: data_kv.enable,
// hide: data_kv.hide,
// priority: data_kv.priority,
// sort: data_kv.sort,
// group: data_kv.group,
// notes: data_kv.notes,
// created_on: data_kv.created_on,
// updated_on: data_kv.updated_on,
filename_no_ext: data_kv.filename_no_ext,
filename_w_ext: data_kv.filename_w_ext,
// hosted_file_content_type: data_kv.hosted_file_content_type,
// file_size: data_kv.file_size,
// hosted_file_size: data_kv.hosted_file_size,
}
);
filename_no_ext: data_kv.filename_no_ext,
filename_w_ext: data_kv.filename_w_ext
// hosted_file_content_type: data_kv.hosted_file_content_type,
// file_size: data_kv.file_size,
// hosted_file_size: data_kv.hosted_file_size,
});
console.log(`Update obj with ID: ${obj_id}`);
} catch (error) {
let status = `Failed to update ${obj_id}: ${error}`;
const status = `Failed to update ${obj_id}: ${error}`;
console.log(status);
}

View File

@@ -1,91 +1,123 @@
import type { Dexie, Table } from 'dexie';
// This function will save an array of objects to a Dexie database table.
// It will first attempt to update existing records using bulkUpdate.
// If that fails, it will fall back to bulkPut.
// The function takes a database instance, table name, array of objects, and properties to save.
// It also accepts a log level for debugging purposes.
// Updated 2025-05-09
export async function db_save_ae_obj_li__ae_obj({
db_instance,
table_name,
obj_li,
properties_to_save,
log_lvl = 0,
}: {
db_instance: any; // The Dexie database instance
table_name: string; // The name of the table in the database
obj_li: any[];
properties_to_save: string[];
log_lvl?: number;
}) {
// log_lvl = 1;
if (log_lvl) {
console.log(`*** db_save_ae_obj_li__ae_obj() *** table_name=${table_name}`, obj_li);
/**
* Extracts the primary key from an object using a prioritized list of possible key names.
* @param obj The object to extract the ID from.
* @param table_name The name of the table, used to construct legacy key names.
* @param log_lvl The logging level.
* @returns The found ID, or undefined if no ID could be found.
*/
function find_object_id(
obj: any,
table_name: string,
log_lvl: number
): string | number | undefined {
const potential_keys = ['id', `${table_name}_id`, `${table_name}_id_random`];
for (const key of potential_keys) {
if (obj[key]) {
if (key !== 'id' && log_lvl > 0) {
console.warn(
`Found legacy ID key "${key}" for table "${table_name}". Consider standardizing to "id".`,
obj
);
}
return obj[key];
}
}
console.error(
`Object is missing a valid ID for table "${table_name}". It will be skipped.`,
obj
);
return undefined;
}
/**
* Saves an array of objects to a Dexie database table using bulkPut.
* This function handles both creating new records and updating existing ones.
*
* @param db_instance The Dexie database instance.
* @param table_name The name of the table in the database.
* @param obj_li The array of objects to save.
* @param properties_to_save The list of property names to include in the saved object.
* @param log_lvl The logging level for debugging.
* @returns A promise that resolves with the keys of the saved objects.
* @throws An error if the database operation fails.
*
* @version 2.0.0
* @since 2025-11-13
*/
export async function db_save_ae_obj_li__ae_obj<T extends Record<string, any>>({
db_instance,
table_name,
obj_li,
properties_to_save,
log_lvl = 0
}: {
db_instance: Dexie;
table_name: string;
obj_li: T[];
properties_to_save: (keyof T)[];
log_lvl?: number;
}) {
if (log_lvl > 0) {
console.log(
`*** db_save_ae_obj_li__ae_obj: Attempting to save ${obj_li.length} objects to table "${table_name}" ***`
);
}
if (!obj_li || obj_li.length === 0) {
if (log_lvl) {
console.log('No objects to save.');
}
if (log_lvl > 0) console.log('No objects to save.');
return [];
}
const db_table = db_instance[table_name];
const db_table: Table<T> = db_instance.table(table_name);
if (!db_table) {
console.error(`Table not found in ${db_instance}: ${table_name}`);
const error_msg = `Table not found in Dexie instance: ${table_name}`;
console.error(error_msg);
throw new Error(error_msg);
}
const data_to_save = obj_li
.map((obj) => {
const record: Partial<T> = {};
// Extract only the specified properties to save.
for (const prop of properties_to_save) {
record[prop] = obj[prop];
}
// Ensure the primary key is included, attempting to find it from various legacy keys.
const id = find_object_id(obj, table_name, log_lvl);
if (id === undefined) {
return null; // Skip objects without a valid ID.
}
const primary_key_name = db_table.schema.primKey.name;
(record as any)[primary_key_name] = id;
return record;
})
.filter(Boolean) as T[];
if (data_to_save.length === 0) {
if (log_lvl > 0) {
console.warn('All objects were skipped, likely due to missing IDs.');
}
return [];
}
const bulkUpdateData = [];
const bulkPutData = [];
for (const obj of obj_li) {
const obj_record: Record<string, any> = {};
// Extract only the specified properties to save
for (const prop of properties_to_save) {
obj_record[prop] = obj[prop];
}
// Ensure the `id` field is included
obj_record.id = obj_record.id || obj.id || obj[`${table_name}_id`] || obj[`${table_name}_id_random`];
if (!obj_record.id) {
console.error(`Object is missing an ID:`, obj);
continue;
}
// Prepare data for bulkUpdate or bulkPut
bulkUpdateData.push({
key: obj_record.id,
changes: obj_record,
});
bulkPutData.push(obj_record);
}
// Attempt bulkUpdate first
try {
const updatedKeys = await db_table.bulkUpdate(bulkUpdateData);
if (log_lvl) {
console.log(`Bulk update completed. Updated keys:`, updatedKeys);
// bulkPut efficiently handles both inserts and updates.
const keys = await db_table.bulkPut(data_to_save);
if (log_lvl > 0) {
console.log(`Successfully saved ${keys.length} objects to "${table_name}".`);
}
return keys;
} catch (error) {
// This is fairly common and normal if the object is new
if (log_lvl) {
console.log(`Bulk update failed. Falling back to bulkPut. This is normal.`, error);
}
console.error(`Failed to save objects to "${table_name}":`, error);
// Re-throw the error to let the caller handle it.
throw error;
}
// Use bulkPut for any records that couldn't be updated
try {
const putKeys = await db_table.bulkPut(bulkPutData);
if (log_lvl) {
console.log(`Bulk put completed. Put keys:`, putKeys);
}
return putKeys;
} catch (error) {
// This should not happen if the object is new
console.error(`Bulk put failed. Something likely went wrong!`, error);
return [];
}
}
}

View File

@@ -1,83 +1,81 @@
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api';
import type { key_val } from '$lib/stores/ae_stores';
import { api } from '$lib/api/api';
import { db_save_ae_obj_li__ae_obj } from "$lib/ae_core/core__idb_dexie";
import { db_core } from "$lib/ae_core/db_core";
let ae_promises: key_val = {};
import { db_save_ae_obj_li__ae_obj } from '$lib/ae_core/core__idb_dexie';
import { db_core } from '$lib/ae_core/db_core';
const ae_promises: key_val = {};
// Updated 2025-06-10
export async function load_ae_obj_id__person(
{
api_cfg,
person_id,
params = {},
try_cache = false,
log_lvl = 0
}: {
api_cfg: any,
person_id: string,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
export async function load_ae_obj_id__person({
api_cfg,
person_id,
params = {},
try_cache = false,
log_lvl = 0
}: {
api_cfg: any;
person_id: string;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** load_ae_obj_id__person() *** person_id=${person_id}`);
}
ae_promises.load__person_obj = await api.get_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'person',
obj_id: person_id,
use_alt_table: false,
use_alt_base: false,
params: params,
log_lvl: log_lvl
ae_promises.load__person_obj = await api
.get_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'person',
obj_id: person_id,
use_alt_table: false,
use_alt_base: false,
params: params,
log_lvl: log_lvl
})
.then(async function (person_obj_get_result) {
if (person_obj_get_result) {
if (try_cache) {
// Process the results first
let processed_obj_li = await process_ae_obj__person_props({
obj_li: [person_obj_get_result],
log_lvl: log_lvl,
.then(async function (person_obj_get_result) {
if (person_obj_get_result) {
if (try_cache) {
// Process the results first
const processed_obj_li = await process_ae_obj__person_props({
obj_li: [person_obj_get_result],
log_lvl: log_lvl
});
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
// Save the updated results list to the database
if (log_lvl) {
console.log('Saving to DB...');
}
await db_save_ae_obj_li__ae_obj({
db_instance: db_core,
table_name: 'person',
obj_li: processed_obj_li,
properties_to_save: properties_to_save,
log_lvl: log_lvl,
});
if (log_lvl) {
console.log('DB save completed.');
}
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
// Save the updated results list to the database
if (log_lvl) {
console.log('Saving to DB...');
}
await db_save_ae_obj_li__ae_obj({
db_instance: db_core,
table_name: 'person',
obj_li: processed_obj_li,
properties_to_save: properties_to_save,
log_lvl: log_lvl
});
if (log_lvl) {
console.log('DB save completed.');
}
// // This is expecting a list
// db_save_ae_obj_li__person({
// obj_type: 'person',
// obj_li: [person_obj_get_result],
// log_lvl: log_lvl
// });
// // This is expecting a list
// db_save_ae_obj_li__person({
// obj_type: 'person',
// obj_li: [person_obj_get_result],
// log_lvl: log_lvl
// });
}
return person_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
return person_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
if (log_lvl) {
console.log('ae_promises.load__person_obj:', ae_promises.load__person_obj);
@@ -86,61 +84,64 @@ export async function load_ae_obj_id__person(
return ae_promises.load__person_obj;
}
// Updated 2025-06-10
export async function load_ae_obj_li__person(
{
api_cfg,
for_obj_type = 'account',
for_obj_id,
qry_email = null,
qry_user_id = null,
enabled = 'enabled',
hidden = 'not_hidden',
limit = 99,
offset = 0,
order_by_li = {'family_name': 'ASC', 'given_name': 'ASC', 'updated_on': 'DESC', 'created_on': 'DESC'},
// params_json = {},
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
for_obj_type: string,
for_obj_id: string,
qry_email?: string|null,
qry_user_id?: string|null,
enabled?: string, // all, disabled, enabled
hidden?: string, // all, hidden, not_hidden
limit?: number,
offset?: number,
order_by_li?: key_val,
// params_json?: null|key_val,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
export async function load_ae_obj_li__person({
api_cfg,
for_obj_type = 'account',
for_obj_id,
qry_email = null,
qry_user_id = null,
enabled = 'enabled',
hidden = 'not_hidden',
limit = 99,
offset = 0,
order_by_li = [
{ family_name: 'ASC' },
{ given_name: 'ASC' },
{ updated_on: 'DESC' },
{ created_on: 'DESC' }
],
// params_json = {},
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
for_obj_type: string;
for_obj_id: string;
qry_email?: string | null;
qry_user_id?: string | null;
enabled?: 'enabled' | 'all' | 'not_enabled' | undefined; // all, disabled, enabled
hidden?: 'hidden' | 'all' | 'not_hidden' | undefined; // all, hidden, not_hidden
limit?: number;
offset?: number;
order_by_li?: { [key: string]: 'ASC' | 'DESC' }[] | null;
// params_json?: null|key_val,
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** load_ae_obj_li__person() *** for_obj_type=${for_obj_type} for_obj_id=${for_obj_id} enabled=${enabled} hidden=${hidden} limit=${limit} offset=${offset}`);
console.log(
`*** load_ae_obj_li__person() *** for_obj_type=${for_obj_type} for_obj_id=${for_obj_id} enabled=${enabled} hidden=${hidden} limit=${limit} offset=${offset}`
);
}
let params_json: key_val = {};
const params_json: key_val = {};
// console.log('params_json:', params_json);
if (qry_user_id) {
// params_json['and_qry'] = {};
// params_json['and_qry']['user_id_random'] = qry_user_id;
params_json['qry'] = []
params_json['qry'] = [];
let qry_param =
{
type: "AND",
field: "user_id_random",
operator: "=",
value: qry_user_id
};
const qry_param = {
type: 'AND',
field: 'user_id_random',
operator: '=',
value: qry_user_id
};
params_json['qry'].push(qry_param);
}
@@ -148,146 +149,144 @@ export async function load_ae_obj_li__person(
console.log('params_json:', params_json);
}
ae_promises.load__person_obj_li = await api.get_ae_obj_li_for_obj_id_crud_v2({
api_cfg: api_cfg,
obj_type: 'person',
for_obj_type: for_obj_type,
for_obj_id: for_obj_id,
use_alt_tbl: false,
use_alt_mdl: false,
use_alt_exp: false,
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
ae_promises.load__person_obj_li = await api
.get_ae_obj_li_for_obj_id_crud_v2({
api_cfg: api_cfg,
obj_type: 'person',
for_obj_type: for_obj_type,
for_obj_id: for_obj_id,
use_alt_tbl: false,
use_alt_mdl: false,
use_alt_exp: false,
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
})
.then(async function (person_obj_li_get_result) {
if (person_obj_li_get_result) {
if (try_cache) {
// Process the results first
let processed_obj_li = await process_ae_obj__person_props({
obj_li: person_obj_li_get_result,
log_lvl: log_lvl,
.then(async function (person_obj_li_get_result) {
if (person_obj_li_get_result) {
if (try_cache) {
// Process the results first
const processed_obj_li = await process_ae_obj__person_props({
obj_li: person_obj_li_get_result,
log_lvl: log_lvl
});
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
// Save the updated results list to the database
if (log_lvl) {
console.log('Saving to DB...');
}
await db_save_ae_obj_li__ae_obj({
db_instance: db_core,
table_name: 'person',
obj_li: processed_obj_li,
properties_to_save: properties_to_save,
log_lvl: log_lvl,
});
if (log_lvl) {
console.log('DB save completed.');
}
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
// Save the updated results list to the database
if (log_lvl) {
console.log('Saving to DB...');
}
await db_save_ae_obj_li__ae_obj({
db_instance: db_core,
table_name: 'person',
obj_li: processed_obj_li,
properties_to_save: properties_to_save,
log_lvl: log_lvl
});
if (log_lvl) {
console.log('DB save completed.');
}
// db_save_ae_obj_li__person({
// obj_type: 'person',
// obj_li: person_obj_li_get_result,
// log_lvl: log_lvl
// });
// db_save_ae_obj_li__person({
// obj_type: 'person',
// obj_li: person_obj_li_get_result,
// log_lvl: log_lvl
// });
}
return person_obj_li_get_result;
} else {
return [];
}
return person_obj_li_get_result;
} else {
return [];
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
console.log('ae_promises.load__person_obj_li:', ae_promises.load__person_obj_li);
return ae_promises.load__person_obj_li;
}
// Updated 2025-06-10
export async function create_ae_obj__person(
{
api_cfg,
user_id,
data_kv,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
user_id?: string,
data_kv: key_val,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
export async function create_ae_obj__person({
api_cfg,
user_id,
data_kv,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
user_id?: string;
data_kv: key_val;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** create_ae_obj__person() *** user_id=${user_id}`);
}
ae_promises.create__person = await api.create_ae_obj_crud({
api_cfg: api_cfg,
obj_type: 'person',
fields: {
user_id_random: user_id,
...data_kv
ae_promises.create__person = await api
.create_ae_obj_crud({
api_cfg: api_cfg,
obj_type: 'person',
fields: {
user_id_random: user_id,
...data_kv
},
key: api_cfg.api_crud_super_key,
params: params,
return_obj: true,
log_lvl: log_lvl
})
.then(async function (person_obj_create_result) {
if (person_obj_create_result) {
if (try_cache) {
// Process the results first
let processed_obj_li = await process_ae_obj__person_props({
obj_li: [person_obj_create_result],
log_lvl: log_lvl,
key: api_cfg.api_crud_super_key,
params: params,
return_obj: true,
log_lvl: log_lvl
})
.then(async function (person_obj_create_result) {
if (person_obj_create_result) {
if (try_cache) {
// Process the results first
const processed_obj_li = await process_ae_obj__person_props({
obj_li: [person_obj_create_result],
log_lvl: log_lvl
});
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
// Save the updated results list to the database
if (log_lvl) {
console.log('Saving to DB...');
}
await db_save_ae_obj_li__ae_obj({
db_instance: db_core,
table_name: 'person',
obj_li: processed_obj_li,
properties_to_save: properties_to_save,
log_lvl: log_lvl,
});
if (log_lvl) {
console.log('DB save completed.');
}
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
// Save the updated results list to the database
if (log_lvl) {
console.log('Saving to DB...');
}
await db_save_ae_obj_li__ae_obj({
db_instance: db_core,
table_name: 'person',
obj_li: processed_obj_li,
properties_to_save: properties_to_save,
log_lvl: log_lvl
});
if (log_lvl) {
console.log('DB save completed.');
}
// db_save_ae_obj_li__person(
// {
// obj_type: 'person',
// obj_li: [person_obj_create_result],
// log_lvl: log_lvl
// });
// db_save_ae_obj_li__person(
// {
// obj_type: 'person',
// obj_li: [person_obj_create_result],
// log_lvl: log_lvl
// });
}
return person_obj_create_result;
} else {
return null;
}
return person_obj_create_result;
} else {
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
})
.finally(function () {
});
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
})
.finally(function () {});
if (log_lvl) {
console.log('ae_promises.create__person:', ae_promises.create__person);
@@ -295,49 +294,47 @@ export async function create_ae_obj__person(
return ae_promises.create__person;
}
// Updated 2025-05-10
export async function delete_ae_obj_id__person(
{
api_cfg,
person_id,
method = 'delete', // 'delete', 'disable', 'hide'
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
person_id: string,
method?: string,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
export async function delete_ae_obj_id__person({
api_cfg,
person_id,
method = 'delete', // 'delete', 'disable', 'hide'
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
person_id: string;
method?: string;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** delete_ae_obj_id__person() *** person_id=${person_id}`);
}
ae_promises.delete__person_obj = await api.delete_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'person',
obj_id: person_id,
key: api_cfg.api_crud_super_key,
params: params,
method: method,
log_lvl: log_lvl
ae_promises.delete__person_obj = await api
.delete_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'person',
obj_id: person_id,
key: api_cfg.api_crud_super_key,
params: params,
method: method,
log_lvl: log_lvl
})
.catch(function (error) {
console.log('No results returned or failed.', error);
})
.finally(async function () {
if (try_cache) {
if (log_lvl) {
console.log(`Attempting to remove IDB entry for person_id=${person_id}`);
.catch(function (error: any) {
console.log('No results returned or failed.', error);
})
.finally(async function () {
if (try_cache) {
if (log_lvl) {
console.log(`Attempting to remove IDB entry for person_id=${person_id}`);
}
await db_core.person.delete(person_id);
}
await db_core.person.delete(person_id);
}
});
});
if (log_lvl) {
console.log('ae_promises.delete__person_obj:', ae_promises.delete__person_obj);
@@ -346,25 +343,22 @@ export async function delete_ae_obj_id__person(
return ae_promises.delete__person_obj;
}
// Updated 2025-06-10
export async function update_ae_obj__person(
{
api_cfg,
person_id,
data_kv,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
person_id: string,
data_kv: key_val,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
export async function update_ae_obj__person({
api_cfg,
person_id,
data_kv,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
person_id: string;
data_kv: key_val;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** update_ae_obj__person() *** person_id=${person_id}`, data_kv);
}
@@ -387,10 +381,10 @@ export async function update_ae_obj__person(
if (result) {
if (try_cache) {
// Process the results first
let processed_obj_li = await process_ae_obj__person_props({
const processed_obj_li = await process_ae_obj__person_props({
obj_li: [result],
log_lvl: log_lvl,
});
log_lvl: log_lvl
});
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
@@ -403,7 +397,7 @@ export async function update_ae_obj__person(
table_name: 'person',
obj_li: processed_obj_li,
properties_to_save: properties_to_save,
log_lvl: log_lvl,
log_lvl: log_lvl
});
if (log_lvl) {
console.log('DB save completed.');
@@ -422,19 +416,16 @@ export async function update_ae_obj__person(
}
}
// Updated 2024-06-10
export function db_save_ae_obj_li__person(
{
obj_type,
obj_li,
log_lvl = 0
}: {
obj_type: string,
obj_li: any,
log_lvl?: number
}
) {
export function db_save_ae_obj_li__person({
obj_type,
obj_li,
log_lvl = 0
}: {
obj_type: string;
obj_li: any;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** db_save_ae_obj_li__person() ***`);
}
@@ -445,7 +436,7 @@ export function db_save_ae_obj_li__person(
console.log(`ae_obj ${obj_type}:`, obj);
}
let obj_record = {
const obj_record = {
id: obj.person_id_random,
// id_random: obj.person_id_random,
person_id: obj.person_id_random,
@@ -509,7 +500,7 @@ export function db_save_ae_obj_li__person(
user_super: obj.user_super,
user_manager: obj.user_manager,
user_administrator: obj.user_administrator,
user_public: obj.user_public,
user_public: obj.user_public
};
let id_random = null;
@@ -546,26 +537,24 @@ export function db_save_ae_obj_li__person(
}
}
// Updated 2025-06-10
let properties_to_save = [
const properties_to_save = [
'id',
'person_id',
'person_id_random',
// 'person_id_random',
'external_id',
'external_sys_id',
'code',
'account_id',
'account_id_random',
// 'account_id_random',
'person_profile_id',
'person_profile_id_random', // The new table person_profile will be used soon...
// 'person_profile_id_random', // The new table person_profile will be used soon...
'user_id',
'user_id_random',
// 'user_id_random',
'pronouns',
'informal_name',
@@ -628,11 +617,11 @@ let properties_to_save = [
'user_public',
'organization_id',
'organization_id_random',
// 'organization_id_random',
'organization_name',
'contact_id',
'contact_id_random',
// 'contact_id_random',
'contact_name',
'contact_email',
'contact_cc_email',
@@ -644,151 +633,104 @@ let properties_to_save = [
'contact_phone_other',
'address_id',
'address_id_random',
// 'address_id_random',
'address_city',
'address_country_alpha_2_code', // contact_address_country_alpha_2_code
'address_country_alpha_2_code' // contact_address_country_alpha_2_code
];
// Updated 2025-06-10
export async function process_ae_obj__person_props(
{
// obj_type,
obj_li,
log_lvl = 0,
}: {
// obj_type: string;
obj_li: any[];
log_lvl?: number;
}
) {
if (log_lvl) {
console.log(`*** process_ae_obj__person_props() ***`, obj_li);
/**
* NON-EXPORTED LOCAL HELPER
* Processes a list of Aether objects by applying common and specific transformations.
*/
async function _process_generic_props<T extends Record<string, any>>({
obj_li,
obj_type,
log_lvl = 0,
specific_processor
}: {
obj_li: T[];
obj_type: string;
log_lvl?: number;
specific_processor?: (obj: T) => Promise<T> | T;
}): Promise<T[]> {
if (log_lvl > 0) {
console.log(
`*** _process_generic_props: Processing ${obj_li.length} objects of type "${obj_type}" ***`
);
}
if (!obj_li || obj_li.length === 0) {
if (log_lvl) {
console.log('No objects to process.');
}
if (log_lvl > 0) console.log('No objects to process.');
return [];
}
const processed_obj_li = [];
const processed_obj_li: T[] = [];
for (const obj of obj_li) {
// const processed_obj = { ...obj };
for (const original_obj of obj_li) {
let processed_obj = { ...original_obj };
// Process the properties as needed
// None needed to process for person at this time...
// --- Common Transformations ---
let processed_obj = {
id: obj.person_id_random,
person_id: obj.person_id_random,
person_id_random: obj.person_id_random,
// 1. Standardize ID and other '_random' fields
// The API often returns fields like 'person_id_random', which need to be aliased to 'person_id'.
for (const key in processed_obj) {
if (key.endsWith('_random')) {
const new_key = key.slice(0, -7); // Remove '_random' suffix
(processed_obj as any)[new_key] = processed_obj[key];
}
}
// Ensure 'id' is set from '[obj_type]_id_random'
const random_id_key = `${obj_type}_id_random`;
if (processed_obj[random_id_key]) {
(processed_obj as any).id = processed_obj[random_id_key];
}
external_id: obj.external_id,
external_sys_id: obj.external_sys_id,
code: obj.code,
// 2. Create common computed properties for client-side sorting.
const group = processed_obj.group ?? '0';
const priority = processed_obj.priority ? 1 : 0;
const sort = processed_obj.sort ?? '0';
const updated = processed_obj.updated_on ?? processed_obj.created_on;
const name = processed_obj.name ?? '';
account_id: obj.account_id_random,
account_id_random: obj.account_id_random,
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
person_profile_id: obj.person_profile_id_random,
person_profile_id_random: obj.person_profile_id_random, // The new table person_profile will be used soon...
// --- Specific Transformations ---
if (specific_processor) {
processed_obj = await Promise.resolve(specific_processor(processed_obj));
}
user_id: obj.user_id_random,
user_id_random: obj.user_id_random,
pronouns: obj.pronouns,
informal_name: obj.informal_name,
title_names: obj.title_names,
given_name: obj.given_name,
middle_name: obj.middle_name,
family_name: obj.family_name,
designations: obj.designations,
professional_title: obj.professional_title,
full_name: obj.full_name,
full_name_override: obj.full_name_override, // was display_name and display_name_override
affiliations: obj.affiliations,
primary_email: obj.primary_email,
biography: obj.biography,
agree: obj.agree,
comments: obj.comments,
allow_auth_key: obj.allow_auth_key, // For sign in without password
// auth_key: obj.auth_key,
passcode: obj.passcode,
// passcode_timeout: obj.passcode_timeout,
// This only allows for basic access to the data.
// passcode_read: obj.passcode_read, // For LLM (AI) generated summary...???
// passcode_read_expire: obj.passcode_read_expire,
// passcode_write: obj.passcode_write,
// passcode_write_expire: obj.passcode_write_expire,
// private_passcode: obj.private_passcode,
// alert: obj.alert,
// alert_msg: obj.alert_msg,
data_json: obj.data_json ?? {},
enable: obj.enable,
hide: obj.hide,
priority: obj.priority,
sort: obj.sort,
group: obj.group,
notes: obj.notes,
created_on: obj.created_on,
updated_on: obj.updated_on,
// Generated fields for sorting locally only
tmp_sort_1: `${obj.group ?? '0'}_${obj.priority ? 1 : 0}_${obj.sort ?? '0'}_${obj.updated_on}_${obj.created_on}`,
tmp_sort_2: `${obj.group ?? '0'}_${obj.priority ? 1 : 0}_${obj.sort ?? '0'}_${obj.updated_on ?? obj.created_on}`,
tmp_sort_3: `${obj.group ?? '0'}_${obj.priority ? 1 : 0}_${obj.sort ?? '0'}_${obj.name}_${obj.updated_on ?? obj.created_on}`,
// tmp_sort_1: `${obj.original_datetime}_${obj.group}_${obj.priority}_${obj.sort}`,
// tmp_sort_2: `${obj.group}_${obj.original_datetime}_${obj.priority}_${obj.sort}`,
// From SQL view
username: obj.username, // Same as user_username
user_name: obj.user_name,
user_email: obj.user_email,
user_allow_auth_key: obj.user_allow_auth_key, // For sign in without password
user_super: obj.user_super,
user_manager: obj.user_manager,
user_administrator: obj.user_administrator,
user_public: obj.user_public,
organization_id: obj.organization_id_random,
organization_id_random: obj.organization_id_random,
organization_name: obj.organization_name,
contact_id: obj.contact_id_random,
contact_id_random: obj.contact_id_random,
contact_name: obj.contact_name,
contact_email: obj.contact_email,
contact_cc_email: obj.contact_cc_email,
contact_phone_mobile: obj.contact_phone_mobile,
contact_phone_home: obj.contact_phone_home,
contact_phone_office: obj.contact_phone_office,
contact_phone_land: obj.contact_phone_land,
contact_phone_fax: obj.contact_phone_fax,
contact_phone_other: obj.contact_phone_other,
address_id: obj.contact_address_id_random,
address_id_random: obj.contact_address_id_random,
address_city: obj.contact_address_city,
address_country_alpha_2_code: obj.contact_address_country_alpha_2_code, // contact_address_country_alpha_2_code
};
processed_obj_li.push(processed_obj);
processed_obj_li.push(processed_obj as T);
}
return processed_obj_li;
}
// Updated 2025-06-10
export async function process_ae_obj__person_props({
obj_li,
log_lvl = 0
}: {
obj_li: any[];
log_lvl?: number;
}) {
return _process_generic_props({
obj_li,
obj_type: 'person',
log_lvl,
specific_processor: (obj) => {
// Person-specific computed sort fields, overriding generic ones if needed
obj.tmp_sort_1 = `${obj.group ?? '0'}_${obj.priority ? 1 : 0}_${
obj.sort ?? '0'
}_${obj.updated_on}_${obj.created_on}`;
obj.tmp_sort_2 = `${obj.group ?? '0'}_${obj.priority ? 1 : 0}_${
obj.sort ?? '0'
}_${obj.updated_on ?? obj.created_on}`;
obj.tmp_sort_3 = `${obj.group ?? '0'}_${obj.priority ? 1 : 0}_${
obj.sort ?? '0'
}_${obj.name ?? ''}_${obj.updated_on ?? obj.created_on}`;
return obj;
}
});
}

View File

@@ -1,52 +1,52 @@
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api';
import QRCode from 'qrcode';
import { db_core } from "$lib/ae_core/db_core";
import type { key_val } from '$lib/stores/ae_stores';
import { api } from '$lib/api/api';
let ae_promises: key_val = {};
import { db_core } from '$lib/ae_core/db_core';
const ae_promises: key_val = {};
// Updated 2024-07-18
export async function generate_qr_code(
{
api_cfg,
account_id,
qr_type, // mecard, obj, str, vcard
qr_id, // This is essentially the filename it can be found at /qr/{account_id}/{qr_id}
qr_data, // vcard fields:
obj_type,
obj_id,
str, // For encoding a string (like a URL) into a QR code.
return_blob=true, // blob or url?
try_cache=false,
log_lvl=0
}: {
api_cfg: any,
account_id: string,
qr_type: string,
qr_id: string,
qr_data?: any,
obj_type?: string,
obj_id?: string,
str?: string,
return_blob?: boolean,
try_cache?: boolean,
log_lvl?: number
}
) {
// I recently made significant updates to this with the help of Copilot. I think it is correct.
// Updated 2025-10-03
export async function generate_qr_code({
api_cfg,
account_id,
qr_type, // mecard, obj, str, vcard
qr_id, // This is essentially the filename it can be found at /qr/{account_id}/{qr_id}
qr_data, // vcard fields:
obj_type,
obj_id,
str, // For encoding a string (like a URL) into a QR code.
return_blob = true, // blob or url?
try_cache = false,
log_lvl = 0
}: {
api_cfg: any;
account_id: string;
qr_type: string;
qr_id: string;
qr_data?: any;
obj_type?: string;
obj_id?: string;
str?: string;
return_blob?: boolean;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** generate_qr_code() *** qr_id=${qr_id}`);
}
let endpoint = `/qr/${account_id}/${qr_id}`;
const endpoint = `/qr/${account_id}/${qr_id}`;
if (log_lvl) {
console.log('Endpoint', endpoint);
}
let params: key_val = {
'regen': true, // Regenerate the file even if nothing has changed.
'return_file': return_blob,
'qr_type': qr_type, // mecard, obj, vcard
'qr_send': return_blob
const params: key_val = {
regen: true, // Regenerate the file even if nothing has changed.
return_file: return_blob,
qr_type: qr_type, // mecard, obj, vcard
qr_send: return_blob
};
if (qr_type == 'vcard') {
@@ -56,16 +56,17 @@ export async function generate_qr_code(
params['n'] = `${qr_data.family_name};${qr_data.given_name}`;
}
params['fn'] = qr_data.full_name_override;
if (qr_data.affiliations) { params['org'] = qr_data.affiliations; }
// url
if (qr_data.affiliations) {
params['org'] = qr_data.affiliations;
}
params['email'] = qr_data.email;
if (qr_data.phone) { params['tel'] = qr_data.phone; }
if (qr_data.phone) {
params['tel'] = qr_data.phone;
}
params['adr'] = qr_data.location_override;
if (qr_data.address_line_1) { params['adr_str'] = qr_data.address_line_1; }
if (qr_data.address_line_1) {
params['adr_str'] = qr_data.address_line_1;
}
params['adr_loc'] = qr_data.city;
params['adr_reg'] = qr_data.state_province;
params['adr_postal'] = qr_data.postal_code;
@@ -81,35 +82,182 @@ export async function generate_qr_code(
console.log('Params', params);
}
const filename = null;
// let filename = `qr_${$ae_loc.account_id}_${qr_id}_${qr_type}.png`;
let filename = null;
// Await the API call
ae_promises.generate_qr_code = await api.get_object({
api_cfg: api_cfg,
endpoint: endpoint,
params: params,
return_blob: return_blob,
filename: filename,
auto_download: false,
log_lvl: log_lvl
});
console.log('QR code generated done!?');
api_cfg: api_cfg,
endpoint: endpoint,
params: params,
return_blob: return_blob,
filename: filename,
auto_download: false,
log_lvl: log_lvl
});
if (return_blob) {
let img_blob = new Blob([ae_promises.generate_qr_code.data]);
let img_obj_url = URL.createObjectURL(img_blob);
// console.log(img_obj_url);
// return img_blob;
return img_obj_url;
if (log_lvl) {
console.log('QR code API response:', ae_promises.generate_qr_code);
}
// let img_blob = new Blob([ae_promises.generate_qr_code.data]);
// console.log(img_blob);
// let img_obj_url = URL.createObjectURL(img_blob);
// console.log(img_obj_url);
// let qr_img_src = img_obj_url;
// If return_blob is true, ensure we return an object URL for use in <img src=...>
if (return_blob) {
const data = ae_promises.generate_qr_code.data ?? ae_promises.generate_qr_code;
// If already a Blob, use it directly
if (data instanceof Blob) {
return URL.createObjectURL(data);
}
// If it's a Response (from fetch), convert to Blob
if (data instanceof Response) {
const blob = await data.blob();
return URL.createObjectURL(blob);
}
// If it's an ArrayBuffer or Uint8Array, convert to Blob
if (data instanceof ArrayBuffer || data instanceof Uint8Array) {
const blob = new Blob([data], { type: 'image/png' });
return URL.createObjectURL(blob);
}
// If it's a base64 string, return as data URL
if (typeof data === 'string' && data.startsWith('data:image')) {
return data;
}
// If it's a raw string (base64), convert to data URL
if (typeof data === 'string') {
return `data:image/png;base64,${data}`;
}
// Fallback: try to create a Blob from whatever is left
try {
const blob = new Blob([data], { type: 'image/png' });
return URL.createObjectURL(blob);
} catch (e) {
if (log_lvl) console.error('Could not create QR code image blob:', e, data);
return null;
}
}
// If not returning a blob, return the raw API response
return ae_promises.generate_qr_code;
}
}
// Updated 2025-10-09
/**
* Generates a QR code image as a Base64 data URL based on provided parameters.
*
* NOTE: This function handles the data formatting and QR generation,
* but does NOT handle server-side logic like file saving, disk path checks,
* or database lookups (like redis_lookup_id_random).
*
* @param {string} qr_type - The type of data format ('mecard', 'vcard', 'obj', 'kv', 'js', 'str').
* @param {Object} params - An object containing all necessary query parameters (n, fn, url, email, etc.).
* @param {string} qr_id - A unique ID (unused in pure client-side generation, but kept for context).
* @returns {Promise<string>} A promise that resolves to a Base64 data URL of the QR code image.
* @throws {Error} If the qr_type is unknown or data is missing.
*/
export async function js_generate_qr_code(qr_type, params = {}) {
const {
n = '',
fn = '',
org = '',
url = '',
email = '',
tel = '',
adr_poa = '',
adr_ext = '',
adr_str = '',
adr_loc = '',
adr_reg = '',
adr_postal = '',
adr_country = '',
obj_type,
obj_id,
key,
val,
js,
str
} = params;
console.log(`*** js_generate_qr_code() *** qr_type=${qr_type}`, params);
let qr_data = null;
// --- 1. Replicate Data Formatting Logic ---
switch (qr_type) {
case 'mecard':
// Format: MECARD:N:name;EMAIL:email;ADR:address;;
// Note: The original Python code had adr, but we'll use n and email as a minimum.
qr_data = `MECARD:N:${n};EMAIL:${email};;`;
// You can enhance this with other MeCard fields if needed.
break;
case 'vcard':
// Format: BEGIN:VCARD...END:VCARD
qr_data = `BEGIN:VCARD\nVERSION:3.0\nN:${n}\nFN:${fn}\nORG:${org}\nEMAIL:${email}\n`;
if (url) {
qr_data += `URL:${url}\n`;
}
if (tel) {
qr_data += `TEL:${tel}\n`;
}
if (adr_loc) {
// ADR format: TYPE=postal:Po box;Ext;Street;Locality;Region;Postal code;Country
qr_data += `ADR:${adr_poa};${adr_ext};${adr_str};${adr_loc};${adr_reg};${adr_postal};${adr_country}\n`;
}
qrData += 'END:VCARD';
break;
case 'obj':
// Custom format: OBJ:ot:obj_type,oi:obj_id
if (!obj_type || !obj_id) throw new Error('Missing obj_type or obj_id for type "obj".');
qr_data = `OBJ:ot:${obj_type},oi:${obj_id}`;
break;
case 'kv':
// Custom format: KV:k:"key",v:"val"
if (!key || !val) throw new Error('Missing key or val for type "kv".');
qr_data = `KV:k:"${key}",v:"${val}"`;
break;
case 'js':
// Assumes 'js' is a stringified JSON object
if (!js) throw new Error('Missing js string for type "js".');
qr_data = `JS:${js}`;
break;
case 'str':
// Raw string data
if (!str) throw new Error('Missing raw string data for type "str".');
qr_data = str;
break;
default:
throw new Error(`Unknown QR type: ${qr_type}`);
}
if (!qr_data) {
throw new Error('Failed to create QR code data string.');
}
// --- 2. Generate QR Code Image ---
try {
// Options match the Python 'qrcode' library defaults closely:
// error_correction = qrcode.constants.ERROR_CORRECT_M
// box_size = 10, border = 1
const data_url = await QRCode.toDataURL(qr_data, {
errorCorrectionLevel: 'M',
margin: 1, // Corresponds to border
scale: 10, // Corresponds to box_size
type: 'image/png'
});
console.log('Generated QR code data URL:', data_url);
return data_url;
} catch (error) {
console.error('Error generating QR code:', error);
throw new Error('Could not generate QR code image.');
}
}

View File

@@ -0,0 +1,50 @@
export interface Site {
id: string;
// id_random: string;
site_id: string;
site_id_random?: string;
code?: string;
account_id: string;
account_id_random?: string;
name: string;
description?: null | string;
restrict_access?: null | boolean;
access_key?: null | string;
access_code_kv_json?: null | string;
logo_path?: null | string;
logo_bg_color?: null | string; // Not really used currently.
// background_image_path?: null|string; // Legacy field
// background_bg_color?: null|string; // Legacy field
title?: null | string;
// header_html?: null|string; // Legacy field
// header_css?: null|string; // Legacy field
// header_image_path?: null|string; // Legacy field
// header_image_bg_color?: null|string; // Legacy field
// body_html?: null|string; // Legacy field
tagline?: null | string;
// site_header_h1?: null|string; // Legacy field
// site_header_h2?: null|string; // Legacy field
style_href?: null | string; // Legacy field
// script_src?: null|string; // Legacy field
google_tracking_id?: null | string;
cfg_json?: null | string; // key value config json
enable: null | boolean;
enable_from?: null | Date;
enable_to?: null | Date;
hide?: null | boolean;
priority?: null | boolean;
sort?: null | number;
group?: null | string;
notes?: null | string;
created_on: Date;
updated_on?: null | Date;
}

View File

@@ -0,0 +1,75 @@
export interface Site_Domain {
id: string;
// id_random: string;
site_id: string;
site_id_random?: string;
fqdn: string;
access_key?: null | string;
required_referrer?: null | string;
valid_for?: null | number; // In hours
enable: null | boolean;
hide?: null | boolean;
priority?: null | boolean;
sort?: null | number;
group?: null | string;
notes?: null | string;
created_on: Date;
updated_on?: null | Date;
}
import { api } from '$lib/api/api';
/**
* Fetches a site_domain object by its Fully Qualified Domain Name (FQDN).
*
* @param api_cfg - The API configuration object.
* @param fqdn - The FQDN of the site domain to fetch.
* @param timeout - The request timeout in milliseconds.
* @param log_lvl - The logging level.
* @returns The site domain object or null if not found.
*/
export async function load_ae_obj_by_fqdn__site_domain({
api_cfg,
fqdn,
timeout = 7000,
log_lvl = 0
}: {
api_cfg: any;
fqdn: string;
timeout?: number;
log_lvl?: number;
}): Promise<any> {
if (log_lvl) {
console.log(
`*** load_ae_obj_by_fqdn__site_domain() *** api.base_url=${api_cfg.base_url}, fqdn=${fqdn}, timeout=${timeout}`
);
}
const params = {};
try {
const site_domain_obj = await api.get_ae_obj_id_crud({
api_cfg: api_cfg,
no_account_id: true, // This seems to be a special case for this endpoint
obj_type: 'site_domain',
obj_id: fqdn, // NOTE: This is the FQDN, not the ID.
use_alt_table: true,
use_alt_base: true,
params: params,
timeout: timeout,
log_lvl: log_lvl
});
if (site_domain_obj) {
return site_domain_obj;
} else {
console.log('No results returned.');
return null;
}
} catch (error) {
console.log('No results returned or failed.', error);
return null;
}
}

View File

@@ -1,73 +1,71 @@
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api';
import type { key_val } from '$lib/stores/ae_stores';
import { api } from '$lib/api/api';
import { db_core } from "$lib/ae_core/db_core";
let ae_promises: key_val = {};
import { db_core } from '$lib/ae_core/db_core';
const ae_promises: key_val = {};
// Updated 2024-10-14
export async function load_ae_obj_li__time_zone(
{
api_cfg,
// account_id,
enabled = 'enabled',
hidden = 'not_hidden',
limit = 99,
offset = 0,
// order_by_li = {'priority': 'DESC', 'group': 'ASC', 'sort': 'DESC', 'name': 'ASC'},
order_by_li = {'priority': 'DESC', 'sort': 'DESC', 'name': 'ASC'},
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
// account_id: string,
enabled?: string,
hidden?: string,
limit?: number,
offset?: number,
order_by_li?: key_val,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
export async function load_ae_obj_li__time_zone({
api_cfg,
// account_id,
enabled = 'enabled',
hidden = 'not_hidden',
limit = 99,
offset = 0,
// order_by_li = {'priority': 'DESC', 'group': 'ASC', 'sort': 'DESC', 'name': 'ASC'},
order_by_li = { priority: 'DESC', sort: 'DESC', name: 'ASC' },
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
// account_id: string,
enabled?: 'enabled' | 'all' | 'not_enabled' | undefined;
hidden?: 'hidden' | 'all' | 'not_hidden' | undefined;
limit?: number;
offset?: number;
order_by_li?: key_val;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** load_ae_obj_li__time_zone() ***`);
}
let params_json: key_val = {};
const params_json: key_val = {};
// console.log('params_json:', params_json);
ae_promises.load__time_zone_li = await api.get_ae_obj_li_for_obj_id_crud_v2({
api_cfg: api_cfg,
obj_type: 'lu',
for_obj_type: 'time_zone',
// for_obj_id: account_id,
use_alt_tbl: true, // NOTE: Using this with the time zones to use the view named "v_lu_time_zone_cust"
use_alt_mdl: false,
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
ae_promises.load__time_zone_li = await api
.get_ae_obj_li_for_obj_id_crud_v2({
api_cfg: api_cfg,
obj_type: 'lu',
for_obj_type: 'time_zone',
// for_obj_id: account_id,
use_alt_tbl: true, // NOTE: Using this with the time zones to use the view named "v_lu_time_zone_cust"
use_alt_mdl: false,
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
})
.then(function (time_zone_li_get_result) {
if (time_zone_li_get_result) {
// handle_db_save_ae_obj_li__time_zone({obj_type: 'time_zone', obj_li: time_zone_li_get_result});
return time_zone_li_get_result;
} else {
return [];
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
.then(function (time_zone_li_get_result) {
if (time_zone_li_get_result) {
// handle_db_save_ae_obj_li__time_zone({obj_type: 'time_zone', obj_li: time_zone_li_get_result});
return time_zone_li_get_result;
} else {
return [];
}
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
console.log('ae_promises.load__time_zone_li:', ae_promises.load__time_zone_li);
return ae_promises.load__time_zone_li;

View File

@@ -1,38 +1,37 @@
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api';
import type { key_val } from '$lib/stores/ae_stores';
import { api } from '$lib/api/api';
import { db_core } from "$lib/ae_core/db_core";
let ae_promises: key_val = {};
import { db_core } from '$lib/ae_core/db_core';
const ae_promises: key_val = {};
// Updated 2025-04-04
export async function auth_ae_obj__username_password(
{
api_cfg,
account_id,
null_account_id = false,
username,
password,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
account_id: string,
null_account_id?: boolean,
username: string,
password: string,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
export async function auth_ae_obj__username_password({
api_cfg,
account_id,
null_account_id = false,
username,
password,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
account_id: string;
null_account_id?: boolean;
username: string;
password: string;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** auth_ae_obj__username_password() *** account_id=${account_id} username=${username} password=${password}`);
console.log(
`*** auth_ae_obj__username_password() *** account_id=${account_id} username=${username} password=${password}`
);
}
let endpoint = '/user/authenticate';
const endpoint = '/user/authenticate';
if (null_account_id) {
params['null_account_id'] = true;
@@ -43,34 +42,33 @@ export async function auth_ae_obj__username_password(
console.log(`auth_ae_obj__username_password() - params:`, params);
}
ae_promises.auth__username_password = await api.get_object({
api_cfg: api_cfg,
endpoint: endpoint,
params: params,
// data: {},
log_lvl: log_lvl
ae_promises.auth__username_password = await api
.get_object({
api_cfg: api_cfg,
endpoint: endpoint,
params: params,
// data: {},
log_lvl: log_lvl
})
.then(async function (user_obj_get_result) {
if (user_obj_get_result) {
// if (try_cache) {
// // This is expecting a list
// db_save_ae_obj_li__user({
// obj_type: 'user',
// obj_li: [user_obj_get_result],
// log_lvl: log_lvl
// });
// }
return user_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
.then(async function (user_obj_get_result) {
if (user_obj_get_result) {
// if (try_cache) {
// // This is expecting a list
// db_save_ae_obj_li__user({
// obj_type: 'user',
// obj_li: [user_obj_get_result],
// log_lvl: log_lvl
// });
// }
return user_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
if (log_lvl) {
console.log('ae_promises.auth__username_password:', ae_promises.auth__username_password);
@@ -78,32 +76,31 @@ export async function auth_ae_obj__username_password(
return ae_promises.auth__username_password;
}
// Updated 2025-04-04
export async function auth_ae_obj__user_id_user_auth_key(
{
api_cfg,
account_id,
user_id,
user_auth_key,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
account_id: string,
user_id: string,
user_auth_key: string,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
export async function auth_ae_obj__user_id_user_auth_key({
api_cfg,
account_id,
user_id,
user_auth_key,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
account_id: string;
user_id: string;
user_auth_key: string;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** auth_ae_obj__user_id_user_auth_key() *** account_id=${account_id} user_id=${user_id}`);
console.log(
`*** auth_ae_obj__user_id_user_auth_key() *** account_id=${account_id} user_id=${user_id}`
);
}
let endpoint = '/user/authenticate';
const endpoint = '/user/authenticate';
params['user_id'] = user_id; // Required
params['auth_key'] = user_auth_key; // Required
@@ -111,23 +108,24 @@ export async function auth_ae_obj__user_id_user_auth_key(
console.log(`auth_ae_obj__user_id_user_auth_key() - params:`, params);
}
ae_promises.auth__user_id_user_key = await api.get_object({
api_cfg: api_cfg,
endpoint: endpoint,
params: params,
log_lvl: log_lvl
ae_promises.auth__user_id_user_key = await api
.get_object({
api_cfg: api_cfg,
endpoint: endpoint,
params: params,
log_lvl: log_lvl
})
.then(async function (user_obj_get_result) {
if (user_obj_get_result) {
return user_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
.then(async function (user_obj_get_result) {
if (user_obj_get_result) {
return user_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
if (log_lvl) {
console.log('ae_promises.auth__user_id_user_key:', ae_promises.auth__user_id_user_key);
@@ -135,42 +133,41 @@ export async function auth_ae_obj__user_id_user_auth_key(
return ae_promises.auth__user_id_user_key;
}
// Send an email to the user with a new one time use authentication key. The new key must be generated and returned first.
// Updated 2025-04-08
export async function send_email_auth_ae_obj__user_id(
{
api_cfg,
account_id,
user_id,
base_url,
key_param_name = 'user_key', // API defaults to 'auth_key'
params = {},
// try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
account_id: string,
user_id: string,
base_url?: string,
key_param_name?: string,
params?: key_val,
// try_cache?: boolean,
log_lvl?: number
}
) {
export async function send_email_auth_ae_obj__user_id({
api_cfg,
account_id,
user_id,
base_url,
key_param_name = 'user_key', // API defaults to 'auth_key'
params = {},
// try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
account_id: string;
user_id: string;
base_url?: string;
key_param_name?: string;
params?: key_val;
// try_cache?: boolean,
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** send_email_auth_ae_obj__user_id() *** account_id=${account_id} user_id=${user_id}`);
console.log(
`*** send_email_auth_ae_obj__user_id() *** account_id=${account_id} user_id=${user_id}`
);
}
if (log_lvl > 1) {
console.log(api_cfg);
}
let email_auth_key_endpoint = `user/${user_id}/email_auth_key_url`;
const email_auth_key_endpoint = `user/${user_id}/email_auth_key_url`;
params = {
'root_url': base_url,
'key_param_name': key_param_name
}
root_url: base_url,
key_param_name: key_param_name
};
ae_promises.auth_key__send_email = await api.get_object({
api_cfg: api_cfg,
endpoint: email_auth_key_endpoint,
@@ -212,7 +209,7 @@ export async function send_email_auth_ae_obj__user_id(
// return null;
// }
// })
// .catch(function (error) {
// .catch(function (error: any) {
// console.log('No results returned or failed.', error);
// });
@@ -224,30 +221,28 @@ export async function send_email_auth_ae_obj__user_id(
// Look up user based on email address provided
// Updated 2025-04-08
export async function qry_ae_obj_li__user_email(
{
api_cfg,
account_id,
null_account_id = false,
email,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
account_id: string,
null_account_id?: boolean,
email: string,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
export async function qry_ae_obj_li__user_email({
api_cfg,
account_id,
null_account_id = false,
email,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
account_id: string;
null_account_id?: boolean;
email: string;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** qry_ae_obj_li__user_email() *** account_id=${account_id} email=${email}`);
}
let endpoint = '/user/lookup_email';
const endpoint = '/user/lookup_email';
params['email'] = email; // Required
params['null_account_id'] = null_account_id || false;
@@ -255,23 +250,24 @@ export async function qry_ae_obj_li__user_email(
console.log(`qry_ae_obj_li__user_email() - params:`, params);
}
ae_promises.qry__user_email = await api.get_object({
api_cfg: api_cfg,
endpoint: endpoint,
params: params,
log_lvl: log_lvl
ae_promises.qry__user_email = await api
.get_object({
api_cfg: api_cfg,
endpoint: endpoint,
params: params,
log_lvl: log_lvl
})
.then(async function (user_obj_get_result) {
if (user_obj_get_result) {
return user_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
.then(async function (user_obj_get_result) {
if (user_obj_get_result) {
return user_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
if (log_lvl) {
console.log('ae_promises.qry__user_email:', ae_promises.qry__user_email);
@@ -279,58 +275,58 @@ export async function qry_ae_obj_li__user_email(
return ae_promises.qry__user_email;
}
// Change user password
// endpoint: PATCH /user/{user_id}/change_password
// params:
// data_kv: password (the new password)
// Updated 2025-04-11
export async function auth_ae_obj__user_id_change_password(
{
api_cfg,
account_id,
user_id,
password,
params = {},
log_lvl = 0
}: {
api_cfg: any,
account_id: string,
user_id: string,
password: string,
params?: key_val,
log_lvl?: number
}
) {
export async function auth_ae_obj__user_id_change_password({
api_cfg,
account_id,
user_id,
password,
params = {},
log_lvl = 0
}: {
api_cfg: any;
account_id: string;
user_id: string;
password: string;
params?: key_val;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** auth_ae_obj__user_id_change_password() *** account_id=${account_id} user_id=${user_id}`);
console.log(
`*** auth_ae_obj__user_id_change_password() *** account_id=${account_id} user_id=${user_id}`
);
}
let endpoint = `/user/${user_id}/change_password`;
const endpoint = `/user/${user_id}/change_password`;
params['user_id'] = user_id; // Required
if (log_lvl > 1) {
console.log(`auth_ae_obj__user_id_change_password() - params:`, params);
}
ae_promises.change_password__user_id = await api.patch_object({
api_cfg: api_cfg,
endpoint: endpoint,
params: params,
data: { password: password },
log_lvl: log_lvl
ae_promises.change_password__user_id = await api
.patch_object({
api_cfg: api_cfg,
endpoint: endpoint,
params: params,
data: { password: password },
log_lvl: log_lvl
})
.then(async function (change_password_result) {
if (change_password_result) {
return change_password_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
.then(async function (change_password_result) {
if (change_password_result) {
return change_password_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
if (log_lvl) {
console.log('ae_promises.change_password__user_id:', ae_promises.change_password__user_id);

View File

@@ -23,21 +23,20 @@ export interface File {
content_type: string;
size: number; // In bytes
enable: null|boolean;
hide?: null|boolean;
priority?: null|boolean
sort?: null|number;
group?: null|string;
notes?: null|string;
enable: null | boolean;
hide?: null | boolean;
priority?: null | boolean;
sort?: null | number;
group?: null | string;
notes?: null | string;
created_on: Date;
updated_on?: null|Date;
updated_on?: null | Date;
// Additional fields for convenience (database views)
filename_no_ext: string;
filename_w_ext: string;
}
// Updated 2024-07-17
export interface Person {
id: string;
@@ -52,88 +51,87 @@ export interface Person {
account_id?: string; // Technically this is not required for global users.
account_id_random?: string; // Technically this is not required for global users.
person_profile_id?: null|string;
person_profile_id_random?: null|string; // The new table person_profile will be used soon...
person_profile_id?: null | string;
person_profile_id_random?: null | string; // The new table person_profile will be used soon...
user_id?: string;
user_id_random?: string;
pronouns?: null|string;
informal_name?: null|string;
title_names?: null|string;
pronouns?: null | string;
informal_name?: null | string;
title_names?: null | string;
given_name: string;
middle_name?: null|string;
family_name: null|string;
designations?: null|string;
middle_name?: null | string;
family_name: null | string;
designations?: null | string;
professional_title?: null|string;
professional_title?: null | string;
full_name?: string;
full_name_override?: null|string; // was called display_name
full_name_override?: null | string; // was called display_name
affiliations?: null|string;
affiliations?: null | string;
primary_email?: string;
biography?: null|string;
biography?: null | string;
agree?: null|boolean;
comments?: null|string;
agree?: null | boolean;
comments?: null | string;
allow_auth_key?: null|boolean; // For sign in without password
auth_key?: null|string; // Should this be saved locally?
passcode?: null|string;
allow_auth_key?: null | boolean; // For sign in without password
auth_key?: null | string; // Should this be saved locally?
passcode?: null | string;
data_json?: null|string;
data_json?: null | string;
enable: null|boolean;
hide?: null|boolean;
priority?: null|boolean
sort?: null|number;
group?: null|string;
notes?: null|string;
enable: null | boolean;
hide?: null | boolean;
priority?: null | boolean;
sort?: null | number;
group?: null | string;
notes?: null | string;
created_on: Date;
updated_on?: null|Date;
updated_on?: null | Date;
// Generated fields for sorting locally only
tmp_sort_1?: null|string;
tmp_sort_2?: null|string;
tmp_sort_3?: null|string;
tmp_sort_1?: null | string;
tmp_sort_2?: null | string;
tmp_sort_3?: null | string;
// Additional fields for convenience (database views)
username?: string; // Same as user_username
// user_username?: null|string; // Same as username
user_name?: null|string;
user_email?: null|string;
user_allow_auth_key?: null|boolean; // For sign in without password
user_name?: null | string;
user_email?: null | string;
user_allow_auth_key?: null | boolean; // For sign in without password
user_super?: boolean;
user_manager?: boolean;
user_administrator?: boolean;
user_public?: boolean;
organization_id?: null|string; // The organization this person belongs to, if any.
organization_id_random?: null|string; // The random ID of the organization this person belongs to, if any.
organization_name?: null|string;
organization_id?: null | string; // The organization this person belongs to, if any.
organization_id_random?: null | string; // The random ID of the organization this person belongs to, if any.
organization_name?: null | string;
contact_id?: null|string; // The contact ID of the person, if any.
contact_id_random?: null|string; // The random ID of the contact, if any.
contact_name?: null|string;
contact_email?: null|string;
contact_cc_email?: null|string;
contact_phone_mobile?: null|string;
contact_phone_home?: null|string;
contact_phone_office?: null|string;
contact_phone_landline?: null|string;
contact_phone_fax?: null|string;
contact_phone_other?: null|string;
contact_id?: null | string; // The contact ID of the person, if any.
contact_id_random?: null | string; // The random ID of the contact, if any.
contact_name?: null | string;
contact_email?: null | string;
contact_cc_email?: null | string;
contact_phone_mobile?: null | string;
contact_phone_home?: null | string;
contact_phone_office?: null | string;
contact_phone_landline?: null | string;
contact_phone_fax?: null | string;
contact_phone_other?: null | string;
address_id?: null|string; // The address ID of the person, if any.
address_id_random?: null|string; // The random ID of the address, if any.
address_city?: null|string;
address_country_alpha_2_code?: null|string; // ISO 3166-1 alpha-2 country code
address_id?: null | string; // The address ID of the person, if any.
address_id_random?: null | string; // The random ID of the address, if any.
address_city?: null | string;
address_country_alpha_2_code?: null | string; // ISO 3166-1 alpha-2 country code
}
// Updated 2025-01-07
export class MySubClassedDexie extends Dexie {
file!: Table<File>;
@@ -162,9 +160,9 @@ export class MySubClassedDexie extends Dexie {
given_name, family_name,
full_name, affiliations, email,
agree,
enable, hide, priority, sort, group, created_on, updated_on`,
enable, hide, priority, sort, group, created_on, updated_on`
});
}
}
export const db_core = new MySubClassedDexie();
export const db_core = new MySubClassedDexie();

View File

@@ -0,0 +1,50 @@
export const editable_fields = [
'code',
'conference',
'type',
'name',
'summary',
'description',
'start_datetime',
'end_datetime',
'timezone',
'location_address_json',
'location_text',
'attend_json',
'attend_text',
'status',
'mod_abstracts_json',
'mod_badges_json',
'mod_exhibits_json',
'mod_meetings_json',
'mod_pres_mgmt_json',
'cfg_json',
'enable',
'hide',
'priority',
'sort',
'group',
'notes',
'contact_li_json',
'external_person_id',
'physical',
'virtual',
'recurring',
'recurring_pattern',
'recurring_start_time',
'recurring_end_time',
'recurring_text',
'weekday_sunday',
'weekday_monday',
'weekday_tuesday',
'weekday_wednesday',
'weekday_thursday',
'weekday_friday',
'weekday_saturday',
'attend_url',
'attend_url_text',
'attend_url_code',
'attend_url_passcode',
'attend_phone',
'attend_phone_passcode'
];

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,549 @@
import type { key_val } from '$lib/stores/ae_stores';
import { api } from '$lib/api/api';
import { db_save_ae_obj_li__ae_obj } from '$lib/ae_core/core__idb_dexie';
import { db_events } from '$lib/ae_events/db_events';
const ae_promises: key_val = {};
// --- PROPERTIES TO SAVE ---
export const properties_to_save = [
'id',
'event_badge_template_id',
// 'event_badge_template_id_random',
'event_id',
// 'event_id_random',
'name',
'description',
// 'template_code',
// 'template_type',
// 'template_json',
// 'template_svg',
// 'template_css',
// 'template_html',
'logo_filename',
'logo_path',
'header_path',
'secondary_header_path',
'footer_path',
'header_row_1',
'header_row_2',
// 'footer_title',
// 'footer_left',
// 'footer_right',
// 'header_background',
// 'footer_background',
'badge_type_list',
'ticket_list',
'ticket_1_text',
'ticket_2_text',
'ticket_3_text',
'ticket_4_text',
'ticket_5_text',
'ticket_6_text',
'ticket_7_text',
'ticket_8_text',
// 'ticket_9_text',
// 'ticket_10_text',
'wireless_ssid',
'wireless_password',
'show_qr_front',
'show_qr_back',
'layout',
'style_filename',
// 'style_href',
// 'default',
'enable',
'hide',
'priority',
'sort',
'group',
'notes',
'created_on',
'updated_on',
// Generated fields for sorting locally only
'tmp_sort_1',
'tmp_sort_2'
];
/**
* NON-EXPORTED LOCAL HELPER
* Processes a list of Aether objects by applying common and specific transformations.
*/
async function _process_generic_props<T extends Record<string, any>>({
obj_li,
obj_type,
log_lvl = 0,
specific_processor
}: {
obj_li: T[];
obj_type: string;
log_lvl?: number;
specific_processor?: (obj: T) => Promise<T> | T;
}): Promise<T[]> {
if (log_lvl > 0) {
console.log(
`*** _process_generic_props: Processing ${obj_li.length} objects of type "${obj_type}" ***`
);
}
if (!obj_li || obj_li.length === 0) {
if (log_lvl > 0) console.log('No objects to process.');
return [];
}
const processed_obj_li: T[] = [];
for (const original_obj of obj_li) {
let processed_obj = { ...original_obj };
// --- Common Transformations ---
// 1. Standardize ID and other '_random' fields
// The API often returns fields like 'person_id_random', which need to be aliased to 'person_id'.
for (const key in processed_obj) {
if (key.endsWith('_random')) {
const newKey = key.slice(0, -7); // Remove '_random' suffix
processed_obj[newKey] = processed_obj[key];
}
}
// Ensure 'id' is set from '[obj_type]_id_random'
const randomIdKey = `${obj_type}_id_random`;
if (processed_obj[randomIdKey]) {
(processed_obj as any).id = processed_obj[randomIdKey];
}
// 2. Create common computed properties for client-side sorting.
const group = processed_obj.group ?? '0';
const priority = processed_obj.priority ? 1 : 0;
const sort = processed_obj.sort ?? '0';
const updated = processed_obj.updated_on ?? processed_obj.created_on;
const name = processed_obj.name ?? '';
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
// --- Specific Transformations ---
if (specific_processor) {
processed_obj = await Promise.resolve(specific_processor(processed_obj));
}
processed_obj_li.push(processed_obj as T);
}
return processed_obj_li;
}
// --- PROCESS FUNCTION ---
export async function process_ae_obj__event_badge_template_props({
obj_li,
log_lvl = 0
}: {
obj_li: any[];
log_lvl?: number;
}) {
return _process_generic_props({
obj_li,
obj_type: 'event_badge_template',
log_lvl,
specific_processor: (obj) => {
// Event badge template-specific computed sort fields, overriding generic ones if needed
obj.tmp_sort_1 = `${obj.group ?? ''}_${obj.priority ? '1' : '0'}_${
obj.sort?.toString().padStart(3, '0') ?? ''
}_${obj.updated_on ?? obj.created_on}`;
obj.tmp_sort_2 = `${obj.group ?? ''}_${obj.priority ? '1' : '0'}_${
obj.sort?.toString().padStart(3, '0') ?? ''
}_${obj.updated_on}_${obj.created_on}`;
return obj;
}
});
}
// --- CRUD FUNCTIONS ---
export async function load_ae_obj_id__event_badge_template({
api_cfg,
event_badge_template_id,
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
event_badge_template_id: string;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(
`*** load_ae_obj_id__event_badge_template() *** event_badge_template_id=${event_badge_template_id}`
);
}
const params = {};
ae_promises.load__event_badge_template_obj = await api
.get_ae_obj_id_crud({
api_cfg,
obj_type: 'event_badge_template',
obj_id: event_badge_template_id,
use_alt_table: false,
use_alt_base: false,
params,
log_lvl
})
.then(async function (obj_get_result) {
if (obj_get_result) {
if (try_cache) {
const processed_obj_li = await process_ae_obj__event_badge_template_props({
obj_li: [obj_get_result],
log_lvl
});
await db_save_ae_obj_li__ae_obj({
db_instance: db_events,
table_name: 'badge_template',
obj_li: processed_obj_li,
properties_to_save,
log_lvl
});
}
return obj_get_result;
} else {
if (log_lvl) console.log('No results returned.');
return null;
}
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
return ae_promises.load__event_badge_template_obj;
}
export async function load_ae_obj_li__event_badge_template({
api_cfg,
event_id,
enabled = 'enabled',
hidden = 'not_hidden',
limit = 49,
offset = 0,
order_by_li = { priority: 'DESC', sort: 'DESC', updated_on: 'DESC', created_on: 'DESC' },
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
event_id: string;
enabled?: 'enabled' | 'all' | 'not_enabled' | undefined;
hidden?: 'hidden' | 'all' | 'not_hidden' | undefined;
limit?: number;
offset?: number;
order_by_li?: key_val;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** load_ae_obj_li__event_badge_template() *** event_id=${event_id}`);
}
const params_json: key_val = {};
// ae_promises.load__event_badge_template_obj_li = await api.get_ae_obj_li_for_obj_id_crud({
ae_promises.load__event_badge_template_obj_li = await api
.get_ae_obj_li_for_obj_id_crud_v2({
api_cfg,
obj_type: 'event_badge_template',
for_obj_type: 'event',
for_obj_id: event_id,
use_alt_tbl: false,
use_alt_mdl: false,
enabled,
hidden,
order_by_li,
limit,
offset,
params_json,
params,
log_lvl
})
.then(async function (obj_li_get_result) {
if (obj_li_get_result) {
if (try_cache) {
const processed_obj_li = await process_ae_obj__event_badge_template_props({
obj_li: obj_li_get_result,
log_lvl
});
await db_save_ae_obj_li__ae_obj({
db_instance: db_events,
table_name: 'badge_template',
obj_li: processed_obj_li,
properties_to_save,
log_lvl
});
}
return obj_li_get_result;
} else {
return [];
}
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
return ae_promises.load__event_badge_template_obj_li;
}
export async function create_ae_obj__event_badge_template({
api_cfg,
event_id,
data_kv,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
event_id: string;
data_kv: key_val;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** create_ae_obj__event_badge_template() *** event_id=${event_id}`);
}
ae_promises.create__event_badge_template = await api
.create_ae_obj_crud({
api_cfg,
obj_type: 'event_badge_template',
fields: {
event_id_random: event_id,
...data_kv
},
key: api_cfg.api_crud_super_key,
params,
return_obj: true,
log_lvl
})
.then(async function (obj_create_result) {
if (obj_create_result) {
if (try_cache) {
const processed_obj_li = await process_ae_obj__event_badge_template_props({
obj_li: [obj_create_result],
log_lvl
});
db_save_ae_obj_li__ae_obj({
db_instance: db_events,
table_name: 'badge_template',
obj_li: processed_obj_li,
properties_to_save,
log_lvl
});
}
return obj_create_result;
} else {
return null;
}
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
return ae_promises.create__event_badge_template;
}
export async function delete_ae_obj_id__event_badge_template({
api_cfg,
event_badge_template_id,
method = 'delete',
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
event_badge_template_id: string;
method?: string;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(
`*** delete_ae_obj_id__event_badge_template() *** event_badge_template_id=${event_badge_template_id}`
);
}
ae_promises.delete__event_badge_template_obj = await api
.delete_ae_obj_id_crud({
api_cfg,
obj_type: 'event_badge_template',
obj_id: event_badge_template_id,
key: api_cfg.api_crud_super_key,
params,
method,
log_lvl
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
})
.finally(function () {
if (try_cache) {
if (log_lvl) {
console.log(
`Attempting to remove IDB entry for event_badge_template_id=${event_badge_template_id}`
);
}
db_events.badge_template.delete(event_badge_template_id);
}
});
return ae_promises.delete__event_badge_template_obj;
}
export async function update_ae_obj__event_badge_template({
api_cfg,
event_badge_template_id,
data_kv,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
event_badge_template_id: string;
data_kv: key_val;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(
`*** update_ae_obj__event_badge_template() *** event_badge_template_id=${event_badge_template_id}`
);
}
ae_promises.update__event_badge_template_obj = await api
.update_ae_obj_id_crud({
api_cfg,
obj_type: 'event_badge_template',
obj_id: event_badge_template_id,
fields: data_kv,
key: api_cfg.api_crud_super_key,
params,
return_obj: true,
log_lvl
})
.then(async function (obj_update_result) {
if (obj_update_result) {
if (try_cache) {
const processed_obj_li = await process_ae_obj__event_badge_template_props({
obj_li: [obj_update_result],
log_lvl
});
db_save_ae_obj_li__ae_obj({
db_instance: db_events,
table_name: 'badge_template',
obj_li: processed_obj_li,
properties_to_save,
log_lvl
});
}
return obj_update_result;
} else {
return null;
}
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
return ae_promises.update__event_badge_template_obj;
}
// --- SEARCH FUNCTION ---
export async function search__event_badge_template({
api_cfg,
event_id,
fulltext_search_qry_str,
like_search_qry_str = null,
enabled = 'enabled',
hidden = 'not_hidden',
limit = 25,
offset = 0,
order_by_li = {
priority: 'DESC',
sort: 'DESC',
name: 'ASC',
updated_on: 'DESC',
created_on: 'DESC'
},
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
event_id: string;
fulltext_search_qry_str?: null | string;
like_search_qry_str?: null | string;
enabled?: 'enabled' | 'all' | 'not_enabled' | undefined;
hidden?: 'hidden' | 'all' | 'not_hidden' | undefined;
limit?: number;
offset?: number;
order_by_li?: key_val;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** search__event_badge_template() *** event_id=${event_id}`);
}
const params_json: key_val = {};
if (fulltext_search_qry_str && fulltext_search_qry_str.length > 2) {
params_json['ft_qry'] = { default_qry_str: fulltext_search_qry_str };
}
if (like_search_qry_str && like_search_qry_str.length > 2) {
params_json['and_like'] = { default_qry_str: like_search_qry_str };
}
params_json['and_qry'] = {};
// ae_promises.search__event_badge_template_obj_li = await api.get_ae_obj_li_for_obj_id_crud({
ae_promises.load__event_badge_template_obj_li = await api
.get_ae_obj_li_for_obj_id_crud_v2({
api_cfg,
obj_type: 'event_badge_template',
for_obj_type: 'event',
for_obj_id: event_id,
use_alt_tbl: false,
use_alt_mdl: false,
enabled,
hidden,
order_by_li,
limit,
offset,
params_json,
params,
log_lvl
})
.then(async function (obj_li_get_result) {
if (obj_li_get_result) {
if (try_cache) {
const processed_obj_li = await process_ae_obj__event_badge_template_props({
obj_li: obj_li_get_result,
log_lvl
});
await db_save_ae_obj_li__ae_obj({
db_instance: db_events,
table_name: 'badge_template',
obj_li: processed_obj_li,
properties_to_save,
log_lvl
});
}
return obj_li_get_result;
} else {
return [];
}
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
return ae_promises.search__event_badge_template_obj_li;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,34 +1,36 @@
// This file is used to export all the functions that are used for Aether Events related functions.
// Import all the functions from this library:
import * as event from "$lib/ae_events/ae_events__event";
import * as event_device from "$lib/ae_events/ae_events__event_device";
import * as event from '$lib/ae_events/ae_events__event';
import * as event_device from '$lib/ae_events/ae_events__event_device';
import * as event_file from "$lib/ae_events/ae_events__event_file";
import * as event_file from '$lib/ae_events/ae_events__event_file';
import {
handle_load_ae_obj_id__exhibit,
handle_load_ae_obj_li__exhibit,
handle_load_ae_obj_id__exhibit_tracking,
handle_load_ae_obj_li__exhibit_tracking,
handle_create_ae_obj__exhibit_tracking,
handle_update_ae_obj__exhibit_tracking,
handle_download_export__event_exhibit_tracking,
handle_db_save_ae_obj_li__exhibitor,
} from "$lib/ae_events/ae_events__exhibit";
load_ae_obj_id__exhibit,
load_ae_obj_li__exhibit,
load_ae_obj_id__exhibit_tracking,
load_ae_obj_li__exhibit_tracking,
create_ae_obj__exhibit_tracking,
update_ae_obj__exhibit_tracking,
download_export__event_exhibit_tracking
// db_save_ae_obj_li__exhibitor,
} from '$lib/ae_events/ae_events__exhibit';
import * as event_location from "$lib/ae_events/ae_events__event_location";
import * as event_location from '$lib/ae_events/ae_events__event_location';
import * as event_session from "$lib/ae_events/ae_events__event_session";
import * as event_session from '$lib/ae_events/ae_events__event_session';
import * as event_presentation from "$lib/ae_events/ae_events__event_presentation";
import * as event_presentation from '$lib/ae_events/ae_events__event_presentation';
import * as event_presenter from "$lib/ae_events/ae_events__event_presenter";
import * as event_presenter from '$lib/ae_events/ae_events__event_presenter';
import * as event_badge from "$lib/ae_events/ae_events__event_badge";
import * as event_badge from '$lib/ae_events/ae_events__event_badge';
import * as event_badge_template from '$lib/ae_events/ae_events__event_badge_template';
let export_obj = {
const export_obj = {
// Events
load_ae_obj_id__event: event.load_ae_obj_id__event,
load_ae_obj_li__event: event.load_ae_obj_li__event,
qry_ae_obj_li__event: event.qry_ae_obj_li__event,
@@ -38,6 +40,29 @@ let export_obj = {
// db_save_ae_obj_li__event: event.db_save_ae_obj_li__event,
sync_config__event_pres_mgmt: event.sync_config__event_pres_mgmt,
// Event Badges
load_ae_obj_id__event_badge: event_badge.load_ae_obj_id__event_badge,
load_ae_obj_li__event_badge: event_badge.load_ae_obj_li__event_badge,
create_ae_obj__event_badge: event_badge.create_ae_obj__event_badge,
delete_ae_obj_id__event_badge: event_badge.delete_ae_obj_id__event_badge,
update_ae_obj__event_badge: event_badge.update_ae_obj__event_badge,
qry__event_badge: event_badge.qry__event_badge,
search__event_badge: event_badge.search__event_badge,
// handle_load_ae_obj_id__badge: event_badge.handle_load_ae_obj_id__badge,
// handle_load_ae_obj_li__badge: event_badge.handle_load_ae_obj_li__badge,
// handle_search__event_badge: event_badge.handle_search__event_badge,
// db_save_ae_obj_li__event_badge: event_badge.db_save_ae_obj_li__event_badge,
// Event Badge Templates
load_ae_obj_id__event_badge_template: event_badge_template.load_ae_obj_id__event_badge_template,
load_ae_obj_li__event_badge_template: event_badge_template.load_ae_obj_li__event_badge_template,
create_ae_obj__event_badge_template: event_badge_template.create_ae_obj__event_badge_template,
delete_ae_obj_id__event_badge_template:
event_badge_template.delete_ae_obj_id__event_badge_template,
update_ae_obj__event_badge_template: event_badge_template.update_ae_obj__event_badge_template,
search__event_badge_template: event_badge_template.search__event_badge_template,
// Event Devices
load_ae_obj_id__event_device: event_device.load_ae_obj_id__event_device,
load_ae_obj_li__event_device: event_device.load_ae_obj_li__event_device,
create_ae_obj__event_device: event_device.create_ae_obj__event_device,
@@ -45,15 +70,28 @@ let export_obj = {
update_ae_obj__event_device: event_device.update_ae_obj__event_device,
// db_save_ae_obj_li__event_device: event_device.db_save_ae_obj_li__event_device,
// Event Exhibits
handle_load_ae_obj_id__exhibit: load_ae_obj_id__exhibit,
handle_load_ae_obj_li__exhibit: load_ae_obj_li__exhibit,
handle_load_ae_obj_id__exhibit_tracking: load_ae_obj_id__exhibit_tracking,
handle_load_ae_obj_li__exhibit_tracking: load_ae_obj_li__exhibit_tracking,
handle_create_ae_obj__exhibit_tracking: create_ae_obj__exhibit_tracking,
handle_update_ae_obj__exhibit_tracking: update_ae_obj__exhibit_tracking,
handle_download_export__event_exhibit_tracking: download_export__event_exhibit_tracking,
// handle_db_save_ae_obj_li__exhibitor: db_save_ae_obj_li__exhibitor,
// Event Files
load_ae_obj_id__event_file: event_file.load_ae_obj_id__event_file,
load_ae_obj_li__event_file: event_file.load_ae_obj_li__event_file,
create_event_file_obj_from_hosted_file_async: event_file.create_event_file_obj_from_hosted_file_async,
create_event_file_obj_from_hosted_file_async:
event_file.create_event_file_obj_from_hosted_file_async,
delete_ae_obj_id__event_file: event_file.delete_ae_obj_id__event_file,
update_ae_obj__event_file: event_file.update_ae_obj__event_file,
qry__event_file: event_file.qry__event_file,
search__event_file: event_file.search__event_file,
// db_save_ae_obj_li__event_file: event_file.db_save_ae_obj_li__event_file,
// Event Locations
load_ae_obj_id__event_location: event_location.load_ae_obj_id__event_location,
load_ae_obj_li__event_location: event_location.load_ae_obj_li__event_location,
create_ae_obj__event_location: event_location.create_ae_obj__event_location,
@@ -61,6 +99,7 @@ let export_obj = {
update_ae_obj__event_location: event_location.update_ae_obj__event_location,
// db_save_ae_obj_li__event_location: event_location.db_save_ae_obj_li__event_location,
// Event Sessions
load_ae_obj_id__event_session: event_session.load_ae_obj_id__event_session,
load_ae_obj_li__event_session: event_session.load_ae_obj_li__event_session,
create_ae_obj__event_session: event_session.create_ae_obj__event_session,
@@ -71,6 +110,7 @@ let export_obj = {
email_sign_in__event_session: event_session.email_sign_in__event_session,
// db_save_ae_obj_li__event_session: event_session.db_save_ae_obj_li__event_session,
// Event Presentations
load_ae_obj_id__event_presentation: event_presentation.load_ae_obj_id__event_presentation,
load_ae_obj_li__event_presentation: event_presentation.load_ae_obj_li__event_presentation,
create_ae_obj__event_presentation: event_presentation.create_ae_obj__event_presentation,
@@ -78,6 +118,7 @@ let export_obj = {
update_ae_obj__event_presentation: event_presentation.update_ae_obj__event_presentation,
// db_save_ae_obj_li__event_presentation: event_presentation.db_save_ae_obj_li__event_presentation,
// Event Presenters
load_ae_obj_id__event_presenter: event_presenter.load_ae_obj_id__event_presenter,
load_ae_obj_li__event_presenter: event_presenter.load_ae_obj_li__event_presenter,
create_ae_obj__event_presenter: event_presenter.create_ae_obj__event_presenter,
@@ -85,20 +126,6 @@ let export_obj = {
update_ae_obj__event_presenter: event_presenter.update_ae_obj__event_presenter,
search__event_presenter: event_presenter.search__event_presenter,
// db_save_ae_obj_li__event_presenter: event_presenter.db_save_ae_obj_li__event_presenter,
email_sign_in__event_presenter: event_presenter.email_sign_in__event_presenter,
handle_load_ae_obj_id__badge: event_badge.handle_load_ae_obj_id__badge,
handle_load_ae_obj_li__badge: event_badge.handle_load_ae_obj_li__badge,
handle_search__event_badge: event_badge.handle_search__event_badge,
// handle_db_save_ae_obj_li__badge: event_badge.handle_db_save_ae_obj_li__badge,
handle_load_ae_obj_id__exhibit: handle_load_ae_obj_id__exhibit,
handle_load_ae_obj_li__exhibit: handle_load_ae_obj_li__exhibit,
handle_load_ae_obj_id__exhibit_tracking: handle_load_ae_obj_id__exhibit_tracking,
handle_load_ae_obj_li__exhibit_tracking: handle_load_ae_obj_li__exhibit_tracking,
handle_create_ae_obj__exhibit_tracking: handle_create_ae_obj__exhibit_tracking,
handle_update_ae_obj__exhibit_tracking: handle_update_ae_obj__exhibit_tracking,
handle_download_export__event_exhibit_tracking: handle_download_export__event_exhibit_tracking,
// handle_db_save_ae_obj_li__exhibitor: handle_db_save_ae_obj_li__exhibitor,
email_sign_in__event_presenter: event_presenter.email_sign_in__event_presenter
};
export let events_func = export_obj;
export const events_func = export_obj;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,9 @@
// This file is used to export all the functions that are used for Aether Journals related functions.
import * as journal from "$lib/ae_journals/ae_journals__journal";
import * as journal_entry from "$lib/ae_journals/ae_journals__journal_entry";
import * as journal from '$lib/ae_journals/ae_journals__journal';
import * as journal_entry from '$lib/ae_journals/ae_journals__journal_entry';
let export_obj = {
const export_obj = {
load_ae_obj_id__journal: journal.load_ae_obj_id__journal,
load_ae_obj_li__journal: journal.load_ae_obj_li__journal,
create_ae_obj__journal: journal.create_ae_obj__journal,
@@ -16,7 +15,7 @@ let export_obj = {
create_ae_obj__journal_entry: journal_entry.create_ae_obj__journal_entry,
delete_ae_obj_id__journal_entry: journal_entry.delete_ae_obj_id__journal_entry,
update_ae_obj__journal_entry: journal_entry.update_ae_obj__journal_entry,
qry__journal_entry: journal_entry.qry__journal_entry,
qry__journal_entry: journal_entry.qry__journal_entry
// db_save_ae_obj_li__journal_entry: journal_entry.db_save_ae_obj_li__journal_entry,
};
export let journals_func = export_obj;
export const journals_func = export_obj;

View File

@@ -3,21 +3,24 @@ import { persisted } from 'svelte-persisted-store';
import { writable } from 'svelte/store';
import type { Writable } from 'svelte/store';
import type { key_val } from '$lib/ae_stores';
import type { key_val } from '$lib/stores/ae_stores';
/* *** BEGIN *** Initialize journals_local_data_struct */
// This is for longer term or sticky app data. This should be stored to *local* storage.
// Updated 2025-03-20
let journals_local_data_struct: key_val = {
const journals_local_data_struct: key_val = {
ver: '2024-08-20_19',
// Shared
name: 'Aether - Journals (SvelteKit 2.x Svelte 4.x)',
name: 'Aether - Journals (SvelteKit 2.x Svelte 5.x)',
title: `OSIT's Æ Journals`, // &AElig;
mode__edit: false,
mode__debug: false,
datetime_format: 'datetime_12_long',
time_format: 'time_12_short',
time_hours: 12, // 12 or 24
qry__enabled: 'enabled', // all, disabled, enabled
qry__hidden: 'not_hidden', // all, hidden, not_hidden
qry__limit: 20,
@@ -28,6 +31,29 @@ let journals_local_data_struct: key_val = {
qry__offset: 0,
qry__journal_id: null,
journal_view_history_li: [], // Appended each time the journal is loaded.
entry_view_history_li: [], // NO LONGER USED: Appended each time the entry is loaded.
entry_view_history_kv: {}, // Keyed by journal_entry_id for quick lookup.
entry_view_history_max: 15, // Maximum number of journal entries to keep in history.
llm__api_base_url: 'https://ai.dgrzone.com/api',
llm__api_model: 'dgrzone-deepseek-8b-quick',
llm__api_token:
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVhYjI2MzdlLThiMjktNGM2Zi05MzVhLWFkYjU1MDkwMGU5MCJ9.VObfR91GrX3j1vHbHZqGsOWEyrL981cbSWWjaXfYbUQ',
llm__api_dangerous_browser: false, // This allows for use of localhost.
llm__stream: false, // Whether to use streaming or not. Not all APIs support this.
llm__timeout_ms: 60000, // 60 seconds
llm__max_retries: 3, // Number of times to retry a failed LLM API call.
llm__retry_delay_ms: 2000, // 2 seconds between retries.
llm__system_prompt: 'You are a helpful assistant that helps people find information.',
llm__max_tokens: 1024,
llm__temperature: 0.7,
llm__top_p: 1.0,
llm__n: 1,
llm__frequency_penalty: 0.0,
llm__presence_penalty: 0.0,
journal: {
edit: false,
edit_kv: {},
@@ -41,27 +67,37 @@ let journals_local_data_struct: key_val = {
{ code: 'professional', name: 'Professional' },
{ code: 'tracking', name: 'Tracking' },
{ code: 'other', name: 'Other' },
{ code: 'test', name: 'Test' },
{ code: 'test', name: 'Test' }
// { code: 'notepad', name: 'Notepad' },
],
]
},
entry: {
edit: false,
edit_kv: {},
},
llm__system_prompt:
'Summarize the following journal entry content in a concise manner, focusing on key points and insights.',
llm__max_tokens: 512,
llm__temperature: 0.7,
llm__top_p: 1.0,
llm__n: 1,
llm__frequency_penalty: 0.0,
llm__presence_penalty: 0.0,
edit: false,
edit_kv: {}
}
};
// console.log(`AE Stores - App Journals Local Storage Data:`, journals_local_data_struct);
// This works and uses *local* storage:
export let journals_loc: Writable<key_val> = persisted('ae_journals_loc', journals_local_data_struct);
export const journals_loc: Writable<key_val> = persisted(
'ae_journals_loc',
journals_local_data_struct
);
// console.log(`AE Stores - App Local Storage Data:`, get(ae_loc));
/* *** BEGIN *** Initialize journals_session_data_struct */
// Temporary app data. This is lost if the page is refreshed or using different tabs/windows. This should be stored to *session* storage.
// Updated 2025-03-20
let journals_session_data_struct: key_val = {
const journals_session_data_struct: key_val = {
ver: '2024-08-20_19',
log_lvl: 1,
@@ -70,6 +106,8 @@ let journals_session_data_struct: key_val = {
trigger__journal_id: null,
// trigger__journal_li: null,
show__modal__journals_config: false,
show__modal_edit__journal_obj: false,
show__modal_new__journal_obj: false,
show__modal_view__journal_id: null,
@@ -77,8 +115,6 @@ let journals_session_data_struct: key_val = {
show__modal_view__journal_entry_id: null,
show__modal_edit__journal_entry_id: null,
show__modal_edit__journal_obj: false,
show__content__journal_entry_history: false,
journal: {
@@ -88,63 +124,62 @@ let journals_session_data_struct: key_val = {
new_journal_name: '',
new_journal_type_code: '',
tmp_obj: {},
tmp_obj: {}
},
entry: {
show__ai_summary: false,
ai_summary: '',
decrypt_kv: {}, // Essentially flag that the entry (content and history) can be decrypted.
edit: false,
edit_kv: {},
tmp_obj: {},
tmp_obj: {}
},
journal_kv: {
// journal_id: {},
},
}
};
// console.log(`AE Stores - App Journals Session Storage Data:`, journals_session_data_struct);
export let journals_sess = writable(journals_session_data_struct);
export const journals_sess = writable(journals_session_data_struct);
/* *** BEGIN *** Initialize journals_slct and journals_trig */
/* The slct and slct_trigger variable should not be stored in local storage. Only use session storage because browser tabs can be open to different journals, badges, exhibits, etc. */
// Intended for temporary session storage.
// Updated 2024-08-20
let journals_slct_obj_template: key_val = {
const journals_slct_obj_template: key_val = {
// Top level
'journal_id': null,
'journal_obj': {},
'journal_obj_li': [],
journal_id: null,
journal_obj: {},
journal_obj_li: [],
'tmp_journal_obj': {}, // Temporary object for new journal
'tmp_journal_entry_obj': {}, // Temporary object for new journal entry
tmp_journal_obj: {}, // Temporary object for new journal
tmp_journal_entry_obj: {}, // Temporary object for new journal entry
'lq__journal_obj': {}, // Testing passing a LiveQuery object around...
lq__journal_obj: {} // Testing passing a LiveQuery object around...
};
// console.log(`AE Stores - Selected Journals Objects:`, journals_slct_obj_template);
// This works, and uses *session* (not local) storage:
export let journals_slct = writable(journals_slct_obj_template);
export const journals_slct = writable(journals_slct_obj_template);
/* *** BEGIN *** Initialize journals_trig */
// Intended for temporary session storage.
// Updated 2025-03-16
let journals_trig_template: key_val = {
const journals_trig_template: key_val = {
journal_id: false,
journal_entry_li: false,
journal_entry_li: false
};
export let journals_trig: any = writable(journals_trig_template);
export const journals_trig: any = writable(journals_trig_template);
// console.log(`AE Journals Stores - Journals Trigger:`, journals_trig);
/* *** BEGIN *** Initialize journals_prom */
// Intended for temporary session storage.
// Updated 2025-03-16
let journals_prom_template: key_val = {
const journals_prom_template: key_val = {
journal_id: false,
journal_entry_li: false,};
export let journals_prom: any = writable(journals_prom_template);
journal_entry_li: false
};
export const journals_prom: any = writable(journals_prom_template);
// console.log(`AE Journals Stores - Journals Trigger:`, journals_prom);

View File

@@ -1,6 +1,6 @@
import Dexie, { type Table } from 'dexie';
import type { key_val } from '../ae_stores';
import type { key_val } from '$lib/stores/ae_stores';
// li = list
// kv = key value list
@@ -9,145 +9,144 @@ import type { key_val } from '../ae_stores';
// LLM = Large Language Model (AI)
// Updated 2025-03-15
export interface Journal {
id: string; // actually "id_random"
journal_id: string;
// Essentially this is a change log of journals
snapshot_id?: string; // This is the original journal ID. If deleted, then delete all children journals.
previous_id?: null|string; // This is the old or parent journal ID
next_id?: null|string; // This is the new or child journal ID
previous_id?: null | string; // This is the old or parent journal ID
next_id?: null | string; // This is the new or child journal ID
external_id?: null|string;
import_id?: null|string;
code?: null|string;
external_id?: null | string;
import_id?: null | string;
code?: null | string;
for_type?: null|string;
for_id?: null|string;
for_type?: null | string;
for_id?: null | string;
// template?: null|boolean; // Is this a template journal? If true, it can be used to create new journals.
type_code?: null|string;
type_code?: null | string;
account_id?: null|string; // Owner account of the journal
person_id?: null|string; // Owner person of the journal
account_id?: null | string; // Owner account of the journal
person_id?: null | string; // Owner person of the journal
// event_id?: null|string; // Assign to an event???
// location_id?: null|string; // Assign to a location???
name: string; // or the title
short_name?: null|string; // Short name for the journal, if any. Used for display purposes.
summary?: null|string; // LLM (AI) generated summary...???
outline?: null|string; // LLM (AI) generated outline...???
short_name?: null | string; // Short name for the journal, if any. Used for display purposes.
summary?: null | string; // LLM (AI) generated summary...???
outline?: null | string; // LLM (AI) generated outline...???
description?: null|string;
description_md_html?: null|string; // Markdown converted to HTML based on description. Uses marked or similar library for conversion.
description_md_html_alt?: null|string; // Markdown converted to HTML based on description. Uses marked or similar library for conversion.
description_html?: null|string;
description_json?: null|string;
description?: null | string;
description_md_html?: null | string; // Markdown converted to HTML based on description. Uses marked or similar library for conversion.
description_md_html_alt?: null | string; // Markdown converted to HTML based on description. Uses marked or similar library for conversion.
description_html?: null | string;
description_json?: null | string;
start_datetime?: null|Date;
end_datetime?: null|Date;
timezone?: null|string;
start_datetime?: null | Date;
end_datetime?: null | Date;
timezone?: null | string;
alert?: null|boolean; // LLM (AI) generated summary...???
alert_msg?: null|string; // LLM (AI) generated summary...???
alert?: null | boolean; // LLM (AI) generated summary...???
alert_msg?: null | string; // LLM (AI) generated summary...???
sort_by?: null|string; // This is the sort by field
sort_by_desc?: null|string; // This is the sort by field description
sort_by?: null | string; // This is the sort by field
sort_by_desc?: null | string; // This is the sort by field description
cfg_json?: null|key_val; // This is the configuration JSON for the journal
cfg_json?: null | key_val; // This is the configuration JSON for the journal
data_json?: null|key_val; // We always need to store something extra...
data_json?: null | key_val; // We always need to store something extra...
ux_mode?: null|string; // 'mobile' or 'desktop'
ux_mode?: null | string; // 'mobile' or 'desktop'
// This only allows for basic access to the data.
passcode_read?: null|string; // For LLM (AI) generated summary...???
passcode_read_expire?: null|Date;
passcode_write?: null|string;
passcode_write_expire?: null|Date
passcode_read?: null | string; // For LLM (AI) generated summary...???
passcode_read_expire?: null | Date;
passcode_write?: null | string;
passcode_write_expire?: null | Date;
passcode?: null|string; // For Journal Entry encryption password
passcode_timeout?: null|number; // Timeout in seconds
passcode?: null | string; // For Journal Entry encryption password
passcode_timeout?: null | number; // Timeout in seconds
private_passcode?: null|string; // Combine with the Journal passcode for Journal Entry encryption password
private_passcode?: null | string; // Combine with the Journal passcode for Journal Entry encryption password
auth_key?: null|string; // For Journal authorization without sign in
auth_key?: null | string; // For Journal authorization without sign in
enable: null|boolean;
hide?: null|boolean;
archive?: null|boolean; // Archive the journal
archive_on?: null|Date;
priority?: null|boolean
sort?: null|number;
group?: null|string;
notes?: null|string;
enable: null | boolean;
hide?: null | boolean;
archive?: null | boolean; // Archive the journal
archive_on?: null | Date;
priority?: null | boolean;
sort?: null | number;
group?: null | string;
notes?: null | string;
created_on: Date;
updated_on?: null|Date;
updated_on?: null | Date;
// Generated fields for sorting locally only
tmp_sort_1?: null|string;
tmp_sort_2?: null|string;
tmp_sort_3?: null|string;
tmp_sort_1?: null | string;
tmp_sort_2?: null | string;
tmp_sort_3?: null | string;
combined_passcode?: null|string; // For Journal Entry encryption password
combined_passcode?: null | string; // For Journal Entry encryption password
// Additional fields for convenience (database views)
file_count?: null|number; // Only files directly under a journal
journal_file_id_li_json?: null|string;
file_count?: null | number; // Only files directly under a journal
journal_file_id_li_json?: null | string;
// One person
person__given_name?: null|string;
person__family_name?: null|string;
person__full_name?: null|string;
person__primary_email?: null|string;
person__passcode?: null|string;
person__given_name?: null | string;
person__family_name?: null | string;
person__full_name?: null | string;
person__primary_email?: null | string;
person__passcode?: null | string;
// JSON formatted key value pairs for multiple people: {id: name, email, etc.}
person__kv_json?: null|string;
person__kv_json?: null | string;
journal_name?: null|string;
journal_name?: null | string;
journal_location_code?: null|string;
journal_location_name?: null|string;
journal_location_code?: null | string;
journal_location_name?: null | string;
journal_entry_count?: null|number;
journal_entry_count?: null | number;
// A key value list of the entries
journal_entry_kv?: null|key_val;
journal_entry_li?: null|[];
journal_entry_kv?: null | key_val;
journal_entry_li?: null | [];
// A key value list of the files
journal_file_kv?: null|key_val;
journal_file_li?: null|[];
journal_file_kv?: null | key_val;
journal_file_li?: null | [];
// journal_collection_id?: null|string; // For a collection of journals?
// Future standard fields!!!
obj_id?: null|string;
obj_ext_uid?: null|string; // Probably not needed for journals
obj_ext_id?: null|string; // Probably not needed for journals
obj_import_id?: null|string; // Probably not needed for journals
obj_code?: null|string;
obj_account_id?: null|string;
obj_passcode?: null|string;
obj_type?: null|string; // Should always be 'journal' in this case
obj_type_ver_id?: null|string; // The ID from the table for the object type
obj_name?: null|string;
obj_summary?: null|string; // LLM (AI) generated summary...???
obj_outline?: null|string; // LLM (AI) generated outline...???
obj_description?: null|string; // Probably not needed for journals
obj_enable?: null|boolean;
obj_enable_on?: null|Date;
obj_archive_on?: null|Date;
obj_hide?: null|boolean;
obj_priority?: null|number;
obj_sort?: null|number;
obj_group?: null|string;
obj_cfg_json?: null|string;
obj_notes?: null|string;
obj_id?: null | string;
obj_ext_uid?: null | string; // Probably not needed for journals
obj_ext_id?: null | string; // Probably not needed for journals
obj_import_id?: null | string; // Probably not needed for journals
obj_code?: null | string;
obj_account_id?: null | string;
obj_passcode?: null | string;
obj_type?: null | string; // Should always be 'journal' in this case
obj_type_ver_id?: null | string; // The ID from the table for the object type
obj_name?: null | string;
obj_summary?: null | string; // LLM (AI) generated summary...???
obj_outline?: null | string; // LLM (AI) generated outline...???
obj_description?: null | string; // Probably not needed for journals
obj_enable?: null | boolean;
obj_enable_on?: null | Date;
obj_archive_on?: null | Date;
obj_hide?: null | boolean;
obj_priority?: null | number;
obj_sort?: null | number;
obj_group?: null | string;
obj_cfg_json?: null | string;
obj_notes?: null | string;
obj_created_on?: Date;
obj_updated_on?: null|Date;
obj_updated_on?: null | Date;
}
export const journal_field_li = [
@@ -258,145 +257,145 @@ export interface Journal_Entry {
// Essentially this is a change log of journal entries
snapshot_id?: string; // This is the original journal ID. If deleted, then delete all children journal entries.
previous_id?: null|string; // This is the old or parent journal ID
next_id?: null|string; // This is the new or child journal ID
previous_id?: null | string; // This is the old or parent journal ID
next_id?: null | string; // This is the new or child journal ID
external_id?: null|string;
import_id?: null|string;
code?: null|string;
external_id?: null | string;
import_id?: null | string;
code?: null | string;
for_type?: null|string;
for_id?: null|string;
for_type?: null | string;
for_id?: null | string;
template?: null|boolean; // Is this a template journal entry? If true, it can be used to create new journal entries.
template?: null | boolean; // Is this a template journal entry? If true, it can be used to create new journal entries.
activity_code?: null|string;
category_code?: null|string;
topic_code?: null|string;
type_code?: null|string;
tags?: null|string; // Comma separated tags
activity_code?: null | string;
category_code?: null | string;
topic_code?: null | string;
type_code?: null | string;
tags?: null | string; // Comma separated tags
journal_entry_type?: null|string; // This is the type of journal entry
journal_entry_type?: null | string; // This is the type of journal entry
account_id?: null|string; // Owner account of the journal
person_id?: null|string; // Owner person of the journal
account_id?: null | string; // Owner account of the journal
person_id?: null | string; // Owner person of the journal
// event_id?: null|string; // Assign to an event???
// location_id?: null|string; // Assign to a location???
public?: null|boolean;
private?: null|boolean;
personal?: null|boolean;
professional?: null|boolean;
public?: null | boolean;
private?: null | boolean;
personal?: null | boolean;
professional?: null | boolean;
name: string; // or the title
short_name?: null|string; // Short name for the journal entry, if any. Used for display purposes. Most likely for the templates list.
summary?: null|string; // LLM (AI) generated summary...???
outline?: null|string; // LLM (AI) generated outline...???
short_name?: null | string; // Short name for the journal entry, if any. Used for display purposes. Most likely for the templates list.
summary?: null | string; // LLM (AI) generated summary...???
outline?: null | string; // LLM (AI) generated outline...???
// description?: null|string; // This is the description of the journal entry
content?: null|string;
content_md_html?: null|string; // Markdown converted to HTML based on content. Uses marked or similar library for conversion.
content_md_html_alt?: null|string; // Markdown converted to HTML based on content. Uses marked or similar library for conversion.
content_html?: null|string;
content_json?: null|string;
content_encrypted?: null|string; // This is the encrypted content of the journal entry
content?: null | string;
content_md_html?: null | string; // Markdown converted to HTML based on content. Uses marked or similar library for conversion.
content_md_html_alt?: null | string; // Markdown converted to HTML based on content. Uses marked or similar library for conversion.
content_html?: null | string;
content_json?: null | string;
content_encrypted?: null | string; // This is the encrypted content of the journal entry
history?: null|string; // This is the history of the journal entry; a log
history_encrypted?: null|string; // This is the encrypted history of the journal entry
history?: null | string; // This is the history of the journal entry; a log
history_encrypted?: null | string; // This is the encrypted history of the journal entry
passcode_hash?: null|string; // This is the passcode hash for the journal entry to look up the passcode
passcode_hash?: null | string; // This is the passcode hash for the journal entry to look up the passcode
start_datetime?: null|Date;
end_datetime?: null|Date;
timezone?: null|string;
seconds?: null|number; // Duration in seconds
start_datetime?: null | Date;
end_datetime?: null | Date;
timezone?: null | string;
seconds?: null | number; // Duration in seconds
location?: null|string; // Location of the journal entry
latitude?: null|number; // Latitude of the journal entry
longitude?: null|number; // Longitude of the journal entry
location?: null | string; // Location of the journal entry
latitude?: null | number; // Latitude of the journal entry
longitude?: null | number; // Longitude of the journal entry
billable?: null|boolean; // Is this billable?
bill_to?: null|string; // Who to bill for this journal entry
bill_rate?: null|number; // Rate to bill for this journal entry
billable_minutes?: null|number; // Billable minutes for this journal entry
billable?: null | boolean; // Is this billable?
bill_to?: null | string; // Who to bill for this journal entry
bill_rate?: null | number; // Rate to bill for this journal entry
billable_minutes?: null | number; // Billable minutes for this journal entry
alert?: null|boolean; // LLM (AI) generated summary...???
alert_msg?: null|string; // LLM (AI) generated summary...???
alert?: null | boolean; // LLM (AI) generated summary...???
alert_msg?: null | string; // LLM (AI) generated summary...???
parent_id?: null|string; // This is the parent journal entry ID. If deleted, then delete all children journal entries.
related_entry_id_li?: null|key_val; // List of related journal entry IDs
parent_id?: null | string; // This is the parent journal entry ID. If deleted, then delete all children journal entries.
related_entry_id_li?: null | key_val; // List of related journal entry IDs
// cfg_json?: null|key_val; // This is the configuration JSON for the journal entry
data_json?: null|key_val; // We always need to store something extra...
data_json?: null | key_val; // We always need to store something extra...
// This only allows for basic access to the content.
passcode_read?: null|string; // For LLM (AI) generated summary...???
passcode_read_expire?: null|Date;
passcode_write?: null|string;
passcode_write_expire?: null|Date
passcode_read?: null | string; // For LLM (AI) generated summary...???
passcode_read_expire?: null | Date;
passcode_write?: null | string;
passcode_write_expire?: null | Date;
enable: null|boolean;
hide?: null|boolean;
priority?: null|boolean
sort?: null|number;
group?: null|string;
notes?: null|string;
enable: null | boolean;
hide?: null | boolean;
priority?: null | boolean;
sort?: null | number;
group?: null | string;
notes?: null | string;
created_on: Date;
updated_on?: null|Date;
updated_on?: null | Date;
// Generated fields for sorting locally only
tmp_sort_1?: null|string;
tmp_sort_2?: null|string;
tmp_sort_3?: null|string;
tmp_sort_1?: null | string;
tmp_sort_2?: null | string;
tmp_sort_3?: null | string;
// Additional fields for convenience (database views)
file_count?: null|number; // Only files directly under a journal
journal_file_id_li_json?: null|string;
file_count?: null | number; // Only files directly under a journal
journal_file_id_li_json?: null | string;
journal_code?: null|string; // This is the code for the journal entry
journal_name?: null|string; // This is the name for the journal entry
journal_code?: null | string; // This is the code for the journal entry
journal_name?: null | string; // This is the name for the journal entry
// One person
person__given_name?: null|string;
person__family_name?: null|string;
person__full_name?: null|string;
person__primary_email?: null|string;
person__passcode?: null|string;
person__given_name?: null | string;
person__family_name?: null | string;
person__full_name?: null | string;
person__primary_email?: null | string;
person__passcode?: null | string;
// JSON formatted key value pairs for multiple people: {id: name, email, etc.}
person__kv_json?: null|string;
person__kv_json?: null | string;
// A key value list of the files
journal_file_kv?: null|key_val;
journal_file_li?: null|[];
journal_file_kv?: null | key_val;
journal_file_li?: null | [];
// journal_collection_id?: null|string; // For a collection of journal entries?
// Future standard fields!!!
obj_id?: null|string;
obj_ext_uid?: null|string; // Probably not needed for journal entries
obj_ext_id?: null|string; // Probably not needed for journal entries
obj_import_id?: null|string; // Probably not needed for journal entries
obj_code?: null|string;
obj_account_id?: null|string;
obj_passcode?: null|string;
obj_type?: null|string; // Should always be 'journal' in this case
obj_type_ver_id?: null|string; // The ID from the table for the object type
obj_name?: null|string;
obj_summary?: null|string; // LLM (AI) generated summary...???
obj_outline?: null|string; // LLM (AI) generated outline...???
obj_description?: null|string; // Probably not needed for journal entries
obj_enable?: null|boolean;
obj_enable_on?: null|Date;
obj_archive_on?: null|Date;
obj_hide?: null|boolean;
obj_priority?: null|number;
obj_sort?: null|number;
obj_group?: null|string;
obj_cfg_json?: null|string;
obj_notes?: null|string;
obj_id?: null | string;
obj_ext_uid?: null | string; // Probably not needed for journal entries
obj_ext_id?: null | string; // Probably not needed for journal entries
obj_import_id?: null | string; // Probably not needed for journal entries
obj_code?: null | string;
obj_account_id?: null | string;
obj_passcode?: null | string;
obj_type?: null | string; // Should always be 'journal' in this case
obj_type_ver_id?: null | string; // The ID from the table for the object type
obj_name?: null | string;
obj_summary?: null | string; // LLM (AI) generated summary...???
obj_outline?: null | string; // LLM (AI) generated outline...???
obj_description?: null | string; // Probably not needed for journal entries
obj_enable?: null | boolean;
obj_enable_on?: null | Date;
obj_archive_on?: null | Date;
obj_hide?: null | boolean;
obj_priority?: null | number;
obj_sort?: null | number;
obj_group?: null | string;
obj_cfg_json?: null | string;
obj_notes?: null | string;
obj_created_on?: Date;
obj_updated_on?: null|Date;
obj_updated_on?: null | Date;
}
export const journal_entry_field_li = [
@@ -504,7 +503,6 @@ export const journal_entry_field_li = [
'obj_updated_on'
];
// Updated 2024-06-10
export class MySubClassedDexie extends Dexie {
// We just tell the typing system this is the case
@@ -535,8 +533,8 @@ export class MySubClassedDexie extends Dexie {
start_datetime, end_datetime,
timezone,
tmp_sort_1, tmp_sort_2, tmp_sort_3,
enable, hide, priority, sort, group, created_on, updated_on`,
});
enable, hide, priority, sort, group, created_on, updated_on`
});
}
}

View File

@@ -0,0 +1,28 @@
# Aether (AE) Posts Module
The Posts module provides functionality for creating and managing posts and their associated comments. This is suitable for features like a blog, forum, or bulletin board.
## Data Structures
### Post
A `Post` object represents a single entry, such as a blog post or a forum thread. It contains a title, content, and metadata about the author and topic.
### Post Comment
A `Post_Comment` object represents a comment made on a `Post`.
## Functionality
This module provides the following functionality:
- **CRUD Operations:** Create, Read, Update, and Delete operations for both `Post` and `Post_Comment` objects.
- **Local Caching:** Uses Dexie.js to cache data in the browser's IndexedDB for offline access and faster load times.
- **API Interaction:** All data operations are synced with the backend API.
## Files
- `ae_posts__post.ts`: Contains functions for managing `Post` objects.
- `ae_posts__post_comment.ts`: Contains functions for managing `Post_Comment` objects.
- `ae_posts_functions.ts`: Exports all the functions from the module for easy use in other parts of the application.
- `db_posts.ts`: Defines the IndexedDB schema for the posts module using Dexie.js.

File diff suppressed because it is too large Load Diff

View File

@@ -1,220 +1,224 @@
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api';
import type { key_val } from '$lib/stores/ae_stores';
import { api } from '$lib/api/api';
import { db_save_ae_obj_li__ae_obj } from "$lib/ae_core/core__idb_dexie";
import { db_save_ae_obj_li__ae_obj } from '$lib/ae_core/core__idb_dexie';
import { db_posts } from "$lib/ae_posts/db_posts";
let ae_promises: key_val = {};
import { db_posts } from '$lib/ae_posts/db_posts';
const ae_promises: key_val = {};
// Updated 2025-06-23
export async function load_ae_obj_id__post_comment(
{
api_cfg,
post_comment_id,
enabled = 'enabled',
hidden = 'not_hidden',
limit = 99,
offset = 0,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
post_comment_id: string,
enabled?: string,
hidden?: string,
limit?: number,
offset?: number,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
export async function load_ae_obj_id__post_comment({
api_cfg,
post_comment_id,
enabled = 'enabled',
hidden = 'not_hidden',
limit = 99,
offset = 0,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
post_comment_id: string;
enabled?: 'enabled' | 'all' | 'not_enabled' | undefined;
hidden?: 'hidden' | 'all' | 'not_hidden' | undefined;
limit?: number;
offset?: number;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** load_ae_obj_id__post_comment() *** post_comment_id=${post_comment_id}`);
}
ae_promises.load__post_comment_obj = await api.get_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'post_comment',
obj_id: post_comment_id,
use_alt_table: false,
use_alt_base: false,
params: params,
log_lvl: log_lvl
ae_promises.load__post_comment_obj = await api
.get_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'post_comment',
obj_id: post_comment_id,
use_alt_table: false,
use_alt_base: false,
params: params,
log_lvl: log_lvl
})
.then(async function (post_comment_obj_get_result) {
if (post_comment_obj_get_result) {
if (try_cache) {
// Process the results first
let processed_obj_li = await process_ae_obj__post_comment_props({
obj_li: [post_comment_obj_get_result],
log_lvl: log_lvl,
.then(async function (post_comment_obj_get_result) {
if (post_comment_obj_get_result) {
if (try_cache) {
// Process the results first
const processed_obj_li = await process_ae_obj__post_comment_props({
obj_li: [post_comment_obj_get_result],
log_lvl: log_lvl
});
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
// Save the updated results list to the database
if (log_lvl) {
console.log('Saving to DB...');
}
await db_save_ae_obj_li__ae_obj({
db_instance: db_posts,
table_name: 'comment',
obj_li: processed_obj_li,
properties_to_save: properties_to_save,
log_lvl: log_lvl,
});
if (log_lvl) {
console.log('DB save completed.');
}
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
// Save the updated results list to the database
if (log_lvl) {
console.log('Saving to DB...');
}
await db_save_ae_obj_li__ae_obj({
db_instance: db_posts,
table_name: 'comment',
obj_li: processed_obj_li,
properties_to_save: properties_to_save,
log_lvl: log_lvl
});
if (log_lvl) {
console.log('DB save completed.');
}
// // This is expecting a list
// db_save_ae_obj_li__post_comment({
// obj_type: 'post_comment',
// obj_li: [post_comment_obj_get_result],
// log_lvl: log_lvl
// // This is expecting a list
// db_save_ae_obj_li__post_comment({
// obj_type: 'post_comment',
// obj_li: [post_comment_obj_get_result],
// log_lvl: log_lvl
// });
// });
}
return post_comment_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
return post_comment_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
return ae_promises.load__post_comment_obj;
}
// Updated 2025-06-23
export async function load_ae_obj_li__post_comment(
{
api_cfg,
for_obj_type = 'post',
for_obj_id,
enabled = 'enabled',
hidden = 'not_hidden',
limit = 99,
offset = 0,
order_by_li = {'priority': 'DESC', 'sort': 'DESC', 'updated_on': 'DESC', 'created_on': 'DESC', 'title': 'ASC'},
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
for_obj_type: string,
for_obj_id: string,
enabled?: string,
hidden?: string,
limit?: number,
offset?: number,
order_by_li?: key_val,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
export async function load_ae_obj_li__post_comment({
api_cfg,
for_obj_type = 'post',
for_obj_id,
enabled = 'enabled',
hidden = 'not_hidden',
limit = 99,
offset = 0,
order_by_li = {
priority: 'DESC',
sort: 'DESC',
updated_on: 'DESC',
created_on: 'DESC',
title: 'ASC'
},
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
for_obj_type: string;
for_obj_id: string;
enabled?: 'enabled' | 'all' | 'not_enabled' | undefined;
hidden?: 'hidden' | 'all' | 'not_hidden' | undefined;
limit?: number;
offset?: number;
order_by_li?: key_val;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** load_ae_obj_li__post_comment() *** for_obj_type=${for_obj_type} for_obj_id=${for_obj_id}`);
console.log(
`*** load_ae_obj_li__post_comment() *** for_obj_type=${for_obj_type} for_obj_id=${for_obj_id}`
);
}
let params_json: key_val = {};
const params_json: key_val = {};
if (log_lvl) {
console.log('params_json:', params_json);
}
ae_promises.load__post_comment_obj_li = await api.get_ae_obj_li_for_obj_id_crud_v2({
api_cfg: api_cfg,
obj_type: 'post_comment',
for_obj_type: for_obj_type,
for_obj_id: for_obj_id,
use_alt_tbl: false,
use_alt_mdl: false,
use_alt_exp: false,
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
ae_promises.load__post_comment_obj_li = await api
.get_ae_obj_li_for_obj_id_crud_v2({
api_cfg: api_cfg,
obj_type: 'post_comment',
for_obj_type: for_obj_type,
for_obj_id: for_obj_id,
use_alt_tbl: false,
use_alt_mdl: false,
use_alt_exp: false,
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
})
.then(async function (post_comment_obj_li_get_result) {
if (post_comment_obj_li_get_result) {
if (try_cache) {
// Process the results first
let processed_obj_li = await process_ae_obj__post_comment_props({
obj_li: post_comment_obj_li_get_result,
log_lvl: log_lvl,
.then(async function (post_comment_obj_li_get_result) {
if (post_comment_obj_li_get_result) {
if (try_cache) {
// Process the results first
const processed_obj_li = await process_ae_obj__post_comment_props({
obj_li: post_comment_obj_li_get_result,
log_lvl: log_lvl
});
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
// Save the updated results list to the database
if (log_lvl) {
console.log('Saving to DB...');
}
await db_save_ae_obj_li__ae_obj({
db_instance: db_posts,
table_name: 'comment',
obj_li: processed_obj_li,
properties_to_save: properties_to_save,
log_lvl: log_lvl,
});
if (log_lvl) {
console.log('DB save completed.');
}
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
// Save the updated results list to the database
if (log_lvl) {
console.log('Saving to DB...');
}
await db_save_ae_obj_li__ae_obj({
db_instance: db_posts,
table_name: 'comment',
obj_li: processed_obj_li,
properties_to_save: properties_to_save,
log_lvl: log_lvl
});
if (log_lvl) {
console.log('DB save completed.');
}
// db_save_ae_obj_li__post_comment({
// obj_type: 'post_comment',
// obj_li: post_comment_obj_li_get_result,
// log_lvl: log_lvl
// });
// db_save_ae_obj_li__post_comment({
// obj_type: 'post_comment',
// obj_li: post_comment_obj_li_get_result,
// log_lvl: log_lvl
// });
}
return post_comment_obj_li_get_result;
} else {
return [];
}
return post_comment_obj_li_get_result;
} else {
return [];
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
if (log_lvl) {
console.log('ae_promises.load__post_comment_obj_li:', ae_promises.load__post_comment_obj_li);
console.log(
'ae_promises.load__post_comment_obj_li:',
ae_promises.load__post_comment_obj_li
);
}
return ae_promises.load__post_comment_obj_li;
}
// Updated 2025-06-23
export async function create_ae_obj__post_comment(
{
api_cfg,
post_id,
data_kv,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
post_id: string,
data_kv: key_val,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
export async function create_ae_obj__post_comment({
api_cfg,
post_id,
data_kv,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
post_id: string;
data_kv: key_val;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** create_ae_obj__post_comment() *** post_id=${post_id}`);
}
@@ -224,61 +228,61 @@ export async function create_ae_obj__post_comment(
return false;
}
ae_promises.create__post_comment = await api.create_ae_obj_crud({
api_cfg: api_cfg,
obj_type: 'post_comment',
fields: {
post_id_random: post_id,
...data_kv
ae_promises.create__post_comment = await api
.create_ae_obj_crud({
api_cfg: api_cfg,
obj_type: 'post_comment',
fields: {
post_id_random: post_id,
...data_kv
},
key: api_cfg.api_crud_super_key,
params: params,
return_obj: true,
log_lvl: log_lvl
})
.then(async function (post_comment_obj_create_result) {
if (post_comment_obj_create_result) {
if (try_cache) {
// Process the results first
let processed_obj_li = await process_ae_obj__post_comment_props({
obj_li: [post_comment_obj_create_result],
log_lvl: log_lvl,
key: api_cfg.api_crud_super_key,
params: params,
return_obj: true,
log_lvl: log_lvl
})
.then(async function (post_comment_obj_create_result) {
if (post_comment_obj_create_result) {
if (try_cache) {
// Process the results first
const processed_obj_li = await process_ae_obj__post_comment_props({
obj_li: [post_comment_obj_create_result],
log_lvl: log_lvl
});
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
// Save the updated results list to the database
if (log_lvl) {
console.log('Saving to DB...');
}
await db_save_ae_obj_li__ae_obj({
db_instance: db_posts,
table_name: 'comment',
obj_li: processed_obj_li,
properties_to_save: properties_to_save,
log_lvl: log_lvl,
});
if (log_lvl) {
console.log('DB save completed.');
}
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
// Save the updated results list to the database
if (log_lvl) {
console.log('Saving to DB...');
}
await db_save_ae_obj_li__ae_obj({
db_instance: db_posts,
table_name: 'comment',
obj_li: processed_obj_li,
properties_to_save: properties_to_save,
log_lvl: log_lvl
});
if (log_lvl) {
console.log('DB save completed.');
}
// db_save_ae_obj_li__post_comment(
// {
// obj_type: 'post_comment',
// obj_li: [post_comment_obj_create_result],
// log_lvl: log_lvl
// });
// db_save_ae_obj_li__post_comment(
// {
// obj_type: 'post_comment',
// obj_li: [post_comment_obj_create_result],
// log_lvl: log_lvl
// });
}
return post_comment_obj_create_result;
} else {
return null;
}
return post_comment_obj_create_result;
} else {
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
})
.finally(function () {
});
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
})
.finally(function () {});
if (log_lvl) {
console.log('ae_promises.create__post_comment:', ae_promises.create__post_comment);
@@ -286,49 +290,49 @@ export async function create_ae_obj__post_comment(
return ae_promises.create__post_comment;
}
// Updated 2024-11-08
export async function delete_ae_obj_id__post_comment(
{
api_cfg,
post_comment_id,
method = 'delete', // 'delete', 'disable', 'hide'
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
post_comment_id: string,
method?: string,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
export async function delete_ae_obj_id__post_comment({
api_cfg,
post_comment_id,
method = 'delete', // 'delete', 'disable', 'hide'
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
post_comment_id: string;
method?: string;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** delete_ae_obj_id__post_comment() *** post_comment_id=${post_comment_id}`);
}
ae_promises.delete__post_comment_obj = await api.delete_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'post_comment',
obj_id: post_comment_id,
key: api_cfg.api_crud_super_key,
params: params,
method: method,
log_lvl: log_lvl
ae_promises.delete__post_comment_obj = await api
.delete_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'post_comment',
obj_id: post_comment_id,
key: api_cfg.api_crud_super_key,
params: params,
method: method,
log_lvl: log_lvl
})
.catch(function (error) {
console.log('No results returned or failed.', error);
})
.finally(function () {
if (try_cache) {
if (log_lvl) {
console.log(`Attempting to remove IDB entry for post_comment_id=${post_comment_id}`);
.catch(function (error: any) {
console.log('No results returned or failed.', error);
})
.finally(function () {
if (try_cache) {
if (log_lvl) {
console.log(
`Attempting to remove IDB entry for post_comment_id=${post_comment_id}`
);
}
db_posts.comment.delete(post_comment_id); // Delete from the DB no matter what.
}
db_posts.comment.delete(post_comment_id); // Delete from the DB no matter what.
}
});
});
if (log_lvl) {
console.log('ae_promises.delete__post_comment_obj:', ae_promises.delete__post_comment_obj);
@@ -337,27 +341,27 @@ export async function delete_ae_obj_id__post_comment(
return ae_promises.delete__post_comment_obj;
}
// Updated 2025-06-23
export async function update_ae_obj__post_comment(
{
api_cfg,
post_comment_id,
data_kv,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
post_comment_id: string,
data_kv: key_val,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
export async function update_ae_obj__post_comment({
api_cfg,
post_comment_id,
data_kv,
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
post_comment_id: string;
data_kv: key_val;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** update_ae_obj__post_comment() *** post_comment_id=${post_comment_id}`, data_kv);
console.log(
`*** update_ae_obj__post_comment() *** post_comment_id=${post_comment_id}`,
data_kv
);
}
// Perform the API update
@@ -369,17 +373,17 @@ export async function update_ae_obj__post_comment(
key: api_cfg.api_crud_super_key,
params: params,
return_obj: true,
log_lvl: log_lvl,
log_lvl: log_lvl
});
// Handle the result
if (result) {
if (try_cache) {
// Process the results first
let processed_obj_li = await process_ae_obj__post_comment_props({
const processed_obj_li = await process_ae_obj__post_comment_props({
obj_li: [result],
log_lvl: log_lvl,
});
log_lvl: log_lvl
});
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
@@ -392,7 +396,7 @@ export async function update_ae_obj__post_comment(
table_name: 'comment',
obj_li: processed_obj_li,
properties_to_save: properties_to_save,
log_lvl: log_lvl,
log_lvl: log_lvl
});
if (log_lvl) {
console.log('DB save completed.');
@@ -411,81 +415,6 @@ export async function update_ae_obj__post_comment(
}
}
// This function will loop through the post_comment_obj_li and save each one to the DB.
// Updated 2024-09-25
export function db_save_ae_obj_li__post_comment(
{
obj_type,
obj_li,
log_lvl = 0
}: {
obj_type: string,
obj_li: any,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** db_save_ae_obj_li__post_comment() ***`);
}
if (obj_li && obj_li.length) {
obj_li.forEach(async function (obj: any) {
if (log_lvl) {
console.log(`ae_obj ${obj_type}:`, obj);
}
try {
const id_random = await db_posts.comment.put({
id: obj.post_comment_id_random,
post_comment_id: obj.post_comment_id_random,
post_id: obj.post_id_random,
external_person_id: obj.external_person_id,
name: obj.name,
title: obj.title, // Switching to name instead of title
// summary: obj.summary,
content: obj.content,
anonymous: obj.anonymous,
full_name: obj.full_name,
email: obj.email,
notify: obj.notify,
linked_li_json: obj.linked_li_json,
cfg_json: obj.cfg_json,
enable: obj.enable,
hide: obj.hide,
priority: obj.priority,
sort: obj.sort,
group: obj.group,
notes: obj.notes,
created_on: obj.created_on,
updated_on: obj.updated_on,
tmp_sort_1: `${obj.group ?? ''}_${obj.priority ? '1' : '0'}_${obj.sort?.toString().padStart(3, '0') ?? ''}_${obj.updated_on ?? obj.created_on}`,
tmp_sort_2: `${obj.group ?? ''}_${obj.priority ? '1' : '0'}_${obj.sort?.toString().padStart(2, '0') ?? ''}_${obj.updated_on}_${obj.created_on}`,
// From SQL view
});
if (log_lvl) {
console.log(`Put obj with ID: ${obj.post_comment_id_random} or ${id_random}`);
}
} catch (error) {
let status = `Failed to put ${obj.post_comment_id_random}: ${error}`;
console.log(status);
return false;
}
});
return true;
}
}
// Updated 2025-06-04
export const properties_to_save = [
'id',
@@ -520,74 +449,103 @@ export const properties_to_save = [
// Generated fields for sorting locally only
'tmp_sort_1',
'tmp_sort_2',
'tmp_sort_2'
// 'tmp_sort_a',
// 'tmp_sort_b',
// From SQL view
];
/**
* NON-EXPORTED LOCAL HELPER
* Processes a list of Aether objects by applying common and specific transformations.
*/
async function _process_generic_props<T extends Record<string, any>>({
obj_li,
obj_type,
log_lvl = 0,
specific_processor
}: {
obj_li: T[];
obj_type: string;
log_lvl?: number;
specific_processor?: (obj: T) => Promise<T> | T;
}): Promise<T[]> {
if (log_lvl > 0) {
console.log(
`*** _process_generic_props: Processing ${obj_li.length} objects of type "${obj_type}" ***`
);
}
if (!obj_li || obj_li.length === 0) {
if (log_lvl > 0) console.log('No objects to process.');
return [];
}
const processed_obj_li: T[] = [];
for (const original_obj of obj_li) {
let processed_obj = { ...original_obj };
// --- Common Transformations ---
// 1. Standardize ID and other '_random' fields
// The API often returns fields like 'person_id_random', which need to be aliased to 'person_id'.
for (const key in processed_obj) {
if (key.endsWith('_random')) {
const newKey = key.slice(0, -7); // Remove '_random' suffix
processed_obj[newKey] = processed_obj[key];
}
}
// Ensure 'id' is set from '[obj_type]_id_random'
const randomIdKey = `${obj_type}_id_random`;
if (processed_obj[randomIdKey]) {
(processed_obj as any).id = processed_obj[randomIdKey];
}
// 2. Create common computed properties for client-side sorting.
const group = processed_obj.group ?? '0';
const priority = processed_obj.priority ? 1 : 0;
const sort = processed_obj.sort ?? '0';
const updated = processed_obj.updated_on ?? processed_obj.created_on;
const name = processed_obj.name ?? '';
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
// --- Specific Transformations ---
if (specific_processor) {
processed_obj = await Promise.resolve(specific_processor(processed_obj));
}
processed_obj_li.push(processed_obj as T);
}
return processed_obj_li;
}
// Updated 2025-06-04
export async function process_ae_obj__post_comment_props({
obj_li,
log_lvl = 0,
log_lvl = 0
}: {
obj_li: any[];
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** process_ae_obj__post_comment_props() ***`, obj_li);
}
return _process_generic_props({
obj_li,
obj_type: 'post_comment',
log_lvl,
specific_processor: (obj) => {
// Post comment-specific computed sort fields, overriding generic ones if needed
obj.tmp_sort_1 = `${obj.group ?? ''}_${obj.priority ? '1' : '0'}_${
obj.sort?.toString().padStart(3, '0') ?? ''
}_${obj.updated_on ?? obj.created_on}`;
obj.tmp_sort_2 = `${obj.group ?? ''}_${obj.priority ? '1' : '0'}_${
obj.sort?.toString().padStart(2, '0') ?? ''
}_${obj.updated_on}_${obj.created_on}`;
if (!obj_li || obj_li.length === 0) {
if (log_lvl) console.log('No objects to process.');
return [];
}
const processed_obj_li = [];
for (const obj of obj_li) {
if (log_lvl) console.log(`Processing ae_obj post_comment:`, obj);
let processed_obj = {
id: obj.post_comment_id_random,
post_comment_id: obj.post_comment_id_random,
post_comment_id_random: obj.post_comment_id_random,
post_id: obj.post_id_random,
post_id_random: obj.post_id_random,
external_person_id: obj.external_person_id,
name: obj.name,
title: obj.title,
content: obj.content,
anonymous: obj.anonymous,
full_name: obj.full_name,
email: obj.email,
notify: obj.notify,
linked_li_json: obj.linked_li_json,
cfg_json: obj.cfg_json,
enable: obj.enable,
hide: obj.hide,
priority: obj.priority,
sort: obj.sort,
group: obj.group,
notes: obj.notes,
created_on: obj.created_on,
updated_on: obj.updated_on,
// Generated fields for sorting locally only
tmp_sort_1: `${obj.group}_${obj.priority}_${obj.sort}_${obj.updated_on ?? obj.created_on}`,
tmp_sort_2: `${obj.group}_${obj.priority}_${obj.sort}_${obj.updated_on}_${obj.created_on}`,
};
processed_obj_li.push(processed_obj);
}
return processed_obj_li;
}
return obj;
}
});
}

View File

@@ -5,36 +5,28 @@ import {
load_ae_obj_li__post,
create_ae_obj__post,
delete_ae_obj_id__post,
update_ae_obj__post,
// qry__post,
db_save_ae_obj_li__post,
} from "$lib/ae_posts/ae_posts__post";
update_ae_obj__post
} from '$lib/ae_posts/ae_posts__post';
import {
load_ae_obj_id__post_comment,
load_ae_obj_li__post_comment,
create_ae_obj__post_comment,
delete_ae_obj_id__post_comment,
update_ae_obj__post_comment,
// qry__post_comment,
db_save_ae_obj_li__post_comment,
} from "$lib/ae_posts/ae_posts__post_comment";
update_ae_obj__post_comment
} from '$lib/ae_posts/ae_posts__post_comment';
let export_obj = {
const export_obj = {
load_ae_obj_id__post: load_ae_obj_id__post,
load_ae_obj_li__post: load_ae_obj_li__post,
create_ae_obj__post: create_ae_obj__post,
delete_ae_obj_id__post: delete_ae_obj_id__post,
update_ae_obj__post: update_ae_obj__post,
db_save_ae_obj_li__post: db_save_ae_obj_li__post,
load_ae_obj_id__post_comment: load_ae_obj_id__post_comment,
load_ae_obj_li__post_comment: load_ae_obj_li__post_comment,
create_ae_obj__post_comment: create_ae_obj__post_comment,
delete_ae_obj_id__post_comment: delete_ae_obj_id__post_comment,
update_ae_obj__post_comment: update_ae_obj__post_comment,
db_save_ae_obj_li__post_comment: db_save_ae_obj_li__post_comment,
update_ae_obj__post_comment: update_ae_obj__post_comment
};
export let posts_func = export_obj;
export const posts_func = export_obj;

View File

@@ -1,6 +1,6 @@
import Dexie, { type Table } from 'dexie';
import type { key_val } from '../ae_stores';
import type { key_val } from '$lib/stores/ae_stores';
// li = list
// kv = key value list
@@ -15,55 +15,54 @@ export interface Post {
account_id: string;
// account_id_random: string;
person_id?: null|string;
external_person_id?: null|string; // For IDAA this is the Novi UUID
user_id?: null|string;
person_id?: null | string;
external_person_id?: null | string; // For IDAA this is the Novi UUID
user_id?: null | string;
topic_id?: string;
topic?: string; // or topic_name?
topic_name?: string;
name: null|string;
title: null|string;
name: null | string;
title: null | string;
// summary?: null|string;
content?: null|string;
content?: null | string;
anonymous?: null|boolean;
full_name?: null|string;
email?: null|string;
notify?: null|boolean;
anonymous?: null | boolean;
full_name?: null | string;
email?: null | string;
notify?: null | boolean;
enable_comments?: null|boolean;
enable_comments?: null | boolean;
archive?: null|boolean;
archive_on?: null|Date;
archive?: null | boolean;
archive_on?: null | Date;
linked_li_json?: null|string;
cfg_json?: null|key_val;
linked_li_json?: null | string;
cfg_json?: null | key_val;
enable: null|boolean;
hide?: null|boolean;
priority?: null|boolean
sort?: null|number;
group?: null|string;
notes?: null|string;
enable: null | boolean;
hide?: null | boolean;
priority?: null | boolean;
sort?: null | number;
group?: null | string;
notes?: null | string;
created_on: Date;
updated_on?: null|Date;
updated_on?: null | Date;
// Generated fields for sorting locally only
tmp_sort_1?: null|string;
tmp_sort_2?: null|string;
tmp_sort_1?: null | string;
tmp_sort_2?: null | string;
// Additional fields for convenience (database views)
post_comment_count?: number;
// Placeholder for generated temp data
hosted_file_id_li?: null|Array<string>;
hosted_file_obj_li?: null|Array<any>;
hosted_file_id_li?: null | Array<string>;
hosted_file_obj_li?: null | Array<any>;
upload_complete?: boolean;
}
// Updated 2024-11-13
export interface Post_Comment {
id: string;
@@ -74,38 +73,37 @@ export interface Post_Comment {
post_id: string;
// post_id_random: string;
external_person_id?: null|string; // For IDAA this is the Novi UUID
external_person_id?: null | string; // For IDAA this is the Novi UUID
name: null|string;
title: null|string;
name: null | string;
title: null | string;
// summary?: null|string;
content?: null|string;
content?: null | string;
anonymous?: null|boolean;
full_name?: null|string;
email?: null|string;
notify?: null|boolean;
anonymous?: null | boolean;
full_name?: null | string;
email?: null | string;
notify?: null | boolean;
linked_li_json?: null|string;
cfg_json?: null|key_val;
linked_li_json?: null | string;
cfg_json?: null | key_val;
enable: null|boolean;
hide?: null|boolean;
priority?: null|boolean
sort?: null|number;
group?: null|string;
notes?: null|string;
enable: null | boolean;
hide?: null | boolean;
priority?: null | boolean;
sort?: null | number;
group?: null | string;
notes?: null | string;
created_on: Date;
updated_on?: null|Date;
updated_on?: null | Date;
// Generated fields for sorting locally only
tmp_sort_1?: null|string;
tmp_sort_2?: null|string;
tmp_sort_1?: null | string;
tmp_sort_2?: null | string;
// Additional fields for convenience (database views)
}
// Updated 2024-09-25
export class MySubClassedDexie extends Dexie {
// We just tell the typing system this is the case
@@ -133,8 +131,8 @@ export class MySubClassedDexie extends Dexie {
title,
full_name, email,
tmp_sort_1, tmp_sort_2,
enable, hide, priority, sort, group, notes, created_on, updated_on, [updated_on+created_on]`,
});
enable, hide, priority, sort, group, notes, created_on, updated_on, [updated_on+created_on]`
});
}
}

View File

@@ -0,0 +1,27 @@
# Aether (AE) Sponsorships Module
The Sponsorships module is designed to manage event or project sponsorships. It includes data structures and functions for handling sponsorship configurations and individual sponsorship records.
## Data Structures
### Sponsorship Configuration (`Sponsorship_Cfg`)
This data structure defines the available sponsorship levels, options, and schedules for a particular event or account. It acts as a template for creating individual sponsorships.
### Sponsorship
This represents an actual sponsorship agreement with an organization or individual. It includes details about the sponsor, the selected level, payment amount, and other relevant information.
## Functionality
This module provides the following functionality:
- **Data Loading:** Functions to load sponsorship configurations and sponsorship records from the backend API.
- **Data Export:** A function to download an export of sponsorship data in CSV or Excel format.
- **Local Caching:** Uses Dexie.js to cache data in the browser's IndexedDB for offline access and faster load times.
- **API Interaction:** All data operations are synced with the backend API.
## Files
- `ae_sponsorships_functions.ts`: Contains functions for loading and processing sponsorship data.
- `db_sponsorships.ts`: Defines the IndexedDB schema for the sponsorships module using Dexie.js.

View File

@@ -1,127 +1,352 @@
import type { key_val } from '$lib/ae_stores';
import { api } from '$lib/api';
import type { key_val } from '$lib/stores/ae_stores';
import { api } from '$lib/api/api';
import { db_sponsorships } from "$lib/ae_sponsorships/db_sponsorships";
import { db_sponsorships } from '$lib/ae_sponsorships/db_sponsorships';
// import { liveQuery } from "dexie";
// import { db_core } from "$lib/db_core";
let ae_promises: key_val = {}; // Promise<any>;
// --- PROPERTIES TO SAVE ---
export const properties_to_save_sponsorship_cfg = [
'id',
'sponsorship_cfg_id',
'account_id',
'for_type',
'for_id',
'level_li_json',
'option_li_json',
'schedule_li_json',
'cfg_json',
'enable',
'hide',
'priority',
'sort',
'group',
'notes',
'created_on',
'updated_on',
// Generated fields for sorting locally only
'tmp_sort_1',
'tmp_sort_2'
];
// --- PROCESS FUNCTION ---
export async function process_ae_obj__sponsorship_cfg_props({
obj_li,
log_lvl = 0
}: {
obj_li: any[];
log_lvl?: number;
}) {
return _process_generic_props({
obj_li,
obj_type: 'sponsorship_cfg',
log_lvl,
specific_processor: (obj) => {
// Sponsorship Cfg-specific computed sort fields, overriding generic ones if needed
obj.tmp_sort_1 = `${obj.group ?? ''}_${obj.priority ? '1' : '0'}_${
obj.sort?.toString().padStart(3, '0') ?? ''
}_${obj.updated_on ?? obj.created_on}`;
obj.tmp_sort_2 = `${obj.group ?? ''}_${obj.priority ? '1' : '0'}_${
obj.sort?.toString().padStart(3, '0') ?? ''
}_${obj.updated_on}_${obj.created_on}`;
// Updated 2024-03-29
async function load_ae_obj_id__sponsorship_cfg(
{
api_cfg,
sponsorship_cfg_id,
try_cache = false,
log_lvl = 0
}: {
api_cfg: any,
sponsorship_cfg_id: string,
try_cache: boolean,
log_lvl: number
return obj;
}
) {
if (log_lvl) {
console.log(`*** load_ae_obj_id__sponsorship_cfg() *** sponsorship_cfg_id=${sponsorship_cfg_id}`);
});
}
// --- PROPERTIES TO SAVE ---
export const properties_to_save_sponsorship = [
'id',
'sponsorship_id',
'account_id',
'organization_id',
'person_id',
'poc_person_id',
'poc_json',
'name',
'name_override',
'description',
'email',
'website_url',
'logo_li_json',
'media_li_json',
'social_li_json',
'address_li_json',
'contact_li_json',
'guest_li_json',
'level_num',
'level_str',
'amount',
'questions_li_json',
'agree',
'comments',
'staff_notes',
'enable',
'hide',
'priority',
'sort',
'group',
'notes',
'created_on',
'updated_on',
// Generated fields for sorting locally only
'tmp_sort_1',
'tmp_sort_2'
];
// --- PROCESS FUNCTION ---
export async function process_ae_obj__sponsorship_props({
obj_li,
log_lvl = 0
}: {
obj_li: any[];
log_lvl?: number;
}) {
return _process_generic_props({
obj_li,
obj_type: 'sponsorship',
log_lvl,
specific_processor: (obj) => {
// Sponsorship-specific computed sort fields, overriding generic ones if needed
obj.tmp_sort_1 = `${obj.group ?? ''}_${obj.priority ? '1' : '0'}_${
obj.sort?.toString().padStart(3, '0') ?? ''
}_${obj.updated_on ?? obj.created_on}`;
obj.tmp_sort_2 = `${obj.group ?? ''}_${obj.priority ? '1' : '0'}_${
obj.sort?.toString().padStart(3, '0') ?? ''
}_${obj.updated_on}_${obj.created_on}`;
return obj;
}
});
}
/**
* NON-EXPORTED LOCAL HELPER
* Processes a list of Aether objects by applying common and specific transformations.
*/
async function _process_generic_props<T extends Record<string, any>>({
obj_li,
obj_type,
log_lvl = 0,
specific_processor
}: {
obj_li: T[];
obj_type: string;
log_lvl?: number;
specific_processor?: (obj: T) => Promise<T> | T;
}): Promise<T[]> {
if (log_lvl > 0) {
console.log(
`*** _process_generic_props: Processing ${obj_li.length} objects of type "${obj_type}" ***`
);
}
let params = {};
if (!obj_li || obj_li.length === 0) {
if (log_lvl > 0) console.log('No objects to process.');
return [];
}
ae_promises.load__sponsorship_cfg_obj = api.get_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'sponsorship_cfg',
obj_id: sponsorship_cfg_id,
use_alt_table: false, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value in the API config.
params: params,
log_lvl: log_lvl
})
.then(function (sponsorship_cfg_obj_get_result) {
if (sponsorship_cfg_obj_get_result) {
if (log_lvl) {
console.log(`*spons_func* Got a result for sponsorship_cfg_id ${sponsorship_cfg_id}`);
} else if (log_lvl > 1) {
console.log(`*spons_func* Got a result for sponsorship_cfg_id ${sponsorship_cfg_id}:`, sponsorship_cfg_obj_get_result);
const processed_obj_li: T[] = [];
for (const original_obj of obj_li) {
let processed_obj = { ...original_obj };
// --- Common Transformations ---
// 1. Standardize ID and other '_random' fields
// The API often returns fields like 'person_id_random', which need to be aliased to 'person_id'.
for (const key in processed_obj) {
if (key.endsWith('_random')) {
const newKey = key.slice(0, -7); // Remove '_random' suffix
processed_obj[newKey] = processed_obj[key];
}
if (try_cache) {
// This is expecting a list
db_save_ae_obj_li__sponsorship_cfg({
obj_type: 'sponsorship_cfg',
obj_li: [sponsorship_cfg_obj_get_result]
});
}
return sponsorship_cfg_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
// Ensure 'id' is set from '[obj_type]_id_random'
const randomIdKey = `${obj_type}_id_random`;
if (processed_obj[randomIdKey]) {
(processed_obj as any).id = processed_obj[randomIdKey];
}
// 2. Create common computed properties for client-side sorting.
const group = processed_obj.group ?? '0';
const priority = processed_obj.priority ? 1 : 0;
const sort = processed_obj.sort ?? '0';
const updated = processed_obj.updated_on ?? processed_obj.created_on;
const name = processed_obj.name ?? '';
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
// --- Specific Transformations ---
if (specific_processor) {
processed_obj = await Promise.resolve(specific_processor(processed_obj));
}
processed_obj_li.push(processed_obj as T);
}
return processed_obj_li;
}
// Updated 2024-03-29
async function load_ae_obj_id__sponsorship_cfg({
api_cfg,
sponsorship_cfg_id,
try_cache = false,
log_lvl = 0
}: {
api_cfg: any;
sponsorship_cfg_id: string;
try_cache: boolean;
log_lvl: number;
}) {
if (log_lvl) {
console.log(
`*** load_ae_obj_id__sponsorship_cfg() *** sponsorship_cfg_id=${sponsorship_cfg_id}`
);
}
const params = {};
ae_promises.load__sponsorship_cfg_obj = api
.get_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'sponsorship_cfg',
obj_id: sponsorship_cfg_id,
use_alt_table: false, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value in the API config.
params: params,
log_lvl: log_lvl
})
.then(async function (sponsorship_cfg_obj_get_result) {
if (sponsorship_cfg_obj_get_result) {
if (log_lvl) {
console.log(
`*spons_func* Got a result for sponsorship_cfg_id ${sponsorship_cfg_id}`
);
} else if (log_lvl > 1) {
console.log(
`*spons_func* Got a result for sponsorship_cfg_id ${sponsorship_cfg_id}:`,
sponsorship_cfg_obj_get_result
);
}
if (try_cache) {
// Process the results first
const processed_obj_li = await process_ae_obj__sponsorship_cfg_props({
obj_li: [sponsorship_cfg_obj_get_result],
log_lvl: log_lvl
});
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
// Save the updated results list to the database
if (log_lvl) {
console.log('Saving to DB...');
}
await db_save_ae_obj_li__ae_obj({
db_instance: db_sponsorships,
table_name: 'cfg',
obj_li: processed_obj_li,
properties_to_save: properties_to_save_sponsorship_cfg,
log_lvl: log_lvl
});
if (log_lvl) {
console.log('DB save completed.');
}
}
return sponsorship_cfg_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
if (log_lvl) {
console.log('ae_promises.load__sponsorship_cfg_obj:', ae_promises.load__sponsorship_cfg_obj);
console.log(
'ae_promises.load__sponsorship_cfg_obj:',
ae_promises.load__sponsorship_cfg_obj
);
}
return ae_promises.load__sponsorship_cfg_obj;
}
// Updated 2024-03-29
async function load_ae_obj_id__sponsorship(
{
api_cfg,
sponsorship_id,
try_cache = false,
log_lvl = 0
}: {
api_cfg: any,
sponsorship_id: string,
try_cache: boolean,
log_lvl: number
}
) {
async function load_ae_obj_id__sponsorship({
api_cfg,
sponsorship_id,
try_cache = false,
log_lvl = 0
}: {
api_cfg: any;
sponsorship_id: string;
try_cache: boolean;
log_lvl: number;
}) {
if (log_lvl) {
console.log(`*** load_ae_obj_id__sponsorship() *** sponsorship_id=${sponsorship_id}`);
}
let params = {};
const params = {};
ae_promises.load__sponsorship_obj = api.get_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'sponsorship',
obj_id: sponsorship_id,
use_alt_table: false, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value in the API config.
params: params,
log_lvl: log_lvl
ae_promises.load__sponsorship_obj = api
.get_ae_obj_id_crud({
api_cfg: api_cfg,
obj_type: 'sponsorship',
obj_id: sponsorship_id,
use_alt_table: false, // NOTE: This will use the table_name_alt value instead of the table_name value in the API config.
use_alt_base: false, // NOTE: This will use the base_name_alt value instead of the base_name value in the API config.
params: params,
log_lvl: log_lvl
})
.then(function (sponsorship_obj_get_result) {
if (sponsorship_obj_get_result) {
if (log_lvl) {
console.log(`*spons_func* Got a result for sponsorship_id ${sponsorship_id}`);
} else if (log_lvl > 1) {
console.log(`*spons_func* Got a result for sponsorship_id ${sponsorship_id}:`, sponsorship_obj_get_result);
.then(async function (sponsorship_obj_get_result) {
if (sponsorship_obj_get_result) {
if (log_lvl) {
console.log(`*spons_func* Got a result for sponsorship_id ${sponsorship_id}`);
} else if (log_lvl > 1) {
console.log(
`*spons_func* Got a result for sponsorship_id ${sponsorship_id}:`,
sponsorship_obj_get_result
);
}
if (try_cache) {
// Process the results first
const processed_obj_li = await process_ae_obj__sponsorship_props({
obj_li: [sponsorship_obj_get_result],
log_lvl: log_lvl
});
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
// Save the updated results list to the database
if (log_lvl) {
console.log('Saving to DB...');
}
await db_save_ae_obj_li__ae_obj({
db_instance: db_sponsorships,
table_name: 'sponsorship',
obj_li: processed_obj_li,
properties_to_save: properties_to_save_sponsorship,
log_lvl: log_lvl
});
if (log_lvl) {
console.log('DB save completed.');
}
}
return sponsorship_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
if (try_cache) {
// This is expecting a list
db_save_ae_obj_li__sponsorship({
obj_type: 'sponsorship',
obj_li: [sponsorship_obj_get_result]
});
}
return sponsorship_obj_get_result;
} else {
console.log('No results returned.');
return null;
}
})
.catch(function (error) {
console.log('No results returned or failed.', error);
});
})
.catch(function (error: any) {
console.log('No results returned or failed.', error);
});
if (log_lvl) {
console.log('ae_promises.load__sponsorship_obj:', ae_promises.load__sponsorship_obj);
@@ -131,70 +356,95 @@ async function load_ae_obj_id__sponsorship(
}
// Updated 2025-01-15
async function load_ae_obj_li__sponsorship(
{
api_cfg,
for_obj_type = 'account',
for_obj_id,
enabled = 'enabled',
hidden = 'not_hidden',
limit = 99,
offset = 0,
order_by_li = {'priority': 'DESC', 'sort': 'DESC', 'name': 'ASC', 'updated_on': 'DESC', 'created_on': 'DESC'},
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any,
for_obj_type: string,
for_obj_id: string,
inc_content_li?: boolean,
enabled?: string,
hidden?: string,
limit?: number,
offset?: number,
order_by_li?: key_val,
params?: key_val,
try_cache?: boolean,
log_lvl?: number
}
) {
async function load_ae_obj_li__sponsorship({
api_cfg,
for_obj_type = 'account',
for_obj_id,
enabled = 'enabled',
hidden = 'not_hidden',
limit = 99,
offset = 0,
order_by_li = {
priority: 'DESC',
sort: 'DESC',
name: 'ASC',
updated_on: 'DESC',
created_on: 'DESC'
},
params = {},
try_cache = true,
log_lvl = 0
}: {
api_cfg: any;
for_obj_type: string;
for_obj_id: string;
inc_content_li?: boolean;
enabled?: 'enabled' | 'all' | 'not_enabled' | undefined;
hidden?: 'hidden' | 'all' | 'not_hidden' | undefined;
limit?: number;
offset?: number;
order_by_li?: key_val;
params?: key_val;
try_cache?: boolean;
log_lvl?: number;
}) {
if (log_lvl) {
console.log(`*** load_ae_obj_li__sponsorship() *** for_obj_type=${for_obj_type} for_obj_id=${for_obj_id}`);
console.log(
`*** load_ae_obj_li__sponsorship() *** for_obj_type=${for_obj_type} for_obj_id=${for_obj_id}`
);
}
let params_json: key_val = {};
const params_json: key_val = {};
ae_promises.load__sponsorship_obj_li = await api.get_ae_obj_li_for_obj_id_crud_v2({
api_cfg: api_cfg,
obj_type: 'sponsorship',
for_obj_type: for_obj_type,
for_obj_id: for_obj_id,
use_alt_tbl: false,
use_alt_mdl: false,
use_alt_exp: false,
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
ae_promises.load__sponsorship_obj_li = await api
.get_ae_obj_li_for_obj_id_crud_v2({
api_cfg: api_cfg,
obj_type: 'sponsorship',
for_obj_type: for_obj_type,
for_obj_id: for_obj_id,
use_alt_tbl: false,
use_alt_mdl: false,
use_alt_exp: false,
enabled: enabled,
hidden: hidden,
order_by_li: order_by_li,
limit: limit,
offset: offset,
params_json: params_json,
params: params,
log_lvl: log_lvl
})
.then(function (sponsorship_obj_li_get_result) {
if (sponsorship_obj_li_get_result) {
if (try_cache) {
db_save_ae_obj_li__sponsorship({
obj_type: 'sponsorship',
obj_li: sponsorship_obj_li_get_result
});
.then(async function (sponsorship_obj_li_get_result) {
if (sponsorship_obj_li_get_result) {
if (try_cache) {
// Process the results first
const processed_obj_li = await process_ae_obj__sponsorship_props({
obj_li: sponsorship_obj_li_get_result,
log_lvl: log_lvl
});
if (log_lvl) {
console.log('Processed object list:', processed_obj_li);
}
// Save the updated results list to the database
if (log_lvl) {
console.log('Saving to DB...');
}
await db_save_ae_obj_li__ae_obj({
db_instance: db_sponsorships,
table_name: 'sponsorship',
obj_li: processed_obj_li,
properties_to_save: properties_to_save_sponsorship,
log_lvl: log_lvl
});
if (log_lvl) {
console.log('DB save completed.');
}
}
return sponsorship_obj_li_get_result;
} else {
return [];
}
return sponsorship_obj_li_get_result;
} else {
return [];
}
});
});
if (log_lvl) {
console.log('ae_promises.load__sponsorship_obj_li:', ae_promises.load__sponsorship_obj_li);
@@ -203,148 +453,57 @@ async function load_ae_obj_li__sponsorship(
return ae_promises.load__sponsorship_obj_li;
}
async function handle_download_export__sponsorship(
{
export async function download_export__sponsorship({
api_cfg,
account_id,
file_type='CSV', // 'CSV' or 'Excel'
return_file=true,
filename='no_filename.csv',
auto_download=false,
params={}, // key value object is expected
log_lvl=0
}: {
api_cfg: any,
account_id: string,
file_type?: string,
return_file?: boolean,
filename?: string,
auto_download?: boolean,
params?: key_val,
log_lvl?: number
file_type = 'CSV', // 'CSV' or 'Excel'
return_file = true,
filename = 'no_filename.csv',
auto_download = false,
params = {}, // key value object is expected
log_lvl = 0
}: {
api_cfg: any;
account_id: string;
file_type?: string;
return_file?: boolean;
filename?: string;
auto_download?: boolean;
params?: key_val;
log_lvl?: number;
}) {
console.log('*** stores_event_api.js: get_sponsorship_export() ***');
const endpoint = `/v2/crud/sponsorship/list`;
params['for_obj_type'] = 'account';
params['for_obj_id'] = account_id;
if (file_type == 'CSV' || file_type == 'Excel') {
params['file_type'] = file_type;
}
) {
console.log('*** stores_event_api.js: get_sponsorship_export() ***');
params['return_file'] = true;
const endpoint = `/v2/crud/sponsorship/list`;
params['for_obj_type'] = 'account';
params['for_obj_id'] = account_id;
if (file_type == 'CSV' || file_type == 'Excel') {
params['file_type'] = file_type;
}
params['return_file'] = true;
ae_promises.download__sponsorship_export_file = await api.get_object({
api_cfg: api_cfg,
endpoint: endpoint,
params: params,
return_blob: return_file,
filename: filename,
auto_download: auto_download,
log_lvl: log_lvl
ae_promises.download__sponsorship_export_file = await api.get_object({
api_cfg: api_cfg,
endpoint: endpoint,
params: params,
return_blob: return_file,
filename: filename,
auto_download: auto_download,
log_lvl: log_lvl
});
console.log('ae_promises.download__sponsorship_export_file:', ae_promises.download__sponsorship_export_file);
return ae_promises.download__sponsorship_export_file;
console.log(
'ae_promises.download__sponsorship_export_file:',
ae_promises.download__sponsorship_export_file
);
return ae_promises.download__sponsorship_export_file;
}
// Updated 2025-01-15
export function db_save_ae_obj_li__sponsorship(
{
obj_type,
obj_li,
log_lvl = 0
}: {
obj_type: string,
obj_li: any,
log_lvl?: number
}
) {
if (log_lvl) {
console.log(`*** db_save_ae_obj_li__sponsorship() ***`);
}
if (obj_li && obj_li.length) {
obj_li.forEach(async function (obj: any) {
if (log_lvl) {
console.log(`ae_obj ${obj_type}:`, obj);
}
try {
const id_random = await db_sponsorships.sponsorship.put({
id: obj.sponsorship_id_random,
sponsorship_id: obj.sponsorship_id_random,
account_id: obj.account_id_random,
external_person_id: obj.external_person_id,
topic_id: obj.topic_id,
topic: obj.topic,
topic_name: obj.topic_name,
name: obj.title,
title: obj.title, // Switching to name instead of title
// summary: obj.summary,
content: obj.content,
anonymous: obj.anonymous,
full_name: obj.full_name,
email: obj.email,
notify: obj.notify,
enable_comments: obj.enable_comments,
archive: obj.archive,
archive_on: obj.archive_on,
linked_li_json: obj.linked_li_json,
cfg_json: obj.cfg_json,
enable: obj.enable,
hide: obj.hide,
priority: obj.priority,
sort: obj.sort,
group: obj.group,
notes: obj.notes,
created_on: obj.created_on,
updated_on: obj.updated_on,
tmp_sort_1: `${obj.group}_${obj.priority}_${obj.sort}_${obj.updated_on ?? obj.created_on}`,
tmp_sort_2: `${obj.group}_${obj.priority}_${obj.sort}_${obj.updated_on}_${obj.created_on}`,
// From SQL view
sponsorship_comment_count: obj.sponsorship_comment_count,
// A key value list of the comments
// sponsorship_comment_kv: obj.sponsorship_comment_kv,
// sponsorship_comment_li: obj.sponsorship_comment_li,
});
if (log_lvl) {
console.log(`Put obj with ID: ${obj.sponsorship_id_random} or ${id_random}`);
}
} catch (error) {
let status = `Failed to put ${obj.sponsorship_id_random}: ${error}`;
console.log(status);
return false;
}
});
return true;
}
}
let export_obj = {
const export_obj = {
load_ae_obj_id__sponsorship_cfg: load_ae_obj_id__sponsorship_cfg,
load_ae_obj_id__sponsorship: load_ae_obj_id__sponsorship,
load_ae_obj_li__sponsorship: load_ae_obj_li__sponsorship,
handle_download_export__sponsorship: handle_download_export__sponsorship,
db_save_ae_obj_li__sponsorship: db_save_ae_obj_li__sponsorship
download_export__sponsorship: download_export__sponsorship
};
export let spons_func = export_obj;
export const spons_func = export_obj;

View File

@@ -1,6 +1,6 @@
import Dexie, { type Table } from 'dexie';
import type { key_val } from '../ae_stores';
import type { key_val } from '$lib/stores/ae_stores';
// li = list
// kv = key value list
@@ -15,19 +15,19 @@ export interface Sponsorship {
account_id: string;
// account_id_random: string;
organization_id?: null|string;
person_id?: null|string;
organization_id?: null | string;
person_id?: null | string;
poc_person_id?: null|string;
poc_json?: null|string;
poc_person_id?: null | string;
poc_json?: null | string;
name: null|string;
name_override: null|string;
name: null | string;
name_override: null | string;
description?: null|string;
description?: null | string;
email?: null|string;
website_url?: null|string;
email?: null | string;
website_url?: null | string;
// html_text?: null|string;
// thumbnail_url?: null|string;
@@ -38,42 +38,41 @@ export interface Sponsorship {
// document_url?: null|string;
// logo_url?: null|string;
logo_li_json?: null|string;
media_li_json?: null|string;
social_li_json?: null|string;
address_li_json?: null|string;
contact_li_json?: null|string;
guest_li_json?: null|string;
logo_li_json?: null | string;
media_li_json?: null | string;
social_li_json?: null | string;
address_li_json?: null | string;
contact_li_json?: null | string;
guest_li_json?: null | string;
level_num?: null|number;
level_str?: null|string;
level_num?: null | number;
level_str?: null | string;
amount?: null|number; // In dollars
amount?: null | number; // In dollars
questions_li_json?: null|string;
questions_li_json?: null | string;
agree?: null|boolean; // Catchall agree or consent
agree?: null | boolean; // Catchall agree or consent
comments?: null|string; // From the sponsor
staff_notes?: null|string; // Internal use; from staff
comments?: null | string; // From the sponsor
staff_notes?: null | string; // Internal use; from staff
enable: null|boolean;
hide?: null|boolean;
priority?: null|boolean
sort?: null|number;
group?: null|string;
notes?: null|string;
enable: null | boolean;
hide?: null | boolean;
priority?: null | boolean;
sort?: null | number;
group?: null | string;
notes?: null | string;
created_on: Date;
updated_on?: null|Date;
updated_on?: null | Date;
// Generated fields for sorting locally only
tmp_sort_1?: null|string;
tmp_sort_2?: null|string;
tmp_sort_1?: null | string;
tmp_sort_2?: null | string;
// Additional fields for convenience (database views)
}
// Updated 2025-01-15
export interface Sponsorship_Cfg {
id: string;
@@ -84,28 +83,27 @@ export interface Sponsorship_Cfg {
account_id: string;
// account_id_random: string;
for_type?: null|string;
for_id?: null|number;
for_type?: null | string;
for_id?: null | number;
level_li_json?: null|string;
option_li_json?: null|string;
schedule_li_json?: null|string;
level_li_json?: null | string;
option_li_json?: null | string;
schedule_li_json?: null | string;
cfg_json?: null|key_val;
cfg_json?: null | key_val;
enable: null|boolean;
hide?: null|boolean;
priority?: null|boolean
sort?: null|number;
group?: null|string;
notes?: null|string;
enable: null | boolean;
hide?: null | boolean;
priority?: null | boolean;
sort?: null | number;
group?: null | string;
notes?: null | string;
created_on: Date;
updated_on?: null|Date;
updated_on?: null | Date;
// Additional fields for convenience (database views)
}
// Updated 2024-09-25
export class MySubClassedDexie extends Dexie {
// We just tell the typing system this is the case
@@ -127,7 +125,7 @@ export class MySubClassedDexie extends Dexie {
cfg: `
id, sponsorship_cfg_id,
account_id,
for_type, for_id`,
for_type, for_id`
});
}
}

View File

@@ -1,32 +0,0 @@
// These are shared snippets of text, This is mostly HTML and CSS.
export let string_snippets: any = {};
string_snippets['html__not_set'] = `
<span
class="text-sm text-gray-500 bg-gray-100 p-1 rounded-md border border-gray-200"
>-- not set --
</span>
`;
string_snippets['classes__core_menu'] = 'flex flex-col items-center space-y-1 border border-blue-200 rounded-md py-1 px-2 hover:bg-blue-100';
string_snippets['classes__core_menu__button'] = 'btn btn-sm mx-1 preset-tonal-tertiary text-info-300 hover:text-info-800';
string_snippets['classes__core_menu__button_highlight'] = 'btn btn-sm mx-1 preset-filled-tertiary-500 text-info-300 hover:text-info-800';
string_snippets['classes__core_menu__button_warning'] = 'btn btn-sm mx-1 preset-tonal-warning text-info-300 hover:text-info-800';
// string_snippets['classes__events_pres_mgmt_menu'] = 'flex flex-col items-center space-y-1 border border-blue-200 rounded-md py-1 px-2 hover:bg-blue-100 transition-all duration-700 hover:duration-300';
string_snippets['classes__events_pres_mgmt_menu'] = 'w-full flex flex-col items-center gap-1 border border-gray-200 rounded-md p-1 hover:bg-gray-100 transition-all duration-700 hover:duration-300';
string_snippets['classes__events_pres_mgmt_menu__button'] = 'btn btn-sm mx-1 preset-tonal-secondary hover:preset-filled-secondary-500';
string_snippets['classes__events_pres_mgmt_menu__button_special'] = 'btn btn-sm mx-1 hover:preset-filled-primary-500';
// string_snippets['classes__events_pres_mgmt_menu__button'] = 'btn btn-sm mx-1 variant-soft-tertiary text-info-300 hover:text-info-800 hover:variant-filled-tertiary';
// string_snippets['classes__events_pres_mgmt_menu__button_special'] = 'btn btn-sm mx-1 variant-ghost-tertiary text-info-300 hover:text-info-800 hover:variant-filled-tertiary';
string_snippets['classes__events_pres_mgmt_menu__button_highlight'] = 'btn btn-sm mx-1 preset-filled-tertiary-500 text-info-300 hover:text-info-800';
string_snippets['classes__events_pres_mgmt_menu__button_warning'] = 'btn btn-sm mx-1 preset-tonal-warning text-info-300 hover:text-info-800';
string_snippets['classes__events_pres_mgmt_menu__button_warning_special'] = 'btn btn-sm mx-1 preset-tonal-warning';
// export string_snippets;

View File

@@ -1,6 +1,12 @@
// Import external files first. Eventually this will be broken up in to smaller files.
import { clean_filename, format_bytes, guess_file_name, guess_file_extension, get_file_hash } from './ae_utils__files';
import { get_obj_li_w_match_prop} from './ae_utils__get_obj_li_w_match_prop';
import {
clean_filename,
format_bytes,
guess_file_name,
guess_file_extension,
get_file_hash
} from './ae_utils__files';
import { get_obj_li_w_match_prop } from './ae_utils__get_obj_li_w_match_prop';
import { file_extension_icon } from './ae_utils__file_extension_icon';
import { process_permission_checks } from './ae_utils__perm_checks';
import { iso_datetime_formatter } from './ae_utils__datetime_format';
@@ -10,8 +16,13 @@ import { to_title_case } from './ae_utils__to_title_case';
import { process_data_string } from './ae_utils__process_data_string';
import { set_obj_prop_display_name } from './ae_utils__set_obj_prop_display_name';
import { return_obj_type_path } from './ae_utils__return_obj_type_path';
import { combine_iv_and_base64, encrypt_content, encrypt_wrapper, decrypt_content, decrypt_wrapper } from './ae_utils__crypto';
import {
combine_iv_and_base64,
encrypt_content,
encrypt_wrapper,
decrypt_content,
decrypt_wrapper
} from './ae_utils__crypto';
export type key_str = {
[key: string]: string;
@@ -21,13 +32,11 @@ export type key_val = {
[key: string]: any;
};
/* This utility function will add commas to a number. */
function number_w_commas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
// This function will update the URL and send a message to the parent window (iframe).
// The name should be something like "example_id".
// Svelte specific:
@@ -35,12 +44,10 @@ function number_w_commas(x) {
// Updated 2024-03-02
// import { pushState, replaceState } from '$app/navigation';
function handle_url_and_message(name: string, value: null|string) {
function handle_url_and_message(name: string, value: null | string) {
console.log(`*** handle_url_and_message() *** name=${name} value=${value}`);
let location = window.location.href;
const location = window.location.href;
// console.log('location:', location);
const url = new URL(location);
// console.log('url:', url);
@@ -54,8 +61,8 @@ function handle_url_and_message(name: string, value: null|string) {
// pushState(url.search, {});
// replaceState(url.href, {});
let message = {name: value};
window.parent.postMessage(message, "*");
const message = { name: value };
window.parent.postMessage(message, '*');
} else {
url.searchParams.delete(name);
history.pushState({}, '', url);
@@ -65,18 +72,34 @@ function handle_url_and_message(name: string, value: null|string) {
// pushState(url.href, {});
// replaceState(url.href, {});
let message = {name: null};
window.parent.postMessage(message, "*");
const message = { name: null };
window.parent.postMessage(message, '*');
}
// console.log('Message sent to parent (iframe):', message);
}
function create_a_element({account_id, base_url, hosted_file_id, filename=null, extension=null, text="Download", class_li='text-blue-500'}) {
function create_a_element({
account_id,
base_url,
hosted_file_id,
filename = null,
extension = null,
text = 'Download',
class_li = 'text-blue-500'
}) {
return `<a href="${base_url}/hosted_file/${hosted_file_id}/download?x_no_account_id_token=${account_id}&filename=${filename}" class="${class_li}">${text}</a>`;
}
function create_img_element({account_id, base_url, hosted_file_id, filename=null, extension=null, class_li='max-w-64', style="", inc_link=false}) {
function create_img_element({
account_id,
base_url,
hosted_file_id,
filename = null,
extension = null,
class_li = 'max-w-64',
style = '',
inc_link = false
}) {
let img_html = '';
if (filename) {
img_html = `<img src="${base_url}/hosted_file/${hosted_file_id}/download?x_no_account_id_token=${account_id}&filename=${filename}" class="${class_li}" style="${style}" />`;
@@ -85,14 +108,28 @@ function create_img_element({account_id, base_url, hosted_file_id, filename=null
}
if (inc_link) {
let a_html = create_a_element({account_id: account_id, base_url: base_url, hosted_file_id: hosted_file_id, filename: filename, extension: extension});
const a_html = create_a_element({
account_id: account_id,
base_url: base_url,
hosted_file_id: hosted_file_id,
filename: filename,
extension: extension
});
img_html = `<div class="ae_img ae_a">${img_html}${a_html}</div>`;
}
return img_html;
}
function create_video_element({account_id, base_url, hosted_file_id, filename=null, extension=null, class_li='max-w-64', inc_link=false}) {
function create_video_element({
account_id,
base_url,
hosted_file_id,
filename = null,
extension = null,
class_li = 'max-w-64',
inc_link = false
}) {
let video_html = '';
if (filename) {
video_html = `<video src="${base_url}/hosted_file/${hosted_file_id}/download?x_no_account_id_token=${account_id}&filename=${filename}" controls class="${class_li}"></video>`;
@@ -101,14 +138,19 @@ function create_video_element({account_id, base_url, hosted_file_id, filename=nu
}
if (inc_link) {
let a_html = create_a_element({account_id: account_id, base_url: base_url, hosted_file_id: hosted_file_id, filename: filename, extension: extension});
const a_html = create_a_element({
account_id: account_id,
base_url: base_url,
hosted_file_id: hosted_file_id,
filename: filename,
extension: extension
});
video_html = `<div class="ae_video ae_a">${video_html}${a_html}</div>`;
}
return video_html;
}
// // Clear the quick access type
// function clear_access_type() {
// // NOTE: I think it makes since to reset this to anonymous even if logged in as an admin or similar.
@@ -127,35 +169,31 @@ function create_video_element({account_id, base_url, hosted_file_id, filename=nu
// return true;
// }
// This function will take a long string (sentences or paragraphs) of text and return an estimated number of words.
function count_words(text: string) {
if (!text || text.length < 1) {
return false;
}
let count = text.trim().split(/\s+/).length;
const count = text.trim().split(/\s+/).length;
return count;
}
// Updated 2024-06-19
// This function behaves weirdly. It needs to be reviewed and updated.
export let shorten_string = function shorten_string(
{
string,
max_length = 45,
begin_length = 15,
end_length = 5,
wildcard_length = 3
}: {
string: undefined|string,
max_length?: number,
begin_length?: number,
end_length?: number,
wildcard_length?: number
}
) {
export const shorten_string = function shorten_string({
string,
max_length = 45,
begin_length = 15,
end_length = 5,
wildcard_length = 3
}: {
string: undefined | string;
max_length?: number;
begin_length?: number;
end_length?: number;
wildcard_length?: number;
}) {
// console.log('*** shorten_filename() ***');
if (!string || typeof string != 'string') {
@@ -168,11 +206,11 @@ export let shorten_string = function shorten_string(
// 20 part 1 characters, 5 part 2 characters, 20 part 3 characters
// let length = string.length;
let char_over = string.length-max_length;
const char_over = string.length - max_length;
let new_string = null;
let wildcards = char_over;
if (char_over > 0) {
let part1 = string.slice(0, begin_length);
const part1 = string.slice(0, begin_length);
let part2 = '';
if (char_over > 5) {
@@ -186,33 +224,30 @@ export let shorten_string = function shorten_string(
part2 = '.'.repeat(wildcards);
}
let part3 = string.slice(end_length*-1);
const part3 = string.slice(end_length * -1);
new_string = part1+part2+part3;
new_string = part1 + part2 + part3;
} else {
new_string = string;
}
return new_string;
}
};
// Updated 2024-06-19
// This function should return a shorted version of a filename if over the max length. It should always contain at least the first character of the original filename and the complete extension.
// Example 1: The Original Long File Name.pdf -> The Orig....pdf
// Example 2: The Original Long File Name.html -> The Ori....html
function shorten_filename(
{
filename,
max_length = 20,
slice_end_at = 15,
max_end_length = 5
}: {
filename: string,
max_length?: number,
slice_end_at?: number,
max_end_length?: number
}
) {
function shorten_filename({
filename,
max_length = 20,
slice_end_at = 15,
max_end_length = 5
}: {
filename: string;
max_length?: number;
slice_end_at?: number;
max_end_length?: number;
}) {
// console.log('*** shorten_filename() ***');
if (typeof filename !== 'string' || filename.length <= max_length) {
@@ -220,27 +255,26 @@ function shorten_filename(
}
let new_filename = null;
let char_over = filename.length - max_length;
const char_over = filename.length - max_length;
let wildcards = char_over - 4; // The number of characters over the max length
if (wildcards < 1) {
return filename; // No point in changing the filename?
}
let part_1 = filename.slice(0, slice_end_at);
const part_1 = filename.slice(0, slice_end_at);
if (wildcards > 3) {
wildcards = 3;
} else {
}
let part_2 = '.'.repeat(wildcards);
let part_3 = filename.slice(max_end_length*-1);
const part_2 = '.'.repeat(wildcards);
const part_3 = filename.slice(max_end_length * -1);
new_filename = part_1+part_2+part_3;
new_filename = part_1 + part_2 + part_3;
return new_filename;
}
export let ae_util = {
export const ae_util = {
is_datetime_recent: is_datetime_recent,
process_permission_checks: process_permission_checks,
iso_datetime_formatter: iso_datetime_formatter,
@@ -268,5 +302,5 @@ export let ae_util = {
encrypt_content: encrypt_content,
encrypt_wrapper: encrypt_wrapper,
decrypt_content: decrypt_content,
decrypt_wrapper: decrypt_wrapper,
decrypt_wrapper: decrypt_wrapper
};

View File

@@ -1,4 +1,4 @@
let log_lvl = 0; // 0 = no logging, 1 = some logging, 2 = all logging
const log_lvl = 0; // 0 = no logging, 1 = some logging, 2 = all logging
// Updated 2025-05-08
async function generate_iv() {
@@ -8,32 +8,40 @@ async function generate_iv() {
}
// Updated 2025-05-08
export let encrypt_content = async function encrypt_content(
content: string,
keyData: string
) {
export const encrypt_content = async function encrypt_content(content: string, keyData: string) {
const iv = await generate_iv();
const keyBytes = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(keyData));
const key = await crypto.subtle.importKey('raw', keyBytes, { name: 'AES-CBC' }, false, ['encrypt']);
const encodedContent = await crypto.subtle.encrypt({ name: 'AES-CBC', iv }, key, new TextEncoder().encode(content));
const key = await crypto.subtle.importKey('raw', keyBytes, { name: 'AES-CBC' }, false, [
'encrypt'
]);
const encodedContent = await crypto.subtle.encrypt(
{ name: 'AES-CBC', iv },
key,
new TextEncoder().encode(content)
);
const base64 = btoa(String.fromCharCode(...new Uint8Array(encodedContent)));
if (log_lvl) {
console.log(`IV: ${iv}; Encrypted:`, base64);
}
return { base64, iv };
}
};
// Updated 2025-05-08
export let combine_iv_and_base64 = function combine_iv_and_base64(
base64: string,
iv: Uint8Array
) {
export const combine_iv_and_base64 = function combine_iv_and_base64(
base64: string,
iv: Uint8Array
) {
if (log_lvl) {
console.log(`IV: ${iv}; Encrypted:`, base64);
}
// Combine the IV and encrypted content
const combined = Array.from(iv).map(byte => byte.toString(16).padStart(2, '0')).join('') + ':' + base64;
const combined =
Array.from(iv)
.map((byte) => byte.toString(16).padStart(2, '0'))
.join('') +
':' +
base64;
if (log_lvl) {
console.log('Combined IV and Base64:', combined);
}
@@ -41,13 +49,10 @@ export let combine_iv_and_base64 = function combine_iv_and_base64(
// const combined = `${ivBase64}:${base64}`;
// console.log('Combined IV and Base64 v2:', combined);
return combined;
}
};
// Updated 2025-05-08
export let encrypt_wrapper = async function encrypt_wrapper(
content: string,
keyData: string
) {
export const encrypt_wrapper = async function encrypt_wrapper(content: string, keyData: string) {
if (!content) {
console.error('No content provided. Returning empty string.');
return '';
@@ -59,51 +64,53 @@ export let encrypt_wrapper = async function encrypt_wrapper(
const { base64, iv } = await encrypt_content(content, keyData);
const combined = combine_iv_and_base64(base64, iv);
return combined;
}
};
// This does not handle errors (invalid key/password) well.
// Updated 2025-05-08
export let decrypt_content = async function decrypt_content(
base64Content: string,
iv: Uint8Array,
keyData: string
) {
export const decrypt_content = async function decrypt_content(
base64Content: string,
iv: Uint8Array,
keyData: string
) {
const keyBytes = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(keyData));
const key = await crypto.subtle.importKey('raw', keyBytes, { name: 'AES-CBC' }, false, ['decrypt']);
const encryptedContent = Uint8Array.from(atob(base64Content), c => c.charCodeAt(0));
const decryptedContent = await crypto.subtle.decrypt({ name: 'AES-CBC', iv }, key, encryptedContent);
const key = await crypto.subtle.importKey('raw', keyBytes, { name: 'AES-CBC' }, false, [
'decrypt'
]);
const encryptedContent = Uint8Array.from(atob(base64Content), (c) => c.charCodeAt(0));
const decryptedContent = await crypto.subtle.decrypt(
{ name: 'AES-CBC', iv },
key,
encryptedContent
);
const decodedContent = new TextDecoder().decode(decryptedContent);
// console.log('Decrypted Content:', decodedContent);
return decodedContent;
}
};
// Updated 2025-05-08
export let split_iv_and_base64 = function split_iv_and_base64(
combined: string
) {
export const split_iv_and_base64 = function split_iv_and_base64(combined: string) {
if (!combined) {
console.error('No combined string provided. Returning empty object.');
return { iv: new Uint8Array(), base64: '' };
}
let [iv_hex, encrypted_base64_string] = combined.split(':');
let base64 = encrypted_base64_string
let iv = new Uint8Array(iv_hex.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));
const [iv_hex, encrypted_base64_string] = combined.split(':');
const base64 = encrypted_base64_string;
const iv = new Uint8Array(iv_hex.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));
if (log_lvl) {
console.log(`IV: ${iv}; Encrypted:`, base64);
}
return { iv, base64 };
}
};
// Updated 2025-05-15
export let decrypt_wrapper = async function decrypt_wrapper(
combined: string,
keyData: string
) {
export const decrypt_wrapper = async function decrypt_wrapper(combined: string, keyData: string) {
if (!combined) {
console.error('No combined string provided. Returning empty string.');
return false;
}
const { iv, base64 } = split_iv_and_base64(combined);
console.log(`IV: ${iv}; Encrypted:`, base64);
let decrypted;
try {
decrypted = await decrypt_content(base64, iv, keyData);
@@ -117,4 +124,4 @@ export let decrypt_wrapper = async function decrypt_wrapper(
return false;
}
return decrypted;
}
};

View File

@@ -1,10 +1,10 @@
import dayjs from 'dayjs';
export let iso_datetime_formatter = function iso_datetime_formatter(
raw_datetime: null|string|Date = null,
export const iso_datetime_formatter = function iso_datetime_formatter(
raw_datetime: null | string | Date = null,
named_format: string = 'datetime_iso_no_seconds', // date_iso, datetime_iso_no_seconds
time_24_hours: boolean = false
) {
) {
// console.log('*** iso_datetime_formatter() ***');
// https://en.wikipedia.org/wiki/ISO_8601
@@ -74,6 +74,9 @@ export let iso_datetime_formatter = function iso_datetime_formatter(
// case 'datetime_12_no_seconds':
// datetime_string = dayjs(raw_datetime).format('YYYY-MM-DD hh:mm A');
// break;
case 'datetime_us':
datetime_string = dayjs(raw_datetime).format('MM/DD/YYYY hh:mm:ss A');
break;
case 'datetime_short':
datetime_string = dayjs(raw_datetime).format('MMM D, YY HH:mm');
break;
@@ -110,6 +113,9 @@ export let iso_datetime_formatter = function iso_datetime_formatter(
case 'date_iso':
datetime_string = dayjs(raw_datetime).format('YYYY-MM-DD');
break;
case 'date_us':
datetime_string = dayjs(raw_datetime).format('MM/DD/YYYY');
break;
case 'date_long_month_day':
datetime_string = dayjs(raw_datetime).format('MMMM D');
break;
@@ -118,7 +124,7 @@ export let iso_datetime_formatter = function iso_datetime_formatter(
break;
case 'date_short_no_year':
datetime_string = dayjs(raw_datetime).format('MMM D');
break;
break;
case 'date_long':
datetime_string = dayjs(raw_datetime).format('MMMM D, YYYY');
break;
@@ -135,7 +141,7 @@ export let iso_datetime_formatter = function iso_datetime_formatter(
datetime_string = dayjs(raw_datetime).format('hh:mm:ss A Z');
break;
case 'time_long':
datetime_string = dayjs(raw_datetime).format('HH:mm:ss A');
datetime_string = dayjs(raw_datetime).format('HH:mm:ss');
break;
case 'time_12_long':
datetime_string = dayjs(raw_datetime).format('hh:mm:ss A');
@@ -164,7 +170,7 @@ export let iso_datetime_formatter = function iso_datetime_formatter(
default:
// console.log(`The named format passed (${named_format}) did not match a common name. Trying to format with the named format value.`);
datetime_string = dayjs(raw_datetime).format(named_format);
// datetime_string = dayjs(raw_datetime).format('YYYY-MM-DD HH:mm:ss');
// datetime_string = dayjs(raw_datetime).format('YYYY-MM-DD HH:mm:ss');
}
return datetime_string;
}
};

Some files were not shown because too many files have changed in this diff Show More