Compare commits
64 Commits
7f17b3b9a1
...
929f08b656
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
929f08b656 | ||
|
|
48a39b16d5 | ||
|
|
ab294c2a0b | ||
|
|
1de563203d | ||
|
|
0091fe3ff6 | ||
|
|
0ad36a74b2 | ||
|
|
fd244720a7 | ||
|
|
362136e677 | ||
|
|
a5a806e256 | ||
|
|
613e43114c | ||
|
|
1c818e648b | ||
|
|
5cd1d3b7ad | ||
|
|
66f0efb507 | ||
|
|
a637343544 | ||
|
|
a8f3c29b9f | ||
|
|
23d25bf65a | ||
|
|
12a9472064 | ||
|
|
b74c6d0e9c | ||
|
|
e1338b1a72 | ||
|
|
6018a94499 | ||
|
|
6e67534454 | ||
|
|
693486bac9 | ||
|
|
6d1d1e2658 | ||
|
|
7f6e286b73 | ||
|
|
a3ed379b17 | ||
|
|
e9379be5a1 | ||
|
|
9a75243d9c | ||
|
|
94849137f0 | ||
|
|
512e5ef87c | ||
|
|
d27ec58fe9 | ||
|
|
42358efe7d | ||
|
|
8e61bd0ba1 | ||
|
|
0bc71391fc | ||
|
|
6e22639e6e | ||
|
|
a6f8ff709e | ||
|
|
dafe79b3c6 | ||
|
|
a4927d37bd | ||
|
|
f3ab1c1050 | ||
|
|
5bed167829 | ||
|
|
a14320d9ed | ||
|
|
de8a016bda | ||
|
|
1c8997bd4f | ||
|
|
fe23899479 | ||
|
|
6662e82f40 | ||
|
|
4586e809d7 | ||
|
|
334c3a21bc | ||
|
|
14c2635df4 | ||
|
|
9673cbefe3 | ||
|
|
9a43879535 | ||
|
|
2c570c82dc | ||
|
|
bf9aa9710c | ||
|
|
942b3ddf5f | ||
|
|
bb0365f1e8 | ||
|
|
2b747de9bd | ||
|
|
519f5b949c | ||
|
|
bf834aa165 | ||
|
|
0d960435f8 | ||
|
|
60461de9d9 | ||
|
|
da3b8dcf46 | ||
|
|
f628e7e3fc | ||
|
|
fdd8691e2e | ||
|
|
621a637b85 | ||
|
|
639e436854 | ||
|
|
81741919a8 |
@@ -1,4 +1,28 @@
|
|||||||
node_modules/
|
.svelte-kit
|
||||||
|
.vite
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
build
|
||||||
|
.cache
|
||||||
|
.DS_Store
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
coverage
|
||||||
|
tests
|
||||||
|
documentation
|
||||||
|
backups
|
||||||
|
*.log
|
||||||
|
*.bak
|
||||||
|
*.tgz
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
npm-debug.log
|
||||||
|
package-lock.json.bak
|
||||||
|
yarn-error.log
|
||||||
|
/.cache
|
||||||
|
/.parcel-cachenode_modules/
|
||||||
build/
|
build/
|
||||||
.svelte-kit/
|
.svelte-kit/
|
||||||
.git/
|
.git/
|
||||||
|
|||||||
10
.prettierrc
10
.prettierrc
@@ -4,6 +4,14 @@
|
|||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"trailingComma": "none",
|
"trailingComma": "none",
|
||||||
"printWidth": 80,
|
"printWidth": 80,
|
||||||
"plugins": ["prettier-plugin-svelte"],
|
"bracketSameLine": true,
|
||||||
|
|
||||||
|
"svelteSortOrder": "options-scripts-markup-styles",
|
||||||
|
"svelteIndentScriptAndStyle": false,
|
||||||
|
"svelteAllowShorthand": true,
|
||||||
|
"plugins": [
|
||||||
|
"prettier-plugin-svelte",
|
||||||
|
"prettier-plugin-tailwindcss"
|
||||||
|
],
|
||||||
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
|
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,10 +100,9 @@ src/routes/
|
|||||||
|
|
||||||
## Active Issues (check TODO__Agents.md for current state)
|
## Active Issues (check TODO__Agents.md for current state)
|
||||||
|
|
||||||
- Session/Presentation page cold-start bug (Events Pres Mgmt) — unresolved
|
- Sev-1: `PUBLIC_AE_API_SECRET_KEY` audit — see TODO__Agents.md (assessed acceptable, 2026-03-11)
|
||||||
- Sev-1: `PUBLIC_AE_API_SECRET_KEY` audit
|
- V3 CRUD migration — remaining legacy API wrappers in events/sponsorships/core (see `PROJECT__Use_AE_API_V3_CRUD_upgrade.md`)
|
||||||
- CRUD v2 retirement → V3 editor
|
- Style Review Phase 3 — IDAA + Pres Mgmt card polish deferred post-April 2026 conference
|
||||||
- 403/401 error boundaries ("Session Expired" UI)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -117,4 +116,4 @@ src/routes/
|
|||||||
| `documentation/GUIDE__SvelteKit2_Svelte5_DexieJS.md` | Dexie + liveQuery patterns |
|
| `documentation/GUIDE__SvelteKit2_Svelte5_DexieJS.md` | Dexie + liveQuery patterns |
|
||||||
| `documentation/GEMINI__Svelte_and_Me.md` | Svelte 5 runes patterns |
|
| `documentation/GEMINI__Svelte_and_Me.md` | Svelte 5 runes patterns |
|
||||||
| `documentation/PROJECT__AE_Events_Launcher_Native_integration.md` | Electron/Launcher |
|
| `documentation/PROJECT__AE_Events_Launcher_Native_integration.md` | Electron/Launcher |
|
||||||
| `documentation/PROJECT__AE_Pres_Mgmt_Session_view_refactor_2026-02.md` | Session bug plan |
|
| `documentation/PROJECT__AE_Events_Badges_Review_Print.md` | Badges — kiosk editing (Task 4.0 open) |
|
||||||
|
|||||||
@@ -116,8 +116,8 @@ Built on the Events object.
|
|||||||
|
|
||||||
Developer sandbox pages — not for production use.
|
Developer sandbox pages — not for production use.
|
||||||
|
|
||||||
- `/testing/ae_obj_field_editor_v3/` — V3 field editor playground
|
- `/testing/ae_obj_field_editor/` — V3 field editor playground
|
||||||
- `/testing/data_store_v3/` — Data store V3 playground
|
- `/testing/data_store/` — Data store V3 playground
|
||||||
- `/testing/editor_test/` — CodeMirror / TipTap editor tests
|
- `/testing/editor_test/` — CodeMirror / TipTap editor tests
|
||||||
- `/testing/hosted_files/` — File upload tests
|
- `/testing/hosted_files/` — File upload tests
|
||||||
|
|
||||||
|
|||||||
27
aether_container_env/Dockerfile.buildkit.example
Normal file
27
aether_container_env/Dockerfile.buildkit.example
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
## BuildKit-friendly multi-stage Dockerfile example for Aether frontend
|
||||||
|
|
||||||
|
# Stage 1: dependencies
|
||||||
|
FROM node:20-alpine AS deps
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package.json package-lock.json ./
|
||||||
|
RUN npm ci --no-audit --prefer-offline
|
||||||
|
|
||||||
|
# Stage 2: build
|
||||||
|
FROM node:20-alpine AS build
|
||||||
|
WORKDIR /app
|
||||||
|
# optionally reuse deps from previous stage
|
||||||
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
|
COPY . .
|
||||||
|
# If you want to use BuildKit cache mounts during local development, uncomment the next line
|
||||||
|
# RUN --mount=type=cache,target=/root/.npm npm ci
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Stage 3: runtime (static site served by nginx)
|
||||||
|
FROM nginx:stable-alpine AS runtime
|
||||||
|
COPY --from=build /app/build /usr/share/nginx/html
|
||||||
|
EXPOSE 80
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
|
|
||||||
|
# Notes:
|
||||||
|
# - Keep dependency installation separate from copying source to maximize cache hits when only application code changes.
|
||||||
|
# - For backend images, follow the same pattern: install deps early, copy source later, and keep a small final runtime image.
|
||||||
33
aether_container_env/ci_buildx_example.sh
Normal file
33
aether_container_env/ci_buildx_example.sh
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Example CI script to build and push an image with buildx using registry cache.
|
||||||
|
# This script is provider-agnostic and intended to be run inside CI where
|
||||||
|
# Docker and buildx are available and authenticated against the registry.
|
||||||
|
|
||||||
|
REGISTRY=${REGISTRY:-ghcr.io/ORG/REPO}
|
||||||
|
IMAGE_TAG=${IMAGE_TAG:-staging}
|
||||||
|
CACHE_REF=${CACHE_REF:-${REGISTRY}:cache}
|
||||||
|
|
||||||
|
echo "Building ${REGISTRY}:${IMAGE_TAG} using registry cache ${CACHE_REF}"
|
||||||
|
|
||||||
|
docker buildx build \
|
||||||
|
--push \
|
||||||
|
--tag ${REGISTRY}:${IMAGE_TAG} \
|
||||||
|
--cache-from type=registry,ref=${CACHE_REF} \
|
||||||
|
--cache-to type=registry,ref=${CACHE_REF},mode=max \
|
||||||
|
.
|
||||||
|
|
||||||
|
echo "Build complete. Image: ${REGISTRY}:${IMAGE_TAG}"
|
||||||
|
|
||||||
|
# Optional: instruct devs how to run locally with a local cache
|
||||||
|
cat <<'EOF'
|
||||||
|
Local test with BuildKit and local cache:
|
||||||
|
DOCKER_BUILDKIT=1 docker build \
|
||||||
|
--tag myapp:staging \
|
||||||
|
--cache-to=type=local,dest=/tmp/docker-cache \
|
||||||
|
--cache-from=type=local,src=/tmp/docker-cache .
|
||||||
|
|
||||||
|
Prune local builder cache older than 72 hours:
|
||||||
|
docker builder prune --filter "until=72h" --force
|
||||||
|
EOF
|
||||||
30
documentation/AE_Docker_CI_cache_policy.md
Normal file
30
documentation/AE_Docker_CI_cache_policy.md
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# AE Docker CI Cache Policy (recommendation)
|
||||||
|
|
||||||
|
Purpose
|
||||||
|
- Provide a straightforward policy to keep build caches useful but bounded.
|
||||||
|
|
||||||
|
Recommendations
|
||||||
|
- Primary CI cache: **registry-based buildx cache** (preferred). Use a single cache ref (e.g. `ghcr.io/ORG/REPO:cache`) reused by CI builds.
|
||||||
|
- Local dev cache: use `--cache-to type=local` for fast iteration but prune periodically.
|
||||||
|
- Retention: keep registry cache for 30 days by default. Implement registry GC or lifecycle rule to delete older cache blobs.
|
||||||
|
|
||||||
|
Rotation strategy
|
||||||
|
- Option A (simple): CI always writes to the same cache ref `:cache`. Periodically (monthly) run a job to `docker pull` and `docker image rm` older tags if you use date-based tagging.
|
||||||
|
- Option B (date-tag): CI writes cache to `cache-YYYYMMDD` and a small scheduled job deletes tags older than 30 days.
|
||||||
|
|
||||||
|
Pruning commands (developer)
|
||||||
|
- Remove local build cache older than 72 hours:
|
||||||
|
```bash
|
||||||
|
docker builder prune --filter "until=72h" --force
|
||||||
|
```
|
||||||
|
- Remove all builder cache (aggressive):
|
||||||
|
```bash
|
||||||
|
docker builder prune --all --force
|
||||||
|
```
|
||||||
|
|
||||||
|
CI runner requirements
|
||||||
|
- `docker` and `docker buildx` available in runner environment.
|
||||||
|
- Registry credentials provided via CI secrets with permission to push/pull images.
|
||||||
|
|
||||||
|
Security & Secrets
|
||||||
|
- Do not store registry credentials in repo. Use CI secret storage.
|
||||||
@@ -575,7 +575,6 @@ This document provides a reference for the data structures of the core Aether AP
|
|||||||
- `orders_info`: `Optional[dict]`
|
- `orders_info`: `Optional[dict]`
|
||||||
- `order_list`: `Optional[list]`
|
- `order_list`: `Optional[list]`
|
||||||
- `order_cart`: `Optional[dict]`
|
- `order_cart`: `Optional[dict]`
|
||||||
- `order_cart_v3`: `Optional[dict]`
|
|
||||||
- `organization`: `Optional[Union[Organization_Base, None]]`
|
- `organization`: `Optional[Union[Organization_Base, None]]`
|
||||||
- `post_list`: `Optional[list]`
|
- `post_list`: `Optional[list]`
|
||||||
- `user`: `Optional[Union[User_Base, None]]`
|
- `user`: `Optional[Union[User_Base, None]]`
|
||||||
|
|||||||
@@ -16,9 +16,8 @@ The Aether project is a Svelte and SvelteKit based application, utilizing Tailwi
|
|||||||
- Flowbite (Tailwind Components)
|
- Flowbite (Tailwind Components)
|
||||||
- Custom Components (a growing library of `ae_comp__*` and `element_*` components)
|
- Custom Components (a growing library of `ae_comp__*` and `element_*` components)
|
||||||
- **Text/Code Editors:**
|
- **Text/Code Editors:**
|
||||||
- CodeMirror 6.x (primary text and code editor, planned for rich text editing)
|
- CodeMirror 6.x (`element_editor_codemirror.svelte`) — source/code editing, markdown
|
||||||
- Edra (TipTap based Rich Text Editor)
|
- TipTap (`element_editor_tiptap.svelte`) — WYSIWYG rich-text for content fields (IDAA, Journals, Leads notes)
|
||||||
- **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)
|
- **Icons:** Lucide Icons (SVG Icons)
|
||||||
- **Markdown Parsing:** `marked` library
|
- **Markdown Parsing:** `marked` library
|
||||||
- **State Management:** Svelte stores, potentially with `liveQuery` from Dexie for reactive IndexedDB interactions.
|
- **State Management:** Svelte stores, potentially with `liveQuery` from Dexie for reactive IndexedDB interactions.
|
||||||
|
|||||||
@@ -40,9 +40,9 @@ These are reusable components that provide common functionalities across differe
|
|||||||
- **`copy_btn`**: A button to copy content to the clipboard.
|
- **`copy_btn`**: A button to copy content to the clipboard.
|
||||||
- Properties: `clipboard`, `bind:value`, `btn_text`, `btn_html`.
|
- Properties: `clipboard`, `bind:value`, `btn_text`, `btn_html`.
|
||||||
- **`txt_editor`**: A basic text area editor.
|
- **`txt_editor`**: A basic text area editor.
|
||||||
- **`md_editor`**: Markdown editor.
|
- **`md_editor`**: Markdown/rich-text editing handled by two active components:
|
||||||
- Uses CodeMirror (planned for rich text editing).
|
- `element_editor_codemirror.svelte` — CodeMirror 6, used for source/code editing
|
||||||
- **Note:** ShadEditor TipTap is present but marked for removal. ShadCN components are also being phased out in favor of CodeMirror for text editing.
|
- `element_editor_tiptap.svelte` — TipTap (WYSIWYG), used for rich-text content fields
|
||||||
- **`html_editor`**: HTML editor.
|
- **`html_editor`**: HTML editor.
|
||||||
- **`media_player`**: Component for playing media files.
|
- **`media_player`**: Component for playing media files.
|
||||||
- Properties: `hosted_file`, `archive_content`, `media_player`.
|
- Properties: `hosted_file`, `archive_content`, `media_player`.
|
||||||
@@ -62,13 +62,11 @@ These are reusable components that provide common functionalities across differe
|
|||||||
- Bindings: `bind:trigger`, `bind:show_spinner`, `bind:show_percent`.
|
- Bindings: `bind:trigger`, `bind:show_spinner`, `bind:show_percent`.
|
||||||
- Status: `started`, `downloading`, `finished`.
|
- Status: `started`, `downloading`, `finished`.
|
||||||
- **`data_store`**: Component for interacting with data stores.
|
- **`data_store`**: Component for interacting with data stores.
|
||||||
- **`ae_crud`**: Generic CRUD (Create, Read, Update, Delete) component.
|
- **`element_ae_obj_field_editor`**: Standard single-field inline editor. Replaces retired `ae_crud` v1/v2 components.
|
||||||
- **Note:** Needs simplification.
|
- Props: `object_type`, `object_id`, `field_name`, `field_type`, `current_value`
|
||||||
- Properties: `obj`, `prop`, `current_value`.
|
- Field types: `text`, `textarea`, `select`, `tiptap`, `checkbox`, `date`, `datetime`, `number`
|
||||||
- Bindings: `bind:value`, `bind:trigger`, `inner fragment`.
|
- Callbacks: `on_success`, `on_error`
|
||||||
- **`ae_obj_prop_val`**: A wrapper for a function to manage object property values.
|
- Respects `$ae_loc.edit_mode` — edit trigger hidden when edit mode is off.
|
||||||
- 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.
|
- **`sql_qry`**: Component for executing SQL queries.
|
||||||
- **`obj_tbl`**: Object SQL results table or similar.
|
- **`obj_tbl`**: Object SQL results table or similar.
|
||||||
- **`qr_scanner`**: Component for scanning QR codes.
|
- **`qr_scanner`**: Component for scanning QR codes.
|
||||||
|
|||||||
@@ -68,39 +68,145 @@ Modify data in the system.
|
|||||||
* **Header:** `x-ae-ignore-extra-fields: true`
|
* **Header:** `x-ae-ignore-extra-fields: true`
|
||||||
* **Behavior:** When set to `true`, the backend will automatically strip any fields from the payload that are not defined in the object's model before attempting to save to the database.
|
* **Behavior:** When set to `true`, the backend will automatically strip any fields from the payload that are not defined in the object's model before attempting to save to the database.
|
||||||
|
|
||||||
|
### D. ID Fields in Responses (Vision ID Convention)
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> **V3 responses always use random string IDs — never database integers.**
|
||||||
|
|
||||||
|
After a successful `POST` create or any `GET`, the response contains:
|
||||||
|
|
||||||
|
| Field | Type | Use |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| `{obj_type}_id` | `string` | **Primary public ID.** Use this for subsequent `PATCH` calls and UI routing. |
|
||||||
|
| `{obj_type}_id_random` | `string` | Legacy alias. Same value as `{obj_type}_id`. Present for backward compat only. |
|
||||||
|
|
||||||
|
**Example — create then immediately PATCH:**
|
||||||
|
```ts
|
||||||
|
const created = await postArchiveContent(archiveId, payload);
|
||||||
|
const newId = created.data.archive_content_id; // random string e.g. "xK9mP3qRtL2"
|
||||||
|
|
||||||
|
// Use it directly in the PATCH URL — no lookup needed
|
||||||
|
await patchArchiveContent(newId, { name: 'Updated Name' });
|
||||||
|
// PATCH /v3/crud/archive/{archive_id}/archive_content/{newId}
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Note on `_id_random` suffix:** The `{obj_type}_id_random` field is a legacy artifact from the pre-Vision model. Once you confirm `{obj_type}_id` is a random string (length 11–22), you do not need `_id_random` as a fallback. New code should only read `{obj_type}_id`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4. V3 Uniform Lookup System
|
## 4. V3 Uniform Lookup System
|
||||||
|
|
||||||
The V3 Lookup system provides a hierarchical, deduplicated interface for standardized tables (Countries, Timezones, etc.). It supports global defaults, account overrides, and site-specific whitelisting.
|
The V3 Lookup system provides a hierarchical, deduplicated interface for standardized reference tables (Countries, Timezones, etc.). It supports global defaults, account-level overrides, and object-level overrides, with optional site-specific whitelisting.
|
||||||
|
|
||||||
|
### How the hierarchy works
|
||||||
|
|
||||||
|
Each lookup table (`lu_v3_country`, `lu_v3_time_zone`, etc.) can hold multiple rows for the same logical item at different scopes:
|
||||||
|
|
||||||
|
| Scope | `account_id` | `for_type` / `for_id` | Wins over |
|
||||||
|
|---|---|---|---|
|
||||||
|
| Global default | `NULL` | `NULL` / `NULL` | nothing |
|
||||||
|
| Account override | set | `NULL` / `NULL` | Global default |
|
||||||
|
| Object override | set | set | Account override + Global default |
|
||||||
|
|
||||||
|
The API uses `ROW_NUMBER() PARTITION BY group` to collapse all rows for the same item down to the single highest-priority winner before returning results. **`group` is the identity key** — it is what makes two rows "the same item competing for priority."
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> **The `group` field is not a display label.** It is the deduplication key. Each lookup type uses a different natural key for `group`:
|
||||||
|
>
|
||||||
|
> | Lookup type | `group` value | Example |
|
||||||
|
> |---|---|---|
|
||||||
|
> | `country` | ISO alpha-2 code | `"US"`, `"CA"`, `"GB"` |
|
||||||
|
> | `country_subdivision` | subdivision code | `"US-NY"`, `"CA-ON"` |
|
||||||
|
> | `time_zone` | IANA timezone name | `"America/New_York"`, `"US/Eastern"` |
|
||||||
|
>
|
||||||
|
> For `time_zone`, `group` and `name` must always be identical — there is no concept of "override all US timezones as a group." Each timezone is its own identity.
|
||||||
|
|
||||||
### A. List Lookups
|
### A. List Lookups
|
||||||
Retrieve a ranked and filtered list of lookup items.
|
|
||||||
|
Retrieve the deduplicated, ranked list for a lookup type.
|
||||||
|
|
||||||
* **Endpoint:** `GET /v3/lookup/{lu_type}/list`
|
* **Endpoint:** `GET /v3/lookup/{lu_type}/list`
|
||||||
* **Available Types:** `country`, `country_subdivision`, `time_zone`
|
* **Available Types:** `country`, `country_subdivision`, `time_zone`
|
||||||
* **Parameters:**
|
* **Parameters:**
|
||||||
* `site_id` (Optional): Random ID of the site to apply a **Whitelist Policy**.
|
* `site_id` (Optional): Random ID of the site — applies a **Whitelist Policy** (see §C).
|
||||||
* `only_priority` (Optional): Set to `true` to return only high-priority items (e.g., common time zones).
|
* `only_priority` (Optional): `true` returns only `priority=1` items (e.g., common time zones).
|
||||||
* `for_type` / `for_id` (Optional): Context for object-specific overrides.
|
* `for_type` / `for_id` (Optional): Object context — activates object-level override matching.
|
||||||
* `include_disabled` (Optional): Set to `true` to see shadowed/disabled records.
|
* `include_disabled` (Optional): `true` includes shadowed/disabled records (useful for admin views).
|
||||||
|
|
||||||
|
**Frontend keying:** Always key Svelte `{#each}` blocks on `group`, not `id` or `name`. `group` is guaranteed unique in the response. Keying on `id` will break if an account override wins (different `id`, same logical item).
|
||||||
|
|
||||||
### B. Resolve Identity
|
### B. Resolve Identity
|
||||||
Resolves a string (code, group, or name) to a single record.
|
|
||||||
|
Resolves a string to a single lookup record.
|
||||||
|
|
||||||
* **Endpoint:** `GET /v3/lookup/{lu_type}/resolve?q=VALUE`
|
* **Endpoint:** `GET /v3/lookup/{lu_type}/resolve?q=VALUE`
|
||||||
* **Usage:** Use this when you have an external code (e.g., ISO "US") and need the full Aether record.
|
* **Usage:** Use when you have an external code (e.g., ISO `"US"`) and need the full Aether record. Scans `name`, `group`, and other identity fields.
|
||||||
|
|
||||||
### C. Site Whitelist Policy
|
### C. Site Whitelist Policy
|
||||||
To limit lookups for a specific site, add a `lookup_policy` to the `site.cfg_json` field.
|
|
||||||
**Schema:**
|
To restrict which lookup items appear for a specific site, add a `lookup_policy` to `site.cfg_json`:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"lookup_policy": {
|
"lookup_policy": {
|
||||||
"country": ["US", "CA", "GB"],
|
"country": ["US", "CA", "GB"],
|
||||||
"time_zone": ["America/New_York"]
|
"time_zone": ["America/New_York", "US/Eastern"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
*Note: Whitelist values must match the `group` field in the database.*
|
|
||||||
|
> **Whitelist values must match the `group` field** — i.e., the natural key for that type (ISO code for country, IANA name for time zone). Using a display name will silently return no results for that item.
|
||||||
|
|
||||||
|
### D. Adding and managing client overrides
|
||||||
|
|
||||||
|
When a client needs a customized label or wants to hide/reorder lookup items, create override records rather than modifying global defaults.
|
||||||
|
|
||||||
|
**Rules:**
|
||||||
|
1. **Never modify global default rows** (`account_id = NULL`). Those are shared across all accounts. Any change there affects every client.
|
||||||
|
2. **Set `group` to the exact same value as the global default row** for the item you are overriding. If `group` doesn't match, the override creates a new item instead of replacing the existing one.
|
||||||
|
3. **Set `account_id`** to the client's account ID. Leave `for_type` / `for_id` null unless the override is specific to a single object (e.g., one site).
|
||||||
|
|
||||||
|
**Example — rename "US/Eastern" for one account:**
|
||||||
|
|
||||||
|
```sql
|
||||||
|
INSERT INTO lu_v3_time_zone
|
||||||
|
(account_id, name, name_override, `group`, enable, priority, sort)
|
||||||
|
VALUES
|
||||||
|
(42, 'US/Eastern', 'Eastern Time (Client Label)', 'US/Eastern', 1, 1, 50);
|
||||||
|
```
|
||||||
|
|
||||||
|
The `name_override` field is the display label the frontend should prefer when set. `group = 'US/Eastern'` ensures this row competes with — and wins over — the global default in the `PARTITION BY group` deduplication.
|
||||||
|
|
||||||
|
**To disable an item for one account** (hide it from their dropdowns):
|
||||||
|
|
||||||
|
```sql
|
||||||
|
INSERT INTO lu_v3_time_zone
|
||||||
|
(account_id, name, `group`, enable)
|
||||||
|
VALUES
|
||||||
|
(42, 'US/Samoa', 'US/Samoa', 0);
|
||||||
|
```
|
||||||
|
|
||||||
|
Setting `enable = 0` on an account-scoped row shadows the global default for that account only.
|
||||||
|
|
||||||
|
**To remove a client override** (revert to global default):
|
||||||
|
|
||||||
|
Simply delete the row where `account_id = <client>` and `group = '<item>'`. The global default row is unaffected and immediately resumes winning.
|
||||||
|
|
||||||
|
### E. Adding new global lookup items
|
||||||
|
|
||||||
|
When seeding new lookup data (e.g., adding timezones in bulk):
|
||||||
|
|
||||||
|
1. Set `group = name` for every row (for `time_zone`). This is a hard invariant — if `group` is set to a regional label like `"United States"` instead of the timezone name, the entire group collapses to a single winner and all but one entry disappear from the API response.
|
||||||
|
2. Set `account_id = NULL` and `for_type = NULL` / `for_id = NULL` for global defaults.
|
||||||
|
3. After seeding, verify with:
|
||||||
|
```sql
|
||||||
|
-- Should return 0 rows; any result means multiple items will collapse into one
|
||||||
|
SELECT `group`, COUNT(*) AS cnt
|
||||||
|
FROM lu_v3_time_zone
|
||||||
|
WHERE account_id IS NULL
|
||||||
|
GROUP BY `group`
|
||||||
|
HAVING cnt > 1;
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Aether UI — Design System Style Guidelines
|
# Aether UI — Design System Style Guidelines
|
||||||
> **Version:** 1.1 (2026-03-17)
|
> **Version:** 1.2 (2026-03-20)
|
||||||
> **Author:** One Sky IT / Scott Idem
|
> **Author:** One Sky IT / Scott Idem
|
||||||
> **Scope:** All Aether SvelteKit frontend components
|
> **Scope:** All Aether SvelteKit frontend components
|
||||||
> **Related:** `AE__UI_Component_Patterns.md`, `ae-firefly.css`, `documentation/AE__Components.md`
|
> **Related:** `AE__UI_Component_Patterns.md`, `ae-firefly.css`, `documentation/AE__Components.md`
|
||||||
@@ -34,6 +34,7 @@ To maintain codebase health and performance, all new development must adhere to
|
|||||||
- **Mandatory**: Use `preset-*` classes for interactive elements (e.g., `preset-tonal-primary`).
|
- **Mandatory**: Use `preset-*` classes for interactive elements (e.g., `preset-tonal-primary`).
|
||||||
- **Forbidden**: Legacy Skeleton v3 `variant-*` classes.
|
- **Forbidden**: Legacy Skeleton v3 `variant-*` classes.
|
||||||
- **Customization**: Use Tailwind 4 `@theme` blocks for project-wide overrides.
|
- **Customization**: Use Tailwind 4 `@theme` blocks for project-wide overrides.
|
||||||
|
- **URLs**: Skeleton for Svelte for LLMs docs: https://www.skeleton.dev/llms-svelte.txt
|
||||||
|
|
||||||
### 🔣 Lucide Icons
|
### 🔣 Lucide Icons
|
||||||
- **Mandatory**: Use `@lucide/svelte` components (e.g., `<Calendar size="1em" />`).
|
- **Mandatory**: Use `@lucide/svelte` components (e.g., `<Calendar size="1em" />`).
|
||||||
@@ -192,6 +193,7 @@ Always wrap in `{#if $lq__obj}{...}{:else}...skeleton...{/if}` — **never** sho
|
|||||||
| Form inputs | Visible `<label>` linked via `for` / `id`, or explicit `aria-label` |
|
| Form inputs | Visible `<label>` linked via `for` / `id`, or explicit `aria-label` |
|
||||||
| Color-only information | Always pair color coding with icon or text — never color alone |
|
| Color-only information | Always pair color coding with icon or text — never color alone |
|
||||||
| Minimum touch target | 44×44px effective hit area for all tap targets |
|
| Minimum touch target | 44×44px effective hit area for all tap targets |
|
||||||
|
| Button label + icon | All buttons should include **both a Lucide icon and text label**. Icon-only is acceptable for space-constrained toolbar/header actions (with `title` attribute); text-only is acceptable when layout is extremely tight. The icon+text combination aids non-English-native users who may not read the label fluently. |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -241,3 +243,34 @@ $events_sess.pres_mgmt.session_qr_url[$lq__obj.id] = result; // ← URL string
|
|||||||
- **`text-sm leading-relaxed`**: Standard for body-level descriptive text in cards.
|
- **`text-sm leading-relaxed`**: Standard for body-level descriptive text in cards.
|
||||||
- **`tracking-wide uppercase`**: Use for section label/eyebrow text with `opacity-40`.
|
- **`tracking-wide uppercase`**: Use for section label/eyebrow text with `opacity-40`.
|
||||||
- **`whitespace-pre-wrap`**: Required for any `<pre>` or `<p>` displaying user-entered multi-line text (preserves breaks without horizontal overflow).
|
- **`whitespace-pre-wrap`**: Required for any `<pre>` or `<p>` displaying user-entered multi-line text (preserves breaks without horizontal overflow).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. Known Issues & Workarounds
|
||||||
|
|
||||||
|
### `btn` + `preset-filled-*` resolves to transparent inside `card` components
|
||||||
|
|
||||||
|
**Symptom:** A button using `btn preset-filled-primary` (or any `preset-filled-*`) inside a `card` div renders with `background-color: transparent`, making it invisible against the card surface.
|
||||||
|
|
||||||
|
**Root cause:** The Skeleton v4 `btn` class sets a transparent background via a CSS variable chain. When nested inside a `card` element, the `preset-filled-*` class fails to win the specificity battle and the button appears invisible. This affects both light and dark mode.
|
||||||
|
|
||||||
|
**Workaround:** Skip `btn` and `preset-filled-*` entirely for buttons inside `card` elements. Use direct Tailwind token classes instead:
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
<!-- ✅ Correct — works reliably inside cards -->
|
||||||
|
<button class="w-full rounded-xl py-5 font-bold flex items-center justify-center gap-2
|
||||||
|
bg-primary-500 text-white hover:brightness-110 transition-all cursor-pointer">
|
||||||
|
...
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Secondary / cancel button inside a card -->
|
||||||
|
<button class="w-full rounded-lg py-3 text-sm font-medium flex items-center justify-center gap-2
|
||||||
|
border border-surface-500/40 hover:bg-surface-200-800 transition-colors cursor-pointer opacity-70">
|
||||||
|
...
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- ❌ Broken inside card — do not use -->
|
||||||
|
<button class="btn btn-xl preset-filled-primary">...</button>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Scope:** `btn` + `preset-*` classes work correctly on standalone buttons (e.g. page headers, nav bars). The issue is specific to the `card` component context. If we migrate away from Skeleton `card`/`btn`, this issue goes away.
|
||||||
|
|||||||
@@ -11,6 +11,11 @@
|
|||||||
2. **Type Safety:** Ensure interfaces in `src/lib/types/ae_types.ts` match backend schemas.
|
2. **Type Safety:** Ensure interfaces in `src/lib/types/ae_types.ts` match backend schemas.
|
||||||
3. **Reactivity Check:** Verify Svelte 5 runes (`$state`, `$derived`) are not creating race conditions with Dexie `liveQuery`.
|
3. **Reactivity Check:** Verify Svelte 5 runes (`$state`, `$derived`) are not creating race conditions with Dexie `liveQuery`.
|
||||||
4. **Build Check:** For major changes, run `npm run build:staging` to ensure no SSR or build-time failures.
|
4. **Build Check:** For major changes, run `npm run build:staging` to ensure no SSR or build-time failures.
|
||||||
|
5. **Integration Tests:** For changes to badge print, event layouts, or auth/store logic, run the relevant Playwright test file(s):
|
||||||
|
```bash
|
||||||
|
npx playwright test tests/event_badge_render.test.ts tests/event_badge_attendee_workflow.test.ts
|
||||||
|
```
|
||||||
|
Run the full suite with `npm run test:integration`. The badge tests (`event_badge_*.test.ts`) are the canonical integration test template.
|
||||||
|
|
||||||
## 2. Commit Policy
|
## 2. Commit Policy
|
||||||
- **Atomic Commits:** One component or one logic fix per commit. Do not batch unrelated changes.
|
- **Atomic Commits:** One component or one logic fix per commit. Do not batch unrelated changes.
|
||||||
@@ -46,8 +51,81 @@ You are not working in a vacuum. Coordinate with the Backend Agent via MCP tools
|
|||||||
| `documentation/AE__Architecture.md` | System architecture overview |
|
| `documentation/AE__Architecture.md` | System architecture overview |
|
||||||
| `documentation/AE__Naming_Conventions.md` | Naming rules |
|
| `documentation/AE__Naming_Conventions.md` | Naming rules |
|
||||||
| `documentation/PROJECT__AE_Events_Launcher_Native_integration.md` | Electron/Launcher reference |
|
| `documentation/PROJECT__AE_Events_Launcher_Native_integration.md` | Electron/Launcher reference |
|
||||||
|
| `tests/README.md` | Playwright test guide — shared helpers, hard-won lessons, demo IDs |
|
||||||
|
|
||||||
## 6. URL Parameters
|
## 6. Inline Field Editing — `element_ae_obj_field_editor`
|
||||||
|
|
||||||
|
The standard component for single-field inline editing throughout the platform. Wraps a `PATCH /v3/crud/{obj_type}/{obj_id}` call behind a click-to-edit UI that respects `$ae_loc.edit_mode`.
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
import Element_ae_obj_field_editor from '$lib/elements/element_ae_obj_field_editor.svelte';
|
||||||
|
```
|
||||||
|
|
||||||
|
### Basic usage — text field with custom display
|
||||||
|
|
||||||
|
Wrap the display content in the default snippet. The component renders it in view mode and swaps in the input on edit.
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
<Element_ae_obj_field_editor
|
||||||
|
object_type={'event_session'}
|
||||||
|
object_id={session.id}
|
||||||
|
field_name={'name'}
|
||||||
|
field_type={'text'}
|
||||||
|
current_value={session.name}
|
||||||
|
on_success={() => events_func.load_ae_obj_id__event_session({ api_cfg: $ae_api, event_session_id: session.id })}
|
||||||
|
>
|
||||||
|
<h1 class="text-2xl font-bold">{session.name}</h1>
|
||||||
|
</Element_ae_obj_field_editor>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Field types
|
||||||
|
|
||||||
|
| `field_type` | Input rendered |
|
||||||
|
| --- | --- |
|
||||||
|
| `text` (default) | `<input type="text">` — Enter key saves |
|
||||||
|
| `textarea` | `<textarea>` — use `textarea_rows` prop |
|
||||||
|
| `select` | `<select>` — pass `select_options={{ value: 'Label' }}` |
|
||||||
|
| `checkbox` | `<input type="checkbox">` — shows Enabled/Disabled |
|
||||||
|
| `tiptap` | TipTap rich-text editor |
|
||||||
|
| `date` | `<input type="date">` |
|
||||||
|
| `datetime` | `<input type="datetime-local">` |
|
||||||
|
| `number` | `<input type="number">` — Enter key saves |
|
||||||
|
|
||||||
|
### Select with nullable FK
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
<Element_ae_obj_field_editor
|
||||||
|
object_type={'event_presenter'}
|
||||||
|
object_id={presenter.event_presenter_id}
|
||||||
|
field_name={'person_id'}
|
||||||
|
field_type={'select'}
|
||||||
|
current_value={presenter.person_id}
|
||||||
|
select_options={$slct.person_obj_kv}
|
||||||
|
allow_null={$ae_loc.administrator_access}
|
||||||
|
on_success={() => events_func.load_ae_obj_id__event_presenter({ api_cfg: $ae_api, event_presenter_id: presenter.event_presenter_id })}
|
||||||
|
>
|
||||||
|
{presenter.person_id ?? 'Not linked'}
|
||||||
|
</Element_ae_obj_field_editor>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key props
|
||||||
|
|
||||||
|
| Prop | Default | Notes |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `current_value` | — | Required. Bound with `$bindable` — liveQuery updates flow through automatically |
|
||||||
|
| `allow_null` | `false` | Shows a "Set Null" button in edit mode |
|
||||||
|
| `display_block` | `false` | Makes the wrapper `display: block` instead of `inline-block` |
|
||||||
|
| `on_success` | — | Callback after successful PATCH — use to trigger SWR cache refresh |
|
||||||
|
| `object_reload` | `true` | Triggers internal SWR reload after patch (in addition to `on_success`) |
|
||||||
|
|
||||||
|
### Behavior notes
|
||||||
|
- The edit trigger button is `visibility: hidden` (not `display: none`) when `$ae_loc.edit_mode` is off — this preserves layout so the page doesn't shift when edit mode toggles.
|
||||||
|
- Optimistic display: draft value is shown immediately after save; cleared once liveQuery confirms the update came back from the DB.
|
||||||
|
- `on_success` should always call the relevant `load_ae_obj_id__*` function to keep Dexie in sync.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. URL Parameters
|
||||||
|
|
||||||
URL params consumed by the app. Params are read by layouts and applied on mount.
|
URL params consumed by the app. Params are read by layouts and applied on mount.
|
||||||
|
|
||||||
|
|||||||
@@ -280,6 +280,66 @@ If you must use non-blocking loads, you must pass the initial data to the compon
|
|||||||
{/if}
|
{/if}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## The `untrack()` Reactive-Tracking Trap
|
||||||
|
|
||||||
|
`untrack()` is used inside `$effect` to read reactive values without registering them as tracked dependencies of that effect. This is correct for most "read-once" values (params, IDs) where you don't want the effect re-running on every change. But it has a silent failure mode: if a value you *need* to re-read is consumed inside `untrack()`, the effect becomes a one-shot and never retries when that value changes.
|
||||||
|
|
||||||
|
### Symptom
|
||||||
|
|
||||||
|
An effect runs once, reads a store value inside `untrack()`, takes an early-exit path (e.g. "no API key → skip"), and never retries — even after the store value is updated by a background process.
|
||||||
|
|
||||||
|
### Real Example (IDAA Novi Verification Bug — 2026-03-25)
|
||||||
|
|
||||||
|
The IDAA layout verifies Novi UUIDs. `site_cfg_json` (which contains the Novi API key) was read **inside** `untrack()`:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// BUG: site_cfg_json read inside untrack → one-shot, never retries
|
||||||
|
$effect(() => {
|
||||||
|
if (!browser) return;
|
||||||
|
const uuid = data.url.searchParams.get('uuid'); // tracked ✓
|
||||||
|
|
||||||
|
untrack(() => {
|
||||||
|
const site_cfg_json = $ae_loc.site_cfg_json; // ← NOT tracked ✗
|
||||||
|
const api_key = site_cfg_json?.novi_idaa_api_key ?? null;
|
||||||
|
if (!api_key) return; // exits silently on first load with stale cache
|
||||||
|
verify_novi_uuid(uuid, api_key, ...);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
On first load, the Dexie cache returned a stale `site_cfg_json` missing the API key. The effect exited early. The background refresh later updated `$ae_loc.site_cfg_json`, but because `site_cfg_json` was consumed inside `untrack()`, the effect never re-ran.
|
||||||
|
|
||||||
|
**Fix:** Move the dependency read **outside** `untrack()`:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// FIX: site_cfg_json tracked outside untrack → effect re-runs when it changes
|
||||||
|
$effect(() => {
|
||||||
|
if (!browser) return;
|
||||||
|
const uuid = data.url.searchParams.get('uuid'); // tracked ✓
|
||||||
|
const site_cfg_json = $ae_loc.site_cfg_json; // tracked ✓ — effect re-runs on change
|
||||||
|
|
||||||
|
untrack(() => {
|
||||||
|
// Guard: already verified for this UUID — don't repeat the round-trip
|
||||||
|
if ($idaa_loc.novi_verified && $idaa_loc.novi_uuid === uuid) return;
|
||||||
|
|
||||||
|
const api_key = site_cfg_json?.novi_idaa_api_key ?? null;
|
||||||
|
if (!api_key) return;
|
||||||
|
verify_novi_uuid(uuid, api_key, ...);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
The guard inside `untrack()` is important: without it, every unrelated change to `$ae_loc` would re-trigger verification.
|
||||||
|
|
||||||
|
### Rule of Thumb
|
||||||
|
|
||||||
|
Before wrapping a store read in `untrack()`, ask: **"Do I need this effect to re-run if this value changes?"**
|
||||||
|
|
||||||
|
- If yes → read it **outside** `untrack()`, and add a guard inside to prevent redundant work.
|
||||||
|
- If no → `untrack()` is correct.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Svelte 5 Binding Pitfalls
|
## Svelte 5 Binding Pitfalls
|
||||||
|
|
||||||
### 1. `props_invalid_value` (The "Expression Binding" Error)
|
### 1. `props_invalid_value` (The "Expression Binding" Error)
|
||||||
|
|||||||
@@ -358,7 +358,7 @@ Firefox users can use "Save to PDF" directly — it just works.
|
|||||||
|
|
||||||
- [x] Wire `style_href` via `<svelte:head>` in print page — done in `print/+page.svelte`; also in `properties_to_save`. (2026-03-18 verified)
|
- [x] Wire `style_href` via `<svelte:head>` in print page — done in `print/+page.svelte`; also in `properties_to_save`. (2026-03-18 verified)
|
||||||
- [x] Add `duplex` to `properties_to_save` — done. (2026-03-18 verified)
|
- [x] Add `duplex` to `properties_to_save` — done. (2026-03-18 verified)
|
||||||
- [x] Add `duplex`-driven suppression to `badge_back` section — done in `ae_comp__badge_obj_view_v2.svelte`; `show_badge_back` derived from `duplex` field. Note: v1 (`ae_comp__badge_obj_view.svelte`) was archived to `~/tmp/gemini_trash/`; v2 is canonical. (2026-03-18 verified)
|
- [x] Add `duplex`-driven suppression to `badge_back` section — done in `ae_comp__badge_obj_view.svelte`; `show_badge_back` derived from `duplex` field.
|
||||||
- [ ] Make `layout` field drive actual card dimensions in the badge component — currently the Zebra ZC10L layout CSS (`badge_layout_zebra_zc10l_pvc.css`) sets dimensions correctly via `[data-layout="..."]` scoping, but fanfold layouts still use Tailwind defaults. Needs proper CSS for each layout code.
|
- [ ] Make `layout` field drive actual card dimensions in the badge component — currently the Zebra ZC10L layout CSS (`badge_layout_zebra_zc10l_pvc.css`) sets dimensions correctly via `[data-layout="..."]` scoping, but fanfold layouts still use Tailwind defaults. Needs proper CSS for each layout code.
|
||||||
- [ ] Remove dead `exhibitor_info` / `presenter_info` / `staff_info` / `vip_info` / `vote_info` `{#if}` blocks from `ae_comp__badge_obj_view_v2.svelte` (if they were carried over from v1)
|
- [ ] Remove dead `exhibitor_info` / `presenter_info` / `staff_info` / `vip_info` / `vote_info` `{#if}` blocks from `ae_comp__badge_obj_view.svelte` (if they were carried over from v1)
|
||||||
- [ ] Improve `ae_comp__badge_template_form.svelte` to edit all relevant fields (currently minimal)
|
- [ ] Improve `ae_comp__badge_template_form.svelte` to edit all relevant fields (currently minimal)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
The Badges module manages event attendee badges with support for:
|
The Badges module manages event attendee badges with support for:
|
||||||
- **External system imports** (iMIS, Zoom, Novi, Impexium, Confex, Cvent, and others)
|
- **External system imports as needed** (CSV/Excel, iMIS, Zoom, Novi, Impexium, Confex, Cvent, and others)
|
||||||
- **Field override protection** to prevent staff/attendee edits from being overwritten by automated syncs
|
- **Field override protection** to prevent staff/attendee edits from being overwritten by automated syncs
|
||||||
- **Multi-tier access control** for field editing
|
- **Multi-tier access control** for field editing
|
||||||
- **QR code generation** for badge scanning
|
- **QR code generation** for badge scanning
|
||||||
@@ -535,8 +535,8 @@ Button has `data-testid="badge-print-btn"` and shows loading/done/error states w
|
|||||||
**Indexed Fields:**
|
**Indexed Fields:**
|
||||||
```typescript
|
```typescript
|
||||||
badge: `
|
badge: `
|
||||||
event_badge_id_random, event_badge_id, id,
|
event_badge_id, id,
|
||||||
event_id, event_id_random,
|
event_id,
|
||||||
full_name, full_name_override, email, email_override,
|
full_name, full_name_override, email, email_override,
|
||||||
affiliations, affiliations_override,
|
affiliations, affiliations_override,
|
||||||
badge_type, badge_type_code, badge_type_code_override, badge_type_override,
|
badge_type, badge_type_code, badge_type_code_override, badge_type_override,
|
||||||
@@ -704,7 +704,7 @@ delete_ae_obj_id__event_badge({ event_badge_id, event_id, method })
|
|||||||
|
|
||||||
### Key Test Lessons Learned
|
### Key Test Lessons Learned
|
||||||
|
|
||||||
**Search API path is FLAT, not nested.** `search_ae_obj_v3` builds `/v3/crud/{obj_type}/search` — always flat regardless of the parent relationship. Mocks must match this:
|
**Search API path is FLAT, not nested.** `search_ae_obj` builds `/v3/crud/{obj_type}/search` — always flat regardless of the parent relationship. Mocks must match this:
|
||||||
```typescript
|
```typescript
|
||||||
// CORRECT — flat path
|
// CORRECT — flat path
|
||||||
url.includes('/v3/crud/event_badge/search') && method === 'POST'
|
url.includes('/v3/crud/event_badge/search') && method === 'POST'
|
||||||
@@ -712,7 +712,7 @@ url.includes('/v3/crud/event_badge/search') && method === 'POST'
|
|||||||
url.includes(`/v3/crud/event/${event_id}/event_badge/search`) && method === 'POST'
|
url.includes(`/v3/crud/event/${event_id}/event_badge/search`) && method === 'POST'
|
||||||
```
|
```
|
||||||
|
|
||||||
**List API (GET) is also FLAT with query params.** `get_ae_obj_li_v3` builds `/v3/crud/{obj_type}/?for_obj_id=...` — always flat. Mocks must check `url.includes('/v3/crud/event_badge_template/') && url.includes('for_obj_id')`.
|
**List API (GET) is also FLAT with query params.** `get_ae_obj_li` builds `/v3/crud/{obj_type}/?for_obj_id=...` — always flat. Mocks must check `url.includes('/v3/crud/event_badge_template/') && url.includes('for_obj_id')`.
|
||||||
|
|
||||||
**CSS `input[value*=...]` selectors don't work with Svelte bind:value.** The CSS selector checks the HTML *attribute*; Svelte's `bind:value` sets the DOM *property* only. In Playwright tests, use `page.getByLabel()` or `locator.inputValue()` instead.
|
**CSS `input[value*=...]` selectors don't work with Svelte bind:value.** The CSS selector checks the HTML *attribute*; Svelte's `bind:value` sets the DOM *property* only. In Playwright tests, use `page.getByLabel()` or `locator.inputValue()` instead.
|
||||||
|
|
||||||
@@ -726,9 +726,9 @@ All API mock responses in tests need these fields.
|
|||||||
|
|
||||||
**Badge view requires both badge AND template.** `ae_comp__badge_obj_view.svelte` wraps everything in `{#if $lq__event_badge_obj && $lq__event_badge_template_obj}` — if the template isn't loaded, edit/print buttons and the badge itself don't render. Tests must mock the badge template endpoint.
|
**Badge view requires both badge AND template.** `ae_comp__badge_obj_view.svelte` wraps everything in `{#if $lq__event_badge_obj && $lq__event_badge_template_obj}` — if the template isn't loaded, edit/print buttons and the badge itself don't render. Tests must mock the badge template endpoint.
|
||||||
|
|
||||||
**Badge GET endpoint (single object):** `/v3/crud/event_badge/{id}` (NOT nested under event). Matches `api.get_ae_obj_v3()` which uses the flat path.
|
**Badge GET endpoint (single object):** `/v3/crud/event_badge/{id}` (NOT nested under event). Matches `api.get_ae_obj()` which uses the flat path.
|
||||||
|
|
||||||
**Badge PATCH endpoint (update):** `/v3/crud/event/${event_id}/event_badge/${badge_id}` (nested under event). Matches `api.patch_ae_obj_v3()` which uses the nested path.
|
**Badge PATCH endpoint (update):** `/v3/crud/event/${event_id}/event_badge/${badge_id}` (nested under event). Matches `api.patch_ae_obj()` which uses the nested path.
|
||||||
|
|
||||||
**Use `data-testid` for test selectors.** Key buttons have targets: `badge-edit-btn`, `badge-save-btn`, `badge-cancel-btn`, `badge-print-btn`, `badge-professional-title-input`.
|
**Use `data-testid` for test selectors.** Key buttons have targets: `badge-edit-btn`, `badge-save-btn`, `badge-cancel-btn`, `badge-print-btn`, `badge-professional-title-input`.
|
||||||
|
|
||||||
|
|||||||
207
documentation/MODULE__AE_Events_Badges_Onsite.md
Normal file
207
documentation/MODULE__AE_Events_Badges_Onsite.md
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
# Aether Events — Onsite Badge Printing
|
||||||
|
|
||||||
|
Notes on setup, process, hardware, and browser behavior for onsite badge printing at events.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Aether badge printing uses the browser's native `window.print()` — no special software or print
|
||||||
|
server needed. The badge render page (`/events/[event_id]/badges/print/[badge_id]`) outputs
|
||||||
|
print-ready HTML/CSS, and the browser sends it directly to the connected printer via CUPS (Linux)
|
||||||
|
or the OS print system (macOS/Windows).
|
||||||
|
|
||||||
|
Chrome (Chromium) is the recommended browser for onsite kiosk stations.
|
||||||
|
Firefox is a solid alternative, especially for Save-to-PDF workflows.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Recommended Workflow — Onsite Kiosk
|
||||||
|
|
||||||
|
1. Open the event's badge printing page: `/events/[event_id]/badges`
|
||||||
|
2. Search for the attendee (name, badge ID, or QR scan)
|
||||||
|
3. Open the badge print page — review the rendered badge
|
||||||
|
4. Click **Print Badge** in the controls panel (or use keyboard shortcut)
|
||||||
|
5. In the browser print dialog:
|
||||||
|
- Set Margins to **None** (Chrome) or leave defaults (Firefox)
|
||||||
|
- Confirm paper/card size matches the stock loaded in the printer
|
||||||
|
- Print
|
||||||
|
6. `print_count` increments automatically on each print via the Print Badge button
|
||||||
|
|
||||||
|
For high-volume events, consider the **rapid QR scan** mode in the Leads module or using a
|
||||||
|
dedicated kiosk session where the operator only handles physical card handoff.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Browser Settings
|
||||||
|
|
||||||
|
### Chrome / Chromium (Recommended for kiosk use)
|
||||||
|
|
||||||
|
Chrome is recommended for onsite badge printing stations. Key print dialog settings:
|
||||||
|
|
||||||
|
| Setting | Correct value | Notes |
|
||||||
|
|---|---|---|
|
||||||
|
| Margins | **None** or **Minimum** | Default margins add URL/date headers — breaks badge centering |
|
||||||
|
| Paper size | Match card stock (e.g. 3.5" × 5.5") | Zebra driver may override this automatically |
|
||||||
|
| Background graphics | **On** | Required for colored header/footer stripe to print |
|
||||||
|
| Pages | 1 | PVC single-sided — only front should print |
|
||||||
|
|
||||||
|
**Important:** Chrome ignores CSS `@page { size }` for Save to PDF — it defaults to letter/A4.
|
||||||
|
For physical printer output, the printer driver controls paper size. This is expected behavior.
|
||||||
|
|
||||||
|
To lock Chrome settings for a kiosk, set Margins to "None" once and Chrome remembers per-printer.
|
||||||
|
|
||||||
|
### Firefox
|
||||||
|
|
||||||
|
Firefox honors CSS `@page { size }` which makes it ideal for PDF generation.
|
||||||
|
For physical printing, Firefox generally "just works" without margin adjustments.
|
||||||
|
|
||||||
|
| Setting | Notes |
|
||||||
|
|---|---|
|
||||||
|
| Paper size | Can be set in dialog, but CSS `@page { size }` is honored |
|
||||||
|
| Margins | Default is usually fine; remove headers/footers if they appear |
|
||||||
|
| Background graphics | Enable for colored stripes and header images to print |
|
||||||
|
|
||||||
|
### General Notes
|
||||||
|
|
||||||
|
- **Background graphics must be enabled** in any browser — otherwise header images, footer
|
||||||
|
color stripes, and tonal backgrounds will not print.
|
||||||
|
- Private/incognito mode blocks PWA install prompts — use normal browser sessions for kiosk.
|
||||||
|
- For highest reliability, set the kiosk machine to auto-login and open Chrome to the event URL.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Linux / CUPS Setup
|
||||||
|
|
||||||
|
For Linux workstations and dedicated kiosk machines running Linux:
|
||||||
|
|
||||||
|
1. Install CUPS if not already present: `sudo pacman -S cups` (Arch) or equivalent
|
||||||
|
2. Start the CUPS service: `sudo systemctl enable --now cups`
|
||||||
|
3. Open the CUPS web UI: `http://localhost:631`
|
||||||
|
4. Add the printer and install the appropriate driver (see per-printer sections below)
|
||||||
|
5. Print a test page from CUPS to confirm card feed and quality
|
||||||
|
6. In Chrome: select the CUPS printer name under Destination in the print dialog
|
||||||
|
|
||||||
|
On macOS and Windows, use the vendor-provided driver installer.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Printers
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Zebra ZC10L — PVC Card Printer
|
||||||
|
|
||||||
|
**Card stock:** 3.5" × 5.5" PVC cards (CR80 extended)
|
||||||
|
**Tested:** 2026-03-17 (rental test day, Arch Linux)
|
||||||
|
**Status:** Working. Confirmed suitable for Axonius NYC (mid-April 2026).
|
||||||
|
|
||||||
|
#### Physical Setup
|
||||||
|
|
||||||
|
- Connect via USB (the ZC10L supports USB and Ethernet)
|
||||||
|
- Load PVC card stock per the Zebra loading instructions — cards face-up, landscape
|
||||||
|
- The ZC10L prints one side (single-sided dye-sub thermal); do not attempt duplex on PVC stock
|
||||||
|
|
||||||
|
#### Linux Driver
|
||||||
|
|
||||||
|
- Download the Zebra ZC10L CUPS driver from zebra.com (ZC Series Linux support)
|
||||||
|
- Install the `.deb` or extract the PPD file and add to CUPS manually
|
||||||
|
- In CUPS (`http://localhost:631`), add the printer and select the ZC10L PPD
|
||||||
|
- Set default paper size to **3.5" × 5.5"** (or CR80 Extended if listed)
|
||||||
|
- Print a blank test page from CUPS before using Chrome
|
||||||
|
|
||||||
|
> **Note:** Driver version tested: *(update here after confirming)*
|
||||||
|
> CUPS printer name used: *(update here after setup)*
|
||||||
|
|
||||||
|
#### Chrome Print Settings (ZC10L)
|
||||||
|
|
||||||
|
| Setting | Value |
|
||||||
|
|---|---|
|
||||||
|
| Destination | Zebra ZC10L (CUPS name) |
|
||||||
|
| Paper size | 3.5 × 5.5 in (or as set in CUPS) |
|
||||||
|
| Margins | **None** |
|
||||||
|
| Background graphics | On |
|
||||||
|
| Pages | 1 (front only) |
|
||||||
|
|
||||||
|
#### CSS Layout
|
||||||
|
|
||||||
|
The ZC10L uses the `badge_3.5x5.5_pvc` layout. The PVC layout CSS is at:
|
||||||
|
`src/routes/events/[event_id]/(badges)/badges/print/badge_layout_zebra_zc10l_pvc.css`
|
||||||
|
|
||||||
|
This layout hides `.badge_back` in `@media print` — only the front face prints.
|
||||||
|
`@page { size: 3.5in 5.5in; margin: 0; }` is set in the CSS.
|
||||||
|
|
||||||
|
#### Known Behaviors / Watch-outs
|
||||||
|
|
||||||
|
- Chrome with **Default** margins: inserts URL/date headers, offsets badge — use **None**
|
||||||
|
- Chrome with **None** or **Minimum** margins: correct output
|
||||||
|
- Firefox: works correctly out of the box with this layout
|
||||||
|
- Physical card alignment: if the badge appears offset on the card, a CSS margin tweak may
|
||||||
|
be needed in the PVC layout file — note the offset and adjust `print_margin_cfg` once that
|
||||||
|
field is wired to the UI
|
||||||
|
- Font sizes: if name/affiliation text appears too small at physical scale, adjust via the
|
||||||
|
font size controls (+ / −) in the print controls panel; note the preferred values for this
|
||||||
|
event's template
|
||||||
|
|
||||||
|
#### Test Results (2026-03-19)
|
||||||
|
|
||||||
|
- Card feeds and prints without jam: ✅
|
||||||
|
- Single-sided PVC confirmed (back does not print): ✅
|
||||||
|
- Chrome margins None/Minimum: correct output ✅
|
||||||
|
- Firefox: correct output ✅
|
||||||
|
- QR code scannable from printed card: ✅
|
||||||
|
- Print tracking (`print_count` increment): ✅
|
||||||
|
- Font sizes / visual quality: tested; specific calibration pending client design direction
|
||||||
|
- Driver version: *(record here)*
|
||||||
|
- Physical offset needed: *(record if any)*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Epson — Fan-Fold / Label Printer
|
||||||
|
|
||||||
|
**Status:** Not yet tested. Section to be filled in after testing.
|
||||||
|
|
||||||
|
Common Epson models used for fan-fold name badge stock: TM-T88 series, C3500, LX series.
|
||||||
|
Fan-fold stock is typically 4" × 3" or 4" × 6" paper labels.
|
||||||
|
|
||||||
|
#### CSS Layout
|
||||||
|
|
||||||
|
Fan-fold badges would use a layout sized to the specific label stock.
|
||||||
|
A new CSS layout file will need to be created per stock size if not already present.
|
||||||
|
Naming convention: `badge_layout_epson_[model]_[size].css`
|
||||||
|
|
||||||
|
#### Setup Notes
|
||||||
|
|
||||||
|
*(To be filled in after testing — cover: driver source, CUPS setup, paper size, Chrome settings)*
|
||||||
|
|
||||||
|
#### Known Behaviors
|
||||||
|
|
||||||
|
*(To be filled in after testing)*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Print Tracking
|
||||||
|
|
||||||
|
The badge print page tracks print counts per badge:
|
||||||
|
|
||||||
|
- `print_count` — increments on each **Print Badge** button click
|
||||||
|
- `print_first_datetime` — timestamp of first print
|
||||||
|
- An amber "Printed N×" chip appears in the print page header after the first print
|
||||||
|
|
||||||
|
The reprint shortcut (trusted access + edit mode) does **not** increment the count.
|
||||||
|
Only the **Print Badge** button path increments the count. This is intentional — reprints
|
||||||
|
for alignment or quality checks should not inflate the print count.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
| Symptom | Cause | Fix |
|
||||||
|
|---|---|---|
|
||||||
|
| White border around printed badge | Chrome Default margins | Change to None or Minimum |
|
||||||
|
| URL / date printed at top or bottom | Chrome Default margins | Change to None |
|
||||||
|
| Header image / stripe not printing | Background graphics disabled | Enable in print dialog |
|
||||||
|
| Badge appears on wrong-size output | Paper size mismatch | Set correct size in CUPS and/or print dialog |
|
||||||
|
| Card jams | Card stock misloaded | Re-seat cards per printer manual; check stock orientation |
|
||||||
|
| Badge content clipped | Layout overflow | Check font size — use − control to reduce if needed |
|
||||||
|
| Second blank card ejected | Duplex triggered on PVC | Confirm `.badge_back { display: none }` in print CSS for this layout |
|
||||||
262
documentation/MODULE__AE_Events_Exhibitor_Leads.md
Normal file
262
documentation/MODULE__AE_Events_Exhibitor_Leads.md
Normal file
@@ -0,0 +1,262 @@
|
|||||||
|
# Aether Events — Exhibitor Leads Module (v3)
|
||||||
|
|
||||||
|
**Status:** Implemented and ready for demo. Core lead capture flow works end-to-end.
|
||||||
|
**Platform:** PWA only — mobile-first, offline-capable.
|
||||||
|
**Target users:** Conference exhibitors scanning attendee badges at their booths.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What It Does
|
||||||
|
|
||||||
|
The Exhibitor Leads module lets conference exhibitors capture and manage attendee leads directly
|
||||||
|
from their booth. Exhibitors scan or search attendee badges and build a list of contacts they met.
|
||||||
|
All data is cached locally (IndexedDB / Dexie.js) for spotty or offline venue Wi-Fi, with
|
||||||
|
background SWR revalidation against the API when the network is available.
|
||||||
|
|
||||||
|
Key capabilities:
|
||||||
|
|
||||||
|
- **Badge scanning** — QR scan or text search (name, email, affiliations, badge ID)
|
||||||
|
- **Lead list** — filterable/sortable, per-exhibitor or per-staff-member view
|
||||||
|
- **Lead detail** — custom question responses, notes (rich text), priority flag, hide/unhide
|
||||||
|
- **Export** — CSV/XLSX download of all leads for an exhibit
|
||||||
|
- **License management** — assign staff accounts (email + passcode) per max license count
|
||||||
|
- **Custom questions** — configurable per-exhibit follow-up questions (ratings, dropdowns, text)
|
||||||
|
- **Offline-first** — IndexedDB cache survives network drops; syncs on reconnect
|
||||||
|
- **PWA install** — Chrome/Android native install prompt; iOS Safari "Add to Home Screen" nudge
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Access Levels
|
||||||
|
|
||||||
|
Three sign-in levels are supported within this module:
|
||||||
|
|
||||||
|
| Level | How to sign in | What they can do |
|
||||||
|
|---|---|---|
|
||||||
|
| **Aether Platform Auth** | Standard Aether login (manager/trusted access) | Full admin bypass; all exhibit data |
|
||||||
|
| **Shared Exhibit Passcode** | Enter booth's `staff_passcode` | Manage licenses, view/add leads |
|
||||||
|
| **Licensed User** | Email + individual passcode from `license_li_json` | Add and manage leads for this booth |
|
||||||
|
|
||||||
|
Auth state is persisted in `$events_loc.leads.auth_exhibit_kv[exhibit_id]` (localStorage-backed).
|
||||||
|
|
||||||
|
A booth only shows in the landing page search to non-admins if it is marked `priority = true` (i.e. paid).
|
||||||
|
|
||||||
|
### `allow_tracking` Opt-In
|
||||||
|
|
||||||
|
Attendees must have `allow_tracking = true` on their badge record to be added as a lead.
|
||||||
|
Attendees without this flag are blocked at both the QR scanner and the manual search:
|
||||||
|
- QR scan shows a "Tracking Blocked" warning card (`ShieldOff` icon)
|
||||||
|
- Manual search shows an "Opt-Out" badge per result row; the "Add as Lead" button is suppressed
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Route Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
/events/[event_id]/leads/
|
||||||
|
→ Exhibit search / landing page — find your booth
|
||||||
|
|
||||||
|
/events/[event_id]/leads/exhibit/[exhibit_id]/
|
||||||
|
→ Main exhibitor view — all 4 tabs
|
||||||
|
|
||||||
|
/events/[event_id]/leads/exhibit/[exhibit_id]/lead/[exhibit_tracking_id]/
|
||||||
|
→ Lead detail view — edit notes, custom responses, flags
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Module Tabs
|
||||||
|
|
||||||
|
### Tab 1 — Start / Sign In
|
||||||
|
|
||||||
|
The only tab visible when not signed in as a licensed leads user.
|
||||||
|
|
||||||
|
- **Sign in with shared passcode** — grants booth management access (license management, passcode change)
|
||||||
|
- **Sign in as licensed user** — grants lead capture access (email + passcode)
|
||||||
|
- **PWA install prompt** — Chrome/Android native install button; iOS "Share → Add to Home Screen" instructions
|
||||||
|
- **License list** — shown when signed in via shared passcode or Aether admin; add/edit/remove staff slots
|
||||||
|
|
||||||
|
### Tab 2 — Add Leads
|
||||||
|
|
||||||
|
Visible only when signed in (licensed user or Aether auth).
|
||||||
|
|
||||||
|
- **Text search** — search by name, email, affiliations, badge ID
|
||||||
|
- **QR scan** — three modes (persisted per exhibit in `tab_scan_qualify`):
|
||||||
|
- **Confirm** (`rapid`) — scan, then choose per badge: **Add & Scan Next** (resets after 2s) or **Add & View Lead** (navigates to detail)
|
||||||
|
- **Auto** — no confirmation tap; adds immediately and auto-resets (high-throughput)
|
||||||
|
- **Multi** — BarcodeDetector batch scan; up to 4 badges in one frame as a confirm grid
|
||||||
|
- Previously-removed leads detected on scan — shown a "Previously Removed" card with **Restore & Scan Next** / **Restore & View Lead** buttons
|
||||||
|
- Results show "Add as Lead" or "View Lead" depending on whether already captured
|
||||||
|
- `external_person_id` and `group` resolved by auth type — see [Capture Identity](#capture-identity) below
|
||||||
|
|
||||||
|
### Tab 3 — Leads List
|
||||||
|
|
||||||
|
The main lead management view.
|
||||||
|
|
||||||
|
- **Search** — full-text across name, email, notes (local IDB fast path + API revalidation)
|
||||||
|
- **Sort** — Newest first, Oldest first, Name A→Z, Name Z→A
|
||||||
|
- **Filter by staff member** — "All Leads" or filter by individual licensed user
|
||||||
|
- **Show/hide hidden records** — toggles `hide` filter on IDB and API results
|
||||||
|
- **Export** — downloads CSV/XLSX for the exhibit (`leads_api_access` required)
|
||||||
|
|
||||||
|
### Tab 4 — Manage / Config
|
||||||
|
|
||||||
|
Exhibit configuration and app settings.
|
||||||
|
|
||||||
|
**Admin Tools** (manager_access only):
|
||||||
|
- Payment status toggle (`priority` field)
|
||||||
|
- Max licenses, small/large device counts
|
||||||
|
|
||||||
|
**Booth Profile** (all signed-in users):
|
||||||
|
- Exhibitor name, booth description (rich text)
|
||||||
|
|
||||||
|
**Access & Security**:
|
||||||
|
- View/change shared staff passcode
|
||||||
|
- Sign out button
|
||||||
|
|
||||||
|
**Lead Retrieval Config**:
|
||||||
|
- Exhibit Leads Licensees — manage staff accounts (`administrator_access` only; gap: should also allow shared-passcode users — see Known Gaps)
|
||||||
|
- Qualifiers & Questions — custom question config
|
||||||
|
- Licenses & Billing — stub (Stripe not yet implemented)
|
||||||
|
|
||||||
|
**App Settings**:
|
||||||
|
- Auto-hide header/footer toggle
|
||||||
|
- Show Payment Tab toggle
|
||||||
|
- Show Extra Details toggle
|
||||||
|
- Refresh interval (1–120 seconds, default 25s), countdown timer, last-refresh timestamp
|
||||||
|
- Reload App, Clear IDB, Hard Reset (clears localStorage)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Data Model
|
||||||
|
|
||||||
|
### `event_exhibit`
|
||||||
|
One exhibitor's presence at an event.
|
||||||
|
|
||||||
|
| Field | Purpose |
|
||||||
|
|---|---|
|
||||||
|
| `event_exhibit_id` | Primary / URL-safe ID |
|
||||||
|
| `name` | Exhibitor display name |
|
||||||
|
| `code` | Booth number |
|
||||||
|
| `staff_passcode` | Shared sign-in code |
|
||||||
|
| `priority` | `1` = paid/active |
|
||||||
|
| `license_max` | Max licensed staff slots |
|
||||||
|
| `license_li_json` | Array of `{ full_name, email, passcode }` |
|
||||||
|
| `leads_custom_questions_json` | Array of question definitions |
|
||||||
|
| `leads_device_sm_qty` / `leads_device_lg_qty` | Device count tracking |
|
||||||
|
|
||||||
|
### `event_exhibit_tracking`
|
||||||
|
One captured lead — links an exhibit to a badge.
|
||||||
|
|
||||||
|
| Field | Purpose |
|
||||||
|
|---|---|
|
||||||
|
| `event_exhibit_tracking_id` | Primary key |
|
||||||
|
| `event_exhibit_id` | Parent exhibit |
|
||||||
|
| `event_badge_id` | Captured attendee's badge |
|
||||||
|
| `external_person_id` | Capturing staff's email (from license) |
|
||||||
|
| `exhibitor_notes` | Rich text notes (HTML via TipTap) |
|
||||||
|
| `responses_json` | `{ [question_code]: { response: value } }` |
|
||||||
|
| `priority` | Star/flag for high-priority leads |
|
||||||
|
| `hide` | Soft-delete / hide from list |
|
||||||
|
| Denormalized badge fields | `event_badge_full_name`, `event_badge_email`, `event_badge_affiliations`, `event_badge_professional_title` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Key Files
|
||||||
|
|
||||||
|
### Routes
|
||||||
|
|
||||||
|
| File | Role |
|
||||||
|
|---|---|
|
||||||
|
| `leads/+page.svelte` | Exhibit search/landing |
|
||||||
|
| `leads/exhibit/[exhibit_id]/+page.svelte` | Main exhibitor view — orchestrates all tabs |
|
||||||
|
| `leads/exhibit/[exhibit_id]/+layout.svelte` / `+layout.ts` | Layout / data load |
|
||||||
|
| `leads/exhibit/[exhibit_id]/lead/[exhibit_tracking_id]/+page.svelte` | Lead detail |
|
||||||
|
|
||||||
|
### Components
|
||||||
|
|
||||||
|
| File | Role |
|
||||||
|
|---|---|
|
||||||
|
| `ae_tab__start.svelte` | Tab 1 — welcome, sign-in, license list |
|
||||||
|
| `ae_tab__add.svelte` | Tab 2 — QR scan + text search toggle |
|
||||||
|
| `ae_tab__manage.svelte` | Tab 4 — admin tools, booth config, app settings |
|
||||||
|
| `ae_comp__exhibit_signin.svelte` | Sign-in UI (shared passcode + licensed user) |
|
||||||
|
| `ae_comp__lead_qr_scanner.svelte` | QR scanner (rapid / qualify mode) |
|
||||||
|
| `ae_comp__lead_manual_search.svelte` | Manual badge search + add |
|
||||||
|
| `ae_comp__exhibit_tracking_search.svelte` | Lead list search/filter/sort bar |
|
||||||
|
| `ae_comp__exhibit_tracking_obj_li.svelte` | Lead list item renderer |
|
||||||
|
| `ae_comp__exhibit_license_list.svelte` | License slot manager |
|
||||||
|
| `ae_comp__exhibit_custom_questions.svelte` | Custom question config editor |
|
||||||
|
| `ae_comp__exhibit_payment.svelte` | **STUB** — Stripe placeholder |
|
||||||
|
| `ae_comp__exhibit_search.svelte` | Exhibit search on the landing page |
|
||||||
|
| `lead/ae_comp__lead_detail_form.svelte` | Custom question response editor |
|
||||||
|
|
||||||
|
### Lib Functions
|
||||||
|
|
||||||
|
| File | Role |
|
||||||
|
|---|---|
|
||||||
|
| `src/lib/ae_events/ae_events__exhibit.ts` | Exhibit load, search, create, update |
|
||||||
|
| `src/lib/ae_events/ae_events__exhibit_tracking.ts` | Tracking load, search, create, update, export |
|
||||||
|
|
||||||
|
Both aggregated into `events_func` via `src/lib/ae_events/ae_events_functions.ts`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Offline / PWA Notes
|
||||||
|
|
||||||
|
- All data is stored in `db_events` (Dexie.js) — `exhibit` and `exhibit_tracking` tables
|
||||||
|
- SWR pattern: IDB cache returned immediately; background API fetch updates IDB and triggers UI refresh
|
||||||
|
- Search: local IDB first pass (fast), then API revalidation via `search__exhibit_tracking`
|
||||||
|
- `beforeinstallprompt` event captured at module load time (`src/lib/pwa/pwa_install.svelte.ts`)
|
||||||
|
— fires within ~1 second of page load, before any Svelte `$effect` runs
|
||||||
|
- iOS Safari: no native install prompt; shows "Share → Add to Home Screen" instructions instead
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Capture Identity
|
||||||
|
|
||||||
|
`external_person_id` and `group` on every `event_exhibit_tracking` record record who captured the lead. Resolved at capture time in all three lead capture components (single scanner, multi scanner, manual search):
|
||||||
|
|
||||||
|
| Auth type | `kv.type` | Value stored |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Licensed exhibit user | `'licensed'` | Their email address (`kv.key`) |
|
||||||
|
| Shared exhibit passcode | `'shared'` | `'shared_passcode'` (label — raw passcode is NOT stored) |
|
||||||
|
| Aether user (admin bypass, no kv) | `undefined` | `$ae_loc.access_type` — e.g. `'trusted'`, `'manager'`, `'super'` |
|
||||||
|
|
||||||
|
`kv` = `$events_loc.leads.auth_exhibit_kv[exhibit_id]` (localStorage-persisted exhibit sign-in state).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Lead Soft-Delete / Re-enable
|
||||||
|
|
||||||
|
Leads are never hard-deleted. "Remove Lead" sets `enable = false`. Key behaviors:
|
||||||
|
|
||||||
|
- **Leads list** always filters out `enable = false` records (both IDB fast-path and API results) — no flash of removed records
|
||||||
|
- **QR scanner**: if a previously-removed badge is scanned, the scanner detects it via `existing_leads_map` (IDB) or API fallback search (`search__exhibit_tracking` with `qry_badge_id` + `enabled: 'not_enabled'`) and shows the reenable card instead of an error
|
||||||
|
- **Lead detail page**: "Remove Lead" button (two-click confirm in header) sets `enable = false` and navigates back. "Restore Lead" card appears at the bottom of the right sidebar when `enable` is falsy.
|
||||||
|
- `search__exhibit_tracking` supports `qry_badge_id` param (added) and `enabled: 'not_enabled'` to find disabled records for a specific badge + exhibit combination
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Known Gaps
|
||||||
|
|
||||||
|
### Payment / Stripe
|
||||||
|
`ae_comp__exhibit_payment.svelte` is a stub. The Stripe integration is not implemented.
|
||||||
|
The payment tab can be hidden via "Show Payment Tab" in App Settings.
|
||||||
|
|
||||||
|
### License Management — Shared Passcode Access
|
||||||
|
Implemented. The license section in the Manage tab is visible to Aether admins and to anyone
|
||||||
|
signed in via the shared exhibit passcode (`auth_exhibit_kv[exhibit_id].type === 'shared'`).
|
||||||
|
Guard in [ae_tab__manage.svelte](src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_tab__manage.svelte):
|
||||||
|
```svelte
|
||||||
|
{#if $ae_loc.administrator_access || $events_loc.leads.auth_exhibit_kv?.[exhibit_id]?.type === 'shared'}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## OSIT Admin Notes
|
||||||
|
|
||||||
|
- Mark `priority = 1` on an exhibit to make it visible in public search and to enable lead capture
|
||||||
|
- `license_max` controls how many licensed staff slots an exhibit can have
|
||||||
|
- Export endpoint: `GET /v3/action/event_exhibit/{id}/tracking_export` — requires `leads_api_access`
|
||||||
|
- Custom questions are stored per-exhibit in `leads_custom_questions_json` (not global)
|
||||||
|
- The exhibitor landing page link format: `/events/[event_id]/leads/exhibit/[exhibit_exhibit_id]/`
|
||||||
53
documentation/PROJECT__AE_Docker_CI_BuildKit_implement.md
Normal file
53
documentation/PROJECT__AE_Docker_CI_BuildKit_implement.md
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# Project: AE Docker + CI BuildKit Implementation
|
||||||
|
|
||||||
|
**Status:** Proposed
|
||||||
|
|
||||||
|
**Goal:** Make Docker image builds for Aether cache-friendly using BuildKit/buildx and CI registry caching, while keeping local developer caches small and manageable.
|
||||||
|
|
||||||
|
Summary
|
||||||
|
- Implement a BuildKit-friendly multi-stage `Dockerfile` pattern for frontend and API images.
|
||||||
|
- Add CI `buildx` examples that push/read registry-based cache to avoid local disk bloat.
|
||||||
|
- Provide cache retention/rotation guidance and developer commands for safe pruning.
|
||||||
|
|
||||||
|
Scope
|
||||||
|
- Repository areas: `aether_container_env/`, root `Dockerfile` (if present), and CI pipeline definitions (Gitea/Drone or other).
|
||||||
|
- Non-goal: full CI pipeline migration to a new provider. This work provides CI snippets and a PR-ready set of files for your CI team.
|
||||||
|
|
||||||
|
Deliverables (this PR)
|
||||||
|
- `documentation/PROJECT__AE_Docker_CI_BuildKit_implement.md` (this file)
|
||||||
|
- `aether_container_env/Dockerfile.buildkit.example` — BuildKit-friendly multi-stage Dockerfile example.
|
||||||
|
- `aether_container_env/ci_buildx_example.sh` — standalone CI script examples (registry cache + local cache usage).
|
||||||
|
- `documentation/AE_Docker_CI_cache_policy.md` — cache rotation and prune guidance.
|
||||||
|
|
||||||
|
Tasks (implementation checklist)
|
||||||
|
- [ ] Review existing `Dockerfile`(s) under `aether_container_env/` and repository root.
|
||||||
|
- [ ] Replace/extend Dockerfile with multi-stage BuildKit-friendly layout (use example as guide).
|
||||||
|
- [ ] Ensure `.dockerignore` (already added) excludes large build artifacts.
|
||||||
|
- [ ] Add CI step using `docker buildx build` with `--cache-from` and `--cache-to` pointed at a registry cache.
|
||||||
|
- [ ] Add a scheduled job or registry lifecycle rule to delete old cache images (30 days default).
|
||||||
|
- [ ] Document required CI secrets and permissions (registry write/read) for the operations team.
|
||||||
|
- [ ] Run verification builds (dev local with BuildKit; CI runs with cache) and record timings.
|
||||||
|
|
||||||
|
Verification
|
||||||
|
- Local dev: `DOCKER_BUILDKIT=1` build with `--cache-to`/`--cache-from` shows cache hits on second run and faster build time.
|
||||||
|
- CI: subsequent CI runs log `cache hit` from `buildx` and total build time reduced vs baseline.
|
||||||
|
- Confirm registry contains `cache` image tags and that rotation job/prune removes old entries.
|
||||||
|
|
||||||
|
Notes about Gitea/CI
|
||||||
|
- Gitea does not include native Actions like GitHub; teams typically use Drone CI, Tekton, or a self-hosted runner that can execute the `docker`/`buildx` CLI.
|
||||||
|
- The provided `ci_buildx_example.sh` is intentionally provider-agnostic — pasteable into Drone, Jenkins, GitLab CI, or any shell-capable runner.
|
||||||
|
|
||||||
|
Risks & Mitigations
|
||||||
|
- Risk: Unbounded registry cache growth. Mitigation: enforce retention policy and rotation job; prefer a single `cache` tag reused by CI.
|
||||||
|
- Risk: Developers unfamiliar with BuildKit. Mitigation: examples show simple `DOCKER_BUILDKIT=1` usage and local cache prune commands.
|
||||||
|
|
||||||
|
Next steps for the container team
|
||||||
|
1. Review examples in `aether_container_env/` and adapt the Dockerfile to your runtime constraints (ssl certs, env injection, secrets).
|
||||||
|
2. Add a CI job using the `ci_buildx_example.sh` snippet; configure registry credentials as secrets.
|
||||||
|
3. Add a scheduled job to rotate/delete old cache images or configure registry lifecycle rules.
|
||||||
|
4. Run a before/after benchmark of `time npm run build:prod` inside the build stage to quantify improvement.
|
||||||
|
|
||||||
|
Files included in this PR for reference:
|
||||||
|
- `aether_container_env/Dockerfile.buildkit.example`
|
||||||
|
- `aether_container_env/ci_buildx_example.sh`
|
||||||
|
- `documentation/AE_Docker_CI_cache_policy.md`
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
- Once satisfied, staff prints the badge.
|
- Once satisfied, staff prints the badge.
|
||||||
- The key differentiator vs the review form: **the live badge render** shows exactly how
|
- The key differentiator vs the review form: **the live badge render** shows exactly how
|
||||||
the badge will print. Attendees and staff can see changes immediately.
|
the badge will print. Attendees and staff can see changes immediately.
|
||||||
- Component: `ae_comp__badge_obj_view.svelte` / `ae_comp__badge_obj_view_v2.svelte`
|
- Component: `ae_comp__badge_obj_view.svelte`
|
||||||
- Route: `/events/[event_id]/badges/[badge_id]/print/`
|
- Route: `/events/[event_id]/badges/[badge_id]/print/`
|
||||||
|
|
||||||
### Permission Model — Same Logic, Both Flows
|
### Permission Model — Same Logic, Both Flows
|
||||||
@@ -69,8 +69,8 @@ Work needed:
|
|||||||
or whether it should share/reuse the review form component alongside the badge render.
|
or whether it should share/reuse the review form component alongside the badge render.
|
||||||
- **Do NOT use `email_override` as the send-to address** — always use `event_badge.email`.
|
- **Do NOT use `email_override` as the send-to address** — always use `event_badge.email`.
|
||||||
|
|
||||||
### 1. Auto-Scaling Badge Text (v2) — In Progress
|
### 1. Auto-Scaling Badge Text — In Progress
|
||||||
`ae_comp__badge_obj_view_v2.svelte` using `element_fit_text.svelte` (binary search auto-scale).
|
`ae_comp__badge_obj_view.svelte` using `element_fit_text.svelte` (binary search auto-scale).
|
||||||
Toggle between v1 (heuristic) and v2 (auto-scale) on the print page via the `v1`/`v2` header button.
|
Toggle between v1 (heuristic) and v2 (auto-scale) on the print page via the `v1`/`v2` header button.
|
||||||
Heights tuned per layout in `fit_heights` derived object. Still needs visual tuning with real badges.
|
Heights tuned per layout in `fit_heights` derived object. Still needs visual tuning with real badges.
|
||||||
|
|
||||||
@@ -118,7 +118,7 @@ the MODULE doc TODO list was stale. `duplex` is in `properties_to_save`; v2 badg
|
|||||||
**Files created/updated:**
|
**Files created/updated:**
|
||||||
- `src/lib/elements/action_fit_text.ts` — Svelte action
|
- `src/lib/elements/action_fit_text.ts` — Svelte action
|
||||||
- `src/lib/elements/element_fit_text.svelte` — Component wrapper
|
- `src/lib/elements/element_fit_text.svelte` — Component wrapper
|
||||||
- `src/routes/events/.../ae_comp__badge_obj_view_v2.svelte` — V2 badge render (canonical)
|
- `src/routes/events/.../ae_comp__badge_obj_view.svelte` — V2 badge render (canonical)
|
||||||
Debug blocks gated behind `$ae_loc.edit_mode` (hidden in production).
|
Debug blocks gated behind `$ae_loc.edit_mode` (hidden in production).
|
||||||
- `print/+page.svelte` — Always uses v2 now. v1/v2 toggle removed. Header redesigned for kiosk UX.
|
- `print/+page.svelte` — Always uses v2 now. v1/v2 toggle removed. Header redesigned for kiosk UX.
|
||||||
- `ae_comp__badge_print_controls.svelte` — Identity card at top, pronouns moved to attendee section,
|
- `ae_comp__badge_print_controls.svelte` — Identity card at top, pronouns moved to attendee section,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# Project Plan: Aether AE Obj Field Editor v3 (Consolidated)
|
# Project Plan: Aether AE Obj Field Editor v3 (Consolidated)
|
||||||
|
|
||||||
> **Status:** 🔵 Active / Testing & Stabilization
|
> **Status:** 🟡 Mostly Complete — Phase 3 items + GUIDE update remaining
|
||||||
> **Date:** February 13, 2026
|
> **Date:** February 13, 2026 (last updated: 2026-03-20)
|
||||||
> **Target Component:** `src/lib/elements/element_ae_obj_field_editor_v3.svelte`
|
> **Target Component:** `src/lib/elements/element_ae_obj_field_editor.svelte`
|
||||||
> **Replaces:** `element_ae_crud.svelte` and `element_ae_crud_v2.svelte`
|
> **Replaces:** `element_ae_crud.svelte` and `element_ae_crud_v2.svelte`
|
||||||
|
|
||||||
## 1. Overview
|
## 1. Overview
|
||||||
@@ -32,12 +32,12 @@ Consolidate the legacy CRUD components into a single, high-performance "Aether O
|
|||||||
|
|
||||||
### Phase 3: Field Type Parity (IN PROGRESS)
|
### Phase 3: Field Type Parity (IN PROGRESS)
|
||||||
- [x] Support `text`, `textarea`, `select`, `tiptap`, and `checkbox`.
|
- [x] Support `text`, `textarea`, `select`, `tiptap`, and `checkbox`.
|
||||||
- [ ] Add `datetime` support using native browser pickers.
|
- [x] Add `datetime` support using native browser pickers — `date` and `datetime-local` inputs implemented.
|
||||||
- [ ] Implement searchable dropdowns for the `select` type.
|
- [ ] Implement searchable dropdowns for the `select` type.
|
||||||
|
|
||||||
### Phase 4: Migration & Cleanup
|
### Phase 4: Migration & Cleanup
|
||||||
- [x] Create a playground route for V3 verification (`/testing/ae_obj_field_editor_v3`).
|
- [x] Create a playground route for V3 verification (`/testing/ae_obj_field_editor`).
|
||||||
- [ ] Deprecate and eventually remove `v1` and `v2` files.
|
- [x] Deprecate and remove `v1` and `v2` files — `element_ae_crud.svelte` and `element_ae_crud_v2.svelte` removed 2026-03-20.
|
||||||
- [ ] Update `GUIDE__Development.md` with the new usage patterns.
|
- [ ] Update `GUIDE__Development.md` with the new usage patterns.
|
||||||
|
|
||||||
## ⚠️ Security & Reliability Stabilization (NEW)
|
## ⚠️ Security & Reliability Stabilization (NEW)
|
||||||
|
|||||||
@@ -7,14 +7,14 @@
|
|||||||
## 1. Project Overview
|
## 1. Project Overview
|
||||||
This document outlines the modernization of the Journals module UI in the SvelteKit frontend (`aether_app_sveltekit`). The primary goals are to fully leverage the generic V3 API architecture and introduce high-velocity productivity features for journal management.
|
This document outlines the modernization of the Journals module UI in the SvelteKit frontend (`aether_app_sveltekit`). The primary goals are to fully leverage the generic V3 API architecture and introduce high-velocity productivity features for journal management.
|
||||||
|
|
||||||
**Context:** The backend transition to the generic `api_crud_v3` router is complete. Custom legacy routers have been removed. The frontend must now fully align with this pattern and provide a frictionless user experience.
|
**Context:** The backend transition to the generic `api_crud` router is complete. Custom legacy routers have been removed. The frontend must now fully align with this pattern and provide a frictionless user experience.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2. Core Objectives
|
## 2. Core Objectives
|
||||||
|
|
||||||
### 🎯 Primary Goals
|
### 🎯 Primary Goals
|
||||||
1. **V3 API Verification:** Ensure all CRUD operations utilize the generic `api_crud_v3` endpoints (Verified).
|
1. **V3 API Verification:** Ensure all CRUD operations utilize the generic `api_crud` endpoints (Verified).
|
||||||
2. **Quick Add UI:** Implement a specialized interface for rapid, friction-free entry creation.
|
2. **Quick Add UI:** Implement a specialized interface for rapid, friction-free entry creation.
|
||||||
3. **Append/Prepend UI:** Allow users to quickly add text to the beginning or end of existing entries without full edit mode.
|
3. **Append/Prepend UI:** Allow users to quickly add text to the beginning or end of existing entries without full edit mode.
|
||||||
4. **Interop & Portability:** Robust import/export logic for Markdown/HTML (Nextcloud Notes compatibility).
|
4. **Interop & Portability:** Robust import/export logic for Markdown/HTML (Nextcloud Notes compatibility).
|
||||||
@@ -25,14 +25,14 @@ This document outlines the modernization of the Journals module UI in the Svelte
|
|||||||
## 3. Technical Architecture
|
## 3. Technical Architecture
|
||||||
|
|
||||||
### Backend (Completed)
|
### Backend (Completed)
|
||||||
* **Router:** `api_crud_v3` (Generic)
|
* **Router:** `api_crud` (Generic)
|
||||||
* **Definitions:** `app/ae_obj_types_def.py` -> `app/object_definitions/journals.py`
|
* **Definitions:** `app/ae_obj_types_def.py` -> `app/object_definitions/journals.py`
|
||||||
* **Endpoints:** `/v3/crud/journal/...` and `/v3/crud/journal_entry/...`
|
* **Endpoints:** `/v3/crud/journal/...` and `/v3/crud/journal_entry/...`
|
||||||
|
|
||||||
### Frontend (In Progress)
|
### Frontend (In Progress)
|
||||||
* **State Management:** `src/lib/ae_journals/ae_journals_stores.ts`
|
* **State Management:** `src/lib/ae_journals/ae_journals_stores.ts`
|
||||||
* **Local Storage:** Dexie.js (`db_journals`)
|
* **Local Storage:** Dexie.js (`db_journals`)
|
||||||
* **API Client:** `src/lib/api/api.ts` -> `get_ae_obj_v3`
|
* **API Client:** `src/lib/api/api.ts` -> `get_ae_obj`
|
||||||
* **Export Engine:** Centralized templates in `src/lib/ae_journals/ae_journals_export_templates.ts`.
|
* **Export Engine:** Centralized templates in `src/lib/ae_journals/ae_journals_export_templates.ts`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -60,26 +60,26 @@ For each file listed above, follow this standard refactoring pattern:
|
|||||||
|
|
||||||
1. **Imports:**
|
1. **Imports:**
|
||||||
* Remove imports of `create_ae_obj_crud`, `update_ae_obj_id_crud`, etc.
|
* Remove imports of `create_ae_obj_crud`, `update_ae_obj_id_crud`, etc.
|
||||||
* Import V3 helpers: `get_ae_obj_v3`, `create_ae_obj_v3`, `update_ae_obj_v3`, `delete_ae_obj_v3`, `search_ae_obj_v3`.
|
* Import V3 helpers: `get_ae_obj`, `create_ae_obj`, `update_ae_obj`, `delete_ae_obj`, `search_ae_obj`.
|
||||||
|
|
||||||
2. **Pattern Replacement:**
|
2. **Pattern Replacement:**
|
||||||
|
|
||||||
* **Get (Single):**
|
* **Get (Single):**
|
||||||
* *Old:* `get_ae_obj_id_crud({ api_cfg, obj_type: 'event_session', obj_id: '...' })`
|
* *Old:* `get_ae_obj_id_crud({ api_cfg, obj_type: 'event_session', obj_id: '...' })`
|
||||||
* *New:* `get_ae_obj_v3({ api_cfg, obj_type: 'event_session', obj_id: '...' })`
|
* *New:* `get_ae_obj({ api_cfg, obj_type: 'event_session', obj_id: '...' })`
|
||||||
|
|
||||||
* **Get (List):**
|
* **Get (List):**
|
||||||
* *Old:* `get_ae_obj_li_for_obj_id_crud_v2(...)`
|
* *Old:* `get_ae_obj_li_for_obj_id_crud_v2(...)`
|
||||||
* *New:* `get_ae_obj_li_v3(...)` or `search_ae_obj_v3(...)` if complex filtering is needed.
|
* *New:* `get_ae_obj_li(...)` or `search_ae_obj(...)` if complex filtering is needed.
|
||||||
|
|
||||||
* **Update:**
|
* **Update:**
|
||||||
* *Old:* `update_ae_obj_id_crud({ ..., fields: { name: 'New Name' } })`
|
* *Old:* `update_ae_obj_id_crud({ ..., fields: { name: 'New Name' } })`
|
||||||
* *New:* `update_ae_obj_v3({ ..., data: { name: 'New Name' } })`
|
* *New:* `update_ae_obj({ ..., data: { name: 'New Name' } })`
|
||||||
* *Note:* Ensure payload whitelisting is applied! V3 will 400 Error on unknown columns.
|
* *Note:* Ensure payload whitelisting is applied! V3 will 400 Error on unknown columns.
|
||||||
|
|
||||||
* **Create:**
|
* **Create:**
|
||||||
* *Old:* `create_ae_obj_crud({ ..., fields: { ... } })`
|
* *Old:* `create_ae_obj_crud({ ..., fields: { ... } })`
|
||||||
* *New:* `create_ae_obj_v3({ ..., data: { ... } })`
|
* *New:* `create_ae_obj({ ..., data: { ... } })`
|
||||||
|
|
||||||
3. **Verification:**
|
3. **Verification:**
|
||||||
* Verify the module still loads data (check Network tab for `/v3/` requests).
|
* Verify the module still loads data (check Network tab for `/v3/` requests).
|
||||||
@@ -106,7 +106,7 @@ V3 returns detailed error metadata in the `meta.details` object.
|
|||||||
**Symptom:** Providing a string ID in a search body that the backend maps to an integer can result in **Zero Results** if the underlying view expects a string.
|
**Symptom:** Providing a string ID in a search body that the backend maps to an integer can result in **Zero Results** if the underlying view expects a string.
|
||||||
|
|
||||||
**Final Solution (Body + Header Injection):**
|
**Final Solution (Body + Header Injection):**
|
||||||
1. **Body:** Inject the raw field name (e.g. `account_id_random`) into the `search_query.and` array to bypass automatic backend mapping.
|
1. **Body:** Inject the raw field name (e.g. `account_id`) into the `search_query.and` array to bypass automatic backend mapping.
|
||||||
2. **Headers:** Pass `headers: { 'x-account-id': ... }` manually to provide context for Auth validation.
|
2. **Headers:** Pass `headers: { 'x-account-id': ... }` manually to provide context for Auth validation.
|
||||||
3. **Isolation (IDAA):** Due to specific bugs in the IDAA module, it has been temporarily isolated to a legacy V2 search function (`qry_ae_obj_li__event_v2`) using `default_qry_str` for text searching, while the main module continues to use the V3 implementation.
|
3. **Isolation (IDAA):** Due to specific bugs in the IDAA module, it has been temporarily isolated to a legacy V2 search function (`qry_ae_obj_li__event_v2`) using `default_qry_str` for text searching, while the main module continues to use the V3 implementation.
|
||||||
|
|
||||||
@@ -114,7 +114,7 @@ V3 returns detailed error metadata in the `meta.details` object.
|
|||||||
|
|
||||||
## 6. Final Cleanup
|
## 6. Final Cleanup
|
||||||
Once all checkboxes above are completed:
|
Once all checkboxes above are completed:
|
||||||
1. [ ] Remove legacy exports from `src/lib/api/api.ts`.
|
1. [x] Remove legacy exports from `src/lib/api/api.ts`.
|
||||||
2. [ ] Delete `src/lib/ae_api/api_get__crud_obj_li_v1.ts`.
|
2. [x] Delete `src/lib/ae_api/api_get__crud_obj_li_v1.ts`.
|
||||||
3. [ ] Delete `src/lib/ae_api/api_get__crud_obj_li_v2.ts`.
|
3. [x] Delete `src/lib/ae_api/api_get__crud_obj_li_v2.ts`.
|
||||||
4. [ ] Delete `src/lib/ae_api/api_get__crud_obj_id.ts` (Legacy version).
|
4. [x] Delete `src/lib/ae_api/api_get__crud_obj_id.ts` (Legacy version).
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Frontend Agent Task List
|
# Frontend Agent Task List
|
||||||
> Use this file to track steps for complex features or bug fixes.
|
> Use this file to track steps for complex features or bug fixes.
|
||||||
> **Status:** <20> Stable — ongoing development.
|
> **Status:** Stable — ongoing development.
|
||||||
|
|
||||||
|
|
||||||
## 🚧 Upcoming High Priority
|
## 🚧 Upcoming High Priority
|
||||||
|
|||||||
@@ -40,3 +40,6 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
*Prepared by: Gemini CLI (March 17, 2026)*
|
*Prepared by: Gemini CLI (March 17, 2026)*
|
||||||
|
|
||||||
|
---
|
||||||
|
*Archival note (2026-03-20): `element_modal_v1.svelte` (referenced in §2 as "new standard modal") was subsequently retired — it had zero active importers. Modal usage in the codebase relies on Flowbite `<Modal>` component. See `AE__UI_Component_Patterns.md` §11.*
|
||||||
@@ -32,7 +32,9 @@ export default tseslint.config(
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
rules: {
|
rules: {
|
||||||
'@typescript-eslint/no-unused-vars': 'warn'
|
'@typescript-eslint/no-unused-vars': 'warn',
|
||||||
|
// No base path configured — this rule is not applicable to this project
|
||||||
|
'svelte/no-navigation-without-resolve': 'off'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
106
package-lock.json
generated
106
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "osit-aether-app-svelte",
|
"name": "osit-aether-app-svelte",
|
||||||
"version": "3.12.08",
|
"version": "3.00.05",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "osit-aether-app-svelte",
|
"name": "osit-aether-app-svelte",
|
||||||
"version": "3.12.08",
|
"version": "3.00.05",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.20.0",
|
"@codemirror/autocomplete": "^6.20.0",
|
||||||
"@codemirror/commands": "^6.10.0",
|
"@codemirror/commands": "^6.10.0",
|
||||||
@@ -34,6 +34,7 @@
|
|||||||
"lucide-svelte": "^0.*.0",
|
"lucide-svelte": "^0.*.0",
|
||||||
"marked": "^17.0.0",
|
"marked": "^17.0.0",
|
||||||
"openai": "^6.10.0",
|
"openai": "^6.10.0",
|
||||||
|
"prettier-plugin-tailwindcss": "^0.7.2",
|
||||||
"qrcode": "^1.5.4",
|
"qrcode": "^1.5.4",
|
||||||
"shadcn-svelte": "^1.0.11",
|
"shadcn-svelte": "^1.0.11",
|
||||||
"svelte-persisted-store": "^0.12.0",
|
"svelte-persisted-store": "^0.12.0",
|
||||||
@@ -6161,6 +6162,16 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/postcss-load-config/node_modules/yaml": {
|
||||||
|
"version": "1.10.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz",
|
||||||
|
"integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/postcss-safe-parser": {
|
"node_modules/postcss-safe-parser": {
|
||||||
"version": "7.0.1",
|
"version": "7.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz",
|
||||||
@@ -6242,7 +6253,6 @@
|
|||||||
"version": "3.8.1",
|
"version": "3.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz",
|
||||||
"integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==",
|
"integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"prettier": "bin/prettier.cjs"
|
"prettier": "bin/prettier.cjs"
|
||||||
@@ -6258,13 +6268,91 @@
|
|||||||
"version": "3.5.1",
|
"version": "3.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.5.1.tgz",
|
||||||
"integrity": "sha512-65+fr5+cgIKWKiqM1Doum4uX6bY8iFCdztvvp2RcF+AJoieaw9kJOFMNcJo/bkmKYsxFaM9OsVZK/gWauG/5mg==",
|
"integrity": "sha512-65+fr5+cgIKWKiqM1Doum4uX6bY8iFCdztvvp2RcF+AJoieaw9kJOFMNcJo/bkmKYsxFaM9OsVZK/gWauG/5mg==",
|
||||||
"dev": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"prettier": "^3.0.0",
|
"prettier": "^3.0.0",
|
||||||
"svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0"
|
"svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/prettier-plugin-tailwindcss": {
|
||||||
|
"version": "0.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.7.2.tgz",
|
||||||
|
"integrity": "sha512-LkphyK3Fw+q2HdMOoiEHWf93fNtYJwfamoKPl7UwtjFQdei/iIBoX11G6j706FzN3ymX9mPVi97qIY8328vdnA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20.19"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@ianvs/prettier-plugin-sort-imports": "*",
|
||||||
|
"@prettier/plugin-hermes": "*",
|
||||||
|
"@prettier/plugin-oxc": "*",
|
||||||
|
"@prettier/plugin-pug": "*",
|
||||||
|
"@shopify/prettier-plugin-liquid": "*",
|
||||||
|
"@trivago/prettier-plugin-sort-imports": "*",
|
||||||
|
"@zackad/prettier-plugin-twig": "*",
|
||||||
|
"prettier": "^3.0",
|
||||||
|
"prettier-plugin-astro": "*",
|
||||||
|
"prettier-plugin-css-order": "*",
|
||||||
|
"prettier-plugin-jsdoc": "*",
|
||||||
|
"prettier-plugin-marko": "*",
|
||||||
|
"prettier-plugin-multiline-arrays": "*",
|
||||||
|
"prettier-plugin-organize-attributes": "*",
|
||||||
|
"prettier-plugin-organize-imports": "*",
|
||||||
|
"prettier-plugin-sort-imports": "*",
|
||||||
|
"prettier-plugin-svelte": "*"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@ianvs/prettier-plugin-sort-imports": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@prettier/plugin-hermes": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@prettier/plugin-oxc": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@prettier/plugin-pug": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@shopify/prettier-plugin-liquid": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@trivago/prettier-plugin-sort-imports": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@zackad/prettier-plugin-twig": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"prettier-plugin-astro": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"prettier-plugin-css-order": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"prettier-plugin-jsdoc": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"prettier-plugin-marko": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"prettier-plugin-multiline-arrays": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"prettier-plugin-organize-attributes": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"prettier-plugin-organize-imports": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"prettier-plugin-sort-imports": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"prettier-plugin-svelte": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/proxy-compare": {
|
"node_modules/proxy-compare": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-3.0.1.tgz",
|
||||||
@@ -7737,16 +7825,6 @@
|
|||||||
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
|
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/yaml": {
|
|
||||||
"version": "1.10.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
|
|
||||||
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
|
|
||||||
"devOptional": true,
|
|
||||||
"license": "ISC",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/yargs": {
|
"node_modules/yargs": {
|
||||||
"version": "15.4.1",
|
"version": "15.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "osit-aether-app-svelte",
|
"name": "osit-aether-app-svelte",
|
||||||
"version": "3.00.04",
|
"version": "3.00.07",
|
||||||
"description": "One Sky IT's Aether App created with Svelte, SvelteKit, Tailwind CSS, Lucide, Font Awesome, and Skeleton UI. -Scott Idem",
|
"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/",
|
"homepage": "https://oneskyit.com/",
|
||||||
"private": true,
|
"private": true,
|
||||||
@@ -112,6 +112,7 @@
|
|||||||
"lucide-svelte": "^0.*.0",
|
"lucide-svelte": "^0.*.0",
|
||||||
"marked": "^17.0.0",
|
"marked": "^17.0.0",
|
||||||
"openai": "^6.10.0",
|
"openai": "^6.10.0",
|
||||||
|
"prettier-plugin-tailwindcss": "^0.7.2",
|
||||||
"qrcode": "^1.5.4",
|
"qrcode": "^1.5.4",
|
||||||
"shadcn-svelte": "^1.0.11",
|
"shadcn-svelte": "^1.0.11",
|
||||||
"svelte-persisted-store": "^0.12.0",
|
"svelte-persisted-store": "^0.12.0",
|
||||||
|
|||||||
@@ -63,50 +63,50 @@ html[data-theme='AE_Firefly_Indigo'] {
|
|||||||
|
|
||||||
/* --- Color ramps (light mode) copied from dark block so both modes have full ramps --- */
|
/* --- Color ramps (light mode) copied from dark block so both modes have full ramps --- */
|
||||||
html[data-theme='AE_Firefly_Indigo'] {
|
html[data-theme='AE_Firefly_Indigo'] {
|
||||||
--color-primary-50: oklch(95.5% 0.040 270deg);
|
--color-primary-50: oklch(95.5% 0.04 270deg);
|
||||||
--color-primary-100: oklch(89.5% 0.072 270deg);
|
--color-primary-100: oklch(89.5% 0.072 270deg);
|
||||||
--color-primary-200: oklch(82.5% 0.108 269deg);
|
--color-primary-200: oklch(82.5% 0.108 269deg);
|
||||||
--color-primary-300: oklch(74.5% 0.135 268deg);
|
--color-primary-300: oklch(74.5% 0.135 268deg);
|
||||||
--color-primary-400: oklch(65.0% 0.155 267deg);
|
--color-primary-400: oklch(65% 0.155 267deg);
|
||||||
--color-primary-500: oklch(50.5% 0.160 266deg);
|
--color-primary-500: oklch(50.5% 0.16 266deg);
|
||||||
--color-primary-600: oklch(43.5% 0.152 265deg);
|
--color-primary-600: oklch(43.5% 0.152 265deg);
|
||||||
--color-primary-700: oklch(37.0% 0.138 264deg);
|
--color-primary-700: oklch(37% 0.138 264deg);
|
||||||
--color-primary-800: oklch(30.0% 0.120 263deg);
|
--color-primary-800: oklch(30% 0.12 263deg);
|
||||||
--color-primary-900: oklch(23.0% 0.100 262deg);
|
--color-primary-900: oklch(23% 0.1 262deg);
|
||||||
--color-primary-950: oklch(15.5% 0.080 261deg);
|
--color-primary-950: oklch(15.5% 0.08 261deg);
|
||||||
--color-primary-contrast-dark: var(--color-primary-950);
|
--color-primary-contrast-dark: var(--color-primary-950);
|
||||||
--color-primary-contrast-light: var(--color-primary-50);
|
--color-primary-contrast-light: var(--color-primary-50);
|
||||||
|
|
||||||
--color-secondary-50: oklch(96.5% 0.032 297deg);
|
--color-secondary-50: oklch(96.5% 0.032 297deg);
|
||||||
--color-secondary-100: oklch(91.5% 0.058 295deg);
|
--color-secondary-100: oklch(91.5% 0.058 295deg);
|
||||||
--color-secondary-200: oklch(85.5% 0.090 293deg);
|
--color-secondary-200: oklch(85.5% 0.09 293deg);
|
||||||
--color-secondary-300: oklch(78.5% 0.115 292deg);
|
--color-secondary-300: oklch(78.5% 0.115 292deg);
|
||||||
--color-secondary-400: oklch(70.0% 0.132 291deg);
|
--color-secondary-400: oklch(70% 0.132 291deg);
|
||||||
--color-secondary-500: oklch(60.0% 0.140 290deg);
|
--color-secondary-500: oklch(60% 0.14 290deg);
|
||||||
--color-secondary-600: oklch(52.5% 0.135 289deg);
|
--color-secondary-600: oklch(52.5% 0.135 289deg);
|
||||||
--color-secondary-700: oklch(45.0% 0.126 288deg);
|
--color-secondary-700: oklch(45% 0.126 288deg);
|
||||||
--color-secondary-800: oklch(37.5% 0.112 286deg);
|
--color-secondary-800: oklch(37.5% 0.112 286deg);
|
||||||
--color-secondary-900: oklch(30.0% 0.094 284deg);
|
--color-secondary-900: oklch(30% 0.094 284deg);
|
||||||
--color-secondary-950: oklch(22.0% 0.076 282deg);
|
--color-secondary-950: oklch(22% 0.076 282deg);
|
||||||
--color-secondary-contrast-dark: var(--color-secondary-950);
|
--color-secondary-contrast-dark: var(--color-secondary-950);
|
||||||
--color-secondary-contrast-light: var(--color-secondary-50);
|
--color-secondary-contrast-light: var(--color-secondary-50);
|
||||||
|
|
||||||
--color-tertiary-50: oklch(96.5% 0.022 348deg);
|
--color-tertiary-50: oklch(96.5% 0.022 348deg);
|
||||||
--color-tertiary-100: oklch(91.0% 0.042 346deg);
|
--color-tertiary-100: oklch(91% 0.042 346deg);
|
||||||
--color-tertiary-200: oklch(84.5% 0.068 344deg);
|
--color-tertiary-200: oklch(84.5% 0.068 344deg);
|
||||||
--color-tertiary-300: oklch(76.5% 0.095 343deg);
|
--color-tertiary-300: oklch(76.5% 0.095 343deg);
|
||||||
--color-tertiary-400: oklch(68.0% 0.118 342deg);
|
--color-tertiary-400: oklch(68% 0.118 342deg);
|
||||||
--color-tertiary-500: oklch(57.5% 0.128 341deg);
|
--color-tertiary-500: oklch(57.5% 0.128 341deg);
|
||||||
--color-tertiary-600: oklch(50.0% 0.122 340deg);
|
--color-tertiary-600: oklch(50% 0.122 340deg);
|
||||||
--color-tertiary-700: oklch(43.0% 0.112 339deg);
|
--color-tertiary-700: oklch(43% 0.112 339deg);
|
||||||
--color-tertiary-800: oklch(35.5% 0.098 338deg);
|
--color-tertiary-800: oklch(35.5% 0.098 338deg);
|
||||||
--color-tertiary-900: oklch(28.0% 0.080 337deg);
|
--color-tertiary-900: oklch(28% 0.08 337deg);
|
||||||
--color-tertiary-950: oklch(20.5% 0.062 336deg);
|
--color-tertiary-950: oklch(20.5% 0.062 336deg);
|
||||||
--color-tertiary-contrast-dark: var(--color-tertiary-950);
|
--color-tertiary-contrast-dark: var(--color-tertiary-950);
|
||||||
--color-tertiary-contrast-light: var(--color-tertiary-50);
|
--color-tertiary-contrast-light: var(--color-tertiary-50);
|
||||||
|
|
||||||
--color-success-50: oklch(95.77% 0.05 152.69deg);
|
--color-success-50: oklch(95.77% 0.05 152.69deg);
|
||||||
--color-success-100: oklch(91.59% 0.06 152.00deg);
|
--color-success-100: oklch(91.59% 0.06 152deg);
|
||||||
--color-success-200: oklch(87.45% 0.08 152.08deg);
|
--color-success-200: oklch(87.45% 0.08 152.08deg);
|
||||||
--color-success-300: oklch(83.57% 0.09 150.85deg);
|
--color-success-300: oklch(83.57% 0.09 150.85deg);
|
||||||
--color-success-400: oklch(79.47% 0.11 150.71deg);
|
--color-success-400: oklch(79.47% 0.11 150.71deg);
|
||||||
@@ -114,51 +114,51 @@ html[data-theme='AE_Firefly_Indigo'] {
|
|||||||
--color-success-600: oklch(67.65% 0.11 149.94deg);
|
--color-success-600: oklch(67.65% 0.11 149.94deg);
|
||||||
--color-success-700: oklch(59.71% 0.09 150.42deg);
|
--color-success-700: oklch(59.71% 0.09 150.42deg);
|
||||||
--color-success-800: oklch(51.74% 0.08 150.24deg);
|
--color-success-800: oklch(51.74% 0.08 150.24deg);
|
||||||
--color-success-900: oklch(43.20% 0.06 151.12deg);
|
--color-success-900: oklch(43.2% 0.06 151.12deg);
|
||||||
--color-success-950: oklch(34.20% 0.04 151.44deg);
|
--color-success-950: oklch(34.2% 0.04 151.44deg);
|
||||||
--color-success-contrast-dark: var(--color-success-950);
|
--color-success-contrast-dark: var(--color-success-950);
|
||||||
--color-success-contrast-light: var(--color-success-50);
|
--color-success-contrast-light: var(--color-success-50);
|
||||||
|
|
||||||
--color-warning-50: oklch(97.5% 0.065 78deg);
|
--color-warning-50: oklch(97.5% 0.065 78deg);
|
||||||
--color-warning-100: oklch(93.5% 0.090 75deg);
|
--color-warning-100: oklch(93.5% 0.09 75deg);
|
||||||
--color-warning-200: oklch(89.5% 0.120 73deg);
|
--color-warning-200: oklch(89.5% 0.12 73deg);
|
||||||
--color-warning-300: oklch(85.5% 0.145 70deg);
|
--color-warning-300: oklch(85.5% 0.145 70deg);
|
||||||
--color-warning-400: oklch(81.5% 0.160 67deg);
|
--color-warning-400: oklch(81.5% 0.16 67deg);
|
||||||
--color-warning-500: oklch(77.0% 0.165 65deg);
|
--color-warning-500: oklch(77% 0.165 65deg);
|
||||||
--color-warning-600: oklch(69.5% 0.155 64deg);
|
--color-warning-600: oklch(69.5% 0.155 64deg);
|
||||||
--color-warning-700: oklch(61.5% 0.140 63deg);
|
--color-warning-700: oklch(61.5% 0.14 63deg);
|
||||||
--color-warning-800: oklch(53.5% 0.125 62deg);
|
--color-warning-800: oklch(53.5% 0.125 62deg);
|
||||||
--color-warning-900: oklch(45.0% 0.105 61deg);
|
--color-warning-900: oklch(45% 0.105 61deg);
|
||||||
--color-warning-950: oklch(37.0% 0.088 60deg);
|
--color-warning-950: oklch(37% 0.088 60deg);
|
||||||
--color-warning-contrast-dark: var(--color-warning-950);
|
--color-warning-contrast-dark: var(--color-warning-950);
|
||||||
--color-warning-contrast-light: var(--color-warning-50);
|
--color-warning-contrast-light: var(--color-warning-50);
|
||||||
|
|
||||||
--color-error-50: oklch(95.0% 0.040 18deg);
|
--color-error-50: oklch(95% 0.04 18deg);
|
||||||
--color-error-100: oklch(88.0% 0.070 20deg);
|
--color-error-100: oklch(88% 0.07 20deg);
|
||||||
--color-error-200: oklch(80.0% 0.105 21deg);
|
--color-error-200: oklch(80% 0.105 21deg);
|
||||||
--color-error-300: oklch(72.0% 0.140 22deg);
|
--color-error-300: oklch(72% 0.14 22deg);
|
||||||
--color-error-400: oklch(64.5% 0.170 23deg);
|
--color-error-400: oklch(64.5% 0.17 23deg);
|
||||||
--color-error-500: oklch(57.5% 0.195 24deg);
|
--color-error-500: oklch(57.5% 0.195 24deg);
|
||||||
--color-error-600: oklch(51.5% 0.182 25deg);
|
--color-error-600: oklch(51.5% 0.182 25deg);
|
||||||
--color-error-700: oklch(45.5% 0.165 26deg);
|
--color-error-700: oklch(45.5% 0.165 26deg);
|
||||||
--color-error-800: oklch(39.5% 0.148 27deg);
|
--color-error-800: oklch(39.5% 0.148 27deg);
|
||||||
--color-error-900: oklch(33.0% 0.128 28deg);
|
--color-error-900: oklch(33% 0.128 28deg);
|
||||||
--color-error-950: oklch(26.5% 0.108 29deg);
|
--color-error-950: oklch(26.5% 0.108 29deg);
|
||||||
--color-error-contrast-dark: var(--color-error-950);
|
--color-error-contrast-dark: var(--color-error-950);
|
||||||
--color-error-contrast-light: var(--color-error-50);
|
--color-error-contrast-light: var(--color-error-50);
|
||||||
|
|
||||||
--color-surface-50: oklch(99.0% 0.003 270deg);
|
--color-surface-50: oklch(99% 0.003 270deg);
|
||||||
--color-surface-100: oklch(96.5% 0.006 268deg);
|
--color-surface-100: oklch(96.5% 0.006 268deg);
|
||||||
--color-surface-200: oklch(92.5% 0.010 266deg);
|
--color-surface-200: oklch(92.5% 0.01 266deg);
|
||||||
--color-surface-300: oklch(87.0% 0.014 265deg);
|
--color-surface-300: oklch(87% 0.014 265deg);
|
||||||
--color-surface-400: oklch(78.5% 0.018 265deg);
|
--color-surface-400: oklch(78.5% 0.018 265deg);
|
||||||
--color-surface-500: oklch(66.5% 0.020 267deg);
|
--color-surface-500: oklch(66.5% 0.02 267deg);
|
||||||
--color-surface-600: oklch(54.5% 0.022 269deg);
|
--color-surface-600: oklch(54.5% 0.022 269deg);
|
||||||
--color-surface-700: oklch(42.5% 0.024 270deg);
|
--color-surface-700: oklch(42.5% 0.024 270deg);
|
||||||
--color-surface-800: oklch(31.0% 0.026 272deg);
|
--color-surface-800: oklch(31% 0.026 272deg);
|
||||||
--color-surface-900: oklch(20.5% 0.030 274deg);
|
--color-surface-900: oklch(20.5% 0.03 274deg);
|
||||||
--color-surface-950: oklch(13.0% 0.034 276deg);
|
--color-surface-950: oklch(13% 0.034 276deg);
|
||||||
--color-surface-contrast-dark: var(--color-surface-950);
|
--color-surface-contrast-dark: var(--color-surface-950);
|
||||||
--color-surface-contrast-light: var(--color-surface-50);
|
--color-surface-contrast-light: var(--color-surface-50);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,20 +182,20 @@ html.dark[data-theme='AE_Firefly_Indigo'] {
|
|||||||
* maintaining sufficient contrast at mid-range shades.
|
* maintaining sufficient contrast at mid-range shades.
|
||||||
* At 500 (L≈50%): sufficient contrast with primary-50 text (≥4:1).
|
* At 500 (L≈50%): sufficient contrast with primary-50 text (≥4:1).
|
||||||
* =================================================================== */
|
* =================================================================== */
|
||||||
--color-primary-50: oklch(95.5% 0.040 270deg);
|
--color-primary-50: oklch(95.5% 0.04 270deg);
|
||||||
--color-primary-100: oklch(89.5% 0.072 270deg);
|
--color-primary-100: oklch(89.5% 0.072 270deg);
|
||||||
--color-primary-200: oklch(82.5% 0.108 269deg);
|
--color-primary-200: oklch(82.5% 0.108 269deg);
|
||||||
--color-primary-300: oklch(74.5% 0.135 268deg);
|
--color-primary-300: oklch(74.5% 0.135 268deg);
|
||||||
--color-primary-400: oklch(65.0% 0.155 267deg);
|
--color-primary-400: oklch(65% 0.155 267deg);
|
||||||
--color-primary-500: oklch(50.5% 0.160 266deg);
|
--color-primary-500: oklch(50.5% 0.16 266deg);
|
||||||
--color-primary-600: oklch(43.5% 0.152 265deg);
|
--color-primary-600: oklch(43.5% 0.152 265deg);
|
||||||
--color-primary-700: oklch(37.0% 0.138 264deg);
|
--color-primary-700: oklch(37% 0.138 264deg);
|
||||||
--color-primary-800: oklch(30.0% 0.120 263deg);
|
--color-primary-800: oklch(30% 0.12 263deg);
|
||||||
--color-primary-900: oklch(23.0% 0.100 262deg);
|
--color-primary-900: oklch(23% 0.1 262deg);
|
||||||
--color-primary-950: oklch(15.5% 0.080 261deg);
|
--color-primary-950: oklch(15.5% 0.08 261deg);
|
||||||
--color-primary-contrast-dark: var(--color-primary-950);
|
--color-primary-contrast-dark: var(--color-primary-950);
|
||||||
--color-primary-contrast-light: var(--color-primary-50);
|
--color-primary-contrast-light: var(--color-primary-50);
|
||||||
--color-primary-contrast-50: var(--color-primary-contrast-dark);
|
--color-primary-contrast-50: var(--color-primary-contrast-dark);
|
||||||
--color-primary-contrast-100: 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-200: var(--color-primary-contrast-dark);
|
||||||
--color-primary-contrast-300: var(--color-primary-contrast-dark);
|
--color-primary-contrast-300: var(--color-primary-contrast-dark);
|
||||||
@@ -214,20 +214,20 @@ html.dark[data-theme='AE_Firefly_Indigo'] {
|
|||||||
* remaining clearly distinct from the primary.
|
* remaining clearly distinct from the primary.
|
||||||
* Used for secondary actions, badges, and soft highlights.
|
* Used for secondary actions, badges, and soft highlights.
|
||||||
* =================================================================== */
|
* =================================================================== */
|
||||||
--color-secondary-50: oklch(96.5% 0.032 297deg);
|
--color-secondary-50: oklch(96.5% 0.032 297deg);
|
||||||
--color-secondary-100: oklch(91.5% 0.058 295deg);
|
--color-secondary-100: oklch(91.5% 0.058 295deg);
|
||||||
--color-secondary-200: oklch(85.5% 0.090 293deg);
|
--color-secondary-200: oklch(85.5% 0.09 293deg);
|
||||||
--color-secondary-300: oklch(78.5% 0.115 292deg);
|
--color-secondary-300: oklch(78.5% 0.115 292deg);
|
||||||
--color-secondary-400: oklch(70.0% 0.132 291deg);
|
--color-secondary-400: oklch(70% 0.132 291deg);
|
||||||
--color-secondary-500: oklch(60.0% 0.140 290deg);
|
--color-secondary-500: oklch(60% 0.14 290deg);
|
||||||
--color-secondary-600: oklch(52.5% 0.135 289deg);
|
--color-secondary-600: oklch(52.5% 0.135 289deg);
|
||||||
--color-secondary-700: oklch(45.0% 0.126 288deg);
|
--color-secondary-700: oklch(45% 0.126 288deg);
|
||||||
--color-secondary-800: oklch(37.5% 0.112 286deg);
|
--color-secondary-800: oklch(37.5% 0.112 286deg);
|
||||||
--color-secondary-900: oklch(30.0% 0.094 284deg);
|
--color-secondary-900: oklch(30% 0.094 284deg);
|
||||||
--color-secondary-950: oklch(22.0% 0.076 282deg);
|
--color-secondary-950: oklch(22% 0.076 282deg);
|
||||||
--color-secondary-contrast-dark: var(--color-secondary-950);
|
--color-secondary-contrast-dark: var(--color-secondary-950);
|
||||||
--color-secondary-contrast-light: var(--color-secondary-50);
|
--color-secondary-contrast-light: var(--color-secondary-50);
|
||||||
--color-secondary-contrast-50: var(--color-secondary-contrast-dark);
|
--color-secondary-contrast-50: var(--color-secondary-contrast-dark);
|
||||||
--color-secondary-contrast-100: 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-200: var(--color-secondary-contrast-dark);
|
||||||
--color-secondary-contrast-300: var(--color-secondary-contrast-dark);
|
--color-secondary-contrast-300: var(--color-secondary-contrast-dark);
|
||||||
@@ -247,20 +247,20 @@ html.dark[data-theme='AE_Firefly_Indigo'] {
|
|||||||
* breaking against a deep indigo sky.
|
* breaking against a deep indigo sky.
|
||||||
* Used for location chips, warm accents, tertiary elements.
|
* Used for location chips, warm accents, tertiary elements.
|
||||||
* =================================================================== */
|
* =================================================================== */
|
||||||
--color-tertiary-50: oklch(96.5% 0.022 348deg);
|
--color-tertiary-50: oklch(96.5% 0.022 348deg);
|
||||||
--color-tertiary-100: oklch(91.0% 0.042 346deg);
|
--color-tertiary-100: oklch(91% 0.042 346deg);
|
||||||
--color-tertiary-200: oklch(84.5% 0.068 344deg);
|
--color-tertiary-200: oklch(84.5% 0.068 344deg);
|
||||||
--color-tertiary-300: oklch(76.5% 0.095 343deg);
|
--color-tertiary-300: oklch(76.5% 0.095 343deg);
|
||||||
--color-tertiary-400: oklch(68.0% 0.118 342deg);
|
--color-tertiary-400: oklch(68% 0.118 342deg);
|
||||||
--color-tertiary-500: oklch(57.5% 0.128 341deg);
|
--color-tertiary-500: oklch(57.5% 0.128 341deg);
|
||||||
--color-tertiary-600: oklch(50.0% 0.122 340deg);
|
--color-tertiary-600: oklch(50% 0.122 340deg);
|
||||||
--color-tertiary-700: oklch(43.0% 0.112 339deg);
|
--color-tertiary-700: oklch(43% 0.112 339deg);
|
||||||
--color-tertiary-800: oklch(35.5% 0.098 338deg);
|
--color-tertiary-800: oklch(35.5% 0.098 338deg);
|
||||||
--color-tertiary-900: oklch(28.0% 0.080 337deg);
|
--color-tertiary-900: oklch(28% 0.08 337deg);
|
||||||
--color-tertiary-950: oklch(20.5% 0.062 336deg);
|
--color-tertiary-950: oklch(20.5% 0.062 336deg);
|
||||||
--color-tertiary-contrast-dark: var(--color-tertiary-950);
|
--color-tertiary-contrast-dark: var(--color-tertiary-950);
|
||||||
--color-tertiary-contrast-light: var(--color-tertiary-50);
|
--color-tertiary-contrast-light: var(--color-tertiary-50);
|
||||||
--color-tertiary-contrast-50: var(--color-tertiary-contrast-dark);
|
--color-tertiary-contrast-50: var(--color-tertiary-contrast-dark);
|
||||||
--color-tertiary-contrast-100: 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-200: var(--color-tertiary-contrast-dark);
|
||||||
--color-tertiary-contrast-300: var(--color-tertiary-contrast-dark);
|
--color-tertiary-contrast-300: var(--color-tertiary-contrast-dark);
|
||||||
@@ -277,8 +277,8 @@ html.dark[data-theme='AE_Firefly_Indigo'] {
|
|||||||
* Hue: ~152°. Consistent with AE_Firefly for recognizable semantic
|
* Hue: ~152°. Consistent with AE_Firefly for recognizable semantic
|
||||||
* color meaning across OSIT themes.
|
* color meaning across OSIT themes.
|
||||||
* =================================================================== */
|
* =================================================================== */
|
||||||
--color-success-50: oklch(95.77% 0.05 152.69deg);
|
--color-success-50: oklch(95.77% 0.05 152.69deg);
|
||||||
--color-success-100: oklch(91.59% 0.06 152.00deg);
|
--color-success-100: oklch(91.59% 0.06 152deg);
|
||||||
--color-success-200: oklch(87.45% 0.08 152.08deg);
|
--color-success-200: oklch(87.45% 0.08 152.08deg);
|
||||||
--color-success-300: oklch(83.57% 0.09 150.85deg);
|
--color-success-300: oklch(83.57% 0.09 150.85deg);
|
||||||
--color-success-400: oklch(79.47% 0.11 150.71deg);
|
--color-success-400: oklch(79.47% 0.11 150.71deg);
|
||||||
@@ -286,11 +286,11 @@ html.dark[data-theme='AE_Firefly_Indigo'] {
|
|||||||
--color-success-600: oklch(67.65% 0.11 149.94deg);
|
--color-success-600: oklch(67.65% 0.11 149.94deg);
|
||||||
--color-success-700: oklch(59.71% 0.09 150.42deg);
|
--color-success-700: oklch(59.71% 0.09 150.42deg);
|
||||||
--color-success-800: oklch(51.74% 0.08 150.24deg);
|
--color-success-800: oklch(51.74% 0.08 150.24deg);
|
||||||
--color-success-900: oklch(43.20% 0.06 151.12deg);
|
--color-success-900: oklch(43.2% 0.06 151.12deg);
|
||||||
--color-success-950: oklch(34.20% 0.04 151.44deg);
|
--color-success-950: oklch(34.2% 0.04 151.44deg);
|
||||||
--color-success-contrast-dark: var(--color-success-950);
|
--color-success-contrast-dark: var(--color-success-950);
|
||||||
--color-success-contrast-light: var(--color-success-50);
|
--color-success-contrast-light: var(--color-success-50);
|
||||||
--color-success-contrast-50: var(--color-success-contrast-dark);
|
--color-success-contrast-50: var(--color-success-contrast-dark);
|
||||||
--color-success-contrast-100: 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-200: var(--color-success-contrast-dark);
|
||||||
--color-success-contrast-300: var(--color-success-contrast-dark);
|
--color-success-contrast-300: var(--color-success-contrast-dark);
|
||||||
@@ -306,20 +306,20 @@ html.dark[data-theme='AE_Firefly_Indigo'] {
|
|||||||
* WARNING — Amber Orange
|
* WARNING — Amber Orange
|
||||||
* Consistent with AE_Firefly for recognizable semantic meaning.
|
* Consistent with AE_Firefly for recognizable semantic meaning.
|
||||||
* =================================================================== */
|
* =================================================================== */
|
||||||
--color-warning-50: oklch(97.5% 0.065 78deg);
|
--color-warning-50: oklch(97.5% 0.065 78deg);
|
||||||
--color-warning-100: oklch(93.5% 0.090 75deg);
|
--color-warning-100: oklch(93.5% 0.09 75deg);
|
||||||
--color-warning-200: oklch(89.5% 0.120 73deg);
|
--color-warning-200: oklch(89.5% 0.12 73deg);
|
||||||
--color-warning-300: oklch(85.5% 0.145 70deg);
|
--color-warning-300: oklch(85.5% 0.145 70deg);
|
||||||
--color-warning-400: oklch(81.5% 0.160 67deg);
|
--color-warning-400: oklch(81.5% 0.16 67deg);
|
||||||
--color-warning-500: oklch(77.0% 0.165 65deg);
|
--color-warning-500: oklch(77% 0.165 65deg);
|
||||||
--color-warning-600: oklch(69.5% 0.155 64deg);
|
--color-warning-600: oklch(69.5% 0.155 64deg);
|
||||||
--color-warning-700: oklch(61.5% 0.140 63deg);
|
--color-warning-700: oklch(61.5% 0.14 63deg);
|
||||||
--color-warning-800: oklch(53.5% 0.125 62deg);
|
--color-warning-800: oklch(53.5% 0.125 62deg);
|
||||||
--color-warning-900: oklch(45.0% 0.105 61deg);
|
--color-warning-900: oklch(45% 0.105 61deg);
|
||||||
--color-warning-950: oklch(37.0% 0.088 60deg);
|
--color-warning-950: oklch(37% 0.088 60deg);
|
||||||
--color-warning-contrast-dark: var(--color-warning-950);
|
--color-warning-contrast-dark: var(--color-warning-950);
|
||||||
--color-warning-contrast-light: var(--color-warning-50);
|
--color-warning-contrast-light: var(--color-warning-50);
|
||||||
--color-warning-contrast-50: var(--color-warning-contrast-dark);
|
--color-warning-contrast-50: var(--color-warning-contrast-dark);
|
||||||
--color-warning-contrast-100: 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-200: var(--color-warning-contrast-dark);
|
||||||
--color-warning-contrast-300: var(--color-warning-contrast-dark);
|
--color-warning-contrast-300: var(--color-warning-contrast-dark);
|
||||||
@@ -335,20 +335,20 @@ html.dark[data-theme='AE_Firefly_Indigo'] {
|
|||||||
* ERROR — Soft Coral/Rose
|
* ERROR — Soft Coral/Rose
|
||||||
* Consistent with AE_Firefly for recognizable semantic meaning.
|
* Consistent with AE_Firefly for recognizable semantic meaning.
|
||||||
* =================================================================== */
|
* =================================================================== */
|
||||||
--color-error-50: oklch(95.0% 0.040 18deg);
|
--color-error-50: oklch(95% 0.04 18deg);
|
||||||
--color-error-100: oklch(88.0% 0.070 20deg);
|
--color-error-100: oklch(88% 0.07 20deg);
|
||||||
--color-error-200: oklch(80.0% 0.105 21deg);
|
--color-error-200: oklch(80% 0.105 21deg);
|
||||||
--color-error-300: oklch(72.0% 0.140 22deg);
|
--color-error-300: oklch(72% 0.14 22deg);
|
||||||
--color-error-400: oklch(64.5% 0.170 23deg);
|
--color-error-400: oklch(64.5% 0.17 23deg);
|
||||||
--color-error-500: oklch(57.5% 0.195 24deg);
|
--color-error-500: oklch(57.5% 0.195 24deg);
|
||||||
--color-error-600: oklch(51.5% 0.182 25deg);
|
--color-error-600: oklch(51.5% 0.182 25deg);
|
||||||
--color-error-700: oklch(45.5% 0.165 26deg);
|
--color-error-700: oklch(45.5% 0.165 26deg);
|
||||||
--color-error-800: oklch(39.5% 0.148 27deg);
|
--color-error-800: oklch(39.5% 0.148 27deg);
|
||||||
--color-error-900: oklch(33.0% 0.128 28deg);
|
--color-error-900: oklch(33% 0.128 28deg);
|
||||||
--color-error-950: oklch(26.5% 0.108 29deg);
|
--color-error-950: oklch(26.5% 0.108 29deg);
|
||||||
--color-error-contrast-dark: var(--color-error-950);
|
--color-error-contrast-dark: var(--color-error-950);
|
||||||
--color-error-contrast-light: var(--color-error-50);
|
--color-error-contrast-light: var(--color-error-50);
|
||||||
--color-error-contrast-50: var(--color-error-contrast-dark);
|
--color-error-contrast-50: var(--color-error-contrast-dark);
|
||||||
--color-error-contrast-100: 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-200: var(--color-error-contrast-dark);
|
||||||
--color-error-contrast-300: var(--color-error-contrast-dark);
|
--color-error-contrast-300: var(--color-error-contrast-dark);
|
||||||
@@ -370,20 +370,20 @@ html.dark[data-theme='AE_Firefly_Indigo'] {
|
|||||||
* 50 → body-bg light: near-white with ImperceptibleISTIC purple cast
|
* 50 → body-bg light: near-white with ImperceptibleISTIC purple cast
|
||||||
* 950 → body-bg dark: deep midnight with indigo depth
|
* 950 → body-bg dark: deep midnight with indigo depth
|
||||||
* =================================================================== */
|
* =================================================================== */
|
||||||
--color-surface-50: oklch(99.0% 0.003 270deg);
|
--color-surface-50: oklch(99% 0.003 270deg);
|
||||||
--color-surface-100: oklch(96.5% 0.006 268deg);
|
--color-surface-100: oklch(96.5% 0.006 268deg);
|
||||||
--color-surface-200: oklch(92.5% 0.010 266deg);
|
--color-surface-200: oklch(92.5% 0.01 266deg);
|
||||||
--color-surface-300: oklch(87.0% 0.014 265deg);
|
--color-surface-300: oklch(87% 0.014 265deg);
|
||||||
--color-surface-400: oklch(78.5% 0.018 265deg);
|
--color-surface-400: oklch(78.5% 0.018 265deg);
|
||||||
--color-surface-500: oklch(66.5% 0.020 267deg);
|
--color-surface-500: oklch(66.5% 0.02 267deg);
|
||||||
--color-surface-600: oklch(54.5% 0.022 269deg);
|
--color-surface-600: oklch(54.5% 0.022 269deg);
|
||||||
--color-surface-700: oklch(42.5% 0.024 270deg);
|
--color-surface-700: oklch(42.5% 0.024 270deg);
|
||||||
--color-surface-800: oklch(31.0% 0.026 272deg);
|
--color-surface-800: oklch(31% 0.026 272deg);
|
||||||
--color-surface-900: oklch(20.5% 0.030 274deg);
|
--color-surface-900: oklch(20.5% 0.03 274deg);
|
||||||
--color-surface-950: oklch(13.0% 0.034 276deg);
|
--color-surface-950: oklch(13% 0.034 276deg);
|
||||||
--color-surface-contrast-dark: var(--color-surface-950);
|
--color-surface-contrast-dark: var(--color-surface-950);
|
||||||
--color-surface-contrast-light: var(--color-surface-50);
|
--color-surface-contrast-light: var(--color-surface-50);
|
||||||
--color-surface-contrast-50: var(--color-surface-contrast-dark);
|
--color-surface-contrast-50: var(--color-surface-contrast-dark);
|
||||||
--color-surface-contrast-100: 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-200: var(--color-surface-contrast-dark);
|
||||||
--color-surface-contrast-300: var(--color-surface-contrast-dark);
|
--color-surface-contrast-300: var(--color-surface-contrast-dark);
|
||||||
|
|||||||
@@ -63,50 +63,50 @@ html[data-theme='AE_Firefly_Rainbow'] {
|
|||||||
|
|
||||||
/* --- Color ramps (light mode) copied from dark block so both modes have full ramps --- */
|
/* --- Color ramps (light mode) copied from dark block so both modes have full ramps --- */
|
||||||
html[data-theme='AE_Firefly_Rainbow'] {
|
html[data-theme='AE_Firefly_Rainbow'] {
|
||||||
--color-primary-50: oklch(97.0% 0.020 15deg);
|
--color-primary-50: oklch(97% 0.02 15deg);
|
||||||
--color-primary-100: oklch(92.0% 0.048 14deg);
|
--color-primary-100: oklch(92% 0.048 14deg);
|
||||||
--color-primary-200: oklch(86.0% 0.085 13deg);
|
--color-primary-200: oklch(86% 0.085 13deg);
|
||||||
--color-primary-300: oklch(79.0% 0.125 13deg);
|
--color-primary-300: oklch(79% 0.125 13deg);
|
||||||
--color-primary-400: oklch(71.0% 0.160 13deg);
|
--color-primary-400: oklch(71% 0.16 13deg);
|
||||||
--color-primary-500: oklch(60.0% 0.190 14deg);
|
--color-primary-500: oklch(60% 0.19 14deg);
|
||||||
--color-primary-600: oklch(52.5% 0.178 15deg);
|
--color-primary-600: oklch(52.5% 0.178 15deg);
|
||||||
--color-primary-700: oklch(45.0% 0.162 16deg);
|
--color-primary-700: oklch(45% 0.162 16deg);
|
||||||
--color-primary-800: oklch(37.5% 0.142 17deg);
|
--color-primary-800: oklch(37.5% 0.142 17deg);
|
||||||
--color-primary-900: oklch(30.0% 0.118 18deg);
|
--color-primary-900: oklch(30% 0.118 18deg);
|
||||||
--color-primary-950: oklch(22.5% 0.092 19deg);
|
--color-primary-950: oklch(22.5% 0.092 19deg);
|
||||||
--color-primary-contrast-dark: var(--color-primary-950);
|
--color-primary-contrast-dark: var(--color-primary-950);
|
||||||
--color-primary-contrast-light: var(--color-primary-50);
|
--color-primary-contrast-light: var(--color-primary-50);
|
||||||
|
|
||||||
--color-secondary-50: oklch(97.0% 0.040 152deg);
|
--color-secondary-50: oklch(97% 0.04 152deg);
|
||||||
--color-secondary-100: oklch(92.5% 0.072 150deg);
|
--color-secondary-100: oklch(92.5% 0.072 150deg);
|
||||||
--color-secondary-200: oklch(87.0% 0.105 149deg);
|
--color-secondary-200: oklch(87% 0.105 149deg);
|
||||||
--color-secondary-300: oklch(81.0% 0.132 148deg);
|
--color-secondary-300: oklch(81% 0.132 148deg);
|
||||||
--color-secondary-400: oklch(74.5% 0.152 148deg);
|
--color-secondary-400: oklch(74.5% 0.152 148deg);
|
||||||
--color-secondary-500: oklch(62.0% 0.160 148deg);
|
--color-secondary-500: oklch(62% 0.16 148deg);
|
||||||
--color-secondary-600: oklch(53.5% 0.148 148deg);
|
--color-secondary-600: oklch(53.5% 0.148 148deg);
|
||||||
--color-secondary-700: oklch(45.5% 0.132 147deg);
|
--color-secondary-700: oklch(45.5% 0.132 147deg);
|
||||||
--color-secondary-800: oklch(37.5% 0.112 146deg);
|
--color-secondary-800: oklch(37.5% 0.112 146deg);
|
||||||
--color-secondary-900: oklch(29.5% 0.090 145deg);
|
--color-secondary-900: oklch(29.5% 0.09 145deg);
|
||||||
--color-secondary-950: oklch(21.5% 0.068 144deg);
|
--color-secondary-950: oklch(21.5% 0.068 144deg);
|
||||||
--color-secondary-contrast-dark: var(--color-secondary-950);
|
--color-secondary-contrast-dark: var(--color-secondary-950);
|
||||||
--color-secondary-contrast-light: var(--color-secondary-50);
|
--color-secondary-contrast-light: var(--color-secondary-50);
|
||||||
|
|
||||||
--color-tertiary-50: oklch(96.5% 0.030 299deg);
|
--color-tertiary-50: oklch(96.5% 0.03 299deg);
|
||||||
--color-tertiary-100: oklch(91.0% 0.058 297deg);
|
--color-tertiary-100: oklch(91% 0.058 297deg);
|
||||||
--color-tertiary-200: oklch(84.5% 0.092 296deg);
|
--color-tertiary-200: oklch(84.5% 0.092 296deg);
|
||||||
--color-tertiary-300: oklch(77.0% 0.122 295deg);
|
--color-tertiary-300: oklch(77% 0.122 295deg);
|
||||||
--color-tertiary-400: oklch(68.5% 0.148 295deg);
|
--color-tertiary-400: oklch(68.5% 0.148 295deg);
|
||||||
--color-tertiary-500: oklch(57.0% 0.158 295deg);
|
--color-tertiary-500: oklch(57% 0.158 295deg);
|
||||||
--color-tertiary-600: oklch(49.5% 0.150 294deg);
|
--color-tertiary-600: oklch(49.5% 0.15 294deg);
|
||||||
--color-tertiary-700: oklch(42.5% 0.138 293deg);
|
--color-tertiary-700: oklch(42.5% 0.138 293deg);
|
||||||
--color-tertiary-800: oklch(35.5% 0.122 292deg);
|
--color-tertiary-800: oklch(35.5% 0.122 292deg);
|
||||||
--color-tertiary-900: oklch(28.5% 0.102 291deg);
|
--color-tertiary-900: oklch(28.5% 0.102 291deg);
|
||||||
--color-tertiary-950: oklch(21.0% 0.080 290deg);
|
--color-tertiary-950: oklch(21% 0.08 290deg);
|
||||||
--color-tertiary-contrast-dark: var(--color-tertiary-950);
|
--color-tertiary-contrast-dark: var(--color-tertiary-950);
|
||||||
--color-tertiary-contrast-light: var(--color-tertiary-50);
|
--color-tertiary-contrast-light: var(--color-tertiary-50);
|
||||||
|
|
||||||
--color-success-50: oklch(95.77% 0.05 152.69deg);
|
--color-success-50: oklch(95.77% 0.05 152.69deg);
|
||||||
--color-success-100: oklch(91.59% 0.06 152.00deg);
|
--color-success-100: oklch(91.59% 0.06 152deg);
|
||||||
--color-success-200: oklch(87.45% 0.08 152.08deg);
|
--color-success-200: oklch(87.45% 0.08 152.08deg);
|
||||||
--color-success-300: oklch(83.57% 0.09 150.85deg);
|
--color-success-300: oklch(83.57% 0.09 150.85deg);
|
||||||
--color-success-400: oklch(79.47% 0.11 150.71deg);
|
--color-success-400: oklch(79.47% 0.11 150.71deg);
|
||||||
@@ -114,51 +114,51 @@ html[data-theme='AE_Firefly_Rainbow'] {
|
|||||||
--color-success-600: oklch(67.65% 0.11 149.94deg);
|
--color-success-600: oklch(67.65% 0.11 149.94deg);
|
||||||
--color-success-700: oklch(59.71% 0.09 150.42deg);
|
--color-success-700: oklch(59.71% 0.09 150.42deg);
|
||||||
--color-success-800: oklch(51.74% 0.08 150.24deg);
|
--color-success-800: oklch(51.74% 0.08 150.24deg);
|
||||||
--color-success-900: oklch(43.20% 0.06 151.12deg);
|
--color-success-900: oklch(43.2% 0.06 151.12deg);
|
||||||
--color-success-950: oklch(34.20% 0.04 151.44deg);
|
--color-success-950: oklch(34.2% 0.04 151.44deg);
|
||||||
--color-success-contrast-dark: var(--color-success-950);
|
--color-success-contrast-dark: var(--color-success-950);
|
||||||
--color-success-contrast-light: var(--color-success-50);
|
--color-success-contrast-light: var(--color-success-50);
|
||||||
|
|
||||||
--color-warning-50: oklch(97.5% 0.065 78deg);
|
--color-warning-50: oklch(97.5% 0.065 78deg);
|
||||||
--color-warning-100: oklch(93.5% 0.090 75deg);
|
--color-warning-100: oklch(93.5% 0.09 75deg);
|
||||||
--color-warning-200: oklch(89.5% 0.120 73deg);
|
--color-warning-200: oklch(89.5% 0.12 73deg);
|
||||||
--color-warning-300: oklch(85.5% 0.145 70deg);
|
--color-warning-300: oklch(85.5% 0.145 70deg);
|
||||||
--color-warning-400: oklch(81.5% 0.160 67deg);
|
--color-warning-400: oklch(81.5% 0.16 67deg);
|
||||||
--color-warning-500: oklch(77.0% 0.165 65deg);
|
--color-warning-500: oklch(77% 0.165 65deg);
|
||||||
--color-warning-600: oklch(69.5% 0.155 64deg);
|
--color-warning-600: oklch(69.5% 0.155 64deg);
|
||||||
--color-warning-700: oklch(61.5% 0.140 63deg);
|
--color-warning-700: oklch(61.5% 0.14 63deg);
|
||||||
--color-warning-800: oklch(53.5% 0.125 62deg);
|
--color-warning-800: oklch(53.5% 0.125 62deg);
|
||||||
--color-warning-900: oklch(45.0% 0.105 61deg);
|
--color-warning-900: oklch(45% 0.105 61deg);
|
||||||
--color-warning-950: oklch(37.0% 0.088 60deg);
|
--color-warning-950: oklch(37% 0.088 60deg);
|
||||||
--color-warning-contrast-dark: var(--color-warning-950);
|
--color-warning-contrast-dark: var(--color-warning-950);
|
||||||
--color-warning-contrast-light: var(--color-warning-50);
|
--color-warning-contrast-light: var(--color-warning-50);
|
||||||
|
|
||||||
--color-error-50: oklch(95.0% 0.040 18deg);
|
--color-error-50: oklch(95% 0.04 18deg);
|
||||||
--color-error-100: oklch(88.0% 0.070 20deg);
|
--color-error-100: oklch(88% 0.07 20deg);
|
||||||
--color-error-200: oklch(80.0% 0.105 21deg);
|
--color-error-200: oklch(80% 0.105 21deg);
|
||||||
--color-error-300: oklch(72.0% 0.140 22deg);
|
--color-error-300: oklch(72% 0.14 22deg);
|
||||||
--color-error-400: oklch(64.5% 0.170 23deg);
|
--color-error-400: oklch(64.5% 0.17 23deg);
|
||||||
--color-error-500: oklch(57.5% 0.195 24deg);
|
--color-error-500: oklch(57.5% 0.195 24deg);
|
||||||
--color-error-600: oklch(51.5% 0.182 25deg);
|
--color-error-600: oklch(51.5% 0.182 25deg);
|
||||||
--color-error-700: oklch(45.5% 0.165 26deg);
|
--color-error-700: oklch(45.5% 0.165 26deg);
|
||||||
--color-error-800: oklch(39.5% 0.148 27deg);
|
--color-error-800: oklch(39.5% 0.148 27deg);
|
||||||
--color-error-900: oklch(33.0% 0.128 28deg);
|
--color-error-900: oklch(33% 0.128 28deg);
|
||||||
--color-error-950: oklch(26.5% 0.108 29deg);
|
--color-error-950: oklch(26.5% 0.108 29deg);
|
||||||
--color-error-contrast-dark: var(--color-error-950);
|
--color-error-contrast-dark: var(--color-error-950);
|
||||||
--color-error-contrast-light: var(--color-error-50);
|
--color-error-contrast-light: var(--color-error-50);
|
||||||
|
|
||||||
--color-surface-50: oklch(99.2% 0.004 75deg);
|
--color-surface-50: oklch(99.2% 0.004 75deg);
|
||||||
--color-surface-100: oklch(97.0% 0.007 72deg);
|
--color-surface-100: oklch(97% 0.007 72deg);
|
||||||
--color-surface-200: oklch(93.5% 0.010 70deg);
|
--color-surface-200: oklch(93.5% 0.01 70deg);
|
||||||
--color-surface-300: oklch(88.5% 0.013 68deg);
|
--color-surface-300: oklch(88.5% 0.013 68deg);
|
||||||
--color-surface-400: oklch(81.5% 0.016 66deg);
|
--color-surface-400: oklch(81.5% 0.016 66deg);
|
||||||
--color-surface-500: oklch(70.5% 0.018 64deg);
|
--color-surface-500: oklch(70.5% 0.018 64deg);
|
||||||
--color-surface-600: oklch(59.0% 0.018 62deg);
|
--color-surface-600: oklch(59% 0.018 62deg);
|
||||||
--color-surface-700: oklch(47.5% 0.018 58deg);
|
--color-surface-700: oklch(47.5% 0.018 58deg);
|
||||||
--color-surface-800: oklch(35.5% 0.020 55deg);
|
--color-surface-800: oklch(35.5% 0.02 55deg);
|
||||||
--color-surface-900: oklch(24.5% 0.020 52deg);
|
--color-surface-900: oklch(24.5% 0.02 52deg);
|
||||||
--color-surface-950: oklch(15.5% 0.022 48deg);
|
--color-surface-950: oklch(15.5% 0.022 48deg);
|
||||||
--color-surface-contrast-dark: var(--color-surface-950);
|
--color-surface-contrast-dark: var(--color-surface-950);
|
||||||
--color-surface-contrast-light: var(--color-surface-50);
|
--color-surface-contrast-light: var(--color-surface-50);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,20 +180,20 @@ html.dark[data-theme='AE_Firefly_Rainbow'] {
|
|||||||
* Kept within sRGB gamut across the full ramp.
|
* Kept within sRGB gamut across the full ramp.
|
||||||
* At 500 (L≈60%): sufficient contrast with primary-50 text (≥4:1).
|
* At 500 (L≈60%): sufficient contrast with primary-50 text (≥4:1).
|
||||||
* =================================================================== */
|
* =================================================================== */
|
||||||
--color-primary-50: oklch(97.0% 0.020 15deg);
|
--color-primary-50: oklch(97% 0.02 15deg);
|
||||||
--color-primary-100: oklch(92.0% 0.048 14deg);
|
--color-primary-100: oklch(92% 0.048 14deg);
|
||||||
--color-primary-200: oklch(86.0% 0.085 13deg);
|
--color-primary-200: oklch(86% 0.085 13deg);
|
||||||
--color-primary-300: oklch(79.0% 0.125 13deg);
|
--color-primary-300: oklch(79% 0.125 13deg);
|
||||||
--color-primary-400: oklch(71.0% 0.160 13deg);
|
--color-primary-400: oklch(71% 0.16 13deg);
|
||||||
--color-primary-500: oklch(60.0% 0.190 14deg);
|
--color-primary-500: oklch(60% 0.19 14deg);
|
||||||
--color-primary-600: oklch(52.5% 0.178 15deg);
|
--color-primary-600: oklch(52.5% 0.178 15deg);
|
||||||
--color-primary-700: oklch(45.0% 0.162 16deg);
|
--color-primary-700: oklch(45% 0.162 16deg);
|
||||||
--color-primary-800: oklch(37.5% 0.142 17deg);
|
--color-primary-800: oklch(37.5% 0.142 17deg);
|
||||||
--color-primary-900: oklch(30.0% 0.118 18deg);
|
--color-primary-900: oklch(30% 0.118 18deg);
|
||||||
--color-primary-950: oklch(22.5% 0.092 19deg);
|
--color-primary-950: oklch(22.5% 0.092 19deg);
|
||||||
--color-primary-contrast-dark: var(--color-primary-950);
|
--color-primary-contrast-dark: var(--color-primary-950);
|
||||||
--color-primary-contrast-light: var(--color-primary-50);
|
--color-primary-contrast-light: var(--color-primary-50);
|
||||||
--color-primary-contrast-50: var(--color-primary-contrast-dark);
|
--color-primary-contrast-50: var(--color-primary-contrast-dark);
|
||||||
--color-primary-contrast-100: 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-200: var(--color-primary-contrast-dark);
|
||||||
--color-primary-contrast-300: var(--color-primary-contrast-dark);
|
--color-primary-contrast-300: var(--color-primary-contrast-dark);
|
||||||
@@ -212,20 +212,20 @@ html.dark[data-theme='AE_Firefly_Rainbow'] {
|
|||||||
* it bridges the warm red primary and the cool violet tertiary.
|
* it bridges the warm red primary and the cool violet tertiary.
|
||||||
* Used for secondary actions, success-adjacent highlights, badges.
|
* Used for secondary actions, success-adjacent highlights, badges.
|
||||||
* =================================================================== */
|
* =================================================================== */
|
||||||
--color-secondary-50: oklch(97.0% 0.040 152deg);
|
--color-secondary-50: oklch(97% 0.04 152deg);
|
||||||
--color-secondary-100: oklch(92.5% 0.072 150deg);
|
--color-secondary-100: oklch(92.5% 0.072 150deg);
|
||||||
--color-secondary-200: oklch(87.0% 0.105 149deg);
|
--color-secondary-200: oklch(87% 0.105 149deg);
|
||||||
--color-secondary-300: oklch(81.0% 0.132 148deg);
|
--color-secondary-300: oklch(81% 0.132 148deg);
|
||||||
--color-secondary-400: oklch(74.5% 0.152 148deg);
|
--color-secondary-400: oklch(74.5% 0.152 148deg);
|
||||||
--color-secondary-500: oklch(62.0% 0.160 148deg);
|
--color-secondary-500: oklch(62% 0.16 148deg);
|
||||||
--color-secondary-600: oklch(53.5% 0.148 148deg);
|
--color-secondary-600: oklch(53.5% 0.148 148deg);
|
||||||
--color-secondary-700: oklch(45.5% 0.132 147deg);
|
--color-secondary-700: oklch(45.5% 0.132 147deg);
|
||||||
--color-secondary-800: oklch(37.5% 0.112 146deg);
|
--color-secondary-800: oklch(37.5% 0.112 146deg);
|
||||||
--color-secondary-900: oklch(29.5% 0.090 145deg);
|
--color-secondary-900: oklch(29.5% 0.09 145deg);
|
||||||
--color-secondary-950: oklch(21.5% 0.068 144deg);
|
--color-secondary-950: oklch(21.5% 0.068 144deg);
|
||||||
--color-secondary-contrast-dark: var(--color-secondary-950);
|
--color-secondary-contrast-dark: var(--color-secondary-950);
|
||||||
--color-secondary-contrast-light: var(--color-secondary-50);
|
--color-secondary-contrast-light: var(--color-secondary-50);
|
||||||
--color-secondary-contrast-50: var(--color-secondary-contrast-dark);
|
--color-secondary-contrast-50: var(--color-secondary-contrast-dark);
|
||||||
--color-secondary-contrast-100: 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-200: var(--color-secondary-contrast-dark);
|
||||||
--color-secondary-contrast-300: var(--color-secondary-contrast-dark);
|
--color-secondary-contrast-300: var(--color-secondary-contrast-dark);
|
||||||
@@ -244,20 +244,20 @@ html.dark[data-theme='AE_Firefly_Rainbow'] {
|
|||||||
* brand color slots. Creates striking contrast with the warm primary.
|
* brand color slots. Creates striking contrast with the warm primary.
|
||||||
* Used for location chips, deep accents, tertiary elements.
|
* Used for location chips, deep accents, tertiary elements.
|
||||||
* =================================================================== */
|
* =================================================================== */
|
||||||
--color-tertiary-50: oklch(96.5% 0.030 299deg);
|
--color-tertiary-50: oklch(96.5% 0.03 299deg);
|
||||||
--color-tertiary-100: oklch(91.0% 0.058 297deg);
|
--color-tertiary-100: oklch(91% 0.058 297deg);
|
||||||
--color-tertiary-200: oklch(84.5% 0.092 296deg);
|
--color-tertiary-200: oklch(84.5% 0.092 296deg);
|
||||||
--color-tertiary-300: oklch(77.0% 0.122 295deg);
|
--color-tertiary-300: oklch(77% 0.122 295deg);
|
||||||
--color-tertiary-400: oklch(68.5% 0.148 295deg);
|
--color-tertiary-400: oklch(68.5% 0.148 295deg);
|
||||||
--color-tertiary-500: oklch(57.0% 0.158 295deg);
|
--color-tertiary-500: oklch(57% 0.158 295deg);
|
||||||
--color-tertiary-600: oklch(49.5% 0.150 294deg);
|
--color-tertiary-600: oklch(49.5% 0.15 294deg);
|
||||||
--color-tertiary-700: oklch(42.5% 0.138 293deg);
|
--color-tertiary-700: oklch(42.5% 0.138 293deg);
|
||||||
--color-tertiary-800: oklch(35.5% 0.122 292deg);
|
--color-tertiary-800: oklch(35.5% 0.122 292deg);
|
||||||
--color-tertiary-900: oklch(28.5% 0.102 291deg);
|
--color-tertiary-900: oklch(28.5% 0.102 291deg);
|
||||||
--color-tertiary-950: oklch(21.0% 0.080 290deg);
|
--color-tertiary-950: oklch(21% 0.08 290deg);
|
||||||
--color-tertiary-contrast-dark: var(--color-tertiary-950);
|
--color-tertiary-contrast-dark: var(--color-tertiary-950);
|
||||||
--color-tertiary-contrast-light: var(--color-tertiary-50);
|
--color-tertiary-contrast-light: var(--color-tertiary-50);
|
||||||
--color-tertiary-contrast-50: var(--color-tertiary-contrast-dark);
|
--color-tertiary-contrast-50: var(--color-tertiary-contrast-dark);
|
||||||
--color-tertiary-contrast-100: 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-200: var(--color-tertiary-contrast-dark);
|
||||||
--color-tertiary-contrast-300: var(--color-tertiary-contrast-dark);
|
--color-tertiary-contrast-300: var(--color-tertiary-contrast-dark);
|
||||||
@@ -274,8 +274,8 @@ html.dark[data-theme='AE_Firefly_Rainbow'] {
|
|||||||
* Hue: ~152°. Consistent with AE_Firefly for recognizable semantic
|
* Hue: ~152°. Consistent with AE_Firefly for recognizable semantic
|
||||||
* color meaning across OSIT themes.
|
* color meaning across OSIT themes.
|
||||||
* =================================================================== */
|
* =================================================================== */
|
||||||
--color-success-50: oklch(95.77% 0.05 152.69deg);
|
--color-success-50: oklch(95.77% 0.05 152.69deg);
|
||||||
--color-success-100: oklch(91.59% 0.06 152.00deg);
|
--color-success-100: oklch(91.59% 0.06 152deg);
|
||||||
--color-success-200: oklch(87.45% 0.08 152.08deg);
|
--color-success-200: oklch(87.45% 0.08 152.08deg);
|
||||||
--color-success-300: oklch(83.57% 0.09 150.85deg);
|
--color-success-300: oklch(83.57% 0.09 150.85deg);
|
||||||
--color-success-400: oklch(79.47% 0.11 150.71deg);
|
--color-success-400: oklch(79.47% 0.11 150.71deg);
|
||||||
@@ -283,11 +283,11 @@ html.dark[data-theme='AE_Firefly_Rainbow'] {
|
|||||||
--color-success-600: oklch(67.65% 0.11 149.94deg);
|
--color-success-600: oklch(67.65% 0.11 149.94deg);
|
||||||
--color-success-700: oklch(59.71% 0.09 150.42deg);
|
--color-success-700: oklch(59.71% 0.09 150.42deg);
|
||||||
--color-success-800: oklch(51.74% 0.08 150.24deg);
|
--color-success-800: oklch(51.74% 0.08 150.24deg);
|
||||||
--color-success-900: oklch(43.20% 0.06 151.12deg);
|
--color-success-900: oklch(43.2% 0.06 151.12deg);
|
||||||
--color-success-950: oklch(34.20% 0.04 151.44deg);
|
--color-success-950: oklch(34.2% 0.04 151.44deg);
|
||||||
--color-success-contrast-dark: var(--color-success-950);
|
--color-success-contrast-dark: var(--color-success-950);
|
||||||
--color-success-contrast-light: var(--color-success-50);
|
--color-success-contrast-light: var(--color-success-50);
|
||||||
--color-success-contrast-50: var(--color-success-contrast-dark);
|
--color-success-contrast-50: var(--color-success-contrast-dark);
|
||||||
--color-success-contrast-100: 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-200: var(--color-success-contrast-dark);
|
||||||
--color-success-contrast-300: var(--color-success-contrast-dark);
|
--color-success-contrast-300: var(--color-success-contrast-dark);
|
||||||
@@ -303,20 +303,20 @@ html.dark[data-theme='AE_Firefly_Rainbow'] {
|
|||||||
* WARNING — Amber Orange
|
* WARNING — Amber Orange
|
||||||
* Consistent with AE_Firefly for recognizable semantic meaning.
|
* Consistent with AE_Firefly for recognizable semantic meaning.
|
||||||
* =================================================================== */
|
* =================================================================== */
|
||||||
--color-warning-50: oklch(97.5% 0.065 78deg);
|
--color-warning-50: oklch(97.5% 0.065 78deg);
|
||||||
--color-warning-100: oklch(93.5% 0.090 75deg);
|
--color-warning-100: oklch(93.5% 0.09 75deg);
|
||||||
--color-warning-200: oklch(89.5% 0.120 73deg);
|
--color-warning-200: oklch(89.5% 0.12 73deg);
|
||||||
--color-warning-300: oklch(85.5% 0.145 70deg);
|
--color-warning-300: oklch(85.5% 0.145 70deg);
|
||||||
--color-warning-400: oklch(81.5% 0.160 67deg);
|
--color-warning-400: oklch(81.5% 0.16 67deg);
|
||||||
--color-warning-500: oklch(77.0% 0.165 65deg);
|
--color-warning-500: oklch(77% 0.165 65deg);
|
||||||
--color-warning-600: oklch(69.5% 0.155 64deg);
|
--color-warning-600: oklch(69.5% 0.155 64deg);
|
||||||
--color-warning-700: oklch(61.5% 0.140 63deg);
|
--color-warning-700: oklch(61.5% 0.14 63deg);
|
||||||
--color-warning-800: oklch(53.5% 0.125 62deg);
|
--color-warning-800: oklch(53.5% 0.125 62deg);
|
||||||
--color-warning-900: oklch(45.0% 0.105 61deg);
|
--color-warning-900: oklch(45% 0.105 61deg);
|
||||||
--color-warning-950: oklch(37.0% 0.088 60deg);
|
--color-warning-950: oklch(37% 0.088 60deg);
|
||||||
--color-warning-contrast-dark: var(--color-warning-950);
|
--color-warning-contrast-dark: var(--color-warning-950);
|
||||||
--color-warning-contrast-light: var(--color-warning-50);
|
--color-warning-contrast-light: var(--color-warning-50);
|
||||||
--color-warning-contrast-50: var(--color-warning-contrast-dark);
|
--color-warning-contrast-50: var(--color-warning-contrast-dark);
|
||||||
--color-warning-contrast-100: 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-200: var(--color-warning-contrast-dark);
|
||||||
--color-warning-contrast-300: var(--color-warning-contrast-dark);
|
--color-warning-contrast-300: var(--color-warning-contrast-dark);
|
||||||
@@ -332,20 +332,20 @@ html.dark[data-theme='AE_Firefly_Rainbow'] {
|
|||||||
* ERROR — Soft Coral/Rose
|
* ERROR — Soft Coral/Rose
|
||||||
* Consistent with AE_Firefly for recognizable semantic meaning.
|
* Consistent with AE_Firefly for recognizable semantic meaning.
|
||||||
* =================================================================== */
|
* =================================================================== */
|
||||||
--color-error-50: oklch(95.0% 0.040 18deg);
|
--color-error-50: oklch(95% 0.04 18deg);
|
||||||
--color-error-100: oklch(88.0% 0.070 20deg);
|
--color-error-100: oklch(88% 0.07 20deg);
|
||||||
--color-error-200: oklch(80.0% 0.105 21deg);
|
--color-error-200: oklch(80% 0.105 21deg);
|
||||||
--color-error-300: oklch(72.0% 0.140 22deg);
|
--color-error-300: oklch(72% 0.14 22deg);
|
||||||
--color-error-400: oklch(64.5% 0.170 23deg);
|
--color-error-400: oklch(64.5% 0.17 23deg);
|
||||||
--color-error-500: oklch(57.5% 0.195 24deg);
|
--color-error-500: oklch(57.5% 0.195 24deg);
|
||||||
--color-error-600: oklch(51.5% 0.182 25deg);
|
--color-error-600: oklch(51.5% 0.182 25deg);
|
||||||
--color-error-700: oklch(45.5% 0.165 26deg);
|
--color-error-700: oklch(45.5% 0.165 26deg);
|
||||||
--color-error-800: oklch(39.5% 0.148 27deg);
|
--color-error-800: oklch(39.5% 0.148 27deg);
|
||||||
--color-error-900: oklch(33.0% 0.128 28deg);
|
--color-error-900: oklch(33% 0.128 28deg);
|
||||||
--color-error-950: oklch(26.5% 0.108 29deg);
|
--color-error-950: oklch(26.5% 0.108 29deg);
|
||||||
--color-error-contrast-dark: var(--color-error-950);
|
--color-error-contrast-dark: var(--color-error-950);
|
||||||
--color-error-contrast-light: var(--color-error-50);
|
--color-error-contrast-light: var(--color-error-50);
|
||||||
--color-error-contrast-50: var(--color-error-contrast-dark);
|
--color-error-contrast-50: var(--color-error-contrast-dark);
|
||||||
--color-error-contrast-100: 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-200: var(--color-error-contrast-dark);
|
||||||
--color-error-contrast-300: var(--color-error-contrast-dark);
|
--color-error-contrast-300: var(--color-error-contrast-dark);
|
||||||
@@ -366,20 +366,20 @@ html.dark[data-theme='AE_Firefly_Rainbow'] {
|
|||||||
* 50 → body-bg light: warm near-white, like morning paper
|
* 50 → body-bg light: warm near-white, like morning paper
|
||||||
* 950 → body-bg dark: deep warm charcoal, like a dim theatre
|
* 950 → body-bg dark: deep warm charcoal, like a dim theatre
|
||||||
* =================================================================== */
|
* =================================================================== */
|
||||||
--color-surface-50: oklch(99.2% 0.004 75deg);
|
--color-surface-50: oklch(99.2% 0.004 75deg);
|
||||||
--color-surface-100: oklch(97.0% 0.007 72deg);
|
--color-surface-100: oklch(97% 0.007 72deg);
|
||||||
--color-surface-200: oklch(93.5% 0.010 70deg);
|
--color-surface-200: oklch(93.5% 0.01 70deg);
|
||||||
--color-surface-300: oklch(88.5% 0.013 68deg);
|
--color-surface-300: oklch(88.5% 0.013 68deg);
|
||||||
--color-surface-400: oklch(81.5% 0.016 66deg);
|
--color-surface-400: oklch(81.5% 0.016 66deg);
|
||||||
--color-surface-500: oklch(70.5% 0.018 64deg);
|
--color-surface-500: oklch(70.5% 0.018 64deg);
|
||||||
--color-surface-600: oklch(59.0% 0.018 62deg);
|
--color-surface-600: oklch(59% 0.018 62deg);
|
||||||
--color-surface-700: oklch(47.5% 0.018 58deg);
|
--color-surface-700: oklch(47.5% 0.018 58deg);
|
||||||
--color-surface-800: oklch(35.5% 0.020 55deg);
|
--color-surface-800: oklch(35.5% 0.02 55deg);
|
||||||
--color-surface-900: oklch(24.5% 0.020 52deg);
|
--color-surface-900: oklch(24.5% 0.02 52deg);
|
||||||
--color-surface-950: oklch(15.5% 0.022 48deg);
|
--color-surface-950: oklch(15.5% 0.022 48deg);
|
||||||
--color-surface-contrast-dark: var(--color-surface-950);
|
--color-surface-contrast-dark: var(--color-surface-950);
|
||||||
--color-surface-contrast-light: var(--color-surface-50);
|
--color-surface-contrast-light: var(--color-surface-50);
|
||||||
--color-surface-contrast-50: var(--color-surface-contrast-dark);
|
--color-surface-contrast-50: var(--color-surface-contrast-dark);
|
||||||
--color-surface-contrast-100: 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-200: var(--color-surface-contrast-dark);
|
||||||
--color-surface-contrast-300: var(--color-surface-contrast-dark);
|
--color-surface-contrast-300: var(--color-surface-contrast-dark);
|
||||||
|
|||||||
@@ -60,50 +60,50 @@ html[data-theme='AE_Firefly_SteelBlue'] {
|
|||||||
--radius-base: 0.375rem;
|
--radius-base: 0.375rem;
|
||||||
--radius-container: 0.875rem;
|
--radius-container: 0.875rem;
|
||||||
/* --- Color ramps (light mode) copied from dark block so both modes have full ramps --- */
|
/* --- Color ramps (light mode) copied from dark block so both modes have full ramps --- */
|
||||||
--color-primary-50: oklch(96.5% 0.022 214deg);
|
--color-primary-50: oklch(96.5% 0.022 214deg);
|
||||||
--color-primary-100: oklch(91.0% 0.045 213deg);
|
--color-primary-100: oklch(91% 0.045 213deg);
|
||||||
--color-primary-200: oklch(84.5% 0.072 212deg);
|
--color-primary-200: oklch(84.5% 0.072 212deg);
|
||||||
--color-primary-300: oklch(76.5% 0.097 212deg);
|
--color-primary-300: oklch(76.5% 0.097 212deg);
|
||||||
--color-primary-400: oklch(67.0% 0.115 213deg);
|
--color-primary-400: oklch(67% 0.115 213deg);
|
||||||
--color-primary-500: oklch(56.0% 0.115 214deg);
|
--color-primary-500: oklch(56% 0.115 214deg);
|
||||||
--color-primary-600: oklch(49.0% 0.112 214deg);
|
--color-primary-600: oklch(49% 0.112 214deg);
|
||||||
--color-primary-700: oklch(41.5% 0.105 213deg);
|
--color-primary-700: oklch(41.5% 0.105 213deg);
|
||||||
--color-primary-800: oklch(34.0% 0.095 212deg);
|
--color-primary-800: oklch(34% 0.095 212deg);
|
||||||
--color-primary-900: oklch(26.5% 0.080 211deg);
|
--color-primary-900: oklch(26.5% 0.08 211deg);
|
||||||
--color-primary-950: oklch(18.5% 0.065 210deg);
|
--color-primary-950: oklch(18.5% 0.065 210deg);
|
||||||
--color-primary-contrast-dark: var(--color-primary-950);
|
--color-primary-contrast-dark: var(--color-primary-950);
|
||||||
--color-primary-contrast-light: var(--color-primary-50);
|
--color-primary-contrast-light: var(--color-primary-50);
|
||||||
|
|
||||||
--color-secondary-50: oklch(97.5% 0.055 56deg);
|
--color-secondary-50: oklch(97.5% 0.055 56deg);
|
||||||
--color-secondary-100: oklch(93.5% 0.090 55deg);
|
--color-secondary-100: oklch(93.5% 0.09 55deg);
|
||||||
--color-secondary-200: oklch(89.5% 0.120 54deg);
|
--color-secondary-200: oklch(89.5% 0.12 54deg);
|
||||||
--color-secondary-300: oklch(85.5% 0.148 53deg);
|
--color-secondary-300: oklch(85.5% 0.148 53deg);
|
||||||
--color-secondary-400: oklch(81.5% 0.162 52deg);
|
--color-secondary-400: oklch(81.5% 0.162 52deg);
|
||||||
--color-secondary-500: oklch(76.5% 0.162 51deg);
|
--color-secondary-500: oklch(76.5% 0.162 51deg);
|
||||||
--color-secondary-600: oklch(68.5% 0.152 50deg);
|
--color-secondary-600: oklch(68.5% 0.152 50deg);
|
||||||
--color-secondary-700: oklch(60.5% 0.138 49deg);
|
--color-secondary-700: oklch(60.5% 0.138 49deg);
|
||||||
--color-secondary-800: oklch(52.0% 0.122 48deg);
|
--color-secondary-800: oklch(52% 0.122 48deg);
|
||||||
--color-secondary-900: oklch(43.5% 0.102 47deg);
|
--color-secondary-900: oklch(43.5% 0.102 47deg);
|
||||||
--color-secondary-950: oklch(35.0% 0.084 46deg);
|
--color-secondary-950: oklch(35% 0.084 46deg);
|
||||||
--color-secondary-contrast-dark: var(--color-secondary-950);
|
--color-secondary-contrast-dark: var(--color-secondary-950);
|
||||||
--color-secondary-contrast-light: var(--color-secondary-50);
|
--color-secondary-contrast-light: var(--color-secondary-50);
|
||||||
|
|
||||||
--color-tertiary-50: oklch(95.5% 0.025 232deg);
|
--color-tertiary-50: oklch(95.5% 0.025 232deg);
|
||||||
--color-tertiary-100: oklch(89.5% 0.048 231deg);
|
--color-tertiary-100: oklch(89.5% 0.048 231deg);
|
||||||
--color-tertiary-200: oklch(82.5% 0.072 230deg);
|
--color-tertiary-200: oklch(82.5% 0.072 230deg);
|
||||||
--color-tertiary-300: oklch(74.5% 0.095 229deg);
|
--color-tertiary-300: oklch(74.5% 0.095 229deg);
|
||||||
--color-tertiary-400: oklch(65.5% 0.120 229deg);
|
--color-tertiary-400: oklch(65.5% 0.12 229deg);
|
||||||
--color-tertiary-500: oklch(54.5% 0.135 230deg);
|
--color-tertiary-500: oklch(54.5% 0.135 230deg);
|
||||||
--color-tertiary-600: oklch(47.0% 0.132 230deg);
|
--color-tertiary-600: oklch(47% 0.132 230deg);
|
||||||
--color-tertiary-700: oklch(39.5% 0.122 229deg);
|
--color-tertiary-700: oklch(39.5% 0.122 229deg);
|
||||||
--color-tertiary-800: oklch(32.0% 0.108 228deg);
|
--color-tertiary-800: oklch(32% 0.108 228deg);
|
||||||
--color-tertiary-900: oklch(25.0% 0.090 227deg);
|
--color-tertiary-900: oklch(25% 0.09 227deg);
|
||||||
--color-tertiary-950: oklch(17.5% 0.072 226deg);
|
--color-tertiary-950: oklch(17.5% 0.072 226deg);
|
||||||
--color-tertiary-contrast-dark: var(--color-tertiary-950);
|
--color-tertiary-contrast-dark: var(--color-tertiary-950);
|
||||||
--color-tertiary-contrast-light: var(--color-tertiary-50);
|
--color-tertiary-contrast-light: var(--color-tertiary-50);
|
||||||
|
|
||||||
--color-success-50: oklch(95.77% 0.05 152.69deg);
|
--color-success-50: oklch(95.77% 0.05 152.69deg);
|
||||||
--color-success-100: oklch(91.59% 0.06 152.00deg);
|
--color-success-100: oklch(91.59% 0.06 152deg);
|
||||||
--color-success-200: oklch(87.45% 0.08 152.08deg);
|
--color-success-200: oklch(87.45% 0.08 152.08deg);
|
||||||
--color-success-300: oklch(83.57% 0.09 150.85deg);
|
--color-success-300: oklch(83.57% 0.09 150.85deg);
|
||||||
--color-success-400: oklch(79.47% 0.11 150.71deg);
|
--color-success-400: oklch(79.47% 0.11 150.71deg);
|
||||||
@@ -111,51 +111,51 @@ html[data-theme='AE_Firefly_SteelBlue'] {
|
|||||||
--color-success-600: oklch(67.65% 0.11 149.94deg);
|
--color-success-600: oklch(67.65% 0.11 149.94deg);
|
||||||
--color-success-700: oklch(59.71% 0.09 150.42deg);
|
--color-success-700: oklch(59.71% 0.09 150.42deg);
|
||||||
--color-success-800: oklch(51.74% 0.08 150.24deg);
|
--color-success-800: oklch(51.74% 0.08 150.24deg);
|
||||||
--color-success-900: oklch(43.20% 0.06 151.12deg);
|
--color-success-900: oklch(43.2% 0.06 151.12deg);
|
||||||
--color-success-950: oklch(34.20% 0.04 151.44deg);
|
--color-success-950: oklch(34.2% 0.04 151.44deg);
|
||||||
--color-success-contrast-dark: var(--color-success-950);
|
--color-success-contrast-dark: var(--color-success-950);
|
||||||
--color-success-contrast-light: var(--color-success-50);
|
--color-success-contrast-light: var(--color-success-50);
|
||||||
|
|
||||||
--color-warning-50: oklch(97.5% 0.065 78deg);
|
--color-warning-50: oklch(97.5% 0.065 78deg);
|
||||||
--color-warning-100: oklch(93.5% 0.090 75deg);
|
--color-warning-100: oklch(93.5% 0.09 75deg);
|
||||||
--color-warning-200: oklch(89.5% 0.120 73deg);
|
--color-warning-200: oklch(89.5% 0.12 73deg);
|
||||||
--color-warning-300: oklch(85.5% 0.145 70deg);
|
--color-warning-300: oklch(85.5% 0.145 70deg);
|
||||||
--color-warning-400: oklch(81.5% 0.160 67deg);
|
--color-warning-400: oklch(81.5% 0.16 67deg);
|
||||||
--color-warning-500: oklch(77.0% 0.165 65deg);
|
--color-warning-500: oklch(77% 0.165 65deg);
|
||||||
--color-warning-600: oklch(69.5% 0.155 64deg);
|
--color-warning-600: oklch(69.5% 0.155 64deg);
|
||||||
--color-warning-700: oklch(61.5% 0.140 63deg);
|
--color-warning-700: oklch(61.5% 0.14 63deg);
|
||||||
--color-warning-800: oklch(53.5% 0.125 62deg);
|
--color-warning-800: oklch(53.5% 0.125 62deg);
|
||||||
--color-warning-900: oklch(45.0% 0.105 61deg);
|
--color-warning-900: oklch(45% 0.105 61deg);
|
||||||
--color-warning-950: oklch(37.0% 0.088 60deg);
|
--color-warning-950: oklch(37% 0.088 60deg);
|
||||||
--color-warning-contrast-dark: var(--color-warning-950);
|
--color-warning-contrast-dark: var(--color-warning-950);
|
||||||
--color-warning-contrast-light: var(--color-warning-50);
|
--color-warning-contrast-light: var(--color-warning-50);
|
||||||
|
|
||||||
--color-error-50: oklch(95.0% 0.040 18deg);
|
--color-error-50: oklch(95% 0.04 18deg);
|
||||||
--color-error-100: oklch(88.0% 0.070 20deg);
|
--color-error-100: oklch(88% 0.07 20deg);
|
||||||
--color-error-200: oklch(80.0% 0.105 21deg);
|
--color-error-200: oklch(80% 0.105 21deg);
|
||||||
--color-error-300: oklch(72.0% 0.140 22deg);
|
--color-error-300: oklch(72% 0.14 22deg);
|
||||||
--color-error-400: oklch(64.5% 0.170 23deg);
|
--color-error-400: oklch(64.5% 0.17 23deg);
|
||||||
--color-error-500: oklch(57.5% 0.195 24deg);
|
--color-error-500: oklch(57.5% 0.195 24deg);
|
||||||
--color-error-600: oklch(51.5% 0.182 25deg);
|
--color-error-600: oklch(51.5% 0.182 25deg);
|
||||||
--color-error-700: oklch(45.5% 0.165 26deg);
|
--color-error-700: oklch(45.5% 0.165 26deg);
|
||||||
--color-error-800: oklch(39.5% 0.148 27deg);
|
--color-error-800: oklch(39.5% 0.148 27deg);
|
||||||
--color-error-900: oklch(33.0% 0.128 28deg);
|
--color-error-900: oklch(33% 0.128 28deg);
|
||||||
--color-error-950: oklch(26.5% 0.108 29deg);
|
--color-error-950: oklch(26.5% 0.108 29deg);
|
||||||
--color-error-contrast-dark: var(--color-error-950);
|
--color-error-contrast-dark: var(--color-error-950);
|
||||||
--color-error-contrast-light: var(--color-error-50);
|
--color-error-contrast-light: var(--color-error-50);
|
||||||
|
|
||||||
--color-surface-50: oklch(99.0% 0.004 220deg);
|
--color-surface-50: oklch(99% 0.004 220deg);
|
||||||
--color-surface-100: oklch(96.5% 0.008 218deg);
|
--color-surface-100: oklch(96.5% 0.008 218deg);
|
||||||
--color-surface-200: oklch(92.5% 0.012 217deg);
|
--color-surface-200: oklch(92.5% 0.012 217deg);
|
||||||
--color-surface-300: oklch(87.0% 0.016 216deg);
|
--color-surface-300: oklch(87% 0.016 216deg);
|
||||||
--color-surface-400: oklch(78.5% 0.020 215deg);
|
--color-surface-400: oklch(78.5% 0.02 215deg);
|
||||||
--color-surface-500: oklch(66.5% 0.022 217deg);
|
--color-surface-500: oklch(66.5% 0.022 217deg);
|
||||||
--color-surface-600: oklch(54.5% 0.025 220deg);
|
--color-surface-600: oklch(54.5% 0.025 220deg);
|
||||||
--color-surface-700: oklch(42.5% 0.028 223deg);
|
--color-surface-700: oklch(42.5% 0.028 223deg);
|
||||||
--color-surface-800: oklch(31.0% 0.032 226deg);
|
--color-surface-800: oklch(31% 0.032 226deg);
|
||||||
--color-surface-900: oklch(20.5% 0.035 228deg);
|
--color-surface-900: oklch(20.5% 0.035 228deg);
|
||||||
--color-surface-950: oklch(13.0% 0.040 232deg);
|
--color-surface-950: oklch(13% 0.04 232deg);
|
||||||
--color-surface-contrast-dark: var(--color-surface-950);
|
--color-surface-contrast-dark: var(--color-surface-950);
|
||||||
--color-surface-contrast-light: var(--color-surface-50);
|
--color-surface-contrast-light: var(--color-surface-50);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,20 +175,20 @@ html.dark[data-theme='AE_Firefly_SteelBlue'] {
|
|||||||
* Approx: #4682B4 (CSS SteelBlue) sits at oklch(56%, 0.113, 214°).
|
* Approx: #4682B4 (CSS SteelBlue) sits at oklch(56%, 0.113, 214°).
|
||||||
* At 500 (L≈56%): sufficient contrast with primary-50 text (≥4:1).
|
* At 500 (L≈56%): sufficient contrast with primary-50 text (≥4:1).
|
||||||
* =================================================================== */
|
* =================================================================== */
|
||||||
--color-primary-50: oklch(96.5% 0.022 214deg);
|
--color-primary-50: oklch(96.5% 0.022 214deg);
|
||||||
--color-primary-100: oklch(91.0% 0.045 213deg);
|
--color-primary-100: oklch(91% 0.045 213deg);
|
||||||
--color-primary-200: oklch(84.5% 0.072 212deg);
|
--color-primary-200: oklch(84.5% 0.072 212deg);
|
||||||
--color-primary-300: oklch(76.5% 0.097 212deg);
|
--color-primary-300: oklch(76.5% 0.097 212deg);
|
||||||
--color-primary-400: oklch(67.0% 0.115 213deg);
|
--color-primary-400: oklch(67% 0.115 213deg);
|
||||||
--color-primary-500: oklch(56.0% 0.115 214deg);
|
--color-primary-500: oklch(56% 0.115 214deg);
|
||||||
--color-primary-600: oklch(49.0% 0.112 214deg);
|
--color-primary-600: oklch(49% 0.112 214deg);
|
||||||
--color-primary-700: oklch(41.5% 0.105 213deg);
|
--color-primary-700: oklch(41.5% 0.105 213deg);
|
||||||
--color-primary-800: oklch(34.0% 0.095 212deg);
|
--color-primary-800: oklch(34% 0.095 212deg);
|
||||||
--color-primary-900: oklch(26.5% 0.080 211deg);
|
--color-primary-900: oklch(26.5% 0.08 211deg);
|
||||||
--color-primary-950: oklch(18.5% 0.065 210deg);
|
--color-primary-950: oklch(18.5% 0.065 210deg);
|
||||||
--color-primary-contrast-dark: var(--color-primary-950);
|
--color-primary-contrast-dark: var(--color-primary-950);
|
||||||
--color-primary-contrast-light: var(--color-primary-50);
|
--color-primary-contrast-light: var(--color-primary-50);
|
||||||
--color-primary-contrast-50: var(--color-primary-contrast-dark);
|
--color-primary-contrast-50: var(--color-primary-contrast-dark);
|
||||||
--color-primary-contrast-100: 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-200: var(--color-primary-contrast-dark);
|
||||||
--color-primary-contrast-300: var(--color-primary-contrast-dark);
|
--color-primary-contrast-300: var(--color-primary-contrast-dark);
|
||||||
@@ -206,20 +206,20 @@ html.dark[data-theme='AE_Firefly_SteelBlue'] {
|
|||||||
* of steel blue. The classic "metal on metal" contrast pairing —
|
* of steel blue. The classic "metal on metal" contrast pairing —
|
||||||
* used for secondary actions, badges, and call-to-action highlights.
|
* used for secondary actions, badges, and call-to-action highlights.
|
||||||
* =================================================================== */
|
* =================================================================== */
|
||||||
--color-secondary-50: oklch(97.5% 0.055 56deg);
|
--color-secondary-50: oklch(97.5% 0.055 56deg);
|
||||||
--color-secondary-100: oklch(93.5% 0.090 55deg);
|
--color-secondary-100: oklch(93.5% 0.09 55deg);
|
||||||
--color-secondary-200: oklch(89.5% 0.120 54deg);
|
--color-secondary-200: oklch(89.5% 0.12 54deg);
|
||||||
--color-secondary-300: oklch(85.5% 0.148 53deg);
|
--color-secondary-300: oklch(85.5% 0.148 53deg);
|
||||||
--color-secondary-400: oklch(81.5% 0.162 52deg);
|
--color-secondary-400: oklch(81.5% 0.162 52deg);
|
||||||
--color-secondary-500: oklch(76.5% 0.162 51deg);
|
--color-secondary-500: oklch(76.5% 0.162 51deg);
|
||||||
--color-secondary-600: oklch(68.5% 0.152 50deg);
|
--color-secondary-600: oklch(68.5% 0.152 50deg);
|
||||||
--color-secondary-700: oklch(60.5% 0.138 49deg);
|
--color-secondary-700: oklch(60.5% 0.138 49deg);
|
||||||
--color-secondary-800: oklch(52.0% 0.122 48deg);
|
--color-secondary-800: oklch(52% 0.122 48deg);
|
||||||
--color-secondary-900: oklch(43.5% 0.102 47deg);
|
--color-secondary-900: oklch(43.5% 0.102 47deg);
|
||||||
--color-secondary-950: oklch(35.0% 0.084 46deg);
|
--color-secondary-950: oklch(35% 0.084 46deg);
|
||||||
--color-secondary-contrast-dark: var(--color-secondary-950);
|
--color-secondary-contrast-dark: var(--color-secondary-950);
|
||||||
--color-secondary-contrast-light: var(--color-secondary-50);
|
--color-secondary-contrast-light: var(--color-secondary-50);
|
||||||
--color-secondary-contrast-50: var(--color-secondary-contrast-dark);
|
--color-secondary-contrast-50: var(--color-secondary-contrast-dark);
|
||||||
--color-secondary-contrast-100: 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-200: var(--color-secondary-contrast-dark);
|
||||||
--color-secondary-contrast-300: var(--color-secondary-contrast-dark);
|
--color-secondary-contrast-300: var(--color-secondary-contrast-dark);
|
||||||
@@ -237,20 +237,20 @@ html.dark[data-theme='AE_Firefly_SteelBlue'] {
|
|||||||
* like the heavy cobalt-blue depths under polished chrome.
|
* like the heavy cobalt-blue depths under polished chrome.
|
||||||
* Used for accents, location chips, and depth elements.
|
* Used for accents, location chips, and depth elements.
|
||||||
* =================================================================== */
|
* =================================================================== */
|
||||||
--color-tertiary-50: oklch(95.5% 0.025 232deg);
|
--color-tertiary-50: oklch(95.5% 0.025 232deg);
|
||||||
--color-tertiary-100: oklch(89.5% 0.048 231deg);
|
--color-tertiary-100: oklch(89.5% 0.048 231deg);
|
||||||
--color-tertiary-200: oklch(82.5% 0.072 230deg);
|
--color-tertiary-200: oklch(82.5% 0.072 230deg);
|
||||||
--color-tertiary-300: oklch(74.5% 0.095 229deg);
|
--color-tertiary-300: oklch(74.5% 0.095 229deg);
|
||||||
--color-tertiary-400: oklch(65.5% 0.120 229deg);
|
--color-tertiary-400: oklch(65.5% 0.12 229deg);
|
||||||
--color-tertiary-500: oklch(54.5% 0.135 230deg);
|
--color-tertiary-500: oklch(54.5% 0.135 230deg);
|
||||||
--color-tertiary-600: oklch(47.0% 0.132 230deg);
|
--color-tertiary-600: oklch(47% 0.132 230deg);
|
||||||
--color-tertiary-700: oklch(39.5% 0.122 229deg);
|
--color-tertiary-700: oklch(39.5% 0.122 229deg);
|
||||||
--color-tertiary-800: oklch(32.0% 0.108 228deg);
|
--color-tertiary-800: oklch(32% 0.108 228deg);
|
||||||
--color-tertiary-900: oklch(25.0% 0.090 227deg);
|
--color-tertiary-900: oklch(25% 0.09 227deg);
|
||||||
--color-tertiary-950: oklch(17.5% 0.072 226deg);
|
--color-tertiary-950: oklch(17.5% 0.072 226deg);
|
||||||
--color-tertiary-contrast-dark: var(--color-tertiary-950);
|
--color-tertiary-contrast-dark: var(--color-tertiary-950);
|
||||||
--color-tertiary-contrast-light: var(--color-tertiary-50);
|
--color-tertiary-contrast-light: var(--color-tertiary-50);
|
||||||
--color-tertiary-contrast-50: var(--color-tertiary-contrast-dark);
|
--color-tertiary-contrast-50: var(--color-tertiary-contrast-dark);
|
||||||
--color-tertiary-contrast-100: 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-200: var(--color-tertiary-contrast-dark);
|
||||||
--color-tertiary-contrast-300: var(--color-tertiary-contrast-dark);
|
--color-tertiary-contrast-300: var(--color-tertiary-contrast-dark);
|
||||||
@@ -267,8 +267,8 @@ html.dark[data-theme='AE_Firefly_SteelBlue'] {
|
|||||||
* Hue: ~152°. Consistent with AE_Firefly for recognizable semantic
|
* Hue: ~152°. Consistent with AE_Firefly for recognizable semantic
|
||||||
* color meaning across OSIT themes.
|
* color meaning across OSIT themes.
|
||||||
* =================================================================== */
|
* =================================================================== */
|
||||||
--color-success-50: oklch(95.77% 0.05 152.69deg);
|
--color-success-50: oklch(95.77% 0.05 152.69deg);
|
||||||
--color-success-100: oklch(91.59% 0.06 152.00deg);
|
--color-success-100: oklch(91.59% 0.06 152deg);
|
||||||
--color-success-200: oklch(87.45% 0.08 152.08deg);
|
--color-success-200: oklch(87.45% 0.08 152.08deg);
|
||||||
--color-success-300: oklch(83.57% 0.09 150.85deg);
|
--color-success-300: oklch(83.57% 0.09 150.85deg);
|
||||||
--color-success-400: oklch(79.47% 0.11 150.71deg);
|
--color-success-400: oklch(79.47% 0.11 150.71deg);
|
||||||
@@ -276,11 +276,11 @@ html.dark[data-theme='AE_Firefly_SteelBlue'] {
|
|||||||
--color-success-600: oklch(67.65% 0.11 149.94deg);
|
--color-success-600: oklch(67.65% 0.11 149.94deg);
|
||||||
--color-success-700: oklch(59.71% 0.09 150.42deg);
|
--color-success-700: oklch(59.71% 0.09 150.42deg);
|
||||||
--color-success-800: oklch(51.74% 0.08 150.24deg);
|
--color-success-800: oklch(51.74% 0.08 150.24deg);
|
||||||
--color-success-900: oklch(43.20% 0.06 151.12deg);
|
--color-success-900: oklch(43.2% 0.06 151.12deg);
|
||||||
--color-success-950: oklch(34.20% 0.04 151.44deg);
|
--color-success-950: oklch(34.2% 0.04 151.44deg);
|
||||||
--color-success-contrast-dark: var(--color-success-950);
|
--color-success-contrast-dark: var(--color-success-950);
|
||||||
--color-success-contrast-light: var(--color-success-50);
|
--color-success-contrast-light: var(--color-success-50);
|
||||||
--color-success-contrast-50: var(--color-success-contrast-dark);
|
--color-success-contrast-50: var(--color-success-contrast-dark);
|
||||||
--color-success-contrast-100: 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-200: var(--color-success-contrast-dark);
|
||||||
--color-success-contrast-300: var(--color-success-contrast-dark);
|
--color-success-contrast-300: var(--color-success-contrast-dark);
|
||||||
@@ -296,20 +296,20 @@ html.dark[data-theme='AE_Firefly_SteelBlue'] {
|
|||||||
* WARNING — Amber Orange
|
* WARNING — Amber Orange
|
||||||
* Consistent with AE_Firefly for recognizable semantic meaning.
|
* Consistent with AE_Firefly for recognizable semantic meaning.
|
||||||
* =================================================================== */
|
* =================================================================== */
|
||||||
--color-warning-50: oklch(97.5% 0.065 78deg);
|
--color-warning-50: oklch(97.5% 0.065 78deg);
|
||||||
--color-warning-100: oklch(93.5% 0.090 75deg);
|
--color-warning-100: oklch(93.5% 0.09 75deg);
|
||||||
--color-warning-200: oklch(89.5% 0.120 73deg);
|
--color-warning-200: oklch(89.5% 0.12 73deg);
|
||||||
--color-warning-300: oklch(85.5% 0.145 70deg);
|
--color-warning-300: oklch(85.5% 0.145 70deg);
|
||||||
--color-warning-400: oklch(81.5% 0.160 67deg);
|
--color-warning-400: oklch(81.5% 0.16 67deg);
|
||||||
--color-warning-500: oklch(77.0% 0.165 65deg);
|
--color-warning-500: oklch(77% 0.165 65deg);
|
||||||
--color-warning-600: oklch(69.5% 0.155 64deg);
|
--color-warning-600: oklch(69.5% 0.155 64deg);
|
||||||
--color-warning-700: oklch(61.5% 0.140 63deg);
|
--color-warning-700: oklch(61.5% 0.14 63deg);
|
||||||
--color-warning-800: oklch(53.5% 0.125 62deg);
|
--color-warning-800: oklch(53.5% 0.125 62deg);
|
||||||
--color-warning-900: oklch(45.0% 0.105 61deg);
|
--color-warning-900: oklch(45% 0.105 61deg);
|
||||||
--color-warning-950: oklch(37.0% 0.088 60deg);
|
--color-warning-950: oklch(37% 0.088 60deg);
|
||||||
--color-warning-contrast-dark: var(--color-warning-950);
|
--color-warning-contrast-dark: var(--color-warning-950);
|
||||||
--color-warning-contrast-light: var(--color-warning-50);
|
--color-warning-contrast-light: var(--color-warning-50);
|
||||||
--color-warning-contrast-50: var(--color-warning-contrast-dark);
|
--color-warning-contrast-50: var(--color-warning-contrast-dark);
|
||||||
--color-warning-contrast-100: 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-200: var(--color-warning-contrast-dark);
|
||||||
--color-warning-contrast-300: var(--color-warning-contrast-dark);
|
--color-warning-contrast-300: var(--color-warning-contrast-dark);
|
||||||
@@ -325,20 +325,20 @@ html.dark[data-theme='AE_Firefly_SteelBlue'] {
|
|||||||
* ERROR — Soft Coral/Rose
|
* ERROR — Soft Coral/Rose
|
||||||
* Consistent with AE_Firefly for recognizable semantic meaning.
|
* Consistent with AE_Firefly for recognizable semantic meaning.
|
||||||
* =================================================================== */
|
* =================================================================== */
|
||||||
--color-error-50: oklch(95.0% 0.040 18deg);
|
--color-error-50: oklch(95% 0.04 18deg);
|
||||||
--color-error-100: oklch(88.0% 0.070 20deg);
|
--color-error-100: oklch(88% 0.07 20deg);
|
||||||
--color-error-200: oklch(80.0% 0.105 21deg);
|
--color-error-200: oklch(80% 0.105 21deg);
|
||||||
--color-error-300: oklch(72.0% 0.140 22deg);
|
--color-error-300: oklch(72% 0.14 22deg);
|
||||||
--color-error-400: oklch(64.5% 0.170 23deg);
|
--color-error-400: oklch(64.5% 0.17 23deg);
|
||||||
--color-error-500: oklch(57.5% 0.195 24deg);
|
--color-error-500: oklch(57.5% 0.195 24deg);
|
||||||
--color-error-600: oklch(51.5% 0.182 25deg);
|
--color-error-600: oklch(51.5% 0.182 25deg);
|
||||||
--color-error-700: oklch(45.5% 0.165 26deg);
|
--color-error-700: oklch(45.5% 0.165 26deg);
|
||||||
--color-error-800: oklch(39.5% 0.148 27deg);
|
--color-error-800: oklch(39.5% 0.148 27deg);
|
||||||
--color-error-900: oklch(33.0% 0.128 28deg);
|
--color-error-900: oklch(33% 0.128 28deg);
|
||||||
--color-error-950: oklch(26.5% 0.108 29deg);
|
--color-error-950: oklch(26.5% 0.108 29deg);
|
||||||
--color-error-contrast-dark: var(--color-error-950);
|
--color-error-contrast-dark: var(--color-error-950);
|
||||||
--color-error-contrast-light: var(--color-error-50);
|
--color-error-contrast-light: var(--color-error-50);
|
||||||
--color-error-contrast-50: var(--color-error-contrast-dark);
|
--color-error-contrast-50: var(--color-error-contrast-dark);
|
||||||
--color-error-contrast-100: 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-200: var(--color-error-contrast-dark);
|
||||||
--color-error-contrast-300: var(--color-error-contrast-dark);
|
--color-error-contrast-300: var(--color-error-contrast-dark);
|
||||||
@@ -359,20 +359,20 @@ html.dark[data-theme='AE_Firefly_SteelBlue'] {
|
|||||||
* 50 → body-bg light: brilliant near-white with a chrome whisper
|
* 50 → body-bg light: brilliant near-white with a chrome whisper
|
||||||
* 950 → body-bg dark: deep gunmetal with subtle cool-blue depth
|
* 950 → body-bg dark: deep gunmetal with subtle cool-blue depth
|
||||||
* =================================================================== */
|
* =================================================================== */
|
||||||
--color-surface-50: oklch(99.0% 0.004 220deg);
|
--color-surface-50: oklch(99% 0.004 220deg);
|
||||||
--color-surface-100: oklch(96.5% 0.008 218deg);
|
--color-surface-100: oklch(96.5% 0.008 218deg);
|
||||||
--color-surface-200: oklch(92.5% 0.012 217deg);
|
--color-surface-200: oklch(92.5% 0.012 217deg);
|
||||||
--color-surface-300: oklch(87.0% 0.016 216deg);
|
--color-surface-300: oklch(87% 0.016 216deg);
|
||||||
--color-surface-400: oklch(78.5% 0.020 215deg);
|
--color-surface-400: oklch(78.5% 0.02 215deg);
|
||||||
--color-surface-500: oklch(66.5% 0.022 217deg);
|
--color-surface-500: oklch(66.5% 0.022 217deg);
|
||||||
--color-surface-600: oklch(54.5% 0.025 220deg);
|
--color-surface-600: oklch(54.5% 0.025 220deg);
|
||||||
--color-surface-700: oklch(42.5% 0.028 223deg);
|
--color-surface-700: oklch(42.5% 0.028 223deg);
|
||||||
--color-surface-800: oklch(31.0% 0.032 226deg);
|
--color-surface-800: oklch(31% 0.032 226deg);
|
||||||
--color-surface-900: oklch(20.5% 0.035 228deg);
|
--color-surface-900: oklch(20.5% 0.035 228deg);
|
||||||
--color-surface-950: oklch(13.0% 0.040 232deg);
|
--color-surface-950: oklch(13% 0.04 232deg);
|
||||||
--color-surface-contrast-dark: var(--color-surface-950);
|
--color-surface-contrast-dark: var(--color-surface-950);
|
||||||
--color-surface-contrast-light: var(--color-surface-50);
|
--color-surface-contrast-light: var(--color-surface-50);
|
||||||
--color-surface-contrast-50: var(--color-surface-contrast-dark);
|
--color-surface-contrast-50: var(--color-surface-contrast-dark);
|
||||||
--color-surface-contrast-100: 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-200: var(--color-surface-contrast-dark);
|
||||||
--color-surface-contrast-300: var(--color-surface-contrast-dark);
|
--color-surface-contrast-300: var(--color-surface-contrast-dark);
|
||||||
|
|||||||
@@ -63,50 +63,50 @@ html[data-theme='AE_Firefly'] {
|
|||||||
|
|
||||||
/* --- Color ramps (light mode) copied from dark block so both modes have full ramps --- */
|
/* --- Color ramps (light mode) copied from dark block so both modes have full ramps --- */
|
||||||
html[data-theme='AE_Firefly'] {
|
html[data-theme='AE_Firefly'] {
|
||||||
--color-primary-50: oklch(96.5% 0.025 192deg);
|
--color-primary-50: oklch(96.5% 0.025 192deg);
|
||||||
--color-primary-100: oklch(91.0% 0.050 190deg);
|
--color-primary-100: oklch(91% 0.05 190deg);
|
||||||
--color-primary-200: oklch(84.5% 0.078 188deg);
|
--color-primary-200: oklch(84.5% 0.078 188deg);
|
||||||
--color-primary-300: oklch(76.5% 0.105 186deg);
|
--color-primary-300: oklch(76.5% 0.105 186deg);
|
||||||
--color-primary-400: oklch(67.5% 0.125 185deg);
|
--color-primary-400: oklch(67.5% 0.125 185deg);
|
||||||
--color-primary-500: oklch(50.5% 0.130 184deg);
|
--color-primary-500: oklch(50.5% 0.13 184deg);
|
||||||
--color-primary-600: oklch(44.0% 0.125 183deg);
|
--color-primary-600: oklch(44% 0.125 183deg);
|
||||||
--color-primary-700: oklch(37.5% 0.115 182deg);
|
--color-primary-700: oklch(37.5% 0.115 182deg);
|
||||||
--color-primary-800: oklch(30.5% 0.105 181deg);
|
--color-primary-800: oklch(30.5% 0.105 181deg);
|
||||||
--color-primary-900: oklch(23.5% 0.090 180deg);
|
--color-primary-900: oklch(23.5% 0.09 180deg);
|
||||||
--color-primary-950: oklch(16.0% 0.075 179deg);
|
--color-primary-950: oklch(16% 0.075 179deg);
|
||||||
--color-primary-contrast-dark: var(--color-primary-950);
|
--color-primary-contrast-dark: var(--color-primary-950);
|
||||||
--color-primary-contrast-light: var(--color-primary-50);
|
--color-primary-contrast-light: var(--color-primary-50);
|
||||||
|
|
||||||
--color-secondary-50: oklch(97.5% 0.060 102deg);
|
--color-secondary-50: oklch(97.5% 0.06 102deg);
|
||||||
--color-secondary-100: oklch(93.5% 0.095 100deg);
|
--color-secondary-100: oklch(93.5% 0.095 100deg);
|
||||||
--color-secondary-200: oklch(89.5% 0.128 98deg);
|
--color-secondary-200: oklch(89.5% 0.128 98deg);
|
||||||
--color-secondary-300: oklch(85.5% 0.155 95deg);
|
--color-secondary-300: oklch(85.5% 0.155 95deg);
|
||||||
--color-secondary-400: oklch(81.0% 0.170 93deg);
|
--color-secondary-400: oklch(81% 0.17 93deg);
|
||||||
--color-secondary-500: oklch(76.0% 0.170 90deg);
|
--color-secondary-500: oklch(76% 0.17 90deg);
|
||||||
--color-secondary-600: oklch(68.5% 0.160 87deg);
|
--color-secondary-600: oklch(68.5% 0.16 87deg);
|
||||||
--color-secondary-700: oklch(60.5% 0.145 85deg);
|
--color-secondary-700: oklch(60.5% 0.145 85deg);
|
||||||
--color-secondary-800: oklch(52.0% 0.130 83deg);
|
--color-secondary-800: oklch(52% 0.13 83deg);
|
||||||
--color-secondary-900: oklch(43.5% 0.110 81deg);
|
--color-secondary-900: oklch(43.5% 0.11 81deg);
|
||||||
--color-secondary-950: oklch(35.0% 0.090 79deg);
|
--color-secondary-950: oklch(35% 0.09 79deg);
|
||||||
--color-secondary-contrast-dark: var(--color-secondary-950);
|
--color-secondary-contrast-dark: var(--color-secondary-950);
|
||||||
--color-secondary-contrast-light: var(--color-secondary-50);
|
--color-secondary-contrast-light: var(--color-secondary-50);
|
||||||
|
|
||||||
--color-tertiary-50: oklch(95.5% 0.042 283deg);
|
--color-tertiary-50: oklch(95.5% 0.042 283deg);
|
||||||
--color-tertiary-100: oklch(89.0% 0.068 281deg);
|
--color-tertiary-100: oklch(89% 0.068 281deg);
|
||||||
--color-tertiary-200: oklch(81.5% 0.092 279deg);
|
--color-tertiary-200: oklch(81.5% 0.092 279deg);
|
||||||
--color-tertiary-300: oklch(73.5% 0.112 278deg);
|
--color-tertiary-300: oklch(73.5% 0.112 278deg);
|
||||||
--color-tertiary-400: oklch(65.0% 0.132 277deg);
|
--color-tertiary-400: oklch(65% 0.132 277deg);
|
||||||
--color-tertiary-500: oklch(55.5% 0.142 276deg);
|
--color-tertiary-500: oklch(55.5% 0.142 276deg);
|
||||||
--color-tertiary-600: oklch(48.5% 0.138 275deg);
|
--color-tertiary-600: oklch(48.5% 0.138 275deg);
|
||||||
--color-tertiary-700: oklch(41.5% 0.128 274deg);
|
--color-tertiary-700: oklch(41.5% 0.128 274deg);
|
||||||
--color-tertiary-800: oklch(34.5% 0.112 273deg);
|
--color-tertiary-800: oklch(34.5% 0.112 273deg);
|
||||||
--color-tertiary-900: oklch(27.5% 0.098 272deg);
|
--color-tertiary-900: oklch(27.5% 0.098 272deg);
|
||||||
--color-tertiary-950: oklch(20.0% 0.082 271deg);
|
--color-tertiary-950: oklch(20% 0.082 271deg);
|
||||||
--color-tertiary-contrast-dark: var(--color-tertiary-950);
|
--color-tertiary-contrast-dark: var(--color-tertiary-950);
|
||||||
--color-tertiary-contrast-light: var(--color-tertiary-50);
|
--color-tertiary-contrast-light: var(--color-tertiary-50);
|
||||||
|
|
||||||
--color-success-50: oklch(95.77% 0.05 152.69deg);
|
--color-success-50: oklch(95.77% 0.05 152.69deg);
|
||||||
--color-success-100: oklch(91.59% 0.06 152.00deg);
|
--color-success-100: oklch(91.59% 0.06 152deg);
|
||||||
--color-success-200: oklch(87.45% 0.08 152.08deg);
|
--color-success-200: oklch(87.45% 0.08 152.08deg);
|
||||||
--color-success-300: oklch(83.57% 0.09 150.85deg);
|
--color-success-300: oklch(83.57% 0.09 150.85deg);
|
||||||
--color-success-400: oklch(79.47% 0.11 150.71deg);
|
--color-success-400: oklch(79.47% 0.11 150.71deg);
|
||||||
@@ -114,51 +114,51 @@ html[data-theme='AE_Firefly'] {
|
|||||||
--color-success-600: oklch(67.65% 0.11 149.94deg);
|
--color-success-600: oklch(67.65% 0.11 149.94deg);
|
||||||
--color-success-700: oklch(59.71% 0.09 150.42deg);
|
--color-success-700: oklch(59.71% 0.09 150.42deg);
|
||||||
--color-success-800: oklch(51.74% 0.08 150.24deg);
|
--color-success-800: oklch(51.74% 0.08 150.24deg);
|
||||||
--color-success-900: oklch(43.20% 0.06 151.12deg);
|
--color-success-900: oklch(43.2% 0.06 151.12deg);
|
||||||
--color-success-950: oklch(34.20% 0.04 151.44deg);
|
--color-success-950: oklch(34.2% 0.04 151.44deg);
|
||||||
--color-success-contrast-dark: var(--color-success-950);
|
--color-success-contrast-dark: var(--color-success-950);
|
||||||
--color-success-contrast-light: var(--color-success-50);
|
--color-success-contrast-light: var(--color-success-50);
|
||||||
|
|
||||||
--color-warning-50: oklch(97.5% 0.065 78deg);
|
--color-warning-50: oklch(97.5% 0.065 78deg);
|
||||||
--color-warning-100: oklch(93.5% 0.090 75deg);
|
--color-warning-100: oklch(93.5% 0.09 75deg);
|
||||||
--color-warning-200: oklch(89.5% 0.120 73deg);
|
--color-warning-200: oklch(89.5% 0.12 73deg);
|
||||||
--color-warning-300: oklch(85.5% 0.145 70deg);
|
--color-warning-300: oklch(85.5% 0.145 70deg);
|
||||||
--color-warning-400: oklch(81.5% 0.160 67deg);
|
--color-warning-400: oklch(81.5% 0.16 67deg);
|
||||||
--color-warning-500: oklch(77.0% 0.165 65deg);
|
--color-warning-500: oklch(77% 0.165 65deg);
|
||||||
--color-warning-600: oklch(69.5% 0.155 64deg);
|
--color-warning-600: oklch(69.5% 0.155 64deg);
|
||||||
--color-warning-700: oklch(61.5% 0.140 63deg);
|
--color-warning-700: oklch(61.5% 0.14 63deg);
|
||||||
--color-warning-800: oklch(53.5% 0.125 62deg);
|
--color-warning-800: oklch(53.5% 0.125 62deg);
|
||||||
--color-warning-900: oklch(45.0% 0.105 61deg);
|
--color-warning-900: oklch(45% 0.105 61deg);
|
||||||
--color-warning-950: oklch(37.0% 0.088 60deg);
|
--color-warning-950: oklch(37% 0.088 60deg);
|
||||||
--color-warning-contrast-dark: var(--color-warning-950);
|
--color-warning-contrast-dark: var(--color-warning-950);
|
||||||
--color-warning-contrast-light: var(--color-warning-50);
|
--color-warning-contrast-light: var(--color-warning-50);
|
||||||
|
|
||||||
--color-error-50: oklch(95.0% 0.040 18deg);
|
--color-error-50: oklch(95% 0.04 18deg);
|
||||||
--color-error-100: oklch(88.0% 0.070 20deg);
|
--color-error-100: oklch(88% 0.07 20deg);
|
||||||
--color-error-200: oklch(80.0% 0.105 21deg);
|
--color-error-200: oklch(80% 0.105 21deg);
|
||||||
--color-error-300: oklch(72.0% 0.140 22deg);
|
--color-error-300: oklch(72% 0.14 22deg);
|
||||||
--color-error-400: oklch(64.5% 0.170 23deg);
|
--color-error-400: oklch(64.5% 0.17 23deg);
|
||||||
--color-error-500: oklch(57.5% 0.195 24deg);
|
--color-error-500: oklch(57.5% 0.195 24deg);
|
||||||
--color-error-600: oklch(51.5% 0.182 25deg);
|
--color-error-600: oklch(51.5% 0.182 25deg);
|
||||||
--color-error-700: oklch(45.5% 0.165 26deg);
|
--color-error-700: oklch(45.5% 0.165 26deg);
|
||||||
--color-error-800: oklch(39.5% 0.148 27deg);
|
--color-error-800: oklch(39.5% 0.148 27deg);
|
||||||
--color-error-900: oklch(33.0% 0.128 28deg);
|
--color-error-900: oklch(33% 0.128 28deg);
|
||||||
--color-error-950: oklch(26.5% 0.108 29deg);
|
--color-error-950: oklch(26.5% 0.108 29deg);
|
||||||
--color-error-contrast-dark: var(--color-error-950);
|
--color-error-contrast-dark: var(--color-error-950);
|
||||||
--color-error-contrast-light: var(--color-error-50);
|
--color-error-contrast-light: var(--color-error-50);
|
||||||
|
|
||||||
--color-surface-50: oklch(99.2% 0.003 220deg);
|
--color-surface-50: oklch(99.2% 0.003 220deg);
|
||||||
--color-surface-100: oklch(97.0% 0.006 217deg);
|
--color-surface-100: oklch(97% 0.006 217deg);
|
||||||
--color-surface-200: oklch(93.5% 0.009 215deg);
|
--color-surface-200: oklch(93.5% 0.009 215deg);
|
||||||
--color-surface-300: oklch(88.5% 0.012 213deg);
|
--color-surface-300: oklch(88.5% 0.012 213deg);
|
||||||
--color-surface-400: oklch(81.5% 0.015 212deg);
|
--color-surface-400: oklch(81.5% 0.015 212deg);
|
||||||
--color-surface-500: oklch(70.5% 0.016 215deg);
|
--color-surface-500: oklch(70.5% 0.016 215deg);
|
||||||
--color-surface-600: oklch(59.0% 0.018 218deg);
|
--color-surface-600: oklch(59% 0.018 218deg);
|
||||||
--color-surface-700: oklch(47.5% 0.020 222deg);
|
--color-surface-700: oklch(47.5% 0.02 222deg);
|
||||||
--color-surface-800: oklch(30.5% 0.022 226deg);
|
--color-surface-800: oklch(30.5% 0.022 226deg);
|
||||||
--color-surface-900: oklch(24.5% 0.025 229deg);
|
--color-surface-900: oklch(24.5% 0.025 229deg);
|
||||||
--color-surface-950: oklch(15.5% 0.028 233deg);
|
--color-surface-950: oklch(15.5% 0.028 233deg);
|
||||||
--color-surface-contrast-dark: var(--color-surface-950);
|
--color-surface-contrast-dark: var(--color-surface-950);
|
||||||
--color-surface-contrast-light: var(--color-surface-50);
|
--color-surface-contrast-light: var(--color-surface-50);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,20 +174,20 @@ html.dark[data-theme='AE_Firefly'] {
|
|||||||
* PRIMARY — Luminescent Firefly Teal
|
* PRIMARY — Luminescent Firefly Teal
|
||||||
* ...existing code...
|
* ...existing code...
|
||||||
*/
|
*/
|
||||||
--color-primary-50: oklch(96.5% 0.025 192deg);
|
--color-primary-50: oklch(96.5% 0.025 192deg);
|
||||||
--color-primary-100: oklch(91.0% 0.050 190deg);
|
--color-primary-100: oklch(91% 0.05 190deg);
|
||||||
--color-primary-200: oklch(84.5% 0.078 188deg);
|
--color-primary-200: oklch(84.5% 0.078 188deg);
|
||||||
--color-primary-300: oklch(76.5% 0.105 186deg);
|
--color-primary-300: oklch(76.5% 0.105 186deg);
|
||||||
--color-primary-400: oklch(67.5% 0.125 185deg);
|
--color-primary-400: oklch(67.5% 0.125 185deg);
|
||||||
--color-primary-500: oklch(50.5% 0.130 184deg);
|
--color-primary-500: oklch(50.5% 0.13 184deg);
|
||||||
--color-primary-600: oklch(44.0% 0.125 183deg);
|
--color-primary-600: oklch(44% 0.125 183deg);
|
||||||
--color-primary-700: oklch(37.5% 0.115 182deg);
|
--color-primary-700: oklch(37.5% 0.115 182deg);
|
||||||
--color-primary-800: oklch(30.5% 0.105 181deg);
|
--color-primary-800: oklch(30.5% 0.105 181deg);
|
||||||
--color-primary-900: oklch(23.5% 0.090 180deg);
|
--color-primary-900: oklch(23.5% 0.09 180deg);
|
||||||
--color-primary-950: oklch(16.0% 0.075 179deg);
|
--color-primary-950: oklch(16% 0.075 179deg);
|
||||||
--color-primary-contrast-dark: var(--color-primary-950);
|
--color-primary-contrast-dark: var(--color-primary-950);
|
||||||
--color-primary-contrast-light: var(--color-primary-50);
|
--color-primary-contrast-light: var(--color-primary-50);
|
||||||
--color-primary-contrast-50: var(--color-primary-contrast-dark);
|
--color-primary-contrast-50: var(--color-primary-contrast-dark);
|
||||||
--color-primary-contrast-100: 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-200: var(--color-primary-contrast-dark);
|
||||||
--color-primary-contrast-300: var(--color-primary-contrast-dark);
|
--color-primary-contrast-300: var(--color-primary-contrast-dark);
|
||||||
@@ -200,20 +200,20 @@ html.dark[data-theme='AE_Firefly'] {
|
|||||||
--color-primary-contrast-950: var(--color-primary-contrast-light);
|
--color-primary-contrast-950: var(--color-primary-contrast-light);
|
||||||
|
|
||||||
/* ...existing code for secondary, tertiary, success, warning, error, surface... */
|
/* ...existing code for secondary, tertiary, success, warning, error, surface... */
|
||||||
--color-secondary-50: oklch(97.5% 0.060 102deg);
|
--color-secondary-50: oklch(97.5% 0.06 102deg);
|
||||||
--color-secondary-100: oklch(93.5% 0.095 100deg);
|
--color-secondary-100: oklch(93.5% 0.095 100deg);
|
||||||
--color-secondary-200: oklch(89.5% 0.128 98deg);
|
--color-secondary-200: oklch(89.5% 0.128 98deg);
|
||||||
--color-secondary-300: oklch(85.5% 0.155 95deg);
|
--color-secondary-300: oklch(85.5% 0.155 95deg);
|
||||||
--color-secondary-400: oklch(81.0% 0.170 93deg);
|
--color-secondary-400: oklch(81% 0.17 93deg);
|
||||||
--color-secondary-500: oklch(76.0% 0.170 90deg);
|
--color-secondary-500: oklch(76% 0.17 90deg);
|
||||||
--color-secondary-600: oklch(68.5% 0.160 87deg);
|
--color-secondary-600: oklch(68.5% 0.16 87deg);
|
||||||
--color-secondary-700: oklch(60.5% 0.145 85deg);
|
--color-secondary-700: oklch(60.5% 0.145 85deg);
|
||||||
--color-secondary-800: oklch(52.0% 0.130 83deg);
|
--color-secondary-800: oklch(52% 0.13 83deg);
|
||||||
--color-secondary-900: oklch(43.5% 0.110 81deg);
|
--color-secondary-900: oklch(43.5% 0.11 81deg);
|
||||||
--color-secondary-950: oklch(35.0% 0.090 79deg);
|
--color-secondary-950: oklch(35% 0.09 79deg);
|
||||||
--color-secondary-contrast-dark: var(--color-secondary-950);
|
--color-secondary-contrast-dark: var(--color-secondary-950);
|
||||||
--color-secondary-contrast-light: var(--color-secondary-50);
|
--color-secondary-contrast-light: var(--color-secondary-50);
|
||||||
--color-secondary-contrast-50: var(--color-secondary-contrast-dark);
|
--color-secondary-contrast-50: var(--color-secondary-contrast-dark);
|
||||||
--color-secondary-contrast-100: 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-200: var(--color-secondary-contrast-dark);
|
||||||
--color-secondary-contrast-300: var(--color-secondary-contrast-dark);
|
--color-secondary-contrast-300: var(--color-secondary-contrast-dark);
|
||||||
@@ -225,20 +225,20 @@ html.dark[data-theme='AE_Firefly'] {
|
|||||||
--color-secondary-contrast-900: var(--color-secondary-contrast-light);
|
--color-secondary-contrast-900: var(--color-secondary-contrast-light);
|
||||||
--color-secondary-contrast-950: var(--color-secondary-contrast-light);
|
--color-secondary-contrast-950: var(--color-secondary-contrast-light);
|
||||||
|
|
||||||
--color-tertiary-50: oklch(95.5% 0.042 283deg);
|
--color-tertiary-50: oklch(95.5% 0.042 283deg);
|
||||||
--color-tertiary-100: oklch(89.0% 0.068 281deg);
|
--color-tertiary-100: oklch(89% 0.068 281deg);
|
||||||
--color-tertiary-200: oklch(81.5% 0.092 279deg);
|
--color-tertiary-200: oklch(81.5% 0.092 279deg);
|
||||||
--color-tertiary-300: oklch(73.5% 0.112 278deg);
|
--color-tertiary-300: oklch(73.5% 0.112 278deg);
|
||||||
--color-tertiary-400: oklch(65.0% 0.132 277deg);
|
--color-tertiary-400: oklch(65% 0.132 277deg);
|
||||||
--color-tertiary-500: oklch(55.5% 0.142 276deg);
|
--color-tertiary-500: oklch(55.5% 0.142 276deg);
|
||||||
--color-tertiary-600: oklch(48.5% 0.138 275deg);
|
--color-tertiary-600: oklch(48.5% 0.138 275deg);
|
||||||
--color-tertiary-700: oklch(41.5% 0.128 274deg);
|
--color-tertiary-700: oklch(41.5% 0.128 274deg);
|
||||||
--color-tertiary-800: oklch(34.5% 0.112 273deg);
|
--color-tertiary-800: oklch(34.5% 0.112 273deg);
|
||||||
--color-tertiary-900: oklch(27.5% 0.098 272deg);
|
--color-tertiary-900: oklch(27.5% 0.098 272deg);
|
||||||
--color-tertiary-950: oklch(20.0% 0.082 271deg);
|
--color-tertiary-950: oklch(20% 0.082 271deg);
|
||||||
--color-tertiary-contrast-dark: var(--color-tertiary-950);
|
--color-tertiary-contrast-dark: var(--color-tertiary-950);
|
||||||
--color-tertiary-contrast-light: var(--color-tertiary-50);
|
--color-tertiary-contrast-light: var(--color-tertiary-50);
|
||||||
--color-tertiary-contrast-50: var(--color-tertiary-contrast-dark);
|
--color-tertiary-contrast-50: var(--color-tertiary-contrast-dark);
|
||||||
--color-tertiary-contrast-100: 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-200: var(--color-tertiary-contrast-dark);
|
||||||
--color-tertiary-contrast-300: var(--color-tertiary-contrast-dark);
|
--color-tertiary-contrast-300: var(--color-tertiary-contrast-dark);
|
||||||
@@ -250,8 +250,8 @@ html.dark[data-theme='AE_Firefly'] {
|
|||||||
--color-tertiary-contrast-900: var(--color-tertiary-contrast-light);
|
--color-tertiary-contrast-900: var(--color-tertiary-contrast-light);
|
||||||
--color-tertiary-contrast-950: var(--color-tertiary-contrast-light);
|
--color-tertiary-contrast-950: var(--color-tertiary-contrast-light);
|
||||||
|
|
||||||
--color-success-50: oklch(95.77% 0.05 152.69deg);
|
--color-success-50: oklch(95.77% 0.05 152.69deg);
|
||||||
--color-success-100: oklch(91.59% 0.06 152.00deg);
|
--color-success-100: oklch(91.59% 0.06 152deg);
|
||||||
--color-success-200: oklch(87.45% 0.08 152.08deg);
|
--color-success-200: oklch(87.45% 0.08 152.08deg);
|
||||||
--color-success-300: oklch(83.57% 0.09 150.85deg);
|
--color-success-300: oklch(83.57% 0.09 150.85deg);
|
||||||
--color-success-400: oklch(79.47% 0.11 150.71deg);
|
--color-success-400: oklch(79.47% 0.11 150.71deg);
|
||||||
@@ -259,11 +259,11 @@ html.dark[data-theme='AE_Firefly'] {
|
|||||||
--color-success-600: oklch(67.65% 0.11 149.94deg);
|
--color-success-600: oklch(67.65% 0.11 149.94deg);
|
||||||
--color-success-700: oklch(59.71% 0.09 150.42deg);
|
--color-success-700: oklch(59.71% 0.09 150.42deg);
|
||||||
--color-success-800: oklch(51.74% 0.08 150.24deg);
|
--color-success-800: oklch(51.74% 0.08 150.24deg);
|
||||||
--color-success-900: oklch(43.20% 0.06 151.12deg);
|
--color-success-900: oklch(43.2% 0.06 151.12deg);
|
||||||
--color-success-950: oklch(34.20% 0.04 151.44deg);
|
--color-success-950: oklch(34.2% 0.04 151.44deg);
|
||||||
--color-success-contrast-dark: var(--color-success-950);
|
--color-success-contrast-dark: var(--color-success-950);
|
||||||
--color-success-contrast-light: var(--color-success-50);
|
--color-success-contrast-light: var(--color-success-50);
|
||||||
--color-success-contrast-50: var(--color-success-contrast-dark);
|
--color-success-contrast-50: var(--color-success-contrast-dark);
|
||||||
--color-success-contrast-100: 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-200: var(--color-success-contrast-dark);
|
||||||
--color-success-contrast-300: var(--color-success-contrast-dark);
|
--color-success-contrast-300: var(--color-success-contrast-dark);
|
||||||
@@ -275,20 +275,20 @@ html.dark[data-theme='AE_Firefly'] {
|
|||||||
--color-success-contrast-900: var(--color-success-contrast-light);
|
--color-success-contrast-900: var(--color-success-contrast-light);
|
||||||
--color-success-contrast-950: var(--color-success-contrast-light);
|
--color-success-contrast-950: var(--color-success-contrast-light);
|
||||||
|
|
||||||
--color-warning-50: oklch(97.5% 0.065 78deg);
|
--color-warning-50: oklch(97.5% 0.065 78deg);
|
||||||
--color-warning-100: oklch(93.5% 0.090 75deg);
|
--color-warning-100: oklch(93.5% 0.09 75deg);
|
||||||
--color-warning-200: oklch(89.5% 0.120 73deg);
|
--color-warning-200: oklch(89.5% 0.12 73deg);
|
||||||
--color-warning-300: oklch(85.5% 0.145 70deg);
|
--color-warning-300: oklch(85.5% 0.145 70deg);
|
||||||
--color-warning-400: oklch(81.5% 0.160 67deg);
|
--color-warning-400: oklch(81.5% 0.16 67deg);
|
||||||
--color-warning-500: oklch(77.0% 0.165 65deg);
|
--color-warning-500: oklch(77% 0.165 65deg);
|
||||||
--color-warning-600: oklch(69.5% 0.155 64deg);
|
--color-warning-600: oklch(69.5% 0.155 64deg);
|
||||||
--color-warning-700: oklch(61.5% 0.140 63deg);
|
--color-warning-700: oklch(61.5% 0.14 63deg);
|
||||||
--color-warning-800: oklch(53.5% 0.125 62deg);
|
--color-warning-800: oklch(53.5% 0.125 62deg);
|
||||||
--color-warning-900: oklch(45.0% 0.105 61deg);
|
--color-warning-900: oklch(45% 0.105 61deg);
|
||||||
--color-warning-950: oklch(37.0% 0.088 60deg);
|
--color-warning-950: oklch(37% 0.088 60deg);
|
||||||
--color-warning-contrast-dark: var(--color-warning-950);
|
--color-warning-contrast-dark: var(--color-warning-950);
|
||||||
--color-warning-contrast-light: var(--color-warning-50);
|
--color-warning-contrast-light: var(--color-warning-50);
|
||||||
--color-warning-contrast-50: var(--color-warning-contrast-dark);
|
--color-warning-contrast-50: var(--color-warning-contrast-dark);
|
||||||
--color-warning-contrast-100: 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-200: var(--color-warning-contrast-dark);
|
||||||
--color-warning-contrast-300: var(--color-warning-contrast-dark);
|
--color-warning-contrast-300: var(--color-warning-contrast-dark);
|
||||||
@@ -300,20 +300,20 @@ html.dark[data-theme='AE_Firefly'] {
|
|||||||
--color-warning-contrast-900: var(--color-warning-contrast-light);
|
--color-warning-contrast-900: var(--color-warning-contrast-light);
|
||||||
--color-warning-contrast-950: var(--color-warning-contrast-light);
|
--color-warning-contrast-950: var(--color-warning-contrast-light);
|
||||||
|
|
||||||
--color-error-50: oklch(95.0% 0.040 18deg);
|
--color-error-50: oklch(95% 0.04 18deg);
|
||||||
--color-error-100: oklch(88.0% 0.070 20deg);
|
--color-error-100: oklch(88% 0.07 20deg);
|
||||||
--color-error-200: oklch(80.0% 0.105 21deg);
|
--color-error-200: oklch(80% 0.105 21deg);
|
||||||
--color-error-300: oklch(72.0% 0.140 22deg);
|
--color-error-300: oklch(72% 0.14 22deg);
|
||||||
--color-error-400: oklch(64.5% 0.170 23deg);
|
--color-error-400: oklch(64.5% 0.17 23deg);
|
||||||
--color-error-500: oklch(57.5% 0.195 24deg);
|
--color-error-500: oklch(57.5% 0.195 24deg);
|
||||||
--color-error-600: oklch(51.5% 0.182 25deg);
|
--color-error-600: oklch(51.5% 0.182 25deg);
|
||||||
--color-error-700: oklch(45.5% 0.165 26deg);
|
--color-error-700: oklch(45.5% 0.165 26deg);
|
||||||
--color-error-800: oklch(39.5% 0.148 27deg);
|
--color-error-800: oklch(39.5% 0.148 27deg);
|
||||||
--color-error-900: oklch(33.0% 0.128 28deg);
|
--color-error-900: oklch(33% 0.128 28deg);
|
||||||
--color-error-950: oklch(26.5% 0.108 29deg);
|
--color-error-950: oklch(26.5% 0.108 29deg);
|
||||||
--color-error-contrast-dark: var(--color-error-950);
|
--color-error-contrast-dark: var(--color-error-950);
|
||||||
--color-error-contrast-light: var(--color-error-50);
|
--color-error-contrast-light: var(--color-error-50);
|
||||||
--color-error-contrast-50: var(--color-error-contrast-dark);
|
--color-error-contrast-50: var(--color-error-contrast-dark);
|
||||||
--color-error-contrast-100: 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-200: var(--color-error-contrast-dark);
|
||||||
--color-error-contrast-300: var(--color-error-contrast-dark);
|
--color-error-contrast-300: var(--color-error-contrast-dark);
|
||||||
@@ -325,20 +325,20 @@ html.dark[data-theme='AE_Firefly'] {
|
|||||||
--color-error-contrast-900: var(--color-error-contrast-light);
|
--color-error-contrast-900: var(--color-error-contrast-light);
|
||||||
--color-error-contrast-950: var(--color-error-contrast-light);
|
--color-error-contrast-950: var(--color-error-contrast-light);
|
||||||
|
|
||||||
--color-surface-50: oklch(99.2% 0.003 220deg);
|
--color-surface-50: oklch(99.2% 0.003 220deg);
|
||||||
--color-surface-100: oklch(97.0% 0.006 217deg);
|
--color-surface-100: oklch(97% 0.006 217deg);
|
||||||
--color-surface-200: oklch(93.5% 0.009 215deg);
|
--color-surface-200: oklch(93.5% 0.009 215deg);
|
||||||
--color-surface-300: oklch(88.5% 0.012 213deg);
|
--color-surface-300: oklch(88.5% 0.012 213deg);
|
||||||
--color-surface-400: oklch(81.5% 0.015 212deg);
|
--color-surface-400: oklch(81.5% 0.015 212deg);
|
||||||
--color-surface-500: oklch(70.5% 0.016 215deg);
|
--color-surface-500: oklch(70.5% 0.016 215deg);
|
||||||
--color-surface-600: oklch(59.0% 0.018 218deg);
|
--color-surface-600: oklch(59% 0.018 218deg);
|
||||||
--color-surface-700: oklch(47.5% 0.020 222deg);
|
--color-surface-700: oklch(47.5% 0.02 222deg);
|
||||||
--color-surface-800: oklch(35.5% 0.022 226deg);
|
--color-surface-800: oklch(35.5% 0.022 226deg);
|
||||||
--color-surface-900: oklch(24.5% 0.025 229deg);
|
--color-surface-900: oklch(24.5% 0.025 229deg);
|
||||||
--color-surface-950: oklch(15.5% 0.028 233deg);
|
--color-surface-950: oklch(15.5% 0.028 233deg);
|
||||||
--color-surface-contrast-dark: var(--color-surface-950);
|
--color-surface-contrast-dark: var(--color-surface-950);
|
||||||
--color-surface-contrast-light: var(--color-surface-50);
|
--color-surface-contrast-light: var(--color-surface-50);
|
||||||
--color-surface-contrast-50: var(--color-surface-contrast-dark);
|
--color-surface-contrast-50: var(--color-surface-contrast-dark);
|
||||||
--color-surface-contrast-100: 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-200: var(--color-surface-contrast-dark);
|
||||||
--color-surface-contrast-300: var(--color-surface-contrast-dark);
|
--color-surface-contrast-300: var(--color-surface-contrast-dark);
|
||||||
|
|||||||
89
src/app.css
89
src/app.css
@@ -10,12 +10,15 @@
|
|||||||
/* Sync native browser control rendering (select dropdowns, scrollbars, etc.)
|
/* Sync native browser control rendering (select dropdowns, scrollbars, etc.)
|
||||||
with the app's dark/light mode toggle. Without this, native controls follow
|
with the app's dark/light mode toggle. Without this, native controls follow
|
||||||
the OS theme rather than the app's .dark/.light class on <html>. */
|
the OS theme rather than the app's .dark/.light class on <html>. */
|
||||||
html.dark { color-scheme: dark; }
|
html.dark {
|
||||||
html.light { color-scheme: light; }
|
color-scheme: dark;
|
||||||
|
}
|
||||||
|
html.light {
|
||||||
|
color-scheme: light;
|
||||||
|
}
|
||||||
|
|
||||||
@import '@skeletonlabs/skeleton';
|
@import '@skeletonlabs/skeleton';
|
||||||
|
|
||||||
|
|
||||||
/* Register Preset Themes */
|
/* Register Preset Themes */
|
||||||
/* @import '@skeletonlabs/skeleton/themes/{theme-name}'; */
|
/* @import '@skeletonlabs/skeleton/themes/{theme-name}'; */
|
||||||
@import '@skeletonlabs/skeleton/themes/cerberus';
|
@import '@skeletonlabs/skeleton/themes/cerberus';
|
||||||
@@ -154,13 +157,13 @@ html.light { color-scheme: light; }
|
|||||||
.dark .input:not([type='checkbox']):not([type='radio']):not([type='range']),
|
.dark .input:not([type='checkbox']):not([type='radio']):not([type='range']),
|
||||||
.dark .select,
|
.dark .select,
|
||||||
.dark .textarea {
|
.dark .textarea {
|
||||||
color: rgb(243 244 246); /* gray-100 */
|
color: rgb(243 244 246); /* gray-100 */
|
||||||
background-color: rgb(55 65 81); /* gray-700 */
|
background-color: rgb(55 65 81); /* gray-700 */
|
||||||
border-color: rgb(75 85 99); /* gray-600 */
|
border-color: rgb(75 85 99); /* gray-600 */
|
||||||
}
|
}
|
||||||
.dark .input::placeholder,
|
.dark .input::placeholder,
|
||||||
.dark .textarea::placeholder {
|
.dark .textarea::placeholder {
|
||||||
color: rgb(156 163 175); /* gray-400 — legible at reduced opacity */
|
color: rgb(156 163 175); /* gray-400 — legible at reduced opacity */
|
||||||
}
|
}
|
||||||
/* Option elements in dark selects — forces browser native dark chrome */
|
/* Option elements in dark selects — forces browser native dark chrome */
|
||||||
.dark .select option {
|
.dark .select option {
|
||||||
@@ -198,8 +201,12 @@ body {
|
|||||||
/* Font size accessibility modes — cycled via the font size button in the sys menu.
|
/* Font size accessibility modes — cycled via the font size button in the sys menu.
|
||||||
Applied as a class on <html> by the layout DOM effect.
|
Applied as a class on <html> by the layout DOM effect.
|
||||||
The 'default' mode has no class (browser default, typically 16px). */
|
The 'default' mode has no class (browser default, typically 16px). */
|
||||||
html.font-size-larger { font-size: 112.5%; } /* ~18px base */
|
html.font-size-larger {
|
||||||
html.font-size-smaller { font-size: 87.5%; } /* ~14px base */
|
font-size: 112.5%;
|
||||||
|
} /* ~18px base */
|
||||||
|
html.font-size-smaller {
|
||||||
|
font-size: 87.5%;
|
||||||
|
} /* ~14px base */
|
||||||
|
|
||||||
html.super_access #appShell {
|
html.super_access #appShell {
|
||||||
background-color: hsla(0, 100%, 50%, 0.5);
|
background-color: hsla(0, 100%, 50%, 0.5);
|
||||||
@@ -356,51 +363,51 @@ html.trusted_access #appShell {
|
|||||||
/* @apply preset-tonal-primary border border-primary-500 transition-all; */
|
/* @apply preset-tonal-primary border border-primary-500 transition-all; */
|
||||||
}
|
}
|
||||||
.ae_btn_secondary {
|
.ae_btn_secondary {
|
||||||
@apply preset-tonal-secondary border border-secondary-500 transition-all;
|
@apply preset-tonal-secondary border-secondary-500 border transition-all;
|
||||||
/* hover:preset-filled-secondary-500 */
|
/* hover:preset-filled-secondary-500 */
|
||||||
}
|
}
|
||||||
.ae_btn_tertiary {
|
.ae_btn_tertiary {
|
||||||
@apply preset-tonal-tertiary border border-tertiary-500 transition-all;
|
@apply preset-tonal-tertiary border-tertiary-500 border transition-all;
|
||||||
}
|
}
|
||||||
.ae_btn_success {
|
.ae_btn_success {
|
||||||
@apply preset-tonal-success border border-success-500 transition-all;
|
@apply preset-tonal-success border-success-500 border transition-all;
|
||||||
}
|
}
|
||||||
.ae_btn_warning {
|
.ae_btn_warning {
|
||||||
@apply preset-tonal-warning border border-warning-500 text-warning-950-50 transition-all;
|
@apply preset-tonal-warning border-warning-500 text-warning-950-50 border transition-all;
|
||||||
}
|
}
|
||||||
.ae_btn_error {
|
.ae_btn_error {
|
||||||
@apply preset-tonal-error border border-error-500 transition-all;
|
@apply preset-tonal-error border-error-500 border transition-all;
|
||||||
}
|
}
|
||||||
.ae_btn_surface {
|
.ae_btn_surface {
|
||||||
@apply preset-tonal-surface border border-surface-500 transition-all;
|
@apply preset-tonal-surface border-surface-500 border transition-all;
|
||||||
}
|
}
|
||||||
/* Buttons customized for Aether using Skeleton Tailwind preset classes */
|
/* Buttons customized for Aether using Skeleton Tailwind preset classes */
|
||||||
.ae_btn_info {
|
.ae_btn_info {
|
||||||
@apply border text-cyan-950 dark:text-cyan-50 bg-cyan-50 dark:bg-cyan-950 border-cyan-100 dark:border-cyan-900 hover:bg-cyan-200 hover:dark:bg-cyan-800 transition-all;
|
@apply border border-cyan-100 bg-cyan-50 text-cyan-950 transition-all hover:bg-cyan-200 dark:border-cyan-900 dark:bg-cyan-950 dark:text-cyan-50 hover:dark:bg-cyan-800;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Buttons are for filled and outlined presets */
|
/* Buttons are for filled and outlined presets */
|
||||||
.ae_btn_secondary_filled {
|
.ae_btn_secondary_filled {
|
||||||
@apply preset-filled-secondary-200-800 border border-secondary-500 transition-all;
|
@apply preset-filled-secondary-200-800 border-secondary-500 border transition-all;
|
||||||
/* hover:preset-filled-secondary-500 */
|
/* hover:preset-filled-secondary-500 */
|
||||||
}
|
}
|
||||||
.ae_btn_secondary_outlined {
|
.ae_btn_secondary_outlined {
|
||||||
@apply preset-outlined-secondary-200-800 hover:preset-filled-secondary-400-600 text-secondary-950-50 transition-all;
|
@apply preset-outlined-secondary-200-800 hover:preset-filled-secondary-400-600 text-secondary-950-50 transition-all;
|
||||||
}
|
}
|
||||||
.ae_btn_success_filled {
|
.ae_btn_success_filled {
|
||||||
@apply preset-filled-success-200-800 border border-success-500 transition-all;
|
@apply preset-filled-success-200-800 border-success-500 border transition-all;
|
||||||
}
|
}
|
||||||
.ae_btn_success_outlined {
|
.ae_btn_success_outlined {
|
||||||
@apply preset-outlined-success-200-800 hover:preset-filled-success-400-600 text-success-950-50 transition-all;
|
@apply preset-outlined-success-200-800 hover:preset-filled-success-400-600 text-success-950-50 transition-all;
|
||||||
}
|
}
|
||||||
.ae_btn_warning_filled {
|
.ae_btn_warning_filled {
|
||||||
@apply preset-filled-warning-200-800 border border-warning-500 transition-all;
|
@apply preset-filled-warning-200-800 border-warning-500 border transition-all;
|
||||||
}
|
}
|
||||||
.ae_btn_warning_outlined {
|
.ae_btn_warning_outlined {
|
||||||
@apply preset-outlined-warning-200-800 hover:preset-filled-warning-400-600 text-warning-950-50 transition-all;
|
@apply preset-outlined-warning-200-800 hover:preset-filled-warning-400-600 text-warning-950-50 transition-all;
|
||||||
}
|
}
|
||||||
.ae_btn_surface_filled {
|
.ae_btn_surface_filled {
|
||||||
@apply preset-filled-surface-200-800 border border-surface-500 transition-all;
|
@apply preset-filled-surface-200-800 border-surface-500 border transition-all;
|
||||||
}
|
}
|
||||||
.ae_btn_surface_outlined {
|
.ae_btn_surface_outlined {
|
||||||
@apply preset-outlined-surface-200-800 hover:preset-filled-surface-400-600 text-surface-950-50 transition-all;
|
@apply preset-outlined-surface-200-800 hover:preset-filled-surface-400-600 text-surface-950-50 transition-all;
|
||||||
@@ -409,10 +416,10 @@ html.trusted_access #appShell {
|
|||||||
@apply preset-outlined-error-200-800 hover:preset-filled-error-400-600 text-error-950-50 transition-all;
|
@apply preset-outlined-error-200-800 hover:preset-filled-error-400-600 text-error-950-50 transition-all;
|
||||||
}
|
}
|
||||||
.ae_btn_info_filled {
|
.ae_btn_info_filled {
|
||||||
@apply border text-cyan-950 dark:text-cyan-50 bg-cyan-200 dark:bg-cyan-800 border-cyan-200 dark:border-cyan-800 transition-all;
|
@apply border border-cyan-200 bg-cyan-200 text-cyan-950 transition-all dark:border-cyan-800 dark:bg-cyan-800 dark:text-cyan-50;
|
||||||
}
|
}
|
||||||
.ae_btn_info_outlined {
|
.ae_btn_info_outlined {
|
||||||
@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;
|
@apply border border-cyan-200 bg-cyan-50 text-cyan-950 transition-all dark:border-cyan-800 dark:bg-cyan-950 dark:text-cyan-50;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Containers customized for Aether using Skeleton Tailwind preset classes */
|
/* Containers customized for Aether using Skeleton Tailwind preset classes */
|
||||||
@@ -436,7 +443,7 @@ html.trusted_access #appShell {
|
|||||||
.ae_module_header {
|
.ae_module_header {
|
||||||
/* LCI request 3a5997 */
|
/* LCI request 3a5997 */
|
||||||
/* bg-gray-300 */
|
/* bg-gray-300 */
|
||||||
@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;
|
@apply preset-tonal-surface flex w-full max-w-7xl flex-col flex-wrap items-center justify-between gap-0.25 rounded-md p-1 px-2 md:flex-row;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-theme='AE_c_LCI'] .ae_module_header {
|
[data-theme='AE_c_LCI'] .ae_module_header {
|
||||||
@@ -453,32 +460,18 @@ html.trusted_access #appShell {
|
|||||||
@apply container;
|
@apply container;
|
||||||
}
|
}
|
||||||
.ae_container_module_menu {
|
.ae_container_module_menu {
|
||||||
@apply w-full max-w-7xl flex flex-col items-center justify-center gap-1 p-1
|
@apply flex w-full max-w-7xl flex-col items-center justify-center gap-1 rounded-md border border-gray-200 p-1 transition-all duration-700 hover:bg-gray-100 hover:duration-300 dark:border-gray-800 dark:hover:bg-gray-900;
|
||||||
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 {
|
.ae_container_module_options {
|
||||||
@apply text-cyan-950 dark:text-cyan-50
|
@apply flex w-full max-w-full flex-row flex-wrap items-center justify-around rounded-md border border-cyan-200 bg-cyan-50 p-2 text-cyan-950 transition-all hover:border-cyan-400 hover:bg-cyan-100 dark:border-cyan-800 dark:bg-cyan-950 dark:text-cyan-50 dark:hover:border-cyan-600 dark:hover:bg-cyan-900;
|
||||||
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
|
|
||||||
flex flex-row flex-wrap items-center justify-around
|
|
||||||
w-full max-w-full
|
|
||||||
p-2
|
|
||||||
transition-all;
|
|
||||||
}
|
}
|
||||||
.ae_container_module_help {
|
.ae_container_module_help {
|
||||||
@apply text-yellow-950 dark:text-yellow-50
|
@apply w-lg max-w-full rounded-md border border-yellow-200 bg-yellow-50 p-2 text-yellow-950 transition-all hover:border-yellow-400 hover:bg-yellow-100 dark:border-yellow-800 dark:bg-yellow-950 dark:text-yellow-50 dark:hover:border-yellow-600 dark:hover:bg-yellow-900;
|
||||||
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
|
|
||||||
w-lg max-w-full
|
|
||||||
p-2
|
|
||||||
transition-all;
|
|
||||||
/* bg-yellow-100 border border-yellow-400 p-2 rounded-md max-w-xl */
|
/* bg-yellow-100 border border-yellow-400 p-2 rounded-md max-w-xl */
|
||||||
}
|
}
|
||||||
|
|
||||||
.ae_container_actions {
|
.ae_container_actions {
|
||||||
@apply container preset-tonal-success border border-success-500 rounded-md flex flex-row items-center my-2 p-2;
|
@apply preset-tonal-success border-success-500 container my-2 flex flex-row items-center rounded-md border p-2;
|
||||||
}
|
}
|
||||||
.ae_container_results {
|
.ae_container_results {
|
||||||
@apply container;
|
@apply container;
|
||||||
@@ -500,23 +493,11 @@ html.trusted_access #appShell {
|
|||||||
@apply container;
|
@apply container;
|
||||||
}
|
}
|
||||||
.ae_container_help {
|
.ae_container_help {
|
||||||
@apply text-yellow-950 dark:text-yellow-50
|
@apply max-w-full rounded-md border border-yellow-200 bg-yellow-50 p-2 text-yellow-950 transition-all hover:border-yellow-400 hover:bg-yellow-100 dark:border-yellow-800 dark:bg-yellow-950 dark:text-yellow-50 dark:hover:border-yellow-600 dark:hover:bg-yellow-900;
|
||||||
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
|
|
||||||
max-w-full
|
|
||||||
p-2
|
|
||||||
transition-all;
|
|
||||||
/* bg-yellow-100 border border-yellow-400 p-2 rounded-md max-w-xl */
|
/* bg-yellow-100 border border-yellow-400 p-2 rounded-md max-w-xl */
|
||||||
}
|
}
|
||||||
.ae_container_info {
|
.ae_container_info {
|
||||||
@apply text-cyan-950 dark:text-cyan-50
|
@apply max-w-full rounded-md border border-cyan-200 bg-cyan-50 p-2 text-cyan-950 transition-all hover:border-cyan-400 hover:bg-cyan-100 dark:border-cyan-800 dark:bg-cyan-950 dark:text-cyan-50 dark:hover:border-cyan-600 dark:hover:bg-cyan-900;
|
||||||
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
|
|
||||||
max-w-full
|
|
||||||
p-2
|
|
||||||
transition-all;
|
|
||||||
}
|
}
|
||||||
.ae_container_msg {
|
.ae_container_msg {
|
||||||
@apply container;
|
@apply container;
|
||||||
|
|||||||
@@ -12,16 +12,13 @@
|
|||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
<link
|
<link
|
||||||
href="https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,400;0,700;1,400;1,700&display=swap"
|
href="https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,400;0,700;1,400;1,700&display=swap"
|
||||||
rel="stylesheet"
|
rel="stylesheet" />
|
||||||
/>
|
|
||||||
<link
|
<link
|
||||||
href="https://fonts.googleapis.com/css2?family=Noto+Serif:ital,wght@0,400;0,700;1,400;1,700&display=swap"
|
href="https://fonts.googleapis.com/css2?family=Noto+Serif:ital,wght@0,400;0,700;1,400;1,700&display=swap"
|
||||||
rel="stylesheet"
|
rel="stylesheet" />
|
||||||
/>
|
|
||||||
<link
|
<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"
|
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"
|
rel="stylesheet" />
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- <link href="app.css" rel="stylesheet"> -->
|
<!-- <link href="app.css" rel="stylesheet"> -->
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,9 @@ export const delete_object = async function delete_object({
|
|||||||
// Construct the URL with query parameters
|
// Construct the URL with query parameters
|
||||||
const url = new URL(endpoint, api_cfg['base_url']);
|
const url = new URL(endpoint, api_cfg['base_url']);
|
||||||
if (params) {
|
if (params) {
|
||||||
Object.keys(params).forEach((key) => url.searchParams.append(key, params[key]));
|
Object.keys(params).forEach((key) =>
|
||||||
|
url.searchParams.append(key, params[key])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean and merge headers without mutating the original api_cfg
|
// Clean and merge headers without mutating the original api_cfg
|
||||||
@@ -70,8 +72,13 @@ export const delete_object = async function delete_object({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Auto-inject Authorization header if JWT is present but header is missing
|
// Auto-inject Authorization header if JWT is present but header is missing
|
||||||
const jwt = headers_cleaned['jwt'] || headers_cleaned['JWT'] || api_cfg['jwt'];
|
const jwt =
|
||||||
if (jwt && !headers_cleaned['Authorization'] && !headers_cleaned['authorization']) {
|
headers_cleaned['jwt'] || headers_cleaned['JWT'] || api_cfg['jwt'];
|
||||||
|
if (
|
||||||
|
jwt &&
|
||||||
|
!headers_cleaned['Authorization'] &&
|
||||||
|
!headers_cleaned['authorization']
|
||||||
|
) {
|
||||||
headers_cleaned['Authorization'] = `Bearer ${jwt}`;
|
headers_cleaned['Authorization'] = `Bearer ${jwt}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,20 +100,26 @@ export const delete_object = async function delete_object({
|
|||||||
try {
|
try {
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
const timeoutId = setTimeout(() => {
|
const timeoutId = setTimeout(() => {
|
||||||
console.error(`API DELETE request timed out after ${timeout}ms.`);
|
console.error(
|
||||||
|
`API DELETE request timed out after ${timeout}ms.`
|
||||||
|
);
|
||||||
controller.abort();
|
controller.abort();
|
||||||
}, timeout);
|
}, timeout);
|
||||||
|
|
||||||
const fetchOptions: RequestInit = {
|
const fetchOptions: RequestInit = {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
headers: headers_cleaned,
|
headers: headers_cleaned,
|
||||||
body: Object.keys(data).length > 0 ? JSON.stringify(data) : undefined,
|
body:
|
||||||
|
Object.keys(data).length > 0
|
||||||
|
? JSON.stringify(data)
|
||||||
|
: undefined,
|
||||||
signal: controller.signal
|
signal: controller.signal
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await fetch_method(url.toString(), fetchOptions).catch(function (
|
const response = await fetch_method(
|
||||||
error: any
|
url.toString(),
|
||||||
) {
|
fetchOptions
|
||||||
|
).catch(function (error: any) {
|
||||||
console.log(
|
console.log(
|
||||||
'API DELETE Object *fetch* request was aborted or failed in an unexpected way.',
|
'API DELETE Object *fetch* request was aborted or failed in an unexpected way.',
|
||||||
error
|
error
|
||||||
@@ -121,7 +134,9 @@ export const delete_object = async function delete_object({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`Response: status=${response.status} attempt=${attempt}`);
|
console.log(
|
||||||
|
`Response: status=${response.status} attempt=${attempt}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@@ -131,13 +146,18 @@ export const delete_object = async function delete_object({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const errorBody = await response.text();
|
const errorBody = await response.text();
|
||||||
console.error(`HTTP error! status: ${response.status}`, errorBody);
|
console.error(
|
||||||
|
`HTTP error! status: ${response.status}`,
|
||||||
|
errorBody
|
||||||
|
);
|
||||||
|
|
||||||
if (response.status >= 400 && response.status < 404) {
|
if (response.status >= 400 && response.status < 404) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error(`HTTP error! status: ${response.status} - ${errorBody}`);
|
throw new Error(
|
||||||
|
`HTTP error! status: ${response.status} - ${errorBody}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const json = await response.json();
|
const json = await response.json();
|
||||||
@@ -148,7 +168,11 @@ export const delete_object = async function delete_object({
|
|||||||
|
|
||||||
// Return the response data or metadata
|
// Return the response data or metadata
|
||||||
// Robustly handle V3 response envelopes
|
// Robustly handle V3 response envelopes
|
||||||
return return_meta ? json : (json.data !== undefined ? json.data : json);
|
return return_meta
|
||||||
|
? json
|
||||||
|
: json.data !== undefined
|
||||||
|
? json.data
|
||||||
|
: json;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`API DELETE error on attempt ${attempt}:`, error);
|
console.error(`API DELETE error on attempt ${attempt}:`, error);
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,9 @@ export async function get_ae_obj_id_crud({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** get_ae_obj_id_crud() *** Type: ${obj_type} ID: ${obj_id}`);
|
console.log(
|
||||||
|
`*** get_ae_obj_id_crud() *** Type: ${obj_type} ID: ${obj_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// V3 Standard: Unified endpoint for all objects
|
// V3 Standard: Unified endpoint for all objects
|
||||||
@@ -77,7 +79,10 @@ export async function get_ae_obj_id_crud({
|
|||||||
log_lvl: log_lvl,
|
log_lvl: log_lvl,
|
||||||
return_meta: return_meta
|
return_meta: return_meta
|
||||||
}).catch(function (error: any) {
|
}).catch(function (error: any) {
|
||||||
console.error(`API GET CRUD object ID request failed for ${obj_type}/${obj_id}`, error);
|
console.error(
|
||||||
|
`API GET CRUD object ID request failed for ${obj_type}/${obj_id}`,
|
||||||
|
error
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ interface GetAeObjV3Params {
|
|||||||
/**
|
/**
|
||||||
* Get a single object by ID (V3)
|
* Get a single object by ID (V3)
|
||||||
*/
|
*/
|
||||||
export async function get_ae_obj_v3({
|
export async function get_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type,
|
obj_type,
|
||||||
obj_id,
|
obj_id,
|
||||||
@@ -27,7 +27,7 @@ export async function get_ae_obj_v3({
|
|||||||
const query_params: key_val = { view, ...params };
|
const query_params: key_val = { view, ...params };
|
||||||
|
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log('*** get_ae_obj_v3 ***');
|
console.log('*** get_ae_obj ***');
|
||||||
console.log('Endpoint:', endpoint);
|
console.log('Endpoint:', endpoint);
|
||||||
console.log('Params:', query_params);
|
console.log('Params:', query_params);
|
||||||
}
|
}
|
||||||
@@ -56,7 +56,7 @@ interface GetNestedAeObjV3Params {
|
|||||||
/**
|
/**
|
||||||
* Get a single nested object by ID (V3)
|
* Get a single nested object by ID (V3)
|
||||||
*/
|
*/
|
||||||
export async function get_nested_ae_obj_v3({
|
export async function get_nested_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
parent_type,
|
parent_type,
|
||||||
parent_id,
|
parent_id,
|
||||||
@@ -71,7 +71,7 @@ export async function get_nested_ae_obj_v3({
|
|||||||
const query_params: key_val = { view, ...params };
|
const query_params: key_val = { view, ...params };
|
||||||
|
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log('*** get_nested_ae_obj_v3 ***');
|
console.log('*** get_nested_ae_obj ***');
|
||||||
console.log('Endpoint:', endpoint);
|
console.log('Endpoint:', endpoint);
|
||||||
console.log('Params:', query_params);
|
console.log('Params:', query_params);
|
||||||
}
|
}
|
||||||
@@ -95,14 +95,17 @@ interface GetAeObjLiV3Params {
|
|||||||
view?: string;
|
view?: string;
|
||||||
limit?: number;
|
limit?: number;
|
||||||
offset?: number;
|
offset?: number;
|
||||||
order_by_li?: Record<string, 'ASC' | 'DESC'> | Record<string, 'ASC' | 'DESC'>[] | null;
|
order_by_li?:
|
||||||
|
| Record<string, 'ASC' | 'DESC'>
|
||||||
|
| Record<string, 'ASC' | 'DESC'>[]
|
||||||
|
| null;
|
||||||
delay_ms?: number;
|
delay_ms?: number;
|
||||||
params?: key_val;
|
params?: key_val;
|
||||||
headers?: key_val;
|
headers?: key_val;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function get_ae_obj_li_v3({
|
export async function get_ae_obj_li({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type,
|
obj_type,
|
||||||
for_obj_type,
|
for_obj_type,
|
||||||
@@ -137,7 +140,7 @@ export async function get_ae_obj_li_v3({
|
|||||||
if (delay_ms > 0) query_params['delay_ms'] = delay_ms;
|
if (delay_ms > 0) query_params['delay_ms'] = delay_ms;
|
||||||
|
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log('*** get_ae_obj_li_v3 ***');
|
console.log('*** get_ae_obj_li ***');
|
||||||
console.log('Endpoint:', endpoint);
|
console.log('Endpoint:', endpoint);
|
||||||
console.log('Params:', query_params);
|
console.log('Params:', query_params);
|
||||||
console.log('Headers:', headers);
|
console.log('Headers:', headers);
|
||||||
@@ -162,12 +165,15 @@ interface GetNestedObjLiV3Params {
|
|||||||
view?: string;
|
view?: string;
|
||||||
limit?: number;
|
limit?: number;
|
||||||
offset?: number;
|
offset?: number;
|
||||||
order_by_li?: Record<string, 'ASC' | 'DESC'> | Record<string, 'ASC' | 'DESC'>[] | null;
|
order_by_li?:
|
||||||
|
| Record<string, 'ASC' | 'DESC'>
|
||||||
|
| Record<string, 'ASC' | 'DESC'>[]
|
||||||
|
| null;
|
||||||
delay_ms?: number;
|
delay_ms?: number;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function get_nested_obj_li_v3({
|
export async function get_nested_obj_li({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
parent_type,
|
parent_type,
|
||||||
parent_id,
|
parent_id,
|
||||||
@@ -195,7 +201,7 @@ export async function get_nested_obj_li_v3({
|
|||||||
if (delay_ms > 0) params['delay_ms'] = delay_ms;
|
if (delay_ms > 0) params['delay_ms'] = delay_ms;
|
||||||
|
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log('*** get_nested_obj_li_v3 ***');
|
console.log('*** get_nested_obj_li ***');
|
||||||
console.log('Endpoint:', endpoint);
|
console.log('Endpoint:', endpoint);
|
||||||
console.log('Params:', params);
|
console.log('Params:', params);
|
||||||
}
|
}
|
||||||
@@ -1,229 +0,0 @@
|
|||||||
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?: '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}]`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log('Endpoint:', endpoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (for_obj_type) {
|
|
||||||
params['for_obj_type'] = for_obj_type;
|
|
||||||
}
|
|
||||||
if (for_obj_id) {
|
|
||||||
params['for_obj_id'] = for_obj_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
params['use_alt_table'] = use_alt_table;
|
|
||||||
params['use_alt_base'] = use_alt_base;
|
|
||||||
|
|
||||||
/* Need to deal with inc params here */
|
|
||||||
|
|
||||||
const allowed_enabled_list = ['all', 'enabled', 'not_enabled'];
|
|
||||||
if (allowed_enabled_list.includes(enabled)) {
|
|
||||||
params['enabled'] = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
const 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) {
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log('Order By:', order_by_li);
|
|
||||||
}
|
|
||||||
headers['order_by_li'] = 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).
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log('JSON Object:', params_json);
|
|
||||||
console.log(JSON.stringify(params_json));
|
|
||||||
}
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
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,
|
|
||||||
return_meta: return_meta,
|
|
||||||
log_lvl: log_lvl
|
|
||||||
});
|
|
||||||
|
|
||||||
if (log_lvl > 1) {
|
|
||||||
console.log(object_li_get_promise);
|
|
||||||
}
|
|
||||||
|
|
||||||
return object_li_get_promise;
|
|
||||||
}
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
import type { key_val } from '$lib/stores/ae_stores';
|
|
||||||
import { get_object } from './api_get_object';
|
|
||||||
|
|
||||||
// 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',
|
|
||||||
activity_log: '/crud/activity_log/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 | 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_v2() ***');
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const endpoint = `/v2${getEndpointForObjType(obj_type, for_obj_type)}`;
|
|
||||||
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';
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
const 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 URL GET params do not handle complex objects very well.
|
|
||||||
if (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: "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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,7 +15,7 @@ interface GetDataStoreV3Params {
|
|||||||
* Uses hierarchical fallback logic (Specific -> Account -> Global)
|
* Uses hierarchical fallback logic (Specific -> Account -> Global)
|
||||||
* Path: GET /v3/data_store/code/{code}
|
* Path: GET /v3/data_store/code/{code}
|
||||||
*/
|
*/
|
||||||
export async function get_data_store_v3({
|
export async function get_data_store({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
code,
|
code,
|
||||||
for_type = null,
|
for_type = null,
|
||||||
@@ -24,7 +24,9 @@ export async function get_data_store_v3({
|
|||||||
log_lvl = 0
|
log_lvl = 0
|
||||||
}: GetDataStoreV3Params): Promise<any> {
|
}: GetDataStoreV3Params): Promise<any> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** get_data_store_v3() *** code=${code} no_account_id=${no_account_id}`);
|
console.log(
|
||||||
|
`*** get_data_store() *** code=${code} no_account_id=${no_account_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const endpoint = `/v3/data_store/code/${code}`;
|
const endpoint = `/v3/data_store/code/${code}`;
|
||||||
@@ -8,7 +8,7 @@ import type { key_val } from '$lib/stores/ae_stores';
|
|||||||
*
|
*
|
||||||
* Endpoint: GET /v3/lookup/{lu_type}/list
|
* Endpoint: GET /v3/lookup/{lu_type}/list
|
||||||
*/
|
*/
|
||||||
export async function get_ae_lookup_li_v3({
|
export async function get_ae_lookup_li({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
lu_type,
|
lu_type,
|
||||||
site_id,
|
site_id,
|
||||||
@@ -16,6 +16,9 @@ export async function get_ae_lookup_li_v3({
|
|||||||
for_id,
|
for_id,
|
||||||
include_disabled = false,
|
include_disabled = false,
|
||||||
only_priority = false,
|
only_priority = false,
|
||||||
|
order_by_li = null,
|
||||||
|
limit = null,
|
||||||
|
offset = null,
|
||||||
params = {},
|
params = {},
|
||||||
headers = {},
|
headers = {},
|
||||||
log_lvl = 0
|
log_lvl = 0
|
||||||
@@ -27,12 +30,15 @@ export async function get_ae_lookup_li_v3({
|
|||||||
for_id?: string;
|
for_id?: string;
|
||||||
include_disabled?: boolean;
|
include_disabled?: boolean;
|
||||||
only_priority?: boolean;
|
only_priority?: boolean;
|
||||||
|
order_by_li?: Record<string, 'ASC' | 'DESC'> | null;
|
||||||
|
limit?: number | null;
|
||||||
|
offset?: number | null;
|
||||||
params?: key_val;
|
params?: key_val;
|
||||||
headers?: Record<string, string>;
|
headers?: Record<string, string>;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** get_ae_lookup_li_v3() *** lu_type=${lu_type}`);
|
console.log(`*** get_ae_lookup_li() *** lu_type=${lu_type}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const endpoint = `/v3/lookup/${lu_type}/list`;
|
const endpoint = `/v3/lookup/${lu_type}/list`;
|
||||||
@@ -43,6 +49,9 @@ export async function get_ae_lookup_li_v3({
|
|||||||
if (for_id) params['for_id'] = for_id;
|
if (for_id) params['for_id'] = for_id;
|
||||||
if (include_disabled) params['include_disabled'] = true;
|
if (include_disabled) params['include_disabled'] = true;
|
||||||
if (only_priority) params['only_priority'] = true;
|
if (only_priority) params['only_priority'] = true;
|
||||||
|
if (order_by_li) params['order_by_li'] = JSON.stringify(order_by_li);
|
||||||
|
if (limit != null) params['limit'] = limit;
|
||||||
|
if (offset != null) params['offset'] = offset;
|
||||||
|
|
||||||
// Lookup data is often global; ensure account context is handled if needed,
|
// Lookup data is often global; ensure account context is handled if needed,
|
||||||
// but GUIDE says it uses site Whitelist Policy.
|
// but GUIDE says it uses site Whitelist Policy.
|
||||||
@@ -41,7 +41,9 @@ export const get_object = async function get_object({
|
|||||||
retry_count?: number;
|
retry_count?: number;
|
||||||
}) {
|
}) {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** get_object() *** Endpoint: ${endpoint} AE Task ID: ${task_id}`);
|
console.log(
|
||||||
|
`*** get_object() *** Endpoint: ${endpoint} AE Task ID: ${task_id}`
|
||||||
|
);
|
||||||
console.log('Params:', params);
|
console.log('Params:', params);
|
||||||
if (log_lvl > 1) {
|
if (log_lvl > 1) {
|
||||||
console.log('Data:', data);
|
console.log('Data:', data);
|
||||||
@@ -55,7 +57,10 @@ export const get_object = async function get_object({
|
|||||||
|
|
||||||
// FAIL FAST: Check if we are explicitly offline to avoid long browser timeouts
|
// FAIL FAST: Check if we are explicitly offline to avoid long browser timeouts
|
||||||
if (typeof navigator !== 'undefined' && !navigator.onLine) {
|
if (typeof navigator !== 'undefined' && !navigator.onLine) {
|
||||||
if (log_lvl) console.log('get_object: Browser is offline. Failing fast to allow cache fallback.');
|
if (log_lvl)
|
||||||
|
console.log(
|
||||||
|
'get_object: Browser is offline. Failing fast to allow cache fallback.'
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +69,9 @@ export const get_object = async function get_object({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const url = new URL(endpoint, api_cfg['base_url']);
|
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 controller = new AbortController();
|
||||||
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
||||||
@@ -96,14 +103,19 @@ export const get_object = async function get_object({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle "Bootstrap Paradox" for unauthenticated requests
|
// Handle "Bootstrap Paradox" for unauthenticated requests
|
||||||
const bypass_val = merged_headers['x-no-account-id'] || merged_headers['x_no_account_id'];
|
const bypass_val =
|
||||||
const is_valid_bypass = bypass_val === 'bypass' ||
|
merged_headers['x-no-account-id'] || merged_headers['x_no_account_id'];
|
||||||
bypass_val === 'Nothing to See Here' ||
|
const is_valid_bypass =
|
||||||
params['key'] ||
|
bypass_val === 'bypass' ||
|
||||||
bypass_val === 'direct-download';
|
bypass_val === 'Nothing to See Here' ||
|
||||||
|
params['key'] ||
|
||||||
|
bypass_val === 'direct-download';
|
||||||
|
|
||||||
if (is_valid_bypass) {
|
if (is_valid_bypass) {
|
||||||
if (log_lvl > 1) console.log('api_get_object: Valid bypass detected. Stripping account ID context.');
|
if (log_lvl > 1)
|
||||||
|
console.log(
|
||||||
|
'api_get_object: Valid bypass detected. Stripping account ID context.'
|
||||||
|
);
|
||||||
delete merged_headers['x-account-id'];
|
delete merged_headers['x-account-id'];
|
||||||
delete merged_headers['x_account_id'];
|
delete merged_headers['x_account_id'];
|
||||||
} else {
|
} else {
|
||||||
@@ -126,11 +138,12 @@ export const get_object = async function get_object({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Auto-inject Authorization header if JWT is present but header is missing
|
// Auto-inject Authorization header if JWT is present but header is missing
|
||||||
let jwt = headers_cleaned['jwt'] ||
|
let jwt =
|
||||||
headers_cleaned['JWT'] ||
|
headers_cleaned['jwt'] ||
|
||||||
api_cfg['jwt'] ||
|
headers_cleaned['JWT'] ||
|
||||||
api_cfg['headers']?.['jwt'] ||
|
api_cfg['jwt'] ||
|
||||||
api_cfg['headers']?.['JWT'];
|
api_cfg['headers']?.['jwt'] ||
|
||||||
|
api_cfg['headers']?.['JWT'];
|
||||||
|
|
||||||
// Final Fallback: Direct check of primary ae_loc key
|
// Final Fallback: Direct check of primary ae_loc key
|
||||||
if (!jwt && typeof localStorage !== 'undefined') {
|
if (!jwt && typeof localStorage !== 'undefined') {
|
||||||
@@ -145,7 +158,11 @@ export const get_object = async function get_object({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jwt && !headers_cleaned['Authorization'] && !headers_cleaned['authorization']) {
|
if (
|
||||||
|
jwt &&
|
||||||
|
!headers_cleaned['Authorization'] &&
|
||||||
|
!headers_cleaned['authorization']
|
||||||
|
) {
|
||||||
headers_cleaned['Authorization'] = `Bearer ${jwt}`;
|
headers_cleaned['Authorization'] = `Bearer ${jwt}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,18 +191,29 @@ export const get_object = async function get_object({
|
|||||||
for (let attempt = 1; attempt <= retry_count; attempt++) {
|
for (let attempt = 1; attempt <= retry_count; attempt++) {
|
||||||
// FAIL FAST: Check if we are explicitly offline to avoid long browser timeouts
|
// FAIL FAST: Check if we are explicitly offline to avoid long browser timeouts
|
||||||
if (typeof navigator !== 'undefined' && !navigator.onLine) {
|
if (typeof navigator !== 'undefined' && !navigator.onLine) {
|
||||||
if (log_lvl) console.log(`get_object: Browser is offline (attempt ${attempt}). Failing fast to allow cache fallback.`);
|
if (log_lvl)
|
||||||
|
console.log(
|
||||||
|
`get_object: Browser is offline (attempt ${attempt}). Failing fast to allow cache fallback.`
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch_method(url.toString(), fetchOptions).catch(function (
|
const response = await fetch_method(
|
||||||
error: any
|
url.toString(),
|
||||||
) {
|
fetchOptions
|
||||||
|
).catch(function (error: any) {
|
||||||
// SILENCE NOISE: Aborted requests (common in SWR/Background loads) shouldn't spam logs
|
// SILENCE NOISE: Aborted requests (common in SWR/Background loads) shouldn't spam logs
|
||||||
if (error.name === 'AbortError' || error.message?.includes('aborted') || error.name === 'TypeError') {
|
if (
|
||||||
|
error.name === 'AbortError' ||
|
||||||
|
error.message?.includes('aborted') ||
|
||||||
|
error.name === 'TypeError'
|
||||||
|
) {
|
||||||
if (log_lvl > 1) {
|
if (log_lvl > 1) {
|
||||||
console.log('API GET: Request was aborted or terminated by browser. This is expected during navigation.', error);
|
console.log(
|
||||||
|
'API GET: Request was aborted or terminated by browser. This is expected during navigation.',
|
||||||
|
error
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return error; // Return error to be handled below
|
return error; // Return error to be handled below
|
||||||
}
|
}
|
||||||
@@ -199,11 +227,19 @@ export const get_object = async function get_object({
|
|||||||
clearTimeout(timeoutId);
|
clearTimeout(timeoutId);
|
||||||
|
|
||||||
// Check if we should stop due to abort or network failure
|
// Check if we should stop due to abort or network failure
|
||||||
if (response instanceof Error || (response && (response.name === 'TypeError' || response.name === 'AbortError'))) {
|
if (
|
||||||
|
response instanceof Error ||
|
||||||
|
(response &&
|
||||||
|
(response.name === 'TypeError' ||
|
||||||
|
response.name === 'AbortError'))
|
||||||
|
) {
|
||||||
// If it was an explicit abort, definitely stop
|
// If it was an explicit abort, definitely stop
|
||||||
if (response.name === 'AbortError') return false;
|
if (response.name === 'AbortError') return false;
|
||||||
|
|
||||||
if (log_lvl > 1) console.log('API GET Object: Detected NetworkError or TypeError. Failing fast.');
|
if (log_lvl > 1)
|
||||||
|
console.log(
|
||||||
|
'API GET Object: Detected NetworkError or TypeError. Failing fast.'
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,24 +267,45 @@ export const get_object = async function get_object({
|
|||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
if (response.status === 404) {
|
if (response.status === 404) {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log('The response was a 404 not found "error". Returning null.');
|
console.log(
|
||||||
|
'The response was a 404 not found "error". Returning null.'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FAIL FAST (Section 2D): Do not retry on Auth or Client errors (400, 401, 403, 422)
|
// FAIL FAST (Section 2D): Do not retry on Auth or Client errors (400, 401, 403, 422)
|
||||||
if (response.status === 400 || response.status === 401 || response.status === 403 || response.status === 422) {
|
if (
|
||||||
if (log_lvl) console.error(`API Client Failure (${response.status}). Failing fast.`);
|
response.status === 400 ||
|
||||||
|
response.status === 401 ||
|
||||||
|
response.status === 403 ||
|
||||||
|
response.status === 422
|
||||||
|
) {
|
||||||
|
if (log_lvl)
|
||||||
|
console.error(
|
||||||
|
`API Client Failure (${response.status}). Failing fast.`
|
||||||
|
);
|
||||||
|
|
||||||
if (response.status === 401 || response.status === 403) {
|
if (response.status === 401 || response.status === 403) {
|
||||||
console.warn(`AUTH DIAGNOSTICS: Headers sent for ${endpoint}:`, {
|
console.warn(
|
||||||
has_auth: !!headers_cleaned['Authorization'],
|
`AUTH DIAGNOSTICS: Headers sent for ${endpoint}:`,
|
||||||
has_api_key: !!headers_cleaned['x-aether-api-key'],
|
{
|
||||||
has_account_id: !!headers_cleaned['x-account-id'],
|
has_auth: !!headers_cleaned['Authorization'],
|
||||||
jwt_preview: jwt ? `${jwt.slice(0, 8)}...` : 'MISSING'
|
has_api_key:
|
||||||
});
|
!!headers_cleaned['x-aether-api-key'],
|
||||||
|
has_account_id:
|
||||||
|
!!headers_cleaned['x-account-id'],
|
||||||
|
jwt_preview: jwt
|
||||||
|
? `${jwt.slice(0, 8)}...`
|
||||||
|
: 'MISSING'
|
||||||
|
}
|
||||||
|
);
|
||||||
// Signal the root layout to show the session-expired banner.
|
// Signal the root layout to show the session-expired banner.
|
||||||
if (browser) ae_auth_error.set({ type: 'expired', ts: Date.now() });
|
if (browser)
|
||||||
|
ae_auth_error.set({
|
||||||
|
type: 'expired',
|
||||||
|
ts: Date.now()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Structured Error Handling (V3): Attempt to get rich error metadata
|
// Structured Error Handling (V3): Attempt to get rich error metadata
|
||||||
@@ -259,7 +316,11 @@ export const get_object = async function get_object({
|
|||||||
// Not JSON
|
// Not JSON
|
||||||
}
|
}
|
||||||
|
|
||||||
if (log_lvl) console.log('The response was not ok. Structured Error Check:', error_json);
|
if (log_lvl)
|
||||||
|
console.log(
|
||||||
|
'The response was not ok. Structured Error Check:',
|
||||||
|
error_json
|
||||||
|
);
|
||||||
|
|
||||||
if (error_json?.meta?.details) {
|
if (error_json?.meta?.details) {
|
||||||
return error_json;
|
return error_json;
|
||||||
@@ -273,7 +334,10 @@ export const get_object = async function get_object({
|
|||||||
status_code: response.status,
|
status_code: response.status,
|
||||||
details: {
|
details: {
|
||||||
category: 'validation',
|
category: 'validation',
|
||||||
message: typeof error_json.detail === 'string' ? error_json.detail : JSON.stringify(error_json.detail),
|
message:
|
||||||
|
typeof error_json.detail === 'string'
|
||||||
|
? error_json.detail
|
||||||
|
: JSON.stringify(error_json.detail),
|
||||||
raw: error_json.detail
|
raw: error_json.detail
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -307,7 +371,9 @@ export const get_object = async function get_object({
|
|||||||
chunks.push(value);
|
chunks.push(value);
|
||||||
receivedLength += value.length;
|
receivedLength += value.length;
|
||||||
|
|
||||||
const percent_completed = Math.round((receivedLength * 100) / contentLength);
|
const percent_completed = Math.round(
|
||||||
|
(receivedLength * 100) / contentLength
|
||||||
|
);
|
||||||
if (log_lvl > 1) {
|
if (log_lvl > 1) {
|
||||||
console.log(
|
console.log(
|
||||||
'GET Blob Progress:',
|
'GET Blob Progress:',
|
||||||
@@ -359,7 +425,10 @@ export const get_object = async function get_object({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(`API GET object request *fetch* error on attempt ${attempt}:`, error);
|
console.log(
|
||||||
|
`API GET object request *fetch* error on attempt ${attempt}:`,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
|
||||||
if (attempt === retry_count) {
|
if (attempt === retry_count) {
|
||||||
console.log('Max retry attempts reached. Returning false.');
|
console.log('Max retry attempts reached. Returning false.');
|
||||||
|
|||||||
@@ -1,524 +0,0 @@
|
|||||||
import axios from 'axios';
|
|
||||||
|
|
||||||
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 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 const get_object_percent_completed = temp_get_object_percent_completed;
|
|
||||||
|
|
||||||
// Updated 2024-05-23
|
|
||||||
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);
|
|
||||||
if (log_lvl > 1) {
|
|
||||||
console.log('Data:', data);
|
|
||||||
console.log(`Base URL: ${api_cfg['base_url']}; Timeout: ${timeout}`);
|
|
||||||
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}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!api_cfg) {
|
|
||||||
console.log('No API Config was provided. Returning false.');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const axios_api = axios.create({
|
|
||||||
baseURL: api_cfg['base_url'],
|
|
||||||
timeout: timeout // in milliseconds; 60000 = 60 seconds
|
|
||||||
/* other custom settings */
|
|
||||||
});
|
|
||||||
axios_api.defaults.headers = api_cfg['headers'];
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log('axios_api.defaults.headers:', axios_api.defaults.headers);
|
|
||||||
console.log('Additional headers:', headers);
|
|
||||||
}
|
|
||||||
|
|
||||||
// console.log('Clean the headers. No _underscores_!')
|
|
||||||
const headers_cleaned: key_val = {};
|
|
||||||
for (const prop in headers) {
|
|
||||||
// No underscores allowed in the header parameters!
|
|
||||||
const prop_cleaned = prop.replaceAll('_', '-');
|
|
||||||
|
|
||||||
// The value must be a string for the header!
|
|
||||||
if (typeof headers[prop] != 'string') {
|
|
||||||
headers[prop] = JSON.stringify(headers[prop]);
|
|
||||||
}
|
|
||||||
|
|
||||||
headers_cleaned[prop_cleaned] = headers[prop];
|
|
||||||
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log(`${prop_cleaned}: ${headers_cleaned[prop_cleaned]}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
headers = headers_cleaned;
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log('All headers cleaned:', headers);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log('URL params:');
|
|
||||||
}
|
|
||||||
for (const prop in params) {
|
|
||||||
if (log_lvl > 1) {
|
|
||||||
console.log(`URL param: ${prop}: ${params[prop]}`);
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
const response_data_promise = await axios_api
|
|
||||||
.get(endpoint, {
|
|
||||||
headers: headers,
|
|
||||||
params: params,
|
|
||||||
onDownloadProgress: (progressEvent) => {
|
|
||||||
const total = progressEvent.total ?? 0;
|
|
||||||
const percent_completed = total > 0 ? Math.round((progressEvent.loaded * 100) / total) : 0;
|
|
||||||
if (log_lvl > 1) {
|
|
||||||
console.log(
|
|
||||||
'GET Data Progress:',
|
|
||||||
progressEvent.progress,
|
|
||||||
'Total:',
|
|
||||||
total,
|
|
||||||
'Loaded:',
|
|
||||||
progressEvent.loaded,
|
|
||||||
'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: total,
|
|
||||||
size_loaded: progressEvent.loaded,
|
|
||||||
percent_completed: percent_completed
|
|
||||||
},
|
|
||||||
'*'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} 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) {
|
|
||||||
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 {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
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}`);
|
|
||||||
console.log(`Response Data:`, response_data_promise);
|
|
||||||
// console.log(response_data_promise);
|
|
||||||
}
|
|
||||||
if (response_data_promise) {
|
|
||||||
// The most common and expected response.
|
|
||||||
// console.log('Returning result. This is generally expected.');
|
|
||||||
return response_data_promise;
|
|
||||||
} else if (response_data_promise === null) {
|
|
||||||
// Less common, but expected response if no results were returned.
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log('Returning null. This is expected if no results were found. (404)');
|
|
||||||
}
|
|
||||||
return response_data_promise;
|
|
||||||
} else if (response_data_promise === false) {
|
|
||||||
// Not common, but expected response if the request to the API had an issue.
|
|
||||||
console.log('Returning false. There may have been an issue with this request.');
|
|
||||||
return response_data_promise;
|
|
||||||
} else {
|
|
||||||
// This generally should not happen. It likely means the query was bad or an API issue.
|
|
||||||
console.log('Returning (JSON/text) unknown. This should not happen in most cases.');
|
|
||||||
Promise.reject(new Error('fail')).then(resolved, rejected);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle the case where a Blob is expected to be returned.
|
|
||||||
} else {
|
|
||||||
// console.log('Expecting a Blob to be returned...');
|
|
||||||
|
|
||||||
const response_data_promise = await axios_api
|
|
||||||
.get(endpoint, {
|
|
||||||
params: params,
|
|
||||||
responseType: 'blob',
|
|
||||||
onDownloadProgress: (progressEvent) => {
|
|
||||||
const total = progressEvent.total ?? 0;
|
|
||||||
const percent_completed = total > 0 ? Math.round((progressEvent.loaded * 100) / total) : 0;
|
|
||||||
console.log(
|
|
||||||
'GET Blob Progress:',
|
|
||||||
progressEvent.progress,
|
|
||||||
'Total:',
|
|
||||||
total,
|
|
||||||
'Loaded:',
|
|
||||||
progressEvent.loaded,
|
|
||||||
'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: total,
|
|
||||||
size_loaded: progressEvent.loaded,
|
|
||||||
percent_completed: percent_completed
|
|
||||||
},
|
|
||||||
'*'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} 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) {
|
|
||||||
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 || 'download');
|
|
||||||
document.body.appendChild(link);
|
|
||||||
link.click();
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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(`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 (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.
|
|
||||||
// console.log('Returning result. This is generally expected.');
|
|
||||||
// let test_blob = new Blob([response_data_promise.data]);
|
|
||||||
// console.log(test_blob);
|
|
||||||
// return test_blob;
|
|
||||||
// console.log(response_data_promise.blob());
|
|
||||||
return response_data_promise;
|
|
||||||
} else if (response_data_promise === null) {
|
|
||||||
// Less common, but expected response if no results were returned.
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log('Returning null. This is expected if no results were found. (404)');
|
|
||||||
}
|
|
||||||
return response_data_promise;
|
|
||||||
} else if (response_data_promise === false) {
|
|
||||||
// Not common, but expected response if the request to the API had an issue.
|
|
||||||
console.log('Returning false. There may have been an issue with this request.');
|
|
||||||
return response_data_promise;
|
|
||||||
} else {
|
|
||||||
// This generally should not happen. It likely means the query was bad or an API issue.
|
|
||||||
console.log('Returning (blob) unknown. This should not happen in most cases.');
|
|
||||||
Promise.reject(new Error('fail')).then(resolved, rejected);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function resolved(result: any) {
|
|
||||||
console.log('Resolved');
|
|
||||||
}
|
|
||||||
|
|
||||||
function rejected(result: any) {
|
|
||||||
console.error(result);
|
|
||||||
}
|
|
||||||
@@ -45,7 +45,9 @@ export const patch_object = async function patch_object({
|
|||||||
// Construct the URL with query parameters
|
// Construct the URL with query parameters
|
||||||
const url = new URL(endpoint, api_cfg['base_url']);
|
const url = new URL(endpoint, api_cfg['base_url']);
|
||||||
if (params) {
|
if (params) {
|
||||||
Object.keys(params).forEach((key) => url.searchParams.append(key, params[key]));
|
Object.keys(params).forEach((key) =>
|
||||||
|
url.searchParams.append(key, params[key])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean and merge headers without mutating the original api_cfg
|
// Clean and merge headers without mutating the original api_cfg
|
||||||
@@ -75,14 +77,19 @@ export const patch_object = async function patch_object({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle "Bootstrap Paradox" for unauthenticated requests
|
// Handle "Bootstrap Paradox" for unauthenticated requests
|
||||||
const bypass_val = merged_headers['x-no-account-id'] || merged_headers['x_no_account_id'];
|
const bypass_val =
|
||||||
const is_valid_bypass = bypass_val === 'bypass' ||
|
merged_headers['x-no-account-id'] || merged_headers['x_no_account_id'];
|
||||||
bypass_val === 'Nothing to See Here' ||
|
const is_valid_bypass =
|
||||||
params['key'] ||
|
bypass_val === 'bypass' ||
|
||||||
bypass_val === 'direct-download';
|
bypass_val === 'Nothing to See Here' ||
|
||||||
|
params['key'] ||
|
||||||
|
bypass_val === 'direct-download';
|
||||||
|
|
||||||
if (is_valid_bypass) {
|
if (is_valid_bypass) {
|
||||||
if (log_lvl > 1) console.log('api_patch_object: Valid bypass detected. Stripping account ID context.');
|
if (log_lvl > 1)
|
||||||
|
console.log(
|
||||||
|
'api_patch_object: Valid bypass detected. Stripping account ID context.'
|
||||||
|
);
|
||||||
delete merged_headers['x-account-id'];
|
delete merged_headers['x-account-id'];
|
||||||
delete merged_headers['x_account_id'];
|
delete merged_headers['x_account_id'];
|
||||||
} else {
|
} else {
|
||||||
@@ -104,11 +111,12 @@ export const patch_object = async function patch_object({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Auto-inject Authorization header if JWT is present but header is missing
|
// Auto-inject Authorization header if JWT is present but header is missing
|
||||||
let jwt = headers_cleaned['jwt'] ||
|
let jwt =
|
||||||
headers_cleaned['JWT'] ||
|
headers_cleaned['jwt'] ||
|
||||||
api_cfg['jwt'] ||
|
headers_cleaned['JWT'] ||
|
||||||
api_cfg['headers']?.['jwt'] ||
|
api_cfg['jwt'] ||
|
||||||
api_cfg['headers']?.['JWT'];
|
api_cfg['headers']?.['jwt'] ||
|
||||||
|
api_cfg['headers']?.['JWT'];
|
||||||
|
|
||||||
// Final Fallback: Direct check of primary ae_loc key
|
// Final Fallback: Direct check of primary ae_loc key
|
||||||
if (!jwt && typeof localStorage !== 'undefined') {
|
if (!jwt && typeof localStorage !== 'undefined') {
|
||||||
@@ -123,7 +131,11 @@ export const patch_object = async function patch_object({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jwt && !headers_cleaned['Authorization'] && !headers_cleaned['authorization']) {
|
if (
|
||||||
|
jwt &&
|
||||||
|
!headers_cleaned['Authorization'] &&
|
||||||
|
!headers_cleaned['authorization']
|
||||||
|
) {
|
||||||
headers_cleaned['Authorization'] = `Bearer ${jwt}`;
|
headers_cleaned['Authorization'] = `Bearer ${jwt}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +157,9 @@ export const patch_object = async function patch_object({
|
|||||||
try {
|
try {
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
const timeoutId = setTimeout(() => {
|
const timeoutId = setTimeout(() => {
|
||||||
console.error(`API PATCH request timed out after ${timeout}ms.`);
|
console.error(
|
||||||
|
`API PATCH request timed out after ${timeout}ms.`
|
||||||
|
);
|
||||||
controller.abort();
|
controller.abort();
|
||||||
}, timeout);
|
}, timeout);
|
||||||
|
|
||||||
@@ -156,9 +170,10 @@ export const patch_object = async function patch_object({
|
|||||||
signal: controller.signal
|
signal: controller.signal
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await fetch_method(url.toString(), fetchOptions).catch(function (
|
const response = await fetch_method(
|
||||||
error: any
|
url.toString(),
|
||||||
) {
|
fetchOptions
|
||||||
|
).catch(function (error: any) {
|
||||||
console.log(
|
console.log(
|
||||||
'API PATCH Object *fetch* request was aborted or failed in an unexpected way.',
|
'API PATCH Object *fetch* request was aborted or failed in an unexpected way.',
|
||||||
error
|
error
|
||||||
@@ -173,30 +188,53 @@ export const patch_object = async function patch_object({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`Response: status=${response.status} attempt=${attempt}`);
|
console.log(
|
||||||
|
`Response: status=${response.status} attempt=${attempt}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
if (response.status === 404) {
|
if (response.status === 404) {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log('The response was a 404 not found "error". Returning null.');
|
console.log(
|
||||||
|
'The response was a 404 not found "error". Returning null.'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FAIL FAST (Section 2D): Do not retry on Auth or Client errors (400, 401, 403, 422)
|
// FAIL FAST (Section 2D): Do not retry on Auth or Client errors (400, 401, 403, 422)
|
||||||
if (response.status === 400 || response.status === 401 || response.status === 403 || response.status === 422) {
|
if (
|
||||||
if (log_lvl) console.error(`API Client Failure (${response.status}). Failing fast.`);
|
response.status === 400 ||
|
||||||
|
response.status === 401 ||
|
||||||
|
response.status === 403 ||
|
||||||
|
response.status === 422
|
||||||
|
) {
|
||||||
|
if (log_lvl)
|
||||||
|
console.error(
|
||||||
|
`API Client Failure (${response.status}). Failing fast.`
|
||||||
|
);
|
||||||
|
|
||||||
if (response.status === 401 || response.status === 403) {
|
if (response.status === 401 || response.status === 403) {
|
||||||
console.warn(`AUTH DIAGNOSTICS (PATCH): Headers sent for ${endpoint}:`, {
|
console.warn(
|
||||||
has_auth: !!headers_cleaned['Authorization'],
|
`AUTH DIAGNOSTICS (PATCH): Headers sent for ${endpoint}:`,
|
||||||
has_api_key: !!headers_cleaned['x-aether-api-key'],
|
{
|
||||||
has_account_id: !!headers_cleaned['x-account-id'],
|
has_auth: !!headers_cleaned['Authorization'],
|
||||||
jwt_preview: jwt ? `${jwt.slice(0, 8)}...` : 'MISSING'
|
has_api_key:
|
||||||
});
|
!!headers_cleaned['x-aether-api-key'],
|
||||||
|
has_account_id:
|
||||||
|
!!headers_cleaned['x-account-id'],
|
||||||
|
jwt_preview: jwt
|
||||||
|
? `${jwt.slice(0, 8)}...`
|
||||||
|
: 'MISSING'
|
||||||
|
}
|
||||||
|
);
|
||||||
// Signal the root layout to show the session-expired banner.
|
// Signal the root layout to show the session-expired banner.
|
||||||
if (browser) ae_auth_error.set({ type: 'expired', ts: Date.now() });
|
if (browser)
|
||||||
|
ae_auth_error.set({
|
||||||
|
type: 'expired',
|
||||||
|
ts: Date.now()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Structured Error Handling (V3): Attempt to get rich error metadata
|
// Structured Error Handling (V3): Attempt to get rich error metadata
|
||||||
@@ -207,7 +245,11 @@ export const patch_object = async function patch_object({
|
|||||||
// Not JSON
|
// Not JSON
|
||||||
}
|
}
|
||||||
|
|
||||||
if (log_lvl) console.log('The response was not ok. Structured Error Check:', error_json);
|
if (log_lvl)
|
||||||
|
console.log(
|
||||||
|
'The response was not ok. Structured Error Check:',
|
||||||
|
error_json
|
||||||
|
);
|
||||||
|
|
||||||
if (error_json?.meta?.details) {
|
if (error_json?.meta?.details) {
|
||||||
return error_json;
|
return error_json;
|
||||||
@@ -221,7 +263,10 @@ export const patch_object = async function patch_object({
|
|||||||
status_code: response.status,
|
status_code: response.status,
|
||||||
details: {
|
details: {
|
||||||
category: 'validation',
|
category: 'validation',
|
||||||
message: typeof error_json.detail === 'string' ? error_json.detail : JSON.stringify(error_json.detail),
|
message:
|
||||||
|
typeof error_json.detail === 'string'
|
||||||
|
? error_json.detail
|
||||||
|
: JSON.stringify(error_json.detail),
|
||||||
raw: error_json.detail
|
raw: error_json.detail
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -242,7 +287,11 @@ export const patch_object = async function patch_object({
|
|||||||
|
|
||||||
// Return the response data or metadata
|
// Return the response data or metadata
|
||||||
// Robustly handle V3 response envelopes
|
// Robustly handle V3 response envelopes
|
||||||
return return_meta ? json : (json.data !== undefined ? json.data : json);
|
return return_meta
|
||||||
|
? json
|
||||||
|
: json.data !== undefined
|
||||||
|
? json.data
|
||||||
|
: json;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`API PATCH error on attempt ${attempt}:`, error);
|
console.error(`API PATCH error on attempt ${attempt}:`, error);
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ interface CreateAeObjV3Params {
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function create_ae_obj_v3({
|
export async function create_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type,
|
obj_type,
|
||||||
fields,
|
fields,
|
||||||
@@ -25,7 +25,7 @@ export async function create_ae_obj_v3({
|
|||||||
const endpoint = `/v3/crud/${obj_type}/`;
|
const endpoint = `/v3/crud/${obj_type}/`;
|
||||||
|
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log('*** create_ae_obj_v3 ***');
|
console.log('*** create_ae_obj ***');
|
||||||
console.log('Endpoint:', endpoint);
|
console.log('Endpoint:', endpoint);
|
||||||
console.log('Fields:', fields);
|
console.log('Fields:', fields);
|
||||||
}
|
}
|
||||||
@@ -33,7 +33,11 @@ export async function create_ae_obj_v3({
|
|||||||
// Standard Aether Pattern: Auto-serialize any key ending in _json
|
// Standard Aether Pattern: Auto-serialize any key ending in _json
|
||||||
const cleaned_fields = { ...fields };
|
const cleaned_fields = { ...fields };
|
||||||
for (const key in cleaned_fields) {
|
for (const key in cleaned_fields) {
|
||||||
if (key.endsWith('_json') && cleaned_fields[key] !== null && typeof cleaned_fields[key] === 'object') {
|
if (
|
||||||
|
key.endsWith('_json') &&
|
||||||
|
cleaned_fields[key] !== null &&
|
||||||
|
typeof cleaned_fields[key] === 'object'
|
||||||
|
) {
|
||||||
if (log_lvl) console.log(`Auto-serializing field: ${key}`);
|
if (log_lvl) console.log(`Auto-serializing field: ${key}`);
|
||||||
cleaned_fields[key] = JSON.stringify(cleaned_fields[key]);
|
cleaned_fields[key] = JSON.stringify(cleaned_fields[key]);
|
||||||
}
|
}
|
||||||
@@ -67,7 +71,7 @@ interface CreateNestedObjV3Params {
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function create_nested_obj_v3({
|
export async function create_nested_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
parent_type,
|
parent_type,
|
||||||
parent_id,
|
parent_id,
|
||||||
@@ -86,7 +90,7 @@ export async function create_nested_obj_v3({
|
|||||||
const endpoint = `/v3/crud/${p_type}/${p_id}/${c_type}/`;
|
const endpoint = `/v3/crud/${p_type}/${p_id}/${c_type}/`;
|
||||||
|
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log('*** create_nested_obj_v3 ***');
|
console.log('*** create_nested_obj ***');
|
||||||
console.log('Endpoint:', endpoint);
|
console.log('Endpoint:', endpoint);
|
||||||
console.log('Fields:', fields);
|
console.log('Fields:', fields);
|
||||||
}
|
}
|
||||||
@@ -94,7 +98,11 @@ export async function create_nested_obj_v3({
|
|||||||
// Standard Aether Pattern: Auto-serialize any key ending in _json
|
// Standard Aether Pattern: Auto-serialize any key ending in _json
|
||||||
const cleaned_fields = { ...fields };
|
const cleaned_fields = { ...fields };
|
||||||
for (const key in cleaned_fields) {
|
for (const key in cleaned_fields) {
|
||||||
if (key.endsWith('_json') && cleaned_fields[key] !== null && typeof cleaned_fields[key] === 'object') {
|
if (
|
||||||
|
key.endsWith('_json') &&
|
||||||
|
cleaned_fields[key] !== null &&
|
||||||
|
typeof cleaned_fields[key] === 'object'
|
||||||
|
) {
|
||||||
cleaned_fields[key] = JSON.stringify(cleaned_fields[key]);
|
cleaned_fields[key] = JSON.stringify(cleaned_fields[key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,7 +129,7 @@ interface UpdateAeObjV3Params {
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function update_ae_obj_v3({
|
export async function update_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type,
|
obj_type,
|
||||||
obj_id,
|
obj_id,
|
||||||
@@ -132,7 +140,7 @@ export async function update_ae_obj_v3({
|
|||||||
const endpoint = `/v3/crud/${obj_type}/${obj_id}`;
|
const endpoint = `/v3/crud/${obj_type}/${obj_id}`;
|
||||||
|
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log('*** update_ae_obj_v3 ***');
|
console.log('*** update_ae_obj ***');
|
||||||
console.log('Endpoint:', endpoint);
|
console.log('Endpoint:', endpoint);
|
||||||
console.log('Fields:', fields);
|
console.log('Fields:', fields);
|
||||||
}
|
}
|
||||||
@@ -140,7 +148,11 @@ export async function update_ae_obj_v3({
|
|||||||
// Standard Aether Pattern: Auto-serialize any key ending in _json
|
// Standard Aether Pattern: Auto-serialize any key ending in _json
|
||||||
const cleaned_fields = { ...fields };
|
const cleaned_fields = { ...fields };
|
||||||
for (const key in cleaned_fields) {
|
for (const key in cleaned_fields) {
|
||||||
if (key.endsWith('_json') && cleaned_fields[key] !== null && typeof cleaned_fields[key] === 'object') {
|
if (
|
||||||
|
key.endsWith('_json') &&
|
||||||
|
cleaned_fields[key] !== null &&
|
||||||
|
typeof cleaned_fields[key] === 'object'
|
||||||
|
) {
|
||||||
if (log_lvl > 1) console.log(`Auto-serializing field: ${key}`);
|
if (log_lvl > 1) console.log(`Auto-serializing field: ${key}`);
|
||||||
cleaned_fields[key] = JSON.stringify(cleaned_fields[key]);
|
cleaned_fields[key] = JSON.stringify(cleaned_fields[key]);
|
||||||
}
|
}
|
||||||
@@ -172,7 +184,7 @@ interface UpdateNestedObjV3Params {
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function update_nested_obj_v3({
|
export async function update_nested_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
parent_type,
|
parent_type,
|
||||||
parent_id,
|
parent_id,
|
||||||
@@ -194,7 +206,7 @@ export async function update_nested_obj_v3({
|
|||||||
const endpoint = `/v3/crud/${p_type}/${p_id}/${c_type}/${c_id}`;
|
const endpoint = `/v3/crud/${p_type}/${p_id}/${c_type}/${c_id}`;
|
||||||
|
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log('*** update_nested_obj_v3 ***');
|
console.log('*** update_nested_obj ***');
|
||||||
console.log('Endpoint:', endpoint);
|
console.log('Endpoint:', endpoint);
|
||||||
console.log('Fields:', fields);
|
console.log('Fields:', fields);
|
||||||
}
|
}
|
||||||
@@ -202,7 +214,11 @@ export async function update_nested_obj_v3({
|
|||||||
// Standard Aether Pattern: Auto-serialize any key ending in _json
|
// Standard Aether Pattern: Auto-serialize any key ending in _json
|
||||||
const cleaned_fields = { ...fields };
|
const cleaned_fields = { ...fields };
|
||||||
for (const key in cleaned_fields) {
|
for (const key in cleaned_fields) {
|
||||||
if (key.endsWith('_json') && cleaned_fields[key] !== null && typeof cleaned_fields[key] === 'object') {
|
if (
|
||||||
|
key.endsWith('_json') &&
|
||||||
|
cleaned_fields[key] !== null &&
|
||||||
|
typeof cleaned_fields[key] === 'object'
|
||||||
|
) {
|
||||||
cleaned_fields[key] = JSON.stringify(cleaned_fields[key]);
|
cleaned_fields[key] = JSON.stringify(cleaned_fields[key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -233,7 +249,7 @@ interface DeleteAeObjV3Params {
|
|||||||
* Delete a single object by ID (V3)
|
* Delete a single object by ID (V3)
|
||||||
* Supports 'delete' (hard), 'soft_delete', 'disable' (enable=false), and 'hide' (hide=true).
|
* Supports 'delete' (hard), 'soft_delete', 'disable' (enable=false), and 'hide' (hide=true).
|
||||||
*/
|
*/
|
||||||
export async function delete_ae_obj_v3({
|
export async function delete_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type,
|
obj_type,
|
||||||
obj_id,
|
obj_id,
|
||||||
@@ -245,7 +261,7 @@ export async function delete_ae_obj_v3({
|
|||||||
const query_params = { ...params, method };
|
const query_params = { ...params, method };
|
||||||
|
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log('*** delete_ae_obj_v3 ***');
|
console.log('*** delete_ae_obj ***');
|
||||||
console.log('Endpoint:', endpoint);
|
console.log('Endpoint:', endpoint);
|
||||||
console.log('Params:', query_params);
|
console.log('Params:', query_params);
|
||||||
}
|
}
|
||||||
@@ -278,7 +294,7 @@ interface DeleteNestedAeObjV3Params {
|
|||||||
/**
|
/**
|
||||||
* Delete a single nested object by ID (V3)
|
* Delete a single nested object by ID (V3)
|
||||||
*/
|
*/
|
||||||
export async function delete_nested_ae_obj_v3({
|
export async function delete_nested_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
parent_type,
|
parent_type,
|
||||||
parent_id,
|
parent_id,
|
||||||
@@ -301,7 +317,7 @@ export async function delete_nested_ae_obj_v3({
|
|||||||
const query_params = { ...params, method };
|
const query_params = { ...params, method };
|
||||||
|
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log('*** delete_nested_ae_obj_v3 ***');
|
console.log('*** delete_nested_ae_obj ***');
|
||||||
console.log('Endpoint:', endpoint);
|
console.log('Endpoint:', endpoint);
|
||||||
console.log('Params:', query_params);
|
console.log('Params:', query_params);
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,10 @@ interface SearchAeObjV3Params {
|
|||||||
view?: string;
|
view?: string;
|
||||||
for_obj_type?: string;
|
for_obj_type?: string;
|
||||||
for_obj_id?: string;
|
for_obj_id?: string;
|
||||||
order_by_li?: Record<string, 'ASC' | 'DESC'> | Record<string, 'ASC' | 'DESC'>[] | null;
|
order_by_li?:
|
||||||
|
| Record<string, 'ASC' | 'DESC'>
|
||||||
|
| Record<string, 'ASC' | 'DESC'>[]
|
||||||
|
| null;
|
||||||
limit?: number;
|
limit?: number;
|
||||||
offset?: number;
|
offset?: number;
|
||||||
delay_ms?: number;
|
delay_ms?: number;
|
||||||
@@ -19,7 +22,7 @@ interface SearchAeObjV3Params {
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function search_ae_obj_v3({
|
export async function search_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type,
|
obj_type,
|
||||||
search_query,
|
search_query,
|
||||||
@@ -55,13 +58,16 @@ export async function search_ae_obj_v3({
|
|||||||
|
|
||||||
// Serialize any complex objects in the query params (e.g. ft_qry, lk_qry)
|
// Serialize any complex objects in the query params (e.g. ft_qry, lk_qry)
|
||||||
for (const key in query_params) {
|
for (const key in query_params) {
|
||||||
if (typeof query_params[key] === 'object' && query_params[key] !== null) {
|
if (
|
||||||
|
typeof query_params[key] === 'object' &&
|
||||||
|
query_params[key] !== null
|
||||||
|
) {
|
||||||
query_params[key] = JSON.stringify(query_params[key]);
|
query_params[key] = JSON.stringify(query_params[key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log('*** search_ae_obj_v3 ***');
|
console.log('*** search_ae_obj ***');
|
||||||
console.log('Endpoint:', endpoint);
|
console.log('Endpoint:', endpoint);
|
||||||
console.log('Params:', query_params);
|
console.log('Params:', query_params);
|
||||||
console.log('Search Query:', search_query);
|
console.log('Search Query:', search_query);
|
||||||
@@ -41,7 +41,9 @@ export const post_object = async function post_object({
|
|||||||
retry_count?: number;
|
retry_count?: number;
|
||||||
}) {
|
}) {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** post_object() *** Endpoint: ${endpoint} Task ID: ${task_id}`);
|
console.log(
|
||||||
|
`*** post_object() *** Endpoint: ${endpoint} Task ID: ${task_id}`
|
||||||
|
);
|
||||||
console.log('Params:', params);
|
console.log('Params:', params);
|
||||||
if (log_lvl > 1) {
|
if (log_lvl > 1) {
|
||||||
console.log('Data:', data);
|
console.log('Data:', data);
|
||||||
@@ -65,7 +67,9 @@ export const post_object = async function post_object({
|
|||||||
// Construct the URL with query parameters
|
// Construct the URL with query parameters
|
||||||
const url = new URL(endpoint, api_cfg['base_url']);
|
const url = new URL(endpoint, api_cfg['base_url']);
|
||||||
if (params) {
|
if (params) {
|
||||||
Object.keys(params).forEach((key) => url.searchParams.append(key, params[key]));
|
Object.keys(params).forEach((key) =>
|
||||||
|
url.searchParams.append(key, params[key])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean and merge headers
|
// Clean and merge headers
|
||||||
@@ -95,14 +99,19 @@ export const post_object = async function post_object({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle "Bootstrap Paradox" for unauthenticated requests
|
// Handle "Bootstrap Paradox" for unauthenticated requests
|
||||||
const bypass_val = merged_headers['x-no-account-id'] || merged_headers['x_no_account_id'];
|
const bypass_val =
|
||||||
const is_valid_bypass = bypass_val === 'bypass' ||
|
merged_headers['x-no-account-id'] || merged_headers['x_no_account_id'];
|
||||||
bypass_val === 'Nothing to See Here' ||
|
const is_valid_bypass =
|
||||||
params['key'] ||
|
bypass_val === 'bypass' ||
|
||||||
bypass_val === 'direct-download';
|
bypass_val === 'Nothing to See Here' ||
|
||||||
|
params['key'] ||
|
||||||
|
bypass_val === 'direct-download';
|
||||||
|
|
||||||
if (is_valid_bypass) {
|
if (is_valid_bypass) {
|
||||||
if (log_lvl > 1) console.log('api_post_object: Valid bypass detected. Stripping account ID context.');
|
if (log_lvl > 1)
|
||||||
|
console.log(
|
||||||
|
'api_post_object: Valid bypass detected. Stripping account ID context.'
|
||||||
|
);
|
||||||
delete merged_headers['x-account-id'];
|
delete merged_headers['x-account-id'];
|
||||||
delete merged_headers['x_account_id'];
|
delete merged_headers['x_account_id'];
|
||||||
} else {
|
} else {
|
||||||
@@ -124,11 +133,12 @@ export const post_object = async function post_object({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Auto-inject Authorization header if JWT is present but header is missing
|
// Auto-inject Authorization header if JWT is present but header is missing
|
||||||
let jwt = headers_cleaned['jwt'] ||
|
let jwt =
|
||||||
headers_cleaned['JWT'] ||
|
headers_cleaned['jwt'] ||
|
||||||
api_cfg['jwt'] ||
|
headers_cleaned['JWT'] ||
|
||||||
api_cfg['headers']?.['jwt'] ||
|
api_cfg['jwt'] ||
|
||||||
api_cfg['headers']?.['JWT'];
|
api_cfg['headers']?.['jwt'] ||
|
||||||
|
api_cfg['headers']?.['JWT'];
|
||||||
|
|
||||||
// Final Fallback: Direct check of primary ae_loc key
|
// Final Fallback: Direct check of primary ae_loc key
|
||||||
if (!jwt && typeof localStorage !== 'undefined') {
|
if (!jwt && typeof localStorage !== 'undefined') {
|
||||||
@@ -143,7 +153,11 @@ export const post_object = async function post_object({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jwt && !headers_cleaned['Authorization'] && !headers_cleaned['authorization']) {
|
if (
|
||||||
|
jwt &&
|
||||||
|
!headers_cleaned['Authorization'] &&
|
||||||
|
!headers_cleaned['authorization']
|
||||||
|
) {
|
||||||
headers_cleaned['Authorization'] = `Bearer ${jwt}`;
|
headers_cleaned['Authorization'] = `Bearer ${jwt}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,13 +200,21 @@ export const post_object = async function post_object({
|
|||||||
console.log('Fetch Options:', fetchOptions);
|
console.log('Fetch Options:', fetchOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await fetch_method(url.toString(), fetchOptions).catch(function (
|
const response = await fetch_method(
|
||||||
error: any
|
url.toString(),
|
||||||
) {
|
fetchOptions
|
||||||
|
).catch(function (error: any) {
|
||||||
// SILENCE NOISE: Aborted requests shouldn't spam logs at log_lvl 0
|
// SILENCE NOISE: Aborted requests shouldn't spam logs at log_lvl 0
|
||||||
if (error.name === 'AbortError' || error.message?.includes('aborted') || error.name === 'TypeError') {
|
if (
|
||||||
|
error.name === 'AbortError' ||
|
||||||
|
error.message?.includes('aborted') ||
|
||||||
|
error.name === 'TypeError'
|
||||||
|
) {
|
||||||
if (log_lvl > 1) {
|
if (log_lvl > 1) {
|
||||||
console.log('API POST: Request was aborted or terminated by browser. Expected during navigation.', error);
|
console.log(
|
||||||
|
'API POST: Request was aborted or terminated by browser. Expected during navigation.',
|
||||||
|
error
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
@@ -206,9 +228,17 @@ export const post_object = async function post_object({
|
|||||||
clearTimeout(timeoutId);
|
clearTimeout(timeoutId);
|
||||||
|
|
||||||
// Check if we should stop due to abort or network failure
|
// Check if we should stop due to abort or network failure
|
||||||
if (response instanceof Error || (response && (response.name === 'TypeError' || response.name === 'AbortError'))) {
|
if (
|
||||||
|
response instanceof Error ||
|
||||||
|
(response &&
|
||||||
|
(response.name === 'TypeError' ||
|
||||||
|
response.name === 'AbortError'))
|
||||||
|
) {
|
||||||
if (response.name === 'AbortError') return false;
|
if (response.name === 'AbortError') return false;
|
||||||
if (log_lvl > 1) console.log('API POST Object: Detected NetworkError or TypeError. Failing fast.');
|
if (log_lvl > 1)
|
||||||
|
console.log(
|
||||||
|
'API POST Object: Detected NetworkError or TypeError. Failing fast.'
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,30 +249,53 @@ export const post_object = async function post_object({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`Response: status=${response.status} attempt=${attempt}`);
|
console.log(
|
||||||
|
`Response: status=${response.status} attempt=${attempt}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
if (response.status === 404) {
|
if (response.status === 404) {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log('The response was a 404 not found "error". Returning null.');
|
console.log(
|
||||||
|
'The response was a 404 not found "error". Returning null.'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FAIL FAST (Section 2D): Do not retry on Auth or Client errors (400, 401, 403, 422)
|
// FAIL FAST (Section 2D): Do not retry on Auth or Client errors (400, 401, 403, 422)
|
||||||
if (response.status === 400 || response.status === 401 || response.status === 403 || response.status === 422) {
|
if (
|
||||||
if (log_lvl) console.error(`API Client Failure (${response.status}). Failing fast.`);
|
response.status === 400 ||
|
||||||
|
response.status === 401 ||
|
||||||
|
response.status === 403 ||
|
||||||
|
response.status === 422
|
||||||
|
) {
|
||||||
|
if (log_lvl)
|
||||||
|
console.error(
|
||||||
|
`API Client Failure (${response.status}). Failing fast.`
|
||||||
|
);
|
||||||
|
|
||||||
if (response.status === 401 || response.status === 403) {
|
if (response.status === 401 || response.status === 403) {
|
||||||
console.warn(`AUTH DIAGNOSTICS (POST): Headers sent for ${endpoint}:`, {
|
console.warn(
|
||||||
has_auth: !!headers_cleaned['Authorization'],
|
`AUTH DIAGNOSTICS (POST): Headers sent for ${endpoint}:`,
|
||||||
has_api_key: !!headers_cleaned['x-aether-api-key'],
|
{
|
||||||
has_account_id: !!headers_cleaned['x-account-id'],
|
has_auth: !!headers_cleaned['Authorization'],
|
||||||
jwt_preview: jwt ? `${jwt.slice(0, 8)}...` : 'MISSING'
|
has_api_key:
|
||||||
});
|
!!headers_cleaned['x-aether-api-key'],
|
||||||
|
has_account_id:
|
||||||
|
!!headers_cleaned['x-account-id'],
|
||||||
|
jwt_preview: jwt
|
||||||
|
? `${jwt.slice(0, 8)}...`
|
||||||
|
: 'MISSING'
|
||||||
|
}
|
||||||
|
);
|
||||||
// Signal the root layout to show the session-expired banner.
|
// Signal the root layout to show the session-expired banner.
|
||||||
if (browser) ae_auth_error.set({ type: 'expired', ts: Date.now() });
|
if (browser)
|
||||||
|
ae_auth_error.set({
|
||||||
|
type: 'expired',
|
||||||
|
ts: Date.now()
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Structured Error Handling (V3): Attempt to get rich error metadata
|
// Structured Error Handling (V3): Attempt to get rich error metadata
|
||||||
@@ -253,7 +306,11 @@ export const post_object = async function post_object({
|
|||||||
// Not JSON
|
// Not JSON
|
||||||
}
|
}
|
||||||
|
|
||||||
if (log_lvl) console.log('The response was not ok. Structured Error Check:', error_json);
|
if (log_lvl)
|
||||||
|
console.log(
|
||||||
|
'The response was not ok. Structured Error Check:',
|
||||||
|
error_json
|
||||||
|
);
|
||||||
|
|
||||||
if (error_json?.meta?.details) {
|
if (error_json?.meta?.details) {
|
||||||
return error_json;
|
return error_json;
|
||||||
@@ -267,7 +324,10 @@ export const post_object = async function post_object({
|
|||||||
status_code: response.status,
|
status_code: response.status,
|
||||||
details: {
|
details: {
|
||||||
category: 'validation',
|
category: 'validation',
|
||||||
message: typeof error_json.detail === 'string' ? error_json.detail : JSON.stringify(error_json.detail),
|
message:
|
||||||
|
typeof error_json.detail === 'string'
|
||||||
|
? error_json.detail
|
||||||
|
: JSON.stringify(error_json.detail),
|
||||||
raw: error_json.detail
|
raw: error_json.detail
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -311,7 +371,11 @@ export const post_object = async function post_object({
|
|||||||
|
|
||||||
// Return the response data or metadata
|
// Return the response data or metadata
|
||||||
// Robustly handle V3 response envelopes
|
// Robustly handle V3 response envelopes
|
||||||
return return_meta ? json : (json.data !== undefined ? json.data : json);
|
return return_meta
|
||||||
|
? json
|
||||||
|
: json.data !== undefined
|
||||||
|
? json.data
|
||||||
|
: json;
|
||||||
} else {
|
} else {
|
||||||
const blob = await response.blob();
|
const blob = await response.blob();
|
||||||
|
|
||||||
|
|||||||
@@ -36,11 +36,13 @@ export async function load_ae_obj_id__archive({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_Archive | null> {
|
}): Promise<ae_Archive | null> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** load_ae_obj_id__archive() *** archive_id=${archive_id}`);
|
console.log(
|
||||||
|
`*** load_ae_obj_id__archive() *** archive_id=${archive_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ae_promises.load__archive_obj = await api
|
ae_promises.load__archive_obj = await api
|
||||||
.get_ae_obj_v3({
|
.get_ae_obj({
|
||||||
api_cfg: api_cfg,
|
api_cfg: api_cfg,
|
||||||
obj_type: 'archive',
|
obj_type: 'archive',
|
||||||
obj_id: archive_id,
|
obj_id: archive_id,
|
||||||
@@ -52,10 +54,11 @@ export async function load_ae_obj_id__archive({
|
|||||||
.then(async function (archive_obj_get_result) {
|
.then(async function (archive_obj_get_result) {
|
||||||
if (archive_obj_get_result) {
|
if (archive_obj_get_result) {
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
const processed_obj_li = await process_ae_obj__archive_props({
|
const processed_obj_li =
|
||||||
obj_li: [archive_obj_get_result],
|
await process_ae_obj__archive_props({
|
||||||
log_lvl: log_lvl
|
obj_li: [archive_obj_get_result],
|
||||||
});
|
log_lvl: log_lvl
|
||||||
|
});
|
||||||
await db_save_ae_obj_li__ae_obj({
|
await db_save_ae_obj_li__ae_obj({
|
||||||
db_instance: db_archives,
|
db_instance: db_archives,
|
||||||
table_name: 'archive',
|
table_name: 'archive',
|
||||||
@@ -76,19 +79,21 @@ export async function load_ae_obj_id__archive({
|
|||||||
|
|
||||||
if (inc_content_li && ae_promises.load__archive_obj) {
|
if (inc_content_li && ae_promises.load__archive_obj) {
|
||||||
// Load the contents for the archive
|
// Load the contents for the archive
|
||||||
const load_archive_content_obj_li = await load_ae_obj_li__archive_content({
|
const load_archive_content_obj_li =
|
||||||
api_cfg: api_cfg,
|
await load_ae_obj_li__archive_content({
|
||||||
for_obj_type: 'archive',
|
api_cfg: api_cfg,
|
||||||
for_obj_id: archive_id,
|
for_obj_type: 'archive',
|
||||||
enabled: enabled,
|
for_obj_id: archive_id,
|
||||||
hidden: hidden,
|
enabled: enabled,
|
||||||
limit: limit,
|
hidden: hidden,
|
||||||
offset: offset,
|
limit: limit,
|
||||||
params: params,
|
offset: offset,
|
||||||
try_cache: try_cache,
|
params: params,
|
||||||
log_lvl: log_lvl
|
try_cache: try_cache,
|
||||||
});
|
log_lvl: log_lvl
|
||||||
ae_promises.load__archive_obj.archive_content_li = load_archive_content_obj_li;
|
});
|
||||||
|
ae_promises.load__archive_obj.archive_content_li =
|
||||||
|
load_archive_content_obj_li;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ae_promises.load__archive_obj;
|
return ae_promises.load__archive_obj;
|
||||||
@@ -125,7 +130,9 @@ export async function load_ae_obj_li__archive({
|
|||||||
view?: string;
|
view?: string;
|
||||||
limit?: number;
|
limit?: number;
|
||||||
offset?: number;
|
offset?: number;
|
||||||
order_by_li?: Record<string, 'ASC' | 'DESC'> | Record<string, 'ASC' | 'DESC'>[];
|
order_by_li?:
|
||||||
|
| Record<string, 'ASC' | 'DESC'>
|
||||||
|
| Record<string, 'ASC' | 'DESC'>[];
|
||||||
params?: key_val;
|
params?: key_val;
|
||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
@@ -138,12 +145,14 @@ export async function load_ae_obj_li__archive({
|
|||||||
|
|
||||||
// DEBUG: Trace massive content loads
|
// DEBUG: Trace massive content loads
|
||||||
if (inc_content_li) {
|
if (inc_content_li) {
|
||||||
console.warn(`load_ae_obj_li__archive: Loading content for ALL archives in list! Limit: ${limit}`);
|
console.warn(
|
||||||
|
`load_ae_obj_li__archive: Loading content for ALL archives in list! Limit: ${limit}`
|
||||||
|
);
|
||||||
// console.trace();
|
// console.trace();
|
||||||
}
|
}
|
||||||
|
|
||||||
ae_promises.load__archive_obj_li = await api
|
ae_promises.load__archive_obj_li = await api
|
||||||
.get_ae_obj_li_v3({
|
.get_ae_obj_li({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'archive',
|
obj_type: 'archive',
|
||||||
for_obj_type,
|
for_obj_type,
|
||||||
@@ -159,10 +168,11 @@ export async function load_ae_obj_li__archive({
|
|||||||
.then(async function (archive_obj_li_get_result) {
|
.then(async function (archive_obj_li_get_result) {
|
||||||
if (archive_obj_li_get_result) {
|
if (archive_obj_li_get_result) {
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
const processed_obj_li = await process_ae_obj__archive_props({
|
const processed_obj_li =
|
||||||
obj_li: archive_obj_li_get_result,
|
await process_ae_obj__archive_props({
|
||||||
log_lvl: log_lvl
|
obj_li: archive_obj_li_get_result,
|
||||||
});
|
log_lvl: log_lvl
|
||||||
|
});
|
||||||
await db_save_ae_obj_li__ae_obj({
|
await db_save_ae_obj_li__ae_obj({
|
||||||
db_instance: db_archives,
|
db_instance: db_archives,
|
||||||
table_name: 'archive',
|
table_name: 'archive',
|
||||||
@@ -220,10 +230,12 @@ export async function create_ae_obj__archive({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_Archive | null> {
|
}): Promise<ae_Archive | null> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** create_ae_obj__archive() *** account_id=${account_id}`);
|
console.log(
|
||||||
|
`*** create_ae_obj__archive() *** account_id=${account_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await api.create_ae_obj_v3({
|
const result = await api.create_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'archive',
|
obj_type: 'archive',
|
||||||
fields: {
|
fields: {
|
||||||
@@ -268,10 +280,12 @@ export async function delete_ae_obj_id__archive({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** delete_ae_obj_id__archive() *** archive_id=${archive_id}`);
|
console.log(
|
||||||
|
`*** delete_ae_obj_id__archive() *** archive_id=${archive_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await api.delete_ae_obj_v3({
|
const result = await api.delete_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'archive',
|
obj_type: 'archive',
|
||||||
obj_id: archive_id,
|
obj_id: archive_id,
|
||||||
@@ -304,10 +318,13 @@ export async function update_ae_obj__archive({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_Archive | null> {
|
}): Promise<ae_Archive | null> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** update_ae_obj__archive() *** archive_id=${archive_id}`, data_kv);
|
console.log(
|
||||||
|
`*** update_ae_obj__archive() *** archive_id=${archive_id}`,
|
||||||
|
data_kv
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await api.update_ae_obj_v3({
|
const result = await api.update_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'archive',
|
obj_type: 'archive',
|
||||||
obj_id: archive_id,
|
obj_id: archive_id,
|
||||||
@@ -366,14 +383,18 @@ export async function qry__archive({
|
|||||||
const search_query: any = { and: [] };
|
const search_query: any = { and: [] };
|
||||||
|
|
||||||
if (account_id) {
|
if (account_id) {
|
||||||
search_query.and.push({ field: 'account_id_random', op: 'eq', value: account_id });
|
search_query.and.push({
|
||||||
|
field: 'account_id_random',
|
||||||
|
op: 'eq',
|
||||||
|
value: account_id
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qry_str) {
|
if (qry_str) {
|
||||||
search_query.q = qry_str;
|
search_query.q = qry_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
ae_promises.load__archive_obj_li = await api.search_ae_obj_v3({
|
ae_promises.load__archive_obj_li = await api.search_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'archive',
|
obj_type: 'archive',
|
||||||
search_query,
|
search_query,
|
||||||
@@ -452,11 +473,15 @@ async function _process_generic_props<T extends Record<string, any>>({
|
|||||||
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
||||||
const name = processed_obj.name ?? '';
|
const name = processed_obj.name ?? '';
|
||||||
|
|
||||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
(processed_obj as any).tmp_sort_1 =
|
||||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
`${group}_${priority}_${sort}_${updated}`;
|
||||||
|
(processed_obj as any).tmp_sort_2 =
|
||||||
|
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||||
|
|
||||||
if (specific_processor) {
|
if (specific_processor) {
|
||||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
processed_obj = await Promise.resolve(
|
||||||
|
specific_processor(processed_obj)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
processed_obj_li.push(processed_obj as T);
|
processed_obj_li.push(processed_obj as T);
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export async function load_ae_obj_id__archive_content({
|
|||||||
}
|
}
|
||||||
|
|
||||||
ae_promises.load__archive_content_obj = await api
|
ae_promises.load__archive_content_obj = await api
|
||||||
.get_ae_obj_v3({
|
.get_ae_obj({
|
||||||
api_cfg: api_cfg,
|
api_cfg: api_cfg,
|
||||||
obj_type: 'archive_content',
|
obj_type: 'archive_content',
|
||||||
obj_id: archive_content_id,
|
obj_id: archive_content_id,
|
||||||
@@ -41,10 +41,11 @@ export async function load_ae_obj_id__archive_content({
|
|||||||
.then(async function (archive_content_obj_get_result) {
|
.then(async function (archive_content_obj_get_result) {
|
||||||
if (archive_content_obj_get_result) {
|
if (archive_content_obj_get_result) {
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
const processed_obj_li = await process_ae_obj__archive_content_props({
|
const processed_obj_li =
|
||||||
obj_li: [archive_content_obj_get_result],
|
await process_ae_obj__archive_content_props({
|
||||||
log_lvl: log_lvl
|
obj_li: [archive_content_obj_get_result],
|
||||||
});
|
log_lvl: log_lvl
|
||||||
|
});
|
||||||
await db_save_ae_obj_li__ae_obj({
|
await db_save_ae_obj_li__ae_obj({
|
||||||
db_instance: db_archives,
|
db_instance: db_archives,
|
||||||
table_name: 'content',
|
table_name: 'content',
|
||||||
@@ -96,7 +97,9 @@ export async function load_ae_obj_li__archive_content({
|
|||||||
view?: string;
|
view?: string;
|
||||||
limit?: number;
|
limit?: number;
|
||||||
offset?: number;
|
offset?: number;
|
||||||
order_by_li?: Record<string, 'ASC' | 'DESC'> | Record<string, 'ASC' | 'DESC'>[];
|
order_by_li?:
|
||||||
|
| Record<string, 'ASC' | 'DESC'>
|
||||||
|
| Record<string, 'ASC' | 'DESC'>[];
|
||||||
params?: key_val;
|
params?: key_val;
|
||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
@@ -108,7 +111,7 @@ export async function load_ae_obj_li__archive_content({
|
|||||||
}
|
}
|
||||||
|
|
||||||
ae_promises.load__archive_content_obj_li = await api
|
ae_promises.load__archive_content_obj_li = await api
|
||||||
.get_ae_obj_li_v3({
|
.get_ae_obj_li({
|
||||||
api_cfg: api_cfg,
|
api_cfg: api_cfg,
|
||||||
obj_type: 'archive_content',
|
obj_type: 'archive_content',
|
||||||
for_obj_type,
|
for_obj_type,
|
||||||
@@ -124,10 +127,11 @@ export async function load_ae_obj_li__archive_content({
|
|||||||
.then(async function (archive_content_obj_li_get_result) {
|
.then(async function (archive_content_obj_li_get_result) {
|
||||||
if (archive_content_obj_li_get_result) {
|
if (archive_content_obj_li_get_result) {
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
const processed_obj_li = await process_ae_obj__archive_content_props({
|
const processed_obj_li =
|
||||||
obj_li: archive_content_obj_li_get_result,
|
await process_ae_obj__archive_content_props({
|
||||||
log_lvl: log_lvl
|
obj_li: archive_content_obj_li_get_result,
|
||||||
});
|
log_lvl: log_lvl
|
||||||
|
});
|
||||||
await db_save_ae_obj_li__ae_obj({
|
await db_save_ae_obj_li__ae_obj({
|
||||||
db_instance: db_archives,
|
db_instance: db_archives,
|
||||||
table_name: 'content',
|
table_name: 'content',
|
||||||
@@ -162,15 +166,19 @@ export async function create_ae_obj__archive_content({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_ArchiveContent | null> {
|
}): Promise<ae_ArchiveContent | null> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** create_ae_obj__archive_content() *** archive_id=${archive_id}`);
|
console.log(
|
||||||
|
`*** create_ae_obj__archive_content() *** archive_id=${archive_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!archive_id) {
|
if (!archive_id) {
|
||||||
console.log(`ERROR: Archives - Content - archive_id required to create`);
|
console.log(
|
||||||
|
`ERROR: Archives - Content - archive_id required to create`
|
||||||
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await api.create_nested_obj_v3({
|
const result = await api.create_nested_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
parent_type: 'archive',
|
parent_type: 'archive',
|
||||||
parent_id: archive_id,
|
parent_id: archive_id,
|
||||||
@@ -219,7 +227,7 @@ export async function delete_ae_obj_id__archive_content({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await api.delete_ae_obj_v3({
|
const result = await api.delete_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'archive_content',
|
obj_type: 'archive_content',
|
||||||
obj_id: archive_content_id,
|
obj_id: archive_content_id,
|
||||||
@@ -258,7 +266,7 @@ export async function update_ae_obj__archive_content({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await api.update_ae_obj_v3({
|
const result = await api.update_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'archive_content',
|
obj_type: 'archive_content',
|
||||||
obj_id: archive_content_id,
|
obj_id: archive_content_id,
|
||||||
@@ -357,11 +365,15 @@ async function _process_generic_props<T extends Record<string, any>>({
|
|||||||
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
||||||
const name = processed_obj.name ?? '';
|
const name = processed_obj.name ?? '';
|
||||||
|
|
||||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
(processed_obj as any).tmp_sort_1 =
|
||||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
`${group}_${priority}_${sort}_${updated}`;
|
||||||
|
(processed_obj as any).tmp_sort_2 =
|
||||||
|
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||||
|
|
||||||
if (specific_processor) {
|
if (specific_processor) {
|
||||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
processed_obj = await Promise.resolve(
|
||||||
|
specific_processor(processed_obj)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
processed_obj_li.push(processed_obj as T);
|
processed_obj_li.push(processed_obj as T);
|
||||||
|
|||||||
@@ -14,14 +14,14 @@ import type { key_val } from '$lib/stores/ae_stores';
|
|||||||
*/
|
*/
|
||||||
export interface Archive {
|
export interface Archive {
|
||||||
id: string;
|
id: string;
|
||||||
// id_random: string;
|
// id_random: string; // NO LONGER USE "_random"
|
||||||
archive_id: string;
|
archive_id: string;
|
||||||
// archive_id_random: string;
|
// archive_id_random: string; // NO LONGER USE "_random"
|
||||||
|
|
||||||
code?: null | string;
|
code?: null | string;
|
||||||
|
|
||||||
account_id: string;
|
account_id: string;
|
||||||
// account_id_random: string;
|
// account_id_random: string; // NO LONGER USE "_random"
|
||||||
|
|
||||||
// archive_type: string;
|
// archive_type: string;
|
||||||
|
|
||||||
@@ -80,12 +80,12 @@ export interface Archive {
|
|||||||
*/
|
*/
|
||||||
export interface Archive_Content {
|
export interface Archive_Content {
|
||||||
id: string;
|
id: string;
|
||||||
// id_random: string;
|
// id_random: string; // NO LONGER USE "_random"
|
||||||
archive_content_id: string;
|
archive_content_id: string;
|
||||||
// archive_content_id_random: string;
|
// archive_content_id_random: string; // NO LONGER USE "_random"
|
||||||
|
|
||||||
archive_id: string;
|
archive_id: string;
|
||||||
// archive_id_random: string;
|
// archive_id_random: string; // NO LONGER USE "_random"
|
||||||
|
|
||||||
archive_content_type: string;
|
archive_content_type: string;
|
||||||
|
|
||||||
@@ -169,10 +169,6 @@ export class MySubClassedDexie extends Dexie {
|
|||||||
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,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,188 +1,191 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
// Imports
|
// Imports
|
||||||
// Import components and elements
|
// Import components and elements
|
||||||
// import Element_input_files_tbl from '$lib/element_input_files_tbl.svelte';
|
// import Element_input_files_tbl from '$lib/element_input_files_tbl.svelte';
|
||||||
|
|
||||||
// Import storage, functions, and libraries
|
// Import storage, functions, and libraries
|
||||||
import type { key_val } from '$lib/stores/ae_stores';
|
import type { key_val } from '$lib/stores/ae_stores';
|
||||||
|
|
||||||
import { api } from '$lib/api/api';
|
import { api } from '$lib/api/api';
|
||||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||||
import {
|
import {
|
||||||
ae_snip,
|
ae_snip,
|
||||||
ae_loc,
|
ae_loc,
|
||||||
ae_sess,
|
ae_sess,
|
||||||
ae_api,
|
ae_api,
|
||||||
ae_trig,
|
ae_trig,
|
||||||
slct,
|
slct,
|
||||||
slct_trigger
|
slct_trigger
|
||||||
} from '$lib/stores/ae_stores';
|
} from '$lib/stores/ae_stores';
|
||||||
|
|
||||||
import AE_Comp_Hosted_Files_Download_Button from '$lib/ae_core/ae_comp__hosted_files_download_button.svelte';
|
import AE_Comp_Hosted_Files_Download_Button from '$lib/ae_core/ae_comp__hosted_files_download_button.svelte';
|
||||||
import { Check, Download, LoaderCircle, MinusCircle, Scissors } from '@lucide/svelte';
|
import {
|
||||||
// Exports
|
Check,
|
||||||
|
Download,
|
||||||
|
LoaderCircle,
|
||||||
|
MinusCircle,
|
||||||
|
Scissors
|
||||||
|
} from '@lucide/svelte';
|
||||||
|
// Exports
|
||||||
|
|
||||||
// export let input_name = 'file_list';
|
// export let input_name = 'file_list';
|
||||||
// export let multiple: boolean = true;
|
// export let multiple: boolean = true;
|
||||||
// export let required: boolean = true;
|
// export let required: boolean = true;
|
||||||
|
|
||||||
// export let input_class_li: string[] = ['file_drop_area'];
|
// export let input_class_li: string[] = ['file_drop_area'];
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
// Expecting these for link_to_type: 'event', 'event_location', 'archive_content', etc
|
// Expecting these for link_to_type: 'event', 'event_location', 'archive_content', etc
|
||||||
link_to_type: string;
|
link_to_type: string;
|
||||||
link_to_id: 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';
|
// 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_default?: string;
|
||||||
class_li?: string;
|
class_li?: string;
|
||||||
// export let table_class_li: string[] = ['table', 'table-sm', 'table-striped', 'table-hover' , 'text-sm'];
|
// export let table_class_li: string[] = ['table', 'table-sm', 'table-striped', 'table-hover' , 'text-sm'];
|
||||||
clip_complete?: boolean;
|
clip_complete?: boolean;
|
||||||
// export let upload_complete: boolean = false;
|
// export let upload_complete: boolean = false;
|
||||||
submit_status?: null | string;
|
submit_status?: null | string;
|
||||||
// hosted_file_id_li?: string[];
|
// hosted_file_id_li?: string[];
|
||||||
// hosted_file_obj_li?: any[];
|
// hosted_file_obj_li?: any[];
|
||||||
hosted_file_obj_kv?: key_val;
|
hosted_file_obj_kv?: key_val;
|
||||||
video_clip_file_kv?: key_val;
|
video_clip_file_kv?: key_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
let {
|
let {
|
||||||
log_lvl = $bindable(0),
|
log_lvl = $bindable(0),
|
||||||
link_to_type = $bindable(),
|
link_to_type = $bindable(),
|
||||||
link_to_id = $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_default = 'flex flex-col gap-1 items-center justify-center w-full max-w-2xl mx-auto my-1',
|
||||||
class_li = $bindable(''),
|
class_li = $bindable(''),
|
||||||
clip_complete = $bindable(false),
|
clip_complete = $bindable(false),
|
||||||
submit_status = $bindable(null),
|
submit_status = $bindable(null),
|
||||||
// hosted_file_id_li = [],
|
// hosted_file_id_li = [],
|
||||||
// hosted_file_obj_li = [],
|
// hosted_file_obj_li = [],
|
||||||
hosted_file_obj_kv = $bindable({}),
|
hosted_file_obj_kv = $bindable({}),
|
||||||
video_clip_file_kv = $bindable({})
|
video_clip_file_kv = $bindable({})
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
|
|
||||||
// Local Variables
|
// Local Variables
|
||||||
let task_id = link_to_id;
|
let task_id = link_to_id;
|
||||||
// let input_file_list: any = null;
|
// let input_file_list: any = null;
|
||||||
let ae_promises: key_val = $state({});
|
let ae_promises: key_val = $state({});
|
||||||
// let ae_promises_clipping: key_val = {};
|
// let ae_promises_clipping: key_val = {};
|
||||||
// let ae_triggers: key_val = {};
|
// let ae_triggers: key_val = {};
|
||||||
|
|
||||||
// let input_element_id = 'ae_comp__hosted_files_upload__input';
|
// let input_element_id = 'ae_comp__hosted_files_upload__input';
|
||||||
|
|
||||||
// let form_kv: key_val = {
|
// let form_kv: key_val = {
|
||||||
// start_time: null,
|
// start_time: null,
|
||||||
// end_time: null,
|
// end_time: null,
|
||||||
// reencode: null,
|
// reencode: null,
|
||||||
// video_file: null,
|
// video_file: null,
|
||||||
// };
|
// };
|
||||||
// let download_clip_src: string;
|
// let download_clip_src: string;
|
||||||
// let download_clip_filename: string;
|
// let download_clip_filename: string;
|
||||||
|
|
||||||
$ae_sess.files.obj = {
|
$ae_sess.files.obj = {
|
||||||
obj: null
|
obj: null
|
||||||
|
};
|
||||||
|
|
||||||
|
// *** Functions and Logic
|
||||||
|
function prevent_default<T extends Event>(fn: (event: T) => void) {
|
||||||
|
return function (event: T) {
|
||||||
|
event.preventDefault();
|
||||||
|
fn(event);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function handle_clip_video(event: Event) {
|
||||||
|
console.log('*** handle_clip_video() ***');
|
||||||
|
|
||||||
|
submit_status = 'clipping';
|
||||||
|
clip_complete = false;
|
||||||
|
|
||||||
|
const form = event.target as HTMLFormElement;
|
||||||
|
const formData = new FormData(form);
|
||||||
|
|
||||||
|
let hosted_file_id = formData.get('hosted_file_id') as string;
|
||||||
|
let start_time = formData.get('start_time') as string;
|
||||||
|
let end_time = formData.get('end_time') as string;
|
||||||
|
let reencode = formData.get('reencode') as string;
|
||||||
|
let scale_down = formData.get('scale_down') as string;
|
||||||
|
let new_filename = formData.get('new_filename') as string;
|
||||||
|
|
||||||
|
$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 = start_time;
|
||||||
|
$ae_loc.files.processed_file_kv[hosted_file_id].end_time = end_time;
|
||||||
|
$ae_loc.files.processed_file_kv[hosted_file_id].reencode = reencode;
|
||||||
|
$ae_loc.files.processed_file_kv[hosted_file_id].scale_down = scale_down;
|
||||||
|
$ae_loc.files.processed_file_kv[hosted_file_id].new_filename = new_filename;
|
||||||
|
$ae_loc.files.processed_file_kv[hosted_file_id].clip_complete = false;
|
||||||
|
|
||||||
|
let endpoint = `/v3/action/hosted_file/${hosted_file_id}/clip_video`;
|
||||||
|
|
||||||
|
let params = {
|
||||||
|
link_to_type: link_to_type,
|
||||||
|
link_to_id: link_to_id,
|
||||||
|
filename_no_ext: new_filename.replace('.mp4', ''),
|
||||||
|
from_type: 'mp4', // Video file type being converted
|
||||||
|
to_type: 'mp4', // Video file type to convert to
|
||||||
|
start_time: start_time,
|
||||||
|
end_time: end_time,
|
||||||
|
reencode: reencode,
|
||||||
|
scale_down: scale_down
|
||||||
};
|
};
|
||||||
|
|
||||||
// *** Functions and Logic
|
ae_promises[hosted_file_id] = {};
|
||||||
function prevent_default<T extends Event>(fn: (event: T) => void) {
|
// .convert__hosted_file_obj
|
||||||
return function (event: T) {
|
ae_promises[hosted_file_id] = api
|
||||||
event.preventDefault();
|
.get_object({
|
||||||
fn(event);
|
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);
|
||||||
|
|
||||||
function handle_clip_video(event: Event) {
|
video_clip_file_kv[result.hosted_file_id] = {};
|
||||||
console.log('*** handle_clip_video() ***');
|
video_clip_file_kv[result.hosted_file_id] = result;
|
||||||
|
|
||||||
submit_status = 'clipping';
|
// $ae_loc.files.video_clip_file_kv[result.hosted_file_id] = {};
|
||||||
clip_complete = false;
|
// $ae_loc.files.video_clip_file_kv[result.hosted_file_id] = result;
|
||||||
|
|
||||||
const form = event.target as HTMLFormElement;
|
$ae_sess.files.processed_file_kv[hosted_file_id].submit_status =
|
||||||
const formData = new FormData(form);
|
'clipped';
|
||||||
|
$ae_sess.files.processed_file_kv[hosted_file_id].clip_complete =
|
||||||
|
true;
|
||||||
|
|
||||||
let hosted_file_id = formData.get('hosted_file_id') as string;
|
$ae_loc.files.processed_file_kv[hosted_file_id].submit_status =
|
||||||
let start_time = formData.get('start_time') as string;
|
'clipped';
|
||||||
let end_time = formData.get('end_time') as string;
|
$ae_loc.files.processed_file_kv[hosted_file_id].clip_complete =
|
||||||
let reencode = formData.get('reencode') as string;
|
true;
|
||||||
let scale_down = formData.get('scale_down') as string;
|
|
||||||
let new_filename = formData.get('new_filename') as string;
|
|
||||||
|
|
||||||
$ae_sess.files.processed_file_kv[hosted_file_id] = {};
|
submit_status = 'clipped';
|
||||||
$ae_sess.files.processed_file_kv[hosted_file_id].submit_status =
|
clip_complete = true;
|
||||||
'clipping';
|
|
||||||
$ae_sess.files.processed_file_kv[hosted_file_id].clip_complete = false;
|
|
||||||
|
|
||||||
// $ae_sess.files.disable_submit__hosted_file_obj = true;
|
// let file_blob = new Blob([result.data]);
|
||||||
$ae_loc.files.processed_file_kv[hosted_file_id] = {};
|
// // console.log(file_blob);
|
||||||
$ae_loc.files.processed_file_kv[hosted_file_id].submit_status =
|
// let file_obj_url = window.URL.createObjectURL(file_blob); // The img src
|
||||||
'clipping';
|
// // const url = window.URL.createObjectURL(new Blob([result.data]));
|
||||||
$ae_loc.files.processed_file_kv[hosted_file_id].start_time = start_time;
|
// download_clip_src = file_obj_url;
|
||||||
$ae_loc.files.processed_file_kv[hosted_file_id].end_time = end_time;
|
// // download_filename = file_obj_url;
|
||||||
$ae_loc.files.processed_file_kv[hosted_file_id].reencode = reencode;
|
|
||||||
$ae_loc.files.processed_file_kv[hosted_file_id].scale_down = scale_down;
|
|
||||||
$ae_loc.files.processed_file_kv[hosted_file_id].new_filename =
|
|
||||||
new_filename;
|
|
||||||
$ae_loc.files.processed_file_kv[hosted_file_id].clip_complete = false;
|
|
||||||
|
|
||||||
let endpoint = `/hosted_file/${hosted_file_id}/clip_video`;
|
return true;
|
||||||
|
});
|
||||||
let params = {
|
}
|
||||||
link_to_type: link_to_type,
|
|
||||||
link_to_id: link_to_id,
|
|
||||||
filename_no_ext: new_filename.replace('.mp4', ''),
|
|
||||||
from_type: 'mp4', // Video file type being converted
|
|
||||||
to_type: 'mp4', // Video file type to convert to
|
|
||||||
start_time: start_time,
|
|
||||||
end_time: end_time,
|
|
||||||
reencode: reencode,
|
|
||||||
scale_down: scale_down
|
|
||||||
};
|
|
||||||
|
|
||||||
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] = {};
|
|
||||||
video_clip_file_kv[result.hosted_file_id] = result;
|
|
||||||
|
|
||||||
// $ae_loc.files.video_clip_file_kv[result.hosted_file_id] = {};
|
|
||||||
// $ae_loc.files.video_clip_file_kv[result.hosted_file_id] = 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>
|
</script>
|
||||||
|
|
||||||
<section class="{class_li_default} {class_li}">
|
<section class="{class_li_default} {class_li}">
|
||||||
@@ -191,11 +194,11 @@
|
|||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
{#each Object.entries(hosted_file_obj_kv) as [hosted_file_id, hosted_file_obj] (hosted_file_id)}
|
{#each Object.entries(hosted_file_obj_kv) as [hosted_file_id, hosted_file_obj] (hosted_file_id)}
|
||||||
<div class="border border-surface-500/20 rounded-lg p-2 m-2 preset-tonal-surface">
|
<div
|
||||||
|
class="border-surface-500/20 preset-tonal-surface m-2 rounded-lg border p-2">
|
||||||
<!-- Download Button (Standardized) -->
|
<!-- Download Button (Standardized) -->
|
||||||
<div
|
<div
|
||||||
class="flex flex-row flex-wrap gap-1 justify-center items-center w-full"
|
class="flex w-full flex-row flex-wrap items-center justify-center gap-1">
|
||||||
>
|
|
||||||
<!-- Remove from uploaded file kv list -->
|
<!-- Remove from uploaded file kv list -->
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -219,8 +222,7 @@
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
class="btn btn-sm preset-tonal-warning hover:preset-filled-warning-500"
|
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}`}
|
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}`}>
|
||||||
>
|
|
||||||
<MinusCircle size="1em" class="m-1" />
|
<MinusCircle size="1em" class="m-1" />
|
||||||
<span class="">Remove</span>
|
<span class="">Remove</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -234,60 +236,49 @@
|
|||||||
variant="tonal"
|
variant="tonal"
|
||||||
classes="novi_btn btn-sm lg:btn-md min-w-72 lg:min-w-96 !justify-start"
|
classes="novi_btn btn-sm lg:btn-md min-w-72 lg:min-w-96 !justify-start"
|
||||||
show_divider={true}
|
show_divider={true}
|
||||||
max_filename={30}
|
max_filename={30} />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
>{ae_util.shorten_filename({
|
>{ae_util.shorten_filename({
|
||||||
filename: hosted_file_obj?.filename,
|
filename: hosted_file_obj?.filename,
|
||||||
max_length: 30
|
max_length: 30
|
||||||
})}</span
|
})}</span>
|
||||||
>
|
|
||||||
<span>
|
<span>
|
||||||
<span class="text-sm font-bold"> File ID: </span>
|
<span class="text-sm font-bold"> File ID: </span>
|
||||||
{hosted_file_obj.hosted_file_id}</span
|
{hosted_file_obj.hosted_file_id}</span>
|
||||||
>
|
|
||||||
<span>
|
<span>
|
||||||
<span class="text-sm font-bold"> Type: </span>
|
<span class="text-sm font-bold"> Type: </span>
|
||||||
{hosted_file_obj.extension}</span
|
{hosted_file_obj.extension}</span>
|
||||||
>
|
|
||||||
<!-- <span>{hosted_file_obj.filename}</span> -->
|
<!-- <span>{hosted_file_obj.filename}</span> -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form
|
<form
|
||||||
onsubmit={prevent_default(handle_clip_video)}
|
onsubmit={prevent_default(handle_clip_video)}
|
||||||
class="{class_li_default} {class_li}"
|
class="{class_li_default} {class_li}">
|
||||||
>
|
|
||||||
<!-- {$ae_sess?.files[hosted_file_obj?.hosted_file_id ?? 'obj'].submit_status ?? 'not set'} -->
|
<!-- {$ae_sess?.files[hosted_file_obj?.hosted_file_id ?? 'obj'].submit_status ?? 'not set'} -->
|
||||||
|
|
||||||
<input
|
<input
|
||||||
type="hidden"
|
type="hidden"
|
||||||
name="hosted_file_id"
|
name="hosted_file_id"
|
||||||
value={hosted_file_obj.hosted_file_id}
|
value={hosted_file_obj.hosted_file_id} />
|
||||||
/>
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="flex flex-row gap-1 justify-center items-center w-full"
|
class="flex w-full flex-row items-center justify-center gap-1">
|
||||||
>
|
<span class="w-32 text-xs font-bold">New Filename:</span>
|
||||||
<span class="text-xs font-bold w-32">New Filename:</span>
|
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
class="input w-full text-sm variant-filled-surface"
|
class="input variant-filled-surface w-full text-sm"
|
||||||
name="new_filename"
|
name="new_filename"
|
||||||
value={hosted_file_obj.filename}
|
value={hosted_file_obj.filename} />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="max-w-(--breakpoint-sm) flex flex-row gap-1 justify-center items-center w-full"
|
class="flex w-full max-w-(--breakpoint-sm) flex-row items-center justify-center gap-1">
|
||||||
>
|
|
||||||
<label
|
<label
|
||||||
class="label w-48"
|
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."
|
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"
|
<span class="text-xs font-bold"
|
||||||
>Start time (HH:MM:SS)</span
|
>Start time (HH:MM:SS)</span>
|
||||||
>
|
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="start_time"
|
name="start_time"
|
||||||
@@ -300,17 +291,14 @@
|
|||||||
].start_time
|
].start_time
|
||||||
: '00:00:00'}
|
: '00:00:00'}
|
||||||
placeholder="HH:MM:SS (00:01:30)"
|
placeholder="HH:MM:SS (00:01:30)"
|
||||||
class="input w-32 variant-filled-surface"
|
class="input variant-filled-surface w-32" />
|
||||||
/>
|
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label
|
<label
|
||||||
class="label w-48"
|
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."
|
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"
|
<span class="text-xs font-bold"
|
||||||
>End time (HH:MM:SS)</span
|
>End time (HH:MM:SS)</span>
|
||||||
>
|
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="end_time"
|
name="end_time"
|
||||||
@@ -323,14 +311,12 @@
|
|||||||
].end_time
|
].end_time
|
||||||
: '00:45:59'}
|
: '00:45:59'}
|
||||||
placeholder="HH:MM:SS (01:05:25)"
|
placeholder="HH:MM:SS (01:05:25)"
|
||||||
class="input w-32 variant-filled-surface"
|
class="input variant-filled-surface w-32" />
|
||||||
/>
|
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<span
|
<span
|
||||||
class="flex flex-col gap-1 items-center justify-center"
|
class="flex flex-col items-center justify-center gap-1"
|
||||||
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."
|
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>
|
<span class="text-xs font-bold"> Re-encode? </span>
|
||||||
<label class="inline-block">
|
<label class="inline-block">
|
||||||
<input
|
<input
|
||||||
@@ -338,8 +324,7 @@
|
|||||||
name="reencode"
|
name="reencode"
|
||||||
value="true"
|
value="true"
|
||||||
class="radio"
|
class="radio"
|
||||||
checked
|
checked />
|
||||||
/>
|
|
||||||
True
|
True
|
||||||
</label>
|
</label>
|
||||||
<label class="inline-block">
|
<label class="inline-block">
|
||||||
@@ -347,16 +332,14 @@
|
|||||||
type="radio"
|
type="radio"
|
||||||
name="reencode"
|
name="reencode"
|
||||||
value="false"
|
value="false"
|
||||||
class="radio"
|
class="radio" />
|
||||||
/>
|
|
||||||
False
|
False
|
||||||
</label>
|
</label>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span
|
<span
|
||||||
class="flex flex-col gap-1 items-center justify-center"
|
class="flex flex-col items-center justify-center gap-1"
|
||||||
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."
|
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>
|
<span class="text-xs font-bold"> Scale down? </span>
|
||||||
<label class="inline-block">
|
<label class="inline-block">
|
||||||
<input
|
<input
|
||||||
@@ -364,8 +347,7 @@
|
|||||||
name="scale_down"
|
name="scale_down"
|
||||||
value="true"
|
value="true"
|
||||||
class="radio"
|
class="radio"
|
||||||
checked
|
checked />
|
||||||
/>
|
|
||||||
True
|
True
|
||||||
</label>
|
</label>
|
||||||
<label class="inline-block">
|
<label class="inline-block">
|
||||||
@@ -373,8 +355,7 @@
|
|||||||
type="radio"
|
type="radio"
|
||||||
name="scale_down"
|
name="scale_down"
|
||||||
value="false"
|
value="false"
|
||||||
class="radio"
|
class="radio" />
|
||||||
/>
|
|
||||||
False
|
False
|
||||||
</label>
|
</label>
|
||||||
</span>
|
</span>
|
||||||
@@ -382,9 +363,8 @@
|
|||||||
|
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
class="btn btn-lg btn-primary preset-tonal-primary border border-primary-500 hover:preset-filled-primary-500 transition-colors"
|
class="btn btn-lg btn-primary preset-tonal-primary border-primary-500 hover:preset-filled-primary-500 border transition-colors"
|
||||||
disabled={submit_status == 'clipping'}
|
disabled={submit_status == 'clipping'}>
|
||||||
>
|
|
||||||
<!-- {#await ae_promises[hosted_file_id]} -->
|
<!-- {#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'}
|
{#if $ae_loc.files.processed_file_kv[hosted_file_id] && $ae_loc.files.processed_file_kv[hosted_file_id].submit_status == 'clipping'}
|
||||||
<LoaderCircle size="1em" class="m-1 animate-spin" />
|
<LoaderCircle size="1em" class="m-1 animate-spin" />
|
||||||
@@ -407,8 +387,7 @@
|
|||||||
{#await ae_promises[hosted_file_id]}
|
{#await ae_promises[hosted_file_id]}
|
||||||
<LoaderCircle size="1em" class="m-1 animate-spin" />
|
<LoaderCircle size="1em" class="m-1 animate-spin" />
|
||||||
<span class="highlight"
|
<span class="highlight"
|
||||||
>Processing... This may take a few minutes.</span
|
>Processing... This may take a few minutes.</span>
|
||||||
>
|
|
||||||
{:then}
|
{:then}
|
||||||
{#if ae_promises[hosted_file_id]}
|
{#if ae_promises[hosted_file_id]}
|
||||||
<Download size="1em" /> Ready to download below!
|
<Download size="1em" /> Ready to download below!
|
||||||
|
|||||||
@@ -1,48 +1,48 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
// Imports
|
// Imports
|
||||||
// Import components and elements
|
// Import components and elements
|
||||||
import AE_Comp_Hosted_Files_Download_Button from '$lib/ae_core/ae_comp__hosted_files_download_button.svelte';
|
import AE_Comp_Hosted_Files_Download_Button from '$lib/ae_core/ae_comp__hosted_files_download_button.svelte';
|
||||||
|
|
||||||
// Import storage, functions, and libraries
|
// Import storage, functions, and libraries
|
||||||
import type { key_val } from '$lib/stores/ae_stores';
|
import type { key_val } from '$lib/stores/ae_stores';
|
||||||
|
|
||||||
import { api } from '$lib/api/api';
|
import { api } from '$lib/api/api';
|
||||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||||
import {
|
import {
|
||||||
ae_snip,
|
ae_snip,
|
||||||
ae_loc,
|
ae_loc,
|
||||||
ae_sess,
|
ae_sess,
|
||||||
ae_api,
|
ae_api,
|
||||||
ae_trig,
|
ae_trig,
|
||||||
slct,
|
slct,
|
||||||
slct_trigger
|
slct_trigger
|
||||||
} from '$lib/stores/ae_stores';
|
} from '$lib/stores/ae_stores';
|
||||||
|
|
||||||
// Exports
|
// Exports
|
||||||
|
|
||||||
// export let hosted_file_id_li: string[] = [];
|
// export let hosted_file_id_li: string[] = [];
|
||||||
// export let hosted_file_obj_li: any[] = [];
|
// export let hosted_file_obj_li: any[] = [];
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
// export let hosted_file_obj_kv: key_val = {};
|
// export let hosted_file_obj_kv: key_val = {};
|
||||||
video_clip_file_kv?: key_val;
|
video_clip_file_kv?: key_val;
|
||||||
class_li_default?: string;
|
class_li_default?: string;
|
||||||
class_li?: string;
|
class_li?: string;
|
||||||
link_to_type: string;
|
link_to_type: string;
|
||||||
link_to_id: string;
|
link_to_id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
let {
|
let {
|
||||||
log_lvl = 0,
|
log_lvl = 0,
|
||||||
video_clip_file_kv = $bindable({}),
|
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-surface-500/20 rounded-lg preset-tonal-surface',
|
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-surface-500/20 rounded-lg preset-tonal-surface',
|
||||||
class_li = '',
|
class_li = '',
|
||||||
link_to_type,
|
link_to_type,
|
||||||
link_to_id
|
link_to_id
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
|
|
||||||
let ae_promises: key_val = $state({});
|
let ae_promises: key_val = $state({});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<h3 class="h3">{Object.entries(video_clip_file_kv).length}× files clipped</h3>
|
<h3 class="h3">{Object.entries(video_clip_file_kv).length}× files clipped</h3>
|
||||||
@@ -54,7 +54,6 @@
|
|||||||
max_filename={30}
|
max_filename={30}
|
||||||
classes="btn btn-sm lg:btn-md preset-tonal-primary hover:preset-filled-primary-500 min-w-72 lg:min-w-96"
|
classes="btn btn-sm lg:btn-md preset-tonal-primary hover:preset-filled-primary-500 min-w-72 lg:min-w-96"
|
||||||
linked_to_type={link_to_type}
|
linked_to_type={link_to_type}
|
||||||
linked_to_id={link_to_id}
|
linked_to_id={link_to_id} />
|
||||||
/>
|
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,243 +1,275 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
// *** Import Svelte specific
|
// *** Import Svelte specific
|
||||||
import * as Lucide from 'lucide-svelte';
|
import * as Lucide from 'lucide-svelte';
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
|
|
||||||
// *** Import Aether specific variables and functions
|
// *** Import Aether specific variables and functions
|
||||||
import type { key_val } from '$lib/stores/ae_stores';
|
import type { key_val } from '$lib/stores/ae_stores';
|
||||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||||
import { download_ae_obj_id__hosted_file } from '$lib/ae_core/core__hosted_files';
|
import { download_ae_obj_id__hosted_file } from '$lib/ae_core/core__hosted_files';
|
||||||
import {
|
import { ae_loc, ae_sess, ae_api } from '$lib/stores/ae_stores';
|
||||||
ae_loc,
|
|
||||||
ae_sess,
|
|
||||||
ae_api
|
|
||||||
} from '$lib/stores/ae_stores';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
hosted_file_id: null | string;
|
hosted_file_id: null | string;
|
||||||
hosted_file_obj: null | key_val;
|
hosted_file_obj: null | key_val;
|
||||||
filename?: null | string;
|
filename?: null | string;
|
||||||
max_filename?: number;
|
max_filename?: number;
|
||||||
auto_download?: boolean;
|
auto_download?: boolean;
|
||||||
linked_to_type?: null | string;
|
linked_to_type?: null | string;
|
||||||
linked_to_id?: null | string;
|
linked_to_id?: null | string;
|
||||||
download_complete?: null | boolean;
|
download_complete?: null | boolean;
|
||||||
download_percent?: number;
|
download_percent?: number;
|
||||||
download_status_msg?: string;
|
download_status_msg?: string;
|
||||||
variant?: 'tonal' | 'filled' | 'outline' | 'ghost';
|
variant?: 'tonal' | 'filled' | 'outline' | 'ghost';
|
||||||
color?: 'primary' | 'secondary' | 'tertiary' | 'success' | 'warning' | 'error' | 'surface';
|
color?:
|
||||||
show_divider?: boolean;
|
| 'primary'
|
||||||
show_direct_download?: boolean;
|
| 'secondary'
|
||||||
require_auth?: boolean;
|
| 'tertiary'
|
||||||
classes?: string;
|
| 'success'
|
||||||
click?: () => void | Promise<any>;
|
| 'warning'
|
||||||
label?: import('svelte').Snippet;
|
| 'error'
|
||||||
|
| 'surface';
|
||||||
|
show_divider?: boolean;
|
||||||
|
show_direct_download?: boolean;
|
||||||
|
require_auth?: boolean;
|
||||||
|
classes?: string;
|
||||||
|
click?: () => void | Promise<any>;
|
||||||
|
label?: import('svelte').Snippet;
|
||||||
|
}
|
||||||
|
|
||||||
|
let {
|
||||||
|
log_lvl = 0,
|
||||||
|
hosted_file_id,
|
||||||
|
hosted_file_obj,
|
||||||
|
filename = $bindable(null),
|
||||||
|
max_filename = $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'),
|
||||||
|
variant = 'tonal',
|
||||||
|
color = 'primary',
|
||||||
|
show_divider = true,
|
||||||
|
show_direct_download = false,
|
||||||
|
require_auth = true,
|
||||||
|
classes = '',
|
||||||
|
click,
|
||||||
|
label
|
||||||
|
}: Props = $props();
|
||||||
|
|
||||||
|
// Map variant/color to classes using literal strings so Tailwind can find them
|
||||||
|
const color_map: Record<string, Record<string, string>> = {
|
||||||
|
primary: {
|
||||||
|
tonal: 'preset-tonal-primary border border-primary-500/30 hover:preset-filled-primary-500',
|
||||||
|
filled: 'preset-filled-primary-500 hover:preset-filled-primary-600',
|
||||||
|
outline: 'border border-primary-500 hover:preset-tonal-primary',
|
||||||
|
ghost: 'hover:preset-tonal-primary'
|
||||||
|
},
|
||||||
|
secondary: {
|
||||||
|
tonal: 'preset-tonal-secondary border border-secondary-500/30 hover:preset-filled-secondary-500',
|
||||||
|
filled: 'preset-filled-secondary-500 hover:preset-filled-secondary-600',
|
||||||
|
outline: 'border border-secondary-500 hover:preset-tonal-secondary',
|
||||||
|
ghost: 'hover:preset-tonal-secondary'
|
||||||
|
},
|
||||||
|
tertiary: {
|
||||||
|
tonal: 'preset-tonal-tertiary border border-tertiary-500/30 hover:preset-filled-tertiary-500',
|
||||||
|
filled: 'preset-filled-tertiary-500 hover:preset-filled-tertiary-600',
|
||||||
|
outline: 'border border-tertiary-500 hover:preset-tonal-tertiary',
|
||||||
|
ghost: 'hover:preset-tonal-tertiary'
|
||||||
|
},
|
||||||
|
success: {
|
||||||
|
tonal: 'preset-tonal-success border border-success-500/30 hover:preset-filled-success-500',
|
||||||
|
filled: 'preset-filled-success-500 hover:preset-filled-success-600',
|
||||||
|
outline: 'border border-success-500 hover:preset-tonal-success',
|
||||||
|
ghost: 'hover:preset-tonal-success'
|
||||||
|
},
|
||||||
|
warning: {
|
||||||
|
tonal: 'preset-tonal-warning border border-warning-500/30 hover:preset-filled-warning-500',
|
||||||
|
filled: 'preset-filled-warning-500 hover:preset-filled-warning-600',
|
||||||
|
outline: 'border border-warning-500 hover:preset-tonal-warning',
|
||||||
|
ghost: 'hover:preset-tonal-warning'
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
tonal: 'preset-tonal-error border border-error-500/30 hover:preset-filled-error-500',
|
||||||
|
filled: 'preset-filled-error-500 hover:preset-filled-error-600',
|
||||||
|
outline: 'border border-error-500 hover:preset-tonal-error',
|
||||||
|
ghost: 'hover:preset-tonal-error'
|
||||||
|
},
|
||||||
|
surface: {
|
||||||
|
tonal: 'preset-tonal-surface border border-surface-500/30 hover:preset-filled-surface-500',
|
||||||
|
filled: 'preset-filled-surface-500 hover:preset-filled-surface-600',
|
||||||
|
outline: 'border border-surface-500 hover:preset-tonal-surface',
|
||||||
|
ghost: 'hover:preset-tonal-surface'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let variant_classes = $derived.by(() => {
|
||||||
|
const base =
|
||||||
|
'btn btn-sm lg:btn-md min-w-48 transition-all overflow-hidden px-3';
|
||||||
|
const style = color_map[color]?.[variant] || color_map.primary.tonal;
|
||||||
|
return `${base} ${style} ${classes}`.trim();
|
||||||
|
});
|
||||||
|
|
||||||
|
let show_filename_view = $state(true);
|
||||||
|
let status_interval: any;
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
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(() => {
|
||||||
|
const file_id =
|
||||||
|
hosted_file_obj?.id ||
|
||||||
|
hosted_file_obj?.hosted_file_id ||
|
||||||
|
hosted_file_id;
|
||||||
|
if (file_id && $ae_sess?.api_download_kv[file_id]?.percent_completed) {
|
||||||
|
download_percent = $ae_sess.api_download_kv[file_id].percent_completed;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Reactive timer to alternate views during active download
|
||||||
|
$effect(() => {
|
||||||
|
const file_id =
|
||||||
|
hosted_file_obj?.id ||
|
||||||
|
hosted_file_obj?.hosted_file_id ||
|
||||||
|
hosted_file_id;
|
||||||
|
const is_actively_downloading =
|
||||||
|
ae_promises[file_id] && download_complete === undefined;
|
||||||
|
|
||||||
|
if (is_actively_downloading) {
|
||||||
|
if (!status_interval) {
|
||||||
|
status_interval = setInterval(() => {
|
||||||
|
show_filename_view = !show_filename_view;
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (status_interval) {
|
||||||
|
clearInterval(status_interval);
|
||||||
|
status_interval = null;
|
||||||
|
}
|
||||||
|
show_filename_view = true; // Default view when not downloading
|
||||||
}
|
}
|
||||||
|
|
||||||
let {
|
return () => {
|
||||||
log_lvl = 0,
|
if (status_interval) {
|
||||||
hosted_file_id,
|
clearInterval(status_interval);
|
||||||
hosted_file_obj,
|
status_interval = null;
|
||||||
filename = $bindable(null),
|
|
||||||
max_filename = $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'),
|
|
||||||
variant = 'tonal',
|
|
||||||
color = 'primary',
|
|
||||||
show_divider = true,
|
|
||||||
show_direct_download = false,
|
|
||||||
require_auth = true,
|
|
||||||
classes = '',
|
|
||||||
click,
|
|
||||||
label
|
|
||||||
}: Props = $props();
|
|
||||||
|
|
||||||
// Map variant/color to classes using literal strings so Tailwind can find them
|
|
||||||
const color_map: Record<string, Record<string, string>> = {
|
|
||||||
primary: {
|
|
||||||
tonal: 'preset-tonal-primary border border-primary-500/30 hover:preset-filled-primary-500',
|
|
||||||
filled: 'preset-filled-primary-500 hover:preset-filled-primary-600',
|
|
||||||
outline: 'border border-primary-500 hover:preset-tonal-primary',
|
|
||||||
ghost: 'hover:preset-tonal-primary'
|
|
||||||
},
|
|
||||||
secondary: {
|
|
||||||
tonal: 'preset-tonal-secondary border border-secondary-500/30 hover:preset-filled-secondary-500',
|
|
||||||
filled: 'preset-filled-secondary-500 hover:preset-filled-secondary-600',
|
|
||||||
outline: 'border border-secondary-500 hover:preset-tonal-secondary',
|
|
||||||
ghost: 'hover:preset-tonal-secondary'
|
|
||||||
},
|
|
||||||
tertiary: {
|
|
||||||
tonal: 'preset-tonal-tertiary border border-tertiary-500/30 hover:preset-filled-tertiary-500',
|
|
||||||
filled: 'preset-filled-tertiary-500 hover:preset-filled-tertiary-600',
|
|
||||||
outline: 'border border-tertiary-500 hover:preset-tonal-tertiary',
|
|
||||||
ghost: 'hover:preset-tonal-tertiary'
|
|
||||||
},
|
|
||||||
success: {
|
|
||||||
tonal: 'preset-tonal-success border border-success-500/30 hover:preset-filled-success-500',
|
|
||||||
filled: 'preset-filled-success-500 hover:preset-filled-success-600',
|
|
||||||
outline: 'border border-success-500 hover:preset-tonal-success',
|
|
||||||
ghost: 'hover:preset-tonal-success'
|
|
||||||
},
|
|
||||||
warning: {
|
|
||||||
tonal: 'preset-tonal-warning border border-warning-500/30 hover:preset-filled-warning-500',
|
|
||||||
filled: 'preset-filled-warning-500 hover:preset-filled-warning-600',
|
|
||||||
outline: 'border border-warning-500 hover:preset-tonal-warning',
|
|
||||||
ghost: 'hover:preset-tonal-warning'
|
|
||||||
},
|
|
||||||
error: {
|
|
||||||
tonal: 'preset-tonal-error border border-error-500/30 hover:preset-filled-error-500',
|
|
||||||
filled: 'preset-filled-error-500 hover:preset-filled-error-600',
|
|
||||||
outline: 'border border-error-500 hover:preset-tonal-error',
|
|
||||||
ghost: 'hover:preset-tonal-error'
|
|
||||||
},
|
|
||||||
surface: {
|
|
||||||
tonal: 'preset-tonal-surface border border-surface-500/30 hover:preset-filled-surface-500',
|
|
||||||
filled: 'preset-filled-surface-500 hover:preset-filled-surface-600',
|
|
||||||
outline: 'border border-surface-500 hover:preset-tonal-surface',
|
|
||||||
ghost: 'hover:preset-tonal-surface'
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
});
|
||||||
|
|
||||||
let variant_classes = $derived.by(() => {
|
let final_filename = $derived(
|
||||||
const base = 'btn btn-sm lg:btn-md min-w-48 transition-all overflow-hidden px-3';
|
filename ?? hosted_file_obj?.filename ?? 'unknown'
|
||||||
const style = color_map[color]?.[variant] || color_map.primary.tonal;
|
);
|
||||||
return `${base} ${style} ${classes}`.trim();
|
let shortened_filename = $derived(
|
||||||
});
|
ae_util.shorten_filename({
|
||||||
|
|
||||||
let show_filename_view = $state(true);
|
|
||||||
let status_interval: any;
|
|
||||||
|
|
||||||
$effect(() => {
|
|
||||||
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(() => {
|
|
||||||
const file_id = hosted_file_obj?.id || hosted_file_obj?.hosted_file_id || hosted_file_id;
|
|
||||||
if (file_id && $ae_sess?.api_download_kv[file_id]?.percent_completed) {
|
|
||||||
download_percent =
|
|
||||||
$ae_sess.api_download_kv[file_id].percent_completed;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Reactive timer to alternate views during active download
|
|
||||||
$effect(() => {
|
|
||||||
const file_id = hosted_file_obj?.id || hosted_file_obj?.hosted_file_id || hosted_file_id;
|
|
||||||
const is_actively_downloading = ae_promises[file_id] && download_complete === undefined;
|
|
||||||
|
|
||||||
if (is_actively_downloading) {
|
|
||||||
if (!status_interval) {
|
|
||||||
status_interval = setInterval(() => {
|
|
||||||
show_filename_view = !show_filename_view;
|
|
||||||
}, 3000);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (status_interval) {
|
|
||||||
clearInterval(status_interval);
|
|
||||||
status_interval = null;
|
|
||||||
}
|
|
||||||
show_filename_view = true; // Default view when not downloading
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
if (status_interval) {
|
|
||||||
clearInterval(status_interval);
|
|
||||||
status_interval = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
let final_filename = $derived(filename ?? hosted_file_obj?.filename ?? 'unknown');
|
|
||||||
let shortened_filename = $derived(ae_util.shorten_filename({
|
|
||||||
filename: final_filename,
|
filename: final_filename,
|
||||||
max_length: max_filename
|
max_length: max_filename
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
|
|
||||||
let direct_download_url = $derived.by(() => {
|
let direct_download_url = $derived.by(() => {
|
||||||
if (!show_direct_download || !hosted_file_obj) return '';
|
if (!show_direct_download || !hosted_file_obj) return '';
|
||||||
// IMPORTANT: For Direct Link Mode, we MUST use the V3 Action endpoint to support Random String IDs.
|
// IMPORTANT: For Direct Link Mode, we MUST use the V3 Action endpoint to support Random String IDs.
|
||||||
// Legacy endpoints often expect integer IDs and will return 404 for string IDs.
|
// Legacy endpoints often expect integer IDs and will return 404 for string IDs.
|
||||||
const file_id = hosted_file_obj.event_file_id || hosted_file_obj.hosted_file_id || hosted_file_id;
|
const file_id =
|
||||||
const obj_type_path = hosted_file_obj.event_file_id ? 'event_file' : 'hosted_file';
|
hosted_file_obj.event_file_id ||
|
||||||
return `${$ae_api.base_url}/v3/action/${obj_type_path}/${file_id}/download?filename=${ae_util.clean_filename(final_filename)}&key=${$ae_api.account_id}`;
|
hosted_file_obj.hosted_file_id ||
|
||||||
});
|
hosted_file_id;
|
||||||
|
const obj_type_path = hosted_file_obj.event_file_id
|
||||||
|
? 'event_file'
|
||||||
|
: 'hosted_file';
|
||||||
|
return `${$ae_api.base_url}/v3/action/${obj_type_path}/${file_id}/download?filename=${ae_util.clean_filename(final_filename)}&key=${$ae_api.account_id}`;
|
||||||
|
});
|
||||||
|
|
||||||
async function handle_click() {
|
async function handle_click() {
|
||||||
const file_id = hosted_file_obj?.id || hosted_file_obj?.hosted_file_id || hosted_file_id;
|
const file_id =
|
||||||
download_complete = undefined;
|
hosted_file_obj?.id ||
|
||||||
download_status_msg = 'Downloading...';
|
hosted_file_obj?.hosted_file_id ||
|
||||||
|
hosted_file_id;
|
||||||
|
download_complete = undefined;
|
||||||
|
download_status_msg = 'Downloading...';
|
||||||
|
|
||||||
if (click) {
|
if (click) {
|
||||||
const result = click();
|
const result = click();
|
||||||
// If the override returns a promise, track it so the UI shows progress
|
// If the override returns a promise, track it so the UI shows progress
|
||||||
if (result instanceof Promise) {
|
if (result instanceof Promise) {
|
||||||
ae_promises[file_id] = result;
|
ae_promises[file_id] = result;
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
ae_promises[file_id] = download_ae_obj_id__hosted_file({
|
|
||||||
api_cfg: $ae_api,
|
|
||||||
hosted_file_id: file_id,
|
|
||||||
return_file: true,
|
|
||||||
filename: final_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;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ae_promises[file_id] = download_ae_obj_id__hosted_file({
|
||||||
|
api_cfg: $ae_api,
|
||||||
|
hosted_file_id: file_id,
|
||||||
|
return_file: true,
|
||||||
|
filename: final_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;
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#snippet content()}
|
{#snippet content()}
|
||||||
{@const file_id = hosted_file_obj?.id || hosted_file_obj?.hosted_file_id || hosted_file_id}
|
{@const file_id =
|
||||||
|
hosted_file_obj?.id ||
|
||||||
|
hosted_file_obj?.hosted_file_id ||
|
||||||
|
hosted_file_id}
|
||||||
{#await ae_promises[file_id]}
|
{#await ae_promises[file_id]}
|
||||||
<div class="flex items-center w-full min-h-[1.5rem]">
|
<div class="flex min-h-[1.5rem] w-full items-center">
|
||||||
<div
|
<div
|
||||||
class="flex items-center pr-2 shrink-0 {show_divider ? 'border-r border-surface-500/30 mr-2' : ''}"
|
class="flex shrink-0 items-center pr-2 {show_divider
|
||||||
>
|
? 'border-surface-500/30 mr-2 border-r'
|
||||||
|
: ''}">
|
||||||
<Lucide.LoaderCircle class="animate-spin" size={18} />
|
<Lucide.LoaderCircle class="animate-spin" size={18} />
|
||||||
</div>
|
</div>
|
||||||
<div class="grow relative text-left h-full">
|
<div class="relative h-full grow text-left">
|
||||||
{#if show_filename_view}
|
{#if show_filename_view}
|
||||||
<div in:fade={{ duration: 250 }} out:fade={{ duration: 250 }} class="flex items-center h-full">
|
<div
|
||||||
|
in:fade={{ duration: 250 }}
|
||||||
|
out:fade={{ duration: 250 }}
|
||||||
|
class="flex h-full items-center">
|
||||||
<span class="truncate">
|
<span class="truncate">
|
||||||
{shortened_filename}
|
{shortened_filename}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div in:fade={{ duration: 250 }} out:fade={{ duration: 250 }} class="absolute inset-0 flex items-center h-full">
|
<div
|
||||||
|
in:fade={{ duration: 250 }}
|
||||||
|
out:fade={{ duration: 250 }}
|
||||||
|
class="absolute inset-0 flex h-full items-center">
|
||||||
<span class="font-bold whitespace-nowrap">
|
<span class="font-bold whitespace-nowrap">
|
||||||
Downloading:
|
Downloading:
|
||||||
{#if $ae_sess.api_download_kv[file_id]}
|
{#if $ae_sess.api_download_kv[file_id]}
|
||||||
{$ae_sess.api_download_kv[file_id].percent_completed}%
|
{$ae_sess.api_download_kv[file_id]
|
||||||
|
.percent_completed}%
|
||||||
{:else}
|
{:else}
|
||||||
...
|
...
|
||||||
{/if}
|
{/if}
|
||||||
@@ -250,18 +282,22 @@
|
|||||||
{#if label}
|
{#if label}
|
||||||
{@render label()}
|
{@render label()}
|
||||||
{:else}
|
{:else}
|
||||||
{@const IconComp = ae_util.file_extension_icon_lucide(hosted_file_obj?.extension)}
|
{@const IconComp = ae_util.file_extension_icon_lucide(
|
||||||
<div class="flex items-center w-full">
|
hosted_file_obj?.extension
|
||||||
|
)}
|
||||||
|
<div class="flex w-full items-center">
|
||||||
<div
|
<div
|
||||||
class="flex items-center pr-2 shrink-0 {show_divider ? 'border-r border-surface-500/30 mr-2' : ''}"
|
class="flex shrink-0 items-center pr-2 {show_divider
|
||||||
>
|
? 'border-surface-500/30 mr-2 border-r'
|
||||||
|
: ''}">
|
||||||
<IconComp size={18} />
|
<IconComp size={18} />
|
||||||
</div>
|
</div>
|
||||||
<span class="grow truncate text-left">
|
<span class="grow truncate text-left">
|
||||||
{shortened_filename}
|
{shortened_filename}
|
||||||
</span>
|
</span>
|
||||||
{#if hosted_file_obj?.file_purpose || hosted_file_obj?.group}
|
{#if hosted_file_obj?.file_purpose || hosted_file_obj?.group}
|
||||||
<span class="badge preset-tonal-success ml-2 text-[10px] uppercase font-bold shrink-0">
|
<span
|
||||||
|
class="badge preset-tonal-success ml-2 shrink-0 text-[10px] font-bold uppercase">
|
||||||
{hosted_file_obj.file_purpose || hosted_file_obj.group}
|
{hosted_file_obj.file_purpose || hosted_file_obj.group}
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
@@ -270,22 +306,25 @@
|
|||||||
{/await}
|
{/await}
|
||||||
|
|
||||||
{#if download_complete === null}
|
{#if download_complete === null}
|
||||||
<span class="text-red-800 dark:text-red-200 ml-2 whitespace-nowrap">File not found</span>
|
<span class="ml-2 whitespace-nowrap text-red-800 dark:text-red-200"
|
||||||
|
>File not found</span>
|
||||||
{:else if download_complete === false}
|
{:else if download_complete === false}
|
||||||
<span class="text-red-800 dark:text-red-200 ml-2 whitespace-nowrap text-xs">Failed!</span>
|
<span
|
||||||
|
class="ml-2 text-xs whitespace-nowrap text-red-800 dark:text-red-200"
|
||||||
|
>Failed!</span>
|
||||||
{/if}
|
{/if}
|
||||||
{/snippet}
|
{/snippet}
|
||||||
|
|
||||||
{#if hosted_file_id && hosted_file_obj}
|
{#if hosted_file_id && hosted_file_obj}
|
||||||
{@const file_id = hosted_file_obj.id || hosted_file_obj.hosted_file_id || hosted_file_id}
|
{@const file_id =
|
||||||
|
hosted_file_obj.id || hosted_file_obj.hosted_file_id || hosted_file_id}
|
||||||
|
|
||||||
{#if show_direct_download}
|
{#if show_direct_download}
|
||||||
<a
|
<a
|
||||||
href={direct_download_url}
|
href={direct_download_url}
|
||||||
download={ae_util.clean_filename(final_filename)}
|
download={ae_util.clean_filename(final_filename)}
|
||||||
class={variant_classes}
|
class={variant_classes}
|
||||||
title={`Direct download (V3 Action):\n${final_filename}\n[API] SHA256: ${hosted_file_obj?.hash_sha256?.slice(0, 10)}...\nHosted ID: ${file_id}`}
|
title={`Direct download (V3 Action):\n${final_filename}\n[API] SHA256: ${hosted_file_obj?.hash_sha256?.slice(0, 10)}...\nHosted ID: ${file_id}`}>
|
||||||
>
|
|
||||||
{@render content()}
|
{@render content()}
|
||||||
</a>
|
</a>
|
||||||
{:else}
|
{:else}
|
||||||
@@ -294,17 +333,21 @@
|
|||||||
disabled={require_auth && !$ae_loc.authenticated_access}
|
disabled={require_auth && !$ae_loc.authenticated_access}
|
||||||
class={variant_classes}
|
class={variant_classes}
|
||||||
onclick={handle_click}
|
onclick={handle_click}
|
||||||
title={`Download this file:\n${final_filename}\n[API] SHA256: ${hosted_file_obj?.hash_sha256?.slice(0, 10)}...\nHosted ID: ${file_id}\n Linked to: ${linked_to_type} ID: ${linked_to_id}`}
|
title={`Download this file:\n${final_filename}\n[API] SHA256: ${hosted_file_obj?.hash_sha256?.slice(0, 10)}...\nHosted ID: ${file_id}\n Linked to: ${linked_to_type} ID: ${linked_to_id}`}>
|
||||||
>
|
|
||||||
{@render content()}
|
{@render content()}
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
<button type="button" disabled class={variant_classes} title="No file selected">
|
<button
|
||||||
<div class="flex items-center w-full">
|
type="button"
|
||||||
|
disabled
|
||||||
|
class={variant_classes}
|
||||||
|
title="No file selected">
|
||||||
|
<div class="flex w-full items-center">
|
||||||
<div
|
<div
|
||||||
class="flex items-center pr-2 shrink-0 {show_divider ? 'border-r border-surface-500/30 mr-2' : ''}"
|
class="flex shrink-0 items-center pr-2 {show_divider
|
||||||
>
|
? 'border-surface-500/30 mr-2 border-r'
|
||||||
|
: ''}">
|
||||||
<Lucide.FileX size={18} />
|
<Lucide.FileX size={18} />
|
||||||
</div>
|
</div>
|
||||||
<span class="grow text-left"> No file info </span>
|
<span class="grow text-left"> No file info </span>
|
||||||
|
|||||||
@@ -1,281 +1,286 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
// untrack import removed — task_id sync now uses direct $effect (no untrack needed)
|
// untrack import removed — task_id sync now uses direct $effect (no untrack needed)
|
||||||
// Imports
|
// Imports
|
||||||
// Import components and elements
|
// Import components and elements
|
||||||
import * as Lucide from 'lucide-svelte';
|
import * as Lucide from 'lucide-svelte';
|
||||||
import Element_input_files_tbl from '$lib/elements/element_input_files_tbl.svelte';
|
import Element_input_files_tbl from '$lib/elements/element_input_files_tbl.svelte';
|
||||||
|
|
||||||
// Import storage, functions, and libraries
|
// Import storage, functions, and libraries
|
||||||
import type { key_val } from '$lib/stores/ae_stores';
|
import type { key_val } from '$lib/stores/ae_stores';
|
||||||
|
|
||||||
import { api } from '$lib/api/api';
|
import { api } from '$lib/api/api';
|
||||||
import {
|
import {
|
||||||
ae_snip,
|
ae_snip,
|
||||||
ae_loc,
|
ae_loc,
|
||||||
ae_sess,
|
ae_sess,
|
||||||
ae_api,
|
ae_api,
|
||||||
ae_trig,
|
ae_trig,
|
||||||
slct,
|
slct,
|
||||||
slct_trigger
|
slct_trigger
|
||||||
} from '$lib/stores/ae_stores';
|
} from '$lib/stores/ae_stores';
|
||||||
|
|
||||||
// Exports
|
// Exports
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
// Expecting these for link_to_type: 'event', 'event_location', 'archive_content', etc
|
// Expecting these for link_to_type: 'event', 'event_location', 'archive_content', etc
|
||||||
link_to_type: string;
|
link_to_type: string;
|
||||||
link_to_id: string;
|
link_to_id: string;
|
||||||
input_name?: string;
|
input_name?: string;
|
||||||
multiple?: boolean;
|
multiple?: boolean;
|
||||||
required?: boolean;
|
required?: boolean;
|
||||||
accept?: string;
|
accept?: string;
|
||||||
class_li_default?: string;
|
class_li_default?: string;
|
||||||
class_li?: string;
|
class_li?: string;
|
||||||
input_class_li?: string[];
|
input_class_li?: string[];
|
||||||
table_class_li?: string[];
|
table_class_li?: string[];
|
||||||
upload_complete?: boolean;
|
upload_complete?: boolean;
|
||||||
submit_status?: null | string;
|
submit_status?: null | string;
|
||||||
hosted_file_id_li?: string[];
|
hosted_file_id_li?: string[];
|
||||||
hosted_file_obj_li?: any[];
|
hosted_file_obj_li?: any[];
|
||||||
hosted_file_obj_kv?: key_val;
|
hosted_file_obj_kv?: key_val;
|
||||||
label?: import('svelte').Snippet;
|
label?: import('svelte').Snippet;
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
// Local Variables
|
||||||
|
let task_id: string = $state('');
|
||||||
|
let input_file_list: any = $state(null);
|
||||||
|
let ae_promises: key_val = $state({}); // Promise<any>;
|
||||||
|
let ae_triggers: key_val = {};
|
||||||
|
|
||||||
|
let input_element_id = 'ae_comp__hosted_files_upload__input';
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
if (log_lvl) {
|
||||||
|
console.log(`*** ae_comp__hosted_files_upload.svelte ***`);
|
||||||
|
console.log(`link_to_type: ${link_to_type} link_to_id: ${link_to_id}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
// Sync task_id with link_to_id prop so it resets when navigating to a different object.
|
||||||
|
task_id = link_to_id;
|
||||||
|
});
|
||||||
|
|
||||||
|
// *** Functions and Logic
|
||||||
|
async function handle_submit_form_files(event: SubmitEvent) {
|
||||||
|
console.log('*** handle_submit_form() ***');
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
if (!event) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let {
|
$ae_sess.files.disable_submit__hosted_file_obj = true;
|
||||||
log_lvl = 0,
|
$ae_sess.files.submit_status = 'saving';
|
||||||
link_to_type,
|
submit_status = 'saving';
|
||||||
link_to_id,
|
upload_complete = false;
|
||||||
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();
|
|
||||||
|
|
||||||
// Local Variables
|
hosted_file_id_li = [];
|
||||||
let task_id: string = $state('');
|
hosted_file_obj_li = [];
|
||||||
let input_file_list: any = $state(null);
|
hosted_file_obj_kv = {};
|
||||||
let ae_promises: key_val = $state({}); // Promise<any>;
|
|
||||||
let ae_triggers: key_val = {};
|
|
||||||
|
|
||||||
let input_element_id = 'ae_comp__hosted_files_upload__input';
|
let hosted_file_results;
|
||||||
|
|
||||||
$effect(() => {
|
const target = event.currentTarget as HTMLFormElement;
|
||||||
if (log_lvl) {
|
const file_input = target
|
||||||
console.log(`*** ae_comp__hosted_files_upload.svelte ***`);
|
? (target[input_element_id] as HTMLInputElement)
|
||||||
console.log(`link_to_type: ${link_to_type} link_to_id: ${link_to_id}`);
|
: null;
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$effect(() => {
|
if (
|
||||||
// Sync task_id with link_to_id prop so it resets when navigating to a different object.
|
target &&
|
||||||
task_id = link_to_id;
|
file_input &&
|
||||||
});
|
file_input.files &&
|
||||||
|
file_input.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
|
// Loop through each file and upload them individually in event.target[input_element_id].files
|
||||||
async function handle_submit_form_files(event: SubmitEvent) {
|
// The task_id should be the file hash.
|
||||||
console.log('*** handle_submit_form() ***');
|
// processed_file_list[i] has the file hash_sha256, hash_sha256_match, warnings, uploaded, uploaded_bytes, filename, and file_size_bytes.
|
||||||
event.preventDefault();
|
for (let i = 0; i < file_input.files.length; i++) {
|
||||||
|
let tmp_file = file_input.files[i];
|
||||||
|
|
||||||
if (!event) {
|
task_id = $ae_sess.files.processed_file_list[i].hash_sha256;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$ae_sess.files.disable_submit__hosted_file_obj = true;
|
// hosted_file_results = await handle_input_upload_files([tmp_file], task_id);
|
||||||
$ae_sess.files.submit_status = 'saving';
|
hosted_file_results = await handle_input_upload_files({
|
||||||
submit_status = 'saving';
|
input_upload_files: [tmp_file],
|
||||||
upload_complete = false;
|
task_id: task_id
|
||||||
|
|
||||||
hosted_file_id_li = [];
|
|
||||||
hosted_file_obj_li = [];
|
|
||||||
hosted_file_obj_kv = {};
|
|
||||||
|
|
||||||
let hosted_file_results;
|
|
||||||
|
|
||||||
const target = event.currentTarget as HTMLFormElement;
|
|
||||||
const file_input = target ? (target[input_element_id] as HTMLInputElement) : null;
|
|
||||||
|
|
||||||
if (
|
|
||||||
target &&
|
|
||||||
file_input &&
|
|
||||||
file_input.files &&
|
|
||||||
file_input.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 < file_input.files.length; i++) {
|
|
||||||
let tmp_file = file_input.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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 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
|
|
||||||
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,
|
|
||||||
task_id
|
|
||||||
}: {
|
|
||||||
input_upload_files: any[];
|
|
||||||
task_id: string;
|
|
||||||
}) {
|
|
||||||
console.log('*** handle_input_upload_files() ***');
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
for (let i = 0; i < input_upload_files.length; i++) {
|
|
||||||
form_data.append(`file_list`, 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/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;
|
|
||||||
|
|
||||||
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; // Same as the hosted_file_id
|
|
||||||
hosted_file_data['hosted_file_id'] = hosted_file_id;
|
|
||||||
hosted_file_data['for_type'] = link_to_type;
|
|
||||||
hosted_file_data['for_id'] = 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;
|
|
||||||
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log(`hosted_file_data:`, 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';
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (log_lvl) {
|
if (hosted_file_results) {
|
||||||
console.log(`Waiting for upload__hosted_file_obj promise...`);
|
console.log(`hosted_file_results:`, hosted_file_results);
|
||||||
|
} else {
|
||||||
|
console.log(`hosted_file_results:`, hosted_file_results);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let hosted_file_result = ae_promises.upload__hosted_file_obj;
|
// 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
|
||||||
|
target.reset();
|
||||||
|
// await tick();
|
||||||
|
|
||||||
return hosted_file_result;
|
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,
|
||||||
|
task_id
|
||||||
|
}: {
|
||||||
|
input_upload_files: any[];
|
||||||
|
task_id: string;
|
||||||
|
}) {
|
||||||
|
console.log('*** handle_input_upload_files() ***');
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
for (let i = 0; i < input_upload_files.length; i++) {
|
||||||
|
form_data.append(`file_list`, 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 = '/v3/action/hosted_file/upload';
|
||||||
|
|
||||||
|
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 upload endpoint always returns a list of successfully uploaded files. 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;
|
||||||
|
|
||||||
|
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; // Same as the hosted_file_id
|
||||||
|
hosted_file_data['hosted_file_id'] = hosted_file_id;
|
||||||
|
hosted_file_data['for_type'] = link_to_type;
|
||||||
|
hosted_file_data['for_id'] = 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;
|
||||||
|
|
||||||
|
if (log_lvl) {
|
||||||
|
console.log(`hosted_file_data:`, 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';
|
||||||
|
});
|
||||||
|
|
||||||
|
if (log_lvl) {
|
||||||
|
console.log(`Waiting for upload__hosted_file_obj promise...`);
|
||||||
|
}
|
||||||
|
let hosted_file_result = ae_promises.upload__hosted_file_obj;
|
||||||
|
|
||||||
|
return hosted_file_result;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- class:hidden={!$ae_loc.trusted_access} -->
|
<!-- class:hidden={!$ae_loc.trusted_access} -->
|
||||||
<form onsubmit={handle_submit_form_files} class="{class_li_default} {class_li}">
|
<form onsubmit={handle_submit_form_files} class="{class_li_default} {class_li}">
|
||||||
{#await ae_promises.upload__hosted_file_obj}
|
{#await ae_promises.upload__hosted_file_obj}
|
||||||
<div class="text-lg flex flex-row gap-1 items-center justify-center">
|
<div class="flex flex-row items-center justify-center gap-1 text-lg">
|
||||||
<Lucide.LoaderCircle class="animate-spin m-1" />
|
<Lucide.LoaderCircle class="m-1 animate-spin" />
|
||||||
<span class="">
|
<span class="">
|
||||||
Uploading
|
Uploading
|
||||||
{#if $ae_sess.api_upload_kv[task_id]}
|
{#if $ae_sess.api_upload_kv[task_id]}
|
||||||
@@ -288,14 +293,14 @@
|
|||||||
<label
|
<label
|
||||||
for="ae_comp__hosted_files_upload__input"
|
for="ae_comp__hosted_files_upload__input"
|
||||||
class="svelte_input_file_label text-center"
|
class="svelte_input_file_label text-center"
|
||||||
class:hidden={$ae_sess.files.disable_submit__hosted_file_obj}
|
class:hidden={$ae_sess.files.disable_submit__hosted_file_obj}>
|
||||||
>
|
|
||||||
{#if label}{@render label()}{:else}
|
{#if label}{@render label()}{:else}
|
||||||
<div class="flex items-center justify-center gap-2 mb-2">
|
<div class="mb-2 flex items-center justify-center gap-2">
|
||||||
<Lucide.Upload class="text-primary-500" />
|
<Lucide.Upload class="text-primary-500" />
|
||||||
<strong class="preset-tonal-primary px-3 py-1 rounded-full">Select Files</strong>
|
<strong class="preset-tonal-primary rounded-full px-3 py-1"
|
||||||
|
>Select Files</strong>
|
||||||
</div>
|
</div>
|
||||||
<span class="text-sm text-gray-600 dark:text-gray-400 italic">
|
<span class="text-sm text-gray-600 italic dark:text-gray-400">
|
||||||
<strong>Supported formats</strong><br />
|
<strong>Supported formats</strong><br />
|
||||||
(PowerPoint, Keynote, PDF, Media, etc)
|
(PowerPoint, Keynote, PDF, Media, etc)
|
||||||
</span>
|
</span>
|
||||||
@@ -313,33 +318,30 @@
|
|||||||
class="
|
class="
|
||||||
svelte_input_file_element
|
svelte_input_file_element
|
||||||
file-dropzone-input
|
file-dropzone-input
|
||||||
px-1
|
|
||||||
block w-full text-lg
|
|
||||||
preset-filled-surface-50-950
|
preset-filled-surface-50-950
|
||||||
text-surface-900 dark:text-surface-100
|
text-surface-900 dark:text-surface-100 border-surface-300
|
||||||
border border-surface-300 dark:border-surface-700 rounded-lg
|
dark:border-surface-700
|
||||||
cursor-pointer
|
focus:ring-primary-500 block
|
||||||
focus:outline-hidden focus:ring-2 focus:ring-primary-500
|
w-full cursor-pointer rounded-lg border
|
||||||
|
px-1
|
||||||
|
text-lg focus:ring-2 focus:outline-hidden
|
||||||
{input_class_li.join(' ')}
|
{input_class_li.join(' ')}
|
||||||
"
|
"
|
||||||
class:hidden={$ae_sess.files.disable_submit__hosted_file_obj}
|
class:hidden={$ae_sess.files.disable_submit__hosted_file_obj} />
|
||||||
/>
|
|
||||||
|
|
||||||
<Element_input_files_tbl
|
<Element_input_files_tbl
|
||||||
bind:input_file_list
|
bind:input_file_list
|
||||||
bind:file_list_status={$ae_sess.files.status__file_list}
|
bind:file_list_status={$ae_sess.files.status__file_list}
|
||||||
bind:processed_file_list={$ae_sess.files.processed_file_list}
|
bind:processed_file_list={$ae_sess.files.processed_file_list}
|
||||||
{table_class_li}
|
{table_class_li} />
|
||||||
/>
|
|
||||||
|
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
class="btn btn-lg btn-primary preset-tonal-primary border border-primary-500 hover:preset-tonal-success hover:border-success-500 w-54"
|
class="btn btn-lg btn-primary preset-tonal-primary border-primary-500 hover:preset-tonal-success hover:border-success-500 w-54 border"
|
||||||
disabled={$ae_sess.files.disable_submit__hosted_file_obj ||
|
disabled={$ae_sess.files.disable_submit__hosted_file_obj ||
|
||||||
$ae_sess.files.status__file_list != 'ready'}
|
$ae_sess.files.status__file_list != 'ready'}>
|
||||||
>
|
|
||||||
{#await ae_promises.upload__hosted_file_obj}
|
{#await ae_promises.upload__hosted_file_obj}
|
||||||
<Lucide.LoaderCircle class="animate-spin m-1" />
|
<Lucide.LoaderCircle class="m-1 animate-spin" />
|
||||||
<span class="">
|
<span class="">
|
||||||
{#if $ae_sess.api_upload_kv[task_id]}
|
{#if $ae_sess.api_upload_kv[task_id]}
|
||||||
{$ae_sess.api_upload_kv[task_id].percent_completed}%
|
{$ae_sess.api_upload_kv[task_id].percent_completed}%
|
||||||
@@ -350,9 +352,12 @@
|
|||||||
{:then}
|
{:then}
|
||||||
<Lucide.UploadCloud class="m-1" size={20} />
|
<Lucide.UploadCloud class="m-1" size={20} />
|
||||||
<span class="text-sm"> Upload </span>
|
<span class="text-sm"> Upload </span>
|
||||||
<span class="grow font-bold ml-2">
|
<span class="ml-2 grow font-bold">
|
||||||
{#if $ae_sess.files.processed_file_list?.length > 0}
|
{#if $ae_sess.files.processed_file_list?.length > 0}
|
||||||
{$ae_sess.files.processed_file_list.length} { $ae_sess.files.processed_file_list.length === 1 ? 'file' : 'files' }
|
{$ae_sess.files.processed_file_list.length}
|
||||||
|
{$ae_sess.files.processed_file_list.length === 1
|
||||||
|
? 'file'
|
||||||
|
: 'files'}
|
||||||
{:else}
|
{:else}
|
||||||
<span class="text-xs"> 0 </span>
|
<span class="text-xs"> 0 </span>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -1,235 +1,358 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { untrack } from 'svelte';
|
import { untrack } from 'svelte';
|
||||||
/**
|
/**
|
||||||
* AE_Comp_Site_Config_Editor.svelte
|
* AE_Comp_Site_Config_Editor.svelte
|
||||||
* Specialized UI for managing site.cfg_json settings.
|
* Specialized UI for managing site.cfg_json settings.
|
||||||
* Supports General, AI, Performance, and IDAA-specific configurations.
|
* Supports General, AI, Performance, and IDAA-specific configurations.
|
||||||
*/
|
*/
|
||||||
import { Modal } from 'flowbite-svelte';
|
import { Modal } from 'flowbite-svelte';
|
||||||
import { Brain, CodeXml, ExternalLink, Globe, Mail, Minus, Palette, Plus, Save, ShieldCheck, Timer } from '@lucide/svelte';
|
import {
|
||||||
import AE_Comp_Editor_CodeMirror from '$lib/elements/AE_Comp_Editor_CodeMirror.svelte';
|
Brain,
|
||||||
import { ae_loc } from '$lib/stores/ae_stores';
|
CodeXml,
|
||||||
|
ExternalLink,
|
||||||
|
Globe,
|
||||||
|
Mail,
|
||||||
|
Minus,
|
||||||
|
Palette,
|
||||||
|
Plus,
|
||||||
|
Save,
|
||||||
|
ShieldCheck,
|
||||||
|
Timer
|
||||||
|
} from '@lucide/svelte';
|
||||||
|
import AE_Comp_Editor_CodeMirror from '$lib/elements/element_editor_codemirror.svelte';
|
||||||
|
import { ae_loc } from '$lib/stores/ae_stores';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
cfg_json: any;
|
cfg_json: any;
|
||||||
on_save?: () => void;
|
on_save?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { cfg_json = $bindable({}), on_save }: Props = $props();
|
let { cfg_json = $bindable({}), on_save }: Props = $props();
|
||||||
|
|
||||||
// Ensure we have a valid object (handle strings/nulls)
|
// Ensure we have a valid object (handle strings/nulls)
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (typeof cfg_json === 'string') {
|
if (typeof cfg_json === 'string') {
|
||||||
try {
|
try {
|
||||||
cfg_json = JSON.parse(cfg_json);
|
cfg_json = JSON.parse(cfg_json);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
cfg_json = {};
|
cfg_json = {};
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!cfg_json) cfg_json = {};
|
}
|
||||||
});
|
|
||||||
|
|
||||||
// Internal State
|
|
||||||
let active_tab: 'visuals' | 'email' | 'ai' | 'refresh' | 'idaa' | 'raw' = $state('visuals');
|
|
||||||
let raw_json_str = $state('');
|
|
||||||
|
|
||||||
// Ensure we have a valid object
|
|
||||||
if (!cfg_json) cfg_json = {};
|
if (!cfg_json) cfg_json = {};
|
||||||
|
});
|
||||||
|
|
||||||
function add_to_list(key: string) {
|
// Internal State
|
||||||
if (!cfg_json[key]) cfg_json[key] = [];
|
let active_tab: 'visuals' | 'email' | 'ai' | 'refresh' | 'idaa' | 'raw' =
|
||||||
const val = prompt('Enter Novi UUID:');
|
$state('visuals');
|
||||||
if (val) cfg_json[key].push(val);
|
let raw_json_str = $state('');
|
||||||
|
|
||||||
|
// Ensure we have a valid object
|
||||||
|
if (!cfg_json) cfg_json = {};
|
||||||
|
|
||||||
|
function add_to_list(key: string) {
|
||||||
|
if (!cfg_json[key]) cfg_json[key] = [];
|
||||||
|
const val = prompt('Enter Novi UUID:');
|
||||||
|
if (val) cfg_json[key].push(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
function remove_from_list(key: string, index: number) {
|
||||||
|
cfg_json[key].splice(index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync Raw JSON string when entering the tab
|
||||||
|
$effect(() => {
|
||||||
|
if (active_tab === 'raw') {
|
||||||
|
untrack(() => {
|
||||||
|
raw_json_str = JSON.stringify(cfg_json, null, 2);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function remove_from_list(key: string, index: number) {
|
// Update cfg_json when raw string changes
|
||||||
cfg_json[key].splice(index, 1);
|
$effect(() => {
|
||||||
|
if (active_tab === 'raw' && raw_json_str) {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(raw_json_str);
|
||||||
|
cfg_json = parsed;
|
||||||
|
} catch (e) {
|
||||||
|
// Ignore invalid JSON while typing
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
// Sync Raw JSON string when entering the tab
|
|
||||||
$effect(() => {
|
|
||||||
if (active_tab === 'raw') {
|
|
||||||
untrack(() => {
|
|
||||||
raw_json_str = JSON.stringify(cfg_json, null, 2);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update cfg_json when raw string changes
|
|
||||||
$effect(() => {
|
|
||||||
if (active_tab === 'raw' && raw_json_str) {
|
|
||||||
try {
|
|
||||||
const parsed = JSON.parse(raw_json_str);
|
|
||||||
cfg_json = parsed;
|
|
||||||
} catch (e) {
|
|
||||||
// Ignore invalid JSON while typing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="ae-site-config-editor flex flex-col h-full space-y-4">
|
<div class="ae-site-config-editor flex h-full flex-col space-y-4">
|
||||||
<!-- Tab Navigation -->
|
<!-- Tab Navigation -->
|
||||||
<div class="flex flex-wrap gap-1 p-1 bg-surface-500/10 rounded-lg max-w-fit">
|
<div
|
||||||
<button class="btn btn-sm transition-all {active_tab === 'visuals' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => active_tab = 'visuals'}>
|
class="bg-surface-500/10 flex max-w-fit flex-wrap gap-1 rounded-lg p-1">
|
||||||
|
<button
|
||||||
|
class="btn btn-sm transition-all {active_tab === 'visuals'
|
||||||
|
? 'variant-filled-primary'
|
||||||
|
: 'variant-soft-surface'}"
|
||||||
|
onclick={() => (active_tab = 'visuals')}>
|
||||||
<Palette size="1.1em" class="mr-1" /> Visuals
|
<Palette size="1.1em" class="mr-1" /> Visuals
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-sm transition-all {active_tab === 'email' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => active_tab = 'email'}>
|
<button
|
||||||
|
class="btn btn-sm transition-all {active_tab === 'email'
|
||||||
|
? 'variant-filled-primary'
|
||||||
|
: 'variant-soft-surface'}"
|
||||||
|
onclick={() => (active_tab = 'email')}>
|
||||||
<Mail size="1.1em" class="mr-1" /> Email
|
<Mail size="1.1em" class="mr-1" /> Email
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-sm transition-all {active_tab === 'ai' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => active_tab = 'ai'}>
|
<button
|
||||||
|
class="btn btn-sm transition-all {active_tab === 'ai'
|
||||||
|
? 'variant-filled-primary'
|
||||||
|
: 'variant-soft-surface'}"
|
||||||
|
onclick={() => (active_tab = 'ai')}>
|
||||||
<Brain size="1.1em" class="mr-1" /> AI/LLM
|
<Brain size="1.1em" class="mr-1" /> AI/LLM
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-sm transition-all {active_tab === 'refresh' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => active_tab = 'refresh'}>
|
<button
|
||||||
|
class="btn btn-sm transition-all {active_tab === 'refresh'
|
||||||
|
? 'variant-filled-primary'
|
||||||
|
: 'variant-soft-surface'}"
|
||||||
|
onclick={() => (active_tab = 'refresh')}>
|
||||||
<Timer size="1.1em" class="mr-1" /> Refresh
|
<Timer size="1.1em" class="mr-1" /> Refresh
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-sm transition-all {active_tab === 'idaa' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => active_tab = 'idaa'}>
|
<button
|
||||||
|
class="btn btn-sm transition-all {active_tab === 'idaa'
|
||||||
|
? 'variant-filled-primary'
|
||||||
|
: 'variant-soft-surface'}"
|
||||||
|
onclick={() => (active_tab = 'idaa')}>
|
||||||
<ShieldCheck size="1.1em" class="mr-1" /> IDAA
|
<ShieldCheck size="1.1em" class="mr-1" /> IDAA
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-sm transition-all {active_tab === 'raw' ? 'variant-filled-primary' : 'variant-soft-surface'}" onclick={() => active_tab = 'raw'}>
|
<button
|
||||||
|
class="btn btn-sm transition-all {active_tab === 'raw'
|
||||||
|
? 'variant-filled-primary'
|
||||||
|
: 'variant-soft-surface'}"
|
||||||
|
onclick={() => (active_tab = 'raw')}>
|
||||||
<CodeXml size="1.1em" class="mr-1" /> Raw JSON
|
<CodeXml size="1.1em" class="mr-1" /> Raw JSON
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Scrollable Content Area -->
|
<!-- Scrollable Content Area -->
|
||||||
<div class="grow overflow-y-auto p-1 pr-2 space-y-6 max-h-[60vh]">
|
<div class="max-h-[60vh] grow space-y-6 overflow-y-auto p-1 pr-2">
|
||||||
|
|
||||||
{#if active_tab === 'visuals'}
|
{#if active_tab === 'visuals'}
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 animate-in fade-in duration-200">
|
<div
|
||||||
|
class="animate-in fade-in grid grid-cols-1 gap-4 duration-200 md:grid-cols-2">
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span class="text-xs font-bold uppercase opacity-50">Theme Name</span>
|
<span class="text-xs font-bold uppercase opacity-50"
|
||||||
<input type="text" bind:value={cfg_json.theme_name} class="input variant-form-material" placeholder="e.g. AE_OSIT_default" />
|
>Theme Name</span>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
bind:value={cfg_json.theme_name}
|
||||||
|
class="input variant-form-material"
|
||||||
|
placeholder="e.g. AE_OSIT_default" />
|
||||||
</label>
|
</label>
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span class="text-xs font-bold uppercase opacity-50">Theme Mode</span>
|
<span class="text-xs font-bold uppercase opacity-50"
|
||||||
<select bind:value={cfg_json.theme_mode} class="select variant-form-material">
|
>Theme Mode</span>
|
||||||
|
<select
|
||||||
|
bind:value={cfg_json.theme_mode}
|
||||||
|
class="select variant-form-material">
|
||||||
<option value="light">Light</option>
|
<option value="light">Light</option>
|
||||||
<option value="dark">Dark</option>
|
<option value="dark">Dark</option>
|
||||||
<option value="auto">Auto (System)</option>
|
<option value="auto">Auto (System)</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<label class="label md:col-span-2">
|
<label class="label md:col-span-2">
|
||||||
<span class="text-xs font-bold uppercase opacity-50">Header Image Path (URL)</span>
|
<span class="text-xs font-bold uppercase opacity-50"
|
||||||
|
>Header Image Path (URL)</span>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<input type="text" bind:value={cfg_json.header_image_path} class="input variant-form-material grow" placeholder="https://..." />
|
<input
|
||||||
|
type="text"
|
||||||
|
bind:value={cfg_json.header_image_path}
|
||||||
|
class="input variant-form-material grow"
|
||||||
|
placeholder="https://..." />
|
||||||
{#if cfg_json.header_image_path}
|
{#if cfg_json.header_image_path}
|
||||||
<a href={cfg_json.header_image_path} target="_blank" rel="noopener noreferrer" class="btn-icon variant-soft-surface"><ExternalLink size="1.2em" /></a>
|
<a
|
||||||
|
href={cfg_json.header_image_path}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
class="btn-icon variant-soft-surface"
|
||||||
|
><ExternalLink size="1.2em" /></a>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{:else if active_tab === 'email'}
|
{:else if active_tab === 'email'}
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 animate-in fade-in duration-200">
|
<div
|
||||||
<section class="space-y-4 border-r border-surface-500/10 pr-4">
|
class="animate-in fade-in grid grid-cols-1 gap-4 duration-200 md:grid-cols-2">
|
||||||
<h4 class="text-sm font-black text-primary-500">Admin Contact</h4>
|
<section class="border-surface-500/10 space-y-4 border-r pr-4">
|
||||||
|
<h4 class="text-primary-500 text-sm font-black">
|
||||||
|
Admin Contact
|
||||||
|
</h4>
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span class="text-xs font-bold uppercase opacity-50">Admin Name</span>
|
<span class="text-xs font-bold uppercase opacity-50"
|
||||||
<input type="text" bind:value={cfg_json.admin_name} class="input variant-form-material" />
|
>Admin Name</span>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
bind:value={cfg_json.admin_name}
|
||||||
|
class="input variant-form-material" />
|
||||||
</label>
|
</label>
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span class="text-xs font-bold uppercase opacity-50">Admin Email</span>
|
<span class="text-xs font-bold uppercase opacity-50"
|
||||||
<input type="email" bind:value={cfg_json.admin_email} class="input variant-form-material" />
|
>Admin Email</span>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
bind:value={cfg_json.admin_email}
|
||||||
|
class="input variant-form-material" />
|
||||||
</label>
|
</label>
|
||||||
</section>
|
</section>
|
||||||
<section class="space-y-4">
|
<section class="space-y-4">
|
||||||
<h4 class="text-sm font-black text-secondary-500">System (No-Reply)</h4>
|
<h4 class="text-secondary-500 text-sm font-black">
|
||||||
|
System (No-Reply)
|
||||||
|
</h4>
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span class="text-xs font-bold uppercase opacity-50">No-Reply Name</span>
|
<span class="text-xs font-bold uppercase opacity-50"
|
||||||
<input type="text" bind:value={cfg_json.noreply_name} class="input variant-form-material" />
|
>No-Reply Name</span>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
bind:value={cfg_json.noreply_name}
|
||||||
|
class="input variant-form-material" />
|
||||||
</label>
|
</label>
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span class="text-xs font-bold uppercase opacity-50">No-Reply Email</span>
|
<span class="text-xs font-bold uppercase opacity-50"
|
||||||
<input type="email" bind:value={cfg_json.noreply_email} class="input variant-form-material" />
|
>No-Reply Email</span>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
bind:value={cfg_json.noreply_email}
|
||||||
|
class="input variant-form-material" />
|
||||||
</label>
|
</label>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{:else if active_tab === 'ai'}
|
{:else if active_tab === 'ai'}
|
||||||
<div class="space-y-4 animate-in fade-in duration-200">
|
<div class="animate-in fade-in space-y-4 duration-200">
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span class="text-xs font-bold uppercase opacity-50">LLM API Base URL</span>
|
<span class="text-xs font-bold uppercase opacity-50"
|
||||||
<input type="text" bind:value={cfg_json.llm__api_base_url} class="input variant-form-material" />
|
>LLM API Base URL</span>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
bind:value={cfg_json.llm__api_base_url}
|
||||||
|
class="input variant-form-material" />
|
||||||
</label>
|
</label>
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span class="text-xs font-bold uppercase opacity-50">LLM Model</span>
|
<span class="text-xs font-bold uppercase opacity-50"
|
||||||
<input type="text" bind:value={cfg_json.llm__api_model} class="input variant-form-material" />
|
>LLM Model</span>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
bind:value={cfg_json.llm__api_model}
|
||||||
|
class="input variant-form-material" />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span class="text-xs font-bold uppercase opacity-50">API Token</span>
|
<span class="text-xs font-bold uppercase opacity-50"
|
||||||
<input type="password" bind:value={cfg_json.llm__api_token} class="input variant-form-material font-mono" />
|
>API Token</span>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
bind:value={cfg_json.llm__api_token}
|
||||||
|
class="input variant-form-material font-mono" />
|
||||||
</label>
|
</label>
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span class="text-xs font-bold uppercase opacity-50">System Prompt</span>
|
<span class="text-xs font-bold uppercase opacity-50"
|
||||||
<textarea bind:value={cfg_json.llm__system_prompt} class="textarea variant-form-material h-24 text-sm"></textarea>
|
>System Prompt</span>
|
||||||
|
<textarea
|
||||||
|
bind:value={cfg_json.llm__system_prompt}
|
||||||
|
class="textarea variant-form-material h-24 text-sm"
|
||||||
|
></textarea>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex items-center space-x-2">
|
<label class="flex items-center space-x-2">
|
||||||
<input type="checkbox" bind:checked={cfg_json.llm__api_dangerous_browser} class="checkbox" />
|
<input
|
||||||
<span class="text-xs font-bold uppercase opacity-50">Allow Browser Fetch (Dangerously)</span>
|
type="checkbox"
|
||||||
|
bind:checked={cfg_json.llm__api_dangerous_browser}
|
||||||
|
class="checkbox" />
|
||||||
|
<span class="text-xs font-bold uppercase opacity-50"
|
||||||
|
>Allow Browser Fetch (Dangerously)</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{:else if active_tab === 'refresh'}
|
{:else if active_tab === 'refresh'}
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 animate-in fade-in duration-200">
|
<div
|
||||||
|
class="animate-in fade-in grid grid-cols-1 gap-4 duration-200 md:grid-cols-2">
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span class="text-xs font-bold uppercase opacity-50">Default (Minutes)</span>
|
<span class="text-xs font-bold uppercase opacity-50"
|
||||||
<input type="number" bind:value={cfg_json.default_refresh_minutes} class="input variant-form-material" />
|
>Default (Minutes)</span>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
bind:value={cfg_json.default_refresh_minutes}
|
||||||
|
class="input variant-form-material" />
|
||||||
</label>
|
</label>
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span class="text-xs font-bold uppercase opacity-50">Authenticated (Minutes)</span>
|
<span class="text-xs font-bold uppercase opacity-50"
|
||||||
<input type="number" bind:value={cfg_json.authenticated_refresh_time} class="input variant-form-material" />
|
>Authenticated (Minutes)</span>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
bind:value={cfg_json.authenticated_refresh_time}
|
||||||
|
class="input variant-form-material" />
|
||||||
</label>
|
</label>
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span class="text-xs font-bold uppercase opacity-50">Trusted (Minutes)</span>
|
<span class="text-xs font-bold uppercase opacity-50"
|
||||||
<input type="number" bind:value={cfg_json.trusted_refresh_minutes} class="input variant-form-material" />
|
>Trusted (Minutes)</span>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
bind:value={cfg_json.trusted_refresh_minutes}
|
||||||
|
class="input variant-form-material" />
|
||||||
</label>
|
</label>
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span class="text-xs font-bold uppercase opacity-50">Manager (Minutes)</span>
|
<span class="text-xs font-bold uppercase opacity-50"
|
||||||
<input type="number" bind:value={cfg_json.manager_refresh_minutes} class="input variant-form-material" />
|
>Manager (Minutes)</span>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
bind:value={cfg_json.manager_refresh_minutes}
|
||||||
|
class="input variant-form-material" />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{:else if active_tab === 'idaa'}
|
{:else if active_tab === 'idaa'}
|
||||||
<div class="space-y-6 animate-in fade-in duration-200">
|
<div class="animate-in fade-in space-y-6 duration-200">
|
||||||
<!-- Novi API -->
|
<!-- Novi API -->
|
||||||
<section class="space-y-4 p-4 bg-surface-500/5 rounded-xl border border-surface-500/10">
|
<section
|
||||||
<h4 class="text-sm font-black flex items-center gap-2">
|
class="bg-surface-500/5 border-surface-500/10 space-y-4 rounded-xl border p-4">
|
||||||
|
<h4 class="flex items-center gap-2 text-sm font-black">
|
||||||
<Globe size="1.1em" class="text-primary-500" /> Novi API Connection
|
<Globe size="1.1em" class="text-primary-500" /> Novi API Connection
|
||||||
</h4>
|
</h4>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span class="text-xs font-bold uppercase opacity-50">Root URL</span>
|
<span class="text-xs font-bold uppercase opacity-50"
|
||||||
<input type="text" bind:value={cfg_json.novi_api_root_url} class="input variant-form-material" />
|
>Root URL</span>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
bind:value={cfg_json.novi_api_root_url}
|
||||||
|
class="input variant-form-material" />
|
||||||
</label>
|
</label>
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span class="text-xs font-bold uppercase opacity-50">API Key</span>
|
<span class="text-xs font-bold uppercase opacity-50"
|
||||||
<input type="password" bind:value={cfg_json.novi_idaa_api_key} class="input variant-form-material font-mono" />
|
>API Key</span>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
bind:value={cfg_json.novi_idaa_api_key}
|
||||||
|
class="input variant-form-material font-mono" />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- UUID Lists -->
|
<!-- UUID Lists -->
|
||||||
<section class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<section class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||||
{#each [
|
{#each [{ key: 'novi_admin_li', label: 'Novi Admins', color: 'text-error-500' }, { key: 'novi_trusted_li', label: 'Novi Trusted', color: 'text-warning-500' }, { key: 'novi_jitsi_mod_li', label: 'Jitsi Moderators', color: 'text-primary-500' }, { key: 'novi_idaa_group_guid_li', label: 'Member Group GUIDs', color: 'text-secondary-500' }] as list (list.key)}
|
||||||
{ key: 'novi_admin_li', label: 'Novi Admins', color: 'text-error-500' },
|
<div class="bg-surface-500/5 space-y-2 rounded-lg p-3">
|
||||||
{ key: 'novi_trusted_li', label: 'Novi Trusted', color: 'text-warning-500' },
|
<header class="flex items-center justify-between">
|
||||||
{ key: 'novi_jitsi_mod_li', label: 'Jitsi Moderators', color: 'text-primary-500' },
|
<span
|
||||||
{ key: 'novi_idaa_group_guid_li', label: 'Member Group GUIDs', color: 'text-secondary-500' }
|
class="text-[10px] font-black tracking-wider uppercase {list.color}"
|
||||||
] as list (list.key)}
|
>{list.label}</span>
|
||||||
<div class="space-y-2 p-3 bg-surface-500/5 rounded-lg">
|
<button
|
||||||
<header class="flex justify-between items-center">
|
class="btn btn-icon btn-icon-sm variant-soft-primary"
|
||||||
<span class="text-[10px] font-black uppercase tracking-wider {list.color}">{list.label}</span>
|
onclick={() => add_to_list(list.key)}>
|
||||||
<button class="btn btn-icon btn-icon-sm variant-soft-primary" onclick={() => add_to_list(list.key)}>
|
|
||||||
<Plus size="12" />
|
<Plus size="12" />
|
||||||
</button>
|
</button>
|
||||||
</header>
|
</header>
|
||||||
<div class="space-y-1">
|
<div class="space-y-1">
|
||||||
{#each cfg_json[list.key] ?? [] as uuid, i (uuid)}
|
{#each cfg_json[list.key] ?? [] as uuid, i (uuid)}
|
||||||
<div class="flex gap-1 items-center bg-surface-500/10 p-1 rounded font-mono text-[10px]">
|
<div
|
||||||
<span class="grow truncate">{uuid}</span>
|
class="bg-surface-500/10 flex items-center gap-1 rounded p-1 font-mono text-[10px]">
|
||||||
<button class="text-error-500 hover:scale-110 transition-transform" onclick={() => remove_from_list(list.key, i)}>
|
<span class="grow truncate"
|
||||||
|
>{uuid}</span>
|
||||||
|
<button
|
||||||
|
class="text-error-500 transition-transform hover:scale-110"
|
||||||
|
onclick={() =>
|
||||||
|
remove_from_list(list.key, i)}>
|
||||||
<Minus size="12" />
|
<Minus size="12" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -240,62 +363,96 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- Notifications -->
|
<!-- Notifications -->
|
||||||
<section class="grid grid-cols-1 md:grid-cols-2 gap-4 p-4 bg-surface-500/5 rounded-xl">
|
<section
|
||||||
|
class="bg-surface-500/5 grid grid-cols-1 gap-4 rounded-xl p-4 md:grid-cols-2">
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
<h4 class="text-[10px] font-black uppercase opacity-50">Bulletin Board</h4>
|
<h4 class="text-[10px] font-black uppercase opacity-50">
|
||||||
|
Bulletin Board
|
||||||
|
</h4>
|
||||||
<label class="flex items-center space-x-2 text-xs">
|
<label class="flex items-center space-x-2 text-xs">
|
||||||
<input type="checkbox" bind:checked={cfg_json.bb_send_staff_new_email} class="checkbox checkbox-sm" />
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
bind:checked={cfg_json.bb_send_staff_new_email}
|
||||||
|
class="checkbox checkbox-sm" />
|
||||||
<span>Notify Staff (New)</span>
|
<span>Notify Staff (New)</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex items-center space-x-2 text-xs">
|
<label class="flex items-center space-x-2 text-xs">
|
||||||
<input type="checkbox" bind:checked={cfg_json.bb_send_staff_update_email} class="checkbox checkbox-sm" />
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
bind:checked={
|
||||||
|
cfg_json.bb_send_staff_update_email
|
||||||
|
}
|
||||||
|
class="checkbox checkbox-sm" />
|
||||||
<span>Notify Staff (Update)</span>
|
<span>Notify Staff (Update)</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex items-center space-x-2 text-xs">
|
<label class="flex items-center space-x-2 text-xs">
|
||||||
<input type="checkbox" bind:checked={cfg_json.bb_send_poster_email} class="checkbox checkbox-sm" />
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
bind:checked={cfg_json.bb_send_poster_email}
|
||||||
|
class="checkbox checkbox-sm" />
|
||||||
<span>Notify Poster</span>
|
<span>Notify Poster</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex items-center space-x-2 text-xs">
|
<label class="flex items-center space-x-2 text-xs">
|
||||||
<input type="checkbox" bind:checked={cfg_json.bb_send_commenter_email} class="checkbox checkbox-sm" />
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
bind:checked={cfg_json.bb_send_commenter_email}
|
||||||
|
class="checkbox checkbox-sm" />
|
||||||
<span>Notify Commenters</span>
|
<span>Notify Commenters</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
<h4 class="text-[10px] font-black uppercase opacity-50">Recovery Meetings</h4>
|
<h4 class="text-[10px] font-black uppercase opacity-50">
|
||||||
|
Recovery Meetings
|
||||||
|
</h4>
|
||||||
<label class="flex items-center space-x-2 text-xs">
|
<label class="flex items-center space-x-2 text-xs">
|
||||||
<input type="checkbox" bind:checked={cfg_json.recovery_mtg_send_staff_new_email} class="checkbox checkbox-sm" />
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
bind:checked={
|
||||||
|
cfg_json.recovery_mtg_send_staff_new_email
|
||||||
|
}
|
||||||
|
class="checkbox checkbox-sm" />
|
||||||
<span>Notify Staff (New)</span>
|
<span>Notify Staff (New)</span>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex items-center space-x-2 text-xs">
|
<label class="flex items-center space-x-2 text-xs">
|
||||||
<input type="checkbox" bind:checked={cfg_json.recovery_mtg_send_staff_update_email} class="checkbox checkbox-sm" />
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
bind:checked={
|
||||||
|
cfg_json.recovery_mtg_send_staff_update_email
|
||||||
|
}
|
||||||
|
class="checkbox checkbox-sm" />
|
||||||
<span>Notify Staff (Update)</span>
|
<span>Notify Staff (Update)</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{:else if active_tab === 'raw'}
|
{:else if active_tab === 'raw'}
|
||||||
<div class="h-[50vh] animate-in fade-in duration-200">
|
<div class="animate-in fade-in h-[50vh] duration-200">
|
||||||
<AE_Comp_Editor_CodeMirror
|
<AE_Comp_Editor_CodeMirror
|
||||||
content={raw_json_str}
|
content={raw_json_str}
|
||||||
bind:new_content={raw_json_str}
|
bind:new_content={raw_json_str}
|
||||||
language="json"
|
language="json"
|
||||||
theme_mode={$ae_loc.theme_mode}
|
theme_mode={$ae_loc.theme_mode}
|
||||||
class_li="h-full border border-surface-500/20 rounded-lg shadow-inner"
|
class_li="h-full border border-surface-500/20 rounded-lg shadow-inner" />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Action Bar -->
|
<!-- Action Bar -->
|
||||||
<div class="flex justify-between items-center pt-4 border-t border-surface-500/10">
|
<div
|
||||||
|
class="border-surface-500/10 flex items-center justify-between border-t pt-4">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<label class="flex items-center space-x-2 cursor-pointer">
|
<label class="flex cursor-pointer items-center space-x-2">
|
||||||
<input type="checkbox" bind:checked={cfg_json.test} class="checkbox" />
|
<input
|
||||||
<span class="text-xs font-bold uppercase text-warning-500">Test Mode</span>
|
type="checkbox"
|
||||||
|
bind:checked={cfg_json.test}
|
||||||
|
class="checkbox" />
|
||||||
|
<span class="text-warning-500 text-xs font-bold uppercase"
|
||||||
|
>Test Mode</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-sm variant-filled-primary font-bold shadow-lg" onclick={on_save}>
|
<button
|
||||||
|
class="btn btn-sm variant-filled-primary font-bold shadow-lg"
|
||||||
|
onclick={on_save}>
|
||||||
<Save size="1.1em" class="mr-2" /> Save Config
|
<Save size="1.1em" class="mr-2" /> Save Config
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -24,11 +24,13 @@ export async function load_ae_obj_id__account({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_Account | null> {
|
}): Promise<ae_Account | null> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** load_ae_obj_id__account() *** account_id=${account_id}`);
|
console.log(
|
||||||
|
`*** load_ae_obj_id__account() *** account_id=${account_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ae_promises.load__account_obj = await api
|
ae_promises.load__account_obj = await api
|
||||||
.get_ae_obj_v3({
|
.get_ae_obj({
|
||||||
api_cfg: api_cfg,
|
api_cfg: api_cfg,
|
||||||
obj_type: 'account',
|
obj_type: 'account',
|
||||||
obj_id: account_id,
|
obj_id: account_id,
|
||||||
@@ -39,10 +41,11 @@ export async function load_ae_obj_id__account({
|
|||||||
.then(async function (account_obj_get_result) {
|
.then(async function (account_obj_get_result) {
|
||||||
if (account_obj_get_result) {
|
if (account_obj_get_result) {
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
const processed_obj_li = await process_ae_obj__account_props({
|
const processed_obj_li =
|
||||||
obj_li: [account_obj_get_result],
|
await process_ae_obj__account_props({
|
||||||
log_lvl: log_lvl
|
obj_li: [account_obj_get_result],
|
||||||
});
|
log_lvl: log_lvl
|
||||||
|
});
|
||||||
await db_save_ae_obj_li__ae_obj({
|
await db_save_ae_obj_li__ae_obj({
|
||||||
db_instance: db_core,
|
db_instance: db_core,
|
||||||
table_name: 'account',
|
table_name: 'account',
|
||||||
@@ -100,7 +103,7 @@ export async function load_ae_obj_li__account({
|
|||||||
}
|
}
|
||||||
|
|
||||||
ae_promises.load__account_obj_li = await api
|
ae_promises.load__account_obj_li = await api
|
||||||
.get_ae_obj_li_v3({
|
.get_ae_obj_li({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'account',
|
obj_type: 'account',
|
||||||
enabled,
|
enabled,
|
||||||
@@ -114,10 +117,11 @@ export async function load_ae_obj_li__account({
|
|||||||
.then(async function (account_obj_li_get_result) {
|
.then(async function (account_obj_li_get_result) {
|
||||||
if (account_obj_li_get_result) {
|
if (account_obj_li_get_result) {
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
const processed_obj_li = await process_ae_obj__account_props({
|
const processed_obj_li =
|
||||||
obj_li: account_obj_li_get_result,
|
await process_ae_obj__account_props({
|
||||||
log_lvl: log_lvl
|
obj_li: account_obj_li_get_result,
|
||||||
});
|
log_lvl: log_lvl
|
||||||
|
});
|
||||||
await db_save_ae_obj_li__ae_obj({
|
await db_save_ae_obj_li__ae_obj({
|
||||||
db_instance: db_core,
|
db_instance: db_core,
|
||||||
table_name: 'account',
|
table_name: 'account',
|
||||||
@@ -154,7 +158,7 @@ export async function create_ae_obj__account({
|
|||||||
}
|
}
|
||||||
|
|
||||||
ae_promises.create__account = await api
|
ae_promises.create__account = await api
|
||||||
.create_ae_obj_v3({
|
.create_ae_obj({
|
||||||
api_cfg: api_cfg,
|
api_cfg: api_cfg,
|
||||||
obj_type: 'account',
|
obj_type: 'account',
|
||||||
fields: data_kv,
|
fields: data_kv,
|
||||||
@@ -164,10 +168,11 @@ export async function create_ae_obj__account({
|
|||||||
.then(async function (account_obj_create_result) {
|
.then(async function (account_obj_create_result) {
|
||||||
if (account_obj_create_result) {
|
if (account_obj_create_result) {
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
const processed_obj_li = await process_ae_obj__account_props({
|
const processed_obj_li =
|
||||||
obj_li: [account_obj_create_result],
|
await process_ae_obj__account_props({
|
||||||
log_lvl: log_lvl
|
obj_li: [account_obj_create_result],
|
||||||
});
|
log_lvl: log_lvl
|
||||||
|
});
|
||||||
await db_save_ae_obj_li__ae_obj({
|
await db_save_ae_obj_li__ae_obj({
|
||||||
db_instance: db_core,
|
db_instance: db_core,
|
||||||
table_name: 'account',
|
table_name: 'account',
|
||||||
@@ -206,10 +211,13 @@ export async function update_ae_obj__account({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_Account | null> {
|
}): Promise<ae_Account | null> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** update_ae_obj__account() *** account_id=${account_id}`, data_kv);
|
console.log(
|
||||||
|
`*** update_ae_obj__account() *** account_id=${account_id}`,
|
||||||
|
data_kv
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await api.update_ae_obj_v3({
|
const result = await api.update_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'account',
|
obj_type: 'account',
|
||||||
obj_id: account_id,
|
obj_id: account_id,
|
||||||
@@ -256,11 +264,13 @@ export async function delete_ae_obj_id__account({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** delete_ae_obj_id__account() *** account_id=${account_id}`);
|
console.log(
|
||||||
|
`*** delete_ae_obj_id__account() *** account_id=${account_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ae_promises.delete__account_obj = await api
|
ae_promises.delete__account_obj = await api
|
||||||
.delete_ae_obj_v3({
|
.delete_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'account',
|
obj_type: 'account',
|
||||||
obj_id: account_id,
|
obj_id: account_id,
|
||||||
@@ -337,11 +347,15 @@ async function _process_generic_props<T extends Record<string, any>>({
|
|||||||
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
||||||
const name = processed_obj.name ?? '';
|
const name = processed_obj.name ?? '';
|
||||||
|
|
||||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
(processed_obj as any).tmp_sort_1 =
|
||||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
`${group}_${priority}_${sort}_${updated}`;
|
||||||
|
(processed_obj as any).tmp_sort_2 =
|
||||||
|
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||||
|
|
||||||
if (specific_processor) {
|
if (specific_processor) {
|
||||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
processed_obj = await Promise.resolve(
|
||||||
|
specific_processor(processed_obj)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
processed_obj_li.push(processed_obj as T);
|
processed_obj_li.push(processed_obj as T);
|
||||||
|
|||||||
@@ -19,10 +19,12 @@ export async function load_ae_obj_id__activity_log({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_ActivityLog | null> {
|
}): Promise<ae_ActivityLog | null> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** load_ae_obj_id__activity_log() *** activity_log_id=${activity_log_id}`);
|
console.log(
|
||||||
|
`*** load_ae_obj_id__activity_log() *** activity_log_id=${activity_log_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ae_promises.load__activity_log_obj = await api.get_ae_obj_v3({
|
ae_promises.load__activity_log_obj = await api.get_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'activity_log',
|
obj_type: 'activity_log',
|
||||||
obj_id: activity_log_id,
|
obj_id: activity_log_id,
|
||||||
@@ -61,10 +63,12 @@ export async function load_ae_obj_li__activity_log({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_ActivityLog[]> {
|
}): Promise<ae_ActivityLog[]> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** load_ae_obj_li__activity_log() *** for_obj_id=${for_obj_id}`);
|
console.log(
|
||||||
|
`*** load_ae_obj_li__activity_log() *** for_obj_id=${for_obj_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ae_promises.load__activity_log_obj_li = await api.get_ae_obj_li_v3({
|
ae_promises.load__activity_log_obj_li = await api.get_ae_obj_li({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'activity_log',
|
obj_type: 'activity_log',
|
||||||
for_obj_type,
|
for_obj_type,
|
||||||
@@ -96,15 +100,19 @@ export async function create_ae_obj__activity_log({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_ActivityLog | null> {
|
}): Promise<ae_ActivityLog | null> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** create_ae_obj__activity_log() *** account_id=${account_id}`);
|
console.log(
|
||||||
|
`*** create_ae_obj__activity_log() *** account_id=${account_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!account_id) {
|
if (!account_id) {
|
||||||
console.log(`ERROR: Core - Activity Log - account_id required to create`);
|
console.log(
|
||||||
|
`ERROR: Core - Activity Log - account_id required to create`
|
||||||
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ae_promises.create__activity_log = await api.create_ae_obj_v3({
|
ae_promises.create__activity_log = await api.create_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'activity_log',
|
obj_type: 'activity_log',
|
||||||
fields: {
|
fields: {
|
||||||
@@ -133,10 +141,12 @@ export async function update_ae_obj__activity_log({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_ActivityLog | null> {
|
}): Promise<ae_ActivityLog | null> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** update_ae_obj__activity_log() *** activity_log_id=${activity_log_id}`);
|
console.log(
|
||||||
|
`*** update_ae_obj__activity_log() *** activity_log_id=${activity_log_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ae_promises.update__activity_log_obj = await api.update_ae_obj_v3({
|
ae_promises.update__activity_log_obj = await api.update_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'activity_log',
|
obj_type: 'activity_log',
|
||||||
obj_id: activity_log_id,
|
obj_id: activity_log_id,
|
||||||
@@ -151,7 +161,6 @@ export async function update_ae_obj__activity_log({
|
|||||||
// Updated 2026-01-07
|
// Updated 2026-01-07
|
||||||
|
|
||||||
export async function qry__activity_log({
|
export async function qry__activity_log({
|
||||||
|
|
||||||
api_cfg,
|
api_cfg,
|
||||||
|
|
||||||
account_id,
|
account_id,
|
||||||
@@ -173,9 +182,7 @@ export async function qry__activity_log({
|
|||||||
order_by_li = { created_on: 'DESC' },
|
order_by_li = { created_on: 'DESC' },
|
||||||
|
|
||||||
log_lvl = 0
|
log_lvl = 0
|
||||||
|
|
||||||
}: {
|
}: {
|
||||||
|
|
||||||
api_cfg: any;
|
api_cfg: any;
|
||||||
|
|
||||||
account_id: string;
|
account_id: string;
|
||||||
@@ -197,49 +204,36 @@ export async function qry__activity_log({
|
|||||||
order_by_li?: Record<string, 'ASC' | 'DESC'>;
|
order_by_li?: Record<string, 'ASC' | 'DESC'>;
|
||||||
|
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
|
|
||||||
}): Promise<ae_ActivityLog[]> {
|
}): Promise<ae_ActivityLog[]> {
|
||||||
|
|
||||||
const search_query: any = {};
|
const search_query: any = {};
|
||||||
|
|
||||||
const filters: any[] = [];
|
const filters: any[] = [];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (account_id) {
|
if (account_id) {
|
||||||
|
filters.push({
|
||||||
filters.push({ field: 'account_id_random', op: 'eq', value: account_id });
|
field: 'account_id_random',
|
||||||
|
op: 'eq',
|
||||||
|
value: account_id
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (qry_person_id) {
|
if (qry_person_id) {
|
||||||
|
filters.push({
|
||||||
filters.push({ field: 'person_id_random', op: 'eq', value: qry_person_id });
|
field: 'person_id_random',
|
||||||
|
op: 'eq',
|
||||||
|
value: qry_person_id
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (filters.length > 0) {
|
if (filters.length > 0) {
|
||||||
|
|
||||||
search_query.and = filters;
|
search_query.and = filters;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (qry_str) {
|
if (qry_str) {
|
||||||
|
|
||||||
search_query.q = qry_str;
|
search_query.q = qry_str;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ae_promises.load__activity_log_obj_li = await api.search_ae_obj({
|
||||||
|
|
||||||
ae_promises.load__activity_log_obj_li = await api.search_ae_obj_v3({
|
|
||||||
|
|
||||||
api_cfg,
|
api_cfg,
|
||||||
|
|
||||||
obj_type: 'activity_log',
|
obj_type: 'activity_log',
|
||||||
@@ -259,13 +253,9 @@ export async function qry__activity_log({
|
|||||||
order_by_li,
|
order_by_li,
|
||||||
|
|
||||||
log_lvl
|
log_lvl
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return ae_promises.load__activity_log_obj_li;
|
return ae_promises.load__activity_log_obj_li;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updated 2026-02-16
|
// Updated 2026-02-16
|
||||||
@@ -338,14 +328,21 @@ async function _process_generic_props<T extends Record<string, any>>({
|
|||||||
const group = processed_obj.group ?? '0';
|
const group = processed_obj.group ?? '0';
|
||||||
const priority = processed_obj.priority ? 1 : 0;
|
const priority = processed_obj.priority ? 1 : 0;
|
||||||
const sort = processed_obj.sort ?? '0';
|
const sort = processed_obj.sort ?? '0';
|
||||||
const updated = processed_obj.updated_on ?? processed_obj.created_on ?? new Date(0).toISOString();
|
const updated =
|
||||||
|
processed_obj.updated_on ??
|
||||||
|
processed_obj.created_on ??
|
||||||
|
new Date(0).toISOString();
|
||||||
const name = processed_obj.name ?? '';
|
const name = processed_obj.name ?? '';
|
||||||
|
|
||||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
(processed_obj as any).tmp_sort_1 =
|
||||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
`${group}_${priority}_${sort}_${updated}`;
|
||||||
|
(processed_obj as any).tmp_sort_2 =
|
||||||
|
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||||
|
|
||||||
if (specific_processor) {
|
if (specific_processor) {
|
||||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
processed_obj = await Promise.resolve(
|
||||||
|
specific_processor(processed_obj)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
processed_obj_li.push(processed_obj as T);
|
processed_obj_li.push(processed_obj as T);
|
||||||
@@ -367,5 +364,3 @@ export async function process_ae_obj__activity_log_props({
|
|||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -23,29 +23,34 @@ export async function load_ae_obj_id__address({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_Address | null> {
|
}): Promise<ae_Address | null> {
|
||||||
ae_promises.load__address_obj = await api.get_ae_obj_v3({
|
ae_promises.load__address_obj = await api
|
||||||
api_cfg,
|
.get_ae_obj({
|
||||||
obj_type: 'address',
|
api_cfg,
|
||||||
obj_id: address_id,
|
obj_type: 'address',
|
||||||
view,
|
obj_id: address_id,
|
||||||
params,
|
view,
|
||||||
log_lvl
|
params,
|
||||||
}).then(async (result) => {
|
log_lvl
|
||||||
if (result) {
|
})
|
||||||
if (try_cache) {
|
.then(async (result) => {
|
||||||
const processed = await process_ae_obj__address_props({ obj_li: [result], log_lvl });
|
if (result) {
|
||||||
await db_save_ae_obj_li__ae_obj({
|
if (try_cache) {
|
||||||
db_instance: db_core,
|
const processed = await process_ae_obj__address_props({
|
||||||
table_name: 'address',
|
obj_li: [result],
|
||||||
obj_li: processed,
|
log_lvl
|
||||||
properties_to_save,
|
});
|
||||||
log_lvl
|
await db_save_ae_obj_li__ae_obj({
|
||||||
});
|
db_instance: db_core,
|
||||||
|
table_name: 'address',
|
||||||
|
obj_li: processed,
|
||||||
|
properties_to_save,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
return result;
|
return null;
|
||||||
}
|
});
|
||||||
return null;
|
|
||||||
});
|
|
||||||
return ae_promises.load__address_obj;
|
return ae_promises.load__address_obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,34 +82,39 @@ export async function load_ae_obj_li__address({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_Address[]> {
|
}): Promise<ae_Address[]> {
|
||||||
ae_promises.load__address_obj_li = await api.get_ae_obj_li_v3({
|
ae_promises.load__address_obj_li = await api
|
||||||
api_cfg,
|
.get_ae_obj_li({
|
||||||
obj_type: 'address',
|
api_cfg,
|
||||||
for_obj_type,
|
obj_type: 'address',
|
||||||
for_obj_id,
|
for_obj_type,
|
||||||
enabled,
|
for_obj_id,
|
||||||
hidden,
|
enabled,
|
||||||
view,
|
hidden,
|
||||||
limit,
|
view,
|
||||||
offset,
|
limit,
|
||||||
order_by_li,
|
offset,
|
||||||
log_lvl
|
order_by_li,
|
||||||
}).then(async (result) => {
|
log_lvl
|
||||||
if (result && Array.isArray(result)) {
|
})
|
||||||
if (try_cache) {
|
.then(async (result) => {
|
||||||
const processed = await process_ae_obj__address_props({ obj_li: result, log_lvl });
|
if (result && Array.isArray(result)) {
|
||||||
await db_save_ae_obj_li__ae_obj({
|
if (try_cache) {
|
||||||
db_instance: db_core,
|
const processed = await process_ae_obj__address_props({
|
||||||
table_name: 'address',
|
obj_li: result,
|
||||||
obj_li: processed,
|
log_lvl
|
||||||
properties_to_save,
|
});
|
||||||
log_lvl
|
await db_save_ae_obj_li__ae_obj({
|
||||||
});
|
db_instance: db_core,
|
||||||
|
table_name: 'address',
|
||||||
|
obj_li: processed,
|
||||||
|
properties_to_save,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
return result;
|
return [];
|
||||||
}
|
});
|
||||||
return [];
|
|
||||||
});
|
|
||||||
return ae_promises.load__address_obj_li;
|
return ae_promises.load__address_obj_li;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,7 +134,7 @@ export async function create_ae_obj__address({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_Address | null> {
|
}): Promise<ae_Address | null> {
|
||||||
const result = await api.create_ae_obj_v3({
|
const result = await api.create_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'address',
|
obj_type: 'address',
|
||||||
fields: {
|
fields: {
|
||||||
@@ -136,7 +146,10 @@ export async function create_ae_obj__address({
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (result && try_cache) {
|
if (result && try_cache) {
|
||||||
const processed = await process_ae_obj__address_props({ obj_li: [result], log_lvl });
|
const processed = await process_ae_obj__address_props({
|
||||||
|
obj_li: [result],
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
await db_save_ae_obj_li__ae_obj({
|
await db_save_ae_obj_li__ae_obj({
|
||||||
db_instance: db_core,
|
db_instance: db_core,
|
||||||
table_name: 'address',
|
table_name: 'address',
|
||||||
@@ -164,7 +177,7 @@ export async function update_ae_obj__address({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_Address | null> {
|
}): Promise<ae_Address | null> {
|
||||||
const result = await api.update_ae_obj_v3({
|
const result = await api.update_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'address',
|
obj_type: 'address',
|
||||||
obj_id: address_id,
|
obj_id: address_id,
|
||||||
@@ -174,7 +187,10 @@ export async function update_ae_obj__address({
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (result && try_cache) {
|
if (result && try_cache) {
|
||||||
const processed = await process_ae_obj__address_props({ obj_li: [result], log_lvl });
|
const processed = await process_ae_obj__address_props({
|
||||||
|
obj_li: [result],
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
await db_save_ae_obj_li__ae_obj({
|
await db_save_ae_obj_li__ae_obj({
|
||||||
db_instance: db_core,
|
db_instance: db_core,
|
||||||
table_name: 'address',
|
table_name: 'address',
|
||||||
@@ -202,7 +218,7 @@ export async function delete_ae_obj_id__address({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
const result = await api.delete_ae_obj_v3({
|
const result = await api.delete_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'address',
|
obj_type: 'address',
|
||||||
obj_id: address_id,
|
obj_id: address_id,
|
||||||
@@ -269,7 +285,9 @@ async function _process_generic_props<T extends Record<string, any>>({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (specific_processor) {
|
if (specific_processor) {
|
||||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
processed_obj = await Promise.resolve(
|
||||||
|
specific_processor(processed_obj)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
processed_obj_li.push(processed_obj as T);
|
processed_obj_li.push(processed_obj as T);
|
||||||
|
|||||||
@@ -23,29 +23,34 @@ export async function load_ae_obj_id__contact({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_Contact | null> {
|
}): Promise<ae_Contact | null> {
|
||||||
ae_promises.load__contact_obj = await api.get_ae_obj_v3({
|
ae_promises.load__contact_obj = await api
|
||||||
api_cfg,
|
.get_ae_obj({
|
||||||
obj_type: 'contact',
|
api_cfg,
|
||||||
obj_id: contact_id,
|
obj_type: 'contact',
|
||||||
view,
|
obj_id: contact_id,
|
||||||
params,
|
view,
|
||||||
log_lvl
|
params,
|
||||||
}).then(async (result) => {
|
log_lvl
|
||||||
if (result) {
|
})
|
||||||
if (try_cache) {
|
.then(async (result) => {
|
||||||
const processed = await process_ae_obj__contact_props({ obj_li: [result], log_lvl });
|
if (result) {
|
||||||
await db_save_ae_obj_li__ae_obj({
|
if (try_cache) {
|
||||||
db_instance: db_core,
|
const processed = await process_ae_obj__contact_props({
|
||||||
table_name: 'contact',
|
obj_li: [result],
|
||||||
obj_li: processed,
|
log_lvl
|
||||||
properties_to_save,
|
});
|
||||||
log_lvl
|
await db_save_ae_obj_li__ae_obj({
|
||||||
});
|
db_instance: db_core,
|
||||||
|
table_name: 'contact',
|
||||||
|
obj_li: processed,
|
||||||
|
properties_to_save,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
return result;
|
return null;
|
||||||
}
|
});
|
||||||
return null;
|
|
||||||
});
|
|
||||||
return ae_promises.load__contact_obj;
|
return ae_promises.load__contact_obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,34 +80,39 @@ export async function load_ae_obj_li__contact({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_Contact[]> {
|
}): Promise<ae_Contact[]> {
|
||||||
ae_promises.load__contact_obj_li = await api.get_ae_obj_li_v3({
|
ae_promises.load__contact_obj_li = await api
|
||||||
api_cfg,
|
.get_ae_obj_li({
|
||||||
obj_type: 'contact',
|
api_cfg,
|
||||||
for_obj_type,
|
obj_type: 'contact',
|
||||||
for_obj_id,
|
for_obj_type,
|
||||||
enabled,
|
for_obj_id,
|
||||||
hidden,
|
enabled,
|
||||||
view,
|
hidden,
|
||||||
limit,
|
view,
|
||||||
offset,
|
limit,
|
||||||
order_by_li,
|
offset,
|
||||||
log_lvl
|
order_by_li,
|
||||||
}).then(async (result) => {
|
log_lvl
|
||||||
if (result && Array.isArray(result)) {
|
})
|
||||||
if (try_cache) {
|
.then(async (result) => {
|
||||||
const processed = await process_ae_obj__contact_props({ obj_li: result, log_lvl });
|
if (result && Array.isArray(result)) {
|
||||||
await db_save_ae_obj_li__ae_obj({
|
if (try_cache) {
|
||||||
db_instance: db_core,
|
const processed = await process_ae_obj__contact_props({
|
||||||
table_name: 'contact',
|
obj_li: result,
|
||||||
obj_li: processed,
|
log_lvl
|
||||||
properties_to_save,
|
});
|
||||||
log_lvl
|
await db_save_ae_obj_li__ae_obj({
|
||||||
});
|
db_instance: db_core,
|
||||||
|
table_name: 'contact',
|
||||||
|
obj_li: processed,
|
||||||
|
properties_to_save,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
return result;
|
return [];
|
||||||
}
|
});
|
||||||
return [];
|
|
||||||
});
|
|
||||||
return ae_promises.load__contact_obj_li;
|
return ae_promises.load__contact_obj_li;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +132,7 @@ export async function create_ae_obj__contact({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_Contact | null> {
|
}): Promise<ae_Contact | null> {
|
||||||
const result = await api.create_ae_obj_v3({
|
const result = await api.create_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'contact',
|
obj_type: 'contact',
|
||||||
fields: {
|
fields: {
|
||||||
@@ -134,7 +144,10 @@ export async function create_ae_obj__contact({
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (result && try_cache) {
|
if (result && try_cache) {
|
||||||
const processed = await process_ae_obj__contact_props({ obj_li: [result], log_lvl });
|
const processed = await process_ae_obj__contact_props({
|
||||||
|
obj_li: [result],
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
await db_save_ae_obj_li__ae_obj({
|
await db_save_ae_obj_li__ae_obj({
|
||||||
db_instance: db_core,
|
db_instance: db_core,
|
||||||
table_name: 'contact',
|
table_name: 'contact',
|
||||||
@@ -162,7 +175,7 @@ export async function update_ae_obj__contact({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_Contact | null> {
|
}): Promise<ae_Contact | null> {
|
||||||
const result = await api.update_ae_obj_v3({
|
const result = await api.update_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'contact',
|
obj_type: 'contact',
|
||||||
obj_id: contact_id,
|
obj_id: contact_id,
|
||||||
@@ -172,7 +185,10 @@ export async function update_ae_obj__contact({
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (result && try_cache) {
|
if (result && try_cache) {
|
||||||
const processed = await process_ae_obj__contact_props({ obj_li: [result], log_lvl });
|
const processed = await process_ae_obj__contact_props({
|
||||||
|
obj_li: [result],
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
await db_save_ae_obj_li__ae_obj({
|
await db_save_ae_obj_li__ae_obj({
|
||||||
db_instance: db_core,
|
db_instance: db_core,
|
||||||
table_name: 'contact',
|
table_name: 'contact',
|
||||||
@@ -200,7 +216,7 @@ export async function delete_ae_obj_id__contact({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
const result = await api.delete_ae_obj_v3({
|
const result = await api.delete_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'contact',
|
obj_type: 'contact',
|
||||||
obj_id: contact_id,
|
obj_id: contact_id,
|
||||||
@@ -267,7 +283,9 @@ async function _process_generic_props<T extends Record<string, any>>({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (specific_processor) {
|
if (specific_processor) {
|
||||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
processed_obj = await Promise.resolve(
|
||||||
|
specific_processor(processed_obj)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
processed_obj_li.push(processed_obj as T);
|
processed_obj_li.push(processed_obj as T);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export async function load_ae_obj_id__organization({
|
|||||||
organization_id: string;
|
organization_id: string;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_Organization | null> {
|
}): Promise<ae_Organization | null> {
|
||||||
return await api.get_ae_obj_v3({
|
return await api.get_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'organization',
|
obj_type: 'organization',
|
||||||
obj_id: organization_id,
|
obj_id: organization_id,
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export async function load_ae_obj_id__person({
|
|||||||
}
|
}
|
||||||
|
|
||||||
ae_promises.load__person_obj = await api
|
ae_promises.load__person_obj = await api
|
||||||
.get_ae_obj_v3({
|
.get_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'person',
|
obj_type: 'person',
|
||||||
obj_id: person_id,
|
obj_id: person_id,
|
||||||
@@ -39,10 +39,12 @@ export async function load_ae_obj_id__person({
|
|||||||
.then(async function (result) {
|
.then(async function (result) {
|
||||||
if (result) {
|
if (result) {
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
const processed_obj_li = await process_ae_obj__person_props({
|
const processed_obj_li = await process_ae_obj__person_props(
|
||||||
obj_li: [result],
|
{
|
||||||
log_lvl
|
obj_li: [result],
|
||||||
});
|
log_lvl
|
||||||
|
}
|
||||||
|
);
|
||||||
await db_save_ae_obj_li__ae_obj({
|
await db_save_ae_obj_li__ae_obj({
|
||||||
db_instance: db_core,
|
db_instance: db_core,
|
||||||
table_name: 'person',
|
table_name: 'person',
|
||||||
@@ -98,7 +100,9 @@ export async function load_ae_obj_li__person({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_Person[]> {
|
}): Promise<ae_Person[]> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** load_ae_obj_li__person() *** for_obj_id=${for_obj_id}`);
|
console.log(
|
||||||
|
`*** load_ae_obj_li__person() *** for_obj_id=${for_obj_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let promise;
|
let promise;
|
||||||
@@ -109,11 +113,19 @@ export async function load_ae_obj_li__person({
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (qry_user_id) {
|
if (qry_user_id) {
|
||||||
search_query.and.push({ field: 'user_id_random', op: 'eq', value: qry_user_id });
|
search_query.and.push({
|
||||||
|
field: 'user_id_random',
|
||||||
|
op: 'eq',
|
||||||
|
value: qry_user_id
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qry_email) {
|
if (qry_email) {
|
||||||
search_query.and.push({ field: 'primary_email', op: 'eq', value: qry_email });
|
search_query.and.push({
|
||||||
|
field: 'primary_email',
|
||||||
|
op: 'eq',
|
||||||
|
value: qry_email
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (for_obj_id) {
|
if (for_obj_id) {
|
||||||
@@ -136,7 +148,7 @@ export async function load_ae_obj_li__person({
|
|||||||
search_query.and.push({ field: 'hide', op: 'eq', value: false });
|
search_query.and.push({ field: 'hide', op: 'eq', value: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
promise = api.search_ae_obj_v3({
|
promise = api.search_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'person',
|
obj_type: 'person',
|
||||||
search_query,
|
search_query,
|
||||||
@@ -146,7 +158,7 @@ export async function load_ae_obj_li__person({
|
|||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
promise = api.get_ae_obj_li_v3({
|
promise = api.get_ae_obj_li({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'person',
|
obj_type: 'person',
|
||||||
for_obj_type,
|
for_obj_type,
|
||||||
@@ -161,26 +173,30 @@ export async function load_ae_obj_li__person({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ae_promises.load__person_obj_li = await promise.then(async function (result_li) {
|
ae_promises.load__person_obj_li = await promise.then(
|
||||||
if (result_li) {
|
async function (result_li) {
|
||||||
if (try_cache) {
|
if (result_li) {
|
||||||
const processed_obj_li = await process_ae_obj__person_props({
|
if (try_cache) {
|
||||||
obj_li: result_li,
|
const processed_obj_li = await process_ae_obj__person_props(
|
||||||
log_lvl
|
{
|
||||||
});
|
obj_li: result_li,
|
||||||
await db_save_ae_obj_li__ae_obj({
|
log_lvl
|
||||||
db_instance: db_core,
|
}
|
||||||
table_name: 'person',
|
);
|
||||||
obj_li: processed_obj_li,
|
await db_save_ae_obj_li__ae_obj({
|
||||||
properties_to_save: properties_to_save,
|
db_instance: db_core,
|
||||||
log_lvl
|
table_name: 'person',
|
||||||
});
|
obj_li: processed_obj_li,
|
||||||
|
properties_to_save: properties_to_save,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result_li;
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
return result_li;
|
|
||||||
} else {
|
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
});
|
);
|
||||||
|
|
||||||
return ae_promises.load__person_obj_li;
|
return ae_promises.load__person_obj_li;
|
||||||
}
|
}
|
||||||
@@ -207,7 +223,7 @@ export async function create_ae_obj__person({
|
|||||||
if (account_id) fields.account_id_random = account_id;
|
if (account_id) fields.account_id_random = account_id;
|
||||||
if (user_id) fields.user_id_random = user_id;
|
if (user_id) fields.user_id_random = user_id;
|
||||||
|
|
||||||
const result = await api.create_ae_obj_v3({
|
const result = await api.create_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'person',
|
obj_type: 'person',
|
||||||
fields,
|
fields,
|
||||||
@@ -248,7 +264,7 @@ export async function update_ae_obj__person({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_Person | null> {
|
}): Promise<ae_Person | null> {
|
||||||
const result = await api.update_ae_obj_v3({
|
const result = await api.update_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'person',
|
obj_type: 'person',
|
||||||
obj_id: person_id,
|
obj_id: person_id,
|
||||||
@@ -290,7 +306,7 @@ export async function delete_ae_obj_id__person({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
const result = await api.delete_ae_obj_v3({
|
const result = await api.delete_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'person',
|
obj_type: 'person',
|
||||||
obj_id: person_id,
|
obj_id: person_id,
|
||||||
@@ -411,11 +427,15 @@ async function _process_generic_props<T extends Record<string, any>>({
|
|||||||
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
||||||
const name = processed_obj.full_name ?? processed_obj.name ?? '';
|
const name = processed_obj.full_name ?? processed_obj.name ?? '';
|
||||||
|
|
||||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
(processed_obj as any).tmp_sort_1 =
|
||||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
`${group}_${priority}_${sort}_${updated}`;
|
||||||
|
(processed_obj as any).tmp_sort_2 =
|
||||||
|
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||||
|
|
||||||
if (specific_processor) {
|
if (specific_processor) {
|
||||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
processed_obj = await Promise.resolve(
|
||||||
|
specific_processor(processed_obj)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
processed_obj_li.push(processed_obj as T);
|
processed_obj_li.push(processed_obj as T);
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import type { key_val } from '$lib/stores/ae_stores';
|
import type { key_val } from '$lib/stores/ae_stores';
|
||||||
|
import { ae_loc } from '$lib/stores/ae_stores';
|
||||||
|
import { get } from 'svelte/store';
|
||||||
import { api } from '$lib/api/api';
|
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';
|
||||||
@@ -11,6 +13,88 @@ const ae_promises: key_val = {};
|
|||||||
* --- SITE CRUD ---
|
* --- SITE CRUD ---
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Legacy version
|
||||||
|
// export async function lookup_site_domain({
|
||||||
|
// api_cfg,
|
||||||
|
// fqdn,
|
||||||
|
// view = 'default',
|
||||||
|
// log_lvl = 0
|
||||||
|
// }: {
|
||||||
|
// api_cfg: any;
|
||||||
|
// fqdn: string;
|
||||||
|
// view?: string;
|
||||||
|
// log_lvl?: number;
|
||||||
|
// }): Promise<ae_SiteDomain | null> {
|
||||||
|
// if (log_lvl) {
|
||||||
|
// console.log(`*** lookup_site_domain() *** fqdn=${fqdn}`);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// try {
|
||||||
|
// // We use get_ae_obj_id_crud because we are looking up by a unique field (fqdn) rather than ID.
|
||||||
|
// // This is the older method that uses the /crud/site/domain/:id endpoint.
|
||||||
|
// const result = await api.get_ae_obj_id_crud({
|
||||||
|
// api_cfg,
|
||||||
|
// no_account_id: true,
|
||||||
|
// obj_type: 'site_domain',
|
||||||
|
// obj_id: fqdn,
|
||||||
|
// use_alt_table: true,
|
||||||
|
// use_alt_base: true,
|
||||||
|
// log_lvl
|
||||||
|
// });
|
||||||
|
|
||||||
|
// if (result) {
|
||||||
|
// // Standardize and save to cache
|
||||||
|
// const processed_obj_li = await process_ae_obj__site_domain_props({
|
||||||
|
// obj_li: [result],
|
||||||
|
// log_lvl
|
||||||
|
// });
|
||||||
|
// await db_save_ae_obj_li__ae_obj({
|
||||||
|
// db_instance: db_core,
|
||||||
|
// table_name: 'site_domain',
|
||||||
|
// obj_li: processed_obj_li,
|
||||||
|
// properties_to_save: properties_to_save__site_domain,
|
||||||
|
// log_lvl
|
||||||
|
// });
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
// } catch (error: any) {
|
||||||
|
// console.log('Site domain lookup failed (API Error).', error);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (log_lvl) console.log('Attempting to load site domain from local cache...');
|
||||||
|
// const cached = await db_core.site_domain.where('fqdn').equals(fqdn).first();
|
||||||
|
|
||||||
|
// if (cached) {
|
||||||
|
// return cached as any;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // CRITICAL FALLBACK: If both API and Cache fail, return a "Ghost" site domain object
|
||||||
|
// // to prevent the 403 error from blocking the UI. Page components will handle empty data.
|
||||||
|
// console.error('AE_SITE_CRITICAL: Site domain lookup failed API and CACHE. Returning ghost object.');
|
||||||
|
// return {
|
||||||
|
// id: 'ghost',
|
||||||
|
// id_random: 'ghost',
|
||||||
|
// site_domain_id: 'ghost',
|
||||||
|
// site_domain_id_random: 'ghost',
|
||||||
|
// site_id: 'ghost',
|
||||||
|
// site_id_random: 'ghost',
|
||||||
|
// account_id: 'ghost',
|
||||||
|
// account_id_random: 'ghost',
|
||||||
|
// account_code: 'ghost',
|
||||||
|
// account_name: 'Ghost Account (Offline)',
|
||||||
|
// fqdn: fqdn,
|
||||||
|
// enable: '1',
|
||||||
|
// header_image_path: '',
|
||||||
|
// style_href: '',
|
||||||
|
// google_tracking_id: '',
|
||||||
|
// access_code_kv_json: {},
|
||||||
|
// cfg_json: {},
|
||||||
|
// access_key: '',
|
||||||
|
// site_domain_access_key: ''
|
||||||
|
// } as any;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Updated 2026-01-26 (Cache-First Optimization)
|
||||||
export async function lookup_site_domain({
|
export async function lookup_site_domain({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
fqdn,
|
fqdn,
|
||||||
@@ -23,88 +107,7 @@ export async function lookup_site_domain({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_SiteDomain | null> {
|
}): Promise<ae_SiteDomain | null> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** lookup_site_domain() *** fqdn=${fqdn}`);
|
console.log(`*** lookup_site_domain() *** fqdn=${fqdn} (Cache-First)`);
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// We use get_ae_obj_id_crud because we are looking up by a unique field (fqdn) rather than ID.
|
|
||||||
// This is the older method that uses the /crud/site/domain/:id endpoint.
|
|
||||||
const result = await api.get_ae_obj_id_crud({
|
|
||||||
api_cfg,
|
|
||||||
no_account_id: true,
|
|
||||||
obj_type: 'site_domain',
|
|
||||||
obj_id: fqdn,
|
|
||||||
use_alt_table: true,
|
|
||||||
use_alt_base: true,
|
|
||||||
log_lvl
|
|
||||||
});
|
|
||||||
|
|
||||||
if (result) {
|
|
||||||
// Standardize and save to cache
|
|
||||||
const processed_obj_li = await process_ae_obj__site_domain_props({
|
|
||||||
obj_li: [result],
|
|
||||||
log_lvl
|
|
||||||
});
|
|
||||||
await db_save_ae_obj_li__ae_obj({
|
|
||||||
db_instance: db_core,
|
|
||||||
table_name: 'site_domain',
|
|
||||||
obj_li: processed_obj_li,
|
|
||||||
properties_to_save: properties_to_save__site_domain,
|
|
||||||
log_lvl
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
|
||||||
console.log('Site domain lookup failed (API Error).', error);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (log_lvl) console.log('Attempting to load site domain from local cache...');
|
|
||||||
const cached = await db_core.site_domain.where('fqdn').equals(fqdn).first();
|
|
||||||
|
|
||||||
if (cached) {
|
|
||||||
return cached as any;
|
|
||||||
}
|
|
||||||
|
|
||||||
// CRITICAL FALLBACK: If both API and Cache fail, return a "Ghost" site domain object
|
|
||||||
// to prevent the 403 error from blocking the UI. Page components will handle empty data.
|
|
||||||
console.error('AE_SITE_CRITICAL: Site domain lookup failed API and CACHE. Returning ghost object.');
|
|
||||||
return {
|
|
||||||
id: 'ghost',
|
|
||||||
id_random: 'ghost',
|
|
||||||
site_domain_id: 'ghost',
|
|
||||||
site_domain_id_random: 'ghost',
|
|
||||||
site_id: 'ghost',
|
|
||||||
site_id_random: 'ghost',
|
|
||||||
account_id: 'ghost',
|
|
||||||
account_id_random: 'ghost',
|
|
||||||
account_code: 'ghost',
|
|
||||||
account_name: 'Ghost Account (Offline)',
|
|
||||||
fqdn: fqdn,
|
|
||||||
enable: '1',
|
|
||||||
header_image_path: '',
|
|
||||||
style_href: '',
|
|
||||||
google_tracking_id: '',
|
|
||||||
access_code_kv_json: {},
|
|
||||||
cfg_json: {},
|
|
||||||
access_key: '',
|
|
||||||
site_domain_access_key: ''
|
|
||||||
} as any;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Updated 2026-01-26 (Cache-First Optimization)
|
|
||||||
export async function lookup_site_domain_v3({
|
|
||||||
api_cfg,
|
|
||||||
fqdn,
|
|
||||||
view = 'default',
|
|
||||||
log_lvl = 0
|
|
||||||
}: {
|
|
||||||
api_cfg: any;
|
|
||||||
fqdn: string;
|
|
||||||
view?: string;
|
|
||||||
log_lvl?: number;
|
|
||||||
}): Promise<ae_SiteDomain | null> {
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log(`*** lookup_site_domain_v3() *** fqdn=${fqdn} (Cache-First)`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. FAST PATH: Check local cache first
|
// 1. FAST PATH: Check local cache first
|
||||||
@@ -112,10 +115,18 @@ export async function lookup_site_domain_v3({
|
|||||||
try {
|
try {
|
||||||
cached = await db_core.site_domain.where('fqdn').equals(fqdn).first();
|
cached = await db_core.site_domain.where('fqdn').equals(fqdn).first();
|
||||||
if (cached) {
|
if (cached) {
|
||||||
if (log_lvl) console.log('BOOTSTRAP: Cache hit. Returning cached site domain immediately.');
|
if (log_lvl)
|
||||||
|
console.log(
|
||||||
|
'BOOTSTRAP: Cache hit. Returning cached site domain immediately.'
|
||||||
|
);
|
||||||
|
|
||||||
// Trigger background refresh to keep cache fresh, but don't await it
|
// Trigger background refresh to keep cache fresh, but don't await it
|
||||||
_refresh_site_domain_v3_background({ api_cfg, fqdn, view, log_lvl: 0 });
|
_refresh_site_domain_background({
|
||||||
|
api_cfg,
|
||||||
|
fqdn,
|
||||||
|
view,
|
||||||
|
log_lvl: 0
|
||||||
|
});
|
||||||
|
|
||||||
return cached as any;
|
return cached as any;
|
||||||
}
|
}
|
||||||
@@ -124,13 +135,23 @@ export async function lookup_site_domain_v3({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2. SLOW PATH: Wait for API if cache is empty
|
// 2. SLOW PATH: Wait for API if cache is empty
|
||||||
return await _refresh_site_domain_v3_background({ api_cfg, fqdn, view, log_lvl });
|
return await _refresh_site_domain_background({
|
||||||
|
api_cfg,
|
||||||
|
fqdn,
|
||||||
|
view,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal helper to perform the actual API fetch and cache update
|
* Internal helper to perform the actual API fetch and cache update
|
||||||
*/
|
*/
|
||||||
async function _refresh_site_domain_v3_background({ api_cfg, fqdn, view, log_lvl }: any) {
|
async function _refresh_site_domain_background({
|
||||||
|
api_cfg,
|
||||||
|
fqdn,
|
||||||
|
view,
|
||||||
|
log_lvl
|
||||||
|
}: any) {
|
||||||
try {
|
try {
|
||||||
const guest_api_cfg = { ...api_cfg };
|
const guest_api_cfg = { ...api_cfg };
|
||||||
guest_api_cfg.headers = { ...api_cfg.headers };
|
guest_api_cfg.headers = { ...api_cfg.headers };
|
||||||
@@ -143,7 +164,7 @@ async function _refresh_site_domain_v3_background({ api_cfg, fqdn, view, log_lvl
|
|||||||
'JWT'
|
'JWT'
|
||||||
];
|
];
|
||||||
|
|
||||||
auth_props.forEach(prop => {
|
auth_props.forEach((prop) => {
|
||||||
delete guest_api_cfg.headers[prop];
|
delete guest_api_cfg.headers[prop];
|
||||||
delete guest_api_cfg.headers[prop.toLowerCase()];
|
delete guest_api_cfg.headers[prop.toLowerCase()];
|
||||||
delete guest_api_cfg.headers[prop.replaceAll('-', '_')];
|
delete guest_api_cfg.headers[prop.replaceAll('-', '_')];
|
||||||
@@ -155,7 +176,7 @@ async function _refresh_site_domain_v3_background({ api_cfg, fqdn, view, log_lvl
|
|||||||
and: [{ field: 'fqdn', op: 'eq', value: fqdn }]
|
and: [{ field: 'fqdn', op: 'eq', value: fqdn }]
|
||||||
};
|
};
|
||||||
|
|
||||||
const result_li = await api.search_ae_obj_v3({
|
const result_li = await api.search_ae_obj({
|
||||||
api_cfg: guest_api_cfg,
|
api_cfg: guest_api_cfg,
|
||||||
obj_type: 'site_domain',
|
obj_type: 'site_domain',
|
||||||
search_query,
|
search_query,
|
||||||
@@ -179,6 +200,25 @@ async function _refresh_site_domain_v3_background({ api_cfg, fqdn, view, log_lvl
|
|||||||
properties_to_save: properties_to_save__site_domain,
|
properties_to_save: properties_to_save__site_domain,
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// WHY: The fast-path returns stale Dexie cache, then this background refresh
|
||||||
|
// runs after the page renders. If cfg_json changed server-side (e.g. a Novi
|
||||||
|
// API key was added), the stale cfg is already in $ae_loc. We push the fresh
|
||||||
|
// cfg_json into the store here so any layout tracking it (e.g. IDAA Novi
|
||||||
|
// verification) gets notified and can retry with the correct config.
|
||||||
|
if (result.cfg_json) {
|
||||||
|
const current_cfg = get(ae_loc).site_cfg_json;
|
||||||
|
if (
|
||||||
|
JSON.stringify(current_cfg) !==
|
||||||
|
JSON.stringify(result.cfg_json)
|
||||||
|
) {
|
||||||
|
ae_loc.update((loc) => ({
|
||||||
|
...loc,
|
||||||
|
site_cfg_json: result.cfg_json
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
@@ -207,7 +247,7 @@ export async function load_ae_obj_id__site({
|
|||||||
}
|
}
|
||||||
|
|
||||||
ae_promises.load__site_obj = await api
|
ae_promises.load__site_obj = await api
|
||||||
.get_ae_obj_v3({
|
.get_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'site',
|
obj_type: 'site',
|
||||||
obj_id: site_id,
|
obj_id: site_id,
|
||||||
@@ -278,7 +318,7 @@ export async function load_ae_obj_li__site({
|
|||||||
}
|
}
|
||||||
|
|
||||||
ae_promises.load__site_obj_li = await api
|
ae_promises.load__site_obj_li = await api
|
||||||
.get_ae_obj_li_v3({
|
.get_ae_obj_li({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'site',
|
obj_type: 'site',
|
||||||
for_obj_type,
|
for_obj_type,
|
||||||
@@ -331,7 +371,7 @@ export async function create_ae_obj__site({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_Site | null> {
|
}): Promise<ae_Site | null> {
|
||||||
const result = await api.create_ae_obj_v3({
|
const result = await api.create_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'site',
|
obj_type: 'site',
|
||||||
fields: {
|
fields: {
|
||||||
@@ -375,7 +415,7 @@ export async function update_ae_obj__site({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_Site | null> {
|
}): Promise<ae_Site | null> {
|
||||||
const result = await api.update_ae_obj_v3({
|
const result = await api.update_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'site',
|
obj_type: 'site',
|
||||||
obj_id: site_id,
|
obj_id: site_id,
|
||||||
@@ -417,7 +457,7 @@ export async function delete_ae_obj_id__site({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
const result = await api.delete_ae_obj_v3({
|
const result = await api.delete_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'site',
|
obj_type: 'site',
|
||||||
obj_id: site_id,
|
obj_id: site_id,
|
||||||
@@ -464,7 +504,7 @@ export async function load_ae_obj_li__site_domain({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_SiteDomain[]> {
|
}): Promise<ae_SiteDomain[]> {
|
||||||
ae_promises.load__site_domain_li = await api
|
ae_promises.load__site_domain_li = await api
|
||||||
.get_nested_obj_li_v3({
|
.get_nested_obj_li({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
parent_type: 'site',
|
parent_type: 'site',
|
||||||
parent_id: site_id,
|
parent_id: site_id,
|
||||||
@@ -480,11 +520,12 @@ export async function load_ae_obj_li__site_domain({
|
|||||||
.then(async function (domain_li) {
|
.then(async function (domain_li) {
|
||||||
if (domain_li) {
|
if (domain_li) {
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
const processed_obj_li = await process_ae_obj__site_domain_props({
|
const processed_obj_li =
|
||||||
obj_li: domain_li,
|
await process_ae_obj__site_domain_props({
|
||||||
site_id,
|
obj_li: domain_li,
|
||||||
log_lvl
|
site_id,
|
||||||
});
|
log_lvl
|
||||||
|
});
|
||||||
await db_save_ae_obj_li__ae_obj({
|
await db_save_ae_obj_li__ae_obj({
|
||||||
db_instance: db_core,
|
db_instance: db_core,
|
||||||
table_name: 'site_domain',
|
table_name: 'site_domain',
|
||||||
@@ -518,7 +559,7 @@ export async function create_ae_obj__site_domain({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_SiteDomain | null> {
|
}): Promise<ae_SiteDomain | null> {
|
||||||
const result = await api.create_nested_obj_v3({
|
const result = await api.create_nested_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
parent_type: 'site',
|
parent_type: 'site',
|
||||||
parent_id: site_id,
|
parent_id: site_id,
|
||||||
@@ -564,7 +605,7 @@ export async function update_ae_obj__site_domain({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_SiteDomain | null> {
|
}): Promise<ae_SiteDomain | null> {
|
||||||
const result = await api.update_nested_obj_v3({
|
const result = await api.update_nested_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
parent_type: 'site',
|
parent_type: 'site',
|
||||||
parent_id: site_id,
|
parent_id: site_id,
|
||||||
@@ -611,7 +652,7 @@ export async function delete_ae_obj_id__site_domain({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
const result = await api.delete_nested_ae_obj_v3({
|
const result = await api.delete_nested_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
parent_type: 'site',
|
parent_type: 'site',
|
||||||
parent_id: site_id,
|
parent_id: site_id,
|
||||||
@@ -728,11 +769,15 @@ async function _process_generic_props<T extends Record<string, any>>({
|
|||||||
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
||||||
const name = processed_obj.name ?? processed_obj.fqdn ?? '';
|
const name = processed_obj.name ?? processed_obj.fqdn ?? '';
|
||||||
|
|
||||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
(processed_obj as any).tmp_sort_1 =
|
||||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
`${group}_${priority}_${sort}_${updated}`;
|
||||||
|
(processed_obj as any).tmp_sort_2 =
|
||||||
|
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||||
|
|
||||||
if (specific_processor) {
|
if (specific_processor) {
|
||||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
processed_obj = await Promise.resolve(
|
||||||
|
specific_processor(processed_obj)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
processed_obj_li.push(processed_obj as T);
|
processed_obj_li.push(processed_obj as T);
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export async function load_ae_obj_id__user({
|
|||||||
}
|
}
|
||||||
|
|
||||||
ae_promises.load__user_obj = await api
|
ae_promises.load__user_obj = await api
|
||||||
.get_ae_obj_v3({
|
.get_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'user',
|
obj_type: 'user',
|
||||||
obj_id: user_id,
|
obj_id: user_id,
|
||||||
@@ -93,7 +93,9 @@ export async function load_ae_obj_li__user({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_User[]> {
|
}): Promise<ae_User[]> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** load_ae_obj_li__user() *** for_obj_id=${for_obj_id} include_global=${include_global} qry_str=${qry_str}`);
|
console.log(
|
||||||
|
`*** load_ae_obj_li__user() *** for_obj_id=${for_obj_id} include_global=${include_global} qry_str=${qry_str}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// SCENARIO A: Text Search
|
// SCENARIO A: Text Search
|
||||||
@@ -107,12 +109,20 @@ export async function load_ae_obj_li__user({
|
|||||||
]
|
]
|
||||||
});
|
});
|
||||||
} else if (for_obj_id) {
|
} else if (for_obj_id) {
|
||||||
search_query.and.push({ field: `account_id_random`, op: 'eq', value: for_obj_id });
|
search_query.and.push({
|
||||||
|
field: `account_id_random`,
|
||||||
|
op: 'eq',
|
||||||
|
value: for_obj_id
|
||||||
|
});
|
||||||
} else if (include_global) {
|
} else if (include_global) {
|
||||||
search_query.and.push({ field: `account_id_random`, op: 'eq', value: null });
|
search_query.and.push({
|
||||||
|
field: `account_id_random`,
|
||||||
|
op: 'eq',
|
||||||
|
value: null
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return await api.search_ae_obj_v3({
|
return await api.search_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'user',
|
obj_type: 'user',
|
||||||
search_query,
|
search_query,
|
||||||
@@ -130,13 +140,33 @@ export async function load_ae_obj_li__user({
|
|||||||
if (for_obj_id && include_global) {
|
if (for_obj_id && include_global) {
|
||||||
if (log_lvl) console.log('Strategy: Multi-call (Account + Global)');
|
if (log_lvl) console.log('Strategy: Multi-call (Account + Global)');
|
||||||
const [acct_users, global_users] = await Promise.all([
|
const [acct_users, global_users] = await Promise.all([
|
||||||
load_ae_obj_li__user({ api_cfg, for_obj_id, include_global: false, enabled, hidden, view, limit, log_lvl }),
|
load_ae_obj_li__user({
|
||||||
load_ae_obj_li__user({ api_cfg, for_obj_id: null, include_global: true, enabled, hidden, view, limit, log_lvl })
|
api_cfg,
|
||||||
|
for_obj_id,
|
||||||
|
include_global: false,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
view,
|
||||||
|
limit,
|
||||||
|
log_lvl
|
||||||
|
}),
|
||||||
|
load_ae_obj_li__user({
|
||||||
|
api_cfg,
|
||||||
|
for_obj_id: null,
|
||||||
|
include_global: true,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
view,
|
||||||
|
limit,
|
||||||
|
log_lvl
|
||||||
|
})
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Merge and unique-ify by ID
|
// Merge and unique-ify by ID
|
||||||
const merged = [...acct_users, ...global_users];
|
const merged = [...acct_users, ...global_users];
|
||||||
const unique = Array.from(new Map(merged.map(u => [u.user_id_random, u])).values());
|
const unique = Array.from(
|
||||||
|
new Map(merged.map((u) => [u.user_id_random, u])).values()
|
||||||
|
);
|
||||||
return unique;
|
return unique;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,7 +177,7 @@ export async function load_ae_obj_li__user({
|
|||||||
const search_query = {
|
const search_query = {
|
||||||
and: [{ field: 'account_id_random', op: 'eq', value: null }]
|
and: [{ field: 'account_id_random', op: 'eq', value: null }]
|
||||||
};
|
};
|
||||||
return await api.search_ae_obj_v3({
|
return await api.search_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'user',
|
obj_type: 'user',
|
||||||
search_query,
|
search_query,
|
||||||
@@ -162,8 +192,9 @@ export async function load_ae_obj_li__user({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SCENARIO D: Account Only or Everything (confirmed working List API)
|
// SCENARIO D: Account Only or Everything (confirmed working List API)
|
||||||
if (log_lvl) console.log(`Strategy: Standard List API (for_obj_id=${for_obj_id})`);
|
if (log_lvl)
|
||||||
return await api.get_ae_obj_li_v3({
|
console.log(`Strategy: Standard List API (for_obj_id=${for_obj_id})`);
|
||||||
|
return await api.get_ae_obj_li({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'user',
|
obj_type: 'user',
|
||||||
for_obj_type: for_obj_id ? for_obj_type : undefined,
|
for_obj_type: for_obj_id ? for_obj_type : undefined,
|
||||||
@@ -197,7 +228,7 @@ export async function create_ae_obj__user({
|
|||||||
const fields: key_val = { ...data_kv };
|
const fields: key_val = { ...data_kv };
|
||||||
if (account_id) fields.account_id_random = account_id;
|
if (account_id) fields.account_id_random = account_id;
|
||||||
|
|
||||||
const result = await api.create_ae_obj_v3({
|
const result = await api.create_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'user',
|
obj_type: 'user',
|
||||||
fields,
|
fields,
|
||||||
@@ -238,7 +269,7 @@ export async function update_ae_obj__user({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_User | null> {
|
}): Promise<ae_User | null> {
|
||||||
const result = await api.update_ae_obj_v3({
|
const result = await api.update_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'user',
|
obj_type: 'user',
|
||||||
obj_id: user_id,
|
obj_id: user_id,
|
||||||
@@ -280,7 +311,7 @@ export async function delete_ae_obj_id__user({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
const result = await api.delete_ae_obj_v3({
|
const result = await api.delete_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'user',
|
obj_type: 'user',
|
||||||
obj_id: user_id,
|
obj_id: user_id,
|
||||||
@@ -383,7 +414,10 @@ export async function auth_ae_obj__username_password({
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log('ae_promises.auth__username_password:', ae_promises.auth__username_password);
|
console.log(
|
||||||
|
'ae_promises.auth__username_password:',
|
||||||
|
ae_promises.auth__username_password
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return ae_promises.auth__username_password;
|
return ae_promises.auth__username_password;
|
||||||
}
|
}
|
||||||
@@ -450,7 +484,10 @@ export async function auth_ae_obj__user_id_user_auth_key({
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log('ae_promises.auth__user_id_user_key:', ae_promises.auth__user_id_user_key);
|
console.log(
|
||||||
|
'ae_promises.auth__user_id_user_key:',
|
||||||
|
ae_promises.auth__user_id_user_key
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return ae_promises.auth__user_id_user_key;
|
return ae_promises.auth__user_id_user_key;
|
||||||
}
|
}
|
||||||
@@ -525,7 +562,9 @@ export async function qry_ae_obj_li__user_email({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** qry_ae_obj_li__user_email() *** account_id=${account_id} email=${email}`);
|
console.log(
|
||||||
|
`*** qry_ae_obj_li__user_email() *** account_id=${account_id} email=${email}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const endpoint = '/user/lookup_email';
|
const endpoint = '/user/lookup_email';
|
||||||
@@ -676,11 +715,15 @@ async function _process_generic_props<T extends Record<string, any>>({
|
|||||||
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
||||||
const name = processed_obj.username ?? processed_obj.name ?? '';
|
const name = processed_obj.username ?? processed_obj.name ?? '';
|
||||||
|
|
||||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
(processed_obj as any).tmp_sort_1 =
|
||||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
`${group}_${priority}_${sort}_${updated}`;
|
||||||
|
(processed_obj as any).tmp_sort_2 =
|
||||||
|
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||||
|
|
||||||
if (specific_processor) {
|
if (specific_processor) {
|
||||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
processed_obj = await Promise.resolve(
|
||||||
|
specific_processor(processed_obj)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
processed_obj_li.push(processed_obj as T);
|
processed_obj_li.push(processed_obj as T);
|
||||||
|
|||||||
@@ -25,7 +25,10 @@ import {
|
|||||||
auth_ae_obj__user_id_change_password
|
auth_ae_obj__user_id_change_password
|
||||||
} from '$lib/ae_core/ae_core__user';
|
} from '$lib/ae_core/ae_core__user';
|
||||||
|
|
||||||
import { generate_qr_code, js_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';
|
||||||
|
|
||||||
@@ -161,7 +164,9 @@ async function load_ae_obj_code__data_store({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!get_ds_result.data_store_id_random) {
|
if (!get_ds_result.data_store_id_random) {
|
||||||
console.log('*ae_func* Something went wrong? No data store ID found.');
|
console.log(
|
||||||
|
'*ae_func* Something went wrong? No data store ID found.'
|
||||||
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,7 +245,10 @@ async function load_ae_obj_code__data_store({
|
|||||||
get_ds_result
|
get_ds_result
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
localStorage.setItem(`${key_prefix}${code}`, JSON.stringify(get_ds_result));
|
localStorage.setItem(
|
||||||
|
`${key_prefix}${code}`,
|
||||||
|
JSON.stringify(get_ds_result)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(
|
console.log(
|
||||||
@@ -327,102 +335,102 @@ async function update_ae_obj_id_crud({
|
|||||||
return ae_promises.api_update__ae_obj;
|
return ae_promises.api_update__ae_obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Core - Already imported above
|
// // Core - Already imported above
|
||||||
// import { load_ae_obj_id__person } from "$lib/ae_core/core__person";
|
// // import { load_ae_obj_id__person } from "$lib/ae_core/core__person";
|
||||||
// import { load_ae_obj_id__user } from "$lib/ae_core/core__user";
|
// // import { load_ae_obj_id__user } from "$lib/ae_core/core__user";
|
||||||
|
|
||||||
// Additional Modules
|
// // Additional Modules
|
||||||
import { load_ae_obj_id__archive } from '$lib/ae_archives/ae_archives__archive';
|
// 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__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 } 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_badge } from "$lib/ae_events/ae_events__event_badge";
|
||||||
import { load_ae_obj_id__event_exhibit } from '$lib/ae_events/ae_events__exhibit';
|
// import { load_ae_obj_id__event_exhibit } from '$lib/ae_events/ae_events__exhibit';
|
||||||
import { load_ae_obj_id__event_device } from '$lib/ae_events/ae_events__event_device';
|
// 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_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_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_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_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_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__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 } 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__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 } 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__post_comment } from '$lib/ae_posts/ae_posts__post_comment';
|
||||||
|
|
||||||
// Updated 2025-09-30
|
// Updated 2025-09-30
|
||||||
async function update_ae_obj_id_crud_v2({
|
// async function update_ae_obj_id_crud_v2({
|
||||||
api_cfg,
|
// api_cfg,
|
||||||
object_type,
|
// object_type,
|
||||||
object_id,
|
// object_id,
|
||||||
object_reload = false,
|
// object_reload = false,
|
||||||
field_name,
|
// field_name,
|
||||||
new_field_value,
|
// new_field_value,
|
||||||
params = {},
|
// params = {},
|
||||||
log_lvl = 0
|
// log_lvl = 0
|
||||||
}: {
|
// }: {
|
||||||
api_cfg: any;
|
// api_cfg: any;
|
||||||
object_type: string;
|
// object_type: string;
|
||||||
object_id: string;
|
// object_id: string;
|
||||||
object_reload?: boolean;
|
// object_reload?: boolean;
|
||||||
field_name: string;
|
// field_name: string;
|
||||||
new_field_value: any;
|
// new_field_value: any;
|
||||||
params?: any | key_val;
|
// params?: any | key_val;
|
||||||
log_lvl?: number;
|
// log_lvl?: number;
|
||||||
}) {
|
// }) {
|
||||||
if (log_lvl) {
|
// if (log_lvl) {
|
||||||
console.log(
|
// 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=`,
|
// `*** 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
|
// new_field_value
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
|
|
||||||
const results = await api.update_ae_obj_id_crud({
|
// const results = await api.update_ae_obj_id_crud({
|
||||||
api_cfg: api_cfg,
|
// api_cfg: api_cfg,
|
||||||
obj_type: object_type,
|
// obj_type: object_type,
|
||||||
obj_id: object_id,
|
// obj_id: object_id,
|
||||||
field_name: field_name,
|
// field_name: field_name,
|
||||||
field_value: new_field_value,
|
// field_value: new_field_value,
|
||||||
key: api_cfg.api_crud_super_key,
|
// key: api_cfg.api_crud_super_key,
|
||||||
log_lvl: log_lvl
|
// log_lvl: log_lvl
|
||||||
});
|
// });
|
||||||
|
|
||||||
if (results) {
|
// if (results) {
|
||||||
if (log_lvl) {
|
// if (log_lvl) {
|
||||||
console.log(`Patched - Field Name: ${field_name} with new Field Value: ${new_field_value}`);
|
// console.log(`Patched - Field Name: ${field_name} with new Field Value: ${new_field_value}`);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (object_reload) {
|
// if (object_reload) {
|
||||||
if (log_lvl) {
|
// if (log_lvl) {
|
||||||
console.log(`Reloading the object after patching...`);
|
// console.log(`Reloading the object after patching...`);
|
||||||
}
|
// }
|
||||||
// Trigger reloads based on object type. These are fire-and-forget or awaited internally by the library functions.
|
// // Trigger reloads based on object type. These are fire-and-forget or awaited internally by the library functions.
|
||||||
if (object_type == 'person') load_ae_obj_id__person({ api_cfg, person_id: object_id, log_lvl });
|
// if (object_type == 'person') load_ae_obj_id__person({ api_cfg, person_id: object_id, log_lvl });
|
||||||
if (object_type == 'archive') load_ae_obj_id__archive({ api_cfg, archive_id: object_id, log_lvl });
|
// if (object_type == 'archive') load_ae_obj_id__archive({ api_cfg, archive_id: object_id, log_lvl });
|
||||||
if (object_type == 'archive_content') load_ae_obj_id__archive_content({ api_cfg, archive_content_id: object_id, log_lvl });
|
// if (object_type == 'archive_content') load_ae_obj_id__archive_content({ api_cfg, archive_content_id: object_id, log_lvl });
|
||||||
if (object_type == 'journal') load_ae_obj_id__journal({ api_cfg, journal_id: object_id, log_lvl });
|
// if (object_type == 'journal') load_ae_obj_id__journal({ api_cfg, journal_id: object_id, log_lvl });
|
||||||
if (object_type == 'journal_entry') load_ae_obj_id__journal_entry({ api_cfg, journal_entry_id: object_id, log_lvl });
|
// if (object_type == 'journal_entry') load_ae_obj_id__journal_entry({ api_cfg, journal_entry_id: object_id, log_lvl });
|
||||||
if (object_type == 'event') load_ae_obj_id__event({ api_cfg, event_id: object_id, log_lvl });
|
// if (object_type == 'event') load_ae_obj_id__event({ api_cfg, event_id: object_id, log_lvl });
|
||||||
if (object_type == 'event_exhibit') load_ae_obj_id__event_exhibit({ api_cfg, exhibit_id: object_id, log_lvl });
|
// if (object_type == 'event_exhibit') load_ae_obj_id__event_exhibit({ api_cfg, exhibit_id: object_id, log_lvl });
|
||||||
if (object_type == 'event_device') load_ae_obj_id__event_device({ api_cfg, event_device_id: object_id, log_lvl });
|
// if (object_type == 'event_device') load_ae_obj_id__event_device({ api_cfg, event_device_id: object_id, log_lvl });
|
||||||
if (object_type == 'event_file') load_ae_obj_id__event_file({ api_cfg, event_file_id: object_id, log_lvl });
|
// if (object_type == 'event_file') load_ae_obj_id__event_file({ api_cfg, event_file_id: object_id, log_lvl });
|
||||||
if (object_type == 'event_location') load_ae_obj_id__event_location({ api_cfg, event_location_id: object_id, log_lvl });
|
// if (object_type == 'event_location') load_ae_obj_id__event_location({ api_cfg, event_location_id: object_id, log_lvl });
|
||||||
if (object_type == 'event_presentation') load_ae_obj_id__event_presentation({ api_cfg, event_presentation_id: object_id, log_lvl });
|
// if (object_type == 'event_presentation') load_ae_obj_id__event_presentation({ api_cfg, event_presentation_id: object_id, log_lvl });
|
||||||
if (object_type == 'event_presenter') load_ae_obj_id__event_presenter({ api_cfg, event_presenter_id: object_id, log_lvl });
|
// if (object_type == 'event_presenter') load_ae_obj_id__event_presenter({ api_cfg, event_presenter_id: object_id, log_lvl });
|
||||||
if (object_type == 'event_session') load_ae_obj_id__event_session({ api_cfg, event_session_id: object_id, log_lvl });
|
// if (object_type == 'event_session') load_ae_obj_id__event_session({ api_cfg, event_session_id: object_id, log_lvl });
|
||||||
if (object_type == 'post') load_ae_obj_id__post({ api_cfg, post_id: object_id, log_lvl });
|
// if (object_type == 'post') load_ae_obj_id__post({ api_cfg, post_id: object_id, log_lvl });
|
||||||
if (object_type == 'post_comment') load_ae_obj_id__post_comment({ api_cfg, post_comment_id: object_id, log_lvl });
|
// if (object_type == 'post_comment') load_ae_obj_id__post_comment({ api_cfg, post_comment_id: object_id, log_lvl });
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
if (log_lvl) {
|
// if (log_lvl) {
|
||||||
console.log(`PATCH failed for ${object_type} ${object_id}`);
|
// console.log(`PATCH failed for ${object_type} ${object_id}`);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
return results;
|
// return results;
|
||||||
}
|
// }
|
||||||
|
|
||||||
async function download_export__obj_type({
|
async function download_export__obj_type({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
@@ -491,7 +499,10 @@ async function download_export__obj_type({
|
|||||||
log_lvl: log_lvl
|
log_lvl: log_lvl
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('ae_promises.download__export_file:', ae_promises.download__export_file);
|
console.log(
|
||||||
|
'ae_promises.download__export_file:',
|
||||||
|
ae_promises.download__export_file
|
||||||
|
);
|
||||||
return ae_promises.download__export_file;
|
return ae_promises.download__export_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -533,7 +544,7 @@ const export_obj = {
|
|||||||
auth_ae_obj__user_id_change_password: auth_ae_obj__user_id_change_password,
|
auth_ae_obj__user_id_change_password: auth_ae_obj__user_id_change_password,
|
||||||
|
|
||||||
update_ae_obj_id_crud: update_ae_obj_id_crud,
|
update_ae_obj_id_crud: update_ae_obj_id_crud,
|
||||||
update_ae_obj_id_crud_v2: update_ae_obj_id_crud_v2,
|
// update_ae_obj_id_crud_v2: update_ae_obj_id_crud_v2,
|
||||||
download_export__obj_type: download_export__obj_type,
|
download_export__obj_type: download_export__obj_type,
|
||||||
generate_qr_code: generate_qr_code,
|
generate_qr_code: generate_qr_code,
|
||||||
js_generate_qr_code: js_generate_qr_code
|
js_generate_qr_code: js_generate_qr_code
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
@@ -13,12 +13,17 @@ export function add_url_params({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** add_url_params() *** base_url=${base_url} endpoint=${endpoint}`, params);
|
console.log(
|
||||||
|
`*** add_url_params() *** base_url=${base_url} endpoint=${endpoint}`,
|
||||||
|
params
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const url_obj = new URL(endpoint, base_url);
|
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) {
|
if (log_lvl) {
|
||||||
console.log('New URL:', url_obj.toString());
|
console.log('New URL:', url_obj.toString());
|
||||||
@@ -30,7 +35,13 @@ export function add_url_params({
|
|||||||
|
|
||||||
// This is used to clean the header property names. Not underscores allowed in the header names.
|
// This is used to clean the header property names. Not underscores allowed in the header names.
|
||||||
// Updated 2025-01-28
|
// 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) {
|
if (log_lvl) {
|
||||||
console.log(`*** clean_headers() ***`, headers);
|
console.log(`*** clean_headers() ***`, headers);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import type { key_val } from '$lib/stores/ae_stores';
|
import type { key_val } from '$lib/stores/ae_stores';
|
||||||
import { api } from '$lib/api/api';
|
import { api } from '$lib/api/api';
|
||||||
|
|
||||||
// Updated 2024-10-02
|
// Updated 2026-03-25
|
||||||
export async function check_hosted_file_obj_w_hash({
|
export async function check_hosted_file_obj_w_hash({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
hosted_file_hash,
|
hosted_file_hash,
|
||||||
@@ -19,7 +19,7 @@ export async function check_hosted_file_obj_w_hash({
|
|||||||
}) {
|
}) {
|
||||||
console.log('*** stores_event_api.js: check_hosted_file_obj_w_hash() ***');
|
console.log('*** stores_event_api.js: check_hosted_file_obj_w_hash() ***');
|
||||||
|
|
||||||
const endpoint = `/hosted_file/hash/${hosted_file_hash}`;
|
const endpoint = `/v3/action/hosted_file/hash/${hosted_file_hash}`;
|
||||||
if (check_for_local) {
|
if (check_for_local) {
|
||||||
params['check_for_local'] = true;
|
params['check_for_local'] = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,65 +1,72 @@
|
|||||||
import type { key_val } from '$lib/stores/ae_stores';
|
|
||||||
import { api } from '$lib/api/api';
|
import { api } from '$lib/api/api';
|
||||||
|
import { db_lookups, LOOKUP_TTL_MS } from '$lib/ae_core/db_lookups';
|
||||||
|
|
||||||
import { db_core } from '$lib/ae_core/db_core';
|
/**
|
||||||
|
* Country lookup — IDB-backed SWR helper.
|
||||||
|
*
|
||||||
|
* Calling this function triggers a background API refresh if IDB is empty or
|
||||||
|
* older than 24 hours. The function returns immediately without awaiting the
|
||||||
|
* refresh. Components subscribe to db_lookups.lu_country via liveQuery and
|
||||||
|
* receive automatic updates when the refresh completes.
|
||||||
|
*
|
||||||
|
* Updated 2026-03-23 — replaced localStorage pattern with IDB + 24h TTL
|
||||||
|
*/
|
||||||
|
|
||||||
const ae_promises: key_val = {};
|
async function _refresh_lu_country_background({
|
||||||
|
|
||||||
// Updated 2024-10-14
|
|
||||||
export async function load_ae_obj_li__country({
|
|
||||||
api_cfg,
|
api_cfg,
|
||||||
// account_id,
|
|
||||||
enabled = 'enabled',
|
|
||||||
hidden = 'not_hidden',
|
|
||||||
limit = 275, // There are roughly 249 as of 2026-02
|
|
||||||
offset = 0,
|
|
||||||
order_by_li = { sort: 'DESC', english_short_name: 'ASC', alpha_2_code: 'ASC' } as const,
|
|
||||||
params = {},
|
|
||||||
try_cache = true,
|
|
||||||
log_lvl = 0
|
log_lvl = 0
|
||||||
}: {
|
}: {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
api_cfg: any;
|
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;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
if (log_lvl) {
|
if (log_lvl) console.log('*** _refresh_lu_country_background() ***');
|
||||||
console.log(`*** load_ae_obj_li__country() ***`);
|
try {
|
||||||
}
|
const result = await api.get_ae_obj_li_for_lu({
|
||||||
|
api_cfg,
|
||||||
const params_json: key_val = {};
|
|
||||||
|
|
||||||
// console.log('params_json:', params_json);
|
|
||||||
|
|
||||||
ae_promises.load__country_li = await api
|
|
||||||
.get_ae_obj_li_for_lu({
|
|
||||||
api_cfg: api_cfg,
|
|
||||||
for_lu_type: 'country',
|
for_lu_type: 'country',
|
||||||
enabled: enabled,
|
enabled: 'enabled',
|
||||||
hidden: hidden,
|
hidden: 'not_hidden',
|
||||||
limit: limit,
|
limit: 275,
|
||||||
offset: offset,
|
log_lvl
|
||||||
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: any) {
|
|
||||||
console.log('No results returned or failed.', error);
|
|
||||||
});
|
});
|
||||||
|
if (result?.length) {
|
||||||
console.log('ae_promises.load__country_li:', ae_promises.load__country_li);
|
await db_lookups.lu_country.clear();
|
||||||
return ae_promises.load__country_li;
|
await db_lookups.lu_country.bulkPut(result);
|
||||||
|
await db_lookups.lu_cache_meta.put({
|
||||||
|
lu_type: 'country',
|
||||||
|
refreshed_at: Date.now()
|
||||||
|
});
|
||||||
|
if (log_lvl)
|
||||||
|
console.log(
|
||||||
|
`lu_country: saved ${result.length} records to IDB`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('lu_country refresh failed:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function load_ae_obj_li__country({
|
||||||
|
api_cfg,
|
||||||
|
log_lvl = 0
|
||||||
|
}: {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
api_cfg: any;
|
||||||
|
log_lvl?: number;
|
||||||
|
}) {
|
||||||
|
if (log_lvl) console.log('*** load_ae_obj_li__country() ***');
|
||||||
|
|
||||||
|
const count = await db_lookups.lu_country.count();
|
||||||
|
const meta = await db_lookups.lu_cache_meta.get('country');
|
||||||
|
const is_stale = !meta || Date.now() - meta.refreshed_at > LOOKUP_TTL_MS;
|
||||||
|
|
||||||
|
if (count === 0 || is_stale) {
|
||||||
|
// Fire-and-forget — liveQuery subscribers receive updates when IDB is written
|
||||||
|
_refresh_lu_country_background({ api_cfg, log_lvl });
|
||||||
|
} else if (log_lvl) {
|
||||||
|
console.log(
|
||||||
|
`lu_country: IDB fresh (${count} records), skipping refresh`
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,68 +1,71 @@
|
|||||||
import type { key_val } from '$lib/stores/ae_stores';
|
|
||||||
import { api } from '$lib/api/api';
|
import { api } from '$lib/api/api';
|
||||||
|
import { db_lookups, LOOKUP_TTL_MS } from '$lib/ae_core/db_lookups';
|
||||||
|
|
||||||
import { db_core } from '$lib/ae_core/db_core';
|
/**
|
||||||
|
* Country subdivision lookup — IDB-backed SWR helper.
|
||||||
|
*
|
||||||
|
* Calling this function triggers a background API refresh if IDB is empty or
|
||||||
|
* older than 24 hours. Components subscribe to db_lookups.lu_country_subdivision
|
||||||
|
* via liveQuery and receive automatic updates when the refresh completes.
|
||||||
|
*
|
||||||
|
* Updated 2026-03-23 — replaced localStorage pattern with IDB + 24h TTL
|
||||||
|
*/
|
||||||
|
|
||||||
const ae_promises: key_val = {};
|
async function _refresh_lu_country_subdivision_background({
|
||||||
|
|
||||||
// Updated 2024-10-14
|
|
||||||
export async function load_ae_obj_li__country_subdivision({
|
|
||||||
api_cfg,
|
api_cfg,
|
||||||
// account_id,
|
|
||||||
enabled = 'enabled',
|
|
||||||
hidden = 'not_hidden',
|
|
||||||
limit = 3500, // There are roughly 3434 as of 2026-02
|
|
||||||
offset = 0,
|
|
||||||
order_by_li = { sort: 'DESC', name: 'ASC', code: 'ASC' } as const,
|
|
||||||
params = {},
|
|
||||||
try_cache = true,
|
|
||||||
log_lvl = 0
|
log_lvl = 0
|
||||||
}: {
|
}: {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
api_cfg: any;
|
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;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
if (log_lvl) {
|
if (log_lvl)
|
||||||
console.log(`*** load_ae_obj_li__country_subdivision() ***`);
|
console.log('*** _refresh_lu_country_subdivision_background() ***');
|
||||||
}
|
try {
|
||||||
|
const result = await api.get_ae_obj_li_for_lu({
|
||||||
const params_json: key_val = {};
|
api_cfg,
|
||||||
|
|
||||||
// console.log('params_json:', params_json);
|
|
||||||
|
|
||||||
ae_promises.load__country_subdivision_li = await api
|
|
||||||
.get_ae_obj_li_for_lu({
|
|
||||||
api_cfg: api_cfg,
|
|
||||||
for_lu_type: 'country_subdivision',
|
for_lu_type: 'country_subdivision',
|
||||||
enabled: enabled,
|
enabled: 'enabled',
|
||||||
hidden: hidden,
|
hidden: 'not_hidden',
|
||||||
limit: limit,
|
limit: 3500,
|
||||||
offset: offset,
|
log_lvl
|
||||||
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: any) {
|
|
||||||
console.log('No results returned or failed.', error);
|
|
||||||
});
|
});
|
||||||
|
if (result?.length) {
|
||||||
console.log(
|
await db_lookups.lu_country_subdivision.clear();
|
||||||
'ae_promises.load__country_subdivision_li:',
|
await db_lookups.lu_country_subdivision.bulkPut(result);
|
||||||
ae_promises.load__country_subdivision_li
|
await db_lookups.lu_cache_meta.put({
|
||||||
);
|
lu_type: 'country_subdivision',
|
||||||
return ae_promises.load__country_subdivision_li;
|
refreshed_at: Date.now()
|
||||||
|
});
|
||||||
|
if (log_lvl)
|
||||||
|
console.log(
|
||||||
|
`lu_country_subdivision: saved ${result.length} records to IDB`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('lu_country_subdivision refresh failed:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function load_ae_obj_li__country_subdivision({
|
||||||
|
api_cfg,
|
||||||
|
log_lvl = 0
|
||||||
|
}: {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
api_cfg: any;
|
||||||
|
log_lvl?: number;
|
||||||
|
}) {
|
||||||
|
if (log_lvl) console.log('*** load_ae_obj_li__country_subdivision() ***');
|
||||||
|
|
||||||
|
const count = await db_lookups.lu_country_subdivision.count();
|
||||||
|
const meta = await db_lookups.lu_cache_meta.get('country_subdivision');
|
||||||
|
const is_stale = !meta || Date.now() - meta.refreshed_at > LOOKUP_TTL_MS;
|
||||||
|
|
||||||
|
if (count === 0 || is_stale) {
|
||||||
|
_refresh_lu_country_subdivision_background({ api_cfg, log_lvl });
|
||||||
|
} else if (log_lvl) {
|
||||||
|
console.log(
|
||||||
|
`lu_country_subdivision: IDB fresh (${count} records), skipping refresh`
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,351 +0,0 @@
|
|||||||
import { marked } from 'marked';
|
|
||||||
|
|
||||||
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';
|
|
||||||
|
|
||||||
// Define generic CRUD args
|
|
||||||
export interface GenericCrudArgs {
|
|
||||||
api_cfg: any;
|
|
||||||
obj_type: string;
|
|
||||||
obj_id?: string;
|
|
||||||
for_obj_type?: string;
|
|
||||||
for_obj_id?: string;
|
|
||||||
|
|
||||||
db_instance?: any; // Optional DB instance for caching
|
|
||||||
db_field_li?: string[]; // Optional list of fields to save in DB
|
|
||||||
|
|
||||||
// Flags to include related core object models
|
|
||||||
inc_account_li?: boolean;
|
|
||||||
inc_address_li?: boolean;
|
|
||||||
inc_contact_li?: boolean;
|
|
||||||
inc_person_li?: boolean;
|
|
||||||
inc_site_li?: boolean;
|
|
||||||
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;
|
|
||||||
inc_event_li?: boolean;
|
|
||||||
inc_event_session_li?: boolean;
|
|
||||||
inc_post_li?: boolean;
|
|
||||||
inc_post_comment_li?: boolean;
|
|
||||||
inc_journal_li?: boolean;
|
|
||||||
inc_journal_entry_li?: boolean;
|
|
||||||
|
|
||||||
inc_obj_type_li?: string[]; // Optional list of object types to include
|
|
||||||
|
|
||||||
data_kv?: key_val;
|
|
||||||
enabled?: 'enabled' | 'not_enabled' | 'all';
|
|
||||||
hidden?: 'not_hidden' | 'hidden' | 'all';
|
|
||||||
method?: string;
|
|
||||||
limit?: number;
|
|
||||||
offset?: number;
|
|
||||||
order_by_li?: Record<string, 'ASC' | 'DESC'> | Record<string, 'ASC' | 'DESC'>[] | null;
|
|
||||||
params?: key_val;
|
|
||||||
try_cache?: boolean;
|
|
||||||
log_lvl?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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, log_lvl = 0 } = args;
|
|
||||||
|
|
||||||
if (!obj_id) {
|
|
||||||
if (log_lvl) console.warn('load_ae_obj_id called without obj_id');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log(`*** load_ae_obj_id() *** obj_type=${obj_type} obj_id=${obj_id}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await api.get_ae_obj_id_crud({
|
|
||||||
api_cfg,
|
|
||||||
obj_type,
|
|
||||||
obj_id,
|
|
||||||
params: {},
|
|
||||||
log_lvl
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generic function: Load list of objects
|
|
||||||
export async function load_ae_obj_li(args: GenericCrudArgs): Promise<any> {
|
|
||||||
const {
|
|
||||||
api_cfg,
|
|
||||||
obj_type,
|
|
||||||
for_obj_type = '',
|
|
||||||
for_obj_id,
|
|
||||||
inc_obj_type_li,
|
|
||||||
enabled = 'enabled',
|
|
||||||
hidden = 'not_hidden',
|
|
||||||
limit = 99,
|
|
||||||
offset = 0,
|
|
||||||
order_by_li = {},
|
|
||||||
params = {},
|
|
||||||
try_cache = true,
|
|
||||||
log_lvl = 0
|
|
||||||
} = 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}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const params_json: key_val = {};
|
|
||||||
|
|
||||||
const result = await api.get_ae_obj_li_for_obj_id_crud_v2({
|
|
||||||
api_cfg,
|
|
||||||
obj_type,
|
|
||||||
for_obj_type,
|
|
||||||
for_obj_id: for_obj_id ?? '',
|
|
||||||
enabled,
|
|
||||||
hidden,
|
|
||||||
order_by_li,
|
|
||||||
limit,
|
|
||||||
offset,
|
|
||||||
params_json: {},
|
|
||||||
params,
|
|
||||||
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, log_lvl = 0 } = args;
|
|
||||||
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log(`*** create_ae_obj() *** obj_type=${obj_type}`, data_kv);
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await api.create_ae_obj_crud({
|
|
||||||
api_cfg,
|
|
||||||
obj_type,
|
|
||||||
fields: data_kv,
|
|
||||||
key: api_cfg.api_crud_super_key,
|
|
||||||
params: {},
|
|
||||||
return_obj: true,
|
|
||||||
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, log_lvl = 0 } = args;
|
|
||||||
|
|
||||||
if (!obj_id) {
|
|
||||||
if (log_lvl) console.warn('update_ae_obj called without obj_id');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log(`*** update_ae_obj() *** obj_type=${obj_type} obj_id=${obj_id}`, data_kv);
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await api.update_ae_obj_id_crud({
|
|
||||||
api_cfg,
|
|
||||||
obj_type,
|
|
||||||
obj_id,
|
|
||||||
fields: data_kv,
|
|
||||||
key: api_cfg.api_crud_super_key,
|
|
||||||
params: {},
|
|
||||||
return_obj: true,
|
|
||||||
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', log_lvl = 0 } = args;
|
|
||||||
|
|
||||||
if (!obj_id) {
|
|
||||||
if (log_lvl) console.warn('delete_ae_obj_id called without obj_id');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log(`*** delete_ae_obj_id() *** obj_type=${obj_type} obj_id=${obj_id}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await api.delete_ae_obj_id_crud({
|
|
||||||
api_cfg,
|
|
||||||
obj_type,
|
|
||||||
obj_id,
|
|
||||||
key: api_cfg.api_crud_super_key,
|
|
||||||
params: {},
|
|
||||||
method,
|
|
||||||
log_lvl
|
|
||||||
});
|
|
||||||
|
|
||||||
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/ae_core__person';
|
|
||||||
|
|
||||||
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
|
|
||||||
}: {
|
|
||||||
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(
|
|
||||||
`*** 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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
if (log_lvl) console.log(
|
|
||||||
`Not Patched - Field Name: ${field_name} with new Field Value: ${new_field_value}; Account ID: ${api_cfg.account_id}`
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (log_lvl) 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 clean_filename = filename.replace(/[^a-zA-Z0-9\[\]-_.]/gi, '_');
|
|
||||||
|
|
||||||
if (limit >= 0) {
|
|
||||||
params['limit'] = limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
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('download_result:', download_result);
|
|
||||||
return download_result;
|
|
||||||
}
|
|
||||||
@@ -39,7 +39,7 @@ export async function load_ae_obj_by_code__data_store({
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const get_ds_result = await api.get_data_store_v3({
|
const get_ds_result = await api.get_data_store({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
code,
|
code,
|
||||||
log_lvl
|
log_lvl
|
||||||
@@ -50,16 +50,24 @@ export async function load_ae_obj_by_code__data_store({
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ds_id = get_ds_result.data_store_id_random || get_ds_result.id_random;
|
const ds_id =
|
||||||
|
get_ds_result.data_store_id_random || get_ds_result.id_random;
|
||||||
|
|
||||||
if (!ds_id) {
|
if (!ds_id) {
|
||||||
if (log_lvl) console.log('*ae_func* Something went wrong? No data store ID found.');
|
if (log_lvl)
|
||||||
|
console.log(
|
||||||
|
'*ae_func* Something went wrong? No data store ID found.'
|
||||||
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map content fields for convenience
|
// Map content fields for convenience
|
||||||
const text_val = get_ds_result.text || '';
|
const text_val = get_ds_result.text || '';
|
||||||
const json_val = get_ds_result.json || (get_ds_result.json_str ? JSON.parse(get_ds_result.json_str) : null);
|
const json_val =
|
||||||
|
get_ds_result.json ||
|
||||||
|
(get_ds_result.json_str
|
||||||
|
? JSON.parse(get_ds_result.json_str)
|
||||||
|
: null);
|
||||||
|
|
||||||
const mapped_ds: ae_DataStore = {
|
const mapped_ds: ae_DataStore = {
|
||||||
...get_ds_result,
|
...get_ds_result,
|
||||||
@@ -77,7 +85,6 @@ export async function load_ae_obj_by_code__data_store({
|
|||||||
if (data_type === 'html') return mapped_ds.html;
|
if (data_type === 'html') return mapped_ds.html;
|
||||||
if (data_type === 'json') return mapped_ds.json;
|
if (data_type === 'json') return mapped_ds.json;
|
||||||
return mapped_ds.text;
|
return mapped_ds.text;
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (log_lvl) console.error('*ae_func* Fetch failed.', error);
|
if (log_lvl) console.error('*ae_func* Fetch failed.', error);
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -22,11 +22,13 @@ export async function load_ae_obj_id__hosted_file({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_HostedFile | null> {
|
}): Promise<ae_HostedFile | null> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** load_ae_obj_id__hosted_file() *** [V3] id=${hosted_file_id}`);
|
console.log(
|
||||||
|
`*** load_ae_obj_id__hosted_file() *** [V3] id=${hosted_file_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ae_promises.load__hosted_file_obj = await api.get_ae_obj_v3({
|
ae_promises.load__hosted_file_obj = await api.get_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'hosted_file',
|
obj_type: 'hosted_file',
|
||||||
obj_id: hosted_file_id,
|
obj_id: hosted_file_id,
|
||||||
@@ -36,10 +38,11 @@ export async function load_ae_obj_id__hosted_file({
|
|||||||
|
|
||||||
if (ae_promises.load__hosted_file_obj) {
|
if (ae_promises.load__hosted_file_obj) {
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
const processed_obj_li = await process_ae_obj__hosted_file_props({
|
const processed_obj_li =
|
||||||
obj_li: [ae_promises.load__hosted_file_obj],
|
await process_ae_obj__hosted_file_props({
|
||||||
log_lvl
|
obj_li: [ae_promises.load__hosted_file_obj],
|
||||||
});
|
log_lvl
|
||||||
|
});
|
||||||
await db_save_ae_obj_li__ae_obj({
|
await db_save_ae_obj_li__ae_obj({
|
||||||
db_instance: db_core,
|
db_instance: db_core,
|
||||||
table_name: 'file',
|
table_name: 'file',
|
||||||
@@ -49,12 +52,14 @@ export async function load_ae_obj_id__hosted_file({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (try_cache) {
|
} else if (try_cache) {
|
||||||
ae_promises.load__hosted_file_obj = await db_core.file.get(hosted_file_id);
|
ae_promises.load__hosted_file_obj =
|
||||||
|
await db_core.file.get(hosted_file_id);
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.log('V3 Request failed.', error);
|
console.log('V3 Request failed.', error);
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
ae_promises.load__hosted_file_obj = await db_core.file.get(hosted_file_id);
|
ae_promises.load__hosted_file_obj =
|
||||||
|
await db_core.file.get(hosted_file_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,11 +95,13 @@ export async function load_ae_obj_li__hosted_file({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_HostedFile[]> {
|
}): Promise<ae_HostedFile[]> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** load_ae_obj_li__hosted_file() *** [V3] for=${for_obj_type}:${for_obj_id}`);
|
console.log(
|
||||||
|
`*** load_ae_obj_li__hosted_file() *** [V3] for=${for_obj_type}:${for_obj_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ae_promises.load__hosted_file_obj_li = await api.get_ae_obj_li_v3({
|
ae_promises.load__hosted_file_obj_li = await api.get_ae_obj_li({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'hosted_file',
|
obj_type: 'hosted_file',
|
||||||
for_obj_type,
|
for_obj_type,
|
||||||
@@ -109,10 +116,11 @@ export async function load_ae_obj_li__hosted_file({
|
|||||||
|
|
||||||
if (ae_promises.load__hosted_file_obj_li) {
|
if (ae_promises.load__hosted_file_obj_li) {
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
const processed_obj_li = await process_ae_obj__hosted_file_props({
|
const processed_obj_li =
|
||||||
obj_li: ae_promises.load__hosted_file_obj_li,
|
await process_ae_obj__hosted_file_props({
|
||||||
log_lvl
|
obj_li: ae_promises.load__hosted_file_obj_li,
|
||||||
});
|
log_lvl
|
||||||
|
});
|
||||||
await db_save_ae_obj_li__ae_obj({
|
await db_save_ae_obj_li__ae_obj({
|
||||||
db_instance: db_core,
|
db_instance: db_core,
|
||||||
table_name: 'file',
|
table_name: 'file',
|
||||||
@@ -123,14 +131,16 @@ export async function load_ae_obj_li__hosted_file({
|
|||||||
}
|
}
|
||||||
} else if (try_cache) {
|
} else if (try_cache) {
|
||||||
ae_promises.load__hosted_file_obj_li = await db_core.file
|
ae_promises.load__hosted_file_obj_li = await db_core.file
|
||||||
.where('for_id').equals(for_obj_id)
|
.where('for_id')
|
||||||
|
.equals(for_obj_id)
|
||||||
.toArray();
|
.toArray();
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.log('V3 List Request failed.', error);
|
console.log('V3 List Request failed.', error);
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
ae_promises.load__hosted_file_obj_li = await db_core.file
|
ae_promises.load__hosted_file_obj_li = await db_core.file
|
||||||
.where('for_id').equals(for_obj_id)
|
.where('for_id')
|
||||||
|
.equals(for_obj_id)
|
||||||
.toArray();
|
.toArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,7 +169,9 @@ export async function delete_ae_obj_id__hosted_file({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** delete_ae_obj_id__hosted_file() *** [Special] id=${hosted_file_id}`);
|
console.log(
|
||||||
|
`*** delete_ae_obj_id__hosted_file() *** [Special] id=${hosted_file_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the specialized hosted file delete endpoint
|
// Use the specialized hosted file delete endpoint
|
||||||
@@ -203,7 +215,9 @@ export async function download_ae_obj_id__hosted_file({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** download_ae_obj_id__hosted_file() *** id=${hosted_file_id}`);
|
console.log(
|
||||||
|
`*** download_ae_obj_id__hosted_file() *** id=${hosted_file_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const task_id = hosted_file_id;
|
const task_id = hosted_file_id;
|
||||||
@@ -290,11 +304,15 @@ async function _process_generic_props<T extends Record<string, any>>({
|
|||||||
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
||||||
const name = processed_obj.name ?? '';
|
const name = processed_obj.name ?? '';
|
||||||
|
|
||||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
(processed_obj as any).tmp_sort_1 =
|
||||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
`${group}_${priority}_${sort}_${updated}`;
|
||||||
|
(processed_obj as any).tmp_sort_2 =
|
||||||
|
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||||
|
|
||||||
if (specific_processor) {
|
if (specific_processor) {
|
||||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
processed_obj = await Promise.resolve(
|
||||||
|
specific_processor(processed_obj)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
processed_obj_li.push(processed_obj as T);
|
processed_obj_li.push(processed_obj as T);
|
||||||
|
|||||||
@@ -115,7 +115,9 @@ export async function db_save_ae_obj_li__ae_obj<T extends Record<string, any>>({
|
|||||||
|
|
||||||
if (data_to_save.length === 0) {
|
if (data_to_save.length === 0) {
|
||||||
if (log_lvl > 0) {
|
if (log_lvl > 0) {
|
||||||
console.warn('All objects were skipped, likely due to missing IDs.');
|
console.warn(
|
||||||
|
'All objects were skipped, likely due to missing IDs.'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -124,7 +126,9 @@ export async function db_save_ae_obj_li__ae_obj<T extends Record<string, any>>({
|
|||||||
// bulkPut efficiently handles both inserts and updates.
|
// bulkPut efficiently handles both inserts and updates.
|
||||||
const keys = await db_table.bulkPut(data_to_save);
|
const keys = await db_table.bulkPut(data_to_save);
|
||||||
if (log_lvl > 0) {
|
if (log_lvl > 0) {
|
||||||
console.log(`Successfully saved ${data_to_save.length} objects to "${table_name}".`);
|
console.log(
|
||||||
|
`Successfully saved ${data_to_save.length} objects to "${table_name}".`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return keys;
|
return keys;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -1,736 +0,0 @@
|
|||||||
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';
|
|
||||||
|
|
||||||
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;
|
|
||||||
}) {
|
|
||||||
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
|
|
||||||
})
|
|
||||||
.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.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// // 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;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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?: '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}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
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'] = [];
|
|
||||||
|
|
||||||
const qry_param = {
|
|
||||||
type: 'AND',
|
|
||||||
field: 'user_id_random',
|
|
||||||
operator: '=',
|
|
||||||
value: qry_user_id
|
|
||||||
};
|
|
||||||
params_json['qry'].push(qry_param);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (log_lvl) {
|
|
||||||
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
|
|
||||||
})
|
|
||||||
.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.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 [];
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.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;
|
|
||||||
}) {
|
|
||||||
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
|
|
||||||
},
|
|
||||||
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.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.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);
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}) {
|
|
||||||
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
|
|
||||||
})
|
|
||||||
.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);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log('ae_promises.delete__person_obj:', ae_promises.delete__person_obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}) {
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log(`*** update_ae_obj__person() *** person_id=${person_id}`, data_kv);
|
|
||||||
}
|
|
||||||
|
|
||||||
// log_lvl = 1;
|
|
||||||
|
|
||||||
// Perform the API update
|
|
||||||
const result = await api.update_ae_obj_id_crud({
|
|
||||||
api_cfg: api_cfg,
|
|
||||||
obj_type: 'person',
|
|
||||||
obj_id: person_id,
|
|
||||||
fields: data_kv,
|
|
||||||
key: api_cfg.api_crud_super_key,
|
|
||||||
params: params,
|
|
||||||
return_obj: true,
|
|
||||||
log_lvl: log_lvl
|
|
||||||
});
|
|
||||||
|
|
||||||
// Handle the result
|
|
||||||
if (result) {
|
|
||||||
if (try_cache) {
|
|
||||||
// Process the results first
|
|
||||||
const processed_obj_li = await process_ae_obj__person_props({
|
|
||||||
obj_li: [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.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// await db_save_ae_obj_li__person({
|
|
||||||
// obj_type: 'person',
|
|
||||||
// obj_li: [result],
|
|
||||||
// log_lvl: log_lvl,
|
|
||||||
// });
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
console.error('Failed to update person.');
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}) {
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log(`*** db_save_ae_obj_li__person() ***`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj_li && obj_li.length) {
|
|
||||||
obj_li.forEach(async function (obj: any) {
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log(`ae_obj ${obj_type}:`, obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
const obj_record = {
|
|
||||||
id: obj.person_id_random,
|
|
||||||
// id_random: obj.person_id_random,
|
|
||||||
person_id: obj.person_id_random,
|
|
||||||
person_id_random: obj.person_id_random,
|
|
||||||
|
|
||||||
external_id: obj.external_id,
|
|
||||||
external_sys_id: obj.external_sys_id,
|
|
||||||
code: obj.code,
|
|
||||||
|
|
||||||
account_id: obj.account_id_random,
|
|
||||||
account_id_random: obj.account_id_random,
|
|
||||||
|
|
||||||
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...
|
|
||||||
|
|
||||||
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,
|
|
||||||
|
|
||||||
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,
|
|
||||||
|
|
||||||
// From SQL view
|
|
||||||
username: obj.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
|
|
||||||
};
|
|
||||||
|
|
||||||
let id_random = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
id_random = await db_core.person.update(obj_record.id, obj_record);
|
|
||||||
} catch (error) {
|
|
||||||
console.log(`Error: Failed to update ${obj_record.id}: ${error}`);
|
|
||||||
}
|
|
||||||
if (!id_random) {
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log(`Failed to update record with ID: ${obj_record.id}. Trying put...`);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
id_random = await db_core.person.put(obj_record);
|
|
||||||
} catch (error) {
|
|
||||||
console.log(`Error: Failed to put ${obj.person_id_random}: ${error}`);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log(`Updated record with ID: ${obj_record.id}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!id_random) {
|
|
||||||
console.log(`Failed to save record with ID: ${obj_record.id}`);
|
|
||||||
} else {
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log(`Saved record with ID: ${obj_record.id}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Updated 2025-06-10
|
|
||||||
const properties_to_save = [
|
|
||||||
'id',
|
|
||||||
'person_id',
|
|
||||||
// 'person_id_random',
|
|
||||||
|
|
||||||
'external_id',
|
|
||||||
'external_sys_id',
|
|
||||||
'code',
|
|
||||||
|
|
||||||
'account_id',
|
|
||||||
// 'account_id_random',
|
|
||||||
|
|
||||||
'person_profile_id',
|
|
||||||
// 'person_profile_id_random', // The new table person_profile will be used soon...
|
|
||||||
|
|
||||||
'user_id',
|
|
||||||
// 'user_id_random',
|
|
||||||
|
|
||||||
'pronouns',
|
|
||||||
'informal_name',
|
|
||||||
'title_names',
|
|
||||||
'given_name',
|
|
||||||
'middle_name',
|
|
||||||
'family_name',
|
|
||||||
'designations',
|
|
||||||
|
|
||||||
'professional_title',
|
|
||||||
|
|
||||||
'full_name',
|
|
||||||
'full_name_override', // was display_name and display_name_override
|
|
||||||
|
|
||||||
'affiliations',
|
|
||||||
'primary_email',
|
|
||||||
'biography',
|
|
||||||
'agree',
|
|
||||||
'comments',
|
|
||||||
|
|
||||||
'allow_auth_key', // For sign in without password
|
|
||||||
// 'auth_key', // Should this be saved locally?
|
|
||||||
'passcode',
|
|
||||||
|
|
||||||
// 'passcode_timeout',
|
|
||||||
// 'passcode_read', // For LLM (AI) generated summary...???
|
|
||||||
// 'passcode_read_expire',
|
|
||||||
// 'passcode_write',
|
|
||||||
// 'passcode_write_expire',
|
|
||||||
// 'private_passcode',
|
|
||||||
|
|
||||||
// 'alert',
|
|
||||||
// 'alert_msg',
|
|
||||||
|
|
||||||
'data_json',
|
|
||||||
|
|
||||||
'enable',
|
|
||||||
'hide',
|
|
||||||
'priority',
|
|
||||||
'sort',
|
|
||||||
'group',
|
|
||||||
'notes',
|
|
||||||
'created_on',
|
|
||||||
'updated_on',
|
|
||||||
|
|
||||||
// Generated fields for sorting locally only
|
|
||||||
'tmp_sort_1',
|
|
||||||
'tmp_sort_2',
|
|
||||||
'tmp_sort_3',
|
|
||||||
|
|
||||||
// From SQL view
|
|
||||||
'username',
|
|
||||||
// 'user_username', // Same as username
|
|
||||||
'user_name',
|
|
||||||
'user_email',
|
|
||||||
'user_allow_auth_key', // For sign in without password
|
|
||||||
'user_super',
|
|
||||||
'user_manager',
|
|
||||||
'user_administrator',
|
|
||||||
'user_public',
|
|
||||||
|
|
||||||
'organization_id',
|
|
||||||
// 'organization_id_random',
|
|
||||||
'organization_name',
|
|
||||||
|
|
||||||
'contact_id',
|
|
||||||
// 'contact_id_random',
|
|
||||||
'contact_name',
|
|
||||||
'contact_email',
|
|
||||||
'contact_cc_email',
|
|
||||||
'contact_phone_mobile',
|
|
||||||
'contact_phone_home',
|
|
||||||
'contact_phone_office',
|
|
||||||
'contact_phone_land',
|
|
||||||
'contact_phone_fax',
|
|
||||||
'contact_phone_other',
|
|
||||||
|
|
||||||
'address_id',
|
|
||||||
// 'address_id_random',
|
|
||||||
'address_city',
|
|
||||||
'address_country_alpha_2_code' // contact_address_country_alpha_2_code
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 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];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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-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;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -49,7 +49,8 @@ export async function generate_qr_code({
|
|||||||
|
|
||||||
if (qr_type == 'vcard') {
|
if (qr_type == 'vcard') {
|
||||||
if (qr_data.informal_name) {
|
if (qr_data.informal_name) {
|
||||||
params['n'] = `${qr_data.family_name};${qr_data.given_name};${qr_data.informal_name}`;
|
params['n'] =
|
||||||
|
`${qr_data.family_name};${qr_data.given_name};${qr_data.informal_name}`;
|
||||||
} else {
|
} else {
|
||||||
params['n'] = `${qr_data.family_name};${qr_data.given_name}`;
|
params['n'] = `${qr_data.family_name};${qr_data.given_name}`;
|
||||||
}
|
}
|
||||||
@@ -99,7 +100,8 @@ export async function generate_qr_code({
|
|||||||
|
|
||||||
// If return_blob is true, ensure we return an object URL for use in <img src=...>
|
// If return_blob is true, ensure we return an object URL for use in <img src=...>
|
||||||
if (return_blob) {
|
if (return_blob) {
|
||||||
const data = ae_promises.generate_qr_code.data ?? ae_promises.generate_qr_code;
|
const data =
|
||||||
|
ae_promises.generate_qr_code.data ?? ae_promises.generate_qr_code;
|
||||||
|
|
||||||
// If already a Blob, use it directly
|
// If already a Blob, use it directly
|
||||||
if (data instanceof Blob) {
|
if (data instanceof Blob) {
|
||||||
@@ -133,7 +135,8 @@ export async function generate_qr_code({
|
|||||||
const blob = new Blob([data as BlobPart], { type: 'image/png' });
|
const blob = new Blob([data as BlobPart], { type: 'image/png' });
|
||||||
return URL.createObjectURL(blob);
|
return URL.createObjectURL(blob);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (log_lvl) console.error('Could not create QR code image blob:', e, data);
|
if (log_lvl)
|
||||||
|
console.error('Could not create QR code image blob:', e, data);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -155,7 +158,10 @@ export async function generate_qr_code({
|
|||||||
* @returns {Promise<string>} A promise that resolves to a Base64 data URL of the QR code image.
|
* @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.
|
* @throws {Error} If the qr_type is unknown or data is missing.
|
||||||
*/
|
*/
|
||||||
export async function js_generate_qr_code(qr_type: string, params: key_val = {}) {
|
export async function js_generate_qr_code(
|
||||||
|
qr_type: string,
|
||||||
|
params: key_val = {}
|
||||||
|
) {
|
||||||
const {
|
const {
|
||||||
n = '',
|
n = '',
|
||||||
fn = '',
|
fn = '',
|
||||||
@@ -175,10 +181,12 @@ export async function js_generate_qr_code(qr_type: string, params: key_val = {})
|
|||||||
key,
|
key,
|
||||||
val,
|
val,
|
||||||
js,
|
js,
|
||||||
str
|
str,
|
||||||
|
log_lvl = 0
|
||||||
} = params;
|
} = params;
|
||||||
|
|
||||||
console.log(`*** js_generate_qr_code() *** qr_type=${qr_type}`, params);
|
if (log_lvl >= 2)
|
||||||
|
console.log(`*** js_generate_qr_code() *** qr_type=${qr_type}`, params);
|
||||||
|
|
||||||
let qr_data: string | null = null;
|
let qr_data: string | null = null;
|
||||||
|
|
||||||
@@ -210,13 +218,15 @@ export async function js_generate_qr_code(qr_type: string, params: key_val = {})
|
|||||||
|
|
||||||
case 'obj':
|
case 'obj':
|
||||||
// Custom format: OBJ:ot:obj_type,oi:obj_id
|
// 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".');
|
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}`;
|
qr_data = `OBJ:ot:${obj_type},oi:${obj_id}`;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'kv':
|
case 'kv':
|
||||||
// Custom format: KV:k:"key",v:"val"
|
// Custom format: KV:k:"key",v:"val"
|
||||||
if (!key || !val) throw new Error('Missing key or val for type "kv".');
|
if (!key || !val)
|
||||||
|
throw new Error('Missing key or val for type "kv".');
|
||||||
qr_data = `KV:k:"${key}",v:"${val}"`;
|
qr_data = `KV:k:"${key}",v:"${val}"`;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -228,7 +238,8 @@ export async function js_generate_qr_code(qr_type: string, params: key_val = {})
|
|||||||
|
|
||||||
case 'str':
|
case 'str':
|
||||||
// Raw string data
|
// Raw string data
|
||||||
if (!str) throw new Error('Missing raw string data for type "str".');
|
if (!str)
|
||||||
|
throw new Error('Missing raw string data for type "str".');
|
||||||
qr_data = str;
|
qr_data = str;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -251,7 +262,6 @@ export async function js_generate_qr_code(qr_type: string, params: key_val = {})
|
|||||||
scale: 10, // Corresponds to box_size
|
scale: 10, // Corresponds to box_size
|
||||||
type: 'image/png'
|
type: 'image/png'
|
||||||
});
|
});
|
||||||
console.log('Generated QR code data URL:', data_url);
|
|
||||||
return data_url;
|
return data_url;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error generating QR code:', error);
|
console.error('Error generating QR code:', error);
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
@@ -1,69 +1,72 @@
|
|||||||
import type { key_val } from '$lib/stores/ae_stores';
|
|
||||||
import { api } from '$lib/api/api';
|
import { api } from '$lib/api/api';
|
||||||
|
import { db_lookups, LOOKUP_TTL_MS } from '$lib/ae_core/db_lookups';
|
||||||
|
|
||||||
import { db_core } from '$lib/ae_core/db_core';
|
/**
|
||||||
|
* Time zone lookup — IDB-backed SWR helper.
|
||||||
|
*
|
||||||
|
* Fetches priority timezones (only_priority=true, ~72 records). Calling this
|
||||||
|
* function triggers a background API refresh if IDB is empty or older than
|
||||||
|
* 24 hours. Components subscribe to db_lookups.lu_time_zone via liveQuery and
|
||||||
|
* receive automatic updates when the refresh completes.
|
||||||
|
*
|
||||||
|
* Updated 2026-03-23 — replaced $ae_loc + localStorage pattern with IDB + 24h TTL
|
||||||
|
*/
|
||||||
|
|
||||||
const ae_promises: key_val = {};
|
async function _refresh_lu_time_zone_background({
|
||||||
|
|
||||||
// Updated 2026-02-20
|
|
||||||
export async function load_ae_obj_li__time_zone({
|
|
||||||
api_cfg,
|
api_cfg,
|
||||||
// account_id,
|
|
||||||
enabled = 'enabled',
|
|
||||||
hidden = 'not_hidden',
|
|
||||||
limit = 1800, // There are roughly 1780 as of 2026-02
|
|
||||||
offset = 0,
|
|
||||||
// order_by_li = {'priority': 'DESC', 'group': 'ASC', 'sort': 'DESC', 'name': 'ASC'},
|
|
||||||
order_by_li = { priority: 'DESC', sort: 'DESC', name: 'ASC' } as const,
|
|
||||||
params = {},
|
|
||||||
only_priority = false,
|
|
||||||
try_cache = true,
|
|
||||||
log_lvl = 0
|
log_lvl = 0
|
||||||
}: {
|
}: {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
api_cfg: any;
|
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;
|
|
||||||
only_priority?: boolean;
|
|
||||||
try_cache?: boolean;
|
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
if (log_lvl) {
|
if (log_lvl) console.log('*** _refresh_lu_time_zone_background() ***');
|
||||||
console.log(`*** load_ae_obj_li__time_zone() *** only_priority=${only_priority}`);
|
try {
|
||||||
}
|
const result = await api.get_ae_obj_li_for_lu({
|
||||||
|
api_cfg,
|
||||||
const params_json: key_val = {};
|
|
||||||
|
|
||||||
// console.log('params_json:', params_json);
|
|
||||||
|
|
||||||
ae_promises.load__time_zone_li = await api
|
|
||||||
.get_ae_obj_li_for_lu({
|
|
||||||
api_cfg: api_cfg,
|
|
||||||
for_lu_type: 'time_zone',
|
for_lu_type: 'time_zone',
|
||||||
enabled: enabled,
|
enabled: 'enabled',
|
||||||
hidden: hidden,
|
hidden: 'not_hidden',
|
||||||
limit: limit,
|
only_priority: true, // ~72 priority timezone records
|
||||||
offset: offset,
|
limit: 1800,
|
||||||
params: params,
|
log_lvl
|
||||||
only_priority: only_priority,
|
|
||||||
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: any) {
|
|
||||||
console.log('No results returned or failed.', error);
|
|
||||||
});
|
});
|
||||||
|
if (result?.length) {
|
||||||
console.log('ae_promises.load__time_zone_li:', ae_promises.load__time_zone_li);
|
await db_lookups.lu_time_zone.clear();
|
||||||
return ae_promises.load__time_zone_li;
|
await db_lookups.lu_time_zone.bulkPut(result);
|
||||||
|
await db_lookups.lu_cache_meta.put({
|
||||||
|
lu_type: 'time_zone',
|
||||||
|
refreshed_at: Date.now()
|
||||||
|
});
|
||||||
|
if (log_lvl)
|
||||||
|
console.log(
|
||||||
|
`lu_time_zone: saved ${result.length} records to IDB`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('lu_time_zone refresh failed:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function load_ae_obj_li__time_zone({
|
||||||
|
api_cfg,
|
||||||
|
log_lvl = 0
|
||||||
|
}: {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
api_cfg: any;
|
||||||
|
log_lvl?: number;
|
||||||
|
}) {
|
||||||
|
if (log_lvl) console.log('*** load_ae_obj_li__time_zone() ***');
|
||||||
|
|
||||||
|
const count = await db_lookups.lu_time_zone.count();
|
||||||
|
const meta = await db_lookups.lu_cache_meta.get('time_zone');
|
||||||
|
const is_stale = !meta || Date.now() - meta.refreshed_at > LOOKUP_TTL_MS;
|
||||||
|
|
||||||
|
if (count === 0 || is_stale) {
|
||||||
|
_refresh_lu_time_zone_background({ api_cfg, log_lvl });
|
||||||
|
} else if (log_lvl) {
|
||||||
|
console.log(
|
||||||
|
`lu_time_zone: IDB fresh (${count} records), skipping refresh`
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,352 +0,0 @@
|
|||||||
import type { key_val } from '$lib/stores/ae_stores';
|
|
||||||
import { api } from '$lib/api/api';
|
|
||||||
|
|
||||||
import { db_core } from '$lib/ae_core/db_core';
|
|
||||||
|
|
||||||
/*
|
|
||||||
* *** LEGACY AUTHENTICATION HEADER LOGIC ***
|
|
||||||
*
|
|
||||||
* The functions in this file interact with legacy Aether API authentication endpoints
|
|
||||||
* (e.g., /user/authenticate, /user/lookup_email).
|
|
||||||
*
|
|
||||||
* Unlike V3 endpoints which handle context automatically or via standard headers,
|
|
||||||
* these legacy endpoints have specific requirements:
|
|
||||||
*
|
|
||||||
* 1. They often require the `x-account-id` header to be explicitly set to the target
|
|
||||||
* account ID to find the user within that specific account context.
|
|
||||||
* 2. The standard API wrapper logic might strip `x-account-id` if `x-no-account-id`
|
|
||||||
* is present (Bootstrap Paradox logic). We must explicitly remove `x-no-account-id`
|
|
||||||
* and set `x-account-id` to ensure the request is routed correctly.
|
|
||||||
* 3. Some endpoints accept `account_id` as a query parameter, while others (like email sending)
|
|
||||||
* may crash (500 Error) if unexpected parameters are passed.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const ae_promises: key_val = {};
|
|
||||||
|
|
||||||
// Updated 2025-04-04
|
|
||||||
// This function handles username/password authentication.
|
|
||||||
// It explicitly sets the x-account-id header to ensure the user is looked up in the correct account.
|
|
||||||
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}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const endpoint = '/user/authenticate';
|
|
||||||
|
|
||||||
// Prepare API config with correct headers to override global guest settings
|
|
||||||
const use_api_cfg = { ...api_cfg, headers: { ...api_cfg.headers } };
|
|
||||||
if (account_id) {
|
|
||||||
use_api_cfg.headers['x-account-id'] = account_id;
|
|
||||||
delete use_api_cfg.headers['x-no-account-id'];
|
|
||||||
params['account_id'] = account_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null_account_id) {
|
|
||||||
params['null_account_id'] = true;
|
|
||||||
}
|
|
||||||
params['username'] = username; // Required
|
|
||||||
params['password'] = password; // Required
|
|
||||||
params['inc_jwt'] = true; // Request a JWT in the response
|
|
||||||
if (log_lvl > 1) {
|
|
||||||
console.log(`auth_ae_obj__username_password() - params:`, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
ae_promises.auth__username_password = await api
|
|
||||||
.get_object({
|
|
||||||
api_cfg: use_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: any) {
|
|
||||||
console.log('No results returned or failed.', error);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log('ae_promises.auth__username_password:', ae_promises.auth__username_password);
|
|
||||||
}
|
|
||||||
return ae_promises.auth__username_password;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Updated 2025-04-04
|
|
||||||
// This function handles authentication using a User ID and a one-time auth key.
|
|
||||||
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}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const endpoint = '/user/authenticate';
|
|
||||||
|
|
||||||
// Prepare API config with correct headers to override global guest settings
|
|
||||||
const use_api_cfg = { ...api_cfg, headers: { ...api_cfg.headers } };
|
|
||||||
if (account_id) {
|
|
||||||
use_api_cfg.headers['x-account-id'] = account_id;
|
|
||||||
delete use_api_cfg.headers['x-no-account-id'];
|
|
||||||
params['account_id'] = account_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
params['user_id'] = user_id; // Required
|
|
||||||
params['auth_key'] = user_auth_key; // Required
|
|
||||||
params['inc_jwt'] = true; // Request a JWT in the response
|
|
||||||
if (log_lvl > 1) {
|
|
||||||
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: use_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: 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);
|
|
||||||
}
|
|
||||||
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
|
|
||||||
// NOTE: This legacy endpoint is sensitive to extra query parameters and will 500 if account_id is passed in the URL.
|
|
||||||
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}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (log_lvl > 1) {
|
|
||||||
console.log(api_cfg);
|
|
||||||
}
|
|
||||||
|
|
||||||
const email_auth_key_endpoint = `/user/${user_id}/email_auth_key_url`;
|
|
||||||
params = {
|
|
||||||
root_url: base_url,
|
|
||||||
key_param_name: key_param_name
|
|
||||||
};
|
|
||||||
|
|
||||||
// Prepare API config with correct headers to override global guest settings
|
|
||||||
const use_api_cfg = { ...api_cfg, headers: { ...api_cfg.headers } };
|
|
||||||
if (account_id) {
|
|
||||||
use_api_cfg.headers['x-account-id'] = account_id;
|
|
||||||
delete use_api_cfg.headers['x-no-account-id'];
|
|
||||||
// WARNING: Do NOT add account_id to params here, as it causes a 500 error on the legacy backend.
|
|
||||||
}
|
|
||||||
|
|
||||||
ae_promises.auth_key__send_email = await api.get_object({
|
|
||||||
api_cfg: use_api_cfg,
|
|
||||||
endpoint: email_auth_key_endpoint,
|
|
||||||
params: params,
|
|
||||||
log_lvl: log_lvl
|
|
||||||
});
|
|
||||||
|
|
||||||
return ae_promises.auth_key__send_email;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}) {
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log(`*** qry_ae_obj_li__user_email() *** account_id=${account_id} email=${email}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const endpoint = '/user/lookup_email';
|
|
||||||
|
|
||||||
// Prepare API config with correct headers to override global guest settings
|
|
||||||
const use_api_cfg = { ...api_cfg, headers: { ...api_cfg.headers } };
|
|
||||||
if (account_id) {
|
|
||||||
use_api_cfg.headers['x-account-id'] = account_id;
|
|
||||||
delete use_api_cfg.headers['x-no-account-id'];
|
|
||||||
params['account_id'] = account_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
params['email'] = email; // Required
|
|
||||||
params['null_account_id'] = null_account_id || false;
|
|
||||||
|
|
||||||
if (log_lvl > 1) {
|
|
||||||
console.log(`qry_ae_obj_li__user_email() - params:`, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
ae_promises.qry__user_email = await api
|
|
||||||
.get_object({
|
|
||||||
api_cfg: use_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: any) {
|
|
||||||
console.log('No results returned or failed.', error);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log('ae_promises.qry__user_email:', ae_promises.qry__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;
|
|
||||||
}) {
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log(
|
|
||||||
`*** auth_ae_obj__user_id_change_password() *** account_id=${account_id} user_id=${user_id}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
})
|
|
||||||
.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);
|
|
||||||
}
|
|
||||||
return ae_promises.change_password__user_id;
|
|
||||||
}
|
|
||||||
81
src/lib/ae_core/db_lookups.ts
Normal file
81
src/lib/ae_core/db_lookups.ts
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
import Dexie, { type Table } from 'dexie';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lookup DB — IDB-backed cache for V3 Uniform Lookup System reference data.
|
||||||
|
*
|
||||||
|
* These tables store the deduplicated, priority-ranked list returned by
|
||||||
|
* GET /v3/lookup/{lu_type}/list. Data is refreshed automatically on a 24-hour
|
||||||
|
* TTL via the core__*.ts load helpers; components subscribe via liveQuery.
|
||||||
|
*
|
||||||
|
* Updated 2026-03-23
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface LuCountry {
|
||||||
|
id: number;
|
||||||
|
group: string; // dedup key = alpha_2_code (e.g. "US")
|
||||||
|
alpha_2_code: string;
|
||||||
|
name: string;
|
||||||
|
english_short_name?: string;
|
||||||
|
name_override?: string;
|
||||||
|
enable?: number;
|
||||||
|
hide?: number;
|
||||||
|
priority?: number;
|
||||||
|
sort?: number;
|
||||||
|
account_id?: number | null;
|
||||||
|
[key: string]: unknown; // allow extra fields from API without TS errors
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LuCountrySubdivision {
|
||||||
|
id: number;
|
||||||
|
group: string; // dedup key = code (e.g. "US-NY")
|
||||||
|
code: string;
|
||||||
|
name: string;
|
||||||
|
country_alpha_2_code?: string;
|
||||||
|
name_override?: string;
|
||||||
|
enable?: number;
|
||||||
|
hide?: number;
|
||||||
|
priority?: number;
|
||||||
|
sort?: number;
|
||||||
|
account_id?: number | null;
|
||||||
|
[key: string]: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LuTimeZone {
|
||||||
|
id: number;
|
||||||
|
group: string; // dedup key = name (IANA identifier, e.g. "US/Eastern")
|
||||||
|
name: string;
|
||||||
|
name_override?: string; // display label override; prefer this over name when set
|
||||||
|
enable?: number;
|
||||||
|
hide?: number;
|
||||||
|
priority?: number;
|
||||||
|
sort?: number;
|
||||||
|
account_id?: number | null;
|
||||||
|
[key: string]: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LuCacheMeta {
|
||||||
|
lu_type: 'country' | 'country_subdivision' | 'time_zone';
|
||||||
|
refreshed_at: number; // Unix timestamp ms — used for 24h TTL check
|
||||||
|
}
|
||||||
|
|
||||||
|
class LookupsDexie extends Dexie {
|
||||||
|
lu_country!: Table<LuCountry>;
|
||||||
|
lu_country_subdivision!: Table<LuCountrySubdivision>;
|
||||||
|
lu_time_zone!: Table<LuTimeZone>;
|
||||||
|
lu_cache_meta!: Table<LuCacheMeta>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super('ae_lookups_db');
|
||||||
|
this.version(1).stores({
|
||||||
|
lu_country: 'id, alpha_2_code, group',
|
||||||
|
lu_country_subdivision: 'id, code, country_alpha_2_code, group',
|
||||||
|
lu_time_zone: 'id, name, group',
|
||||||
|
lu_cache_meta: 'lu_type'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const db_lookups = new LookupsDexie();
|
||||||
|
|
||||||
|
/** 24-hour TTL in milliseconds */
|
||||||
|
export const LOOKUP_TTL_MS = 24 * 60 * 60 * 1000;
|
||||||
@@ -1,125 +1,140 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
/**
|
/**
|
||||||
* AE_AITools.svelte
|
* AE_AITools.svelte
|
||||||
* GENERIC Aether AI Toolset (Runes/Svelte 5)
|
* GENERIC Aether AI Toolset (Runes/Svelte 5)
|
||||||
* Extracted logic from Journals module to be system-wide.
|
* Extracted logic from Journals module to be system-wide.
|
||||||
*/
|
*/
|
||||||
import OpenAI from 'openai';
|
import OpenAI from 'openai';
|
||||||
import { Modal } from 'flowbite-svelte';
|
import { Modal } from 'flowbite-svelte';
|
||||||
import {
|
import {
|
||||||
Bot, BotMessageSquare, Loader, FileText,
|
Bot,
|
||||||
Save, FilePenLine, RotateCcw, Settings,
|
BotMessageSquare,
|
||||||
RefreshCcw, Globe, Copy
|
Loader,
|
||||||
} from '@lucide/svelte';
|
FileText,
|
||||||
import { ae_loc, ae_api } from '$lib/stores/ae_stores';
|
Save,
|
||||||
import AE_Comp_Editor_CodeMirror from '$lib/elements/AE_Comp_Editor_CodeMirror.svelte';
|
FilePenLine,
|
||||||
|
RotateCcw,
|
||||||
|
Settings,
|
||||||
|
RefreshCcw,
|
||||||
|
Globe,
|
||||||
|
Copy
|
||||||
|
} from '@lucide/svelte';
|
||||||
|
import { ae_loc, ae_api } from '$lib/stores/ae_stores';
|
||||||
|
import AE_Comp_Editor_CodeMirror from '$lib/elements/element_editor_codemirror.svelte';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
// Core Props
|
// Core Props
|
||||||
content: string; // The text to summarize/analyze
|
content: string; // The text to summarize/analyze
|
||||||
summary: string; // The result (bindable)
|
summary: string; // The result (bindable)
|
||||||
|
|
||||||
// Configuration (Bindable for global settings persistence)
|
// Configuration (Bindable for global settings persistence)
|
||||||
model?: string;
|
model?: string;
|
||||||
baseUrl?: string;
|
baseUrl?: string;
|
||||||
token?: string;
|
token?: string;
|
||||||
systemPrompt?: string;
|
systemPrompt?: string;
|
||||||
maxTokens?: number;
|
maxTokens?: number;
|
||||||
temperature?: number;
|
temperature?: number;
|
||||||
|
|
||||||
// Callbacks
|
// Callbacks
|
||||||
onSave?: (newSummary: string) => void;
|
onSave?: (newSummary: string) => void;
|
||||||
onSyncConfig?: () => void; // Optional: callback to sync from global site config
|
onSyncConfig?: () => void; // Optional: callback to sync from global site config
|
||||||
|
|
||||||
// UI Customization
|
// UI Customization
|
||||||
buttonClass?: string;
|
buttonClass?: string;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
let {
|
||||||
|
content,
|
||||||
|
summary = $bindable(),
|
||||||
|
model = $bindable(),
|
||||||
|
baseUrl = $bindable(),
|
||||||
|
token = $bindable(),
|
||||||
|
systemPrompt = $bindable(),
|
||||||
|
maxTokens = $bindable(),
|
||||||
|
temperature = $bindable(),
|
||||||
|
onSave,
|
||||||
|
onSyncConfig,
|
||||||
|
buttonClass = 'btn btn-sm preset-tonal-primary shadow-lg hover:scale-105 transition-all',
|
||||||
|
log_lvl = 0
|
||||||
|
}: Props = $props();
|
||||||
|
|
||||||
|
// Apply defaults if undefined (Safe for Svelte 5 Runes)
|
||||||
|
if (model === undefined) model = 'dgrzone-deepseek-8b-quick';
|
||||||
|
if (baseUrl === undefined) baseUrl = 'https://ai.dgrzone.com/api';
|
||||||
|
if (token === undefined) token = '';
|
||||||
|
if (systemPrompt === undefined) systemPrompt = 'You are a helpful assistant.';
|
||||||
|
if (maxTokens === undefined) maxTokens = 512;
|
||||||
|
if (temperature === undefined) temperature = 0.7;
|
||||||
|
|
||||||
|
// Internal State
|
||||||
|
let ae_promises: any = $state(null);
|
||||||
|
let show_modal = $state(false);
|
||||||
|
let active_tab: 'result' | 'settings' = $state('result');
|
||||||
|
let tmp_summary = $state('');
|
||||||
|
|
||||||
|
async function generate_ai_result() {
|
||||||
|
if (!content) {
|
||||||
|
alert('No content available to analyze.');
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let {
|
active_tab = 'result';
|
||||||
content,
|
|
||||||
summary = $bindable(),
|
|
||||||
model = $bindable(),
|
|
||||||
baseUrl = $bindable(),
|
|
||||||
token = $bindable(),
|
|
||||||
systemPrompt = $bindable(),
|
|
||||||
maxTokens = $bindable(),
|
|
||||||
temperature = $bindable(),
|
|
||||||
onSave,
|
|
||||||
onSyncConfig,
|
|
||||||
buttonClass = "btn btn-sm preset-tonal-primary shadow-lg hover:scale-105 transition-all",
|
|
||||||
log_lvl = 0
|
|
||||||
}: Props = $props();
|
|
||||||
|
|
||||||
// Apply defaults if undefined (Safe for Svelte 5 Runes)
|
// If no token is provided, trigger a "Demo Mode" placeholder after a fake delay
|
||||||
if (model === undefined) model = 'dgrzone-deepseek-8b-quick';
|
if (!token || token === '') {
|
||||||
if (baseUrl === undefined) baseUrl = 'https://ai.dgrzone.com/api';
|
console.log('AE_AITools: No token provided. Entering Demo Mode.');
|
||||||
if (token === undefined) token = '';
|
ae_promises = new Promise((resolve) => {
|
||||||
if (systemPrompt === undefined) systemPrompt = 'You are a helpful assistant.';
|
setTimeout(() => {
|
||||||
if (maxTokens === undefined) maxTokens = 512;
|
tmp_summary = `### AI Summary (DEMO MODE)\n\nThis is a placeholder summary because no API token was provided in the settings. \n\n**Original Content Length:** ${content.length} characters.\n\n**System Prompt:** ${systemPrompt}\n\n**Model:** ${model}`;
|
||||||
if (temperature === undefined) temperature = 0.7;
|
show_modal = true;
|
||||||
|
resolve(true);
|
||||||
// Internal State
|
}, 1500);
|
||||||
let ae_promises: any = $state(null);
|
|
||||||
let show_modal = $state(false);
|
|
||||||
let active_tab: 'result' | 'settings' = $state('result');
|
|
||||||
let tmp_summary = $state('');
|
|
||||||
|
|
||||||
async function generate_ai_result() {
|
|
||||||
if (!content) {
|
|
||||||
alert('No content available to analyze.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
active_tab = 'result';
|
|
||||||
|
|
||||||
// If no token is provided, trigger a "Demo Mode" placeholder after a fake delay
|
|
||||||
if (!token || token === '') {
|
|
||||||
console.log('AE_AITools: No token provided. Entering Demo Mode.');
|
|
||||||
ae_promises = new Promise((resolve) => {
|
|
||||||
setTimeout(() => {
|
|
||||||
tmp_summary = `### AI Summary (DEMO MODE)\n\nThis is a placeholder summary because no API token was provided in the settings. \n\n**Original Content Length:** ${content.length} characters.\n\n**System Prompt:** ${systemPrompt}\n\n**Model:** ${model}`;
|
|
||||||
show_modal = true;
|
|
||||||
resolve(true);
|
|
||||||
}, 1500);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ai_client = new OpenAI({
|
|
||||||
apiKey: token,
|
|
||||||
baseURL: baseUrl,
|
|
||||||
dangerouslyAllowBrowser: true
|
|
||||||
});
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
const ai_client = new OpenAI({
|
||||||
ae_promises = ai_client.chat.completions.create({
|
apiKey: token,
|
||||||
|
baseURL: baseUrl,
|
||||||
|
dangerouslyAllowBrowser: true
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
ae_promises = ai_client.chat.completions
|
||||||
|
.create({
|
||||||
model: model || 'dgrzone-deepseek-8b-quick',
|
model: model || 'dgrzone-deepseek-8b-quick',
|
||||||
max_tokens: maxTokens,
|
max_tokens: maxTokens,
|
||||||
temperature: temperature,
|
temperature: temperature,
|
||||||
messages: [
|
messages: [
|
||||||
{ role: 'system', content: systemPrompt || 'You are a helpful assistant.' },
|
{
|
||||||
|
role: 'system',
|
||||||
|
content: systemPrompt || 'You are a helpful assistant.'
|
||||||
|
},
|
||||||
{ role: 'user', content: content }
|
{ role: 'user', content: content }
|
||||||
]
|
]
|
||||||
}).then((resp) => {
|
})
|
||||||
const result = resp?.choices?.[0]?.message?.content || 'No result generated.';
|
.then((resp) => {
|
||||||
|
const result =
|
||||||
|
resp?.choices?.[0]?.message?.content ||
|
||||||
|
'No result generated.';
|
||||||
tmp_summary = result;
|
tmp_summary = result;
|
||||||
show_modal = true;
|
show_modal = true;
|
||||||
});
|
});
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
console.error('AE_AITools: AI Error:', err);
|
console.error('AE_AITools: AI Error:', err);
|
||||||
// Even on error, show the modal with the error message so the UI can be inspected
|
// Even on error, show the modal with the error message so the UI can be inspected
|
||||||
tmp_summary = `### AI Error\n\nFailed to connect to the AI service.\n\n**Error:** ${err.message}\n\nCheck your Settings tab for Base URL and Token configuration.`;
|
tmp_summary = `### AI Error\n\nFailed to connect to the AI service.\n\n**Error:** ${err.message}\n\nCheck your Settings tab for Base URL and Token configuration.`;
|
||||||
show_modal = true;
|
show_modal = true;
|
||||||
ae_promises = Promise.resolve();
|
ae_promises = Promise.resolve();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function handle_save() {
|
function handle_save() {
|
||||||
summary = tmp_summary;
|
summary = tmp_summary;
|
||||||
if (onSave) onSave(tmp_summary);
|
if (onSave) onSave(tmp_summary);
|
||||||
show_modal = false;
|
show_modal = false;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="ae-ai-tools-wrapper inline-flex items-center gap-1">
|
<div class="ae-ai-tools-wrapper inline-flex items-center gap-1">
|
||||||
@@ -128,13 +143,12 @@
|
|||||||
type="button"
|
type="button"
|
||||||
onclick={generate_ai_result}
|
onclick={generate_ai_result}
|
||||||
class={buttonClass}
|
class={buttonClass}
|
||||||
title="Generate AI summary/analysis"
|
title="Generate AI summary/analysis">
|
||||||
>
|
|
||||||
{#await ae_promises}
|
{#await ae_promises}
|
||||||
<Loader class="inline-block mr-1 animate-spin" size="1.2em" />
|
<Loader class="mr-1 inline-block animate-spin" size="1.2em" />
|
||||||
<span class="text-sm">Processing...</span>
|
<span class="text-sm">Processing...</span>
|
||||||
{:then}
|
{:then}
|
||||||
<BotMessageSquare class="inline-block mr-1" size="1.2em" />
|
<BotMessageSquare class="mr-1 inline-block" size="1.2em" />
|
||||||
<span class="text-sm">Summarize</span>
|
<span class="text-sm">Summarize</span>
|
||||||
{:catch}
|
{:catch}
|
||||||
<span class="text-sm text-red-500">Error</span>
|
<span class="text-sm text-red-500">Error</span>
|
||||||
@@ -149,8 +163,7 @@
|
|||||||
show_modal = true;
|
show_modal = true;
|
||||||
}}
|
}}
|
||||||
class="btn btn-sm variant-soft-surface shadow-md"
|
class="btn btn-sm variant-soft-surface shadow-md"
|
||||||
title="AI Settings"
|
title="AI Settings">
|
||||||
>
|
|
||||||
<Settings size="1.2em" />
|
<Settings size="1.2em" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
@@ -160,32 +173,37 @@
|
|||||||
title="Aether AI Assistant"
|
title="Aether AI Assistant"
|
||||||
bind:open={show_modal}
|
bind:open={show_modal}
|
||||||
size="lg"
|
size="lg"
|
||||||
class="bg-white dark:bg-gray-800"
|
class="bg-white dark:bg-gray-800">
|
||||||
>
|
|
||||||
<div class="space-y-4 p-2">
|
<div class="space-y-4 p-2">
|
||||||
<!-- Tab Navigation -->
|
<!-- Tab Navigation -->
|
||||||
<div class="flex gap-1 border-b border-surface-500/20 pb-2">
|
<div class="border-surface-500/20 flex gap-1 border-b pb-2">
|
||||||
<button
|
<button
|
||||||
class="btn btn-sm {active_tab === 'result' ? 'variant-filled-primary' : 'variant-soft-surface'}"
|
class="btn btn-sm {active_tab === 'result'
|
||||||
onclick={() => active_tab = 'result'}
|
? 'variant-filled-primary'
|
||||||
>
|
: 'variant-soft-surface'}"
|
||||||
|
onclick={() => (active_tab = 'result')}>
|
||||||
<Bot size="1.1em" class="mr-1" /> Result
|
<Bot size="1.1em" class="mr-1" /> Result
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn btn-sm {active_tab === 'settings' ? 'variant-filled-secondary' : 'variant-soft-surface'}"
|
class="btn btn-sm {active_tab === 'settings'
|
||||||
onclick={() => active_tab = 'settings'}
|
? 'variant-filled-secondary'
|
||||||
>
|
: 'variant-soft-surface'}"
|
||||||
|
onclick={() => (active_tab = 'settings')}>
|
||||||
<Settings size="1.1em" class="mr-1" /> Settings
|
<Settings size="1.1em" class="mr-1" /> Settings
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if active_tab === 'result'}
|
{#if active_tab === 'result'}
|
||||||
<div class="space-y-4 animate-in fade-in duration-200">
|
<div class="animate-in fade-in space-y-4 duration-200">
|
||||||
<div class="flex gap-2 justify-start">
|
<div class="flex justify-start gap-2">
|
||||||
<button class="btn btn-sm variant-filled-success" onclick={handle_save}>
|
<button
|
||||||
|
class="btn btn-sm variant-filled-success"
|
||||||
|
onclick={handle_save}>
|
||||||
<Save size="1.1em" class="mr-1" /> Save Result
|
<Save size="1.1em" class="mr-1" /> Save Result
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-sm variant-ghost-primary" onclick={generate_ai_result}>
|
<button
|
||||||
|
class="btn btn-sm variant-ghost-primary"
|
||||||
|
onclick={generate_ai_result}>
|
||||||
<RotateCcw size="1.1em" class="mr-1" /> Re-run
|
<RotateCcw size="1.1em" class="mr-1" /> Re-run
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -195,57 +213,84 @@
|
|||||||
bind:new_content={tmp_summary}
|
bind:new_content={tmp_summary}
|
||||||
theme_mode={$ae_loc.theme_mode}
|
theme_mode={$ae_loc.theme_mode}
|
||||||
placeholder="AI Result will appear here..."
|
placeholder="AI Result will appear here..."
|
||||||
class_li="p-2 border rounded-lg h-96 shadow-inner bg-surface-500/5"
|
class_li="p-2 border rounded-lg h-96 shadow-inner bg-surface-500/5" />
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="space-y-6 animate-in slide-in-from-left-4 duration-200">
|
<div
|
||||||
|
class="animate-in slide-in-from-left-4 space-y-6 duration-200">
|
||||||
<!-- Connection Settings -->
|
<!-- Connection Settings -->
|
||||||
<div class="space-y-4">
|
<div class="space-y-4">
|
||||||
<h3 class="text-sm font-bold uppercase tracking-widest text-surface-500 flex items-center gap-2">
|
<h3
|
||||||
|
class="text-surface-500 flex items-center gap-2 text-sm font-bold tracking-widest uppercase">
|
||||||
<Globe size="1.1em" /> API Connection
|
<Globe size="1.1em" /> API Connection
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
{#if onSyncConfig}
|
{#if onSyncConfig}
|
||||||
<button class="btn btn-sm variant-soft-primary" onclick={onSyncConfig}>
|
<button
|
||||||
<Copy size="1.1em" class="mr-1" /> Sync Global Defaults
|
class="btn btn-sm variant-soft-primary"
|
||||||
|
onclick={onSyncConfig}>
|
||||||
|
<Copy size="1.1em" class="mr-1" /> Sync Global
|
||||||
|
Defaults
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span>Base URL</span>
|
<span>Base URL</span>
|
||||||
<input type="text" bind:value={baseUrl} class="input input-sm" />
|
<input
|
||||||
|
type="text"
|
||||||
|
bind:value={baseUrl}
|
||||||
|
class="input input-sm" />
|
||||||
</label>
|
</label>
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span>Model</span>
|
<span>Model</span>
|
||||||
<input type="text" bind:value={model} class="input input-sm" />
|
<input
|
||||||
|
type="text"
|
||||||
|
bind:value={model}
|
||||||
|
class="input input-sm" />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span>API Token</span>
|
<span>API Token</span>
|
||||||
<input type="password" bind:value={token} class="input input-sm font-mono" />
|
<input
|
||||||
|
type="password"
|
||||||
|
bind:value={token}
|
||||||
|
class="input input-sm font-mono" />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Model Parameters -->
|
<!-- Model Parameters -->
|
||||||
<div class="space-y-4 pt-4 border-t border-surface-500/10">
|
<div
|
||||||
<h3 class="text-sm font-bold uppercase tracking-widest text-surface-500 flex items-center gap-2">
|
class="border-surface-500/10 space-y-4 border-t pt-4">
|
||||||
|
<h3
|
||||||
|
class="text-surface-500 flex items-center gap-2 text-sm font-bold tracking-widest uppercase">
|
||||||
<FilePenLine size="1.1em" /> Inference Parameters
|
<FilePenLine size="1.1em" /> Inference Parameters
|
||||||
</h3>
|
</h3>
|
||||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span>Temperature ({temperature})</span>
|
<span>Temperature ({temperature})</span>
|
||||||
<input type="range" bind:value={temperature} min="0" max="1" step="0.1" class="range" />
|
<input
|
||||||
|
type="range"
|
||||||
|
bind:value={temperature}
|
||||||
|
min="0"
|
||||||
|
max="1"
|
||||||
|
step="0.1"
|
||||||
|
class="range" />
|
||||||
</label>
|
</label>
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span>Max Tokens</span>
|
<span>Max Tokens</span>
|
||||||
<input type="number" bind:value={maxTokens} class="input input-sm" />
|
<input
|
||||||
|
type="number"
|
||||||
|
bind:value={maxTokens}
|
||||||
|
class="input input-sm" />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<label class="label">
|
<label class="label">
|
||||||
<span>System Prompt</span>
|
<span>System Prompt</span>
|
||||||
<textarea bind:value={systemPrompt} class="textarea h-24 text-xs font-mono"></textarea>
|
<textarea
|
||||||
|
bind:value={systemPrompt}
|
||||||
|
class="textarea h-24 font-mono text-xs"
|
||||||
|
></textarea>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,65 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
/**
|
|
||||||
* AE_MetadataFooter.svelte
|
|
||||||
* GENERIC Aether Metadata Display
|
|
||||||
* Reusable across all modules to standardize created/updated/original info.
|
|
||||||
*/
|
|
||||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
|
||||||
import { ae_loc } from '$lib/stores/ae_stores';
|
|
||||||
import { Clock, CalendarClock, Globe } from '@lucide/svelte';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
obj: any;
|
|
||||||
showOriginal?: boolean;
|
|
||||||
containerClass?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
let {
|
|
||||||
obj,
|
|
||||||
showOriginal = true,
|
|
||||||
containerClass = "ae_meta flex flex-col gap-2 p-4 border-t border-surface-500/10 text-xs text-surface-500 w-full"
|
|
||||||
}: Props = $props();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<footer class={containerClass}>
|
|
||||||
<!-- Original Date/Time Info (if applicable) -->
|
|
||||||
{#if showOriginal && (obj?.original_datetime || obj?.original_timezone)}
|
|
||||||
<div class="flex flex-row flex-wrap gap-x-4 gap-y-1 items-center bg-surface-500/5 p-2 rounded">
|
|
||||||
<span class="flex items-center gap-1">
|
|
||||||
<Globe size="1.1em" class="opacity-70" />
|
|
||||||
<span class="font-bold uppercase tracking-tighter">Original:</span>
|
|
||||||
{obj?.original_datetime ? ae_util.iso_datetime_formatter(obj.original_datetime, 'datetime_iso_12_no_seconds') : '--'}
|
|
||||||
</span>
|
|
||||||
{#if obj?.original_timezone}
|
|
||||||
<span class="flex items-center gap-1">
|
|
||||||
<span class="font-bold uppercase tracking-tighter">TZ:</span>
|
|
||||||
{obj.original_timezone}
|
|
||||||
</span>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<!-- System Timestamps -->
|
|
||||||
<div class="flex flex-col sm:flex-row justify-between items-center gap-2 px-1">
|
|
||||||
<div class="flex flex-wrap gap-4 justify-center sm:justify-start">
|
|
||||||
<span class="flex items-center gap-1" title="Creation date">
|
|
||||||
<CalendarClock size="1.1em" class="opacity-70 text-primary-500" />
|
|
||||||
<span class="font-semibold uppercase tracking-tighter">Created:</span>
|
|
||||||
{ae_util.iso_datetime_formatter(obj?.created_on, 'datetime_iso_12_no_seconds')}
|
|
||||||
</span>
|
|
||||||
{#if obj?.updated_on}
|
|
||||||
<span class="flex items-center gap-1" title="Last update">
|
|
||||||
<Clock size="1.1em" class="opacity-70 text-secondary-500" />
|
|
||||||
<span class="font-semibold uppercase tracking-tighter">Updated:</span>
|
|
||||||
{ae_util.iso_datetime_formatter(obj.updated_on, 'datetime_iso_12_no_seconds')}
|
|
||||||
</span>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{#if obj?.journal_entry_type || obj?.type}
|
|
||||||
<span class="badge variant-soft-surface text-[10px] uppercase font-bold tracking-widest">
|
|
||||||
Type: {obj?.journal_entry_type || obj?.type}
|
|
||||||
</span>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
@@ -1,58 +1,64 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
/**
|
/**
|
||||||
* AE_ObjectFlags.svelte
|
* AE_ObjectFlags.svelte
|
||||||
* GENERIC Aether Object Flags & Visibility Toggles
|
* GENERIC Aether Object Flags & Visibility Toggles
|
||||||
* Manages: alert, private, public, personal, professional, template
|
* Manages: alert, private, public, personal, professional, template
|
||||||
*/
|
*/
|
||||||
import {
|
import {
|
||||||
Siren, MessageSquareWarning, Fingerprint,
|
Siren,
|
||||||
Globe, BookHeart, BriefcaseBusiness, NotepadTextDashed,
|
MessageSquareWarning,
|
||||||
Settings
|
Fingerprint,
|
||||||
} from '@lucide/svelte';
|
Globe,
|
||||||
import { ae_loc } from '$lib/stores/ae_stores';
|
BookHeart,
|
||||||
|
BriefcaseBusiness,
|
||||||
|
NotepadTextDashed,
|
||||||
|
Settings
|
||||||
|
} from '@lucide/svelte';
|
||||||
|
import { ae_loc } from '$lib/stores/ae_stores';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
// The object containing the flags (bindable)
|
// The object containing the flags (bindable)
|
||||||
obj: any;
|
obj: any;
|
||||||
|
|
||||||
// Visibility configuration (optional overrides)
|
// Visibility configuration (optional overrides)
|
||||||
show_labels?: boolean;
|
show_labels?: boolean;
|
||||||
hide_alert?: boolean;
|
hide_alert?: boolean;
|
||||||
hide_private?: boolean;
|
hide_private?: boolean;
|
||||||
hide_public?: boolean;
|
hide_public?: boolean;
|
||||||
hide_personal?: boolean;
|
hide_personal?: boolean;
|
||||||
hide_professional?: boolean;
|
hide_professional?: boolean;
|
||||||
hide_template?: boolean;
|
hide_template?: boolean;
|
||||||
|
|
||||||
// Callbacks
|
// Callbacks
|
||||||
on_toggle?: (prop: string, newValue: boolean) => void;
|
on_toggle?: (prop: string, newValue: boolean) => void;
|
||||||
|
|
||||||
// Styling
|
// Styling
|
||||||
container_class?: string;
|
container_class?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
let {
|
let {
|
||||||
obj = $bindable(),
|
obj = $bindable(),
|
||||||
show_labels = true,
|
show_labels = true,
|
||||||
hide_alert: hide_alert = false,
|
hide_alert: hide_alert = false,
|
||||||
hide_private: hide_private = false,
|
hide_private: hide_private = false,
|
||||||
hide_public: hide_public = false,
|
hide_public: hide_public = false,
|
||||||
hide_personal: hide_personal = false,
|
hide_personal: hide_personal = false,
|
||||||
hide_professional: hide_professional = false,
|
hide_professional: hide_professional = false,
|
||||||
hide_template: hide_template = false,
|
hide_template: hide_template = false,
|
||||||
on_toggle: onToggle,
|
on_toggle: onToggle,
|
||||||
container_class = "flex flex-row flex-wrap gap-1 items-center justify-evenly py-2 border-y border-surface-500/10"
|
container_class = 'flex flex-row flex-wrap gap-1 items-center justify-evenly py-2 border-y border-surface-500/10'
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
|
|
||||||
function handle_toggle(prop: string) {
|
function handle_toggle(prop: string) {
|
||||||
obj[prop] = !obj[prop];
|
obj[prop] = !obj[prop];
|
||||||
if (onToggle) onToggle(prop, obj[prop]);
|
if (onToggle) onToggle(prop, obj[prop]);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class={container_class}>
|
<div class={container_class}>
|
||||||
{#if show_labels}
|
{#if show_labels}
|
||||||
<span class="text-xs text-surface-500 flex items-center gap-1 uppercase font-bold tracking-wider mr-2">
|
<span
|
||||||
|
class="text-surface-500 mr-2 flex items-center gap-1 text-xs font-bold tracking-wider uppercase">
|
||||||
<Settings size="1.1em" /> Flags:
|
<Settings size="1.1em" /> Flags:
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
@@ -63,9 +69,10 @@
|
|||||||
type="button"
|
type="button"
|
||||||
onclick={() => handle_toggle('alert')}
|
onclick={() => handle_toggle('alert')}
|
||||||
class="btn-icon btn-icon-sm preset-tonal-secondary hover:preset-filled-secondary-500 transition"
|
class="btn-icon btn-icon-sm preset-tonal-secondary hover:preset-filled-secondary-500 transition"
|
||||||
title="Toggle Alert Status"
|
title="Toggle Alert Status">
|
||||||
>
|
<Siren
|
||||||
<Siren size="1.2em" class={obj?.alert ? 'text-error-500' : 'opacity-40'} />
|
size="1.2em"
|
||||||
|
class={obj?.alert ? 'text-error-500' : 'opacity-40'} />
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
@@ -75,9 +82,10 @@
|
|||||||
type="button"
|
type="button"
|
||||||
onclick={() => handle_toggle('private')}
|
onclick={() => handle_toggle('private')}
|
||||||
class="btn-icon btn-icon-sm preset-tonal-secondary hover:preset-filled-secondary-500 transition"
|
class="btn-icon btn-icon-sm preset-tonal-secondary hover:preset-filled-secondary-500 transition"
|
||||||
title="Toggle Private/Encrypted"
|
title="Toggle Private/Encrypted">
|
||||||
>
|
<Fingerprint
|
||||||
<Fingerprint size="1.2em" class={obj?.private ? 'text-success-500' : 'opacity-40'} />
|
size="1.2em"
|
||||||
|
class={obj?.private ? 'text-success-500' : 'opacity-40'} />
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
@@ -87,9 +95,10 @@
|
|||||||
type="button"
|
type="button"
|
||||||
onclick={() => handle_toggle('public')}
|
onclick={() => handle_toggle('public')}
|
||||||
class="btn-icon btn-icon-sm preset-tonal-secondary hover:preset-filled-secondary-500 transition"
|
class="btn-icon btn-icon-sm preset-tonal-secondary hover:preset-filled-secondary-500 transition"
|
||||||
title="Toggle Public Visibility"
|
title="Toggle Public Visibility">
|
||||||
>
|
<Globe
|
||||||
<Globe size="1.2em" class={obj?.public ? 'text-success-500' : 'opacity-40'} />
|
size="1.2em"
|
||||||
|
class={obj?.public ? 'text-success-500' : 'opacity-40'} />
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
@@ -99,9 +108,10 @@
|
|||||||
type="button"
|
type="button"
|
||||||
onclick={() => handle_toggle('personal')}
|
onclick={() => handle_toggle('personal')}
|
||||||
class="btn-icon btn-icon-sm preset-tonal-secondary hover:preset-filled-secondary-500 transition"
|
class="btn-icon btn-icon-sm preset-tonal-secondary hover:preset-filled-secondary-500 transition"
|
||||||
title="Toggle Personal Scope"
|
title="Toggle Personal Scope">
|
||||||
>
|
<BookHeart
|
||||||
<BookHeart size="1.2em" class={obj?.personal ? 'text-success-500' : 'opacity-40'} />
|
size="1.2em"
|
||||||
|
class={obj?.personal ? 'text-success-500' : 'opacity-40'} />
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
@@ -111,9 +121,10 @@
|
|||||||
type="button"
|
type="button"
|
||||||
onclick={() => handle_toggle('professional')}
|
onclick={() => handle_toggle('professional')}
|
||||||
class="btn-icon btn-icon-sm preset-tonal-secondary hover:preset-filled-secondary-500 transition"
|
class="btn-icon btn-icon-sm preset-tonal-secondary hover:preset-filled-secondary-500 transition"
|
||||||
title="Toggle Professional Scope"
|
title="Toggle Professional Scope">
|
||||||
>
|
<BriefcaseBusiness
|
||||||
<BriefcaseBusiness size="1.2em" class={obj?.professional ? 'text-success-500' : 'opacity-40'} />
|
size="1.2em"
|
||||||
|
class={obj?.professional ? 'text-success-500' : 'opacity-40'} />
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
@@ -123,9 +134,10 @@
|
|||||||
type="button"
|
type="button"
|
||||||
onclick={() => handle_toggle('template')}
|
onclick={() => handle_toggle('template')}
|
||||||
class="btn-icon btn-icon-sm preset-tonal-secondary hover:preset-filled-secondary-500 transition"
|
class="btn-icon btn-icon-sm preset-tonal-secondary hover:preset-filled-secondary-500 transition"
|
||||||
title="Toggle Template Mode"
|
title="Toggle Template Mode">
|
||||||
>
|
<NotepadTextDashed
|
||||||
<NotepadTextDashed size="1.2em" class={obj?.template ? 'text-success-500' : 'opacity-40'} />
|
size="1.2em"
|
||||||
|
class={obj?.template ? 'text-success-500' : 'opacity-40'} />
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,95 +1,96 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
/**
|
/**
|
||||||
* AE_Record_Controls.svelte
|
* AE_Record_Controls.svelte
|
||||||
* GENERIC Aether Record Management Controls
|
* GENERIC Aether Record Management Controls
|
||||||
* Manages: priority, hide, enable, alert, delete/disable
|
* Manages: priority, hide, enable, alert, delete/disable
|
||||||
*
|
*
|
||||||
* Emits events — NO API calls. Parent is responsible for:
|
* Emits events — NO API calls. Parent is responsible for:
|
||||||
* 1. Calling the API (update_ae_obj_v3, delete_ae_obj_id__*)
|
* 1. Calling the API (update_ae_obj, delete_ae_obj_id__*)
|
||||||
* 2. Refreshing the object from cache/API
|
* 2. Refreshing the object from cache/API
|
||||||
* 3. Navigating away on delete
|
* 3. Navigating away on delete
|
||||||
*
|
*
|
||||||
* Usage:
|
* Usage:
|
||||||
* <AE_Record_Controls
|
* <AE_Record_Controls
|
||||||
* obj={$lq__event_session_obj}
|
* obj={$lq__event_session_obj}
|
||||||
* obj_label="session"
|
* obj_label="session"
|
||||||
* allow_delete={$ae_loc.manager_access}
|
* allow_delete={$ae_loc.manager_access}
|
||||||
* allow_disable={$ae_loc.administrator_access}
|
* allow_disable={$ae_loc.administrator_access}
|
||||||
* on_toggle={(field, val) => { ... }}
|
* on_toggle={(field, val) => { ... }}
|
||||||
* on_delete={(method) => { ... }}
|
* on_delete={(method) => { ... }}
|
||||||
* />
|
* />
|
||||||
*/
|
*/
|
||||||
import {
|
import {
|
||||||
Star,
|
Star,
|
||||||
Eye,
|
Eye,
|
||||||
EyeOff,
|
EyeOff,
|
||||||
ToggleLeft,
|
ToggleLeft,
|
||||||
ToggleRight,
|
ToggleRight,
|
||||||
Bell,
|
Bell,
|
||||||
BellOff,
|
BellOff,
|
||||||
Trash2,
|
Trash2,
|
||||||
CircleMinus,
|
CircleMinus,
|
||||||
Settings
|
Settings
|
||||||
} from '@lucide/svelte';
|
} from '@lucide/svelte';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
// The object whose flags are being displayed (read-only — parent owns state)
|
// The object whose flags are being displayed (read-only — parent owns state)
|
||||||
obj: any;
|
obj: any;
|
||||||
|
|
||||||
// Human-readable label for confirm dialogs ("session", "presenter", "location", etc.)
|
// Human-readable label for confirm dialogs ("session", "presenter", "location", etc.)
|
||||||
obj_label?: string;
|
obj_label?: string;
|
||||||
|
|
||||||
// Visibility — hide any control that doesn't apply for this object type
|
// Visibility — hide any control that doesn't apply for this object type
|
||||||
show_alert?: boolean;
|
show_alert?: boolean;
|
||||||
show_priority?: boolean;
|
show_priority?: boolean;
|
||||||
show_enable?: boolean;
|
show_enable?: boolean;
|
||||||
show_hide?: boolean;
|
show_hide?: boolean;
|
||||||
show_labels?: boolean;
|
show_labels?: boolean;
|
||||||
|
|
||||||
// Permission gates — parent passes booleans derived from $ae_loc
|
// Permission gates — parent passes booleans derived from $ae_loc
|
||||||
allow_delete?: boolean; // Hard permanent delete (manager+)
|
allow_delete?: boolean; // Hard permanent delete (manager+)
|
||||||
allow_disable?: boolean; // Soft disable/remove (administrator+)
|
allow_disable?: boolean; // Soft disable/remove (administrator+)
|
||||||
|
|
||||||
// Callbacks — parent handles API + refresh + navigation
|
// Callbacks — parent handles API + refresh + navigation
|
||||||
on_toggle?: (field: string, new_val: boolean) => void;
|
on_toggle?: (field: string, new_val: boolean) => void;
|
||||||
on_delete?: (method: 'delete' | 'disable') => void;
|
on_delete?: (method: 'delete' | 'disable') => void;
|
||||||
|
|
||||||
// Styling
|
// Styling
|
||||||
container_class?: string;
|
container_class?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
let {
|
let {
|
||||||
obj,
|
obj,
|
||||||
obj_label = 'record',
|
obj_label = 'record',
|
||||||
show_alert = true,
|
show_alert = true,
|
||||||
show_priority = true,
|
show_priority = true,
|
||||||
show_enable = true,
|
show_enable = true,
|
||||||
show_hide = true,
|
show_hide = true,
|
||||||
show_labels = true,
|
show_labels = true,
|
||||||
allow_delete = false,
|
allow_delete = false,
|
||||||
allow_disable = false,
|
allow_disable = false,
|
||||||
on_toggle,
|
on_toggle,
|
||||||
on_delete,
|
on_delete,
|
||||||
container_class = 'flex flex-row flex-wrap gap-1 items-center justify-evenly py-2 border-y border-surface-500/10'
|
container_class = 'flex flex-row flex-wrap gap-1 items-center justify-evenly py-2 border-y border-surface-500/10'
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
|
|
||||||
function toggle(field: string) {
|
function toggle(field: string) {
|
||||||
if (on_toggle) on_toggle(field, !obj?.[field]);
|
if (on_toggle) on_toggle(field, !obj?.[field]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle_delete(method: 'delete' | 'disable') {
|
function handle_delete(method: 'delete' | 'disable') {
|
||||||
const msg =
|
const msg =
|
||||||
method === 'delete'
|
method === 'delete'
|
||||||
? `Permanently delete this ${obj_label}? This cannot be undone.`
|
? `Permanently delete this ${obj_label}? This cannot be undone.`
|
||||||
: `Remove (disable) this ${obj_label}?`;
|
: `Remove (disable) this ${obj_label}?`;
|
||||||
if (!confirm(msg)) return;
|
if (!confirm(msg)) return;
|
||||||
if (on_delete) on_delete(method);
|
if (on_delete) on_delete(method);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class={container_class}>
|
<div class={container_class}>
|
||||||
{#if show_labels}
|
{#if show_labels}
|
||||||
<span class="text-xs text-surface-500 flex items-center gap-1 uppercase font-bold tracking-wider mr-2">
|
<span
|
||||||
|
class="text-surface-500 mr-2 flex items-center gap-1 text-xs font-bold tracking-wider uppercase">
|
||||||
<Settings size="1.1em" /> Controls:
|
<Settings size="1.1em" /> Controls:
|
||||||
</span>
|
</span>
|
||||||
{/if}
|
{/if}
|
||||||
@@ -103,12 +104,10 @@
|
|||||||
class:preset-filled-warning-500={obj?.priority}
|
class:preset-filled-warning-500={obj?.priority}
|
||||||
class:preset-tonal-secondary={!obj?.priority}
|
class:preset-tonal-secondary={!obj?.priority}
|
||||||
class:hover:preset-filled-warning-500={!obj?.priority}
|
class:hover:preset-filled-warning-500={!obj?.priority}
|
||||||
title={obj?.priority ? 'Remove priority flag' : 'Mark as priority'}
|
title={obj?.priority ? 'Remove priority flag' : 'Mark as priority'}>
|
||||||
>
|
|
||||||
<Star
|
<Star
|
||||||
size="1.2em"
|
size="1.2em"
|
||||||
class={obj?.priority ? 'fill-current' : 'opacity-50'}
|
class={obj?.priority ? 'fill-current' : 'opacity-50'} />
|
||||||
/>
|
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
@@ -121,8 +120,7 @@
|
|||||||
class:preset-filled-warning-500={obj?.hide}
|
class:preset-filled-warning-500={obj?.hide}
|
||||||
class:preset-tonal-secondary={!obj?.hide}
|
class:preset-tonal-secondary={!obj?.hide}
|
||||||
class:hover:preset-filled-warning-500={!obj?.hide}
|
class:hover:preset-filled-warning-500={!obj?.hide}
|
||||||
title={obj?.hide ? 'Unhide this record' : 'Hide this record'}
|
title={obj?.hide ? 'Unhide this record' : 'Hide this record'}>
|
||||||
>
|
|
||||||
{#if obj?.hide}
|
{#if obj?.hide}
|
||||||
<EyeOff size="1.2em" class="text-warning-500" />
|
<EyeOff size="1.2em" class="text-warning-500" />
|
||||||
{:else}
|
{:else}
|
||||||
@@ -140,8 +138,7 @@
|
|||||||
class:preset-filled-success-500={obj?.enable}
|
class:preset-filled-success-500={obj?.enable}
|
||||||
class:preset-filled-error-500={!obj?.enable}
|
class:preset-filled-error-500={!obj?.enable}
|
||||||
class:hover:preset-filled-success-500={!obj?.enable}
|
class:hover:preset-filled-success-500={!obj?.enable}
|
||||||
title={obj?.enable ? 'Disable this record' : 'Enable this record'}
|
title={obj?.enable ? 'Disable this record' : 'Enable this record'}>
|
||||||
>
|
|
||||||
{#if obj?.enable}
|
{#if obj?.enable}
|
||||||
<ToggleRight size="1.2em" class="text-success-300" />
|
<ToggleRight size="1.2em" class="text-success-300" />
|
||||||
{:else}
|
{:else}
|
||||||
@@ -159,8 +156,7 @@
|
|||||||
class:preset-filled-error-500={obj?.alert}
|
class:preset-filled-error-500={obj?.alert}
|
||||||
class:preset-tonal-secondary={!obj?.alert}
|
class:preset-tonal-secondary={!obj?.alert}
|
||||||
class:hover:preset-filled-error-500={!obj?.alert}
|
class:hover:preset-filled-error-500={!obj?.alert}
|
||||||
title={obj?.alert ? 'Remove alert status' : 'Mark as alert'}
|
title={obj?.alert ? 'Remove alert status' : 'Mark as alert'}>
|
||||||
>
|
|
||||||
{#if obj?.alert}
|
{#if obj?.alert}
|
||||||
<Bell size="1.2em" class="text-error-300" />
|
<Bell size="1.2em" class="text-error-300" />
|
||||||
{:else}
|
{:else}
|
||||||
@@ -175,8 +171,7 @@
|
|||||||
type="button"
|
type="button"
|
||||||
onclick={() => handle_delete('delete')}
|
onclick={() => handle_delete('delete')}
|
||||||
class="btn-icon btn-icon-sm preset-filled-error-500 hover:preset-filled-error-600 transition"
|
class="btn-icon btn-icon-sm preset-filled-error-500 hover:preset-filled-error-600 transition"
|
||||||
title="Permanently delete this {obj_label}"
|
title="Permanently delete this {obj_label}">
|
||||||
>
|
|
||||||
<Trash2 size="1.2em" />
|
<Trash2 size="1.2em" />
|
||||||
</button>
|
</button>
|
||||||
{:else if allow_disable}
|
{:else if allow_disable}
|
||||||
@@ -184,8 +179,7 @@
|
|||||||
type="button"
|
type="button"
|
||||||
onclick={() => handle_delete('disable')}
|
onclick={() => handle_delete('disable')}
|
||||||
class="btn-icon btn-icon-sm preset-filled-warning-500 hover:preset-filled-warning-600 transition"
|
class="btn-icon btn-icon-sm preset-filled-warning-500 hover:preset-filled-warning-600 transition"
|
||||||
title="Disable / soft-remove this {obj_label}"
|
title="Disable / soft-remove this {obj_label}">
|
||||||
>
|
|
||||||
<CircleMinus size="1.2em" />
|
<CircleMinus size="1.2em" />
|
||||||
</button>
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import type { key_val } from '$lib/stores/ae_stores';
|
import type { key_val } from '$lib/stores/ae_stores';
|
||||||
import { api } from '$lib/api/api';
|
import { api } from '$lib/api/api';
|
||||||
import { get_ae_obj_li_for_obj_id_crud_v2 } from '$lib/ae_api/api_get__crud_obj_li_v2';
|
|
||||||
|
|
||||||
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_events } from '$lib/ae_events/db_events';
|
import { db_events } from '$lib/ae_events/db_events';
|
||||||
@@ -47,7 +46,9 @@ export async function load_ae_obj_id__event({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_Event | null> {
|
}): Promise<ae_Event | null> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** load_ae_obj_id__event() *** event_id=${event_id} (SWR Optimization)`);
|
console.log(
|
||||||
|
`*** load_ae_obj_id__event() *** event_id=${event_id} (SWR Optimization)`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hierarchy Enforcement: Pulling presentations/presenters requires pulling sessions first
|
// Hierarchy Enforcement: Pulling presentations/presenters requires pulling sessions first
|
||||||
@@ -58,20 +59,43 @@ export async function load_ae_obj_id__event({
|
|||||||
try {
|
try {
|
||||||
const cached_event = await db_events.event.get(event_id);
|
const cached_event = await db_events.event.get(event_id);
|
||||||
if (cached_event) {
|
if (cached_event) {
|
||||||
if (log_lvl) console.log('EVENT LOAD: Cache hit. Returning stale data immediately.');
|
if (log_lvl)
|
||||||
|
console.log(
|
||||||
|
'EVENT LOAD: Cache hit. Returning stale data immediately.'
|
||||||
|
);
|
||||||
|
|
||||||
// Trigger background refresh
|
// Trigger background refresh
|
||||||
_refresh_event_v3_background({
|
_refresh_event_background({
|
||||||
api_cfg, event_id, view, try_cache,
|
api_cfg,
|
||||||
inc_device_li, inc_file_li, inc_location_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_template_li,
|
event_id,
|
||||||
enabled, hidden,
|
view,
|
||||||
|
try_cache,
|
||||||
|
inc_device_li,
|
||||||
|
inc_file_li,
|
||||||
|
inc_location_li,
|
||||||
|
inc_session_li,
|
||||||
|
inc_presentation_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
inc_template_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
log_lvl: 0
|
log_lvl: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
// Still handle nested loads for the cached version to ensure UI richness
|
// Still handle nested loads for the cached version to ensure UI richness
|
||||||
return await _handle_nested_loads(cached_event, {
|
return await _handle_nested_loads(cached_event, {
|
||||||
api_cfg, inc_device_li, inc_file_li, inc_location_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_template_li,
|
api_cfg,
|
||||||
enabled, hidden, try_cache, log_lvl
|
inc_device_li,
|
||||||
|
inc_file_li,
|
||||||
|
inc_location_li,
|
||||||
|
inc_session_li,
|
||||||
|
inc_presentation_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
inc_template_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
try_cache,
|
||||||
|
log_lvl
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -80,10 +104,20 @@ export async function load_ae_obj_id__event({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2. SLOW PATH: Wait for API if cache is empty or try_cache is false
|
// 2. SLOW PATH: Wait for API if cache is empty or try_cache is false
|
||||||
return await _refresh_event_v3_background({
|
return await _refresh_event_background({
|
||||||
api_cfg, event_id, view, try_cache,
|
api_cfg,
|
||||||
inc_device_li, inc_file_li, inc_location_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_template_li,
|
event_id,
|
||||||
enabled, hidden,
|
view,
|
||||||
|
try_cache,
|
||||||
|
inc_device_li,
|
||||||
|
inc_file_li,
|
||||||
|
inc_location_li,
|
||||||
|
inc_session_li,
|
||||||
|
inc_presentation_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
inc_template_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -91,10 +125,20 @@ export async function load_ae_obj_id__event({
|
|||||||
/**
|
/**
|
||||||
* Internal helper to perform the actual API fetch and cache update for events
|
* Internal helper to perform the actual API fetch and cache update for events
|
||||||
*/
|
*/
|
||||||
async function _refresh_event_v3_background({
|
async function _refresh_event_background({
|
||||||
api_cfg, event_id, view, try_cache,
|
api_cfg,
|
||||||
inc_device_li, inc_file_li, inc_location_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_template_li,
|
event_id,
|
||||||
enabled, hidden,
|
view,
|
||||||
|
try_cache,
|
||||||
|
inc_device_li,
|
||||||
|
inc_file_li,
|
||||||
|
inc_location_li,
|
||||||
|
inc_session_li,
|
||||||
|
inc_presentation_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
inc_template_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
log_lvl
|
log_lvl
|
||||||
}: any) {
|
}: any) {
|
||||||
// Check if offline
|
// Check if offline
|
||||||
@@ -104,7 +148,7 @@ async function _refresh_event_v3_background({
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await api.get_ae_obj_v3({
|
const result = await api.get_ae_obj({
|
||||||
api_cfg: api_cfg,
|
api_cfg: api_cfg,
|
||||||
obj_type: 'event',
|
obj_type: 'event',
|
||||||
obj_id: event_id,
|
obj_id: event_id,
|
||||||
@@ -130,8 +174,18 @@ async function _refresh_event_v3_background({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return await _handle_nested_loads(processed_obj, {
|
return await _handle_nested_loads(processed_obj, {
|
||||||
api_cfg, inc_device_li, inc_file_li, inc_location_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_template_li,
|
api_cfg,
|
||||||
enabled, hidden, try_cache: false, log_lvl
|
inc_device_li,
|
||||||
|
inc_file_li,
|
||||||
|
inc_location_li,
|
||||||
|
inc_session_li,
|
||||||
|
inc_presentation_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
inc_template_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
try_cache: false,
|
||||||
|
log_lvl
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
@@ -143,8 +197,27 @@ async function _refresh_event_v3_background({
|
|||||||
/**
|
/**
|
||||||
* Shared logic for loading nested child collections
|
* Shared logic for loading nested child collections
|
||||||
*/
|
*/
|
||||||
async function _handle_nested_loads(event_obj: any, { api_cfg, inc_device_li, inc_file_li, inc_location_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_template_li, enabled, hidden, try_cache, log_lvl }: any) {
|
async function _handle_nested_loads(
|
||||||
if (log_lvl) console.log(`Loading nested collections for event: ${event_obj.event_id} (Devices: ${inc_device_li}, Files: ${inc_file_li}, Locations: ${inc_location_li}, Sessions: ${inc_session_li}, Presentations: ${inc_presentation_li}, Presenters: ${inc_presenter_li}, Templates: ${inc_template_li})`);
|
event_obj: any,
|
||||||
|
{
|
||||||
|
api_cfg,
|
||||||
|
inc_device_li,
|
||||||
|
inc_file_li,
|
||||||
|
inc_location_li,
|
||||||
|
inc_session_li,
|
||||||
|
inc_presentation_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
inc_template_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
try_cache,
|
||||||
|
log_lvl
|
||||||
|
}: any
|
||||||
|
) {
|
||||||
|
if (log_lvl)
|
||||||
|
console.log(
|
||||||
|
`Loading nested collections for event: ${event_obj.event_id} (Devices: ${inc_device_li}, Files: ${inc_file_li}, Locations: ${inc_location_li}, Sessions: ${inc_session_li}, Presentations: ${inc_presentation_li}, Presenters: ${inc_presenter_li}, Templates: ${inc_template_li})`
|
||||||
|
);
|
||||||
// String-Only ID Vision: the '_id' field IS the string ID
|
// String-Only ID Vision: the '_id' field IS the string ID
|
||||||
const current_event_id = event_obj.id || event_obj.event_id;
|
const current_event_id = event_obj.id || event_obj.event_id;
|
||||||
|
|
||||||
@@ -152,56 +225,66 @@ async function _handle_nested_loads(event_obj: any, { api_cfg, inc_device_li, in
|
|||||||
const tasks = [];
|
const tasks = [];
|
||||||
|
|
||||||
if (inc_device_li) {
|
if (inc_device_li) {
|
||||||
tasks.push(load_ae_obj_li__event_device({
|
tasks.push(
|
||||||
api_cfg,
|
load_ae_obj_li__event_device({
|
||||||
for_obj_type: 'event',
|
api_cfg,
|
||||||
for_obj_id: current_event_id,
|
for_obj_type: 'event',
|
||||||
try_cache,
|
for_obj_id: current_event_id,
|
||||||
log_lvl
|
try_cache,
|
||||||
}).then(res => event_obj.event_device_obj_li = res));
|
log_lvl
|
||||||
|
}).then((res) => (event_obj.event_device_obj_li = res))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (inc_file_li) {
|
if (inc_file_li) {
|
||||||
tasks.push(load_ae_obj_li__event_file({
|
tasks.push(
|
||||||
api_cfg,
|
load_ae_obj_li__event_file({
|
||||||
for_obj_type: 'event',
|
api_cfg,
|
||||||
for_obj_id: current_event_id,
|
for_obj_type: 'event',
|
||||||
enabled: 'all',
|
for_obj_id: current_event_id,
|
||||||
limit: 100,
|
enabled: 'all',
|
||||||
try_cache,
|
limit: 100,
|
||||||
log_lvl
|
try_cache,
|
||||||
}).then(res => event_obj.event_file_li = res));
|
log_lvl
|
||||||
|
}).then((res) => (event_obj.event_file_li = res))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (inc_location_li) {
|
if (inc_location_li) {
|
||||||
tasks.push(load_ae_obj_li__event_location({
|
tasks.push(
|
||||||
api_cfg,
|
load_ae_obj_li__event_location({
|
||||||
for_obj_type: 'event',
|
api_cfg,
|
||||||
for_obj_id: current_event_id,
|
for_obj_type: 'event',
|
||||||
enabled,
|
for_obj_id: current_event_id,
|
||||||
hidden,
|
enabled,
|
||||||
try_cache,
|
hidden,
|
||||||
log_lvl
|
try_cache,
|
||||||
}).then(res => event_obj.event_location_obj_li = res));
|
log_lvl
|
||||||
|
}).then((res) => (event_obj.event_location_obj_li = res))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (inc_session_li) {
|
if (inc_session_li) {
|
||||||
tasks.push(load_ae_obj_li__event_session({
|
tasks.push(
|
||||||
api_cfg,
|
load_ae_obj_li__event_session({
|
||||||
for_obj_type: 'event',
|
api_cfg,
|
||||||
for_obj_id: current_event_id,
|
for_obj_type: 'event',
|
||||||
inc_presentation_li,
|
for_obj_id: current_event_id,
|
||||||
inc_presenter_li,
|
inc_presentation_li,
|
||||||
enabled,
|
inc_presenter_li,
|
||||||
hidden,
|
enabled,
|
||||||
try_cache,
|
hidden,
|
||||||
log_lvl
|
try_cache,
|
||||||
}).then(res => event_obj.event_session_obj_li = res));
|
log_lvl
|
||||||
|
}).then((res) => (event_obj.event_session_obj_li = res))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (inc_template_li) {
|
if (inc_template_li) {
|
||||||
tasks.push(load_ae_obj_li__event_badge_template({
|
tasks.push(
|
||||||
api_cfg,
|
load_ae_obj_li__event_badge_template({
|
||||||
event_id: current_event_id,
|
api_cfg,
|
||||||
try_cache,
|
event_id: current_event_id,
|
||||||
log_lvl
|
try_cache,
|
||||||
}).then(res => event_obj.event_badge_template_obj_li = res));
|
log_lvl
|
||||||
|
}).then((res) => (event_obj.event_badge_template_obj_li = res))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tasks.length > 0) await Promise.all(tasks);
|
if (tasks.length > 0) await Promise.all(tasks);
|
||||||
@@ -239,20 +322,25 @@ export async function load_ae_obj_li__event({
|
|||||||
inc_presenter_li?: boolean;
|
inc_presenter_li?: boolean;
|
||||||
limit?: number;
|
limit?: number;
|
||||||
offset?: number;
|
offset?: number;
|
||||||
order_by_li?: Record<string, 'ASC' | 'DESC'> | Record<string, 'ASC' | 'DESC'>[];
|
order_by_li?:
|
||||||
|
| Record<string, 'ASC' | 'DESC'>
|
||||||
|
| Record<string, 'ASC' | 'DESC'>[];
|
||||||
params?: key_val;
|
params?: key_val;
|
||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_Event[]> {
|
}): Promise<ae_Event[]> {
|
||||||
|
|
||||||
// Hierarchy Enforcement: Pulling presentations/presenters requires pulling sessions first
|
// Hierarchy Enforcement: Pulling presentations/presenters requires pulling sessions first
|
||||||
if (inc_presenter_li || inc_presentation_li) inc_session_li = true;
|
if (inc_presenter_li || inc_presentation_li) inc_session_li = true;
|
||||||
|
|
||||||
// Check if offline
|
// Check if offline
|
||||||
if (typeof navigator !== 'undefined' && !navigator.onLine) {
|
if (typeof navigator !== 'undefined' && !navigator.onLine) {
|
||||||
if (log_lvl) console.log('Browser is offline. Skipping API and attempting cache load.');
|
if (log_lvl)
|
||||||
|
console.log(
|
||||||
|
'Browser is offline. Skipping API and attempting cache load.'
|
||||||
|
);
|
||||||
ae_promises.load__event_obj_li = await db_events.event
|
ae_promises.load__event_obj_li = await db_events.event
|
||||||
.where('account_id').equals(for_obj_id)
|
.where('account_id')
|
||||||
|
.equals(for_obj_id)
|
||||||
.toArray();
|
.toArray();
|
||||||
return ae_promises.load__event_obj_li || [];
|
return ae_promises.load__event_obj_li || [];
|
||||||
}
|
}
|
||||||
@@ -265,10 +353,14 @@ export async function load_ae_obj_li__event({
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (for_obj_id) {
|
if (for_obj_id) {
|
||||||
search_query.and.push({ field: `${for_obj_type}_id`, op: 'eq', value: for_obj_id });
|
search_query.and.push({
|
||||||
|
field: `${for_obj_type}_id`,
|
||||||
|
op: 'eq',
|
||||||
|
value: for_obj_id
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
promise = api.search_ae_obj_v3({
|
promise = api.search_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'event',
|
obj_type: 'event',
|
||||||
headers: { 'x-account-id': for_obj_id },
|
headers: { 'x-account-id': for_obj_id },
|
||||||
@@ -282,7 +374,7 @@ export async function load_ae_obj_li__event({
|
|||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
promise = api.get_ae_obj_li_v3({
|
promise = api.get_ae_obj_li({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'event',
|
obj_type: 'event',
|
||||||
for_obj_type,
|
for_obj_type,
|
||||||
@@ -320,9 +412,11 @@ export async function load_ae_obj_li__event({
|
|||||||
} else {
|
} else {
|
||||||
console.log('No results returned from API.');
|
console.log('No results returned from API.');
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
if (log_lvl) console.log('Attempting to load from local cache...');
|
if (log_lvl)
|
||||||
|
console.log('Attempting to load from local cache...');
|
||||||
ae_promises.load__event_obj_li = await db_events.event
|
ae_promises.load__event_obj_li = await db_events.event
|
||||||
.where('account_id').equals(for_obj_id)
|
.where('account_id')
|
||||||
|
.equals(for_obj_id)
|
||||||
.toArray();
|
.toArray();
|
||||||
} else {
|
} else {
|
||||||
ae_promises.load__event_obj_li = [];
|
ae_promises.load__event_obj_li = [];
|
||||||
@@ -331,9 +425,13 @@ export async function load_ae_obj_li__event({
|
|||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.log('API request failed.', error);
|
console.log('API request failed.', error);
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
if (log_lvl) console.log('Attempting to load from local cache after error...');
|
if (log_lvl)
|
||||||
|
console.log(
|
||||||
|
'Attempting to load from local cache after error...'
|
||||||
|
);
|
||||||
ae_promises.load__event_obj_li = await db_events.event
|
ae_promises.load__event_obj_li = await db_events.event
|
||||||
.where('account_id').equals(for_obj_id)
|
.where('account_id')
|
||||||
|
.equals(for_obj_id)
|
||||||
.toArray();
|
.toArray();
|
||||||
} else {
|
} else {
|
||||||
ae_promises.load__event_obj_li = [];
|
ae_promises.load__event_obj_li = [];
|
||||||
@@ -341,18 +439,20 @@ export async function load_ae_obj_li__event({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (inc_session_li && ae_promises.load__event_obj_li) {
|
if (inc_session_li && ae_promises.load__event_obj_li) {
|
||||||
const session_tasks = ae_promises.load__event_obj_li.map((event_obj: any) => {
|
const session_tasks = ae_promises.load__event_obj_li.map(
|
||||||
const current_event_id = event_obj.id || event_obj.event_id;
|
(event_obj: any) => {
|
||||||
return load_ae_obj_li__event_session({
|
const current_event_id = event_obj.id || event_obj.event_id;
|
||||||
api_cfg,
|
return load_ae_obj_li__event_session({
|
||||||
for_obj_type: 'event',
|
api_cfg,
|
||||||
for_obj_id: current_event_id,
|
for_obj_type: 'event',
|
||||||
inc_presentation_li,
|
for_obj_id: current_event_id,
|
||||||
inc_presenter_li,
|
inc_presentation_li,
|
||||||
try_cache,
|
inc_presenter_li,
|
||||||
log_lvl
|
try_cache,
|
||||||
}).then((res) => (event_obj.event_session_obj_li = res));
|
log_lvl
|
||||||
});
|
}).then((res) => (event_obj.event_session_obj_li = res));
|
||||||
|
}
|
||||||
|
);
|
||||||
await Promise.all(session_tasks);
|
await Promise.all(session_tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,7 +475,7 @@ export async function create_ae_obj__event({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_Event | null> {
|
}): Promise<ae_Event | null> {
|
||||||
const result = await api.create_ae_obj_v3({
|
const result = await api.create_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'event',
|
obj_type: 'event',
|
||||||
fields: {
|
fields: {
|
||||||
@@ -424,7 +524,7 @@ export async function delete_ae_obj_id__event({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
const result = await api.delete_ae_obj_v3({
|
const result = await api.delete_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'event',
|
obj_type: 'event',
|
||||||
obj_id: event_id,
|
obj_id: event_id,
|
||||||
@@ -456,7 +556,7 @@ export async function update_ae_obj__event({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_Event | null> {
|
}): Promise<ae_Event | null> {
|
||||||
const result = await api.update_ae_obj_v3({
|
const result = await api.update_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'event',
|
obj_type: 'event',
|
||||||
obj_id: event_id,
|
obj_id: event_id,
|
||||||
@@ -544,13 +644,21 @@ export async function search__event({
|
|||||||
};
|
};
|
||||||
const params: key_val = {};
|
const params: key_val = {};
|
||||||
|
|
||||||
search_query.and.push({ field: 'default_qry_str', op: 'like', value: `%${qry_str.trim()}%` });
|
search_query.and.push({
|
||||||
params['lk_qry'] = { 'default_qry_str': qry_str.trim() };
|
field: 'default_qry_str',
|
||||||
|
op: 'like',
|
||||||
|
value: `%${qry_str.trim()}%`
|
||||||
|
});
|
||||||
|
params['lk_qry'] = { default_qry_str: qry_str.trim() };
|
||||||
|
|
||||||
if (for_obj_id) {
|
if (for_obj_id) {
|
||||||
// V3 Standard: Use random string ID for body filters.
|
// V3 Standard: Use random string ID for body filters.
|
||||||
// The API resolves this to the integer column automatically.
|
// The API resolves this to the integer column automatically.
|
||||||
search_query.and.push({ field: `${for_obj_type}_id_random`, op: 'eq', value: for_obj_id });
|
search_query.and.push({
|
||||||
|
field: `${for_obj_type}_id_random`,
|
||||||
|
op: 'eq',
|
||||||
|
value: for_obj_id
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: We do NOT push 'physical' and 'virtual' to the server-side query here.
|
// NOTE: We do NOT push 'physical' and 'virtual' to the server-side query here.
|
||||||
@@ -558,7 +666,7 @@ export async function search__event({
|
|||||||
// meetings that are only physical or only virtual if both filters are active.
|
// meetings that are only physical or only virtual if both filters are active.
|
||||||
// We handle this in the Client-side Filter Layer below for correct OR logic.
|
// We handle this in the Client-side Filter Layer below for correct OR logic.
|
||||||
|
|
||||||
result_li = await api.search_ae_obj_v3({
|
result_li = await api.search_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'event',
|
obj_type: 'event',
|
||||||
headers: { 'x-account-id': for_obj_id },
|
headers: { 'x-account-id': for_obj_id },
|
||||||
@@ -574,7 +682,7 @@ export async function search__event({
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Option B: List All
|
// Option B: List All
|
||||||
result_li = await api.get_ae_obj_li_v3({
|
result_li = await api.get_ae_obj_li({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'event',
|
obj_type: 'event',
|
||||||
for_obj_type,
|
for_obj_type,
|
||||||
@@ -594,7 +702,11 @@ export async function search__event({
|
|||||||
let valid_result_li: ae_Event[] = [];
|
let valid_result_li: ae_Event[] = [];
|
||||||
if (Array.isArray(result_li)) {
|
if (Array.isArray(result_li)) {
|
||||||
valid_result_li = result_li;
|
valid_result_li = result_li;
|
||||||
} else if (result_li && typeof result_li === 'object' && Array.isArray((result_li as any).data)) {
|
} else if (
|
||||||
|
result_li &&
|
||||||
|
typeof result_li === 'object' &&
|
||||||
|
Array.isArray((result_li as any).data)
|
||||||
|
) {
|
||||||
valid_result_li = (result_li as any).data;
|
valid_result_li = (result_li as any).data;
|
||||||
} else {
|
} else {
|
||||||
return [];
|
return [];
|
||||||
@@ -642,13 +754,12 @@ export async function search__event({
|
|||||||
|
|
||||||
// Handle person ID filter
|
// Handle person ID filter
|
||||||
if (qry_person_id) {
|
if (qry_person_id) {
|
||||||
const match = (
|
const match =
|
||||||
ev.external_person_id === qry_person_id ||
|
ev.external_person_id === qry_person_id ||
|
||||||
ev.poc_person_id === qry_person_id ||
|
ev.poc_person_id === qry_person_id ||
|
||||||
ev.poc_person_id_random === qry_person_id ||
|
ev.poc_person_id_random === qry_person_id ||
|
||||||
ev.poc_event_person_id === qry_person_id ||
|
ev.poc_event_person_id === qry_person_id ||
|
||||||
ev.poc_event_person_id_random === qry_person_id
|
ev.poc_event_person_id_random === qry_person_id;
|
||||||
);
|
|
||||||
if (!match) return false;
|
if (!match) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -656,7 +767,9 @@ export async function search__event({
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`Filter results (Hybrid): Input=${processed_obj_li.length}, Output=${filtered_obj_li.length}`);
|
console.log(
|
||||||
|
`Filter results (Hybrid): Input=${processed_obj_li.length}, Output=${filtered_obj_li.length}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return filtered_obj_li.slice(0, limit);
|
return filtered_obj_li.slice(0, limit);
|
||||||
@@ -664,139 +777,6 @@ export async function search__event({
|
|||||||
|
|
||||||
export const qry_ae_obj_li__event = search__event;
|
export const qry_ae_obj_li__event = search__event;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specialized search function for IDAA module using legacy V2 endpoints.
|
|
||||||
* This is isolated to prevent V3 migration bugs from affecting Recovery Meetings.
|
|
||||||
*/
|
|
||||||
// Updated 2026-01-20
|
|
||||||
export async function qry_ae_obj_li__event_v2({
|
|
||||||
api_cfg,
|
|
||||||
for_obj_type = 'account',
|
|
||||||
for_obj_id,
|
|
||||||
qry_str,
|
|
||||||
qry_person_id = null,
|
|
||||||
qry_conference = null,
|
|
||||||
qry_physical = null,
|
|
||||||
qry_virtual = null,
|
|
||||||
qry_type = null,
|
|
||||||
enabled = 'enabled',
|
|
||||||
hidden = 'not_hidden',
|
|
||||||
view = 'default',
|
|
||||||
limit = 99,
|
|
||||||
offset = 0,
|
|
||||||
order_by_li = { start_datetime: 'DESC' } as const,
|
|
||||||
try_cache = true,
|
|
||||||
log_lvl = 0
|
|
||||||
}: {
|
|
||||||
api_cfg: any;
|
|
||||||
for_obj_type?: string;
|
|
||||||
for_obj_id: string;
|
|
||||||
qry_str?: string;
|
|
||||||
qry_person_id?: string | null;
|
|
||||||
qry_conference?: boolean | null;
|
|
||||||
qry_physical?: boolean | null;
|
|
||||||
qry_virtual?: boolean | null;
|
|
||||||
qry_type?: string | null;
|
|
||||||
enabled?: 'enabled' | 'all' | 'not_enabled';
|
|
||||||
hidden?: 'hidden' | 'all' | 'not_hidden';
|
|
||||||
view?: string;
|
|
||||||
limit?: number;
|
|
||||||
offset?: number;
|
|
||||||
order_by_li?: Record<string, 'ASC' | 'DESC'>;
|
|
||||||
try_cache?: boolean;
|
|
||||||
log_lvl?: number;
|
|
||||||
}) {
|
|
||||||
if (log_lvl) console.log('*** qry_ae_obj_li__event_v2() ***');
|
|
||||||
|
|
||||||
const params_json: any = { qry: { and: [] } };
|
|
||||||
|
|
||||||
if (qry_str) {
|
|
||||||
// Use default_qry_str for searching as requested
|
|
||||||
params_json.qry.and.push({ field: 'default_qry_str', op: 'like', value: `%${qry_str}%` });
|
|
||||||
}
|
|
||||||
|
|
||||||
const result_li = await get_ae_obj_li_for_obj_id_crud_v2({
|
|
||||||
api_cfg,
|
|
||||||
obj_type: 'event',
|
|
||||||
for_obj_type,
|
|
||||||
for_obj_id,
|
|
||||||
enabled,
|
|
||||||
hidden,
|
|
||||||
limit,
|
|
||||||
offset,
|
|
||||||
order_by_li,
|
|
||||||
params_json,
|
|
||||||
log_lvl
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!result_li) return [];
|
|
||||||
|
|
||||||
const processed_obj_li = await process_ae_obj__event_props({
|
|
||||||
obj_li: result_li,
|
|
||||||
log_lvl: log_lvl
|
|
||||||
});
|
|
||||||
|
|
||||||
if (try_cache) {
|
|
||||||
await db_save_ae_obj_li__ae_obj({
|
|
||||||
db_instance: db_events,
|
|
||||||
table_name: 'event',
|
|
||||||
obj_li: processed_obj_li,
|
|
||||||
properties_to_save: properties_to_save,
|
|
||||||
log_lvl: log_lvl
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Client-side Filter Layer
|
|
||||||
const filtered_obj_li = processed_obj_li.filter((ev: any) => {
|
|
||||||
// Handle conference filter
|
|
||||||
if (qry_conference != null) {
|
|
||||||
const ev_conf = ev.conference === true || ev.conference === 1 || ev.conference === '1';
|
|
||||||
if (ev_conf !== !!qry_conference) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Location Filtering (Inclusive OR logic)
|
|
||||||
// If either filter is explicitly true, we restrict results.
|
|
||||||
// If both are false or null, we show everything.
|
|
||||||
if (qry_physical === true || qry_virtual === true) {
|
|
||||||
const ev_physical = ev.physical === true || ev.physical === 1 || ev.physical === '1';
|
|
||||||
const ev_virtual = ev.virtual === true || ev.virtual === 1 || ev.virtual === '1';
|
|
||||||
|
|
||||||
let match = false;
|
|
||||||
if (qry_physical === true && ev_physical) match = true;
|
|
||||||
if (qry_virtual === true && ev_virtual) match = true;
|
|
||||||
|
|
||||||
if (!match) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle type filter (skip if null, undefined, 'all', or empty string)
|
|
||||||
if (qry_type != null && qry_type !== 'all' && qry_type !== '') {
|
|
||||||
if (ev.type !== qry_type) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle person ID filter
|
|
||||||
if (qry_person_id) {
|
|
||||||
const match = (
|
|
||||||
ev.external_person_id === qry_person_id ||
|
|
||||||
ev.poc_person_id === qry_person_id ||
|
|
||||||
ev.poc_person_id_random === qry_person_id ||
|
|
||||||
ev.poc_event_person_id === qry_person_id ||
|
|
||||||
ev.poc_event_person_id_random === qry_person_id
|
|
||||||
);
|
|
||||||
if (!match) return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (log_lvl) {
|
|
||||||
console.log(`Filter results (V2): Input=${processed_obj_li.length}, Output=${filtered_obj_li.length}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return filtered_obj_li.slice(0, limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Updated 2026-03-10
|
// Updated 2026-03-10
|
||||||
export const properties_to_save = [
|
export const properties_to_save = [
|
||||||
'id',
|
'id',
|
||||||
@@ -913,14 +893,21 @@ async function _process_generic_props<T extends Record<string, any>>({
|
|||||||
const group = processed_obj.group ?? '0';
|
const group = processed_obj.group ?? '0';
|
||||||
const priority = processed_obj.priority ? 1 : 0;
|
const priority = processed_obj.priority ? 1 : 0;
|
||||||
const sort = processed_obj.sort ?? '0';
|
const sort = processed_obj.sort ?? '0';
|
||||||
const updated = processed_obj.updated_on ?? processed_obj.created_on ?? new Date(0).toISOString();
|
const updated =
|
||||||
|
processed_obj.updated_on ??
|
||||||
|
processed_obj.created_on ??
|
||||||
|
new Date(0).toISOString();
|
||||||
const name = processed_obj.name ?? '';
|
const name = processed_obj.name ?? '';
|
||||||
|
|
||||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
(processed_obj as any).tmp_sort_1 =
|
||||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
`${group}_${priority}_${sort}_${updated}`;
|
||||||
|
(processed_obj as any).tmp_sort_2 =
|
||||||
|
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||||
|
|
||||||
if (specific_processor) {
|
if (specific_processor) {
|
||||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
processed_obj = await Promise.resolve(
|
||||||
|
specific_processor(processed_obj)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
processed_obj_li.push(processed_obj as T);
|
processed_obj_li.push(processed_obj as T);
|
||||||
@@ -982,7 +969,8 @@ export function sync_config__event_pres_mgmt({
|
|||||||
pres_mgmt_cfg_remote?.label__session_poc_name_short ?? 'POC';
|
pres_mgmt_cfg_remote?.label__session_poc_name_short ?? 'POC';
|
||||||
pres_mgmt_cfg_local.label__session_poc_name =
|
pres_mgmt_cfg_local.label__session_poc_name =
|
||||||
pres_mgmt_cfg_remote?.label__session_poc_name ?? 'Point of Contact';
|
pres_mgmt_cfg_remote?.label__session_poc_name ?? 'Point of Contact';
|
||||||
pres_mgmt_cfg_local.hide__session_poc = pres_mgmt_cfg_remote?.hide__session_poc ?? false;
|
pres_mgmt_cfg_local.hide__session_poc =
|
||||||
|
pres_mgmt_cfg_remote?.hide__session_poc ?? false;
|
||||||
pres_mgmt_cfg_local.require__presenter_agree =
|
pres_mgmt_cfg_local.require__presenter_agree =
|
||||||
pres_mgmt_cfg_remote?.require__presenter_agree ?? false;
|
pres_mgmt_cfg_remote?.require__presenter_agree ?? false;
|
||||||
pres_mgmt_cfg_local.require__session_agree =
|
pres_mgmt_cfg_local.require__session_agree =
|
||||||
@@ -1007,24 +995,28 @@ export function sync_config__event_pres_mgmt({
|
|||||||
pres_mgmt_cfg_local.hide__presentation_datetime =
|
pres_mgmt_cfg_local.hide__presentation_datetime =
|
||||||
pres_mgmt_cfg_remote?.hide__presentation_datetime ?? false;
|
pres_mgmt_cfg_remote?.hide__presentation_datetime ?? false;
|
||||||
pres_mgmt_cfg_local.show_content__presentation_description =
|
pres_mgmt_cfg_local.show_content__presentation_description =
|
||||||
pres_mgmt_cfg_remote?.show_content__presentation_description ?? false;
|
pres_mgmt_cfg_remote?.show_content__presentation_description ??
|
||||||
|
false;
|
||||||
pres_mgmt_cfg_local.hide__presenter_code =
|
pres_mgmt_cfg_local.hide__presenter_code =
|
||||||
pres_mgmt_cfg_remote?.hide__presenter_code ?? false;
|
pres_mgmt_cfg_remote?.hide__presenter_code ?? false;
|
||||||
pres_mgmt_cfg_local.hide__presenter_biography =
|
pres_mgmt_cfg_local.hide__presenter_biography =
|
||||||
pres_mgmt_cfg_remote?.hide__presenter_biography ?? false;
|
pres_mgmt_cfg_remote?.hide__presenter_biography ?? false;
|
||||||
pres_mgmt_cfg_local.hide__session_code = pres_mgmt_cfg_remote?.hide__session_code ?? false;
|
pres_mgmt_cfg_local.hide__session_code =
|
||||||
|
pres_mgmt_cfg_remote?.hide__session_code ?? false;
|
||||||
pres_mgmt_cfg_local.hide__session_description =
|
pres_mgmt_cfg_local.hide__session_description =
|
||||||
pres_mgmt_cfg_remote?.hide__session_description ?? false;
|
pres_mgmt_cfg_remote?.hide__session_description ?? false;
|
||||||
pres_mgmt_cfg_local.hide__session_location =
|
pres_mgmt_cfg_local.hide__session_location =
|
||||||
pres_mgmt_cfg_remote?.hide__session_location ?? false;
|
pres_mgmt_cfg_remote?.hide__session_location ?? false;
|
||||||
pres_mgmt_cfg_local.hide__session_msg = pres_mgmt_cfg_remote?.hide__session_msg ?? false;
|
pres_mgmt_cfg_local.hide__session_msg =
|
||||||
|
pres_mgmt_cfg_remote?.hide__session_msg ?? false;
|
||||||
pres_mgmt_cfg_local.hide__session_poc_profile =
|
pres_mgmt_cfg_local.hide__session_poc_profile =
|
||||||
pres_mgmt_cfg_remote?.hide__session_poc_profile ?? false;
|
pres_mgmt_cfg_remote?.hide__session_poc_profile ?? false;
|
||||||
pres_mgmt_cfg_local.hide__session_poc_biography =
|
pres_mgmt_cfg_local.hide__session_poc_biography =
|
||||||
pres_mgmt_cfg_remote?.hide__session_poc_biography ?? false;
|
pres_mgmt_cfg_remote?.hide__session_poc_biography ?? false;
|
||||||
pres_mgmt_cfg_local.hide__session_poc_profile_pic =
|
pres_mgmt_cfg_local.hide__session_poc_profile_pic =
|
||||||
pres_mgmt_cfg_remote?.hide__session_poc_profile_pic ?? false;
|
pres_mgmt_cfg_remote?.hide__session_poc_profile_pic ?? false;
|
||||||
pres_mgmt_cfg_local.hide_launcher_link = pres_mgmt_cfg_remote?.hide_launcher_link ?? false;
|
pres_mgmt_cfg_local.hide_launcher_link =
|
||||||
|
pres_mgmt_cfg_remote?.hide_launcher_link ?? false;
|
||||||
pres_mgmt_cfg_local.hide_launcher_link_legacy =
|
pres_mgmt_cfg_local.hide_launcher_link_legacy =
|
||||||
pres_mgmt_cfg_remote?.hide_launcher_link_legacy ?? false;
|
pres_mgmt_cfg_remote?.hide_launcher_link_legacy ?? false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,31 +3,45 @@ import { describe, it, expect, vi } from 'vitest';
|
|||||||
// Use hoist-safe factories for vi.mock
|
// Use hoist-safe factories for vi.mock
|
||||||
vi.mock('$lib/api/api', () => ({
|
vi.mock('$lib/api/api', () => ({
|
||||||
api: {
|
api: {
|
||||||
create_nested_obj_v3: vi.fn(),
|
create_nested_obj: vi.fn(),
|
||||||
update_nested_obj_v3: vi.fn(),
|
update_nested_obj: vi.fn(),
|
||||||
delete_nested_ae_obj_v3: vi.fn(),
|
delete_nested_ae_obj: vi.fn(),
|
||||||
search_ae_obj_v3: vi.fn()
|
search_ae_obj: vi.fn()
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
vi.mock('$lib/ae_core/core__idb_dexie', () => ({ db_save_ae_obj_li__ae_obj: vi.fn() }));
|
vi.mock('$lib/ae_core/core__idb_dexie', () => ({
|
||||||
vi.mock('$lib/ae_events/db_events', () => ({ db_events: { badge: { get: vi.fn(), delete: vi.fn() } } }));
|
db_save_ae_obj_li__ae_obj: vi.fn()
|
||||||
vi.mock('$lib/ae_events/ae_events__event_badge_template', () => ({ load_ae_obj_id__event_badge_template: vi.fn() }));
|
}));
|
||||||
|
vi.mock('$lib/ae_events/db_events', () => ({
|
||||||
|
db_events: { badge: { get: vi.fn(), delete: vi.fn() } }
|
||||||
|
}));
|
||||||
|
vi.mock('$lib/ae_events/ae_events__event_badge_template', () => ({
|
||||||
|
load_ae_obj_id__event_badge_template: vi.fn()
|
||||||
|
}));
|
||||||
|
|
||||||
import { create_ae_obj__event_badge } from './ae_events__event_badge';
|
import { create_ae_obj__event_badge } from './ae_events__event_badge';
|
||||||
|
|
||||||
describe('create_ae_obj__event_badge', () => {
|
describe('create_ae_obj__event_badge', () => {
|
||||||
it('calls api.create_nested_obj_v3 with the correct params and returns the result', async () => {
|
it('calls api.create_nested_obj with the correct params and returns the result', async () => {
|
||||||
const mocked = await import('$lib/api/api');
|
const mocked = await import('$lib/api/api');
|
||||||
const mockCreateNested = mocked.api.create_nested_obj_v3 as any;
|
const mockCreateNested = mocked.api.create_nested_obj as any;
|
||||||
|
|
||||||
const fakeResult = { event_badge_id: 'eb123', full_name: 'Test User' };
|
const fakeResult = { event_badge_id: 'eb123', full_name: 'Test User' };
|
||||||
mockCreateNested.mockResolvedValue(fakeResult);
|
mockCreateNested.mockResolvedValue(fakeResult);
|
||||||
|
|
||||||
const api_cfg = { base_url: 'http://localhost', headers: {} };
|
const api_cfg = { base_url: 'http://localhost', headers: {} };
|
||||||
const event_id = 'evt1';
|
const event_id = 'evt1';
|
||||||
const data_kv = { full_name_override: 'Test User', email: 't@example.com' };
|
const data_kv = {
|
||||||
|
full_name_override: 'Test User',
|
||||||
|
email: 't@example.com'
|
||||||
|
};
|
||||||
|
|
||||||
const result = await create_ae_obj__event_badge({ api_cfg, event_id, data_kv, try_cache: false });
|
const result = await create_ae_obj__event_badge({
|
||||||
|
api_cfg,
|
||||||
|
event_id,
|
||||||
|
data_kv,
|
||||||
|
try_cache: false
|
||||||
|
});
|
||||||
|
|
||||||
expect(mockCreateNested).toHaveBeenCalled();
|
expect(mockCreateNested).toHaveBeenCalled();
|
||||||
expect(mockCreateNested).toHaveBeenCalledWith({
|
expect(mockCreateNested).toHaveBeenCalledWith({
|
||||||
@@ -45,15 +59,22 @@ describe('create_ae_obj__event_badge', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('update_ae_obj__event_badge', () => {
|
describe('update_ae_obj__event_badge', () => {
|
||||||
it('calls api.update_nested_obj_v3 with correct params and returns result', async () => {
|
it('calls api.update_nested_obj with correct params and returns result', async () => {
|
||||||
const mocked = await import('$lib/api/api');
|
const mocked = await import('$lib/api/api');
|
||||||
const mockUpdate = mocked.api.update_nested_obj_v3 as any;
|
const mockUpdate = mocked.api.update_nested_obj as any;
|
||||||
const fakeResult = { event_badge_id: 'eb999', full_name: 'Updated' };
|
const fakeResult = { event_badge_id: 'eb999', full_name: 'Updated' };
|
||||||
mockUpdate.mockResolvedValue(fakeResult);
|
mockUpdate.mockResolvedValue(fakeResult);
|
||||||
|
|
||||||
const { update_ae_obj__event_badge } = await import('./ae_events__event_badge');
|
const { update_ae_obj__event_badge } =
|
||||||
|
await import('./ae_events__event_badge');
|
||||||
const api_cfg = { base_url: 'http://localhost', headers: {} };
|
const api_cfg = { base_url: 'http://localhost', headers: {} };
|
||||||
const res = await update_ae_obj__event_badge({ api_cfg, event_id: 'evt1', event_badge_id: 'eb999', data_kv: { full_name_override: 'Updated' }, try_cache: false });
|
const res = await update_ae_obj__event_badge({
|
||||||
|
api_cfg,
|
||||||
|
event_id: 'evt1',
|
||||||
|
event_badge_id: 'eb999',
|
||||||
|
data_kv: { full_name_override: 'Updated' },
|
||||||
|
try_cache: false
|
||||||
|
});
|
||||||
|
|
||||||
expect(mockUpdate).toHaveBeenCalled();
|
expect(mockUpdate).toHaveBeenCalled();
|
||||||
expect(mockUpdate).toHaveBeenCalledWith({
|
expect(mockUpdate).toHaveBeenCalledWith({
|
||||||
@@ -71,18 +92,24 @@ describe('update_ae_obj__event_badge', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('delete_ae_obj_id__event_badge', () => {
|
describe('delete_ae_obj_id__event_badge', () => {
|
||||||
it('calls api.delete_nested_ae_obj_v3 and deletes from local DB when try_cache true', async () => {
|
it('calls api.delete_nested_ae_obj and deletes from local DB when try_cache true', async () => {
|
||||||
const mocked = await import('$lib/api/api');
|
const mocked = await import('$lib/api/api');
|
||||||
const mockDelete = mocked.api.delete_nested_ae_obj_v3 as any;
|
const mockDelete = mocked.api.delete_nested_ae_obj as any;
|
||||||
mockDelete.mockResolvedValue({ success: true });
|
mockDelete.mockResolvedValue({ success: true });
|
||||||
|
|
||||||
const db = await import('$lib/ae_events/db_events');
|
const db = await import('$lib/ae_events/db_events');
|
||||||
const dbDelete = db.db_events.badge.delete as any;
|
const dbDelete = db.db_events.badge.delete as any;
|
||||||
|
|
||||||
const { delete_ae_obj_id__event_badge } = await import('./ae_events__event_badge');
|
const { delete_ae_obj_id__event_badge } =
|
||||||
|
await import('./ae_events__event_badge');
|
||||||
|
|
||||||
const api_cfg = { base_url: 'http://localhost', headers: {} };
|
const api_cfg = { base_url: 'http://localhost', headers: {} };
|
||||||
const res = await delete_ae_obj_id__event_badge({ api_cfg, event_id: 'evt1', event_badge_id: 'ebDel', try_cache: true });
|
const res = await delete_ae_obj_id__event_badge({
|
||||||
|
api_cfg,
|
||||||
|
event_id: 'evt1',
|
||||||
|
event_badge_id: 'ebDel',
|
||||||
|
try_cache: true
|
||||||
|
});
|
||||||
|
|
||||||
expect(mockDelete).toHaveBeenCalled();
|
expect(mockDelete).toHaveBeenCalled();
|
||||||
expect(dbDelete).toHaveBeenCalledWith('ebDel');
|
expect(dbDelete).toHaveBeenCalledWith('ebDel');
|
||||||
@@ -91,15 +118,21 @@ describe('delete_ae_obj_id__event_badge', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('search__event_badge', () => {
|
describe('search__event_badge', () => {
|
||||||
it('calls api.search_ae_obj_v3 and returns list (handles data envelope)', async () => {
|
it('calls api.search_ae_obj and returns list (handles data envelope)', async () => {
|
||||||
const mocked = await import('$lib/api/api');
|
const mocked = await import('$lib/api/api');
|
||||||
const mockSearch = mocked.api.search_ae_obj_v3 as any;
|
const mockSearch = mocked.api.search_ae_obj as any;
|
||||||
const fakeList = [{ event_badge_id: 'eb1' }, { event_badge_id: 'eb2' }];
|
const fakeList = [{ event_badge_id: 'eb1' }, { event_badge_id: 'eb2' }];
|
||||||
mockSearch.mockResolvedValue({ data: fakeList });
|
mockSearch.mockResolvedValue({ data: fakeList });
|
||||||
|
|
||||||
const { search__event_badge } = await import('./ae_events__event_badge');
|
const { search__event_badge } =
|
||||||
|
await import('./ae_events__event_badge');
|
||||||
const api_cfg = { base_url: 'http://localhost', headers: {} };
|
const api_cfg = { base_url: 'http://localhost', headers: {} };
|
||||||
const res = await search__event_badge({ api_cfg, event_id: 'evt1', fulltext_search_qry_str: 'Test', try_cache: false });
|
const res = await search__event_badge({
|
||||||
|
api_cfg,
|
||||||
|
event_id: 'evt1',
|
||||||
|
fulltext_search_qry_str: 'Test',
|
||||||
|
try_cache: false
|
||||||
|
});
|
||||||
|
|
||||||
expect(mockSearch).toHaveBeenCalled();
|
expect(mockSearch).toHaveBeenCalled();
|
||||||
expect(Array.isArray(res)).toBe(true);
|
expect(Array.isArray(res)).toBe(true);
|
||||||
|
|||||||
@@ -35,29 +35,36 @@ export async function load_ae_obj_id__event_badge({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventBadge | null> {
|
}): Promise<ae_EventBadge | null> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** load_ae_obj_id__event_badge() *** event_badge_id=${event_badge_id}`);
|
console.log(
|
||||||
|
`*** load_ae_obj_id__event_badge() *** event_badge_id=${event_badge_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ae_promises.load__event_badge_obj = await api
|
ae_promises.load__event_badge_obj = await api.get_ae_obj({
|
||||||
.get_ae_obj_v3({
|
api_cfg,
|
||||||
api_cfg,
|
obj_type: 'event_badge',
|
||||||
obj_type: 'event_badge',
|
obj_id: event_badge_id,
|
||||||
obj_id: event_badge_id,
|
view,
|
||||||
view,
|
log_lvl
|
||||||
log_lvl
|
});
|
||||||
});
|
|
||||||
|
|
||||||
if (ae_promises.load__event_badge_obj) {
|
if (ae_promises.load__event_badge_obj) {
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
// In theory we should be able to use the event_id found in the Badge load object. 2026-02-04
|
// In theory we should be able to use the event_id found in the Badge load object. 2026-02-04
|
||||||
// This keeps coming up as undefined: ae_promises.load__event_badge_obj.event_id
|
// This keeps coming up as undefined: ae_promises.load__event_badge_obj.event_id
|
||||||
if (log_lvl) console.log(`Saving to local cache... Event ID: ${event_id} or ${ae_promises.load__event_badge_obj.event_id}`);
|
if (log_lvl)
|
||||||
const processed_obj_li = await process_ae_obj__event_badge_props({
|
console.log(
|
||||||
obj_li: [ae_promises.load__event_badge_obj],
|
`Saving to local cache... Event ID: ${event_id} or ${ae_promises.load__event_badge_obj.event_id}`
|
||||||
event_id: event_id || ae_promises.load__event_badge_obj.event_id,
|
);
|
||||||
log_lvl
|
const processed_obj_li =
|
||||||
});
|
await process_ae_obj__event_badge_props({
|
||||||
|
obj_li: [ae_promises.load__event_badge_obj],
|
||||||
|
event_id:
|
||||||
|
event_id ||
|
||||||
|
ae_promises.load__event_badge_obj.event_id,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
await db_save_ae_obj_li__ae_obj({
|
await db_save_ae_obj_li__ae_obj({
|
||||||
db_instance: db_events,
|
db_instance: db_events,
|
||||||
table_name: 'badge',
|
table_name: 'badge',
|
||||||
@@ -71,15 +78,21 @@ export async function load_ae_obj_id__event_badge({
|
|||||||
} else {
|
} else {
|
||||||
console.log('No results returned from API.');
|
console.log('No results returned from API.');
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
if (log_lvl) console.log('Attempting to load from local cache...');
|
if (log_lvl)
|
||||||
ae_promises.load__event_badge_obj = await db_events.badge.get(event_badge_id);
|
console.log('Attempting to load from local cache...');
|
||||||
|
ae_promises.load__event_badge_obj =
|
||||||
|
await db_events.badge.get(event_badge_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.log('API request failed.', error);
|
console.log('API request failed.', error);
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
if (log_lvl) console.log('Attempting to load from local cache after error...');
|
if (log_lvl)
|
||||||
ae_promises.load__event_badge_obj = await db_events.badge.get(event_badge_id);
|
console.log(
|
||||||
|
'Attempting to load from local cache after error...'
|
||||||
|
);
|
||||||
|
ae_promises.load__event_badge_obj =
|
||||||
|
await db_events.badge.get(event_badge_id);
|
||||||
} else {
|
} else {
|
||||||
ae_promises.load__event_badge_obj = null;
|
ae_promises.load__event_badge_obj = null;
|
||||||
}
|
}
|
||||||
@@ -87,14 +100,16 @@ export async function load_ae_obj_id__event_badge({
|
|||||||
|
|
||||||
if (inc_template && ae_promises.load__event_badge_obj) {
|
if (inc_template && ae_promises.load__event_badge_obj) {
|
||||||
// Load the templates for the event badge
|
// Load the templates for the event badge
|
||||||
const current_template_id = ae_promises.load__event_badge_obj.event_badge_template_id;
|
const current_template_id =
|
||||||
|
ae_promises.load__event_badge_obj.event_badge_template_id;
|
||||||
if (current_template_id) {
|
if (current_template_id) {
|
||||||
ae_promises.load__event_badge_obj.event_badge_template = await load_ae_obj_id__event_badge_template({
|
ae_promises.load__event_badge_obj.event_badge_template =
|
||||||
api_cfg: api_cfg,
|
await load_ae_obj_id__event_badge_template({
|
||||||
event_badge_template_id: current_template_id,
|
api_cfg: api_cfg,
|
||||||
try_cache: try_cache,
|
event_badge_template_id: current_template_id,
|
||||||
log_lvl: log_lvl
|
try_cache: try_cache,
|
||||||
});
|
log_lvl: log_lvl
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +126,12 @@ export async function load_ae_obj_li__event_badge({
|
|||||||
view = 'default',
|
view = 'default',
|
||||||
limit = 99,
|
limit = 99,
|
||||||
offset = 0,
|
offset = 0,
|
||||||
order_by_li = { priority: 'DESC', sort: 'DESC', updated_on: 'DESC', created_on: 'DESC' },
|
order_by_li = {
|
||||||
|
priority: 'DESC',
|
||||||
|
sort: 'DESC',
|
||||||
|
updated_on: 'DESC',
|
||||||
|
created_on: 'DESC'
|
||||||
|
},
|
||||||
params = {},
|
params = {},
|
||||||
try_cache = true,
|
try_cache = true,
|
||||||
log_lvl = 0
|
log_lvl = 0
|
||||||
@@ -130,32 +150,34 @@ export async function load_ae_obj_li__event_badge({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventBadge[]> {
|
}): Promise<ae_EventBadge[]> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** load_ae_obj_li__event_badge() *** event_id=${event_id}`);
|
console.log(
|
||||||
|
`*** load_ae_obj_li__event_badge() *** event_id=${event_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ae_promises.load__event_badge_obj_li = await api
|
ae_promises.load__event_badge_obj_li = await api.get_ae_obj_li({
|
||||||
.get_ae_obj_li_v3({
|
api_cfg,
|
||||||
api_cfg,
|
obj_type: 'event_badge',
|
||||||
obj_type: 'event_badge',
|
for_obj_type: 'event',
|
||||||
for_obj_type: 'event',
|
for_obj_id: event_id,
|
||||||
for_obj_id: event_id,
|
enabled: enabled,
|
||||||
enabled: enabled,
|
hidden: hidden,
|
||||||
hidden: hidden,
|
view: view,
|
||||||
view: view,
|
order_by_li: order_by_li,
|
||||||
order_by_li: order_by_li,
|
limit: limit,
|
||||||
limit: limit,
|
offset: offset,
|
||||||
offset: offset,
|
log_lvl: log_lvl
|
||||||
log_lvl: log_lvl
|
});
|
||||||
});
|
|
||||||
|
|
||||||
if (ae_promises.load__event_badge_obj_li) {
|
if (ae_promises.load__event_badge_obj_li) {
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
const processed_obj_li = await process_ae_obj__event_badge_props({
|
const processed_obj_li =
|
||||||
obj_li: ae_promises.load__event_badge_obj_li,
|
await process_ae_obj__event_badge_props({
|
||||||
event_id,
|
obj_li: ae_promises.load__event_badge_obj_li,
|
||||||
log_lvl
|
event_id,
|
||||||
});
|
log_lvl
|
||||||
|
});
|
||||||
await db_save_ae_obj_li__ae_obj({
|
await db_save_ae_obj_li__ae_obj({
|
||||||
db_instance: db_events,
|
db_instance: db_events,
|
||||||
table_name: 'badge',
|
table_name: 'badge',
|
||||||
@@ -169,9 +191,11 @@ export async function load_ae_obj_li__event_badge({
|
|||||||
} else {
|
} else {
|
||||||
console.log('No results returned from API.');
|
console.log('No results returned from API.');
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
if (log_lvl) console.log('Attempting to load from local cache...');
|
if (log_lvl)
|
||||||
|
console.log('Attempting to load from local cache...');
|
||||||
ae_promises.load__event_badge_obj_li = await db_events.badge
|
ae_promises.load__event_badge_obj_li = await db_events.badge
|
||||||
.where('event_id').equals(event_id)
|
.where('event_id')
|
||||||
|
.equals(event_id)
|
||||||
.toArray();
|
.toArray();
|
||||||
} else {
|
} else {
|
||||||
ae_promises.load__event_badge_obj_li = [];
|
ae_promises.load__event_badge_obj_li = [];
|
||||||
@@ -180,9 +204,13 @@ export async function load_ae_obj_li__event_badge({
|
|||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.log('API request failed.', error);
|
console.log('API request failed.', error);
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
if (log_lvl) console.log('Attempting to load from local cache after error...');
|
if (log_lvl)
|
||||||
|
console.log(
|
||||||
|
'Attempting to load from local cache after error...'
|
||||||
|
);
|
||||||
ae_promises.load__event_badge_obj_li = await db_events.badge
|
ae_promises.load__event_badge_obj_li = await db_events.badge
|
||||||
.where('event_id').equals(event_id)
|
.where('event_id')
|
||||||
|
.equals(event_id)
|
||||||
.toArray();
|
.toArray();
|
||||||
} else {
|
} else {
|
||||||
ae_promises.load__event_badge_obj_li = [];
|
ae_promises.load__event_badge_obj_li = [];
|
||||||
@@ -193,12 +221,13 @@ export async function load_ae_obj_li__event_badge({
|
|||||||
for (const badge_obj of ae_promises.load__event_badge_obj_li) {
|
for (const badge_obj of ae_promises.load__event_badge_obj_li) {
|
||||||
const current_template_id = badge_obj.event_badge_template_id;
|
const current_template_id = badge_obj.event_badge_template_id;
|
||||||
if (current_template_id) {
|
if (current_template_id) {
|
||||||
badge_obj.event_badge_template = await load_ae_obj_id__event_badge_template({
|
badge_obj.event_badge_template =
|
||||||
api_cfg: api_cfg,
|
await load_ae_obj_id__event_badge_template({
|
||||||
event_badge_template_id: current_template_id,
|
api_cfg: api_cfg,
|
||||||
try_cache: try_cache,
|
event_badge_template_id: current_template_id,
|
||||||
log_lvl: log_lvl
|
try_cache: try_cache,
|
||||||
});
|
log_lvl: log_lvl
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -223,10 +252,12 @@ export async function create_ae_obj__event_badge({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventBadge | null> {
|
}): Promise<ae_EventBadge | null> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** create_ae_obj__event_badge() *** event_id=${event_id}`);
|
console.log(
|
||||||
|
`*** create_ae_obj__event_badge() *** event_id=${event_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await api.create_nested_obj_v3({
|
const result = await api.create_nested_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
parent_type: 'event',
|
parent_type: 'event',
|
||||||
parent_id: event_id,
|
parent_id: event_id,
|
||||||
@@ -275,10 +306,12 @@ export async function delete_ae_obj_id__event_badge({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** delete_ae_obj_id__event_badge() *** event_badge_id=${event_badge_id}`);
|
console.log(
|
||||||
|
`*** delete_ae_obj_id__event_badge() *** event_badge_id=${event_badge_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await api.delete_nested_ae_obj_v3({
|
const result = await api.delete_nested_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
parent_type: 'event',
|
parent_type: 'event',
|
||||||
parent_id: event_id,
|
parent_id: event_id,
|
||||||
@@ -315,10 +348,12 @@ export async function update_ae_obj__event_badge({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventBadge | null> {
|
}): Promise<ae_EventBadge | null> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** update_ae_obj__event_badge() *** event_badge_id=${event_badge_id}`);
|
console.log(
|
||||||
|
`*** update_ae_obj__event_badge() *** event_badge_id=${event_badge_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await api.update_nested_obj_v3({
|
const result = await api.update_nested_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
parent_type: 'event',
|
parent_type: 'event',
|
||||||
parent_id: event_id,
|
parent_id: event_id,
|
||||||
@@ -391,7 +426,9 @@ export async function search__event_badge({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventBadge[] | false> {
|
}): Promise<ae_EventBadge[] | false> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** search__event_badge() *** event_id=${event_id} ft=${fulltext_search_qry_str}`);
|
console.log(
|
||||||
|
`*** search__event_badge() *** event_id=${event_id} ft=${fulltext_search_qry_str}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const search_query: any = {
|
const search_query: any = {
|
||||||
@@ -406,15 +443,23 @@ export async function search__event_badge({
|
|||||||
// Multi-word support: Split query by spaces and search for all words (AND logic)
|
// Multi-word support: Split query by spaces and search for all words (AND logic)
|
||||||
if (fulltext_search_qry_str && fulltext_search_qry_str.trim().length > 0) {
|
if (fulltext_search_qry_str && fulltext_search_qry_str.trim().length > 0) {
|
||||||
const qry = fulltext_search_qry_str.trim();
|
const qry = fulltext_search_qry_str.trim();
|
||||||
const words = qry.split(/\s+/).filter(w => w.length > 0);
|
const words = qry.split(/\s+/).filter((w) => w.length > 0);
|
||||||
|
|
||||||
if (words.length === 1) {
|
if (words.length === 1) {
|
||||||
// Single word: use simple LIKE
|
// Single word: use simple LIKE
|
||||||
search_query.and.push({ field: 'default_qry_str', op: 'like', value: `%${words[0]}%` });
|
search_query.and.push({
|
||||||
|
field: 'default_qry_str',
|
||||||
|
op: 'like',
|
||||||
|
value: `%${words[0]}%`
|
||||||
|
});
|
||||||
} else if (words.length > 1) {
|
} else if (words.length > 1) {
|
||||||
// Multiple words: each word must match (AND logic)
|
// Multiple words: each word must match (AND logic)
|
||||||
for (const word of words) {
|
for (const word of words) {
|
||||||
search_query.and.push({ field: 'default_qry_str', op: 'like', value: `%${word}%` });
|
search_query.and.push({
|
||||||
|
field: 'default_qry_str',
|
||||||
|
op: 'like',
|
||||||
|
value: `%${word}%`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -424,7 +469,11 @@ export async function search__event_badge({
|
|||||||
|
|
||||||
if (affiliations_qry_str && affiliations_qry_str.trim().length > 0) {
|
if (affiliations_qry_str && affiliations_qry_str.trim().length > 0) {
|
||||||
const qry = affiliations_qry_str.trim();
|
const qry = affiliations_qry_str.trim();
|
||||||
search_query.and.push({ field: 'affiliations', op: 'like', value: `%${qry}%` });
|
search_query.and.push({
|
||||||
|
field: 'affiliations',
|
||||||
|
op: 'like',
|
||||||
|
value: `%${qry}%`
|
||||||
|
});
|
||||||
params['lk_qry'] = params['lk_qry'] || {};
|
params['lk_qry'] = params['lk_qry'] || {};
|
||||||
params['lk_qry']['affiliations'] = qry;
|
params['lk_qry']['affiliations'] = qry;
|
||||||
}
|
}
|
||||||
@@ -435,11 +484,19 @@ export async function search__event_badge({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (external_event_id) {
|
if (external_event_id) {
|
||||||
search_query.and.push({ field: 'external_event_id', op: 'eq', value: external_event_id });
|
search_query.and.push({
|
||||||
|
field: 'external_event_id',
|
||||||
|
op: 'eq',
|
||||||
|
value: external_event_id
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type_code) {
|
if (type_code) {
|
||||||
search_query.and.push({ field: 'badge_type_code', op: 'eq', value: type_code });
|
search_query.and.push({
|
||||||
|
field: 'badge_type_code',
|
||||||
|
op: 'eq',
|
||||||
|
value: type_code
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (printed_status === 'printed') {
|
if (printed_status === 'printed') {
|
||||||
@@ -448,14 +505,18 @@ export async function search__event_badge({
|
|||||||
search_query.and.push({ field: 'print_count', op: 'eq', value: 0 });
|
search_query.and.push({ field: 'print_count', op: 'eq', value: 0 });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enabled === 'enabled') search_query.and.push({ field: 'enable', op: 'eq', value: true });
|
if (enabled === 'enabled')
|
||||||
else if (enabled === 'not_enabled') search_query.and.push({ field: 'enable', op: 'eq', value: false });
|
search_query.and.push({ field: 'enable', op: 'eq', value: true });
|
||||||
|
else if (enabled === 'not_enabled')
|
||||||
|
search_query.and.push({ field: 'enable', op: 'eq', value: false });
|
||||||
|
|
||||||
if (hidden === 'hidden') search_query.and.push({ field: 'hide', op: 'eq', value: true });
|
if (hidden === 'hidden')
|
||||||
else if (hidden === 'not_hidden') search_query.and.push({ field: 'hide', op: 'eq', value: false });
|
search_query.and.push({ field: 'hide', op: 'eq', value: true });
|
||||||
|
else if (hidden === 'not_hidden')
|
||||||
|
search_query.and.push({ field: 'hide', op: 'eq', value: false });
|
||||||
|
|
||||||
ae_promises.search__event_badge_obj_li = await api
|
ae_promises.search__event_badge_obj_li = await api
|
||||||
.search_ae_obj_v3({
|
.search_ae_obj({
|
||||||
api_cfg: api_cfg,
|
api_cfg: api_cfg,
|
||||||
obj_type: 'event_badge',
|
obj_type: 'event_badge',
|
||||||
search_query,
|
search_query,
|
||||||
@@ -473,17 +534,21 @@ export async function search__event_badge({
|
|||||||
let result_li: ae_EventBadge[] = [];
|
let result_li: ae_EventBadge[] = [];
|
||||||
if (Array.isArray(badge_obj_li_get_result)) {
|
if (Array.isArray(badge_obj_li_get_result)) {
|
||||||
result_li = badge_obj_li_get_result;
|
result_li = badge_obj_li_get_result;
|
||||||
} else if (badge_obj_li_get_result?.data && Array.isArray(badge_obj_li_get_result.data)) {
|
} else if (
|
||||||
|
badge_obj_li_get_result?.data &&
|
||||||
|
Array.isArray(badge_obj_li_get_result.data)
|
||||||
|
) {
|
||||||
result_li = badge_obj_li_get_result.data;
|
result_li = badge_obj_li_get_result.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result_li.length > 0) {
|
if (result_li.length > 0) {
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
const processed_obj_li = await process_ae_obj__event_badge_props({
|
const processed_obj_li =
|
||||||
obj_li: result_li,
|
await process_ae_obj__event_badge_props({
|
||||||
event_id,
|
obj_li: result_li,
|
||||||
log_lvl
|
event_id,
|
||||||
});
|
log_lvl
|
||||||
|
});
|
||||||
await db_save_ae_obj_li__ae_obj({
|
await db_save_ae_obj_li__ae_obj({
|
||||||
db_instance: db_events,
|
db_instance: db_events,
|
||||||
table_name: 'badge',
|
table_name: 'badge',
|
||||||
@@ -631,14 +696,21 @@ async function _process_generic_props<T extends Record<string, any>>({
|
|||||||
const group = processed_obj.group ?? '0';
|
const group = processed_obj.group ?? '0';
|
||||||
const priority = processed_obj.priority ? 1 : 0;
|
const priority = processed_obj.priority ? 1 : 0;
|
||||||
const sort = processed_obj.sort ?? '0';
|
const sort = processed_obj.sort ?? '0';
|
||||||
const updated = processed_obj.updated_on ?? processed_obj.created_on ?? new Date(0).toISOString();
|
const updated =
|
||||||
|
processed_obj.updated_on ??
|
||||||
|
processed_obj.created_on ??
|
||||||
|
new Date(0).toISOString();
|
||||||
const name = processed_obj.name ?? '';
|
const name = processed_obj.name ?? '';
|
||||||
|
|
||||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
(processed_obj as any).tmp_sort_1 =
|
||||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
`${group}_${priority}_${sort}_${updated}`;
|
||||||
|
(processed_obj as any).tmp_sort_2 =
|
||||||
|
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||||
|
|
||||||
if (specific_processor) {
|
if (specific_processor) {
|
||||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
processed_obj = await Promise.resolve(
|
||||||
|
specific_processor(processed_obj)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
processed_obj_li.push(processed_obj as T);
|
processed_obj_li.push(processed_obj as T);
|
||||||
@@ -663,7 +735,9 @@ export async function process_ae_obj__event_badge_props({
|
|||||||
log_lvl,
|
log_lvl,
|
||||||
specific_processor: (obj) => {
|
specific_processor: (obj) => {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** process_ae_obj__event_badge_props() *** event_id=${event_id}`);
|
console.log(
|
||||||
|
`*** process_ae_obj__event_badge_props() *** event_id=${event_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (event_id) {
|
if (event_id) {
|
||||||
if (!obj.event_id) obj.event_id = event_id;
|
if (!obj.event_id) obj.event_id = event_id;
|
||||||
|
|||||||
@@ -87,11 +87,15 @@ async function _process_generic_props<T extends Record<string, any>>({
|
|||||||
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
||||||
const name = processed_obj.name ?? '';
|
const name = processed_obj.name ?? '';
|
||||||
|
|
||||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
(processed_obj as any).tmp_sort_1 =
|
||||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
`${group}_${priority}_${sort}_${updated}`;
|
||||||
|
(processed_obj as any).tmp_sort_2 =
|
||||||
|
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||||
|
|
||||||
if (specific_processor) {
|
if (specific_processor) {
|
||||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
processed_obj = await Promise.resolve(
|
||||||
|
specific_processor(processed_obj)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
processed_obj_li.push(processed_obj as T);
|
processed_obj_li.push(processed_obj as T);
|
||||||
@@ -129,11 +133,13 @@ export async function load_ae_obj_id__event_badge_template({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** load_ae_obj_id__event_badge_template() *** [V3] id=${event_badge_template_id}`);
|
console.log(
|
||||||
|
`*** load_ae_obj_id__event_badge_template() *** [V3] id=${event_badge_template_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ae_promises.load__event_badge_template_obj = await api.get_ae_obj_v3({
|
ae_promises.load__event_badge_template_obj = await api.get_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'event_badge_template',
|
obj_type: 'event_badge_template',
|
||||||
obj_id: event_badge_template_id,
|
obj_id: event_badge_template_id,
|
||||||
@@ -156,11 +162,13 @@ export async function load_ae_obj_id__event_badge_template({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (try_cache) {
|
} else if (try_cache) {
|
||||||
ae_promises.load__event_badge_template_obj = await db_events.badge_template.get(event_badge_template_id);
|
ae_promises.load__event_badge_template_obj =
|
||||||
|
await db_events.badge_template.get(event_badge_template_id);
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
ae_promises.load__event_badge_template_obj = await db_events.badge_template.get(event_badge_template_id);
|
ae_promises.load__event_badge_template_obj =
|
||||||
|
await db_events.badge_template.get(event_badge_template_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,19 +205,21 @@ export async function load_ae_obj_li__event_badge_template({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
try {
|
try {
|
||||||
ae_promises.load__event_badge_template_obj_li = await api.get_ae_obj_li_v3({
|
ae_promises.load__event_badge_template_obj_li = await api.get_ae_obj_li(
|
||||||
api_cfg,
|
{
|
||||||
obj_type: 'event_badge_template',
|
api_cfg,
|
||||||
for_obj_type: 'event',
|
obj_type: 'event_badge_template',
|
||||||
for_obj_id: event_id,
|
for_obj_type: 'event',
|
||||||
enabled,
|
for_obj_id: event_id,
|
||||||
hidden,
|
enabled,
|
||||||
view,
|
hidden,
|
||||||
limit,
|
view,
|
||||||
offset,
|
limit,
|
||||||
order_by_li,
|
offset,
|
||||||
log_lvl
|
order_by_li,
|
||||||
});
|
log_lvl
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
if (ae_promises.load__event_badge_template_obj_li) {
|
if (ae_promises.load__event_badge_template_obj_li) {
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
@@ -226,15 +236,19 @@ export async function load_ae_obj_li__event_badge_template({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (try_cache) {
|
} else if (try_cache) {
|
||||||
ae_promises.load__event_badge_template_obj_li = await db_events.badge_template
|
ae_promises.load__event_badge_template_obj_li =
|
||||||
.where('event_id').equals(event_id)
|
await db_events.badge_template
|
||||||
.toArray();
|
.where('event_id')
|
||||||
|
.equals(event_id)
|
||||||
|
.toArray();
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
ae_promises.load__event_badge_template_obj_li = await db_events.badge_template
|
ae_promises.load__event_badge_template_obj_li =
|
||||||
.where('event_id').equals(event_id)
|
await db_events.badge_template
|
||||||
.toArray();
|
.where('event_id')
|
||||||
|
.equals(event_id)
|
||||||
|
.toArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,115 +257,115 @@ export async function load_ae_obj_li__event_badge_template({
|
|||||||
|
|
||||||
// Updated 2026-01-20 to V3
|
// Updated 2026-01-20 to V3
|
||||||
export async function create_ae_obj__event_badge_template({
|
export async function create_ae_obj__event_badge_template({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
event_id,
|
event_id,
|
||||||
data_kv,
|
data_kv,
|
||||||
try_cache = true,
|
try_cache = true,
|
||||||
log_lvl = 0
|
log_lvl = 0
|
||||||
}: {
|
}: {
|
||||||
api_cfg: any;
|
api_cfg: any;
|
||||||
event_id: string;
|
event_id: string;
|
||||||
data_kv: key_val;
|
data_kv: key_val;
|
||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
const result = await api.create_nested_obj_v3({
|
const result = await api.create_nested_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
for_obj_type: 'event',
|
for_obj_type: 'event',
|
||||||
for_obj_id: event_id,
|
for_obj_id: event_id,
|
||||||
obj_type: 'event_badge_template',
|
obj_type: 'event_badge_template',
|
||||||
fields: { ...data_kv },
|
fields: { ...data_kv },
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result && try_cache) {
|
if (result && try_cache) {
|
||||||
const processed_obj_li = await process_ae_badge_template_props({
|
const processed_obj_li = await process_ae_badge_template_props({
|
||||||
obj_li: [result],
|
obj_li: [result],
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
await db_save_ae_obj_li__ae_obj({
|
await db_save_ae_obj_li__ae_obj({
|
||||||
db_instance: db_events,
|
db_instance: db_events,
|
||||||
table_name: 'badge_template',
|
table_name: 'badge_template',
|
||||||
obj_li: processed_obj_li,
|
obj_li: processed_obj_li,
|
||||||
properties_to_save,
|
properties_to_save,
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updated 2026-01-20 to V3
|
// Updated 2026-01-20 to V3
|
||||||
export async function delete_ae_obj_id__event_badge_template({
|
export async function delete_ae_obj_id__event_badge_template({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
event_id,
|
event_id,
|
||||||
event_badge_template_id,
|
event_badge_template_id,
|
||||||
method = 'delete',
|
method = 'delete',
|
||||||
try_cache = true,
|
try_cache = true,
|
||||||
log_lvl = 0
|
log_lvl = 0
|
||||||
}: {
|
}: {
|
||||||
api_cfg: any;
|
api_cfg: any;
|
||||||
event_id: string;
|
event_id: string;
|
||||||
event_badge_template_id: string;
|
event_badge_template_id: string;
|
||||||
method?: 'delete' | 'soft_delete' | 'disable' | 'hide';
|
method?: 'delete' | 'soft_delete' | 'disable' | 'hide';
|
||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
const result = await api.delete_nested_ae_obj_v3({
|
const result = await api.delete_nested_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
for_obj_type: 'event',
|
for_obj_type: 'event',
|
||||||
for_obj_id: event_id,
|
for_obj_id: event_id,
|
||||||
obj_type: 'event_badge_template',
|
obj_type: 'event_badge_template',
|
||||||
obj_id: event_badge_template_id,
|
obj_id: event_badge_template_id,
|
||||||
method,
|
method,
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
|
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
await db_events.badge_template.delete(event_badge_template_id);
|
await db_events.badge_template.delete(event_badge_template_id);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updated 2026-01-20 to V3
|
// Updated 2026-01-20 to V3
|
||||||
export async function update_ae_obj__event_badge_template({
|
export async function update_ae_obj__event_badge_template({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
event_id,
|
event_id,
|
||||||
event_badge_template_id,
|
event_badge_template_id,
|
||||||
data_kv,
|
data_kv,
|
||||||
try_cache = true,
|
try_cache = true,
|
||||||
log_lvl = 0
|
log_lvl = 0
|
||||||
}: {
|
}: {
|
||||||
api_cfg: any;
|
api_cfg: any;
|
||||||
event_id: string;
|
event_id: string;
|
||||||
event_badge_template_id: string;
|
event_badge_template_id: string;
|
||||||
data_kv: key_val;
|
data_kv: key_val;
|
||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
const result = await api.update_nested_obj_v3({
|
const result = await api.update_nested_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
for_obj_type: 'event',
|
for_obj_type: 'event',
|
||||||
for_obj_id: event_id,
|
for_obj_id: event_id,
|
||||||
obj_type: 'event_badge_template',
|
obj_type: 'event_badge_template',
|
||||||
obj_id: event_badge_template_id,
|
obj_id: event_badge_template_id,
|
||||||
fields: data_kv,
|
fields: data_kv,
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result && try_cache) {
|
if (result && try_cache) {
|
||||||
const processed_obj_li = await process_ae_badge_template_props({
|
const processed_obj_li = await process_ae_badge_template_props({
|
||||||
obj_li: [result],
|
obj_li: [result],
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
await db_save_ae_obj_li__ae_obj({
|
await db_save_ae_obj_li__ae_obj({
|
||||||
db_instance: db_events,
|
db_instance: db_events,
|
||||||
table_name: 'badge_template',
|
table_name: 'badge_template',
|
||||||
obj_li: processed_obj_li,
|
obj_li: processed_obj_li,
|
||||||
properties_to_save,
|
properties_to_save,
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updated 2026-01-20 to V3
|
// Updated 2026-01-20 to V3
|
||||||
@@ -388,13 +402,17 @@ export async function search__event_badge_template({
|
|||||||
and: [{ field: 'event_id', op: 'eq', value: event_id }]
|
and: [{ field: 'event_id', op: 'eq', value: event_id }]
|
||||||
};
|
};
|
||||||
|
|
||||||
if (enabled === 'enabled') search_query.and.push({ field: 'enable', op: 'eq', value: true });
|
if (enabled === 'enabled')
|
||||||
else if (enabled === 'not_enabled') search_query.and.push({ field: 'enable', op: 'eq', value: false });
|
search_query.and.push({ field: 'enable', op: 'eq', value: true });
|
||||||
|
else if (enabled === 'not_enabled')
|
||||||
|
search_query.and.push({ field: 'enable', op: 'eq', value: false });
|
||||||
|
|
||||||
if (hidden === 'hidden') search_query.and.push({ field: 'hide', op: 'eq', value: true });
|
if (hidden === 'hidden')
|
||||||
else if (hidden === 'not_hidden') search_query.and.push({ field: 'hide', op: 'eq', value: false });
|
search_query.and.push({ field: 'hide', op: 'eq', value: true });
|
||||||
|
else if (hidden === 'not_hidden')
|
||||||
|
search_query.and.push({ field: 'hide', op: 'eq', value: false });
|
||||||
|
|
||||||
const result_li = await api.search_ae_obj_v3({
|
const result_li = await api.search_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'event_badge_template',
|
obj_type: 'event_badge_template',
|
||||||
search_query,
|
search_query,
|
||||||
|
|||||||
@@ -28,11 +28,13 @@ export async function load_ae_obj_id__event_device({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventDevice | null> {
|
}): Promise<ae_EventDevice | null> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** load_ae_obj_id__event_device() *** [V3] id=${event_device_id}`);
|
console.log(
|
||||||
|
`*** load_ae_obj_id__event_device() *** [V3] id=${event_device_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await api.get_ae_obj_v3({
|
const result = await api.get_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'event_device',
|
obj_type: 'event_device',
|
||||||
obj_id: event_device_id,
|
obj_id: event_device_id,
|
||||||
@@ -57,26 +59,30 @@ export async function load_ae_obj_id__event_device({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (try_cache) {
|
} else if (try_cache) {
|
||||||
ae_promises.load__event_device_obj = await db_events.device.get(event_device_id);
|
ae_promises.load__event_device_obj =
|
||||||
|
await db_events.device.get(event_device_id);
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.log('V3 Request failed.', error);
|
console.log('V3 Request failed.', error);
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
ae_promises.load__event_device_obj = await db_events.device.get(event_device_id);
|
ae_promises.load__event_device_obj =
|
||||||
|
await db_events.device.get(event_device_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ae_promises.load__event_device_obj) return null;
|
if (!ae_promises.load__event_device_obj) return null;
|
||||||
|
|
||||||
if (inc_location_id) {
|
if (inc_location_id) {
|
||||||
const current_location_id = ae_promises.load__event_device_obj.event_location_id;
|
const current_location_id =
|
||||||
|
ae_promises.load__event_device_obj.event_location_id;
|
||||||
if (current_location_id) {
|
if (current_location_id) {
|
||||||
ae_promises.load__event_device_obj.event_location_obj = await load_ae_obj_id__event_location({
|
ae_promises.load__event_device_obj.event_location_obj =
|
||||||
api_cfg,
|
await load_ae_obj_id__event_location({
|
||||||
event_location_id: current_location_id,
|
api_cfg,
|
||||||
try_cache,
|
event_location_id: current_location_id,
|
||||||
log_lvl
|
try_cache,
|
||||||
});
|
log_lvl
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,11 +121,13 @@ export async function load_ae_obj_li__event_device({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventDevice[]> {
|
}): Promise<ae_EventDevice[]> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** load_ae_obj_li__event_device() *** [V3] for=${for_obj_type}:${for_obj_id}`);
|
console.log(
|
||||||
|
`*** load_ae_obj_li__event_device() *** [V3] for=${for_obj_type}:${for_obj_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result_li = await api.get_ae_obj_li_v3({
|
const result_li = await api.get_ae_obj_li({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'event_device',
|
obj_type: 'event_device',
|
||||||
for_obj_type,
|
for_obj_type,
|
||||||
@@ -150,14 +158,16 @@ export async function load_ae_obj_li__event_device({
|
|||||||
}
|
}
|
||||||
} else if (try_cache) {
|
} else if (try_cache) {
|
||||||
ae_promises.load__event_device_obj_li = await db_events.device
|
ae_promises.load__event_device_obj_li = await db_events.device
|
||||||
.where('event_id').equals(for_obj_id)
|
.where('event_id')
|
||||||
|
.equals(for_obj_id)
|
||||||
.toArray();
|
.toArray();
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.log('V3 List Request failed.', error);
|
console.log('V3 List Request failed.', error);
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
ae_promises.load__event_device_obj_li = await db_events.device
|
ae_promises.load__event_device_obj_li = await db_events.device
|
||||||
.where('event_id').equals(for_obj_id)
|
.where('event_id')
|
||||||
|
.equals(for_obj_id)
|
||||||
.toArray();
|
.toArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -165,12 +175,13 @@ export async function load_ae_obj_li__event_device({
|
|||||||
if (inc_location_id && ae_promises.load__event_device_obj_li) {
|
if (inc_location_id && ae_promises.load__event_device_obj_li) {
|
||||||
for (const device of ae_promises.load__event_device_obj_li) {
|
for (const device of ae_promises.load__event_device_obj_li) {
|
||||||
if (device.event_location_id) {
|
if (device.event_location_id) {
|
||||||
device.event_location_obj = await load_ae_obj_id__event_location({
|
device.event_location_obj =
|
||||||
api_cfg,
|
await load_ae_obj_id__event_location({
|
||||||
event_location_id: device.event_location_id,
|
api_cfg,
|
||||||
try_cache,
|
event_location_id: device.event_location_id,
|
||||||
log_lvl
|
try_cache,
|
||||||
});
|
log_lvl
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -180,155 +191,161 @@ export async function load_ae_obj_li__event_device({
|
|||||||
|
|
||||||
// Updated 2026-01-20 to V3
|
// Updated 2026-01-20 to V3
|
||||||
export async function create_ae_obj__event_device({
|
export async function create_ae_obj__event_device({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
event_id,
|
event_id,
|
||||||
data_kv,
|
data_kv,
|
||||||
try_cache = true,
|
try_cache = true,
|
||||||
log_lvl = 0
|
log_lvl = 0
|
||||||
}: {
|
}: {
|
||||||
api_cfg: any;
|
api_cfg: any;
|
||||||
event_id?: string;
|
event_id?: string;
|
||||||
data_kv: key_val;
|
data_kv: key_val;
|
||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventDevice | null> {
|
}): Promise<ae_EventDevice | null> {
|
||||||
if (!event_id) event_id = get(slct).event_id;
|
if (!event_id) event_id = get(slct).event_id;
|
||||||
if (!event_id) {
|
if (!event_id) {
|
||||||
console.error('create_ae_obj__event_device: event_id is required');
|
console.error('create_ae_obj__event_device: event_id is required');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** create_ae_obj__event_device() *** [V3] event_id=${event_id}`);
|
console.log(
|
||||||
}
|
`*** create_ae_obj__event_device() *** [V3] event_id=${event_id}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const result = await api.create_nested_obj_v3({
|
const result = await api.create_nested_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
for_obj_type: 'event',
|
for_obj_type: 'event',
|
||||||
for_obj_id: event_id,
|
for_obj_id: event_id,
|
||||||
obj_type: 'event_device',
|
obj_type: 'event_device',
|
||||||
fields: { ...data_kv },
|
fields: { ...data_kv },
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
const processed = await process_ae_obj__event_device_props({
|
const processed = await process_ae_obj__event_device_props({
|
||||||
obj_li: [result],
|
obj_li: [result],
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
const processed_obj = processed[0];
|
const processed_obj = processed[0];
|
||||||
|
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
await db_save_ae_obj_li__ae_obj({
|
await db_save_ae_obj_li__ae_obj({
|
||||||
db_instance: db_events,
|
db_instance: db_events,
|
||||||
table_name: 'device',
|
table_name: 'device',
|
||||||
obj_li: [processed_obj],
|
obj_li: [processed_obj],
|
||||||
properties_to_save,
|
properties_to_save,
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return processed_obj;
|
return processed_obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updated 2026-01-20 to V3
|
// Updated 2026-01-20 to V3
|
||||||
export async function delete_ae_obj_id__event_device({
|
export async function delete_ae_obj_id__event_device({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
event_id,
|
event_id,
|
||||||
event_device_id,
|
event_device_id,
|
||||||
method = 'delete',
|
method = 'delete',
|
||||||
try_cache = true,
|
try_cache = true,
|
||||||
log_lvl = 0
|
log_lvl = 0
|
||||||
}: {
|
}: {
|
||||||
api_cfg: any;
|
api_cfg: any;
|
||||||
event_id?: string;
|
event_id?: string;
|
||||||
event_device_id: string;
|
event_device_id: string;
|
||||||
method?: 'delete' | 'soft_delete' | 'disable' | 'hide';
|
method?: 'delete' | 'soft_delete' | 'disable' | 'hide';
|
||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
if (!event_id) event_id = get(slct).event_id;
|
if (!event_id) event_id = get(slct).event_id;
|
||||||
if (!event_id) {
|
if (!event_id) {
|
||||||
console.error('delete_ae_obj_id__event_device: event_id is required');
|
console.error('delete_ae_obj_id__event_device: event_id is required');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** delete_ae_obj_id__event_device() *** [V3] id=${event_device_id}`);
|
console.log(
|
||||||
}
|
`*** delete_ae_obj_id__event_device() *** [V3] id=${event_device_id}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const result = await api.delete_nested_ae_obj_v3({
|
const result = await api.delete_nested_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
for_obj_type: 'event',
|
for_obj_type: 'event',
|
||||||
for_obj_id: event_id,
|
for_obj_id: event_id,
|
||||||
obj_type: 'event_device',
|
obj_type: 'event_device',
|
||||||
obj_id: event_device_id,
|
obj_id: event_device_id,
|
||||||
method,
|
method,
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
|
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
await db_events.device.delete(event_device_id);
|
await db_events.device.delete(event_device_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updated 2026-01-20 to V3
|
// Updated 2026-01-20 to V3
|
||||||
export async function update_ae_obj__event_device({
|
export async function update_ae_obj__event_device({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
event_id,
|
event_id,
|
||||||
event_device_id,
|
event_device_id,
|
||||||
data_kv,
|
data_kv,
|
||||||
try_cache = true,
|
try_cache = true,
|
||||||
log_lvl = 0
|
log_lvl = 0
|
||||||
}: {
|
}: {
|
||||||
api_cfg: any;
|
api_cfg: any;
|
||||||
event_id?: string;
|
event_id?: string;
|
||||||
event_device_id: string;
|
event_device_id: string;
|
||||||
data_kv: key_val;
|
data_kv: key_val;
|
||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventDevice | null> {
|
}): Promise<ae_EventDevice | null> {
|
||||||
if (!event_id) event_id = get(slct).event_id;
|
if (!event_id) event_id = get(slct).event_id;
|
||||||
if (!event_id) {
|
if (!event_id) {
|
||||||
console.error('update_ae_obj__event_device: event_id is required');
|
console.error('update_ae_obj__event_device: event_id is required');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** update_ae_obj__event_device() *** [V3] id=${event_device_id}`);
|
console.log(
|
||||||
}
|
`*** update_ae_obj__event_device() *** [V3] id=${event_device_id}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const result = await api.update_nested_obj_v3({
|
const result = await api.update_nested_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
for_obj_type: 'event',
|
for_obj_type: 'event',
|
||||||
for_obj_id: event_id,
|
for_obj_id: event_id,
|
||||||
obj_type: 'event_device',
|
obj_type: 'event_device',
|
||||||
obj_id: event_device_id,
|
obj_id: event_device_id,
|
||||||
fields: data_kv,
|
fields: data_kv,
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
const processed = await process_ae_obj__event_device_props({
|
const processed = await process_ae_obj__event_device_props({
|
||||||
obj_li: [result],
|
obj_li: [result],
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
const processed_obj = processed[0];
|
const processed_obj = processed[0];
|
||||||
|
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
await db_save_ae_obj_li__ae_obj({
|
await db_save_ae_obj_li__ae_obj({
|
||||||
db_instance: db_events,
|
db_instance: db_events,
|
||||||
table_name: 'device',
|
table_name: 'device',
|
||||||
obj_li: [processed_obj],
|
obj_li: [processed_obj],
|
||||||
properties_to_save,
|
properties_to_save,
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return processed_obj;
|
return processed_obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updated 2026-01-20 to V3
|
// Updated 2026-01-20 to V3
|
||||||
@@ -361,7 +378,9 @@ export async function search__event_device({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventDevice[]> {
|
}): Promise<ae_EventDevice[]> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** search__event_device() *** [V3] event_id=${event_id} qry=${qry_str}`);
|
console.log(
|
||||||
|
`*** search__event_device() *** [V3] event_id=${event_id} qry=${qry_str}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const search_query: any = {
|
const search_query: any = {
|
||||||
@@ -370,13 +389,17 @@ export async function search__event_device({
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Logical filters
|
// Logical filters
|
||||||
if (enabled === 'enabled') search_query.and.push({ field: 'enable', op: 'eq', value: true });
|
if (enabled === 'enabled')
|
||||||
else if (enabled === 'not_enabled') search_query.and.push({ field: 'enable', op: 'eq', value: false });
|
search_query.and.push({ field: 'enable', op: 'eq', value: true });
|
||||||
|
else if (enabled === 'not_enabled')
|
||||||
|
search_query.and.push({ field: 'enable', op: 'eq', value: false });
|
||||||
|
|
||||||
if (hidden === 'hidden') search_query.and.push({ field: 'hide', op: 'eq', value: true });
|
if (hidden === 'hidden')
|
||||||
else if (hidden === 'not_hidden') search_query.and.push({ field: 'hide', op: 'eq', value: false });
|
search_query.and.push({ field: 'hide', op: 'eq', value: true });
|
||||||
|
else if (hidden === 'not_hidden')
|
||||||
|
search_query.and.push({ field: 'hide', op: 'eq', value: false });
|
||||||
|
|
||||||
const result_li = await api.search_ae_obj_v3({
|
const result_li = await api.search_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'event_device',
|
obj_type: 'event_device',
|
||||||
search_query,
|
search_query,
|
||||||
@@ -499,11 +522,15 @@ async function _process_generic_props<T extends Record<string, any>>({
|
|||||||
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
||||||
const name = processed_obj.name ?? '';
|
const name = processed_obj.name ?? '';
|
||||||
|
|
||||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
(processed_obj as any).tmp_sort_1 =
|
||||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
`${group}_${priority}_${sort}_${updated}`;
|
||||||
|
(processed_obj as any).tmp_sort_2 =
|
||||||
|
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||||
|
|
||||||
if (specific_processor) {
|
if (specific_processor) {
|
||||||
processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
processed_obj = await Promise.resolve(
|
||||||
|
specific_processor(processed_obj)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
processed_obj_li.push(processed_obj as T);
|
processed_obj_li.push(processed_obj as T);
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ async function _refresh_file_id_background({
|
|||||||
}: any) {
|
}: any) {
|
||||||
if (typeof navigator !== 'undefined' && !navigator.onLine) return null;
|
if (typeof navigator !== 'undefined' && !navigator.onLine) return null;
|
||||||
try {
|
try {
|
||||||
const result = await api.get_ae_obj_v3({
|
const result = await api.get_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'event_file',
|
obj_type: 'event_file',
|
||||||
obj_id: event_file_id,
|
obj_id: event_file_id,
|
||||||
@@ -191,10 +191,12 @@ async function _refresh_file_li_background({
|
|||||||
if (typeof navigator !== 'undefined' && !navigator.onLine) return [];
|
if (typeof navigator !== 'undefined' && !navigator.onLine) return [];
|
||||||
try {
|
try {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`📡 [DEBUG] _refresh_file_li_background: Fetching files for ${for_obj_type}:${for_obj_id}`);
|
console.log(
|
||||||
|
`📡 [DEBUG] _refresh_file_li_background: Fetching files for ${for_obj_type}:${for_obj_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const result_li = await api.get_ae_obj_li_v3({
|
const result_li = await api.get_ae_obj_li({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'event_file',
|
obj_type: 'event_file',
|
||||||
for_obj_type,
|
for_obj_type,
|
||||||
@@ -211,7 +213,10 @@ async function _refresh_file_li_background({
|
|||||||
|
|
||||||
if (result_li) {
|
if (result_li) {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`📦 [DEBUG] Raw API results count:`, result_li.length);
|
console.log(
|
||||||
|
`📦 [DEBUG] Raw API results count:`,
|
||||||
|
result_li.length
|
||||||
|
);
|
||||||
if (result_li.length > 0) {
|
if (result_li.length > 0) {
|
||||||
console.log(`🔍 [DEBUG] Sample Raw IDs:`, {
|
console.log(`🔍 [DEBUG] Sample Raw IDs:`, {
|
||||||
id: result_li[0].id,
|
id: result_li[0].id,
|
||||||
@@ -253,7 +258,10 @@ async function _refresh_file_li_background({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
if (log_lvl) console.log(`💾 [DEBUG] Saving ${processed.length} records to ae_events_db.file`);
|
if (log_lvl)
|
||||||
|
console.log(
|
||||||
|
`💾 [DEBUG] Saving ${processed.length} records to ae_events_db.file`
|
||||||
|
);
|
||||||
await db_save_ae_obj_li__ae_obj({
|
await db_save_ae_obj_li__ae_obj({
|
||||||
db_instance: db_events,
|
db_instance: db_events,
|
||||||
table_name: 'file',
|
table_name: 'file',
|
||||||
@@ -265,10 +273,15 @@ async function _refresh_file_li_background({
|
|||||||
return processed;
|
return processed;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (log_lvl) console.error(`❌ [DEBUG] Error in _refresh_file_li_background:`, e);
|
if (log_lvl)
|
||||||
|
console.error(
|
||||||
|
`❌ [DEBUG] Error in _refresh_file_li_background:`,
|
||||||
|
e
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
}export async function create_event_file_obj_from_hosted_file_async({
|
}
|
||||||
|
export async function create_event_file_obj_from_hosted_file_async({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
hosted_file_id,
|
hosted_file_id,
|
||||||
params = {},
|
params = {},
|
||||||
@@ -318,7 +331,7 @@ export async function delete_ae_obj_id__event_file({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
const result = await api.delete_ae_obj_v3({
|
const result = await api.delete_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'event_file',
|
obj_type: 'event_file',
|
||||||
obj_id: event_file_id,
|
obj_id: event_file_id,
|
||||||
@@ -344,7 +357,7 @@ export async function update_ae_obj__event_file({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventFile | null> {
|
}): Promise<ae_EventFile | null> {
|
||||||
const result = await api.update_ae_obj_v3({
|
const result = await api.update_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'event_file',
|
obj_type: 'event_file',
|
||||||
obj_id: event_file_id,
|
obj_id: event_file_id,
|
||||||
@@ -427,7 +440,7 @@ export async function search__event_file({
|
|||||||
op: 'eq',
|
op: 'eq',
|
||||||
value: qry_file_purpose
|
value: qry_file_purpose
|
||||||
});
|
});
|
||||||
const result_li = await api.search_ae_obj_v3({
|
const result_li = await api.search_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'event_file',
|
obj_type: 'event_file',
|
||||||
search_query,
|
search_query,
|
||||||
@@ -459,7 +472,7 @@ export async function search__event_file({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return processed; // Return processed data with mapped fields
|
return processed; // Return processed data with mapped fields
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
@@ -545,7 +558,11 @@ async function _process_generic_props<T extends Record<string, any>>({
|
|||||||
if (key.endsWith('_random')) {
|
if (key.endsWith('_random')) {
|
||||||
const newKey = key.slice(0, -7);
|
const newKey = key.slice(0, -7);
|
||||||
// ONLY overwrite if the random variant has a valid value
|
// ONLY overwrite if the random variant has a valid value
|
||||||
if (processed_obj[key] !== null && processed_obj[key] !== undefined && processed_obj[key] !== '') {
|
if (
|
||||||
|
processed_obj[key] !== null &&
|
||||||
|
processed_obj[key] !== undefined &&
|
||||||
|
processed_obj[key] !== ''
|
||||||
|
) {
|
||||||
(processed_obj as any)[newKey] = processed_obj[key];
|
(processed_obj as any)[newKey] = processed_obj[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,9 @@ export async function load_ae_obj_id__event_location({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventLocation | null> {
|
}): Promise<ae_EventLocation | null> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** load_ae_obj_id__event_location() *** [V3] id=${event_location_id} (SWR)`);
|
console.log(
|
||||||
|
`*** load_ae_obj_id__event_location() *** [V3] id=${event_location_id} (SWR)`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. FAST PATH: Cache hit
|
// 1. FAST PATH: Cache hit
|
||||||
@@ -46,12 +48,26 @@ export async function load_ae_obj_id__event_location({
|
|||||||
const cached = await db_events.location.get(event_location_id);
|
const cached = await db_events.location.get(event_location_id);
|
||||||
if (cached) {
|
if (cached) {
|
||||||
_refresh_location_id_background({
|
_refresh_location_id_background({
|
||||||
api_cfg, event_location_id, view, try_cache,
|
api_cfg,
|
||||||
inc_file_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_device_li, inc_all_file_li,
|
event_location_id,
|
||||||
|
view,
|
||||||
|
try_cache,
|
||||||
|
inc_file_li,
|
||||||
|
inc_session_li,
|
||||||
|
inc_presentation_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
inc_device_li,
|
||||||
|
inc_all_file_li,
|
||||||
log_lvl: 0
|
log_lvl: 0
|
||||||
});
|
});
|
||||||
return await _handle_nested_loads(cached, {
|
return await _handle_nested_loads(cached, {
|
||||||
api_cfg, inc_file_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_device_li, inc_all_file_li,
|
api_cfg,
|
||||||
|
inc_file_li,
|
||||||
|
inc_session_li,
|
||||||
|
inc_presentation_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
inc_device_li,
|
||||||
|
inc_all_file_li,
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -60,24 +76,65 @@ export async function load_ae_obj_id__event_location({
|
|||||||
|
|
||||||
// 2. SLOW PATH: Wait for API
|
// 2. SLOW PATH: Wait for API
|
||||||
return await _refresh_location_id_background({
|
return await _refresh_location_id_background({
|
||||||
api_cfg, event_location_id, view, try_cache,
|
api_cfg,
|
||||||
inc_file_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_device_li, inc_all_file_li,
|
event_location_id,
|
||||||
|
view,
|
||||||
|
try_cache,
|
||||||
|
inc_file_li,
|
||||||
|
inc_session_li,
|
||||||
|
inc_presentation_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
inc_device_li,
|
||||||
|
inc_all_file_li,
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function _refresh_location_id_background({ api_cfg, event_location_id, view, try_cache, inc_file_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_device_li, inc_all_file_li, log_lvl }: any) {
|
async function _refresh_location_id_background({
|
||||||
|
api_cfg,
|
||||||
|
event_location_id,
|
||||||
|
view,
|
||||||
|
try_cache,
|
||||||
|
inc_file_li,
|
||||||
|
inc_session_li,
|
||||||
|
inc_presentation_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
inc_device_li,
|
||||||
|
inc_all_file_li,
|
||||||
|
log_lvl
|
||||||
|
}: any) {
|
||||||
if (typeof navigator !== 'undefined' && !navigator.onLine) return null;
|
if (typeof navigator !== 'undefined' && !navigator.onLine) return null;
|
||||||
try {
|
try {
|
||||||
const result = await api.get_ae_obj_v3({ api_cfg, obj_type: 'event_location', obj_id: event_location_id, view, log_lvl });
|
const result = await api.get_ae_obj({
|
||||||
|
api_cfg,
|
||||||
|
obj_type: 'event_location',
|
||||||
|
obj_id: event_location_id,
|
||||||
|
view,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
if (result) {
|
if (result) {
|
||||||
const processed = await process_ae_obj__event_location_props({ obj_li: [result], log_lvl });
|
const processed = await process_ae_obj__event_location_props({
|
||||||
|
obj_li: [result],
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
const processed_obj = processed[0];
|
const processed_obj = processed[0];
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'location', obj_li: [processed_obj], properties_to_save, log_lvl });
|
await db_save_ae_obj_li__ae_obj({
|
||||||
|
db_instance: db_events,
|
||||||
|
table_name: 'location',
|
||||||
|
obj_li: [processed_obj],
|
||||||
|
properties_to_save,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return await _handle_nested_loads(processed_obj, {
|
return await _handle_nested_loads(processed_obj, {
|
||||||
api_cfg, inc_file_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_device_li, inc_all_file_li,
|
api_cfg,
|
||||||
|
inc_file_li,
|
||||||
|
inc_session_li,
|
||||||
|
inc_presentation_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
inc_device_li,
|
||||||
|
inc_all_file_li,
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -129,23 +186,47 @@ export async function load_ae_obj_li__event_location({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventLocation[]> {
|
}): Promise<ae_EventLocation[]> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** load_ae_obj_li__event_location() *** [V3] for=${for_obj_type}:${for_obj_id} (SWR)`);
|
console.log(
|
||||||
|
`*** load_ae_obj_li__event_location() *** [V3] for=${for_obj_type}:${for_obj_id} (SWR)`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. FAST PATH: Check cache
|
// 1. FAST PATH: Check cache
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
try {
|
try {
|
||||||
const cached_li = await db_events.location.where('event_id').equals(for_obj_id).toArray();
|
const cached_li = await db_events.location
|
||||||
|
.where('event_id')
|
||||||
|
.equals(for_obj_id)
|
||||||
|
.toArray();
|
||||||
if (cached_li && cached_li.length > 0) {
|
if (cached_li && cached_li.length > 0) {
|
||||||
_refresh_location_li_background({
|
_refresh_location_li_background({
|
||||||
api_cfg, for_obj_type, for_obj_id,
|
api_cfg,
|
||||||
inc_file_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_device_li, inc_all_file_li,
|
for_obj_type,
|
||||||
enabled, hidden, view, limit, offset, order_by_li, try_cache,
|
for_obj_id,
|
||||||
|
inc_file_li,
|
||||||
|
inc_session_li,
|
||||||
|
inc_presentation_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
inc_device_li,
|
||||||
|
inc_all_file_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
view,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
order_by_li,
|
||||||
|
try_cache,
|
||||||
log_lvl: 0
|
log_lvl: 0
|
||||||
});
|
});
|
||||||
for (const loc of cached_li) {
|
for (const loc of cached_li) {
|
||||||
_handle_nested_loads(loc, {
|
_handle_nested_loads(loc, {
|
||||||
api_cfg, inc_file_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_device_li, inc_all_file_li,
|
api_cfg,
|
||||||
|
inc_file_li,
|
||||||
|
inc_session_li,
|
||||||
|
inc_presentation_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
inc_device_li,
|
||||||
|
inc_all_file_li,
|
||||||
log_lvl: 0
|
log_lvl: 0
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -156,31 +237,89 @@ export async function load_ae_obj_li__event_location({
|
|||||||
|
|
||||||
// 2. SLOW PATH: API
|
// 2. SLOW PATH: API
|
||||||
return await _refresh_location_li_background({
|
return await _refresh_location_li_background({
|
||||||
api_cfg, for_obj_type, for_obj_id,
|
api_cfg,
|
||||||
inc_file_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_device_li, inc_all_file_li,
|
for_obj_type,
|
||||||
enabled, hidden, view, limit, offset, order_by_li, try_cache,
|
for_obj_id,
|
||||||
|
inc_file_li,
|
||||||
|
inc_session_li,
|
||||||
|
inc_presentation_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
inc_device_li,
|
||||||
|
inc_all_file_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
view,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
order_by_li,
|
||||||
|
try_cache,
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function _refresh_location_li_background({ api_cfg, for_obj_type, for_obj_id, inc_file_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_device_li, inc_all_file_li, enabled, hidden, view, limit, offset, order_by_li, try_cache, log_lvl }: any) {
|
async function _refresh_location_li_background({
|
||||||
|
api_cfg,
|
||||||
|
for_obj_type,
|
||||||
|
for_obj_id,
|
||||||
|
inc_file_li,
|
||||||
|
inc_session_li,
|
||||||
|
inc_presentation_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
inc_device_li,
|
||||||
|
inc_all_file_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
view,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
order_by_li,
|
||||||
|
try_cache,
|
||||||
|
log_lvl
|
||||||
|
}: any) {
|
||||||
if (typeof navigator !== 'undefined' && !navigator.onLine) return [];
|
if (typeof navigator !== 'undefined' && !navigator.onLine) return [];
|
||||||
try {
|
try {
|
||||||
const result_li = await api.get_ae_obj_li_v3({ api_cfg, obj_type: 'event_location', for_obj_type, for_obj_id, enabled, hidden, view, limit, offset, order_by_li, log_lvl });
|
const result_li = await api.get_ae_obj_li({
|
||||||
|
api_cfg,
|
||||||
|
obj_type: 'event_location',
|
||||||
|
for_obj_type,
|
||||||
|
for_obj_id,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
view,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
order_by_li,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
if (result_li) {
|
if (result_li) {
|
||||||
const processed = await process_ae_obj__event_location_props({ obj_li: result_li, log_lvl });
|
const processed = await process_ae_obj__event_location_props({
|
||||||
|
obj_li: result_li,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
|
|
||||||
// String-Only ID Vision: Ensure linking ID is set for indexing
|
// String-Only ID Vision: Ensure linking ID is set for indexing
|
||||||
if (for_obj_type === 'event') {
|
if (for_obj_type === 'event') {
|
||||||
processed.forEach(loc => loc.event_id = for_obj_id);
|
processed.forEach((loc) => (loc.event_id = for_obj_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'location', obj_li: processed, properties_to_save, log_lvl });
|
await db_save_ae_obj_li__ae_obj({
|
||||||
|
db_instance: db_events,
|
||||||
|
table_name: 'location',
|
||||||
|
obj_li: processed,
|
||||||
|
properties_to_save,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
}
|
}
|
||||||
for (const loc of processed) {
|
for (const loc of processed) {
|
||||||
_handle_nested_loads(loc, {
|
_handle_nested_loads(loc, {
|
||||||
api_cfg, inc_file_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_device_li, inc_all_file_li,
|
api_cfg,
|
||||||
|
inc_file_li,
|
||||||
|
inc_session_li,
|
||||||
|
inc_presentation_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
inc_device_li,
|
||||||
|
inc_all_file_li,
|
||||||
log_lvl: 0
|
log_lvl: 0
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -193,34 +332,66 @@ async function _refresh_location_li_background({ api_cfg, for_obj_type, for_obj_
|
|||||||
/**
|
/**
|
||||||
* Handle nested data loads for a single location object.
|
* Handle nested data loads for a single location object.
|
||||||
*/
|
*/
|
||||||
async function _handle_nested_loads(location_obj: any, { api_cfg, inc_file_li, inc_session_li, inc_presentation_li, inc_presenter_li, inc_device_li, inc_all_file_li, log_lvl }: any) {
|
async function _handle_nested_loads(
|
||||||
const current_location_id = location_obj.id || location_obj.event_location_id;
|
location_obj: any,
|
||||||
|
{
|
||||||
|
api_cfg,
|
||||||
|
inc_file_li,
|
||||||
|
inc_session_li,
|
||||||
|
inc_presentation_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
inc_device_li,
|
||||||
|
inc_all_file_li,
|
||||||
|
log_lvl
|
||||||
|
}: any
|
||||||
|
) {
|
||||||
|
const current_location_id =
|
||||||
|
location_obj.id || location_obj.event_location_id;
|
||||||
if (!current_location_id) return location_obj;
|
if (!current_location_id) return location_obj;
|
||||||
|
|
||||||
const tasks = [];
|
const tasks = [];
|
||||||
if (inc_file_li) {
|
if (inc_file_li) {
|
||||||
tasks.push(load_ae_obj_li__event_file({
|
tasks.push(
|
||||||
api_cfg, for_obj_type: 'event_location', for_obj_id: current_location_id,
|
load_ae_obj_li__event_file({
|
||||||
enabled: 'all', limit: 25, log_lvl
|
api_cfg,
|
||||||
}).then(res => location_obj.event_file_li = res));
|
for_obj_type: 'event_location',
|
||||||
|
for_obj_id: current_location_id,
|
||||||
|
enabled: 'all',
|
||||||
|
limit: 25,
|
||||||
|
log_lvl
|
||||||
|
}).then((res) => (location_obj.event_file_li = res))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inc_session_li) {
|
if (inc_session_li) {
|
||||||
tasks.push(load_ae_obj_li__event_session({
|
tasks.push(
|
||||||
api_cfg, for_obj_type: 'event_location', for_obj_id: current_location_id,
|
load_ae_obj_li__event_session({
|
||||||
inc_file_li: inc_all_file_li,
|
api_cfg,
|
||||||
inc_all_file_li: inc_all_file_li,
|
for_obj_type: 'event_location',
|
||||||
inc_presentation_li: inc_presentation_li,
|
for_obj_id: current_location_id,
|
||||||
inc_presenter_li: inc_presenter_li,
|
inc_file_li: inc_all_file_li,
|
||||||
enabled: 'enabled', hidden: 'not_hidden', limit: 150, log_lvl
|
inc_all_file_li: inc_all_file_li,
|
||||||
}).then(res => location_obj.event_session_obj_li = res));
|
inc_presentation_li: inc_presentation_li,
|
||||||
|
inc_presenter_li: inc_presenter_li,
|
||||||
|
enabled: 'enabled',
|
||||||
|
hidden: 'not_hidden',
|
||||||
|
limit: 150,
|
||||||
|
log_lvl
|
||||||
|
}).then((res) => (location_obj.event_session_obj_li = res))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inc_device_li) {
|
if (inc_device_li) {
|
||||||
tasks.push(load_ae_obj_li__event_device({
|
tasks.push(
|
||||||
api_cfg, for_obj_type: 'event_location', for_obj_id: current_location_id,
|
load_ae_obj_li__event_device({
|
||||||
enabled: 'all', limit: 50, log_lvl
|
api_cfg,
|
||||||
}).then(res => location_obj.event_device_li = res));
|
for_obj_type: 'event_location',
|
||||||
|
for_obj_id: current_location_id,
|
||||||
|
enabled: 'all',
|
||||||
|
limit: 50,
|
||||||
|
log_lvl
|
||||||
|
}).then((res) => (location_obj.event_device_li = res))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tasks.length > 0) await Promise.all(tasks);
|
if (tasks.length > 0) await Promise.all(tasks);
|
||||||
@@ -229,132 +400,183 @@ async function _handle_nested_loads(location_obj: any, { api_cfg, inc_file_li, i
|
|||||||
|
|
||||||
// Updated 2026-01-20 to V3
|
// Updated 2026-01-20 to V3
|
||||||
export async function create_ae_obj__event_location({
|
export async function create_ae_obj__event_location({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
event_id,
|
event_id,
|
||||||
data_kv,
|
data_kv,
|
||||||
try_cache = true,
|
try_cache = true,
|
||||||
log_lvl = 0
|
log_lvl = 0
|
||||||
}: {
|
}: {
|
||||||
api_cfg: any;
|
api_cfg: any;
|
||||||
event_id: string;
|
event_id: string;
|
||||||
data_kv: key_val;
|
data_kv: key_val;
|
||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventLocation | null> {
|
}): Promise<ae_EventLocation | null> {
|
||||||
const result = await api.create_nested_obj_v3({
|
const result = await api.create_nested_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
for_obj_type: 'event',
|
for_obj_type: 'event',
|
||||||
for_obj_id: event_id,
|
for_obj_id: event_id,
|
||||||
obj_type: 'event_location',
|
obj_type: 'event_location',
|
||||||
fields: { ...data_kv },
|
fields: { ...data_kv },
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
const processed = await process_ae_obj__event_location_props({ obj_li: [result], log_lvl });
|
const processed = await process_ae_obj__event_location_props({
|
||||||
const processed_obj = processed[0];
|
obj_li: [result],
|
||||||
if (try_cache) {
|
log_lvl
|
||||||
await db_save_ae_obj_li__ae_obj({
|
});
|
||||||
db_instance: db_events,
|
const processed_obj = processed[0];
|
||||||
table_name: 'location',
|
if (try_cache) {
|
||||||
obj_li: [processed_obj],
|
await db_save_ae_obj_li__ae_obj({
|
||||||
properties_to_save,
|
db_instance: db_events,
|
||||||
log_lvl
|
table_name: 'location',
|
||||||
});
|
obj_li: [processed_obj],
|
||||||
}
|
properties_to_save,
|
||||||
return processed_obj;
|
log_lvl
|
||||||
}
|
});
|
||||||
return null;
|
}
|
||||||
|
return processed_obj;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updated 2026-01-20 to V3
|
// Updated 2026-01-20 to V3
|
||||||
export async function delete_ae_obj_id__event_location({
|
export async function delete_ae_obj_id__event_location({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
event_id,
|
event_id,
|
||||||
event_location_id,
|
event_location_id,
|
||||||
method = 'delete',
|
method = 'delete',
|
||||||
try_cache = true,
|
try_cache = true,
|
||||||
log_lvl = 0
|
log_lvl = 0
|
||||||
}: {
|
}: {
|
||||||
api_cfg: any;
|
api_cfg: any;
|
||||||
event_id: string;
|
event_id: string;
|
||||||
event_location_id: string;
|
event_location_id: string;
|
||||||
method?: 'delete' | 'soft_delete' | 'disable' | 'hide';
|
method?: 'delete' | 'soft_delete' | 'disable' | 'hide';
|
||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
const result = await api.delete_nested_ae_obj_v3({
|
const result = await api.delete_nested_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
for_obj_type: 'event',
|
for_obj_type: 'event',
|
||||||
for_obj_id: event_id,
|
for_obj_id: event_id,
|
||||||
obj_type: 'event_location',
|
obj_type: 'event_location',
|
||||||
obj_id: event_location_id,
|
obj_id: event_location_id,
|
||||||
method,
|
method,
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
if (try_cache) await db_events.location.delete(event_location_id);
|
if (try_cache) await db_events.location.delete(event_location_id);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updated 2026-01-20 to V3
|
// Updated 2026-01-20 to V3
|
||||||
export async function update_ae_obj__event_location({
|
export async function update_ae_obj__event_location({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
event_id,
|
event_id,
|
||||||
event_location_id,
|
event_location_id,
|
||||||
data_kv,
|
data_kv,
|
||||||
try_cache = true,
|
try_cache = true,
|
||||||
log_lvl = 0
|
log_lvl = 0
|
||||||
}: {
|
}: {
|
||||||
api_cfg: any;
|
api_cfg: any;
|
||||||
event_id: string;
|
event_id: string;
|
||||||
event_location_id: string;
|
event_location_id: string;
|
||||||
data_kv: key_val;
|
data_kv: key_val;
|
||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventLocation | null> {
|
}): Promise<ae_EventLocation | null> {
|
||||||
const result = await api.update_nested_obj_v3({
|
const result = await api.update_nested_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
for_obj_type: 'event',
|
for_obj_type: 'event',
|
||||||
for_obj_id: event_id,
|
for_obj_id: event_id,
|
||||||
obj_type: 'event_location',
|
obj_type: 'event_location',
|
||||||
obj_id: event_location_id,
|
obj_id: event_location_id,
|
||||||
fields: data_kv,
|
fields: data_kv,
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
if (result) {
|
if (result) {
|
||||||
const processed = await process_ae_obj__event_location_props({ obj_li: [result], log_lvl });
|
const processed = await process_ae_obj__event_location_props({
|
||||||
const processed_obj = processed[0];
|
obj_li: [result],
|
||||||
if (try_cache) {
|
log_lvl
|
||||||
await db_save_ae_obj_li__ae_obj({
|
});
|
||||||
db_instance: db_events,
|
const processed_obj = processed[0];
|
||||||
table_name: 'location',
|
if (try_cache) {
|
||||||
obj_li: [processed_obj],
|
await db_save_ae_obj_li__ae_obj({
|
||||||
properties_to_save,
|
db_instance: db_events,
|
||||||
log_lvl
|
table_name: 'location',
|
||||||
});
|
obj_li: [processed_obj],
|
||||||
}
|
properties_to_save,
|
||||||
return processed_obj;
|
log_lvl
|
||||||
}
|
});
|
||||||
return null;
|
}
|
||||||
|
return processed_obj;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updated 2026-01-20 to V3
|
// Updated 2026-01-20 to V3
|
||||||
export async function search__event_location({
|
export async function search__event_location({
|
||||||
api_cfg, event_id, qry_str = '', enabled = 'enabled', hidden = 'not_hidden', view = 'default', limit = 25, offset = 0, order_by_li = [{ sort: 'ASC' }, { name: 'ASC' }], try_cache = true, log_lvl = 0
|
api_cfg,
|
||||||
|
event_id,
|
||||||
|
qry_str = '',
|
||||||
|
enabled = 'enabled',
|
||||||
|
hidden = 'not_hidden',
|
||||||
|
view = 'default',
|
||||||
|
limit = 25,
|
||||||
|
offset = 0,
|
||||||
|
order_by_li = [{ sort: 'ASC' }, { name: 'ASC' }],
|
||||||
|
try_cache = true,
|
||||||
|
log_lvl = 0
|
||||||
}: {
|
}: {
|
||||||
api_cfg: any; event_id: string; qry_str?: string; enabled?: 'enabled' | 'all' | 'not_enabled'; hidden?: 'hidden' | 'all' | 'not_hidden'; view?: string; limit?: number; offset?: number; order_by_li?: any; try_cache?: boolean; log_lvl?: number;
|
api_cfg: any;
|
||||||
|
event_id: string;
|
||||||
|
qry_str?: string;
|
||||||
|
enabled?: 'enabled' | 'all' | 'not_enabled';
|
||||||
|
hidden?: 'hidden' | 'all' | 'not_hidden';
|
||||||
|
view?: string;
|
||||||
|
limit?: number;
|
||||||
|
offset?: number;
|
||||||
|
order_by_li?: any;
|
||||||
|
try_cache?: boolean;
|
||||||
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventLocation[]> {
|
}): Promise<ae_EventLocation[]> {
|
||||||
const search_query: any = { q: qry_str, and: [{ field: 'event_id', op: 'eq', value: event_id }] };
|
const search_query: any = {
|
||||||
if (enabled === 'enabled') search_query.and.push({ field: 'enable', op: 'eq', value: true });
|
q: qry_str,
|
||||||
else if (enabled === 'not_enabled') search_query.and.push({ field: 'enable', op: 'eq', value: false });
|
and: [{ field: 'event_id', op: 'eq', value: event_id }]
|
||||||
if (hidden === 'hidden') search_query.and.push({ field: 'hide', op: 'eq', value: true });
|
};
|
||||||
else if (hidden === 'not_hidden') search_query.and.push({ field: 'hide', op: 'eq', value: false });
|
if (enabled === 'enabled')
|
||||||
|
search_query.and.push({ field: 'enable', op: 'eq', value: true });
|
||||||
|
else if (enabled === 'not_enabled')
|
||||||
|
search_query.and.push({ field: 'enable', op: 'eq', value: false });
|
||||||
|
if (hidden === 'hidden')
|
||||||
|
search_query.and.push({ field: 'hide', op: 'eq', value: true });
|
||||||
|
else if (hidden === 'not_hidden')
|
||||||
|
search_query.and.push({ field: 'hide', op: 'eq', value: false });
|
||||||
|
|
||||||
const result_li = await api.search_ae_obj_v3({ api_cfg, obj_type: 'event_location', search_query, order_by_li, view, limit, offset, log_lvl });
|
const result_li = await api.search_ae_obj({
|
||||||
|
api_cfg,
|
||||||
|
obj_type: 'event_location',
|
||||||
|
search_query,
|
||||||
|
order_by_li,
|
||||||
|
view,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
if (result_li) {
|
if (result_li) {
|
||||||
const processed = await process_ae_obj__event_location_props({ obj_li: result_li, log_lvl });
|
const processed = await process_ae_obj__event_location_props({
|
||||||
|
obj_li: result_li,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'location', obj_li: processed, properties_to_save, log_lvl });
|
await db_save_ae_obj_li__ae_obj({
|
||||||
|
db_instance: db_events,
|
||||||
|
table_name: 'location',
|
||||||
|
obj_li: processed,
|
||||||
|
properties_to_save,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return processed;
|
return processed;
|
||||||
}
|
}
|
||||||
@@ -362,10 +584,40 @@ export async function search__event_location({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const properties_to_save = [
|
export const properties_to_save = [
|
||||||
'id', 'event_location_id', 'event_location_id_random', 'event_id', 'event_id_random', 'external_id', 'code', 'name', 'description', 'passcode', 'enable', 'hide', 'priority', 'sort', 'group', 'notes', 'created_on', 'updated_on', 'tmp_sort_1', 'tmp_sort_2', 'event_name'
|
'id',
|
||||||
|
'event_location_id',
|
||||||
|
'event_location_id_random',
|
||||||
|
'event_id',
|
||||||
|
'event_id_random',
|
||||||
|
'external_id',
|
||||||
|
'code',
|
||||||
|
'name',
|
||||||
|
'description',
|
||||||
|
'passcode',
|
||||||
|
'enable',
|
||||||
|
'hide',
|
||||||
|
'priority',
|
||||||
|
'sort',
|
||||||
|
'group',
|
||||||
|
'notes',
|
||||||
|
'created_on',
|
||||||
|
'updated_on',
|
||||||
|
'tmp_sort_1',
|
||||||
|
'tmp_sort_2',
|
||||||
|
'event_name'
|
||||||
];
|
];
|
||||||
|
|
||||||
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[]> {
|
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 (!obj_li || obj_li.length === 0) return [];
|
if (!obj_li || obj_li.length === 0) return [];
|
||||||
const processed_obj_li: T[] = [];
|
const processed_obj_li: T[] = [];
|
||||||
for (const original_obj of obj_li) {
|
for (const original_obj of obj_li) {
|
||||||
@@ -378,24 +630,42 @@ async function _process_generic_props<T extends Record<string, any>>({ obj_li, o
|
|||||||
}
|
}
|
||||||
const randomIdKey = `${obj_type}_id_random`;
|
const randomIdKey = `${obj_type}_id_random`;
|
||||||
const baseIdKey = `${obj_type}_id`;
|
const baseIdKey = `${obj_type}_id`;
|
||||||
if (processed_obj[randomIdKey]) (processed_obj as any).id = processed_obj[randomIdKey];
|
if (processed_obj[randomIdKey])
|
||||||
else if (processed_obj[baseIdKey]) (processed_obj as any).id = processed_obj[baseIdKey];
|
(processed_obj as any).id = processed_obj[randomIdKey];
|
||||||
|
else if (processed_obj[baseIdKey])
|
||||||
|
(processed_obj as any).id = processed_obj[baseIdKey];
|
||||||
const group = processed_obj.group ?? '0';
|
const group = processed_obj.group ?? '0';
|
||||||
const priority = processed_obj.priority ? 1 : 0;
|
const priority = processed_obj.priority ? 1 : 0;
|
||||||
const sort = processed_obj.sort ?? '0';
|
const sort = processed_obj.sort ?? '0';
|
||||||
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
const updated = processed_obj.updated_on ?? processed_obj.created_on;
|
||||||
const name = processed_obj.name ?? '';
|
const name = processed_obj.name ?? '';
|
||||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
(processed_obj as any).tmp_sort_1 =
|
||||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
`${group}_${priority}_${sort}_${updated}`;
|
||||||
if (specific_processor) processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
(processed_obj as any).tmp_sort_2 =
|
||||||
|
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||||
|
if (specific_processor)
|
||||||
|
processed_obj = await Promise.resolve(
|
||||||
|
specific_processor(processed_obj)
|
||||||
|
);
|
||||||
processed_obj_li.push(processed_obj as T);
|
processed_obj_li.push(processed_obj as T);
|
||||||
}
|
}
|
||||||
return processed_obj_li;
|
return processed_obj_li;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function process_ae_obj__event_location_props({ obj_li, log_lvl = 0 }: { obj_li: any[]; log_lvl?: number; }) {
|
export async function process_ae_obj__event_location_props({
|
||||||
return _process_generic_props({ obj_li, obj_type: 'event_location', log_lvl, specific_processor: (obj) => {
|
obj_li,
|
||||||
if (obj.event_id_random) obj.event_id = obj.event_id_random;
|
log_lvl = 0
|
||||||
return obj;
|
}: {
|
||||||
}});
|
obj_li: any[];
|
||||||
|
log_lvl?: number;
|
||||||
|
}) {
|
||||||
|
return _process_generic_props({
|
||||||
|
obj_li,
|
||||||
|
obj_type: 'event_location',
|
||||||
|
log_lvl,
|
||||||
|
specific_processor: (obj) => {
|
||||||
|
if (obj.event_id_random) obj.event_id = obj.event_id_random;
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
@@ -37,41 +37,116 @@ export async function load_ae_obj_id__event_presentation({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventPresentation | null> {
|
}): Promise<ae_EventPresentation | null> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** load_ae_obj_id__event_presentation() *** id=${event_presentation_id} (SWR)`);
|
console.log(
|
||||||
|
`*** load_ae_obj_id__event_presentation() *** id=${event_presentation_id} (SWR)`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. FAST PATH: Cache hit
|
// 1. FAST PATH: Cache hit
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
try {
|
try {
|
||||||
const cached = await db_events.presentation.get(event_presentation_id);
|
const cached = await db_events.presentation.get(
|
||||||
|
event_presentation_id
|
||||||
|
);
|
||||||
if (cached) {
|
if (cached) {
|
||||||
// Background refresh (non-blocking)
|
// Background refresh (non-blocking)
|
||||||
_refresh_presentation_id_background({ api_cfg, event_presentation_id, view, try_cache, inc_file_li, inc_presenter_li, enabled, hidden, limit, offset, log_lvl: 0 });
|
_refresh_presentation_id_background({
|
||||||
|
api_cfg,
|
||||||
|
event_presentation_id,
|
||||||
|
view,
|
||||||
|
try_cache,
|
||||||
|
inc_file_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
log_lvl: 0
|
||||||
|
});
|
||||||
// Await nested loads from cache to return a complete object
|
// Await nested loads from cache to return a complete object
|
||||||
return await _handle_nested_loads(cached, { api_cfg, inc_file_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache, log_lvl: 0 });
|
return await _handle_nested_loads(cached, {
|
||||||
|
api_cfg,
|
||||||
|
inc_file_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
try_cache,
|
||||||
|
log_lvl: 0
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. SLOW PATH: Wait for API
|
// 2. SLOW PATH: Wait for API
|
||||||
return await _refresh_presentation_id_background({ api_cfg, event_presentation_id, view, try_cache, inc_file_li, inc_presenter_li, enabled, hidden, limit, offset, log_lvl });
|
return await _refresh_presentation_id_background({
|
||||||
|
api_cfg,
|
||||||
|
event_presentation_id,
|
||||||
|
view,
|
||||||
|
try_cache,
|
||||||
|
inc_file_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal background refresh for a single presentation
|
* Internal background refresh for a single presentation
|
||||||
*/
|
*/
|
||||||
async function _refresh_presentation_id_background({ api_cfg, event_presentation_id, view, try_cache, inc_file_li, inc_presenter_li, enabled, hidden, limit, offset, log_lvl }: any) {
|
async function _refresh_presentation_id_background({
|
||||||
|
api_cfg,
|
||||||
|
event_presentation_id,
|
||||||
|
view,
|
||||||
|
try_cache,
|
||||||
|
inc_file_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
log_lvl
|
||||||
|
}: any) {
|
||||||
if (typeof navigator !== 'undefined' && !navigator.onLine) return null;
|
if (typeof navigator !== 'undefined' && !navigator.onLine) return null;
|
||||||
try {
|
try {
|
||||||
const result = await api.get_ae_obj_v3({ api_cfg, obj_type: 'event_presentation', obj_id: event_presentation_id, view, log_lvl });
|
const result = await api.get_ae_obj({
|
||||||
|
api_cfg,
|
||||||
|
obj_type: 'event_presentation',
|
||||||
|
obj_id: event_presentation_id,
|
||||||
|
view,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
if (result) {
|
if (result) {
|
||||||
const processed = await process_ae_obj__event_presentation_props({ obj_li: [result], log_lvl });
|
const processed = await process_ae_obj__event_presentation_props({
|
||||||
|
obj_li: [result],
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
const processed_obj = processed[0];
|
const processed_obj = processed[0];
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'presentation', obj_li: [processed_obj], properties_to_save, log_lvl });
|
await db_save_ae_obj_li__ae_obj({
|
||||||
|
db_instance: db_events,
|
||||||
|
table_name: 'presentation',
|
||||||
|
obj_li: [processed_obj],
|
||||||
|
properties_to_save,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
}
|
}
|
||||||
// During refresh, we disable child SWR to prevent a request storm
|
// During refresh, we disable child SWR to prevent a request storm
|
||||||
return await _handle_nested_loads(processed_obj, { api_cfg, inc_file_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache: false, log_lvl });
|
return await _handle_nested_loads(processed_obj, {
|
||||||
|
api_cfg,
|
||||||
|
inc_file_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
try_cache: false,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
return null;
|
return null;
|
||||||
@@ -80,23 +155,54 @@ async function _refresh_presentation_id_background({ api_cfg, event_presentation
|
|||||||
/**
|
/**
|
||||||
* Helper to handle nested collection loads for a presentation
|
* Helper to handle nested collection loads for a presentation
|
||||||
*/
|
*/
|
||||||
async function _handle_nested_loads(presentation_obj: any, { api_cfg, inc_file_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache, log_lvl }: any) {
|
async function _handle_nested_loads(
|
||||||
const current_presentation_id = presentation_obj.id || presentation_obj.event_presentation_id;
|
presentation_obj: any,
|
||||||
|
{
|
||||||
|
api_cfg,
|
||||||
|
inc_file_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
try_cache,
|
||||||
|
log_lvl
|
||||||
|
}: any
|
||||||
|
) {
|
||||||
|
const current_presentation_id =
|
||||||
|
presentation_obj.id || presentation_obj.event_presentation_id;
|
||||||
if (!current_presentation_id) return presentation_obj;
|
if (!current_presentation_id) return presentation_obj;
|
||||||
|
|
||||||
const tasks = [];
|
const tasks = [];
|
||||||
if (inc_file_li) {
|
if (inc_file_li) {
|
||||||
tasks.push(load_ae_obj_li__event_file({
|
tasks.push(
|
||||||
api_cfg, for_obj_type: 'event_presentation', for_obj_id: current_presentation_id,
|
load_ae_obj_li__event_file({
|
||||||
enabled, limit: 25, try_cache, log_lvl
|
api_cfg,
|
||||||
}).then(res => presentation_obj.event_file_li = res));
|
for_obj_type: 'event_presentation',
|
||||||
|
for_obj_id: current_presentation_id,
|
||||||
|
enabled,
|
||||||
|
limit: 25,
|
||||||
|
try_cache,
|
||||||
|
log_lvl
|
||||||
|
}).then((res) => (presentation_obj.event_file_li = res))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inc_presenter_li) {
|
if (inc_presenter_li) {
|
||||||
tasks.push(load_ae_obj_li__event_presenter({
|
tasks.push(
|
||||||
api_cfg, for_obj_type: 'event_presentation', for_obj_id: current_presentation_id,
|
load_ae_obj_li__event_presenter({
|
||||||
inc_file_li, enabled, hidden, limit, offset, try_cache, log_lvl
|
api_cfg,
|
||||||
}).then(res => presentation_obj.event_presenter_li = res));
|
for_obj_type: 'event_presentation',
|
||||||
|
for_obj_id: current_presentation_id,
|
||||||
|
inc_file_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
try_cache,
|
||||||
|
log_lvl
|
||||||
|
}).then((res) => (presentation_obj.event_presenter_li = res))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tasks.length > 0) await Promise.all(tasks);
|
if (tasks.length > 0) await Promise.all(tasks);
|
||||||
@@ -140,17 +246,36 @@ export async function load_ae_obj_li__event_presentation({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventPresentation[]> {
|
}): Promise<ae_EventPresentation[]> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** load_ae_obj_li__event_presentation() *** for=${for_obj_type}:${for_obj_id} (SWR)`);
|
console.log(
|
||||||
|
`*** load_ae_obj_li__event_presentation() *** for=${for_obj_type}:${for_obj_id} (SWR)`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. FAST PATH: Cache hit
|
// 1. FAST PATH: Cache hit
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
try {
|
try {
|
||||||
// String-Only ID Vision: query event_session_id using the string ID
|
// String-Only ID Vision: query event_session_id using the string ID
|
||||||
const cached_li = await db_events.presentation.where('event_session_id').equals(for_obj_id).toArray();
|
const cached_li = await db_events.presentation
|
||||||
|
.where('event_session_id')
|
||||||
|
.equals(for_obj_id)
|
||||||
|
.toArray();
|
||||||
if (cached_li && cached_li.length > 0) {
|
if (cached_li && cached_li.length > 0) {
|
||||||
// Background refresh (non-blocking)
|
// Background refresh (non-blocking)
|
||||||
_refresh_presentation_li_background({ api_cfg, for_obj_type, for_obj_id, inc_file_li, inc_presenter_li, enabled, hidden, view, limit, offset, order_by_li, try_cache, log_lvl: 0 });
|
_refresh_presentation_li_background({
|
||||||
|
api_cfg,
|
||||||
|
for_obj_type,
|
||||||
|
for_obj_id,
|
||||||
|
inc_file_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
view,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
order_by_li,
|
||||||
|
try_cache,
|
||||||
|
log_lvl: 0
|
||||||
|
});
|
||||||
|
|
||||||
// Warm cache for nested loads in the background (FIRE AND FORGET)
|
// Warm cache for nested loads in the background (FIRE AND FORGET)
|
||||||
// DEPRECATED Optimization: Don't fire child loads for every item in a list here.
|
// DEPRECATED Optimization: Don't fire child loads for every item in a list here.
|
||||||
@@ -167,23 +292,72 @@ export async function load_ae_obj_li__event_presentation({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2. SLOW PATH: Wait for API
|
// 2. SLOW PATH: Wait for API
|
||||||
return await _refresh_presentation_li_background({ api_cfg, for_obj_type, for_obj_id, inc_file_li, inc_presenter_li, enabled, hidden, view, limit, offset, order_by_li, try_cache, log_lvl });
|
return await _refresh_presentation_li_background({
|
||||||
|
api_cfg,
|
||||||
|
for_obj_type,
|
||||||
|
for_obj_id,
|
||||||
|
inc_file_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
view,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
order_by_li,
|
||||||
|
try_cache,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function _refresh_presentation_li_background({ api_cfg, for_obj_type, for_obj_id, inc_file_li, inc_presenter_li, enabled, hidden, view, limit, offset, order_by_li, try_cache, log_lvl }: any) {
|
async function _refresh_presentation_li_background({
|
||||||
|
api_cfg,
|
||||||
|
for_obj_type,
|
||||||
|
for_obj_id,
|
||||||
|
inc_file_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
view,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
order_by_li,
|
||||||
|
try_cache,
|
||||||
|
log_lvl
|
||||||
|
}: any) {
|
||||||
if (typeof navigator !== 'undefined' && !navigator.onLine) return [];
|
if (typeof navigator !== 'undefined' && !navigator.onLine) return [];
|
||||||
try {
|
try {
|
||||||
const result_li = await api.get_ae_obj_li_v3({ api_cfg, obj_type: 'event_presentation', for_obj_type, for_obj_id, enabled, hidden, view, limit, offset, order_by_li, log_lvl });
|
const result_li = await api.get_ae_obj_li({
|
||||||
|
api_cfg,
|
||||||
|
obj_type: 'event_presentation',
|
||||||
|
for_obj_type,
|
||||||
|
for_obj_id,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
view,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
order_by_li,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
if (result_li) {
|
if (result_li) {
|
||||||
const processed = await process_ae_obj__event_presentation_props({ obj_li: result_li, log_lvl });
|
const processed = await process_ae_obj__event_presentation_props({
|
||||||
|
obj_li: result_li,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
|
|
||||||
// Ensure the linking ID is set correctly for indexing
|
// Ensure the linking ID is set correctly for indexing
|
||||||
if (for_obj_type === 'event_session') {
|
if (for_obj_type === 'event_session') {
|
||||||
processed.forEach(p => p.event_session_id = for_obj_id);
|
processed.forEach((p) => (p.event_session_id = for_obj_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'presentation', obj_li: processed, properties_to_save, log_lvl });
|
await db_save_ae_obj_li__ae_obj({
|
||||||
|
db_instance: db_events,
|
||||||
|
table_name: 'presentation',
|
||||||
|
obj_li: processed,
|
||||||
|
properties_to_save,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
// CRITICAL FIX (2026-02-26): Yield to microtask queue so Dexie liveQuery observers
|
// CRITICAL FIX (2026-02-26): Yield to microtask queue so Dexie liveQuery observers
|
||||||
// fire before we return. Without this, component-mounted liveQueries may subscribe
|
// fire before we return. Without this, component-mounted liveQueries may subscribe
|
||||||
// to IDB *before* the write completes, causing empty results on cold-start.
|
// to IDB *before* the write completes, causing empty results on cold-start.
|
||||||
@@ -194,9 +368,21 @@ async function _refresh_presentation_li_background({ api_cfg, for_obj_type, for_
|
|||||||
// before presenter data was loaded, causing "refresh twice" bug on cold-start.
|
// before presenter data was loaded, causing "refresh twice" bug on cold-start.
|
||||||
// Now we await all nested loads AND preserve try_cache so presenters are written to IDB.
|
// Now we await all nested loads AND preserve try_cache so presenters are written to IDB.
|
||||||
if (inc_file_li || inc_presenter_li) {
|
if (inc_file_li || inc_presenter_li) {
|
||||||
await Promise.all(processed.map(p =>
|
await Promise.all(
|
||||||
_handle_nested_loads(p, { api_cfg, inc_file_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache, log_lvl: 0 })
|
processed.map((p) =>
|
||||||
));
|
_handle_nested_loads(p, {
|
||||||
|
api_cfg,
|
||||||
|
inc_file_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
try_cache,
|
||||||
|
log_lvl: 0
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return processed;
|
return processed;
|
||||||
}
|
}
|
||||||
@@ -206,42 +392,45 @@ async function _refresh_presentation_li_background({ api_cfg, for_obj_type, for_
|
|||||||
|
|
||||||
// Updated 2026-01-20 to V3
|
// Updated 2026-01-20 to V3
|
||||||
export async function create_ae_obj__event_presentation({
|
export async function create_ae_obj__event_presentation({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
event_session_id,
|
event_session_id,
|
||||||
data_kv,
|
data_kv,
|
||||||
try_cache = true,
|
try_cache = true,
|
||||||
log_lvl = 0
|
log_lvl = 0
|
||||||
}: {
|
}: {
|
||||||
api_cfg: any;
|
api_cfg: any;
|
||||||
event_session_id: string;
|
event_session_id: string;
|
||||||
data_kv: key_val;
|
data_kv: key_val;
|
||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventPresentation | null> {
|
}): Promise<ae_EventPresentation | null> {
|
||||||
const result = await api.create_nested_obj_v3({
|
const result = await api.create_nested_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
for_obj_type: 'event_session',
|
for_obj_type: 'event_session',
|
||||||
for_obj_id: event_session_id,
|
for_obj_id: event_session_id,
|
||||||
obj_type: 'event_presentation',
|
obj_type: 'event_presentation',
|
||||||
fields: { ...data_kv },
|
fields: { ...data_kv },
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
const processed = await process_ae_obj__event_presentation_props({ obj_li: [result], log_lvl });
|
const processed = await process_ae_obj__event_presentation_props({
|
||||||
const processed_obj = processed[0];
|
obj_li: [result],
|
||||||
if (try_cache) {
|
log_lvl
|
||||||
await db_save_ae_obj_li__ae_obj({
|
});
|
||||||
db_instance: db_events,
|
const processed_obj = processed[0];
|
||||||
table_name: 'presentation',
|
if (try_cache) {
|
||||||
obj_li: [processed_obj],
|
await db_save_ae_obj_li__ae_obj({
|
||||||
properties_to_save,
|
db_instance: db_events,
|
||||||
log_lvl
|
table_name: 'presentation',
|
||||||
});
|
obj_li: [processed_obj],
|
||||||
}
|
properties_to_save,
|
||||||
return processed_obj;
|
log_lvl
|
||||||
}
|
});
|
||||||
return null;
|
}
|
||||||
|
return processed_obj;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updated 2026-01-20 to V3
|
// Updated 2026-01-20 to V3
|
||||||
@@ -258,8 +447,12 @@ export async function delete_ae_obj_id__event_presentation({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
const result = await api.delete_ae_obj_v3({
|
const result = await api.delete_ae_obj({
|
||||||
api_cfg, obj_type: 'event_presentation', obj_id: event_presentation_id, method, log_lvl
|
api_cfg,
|
||||||
|
obj_type: 'event_presentation',
|
||||||
|
obj_id: event_presentation_id,
|
||||||
|
method,
|
||||||
|
log_lvl
|
||||||
});
|
});
|
||||||
if (try_cache) await db_events.presentation.delete(event_presentation_id);
|
if (try_cache) await db_events.presentation.delete(event_presentation_id);
|
||||||
return result;
|
return result;
|
||||||
@@ -279,14 +472,27 @@ export async function update_ae_obj__event_presentation({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventPresentation | null> {
|
}): Promise<ae_EventPresentation | null> {
|
||||||
const result = await api.update_ae_obj_v3({
|
const result = await api.update_ae_obj({
|
||||||
api_cfg, obj_type: 'event_presentation', obj_id: event_presentation_id, fields: data_kv, log_lvl
|
api_cfg,
|
||||||
|
obj_type: 'event_presentation',
|
||||||
|
obj_id: event_presentation_id,
|
||||||
|
fields: data_kv,
|
||||||
|
log_lvl
|
||||||
});
|
});
|
||||||
if (result) {
|
if (result) {
|
||||||
const processed = await process_ae_obj__event_presentation_props({ obj_li: [result], log_lvl });
|
const processed = await process_ae_obj__event_presentation_props({
|
||||||
|
obj_li: [result],
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
const processed_obj = processed[0];
|
const processed_obj = processed[0];
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'presentation', obj_li: [processed_obj], properties_to_save, log_lvl });
|
await db_save_ae_obj_li__ae_obj({
|
||||||
|
db_instance: db_events,
|
||||||
|
table_name: 'presentation',
|
||||||
|
obj_li: [processed_obj],
|
||||||
|
properties_to_save,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return processed_obj;
|
return processed_obj;
|
||||||
}
|
}
|
||||||
@@ -295,24 +501,74 @@ export async function update_ae_obj__event_presentation({
|
|||||||
|
|
||||||
// Updated 2026-01-21 to Restore Full Aether Search Logic
|
// Updated 2026-01-21 to Restore Full Aether Search Logic
|
||||||
export async function search__event_presentation({
|
export async function search__event_presentation({
|
||||||
api_cfg, event_id, fulltext_search_qry_str = '', like_search_qry_str = '', enabled = 'enabled', hidden = 'not_hidden', view = 'default', limit = 50, offset = 0, order_by_li = [{ sort: 'ASC' }, { start_datetime: 'ASC' }, { name: 'ASC' }], try_cache = true, log_lvl = 0
|
api_cfg,
|
||||||
|
event_id,
|
||||||
|
fulltext_search_qry_str = '',
|
||||||
|
like_search_qry_str = '',
|
||||||
|
enabled = 'enabled',
|
||||||
|
hidden = 'not_hidden',
|
||||||
|
view = 'default',
|
||||||
|
limit = 50,
|
||||||
|
offset = 0,
|
||||||
|
order_by_li = [{ sort: 'ASC' }, { start_datetime: 'ASC' }, { name: 'ASC' }],
|
||||||
|
try_cache = true,
|
||||||
|
log_lvl = 0
|
||||||
}: {
|
}: {
|
||||||
api_cfg: any; event_id: string; fulltext_search_qry_str?: string; like_search_qry_str?: string; enabled?: 'enabled' | 'all' | 'not_enabled'; hidden?: 'hidden' | 'all' | 'not_hidden'; view?: string; limit?: number; offset?: number; order_by_li?: any; try_cache?: boolean; log_lvl?: number;
|
api_cfg: any;
|
||||||
|
event_id: string;
|
||||||
|
fulltext_search_qry_str?: string;
|
||||||
|
like_search_qry_str?: string;
|
||||||
|
enabled?: 'enabled' | 'all' | 'not_enabled';
|
||||||
|
hidden?: 'hidden' | 'all' | 'not_hidden';
|
||||||
|
view?: string;
|
||||||
|
limit?: number;
|
||||||
|
offset?: number;
|
||||||
|
order_by_li?: any;
|
||||||
|
try_cache?: boolean;
|
||||||
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventPresentation[]> {
|
}): Promise<ae_EventPresentation[]> {
|
||||||
const search_query: any = { q: '', and: [{ field: 'event_id', op: 'eq', value: event_id }] };
|
const search_query: any = {
|
||||||
|
q: '',
|
||||||
|
and: [{ field: 'event_id', op: 'eq', value: event_id }]
|
||||||
|
};
|
||||||
const params: key_val = {};
|
const params: key_val = {};
|
||||||
if (fulltext_search_qry_str && fulltext_search_qry_str.length > 2) params['ft_qry'] = { 'default_qry_str': fulltext_search_qry_str };
|
if (fulltext_search_qry_str && fulltext_search_qry_str.length > 2)
|
||||||
if (like_search_qry_str) params['lk_qry'] = { 'default_qry_str': like_search_qry_str };
|
params['ft_qry'] = { default_qry_str: fulltext_search_qry_str };
|
||||||
if (enabled === 'enabled') search_query.and.push({ field: 'enable', op: 'eq', value: 1 });
|
if (like_search_qry_str)
|
||||||
else if (enabled === 'not_enabled') search_query.and.push({ field: 'enable', op: 'eq', value: 0 });
|
params['lk_qry'] = { default_qry_str: like_search_qry_str };
|
||||||
if (hidden === 'hidden') search_query.and.push({ field: 'hide', op: 'eq', value: 1 });
|
if (enabled === 'enabled')
|
||||||
else if (hidden === 'not_hidden') search_query.and.push({ field: 'hide', op: 'eq', value: 0 });
|
search_query.and.push({ field: 'enable', op: 'eq', value: 1 });
|
||||||
|
else if (enabled === 'not_enabled')
|
||||||
|
search_query.and.push({ field: 'enable', op: 'eq', value: 0 });
|
||||||
|
if (hidden === 'hidden')
|
||||||
|
search_query.and.push({ field: 'hide', op: 'eq', value: 1 });
|
||||||
|
else if (hidden === 'not_hidden')
|
||||||
|
search_query.and.push({ field: 'hide', op: 'eq', value: 0 });
|
||||||
|
|
||||||
const result_li = await api.search_ae_obj_v3({ api_cfg, obj_type: 'event_presentation', search_query, order_by_li, params, view, limit, offset, log_lvl });
|
const result_li = await api.search_ae_obj({
|
||||||
|
api_cfg,
|
||||||
|
obj_type: 'event_presentation',
|
||||||
|
search_query,
|
||||||
|
order_by_li,
|
||||||
|
params,
|
||||||
|
view,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
if (result_li) {
|
if (result_li) {
|
||||||
const processed = await process_ae_obj__event_presentation_props({ obj_li: result_li, log_lvl });
|
const processed = await process_ae_obj__event_presentation_props({
|
||||||
|
obj_li: result_li,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'presentation', obj_li: processed, properties_to_save, log_lvl });
|
await db_save_ae_obj_li__ae_obj({
|
||||||
|
db_instance: db_events,
|
||||||
|
table_name: 'presentation',
|
||||||
|
obj_li: processed,
|
||||||
|
properties_to_save,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return processed;
|
return processed;
|
||||||
}
|
}
|
||||||
@@ -322,10 +578,53 @@ export async function search__event_presentation({
|
|||||||
export const qry__event_presentation = search__event_presentation;
|
export const qry__event_presentation = search__event_presentation;
|
||||||
|
|
||||||
export const properties_to_save = [
|
export const properties_to_save = [
|
||||||
'id', 'event_presentation_id', 'event_presentation_id_random', 'external_id', 'code', 'for_type', 'for_id', 'for_id_random', 'type_code', 'event_id', 'event_session_id', 'event_abstract_id', 'event_id_random', 'event_session_id_random', 'event_abstract_id_random', 'abstract_code', 'name', 'description', 'start_datetime', 'end_datetime', 'passcode', 'hide_event_launcher', 'enable', 'hide', 'priority', 'sort', 'group', 'notes', 'created_on', 'updated_on', 'tmp_sort_1', 'tmp_sort_2', 'event_session_code', 'event_session_name'
|
'id',
|
||||||
|
'event_presentation_id',
|
||||||
|
'event_presentation_id_random',
|
||||||
|
'external_id',
|
||||||
|
'code',
|
||||||
|
'for_type',
|
||||||
|
'for_id',
|
||||||
|
'for_id_random',
|
||||||
|
'type_code',
|
||||||
|
'event_id',
|
||||||
|
'event_session_id',
|
||||||
|
'event_abstract_id',
|
||||||
|
'event_id_random',
|
||||||
|
'event_session_id_random',
|
||||||
|
'event_abstract_id_random',
|
||||||
|
'abstract_code',
|
||||||
|
'name',
|
||||||
|
'description',
|
||||||
|
'start_datetime',
|
||||||
|
'end_datetime',
|
||||||
|
'passcode',
|
||||||
|
'hide_event_launcher',
|
||||||
|
'enable',
|
||||||
|
'hide',
|
||||||
|
'priority',
|
||||||
|
'sort',
|
||||||
|
'group',
|
||||||
|
'notes',
|
||||||
|
'created_on',
|
||||||
|
'updated_on',
|
||||||
|
'tmp_sort_1',
|
||||||
|
'tmp_sort_2',
|
||||||
|
'event_session_code',
|
||||||
|
'event_session_name'
|
||||||
];
|
];
|
||||||
|
|
||||||
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[]> {
|
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 (!obj_li || obj_li.length === 0) return [];
|
if (!obj_li || obj_li.length === 0) return [];
|
||||||
const processed_obj_li: T[] = [];
|
const processed_obj_li: T[] = [];
|
||||||
for (const original_obj of obj_li) {
|
for (const original_obj of obj_li) {
|
||||||
@@ -338,26 +637,48 @@ async function _process_generic_props<T extends Record<string, any>>({ obj_li, o
|
|||||||
}
|
}
|
||||||
const randomIdKey = `${obj_type}_id_random`;
|
const randomIdKey = `${obj_type}_id_random`;
|
||||||
const baseIdKey = `${obj_type}_id`;
|
const baseIdKey = `${obj_type}_id`;
|
||||||
if (processed_obj[randomIdKey]) (processed_obj as any).id = processed_obj[randomIdKey];
|
if (processed_obj[randomIdKey])
|
||||||
else if (processed_obj[baseIdKey]) (processed_obj as any).id = processed_obj[baseIdKey];
|
(processed_obj as any).id = processed_obj[randomIdKey];
|
||||||
|
else if (processed_obj[baseIdKey])
|
||||||
|
(processed_obj as any).id = processed_obj[baseIdKey];
|
||||||
const group = processed_obj.group ?? '0';
|
const group = processed_obj.group ?? '0';
|
||||||
const priority = processed_obj.priority ? 1 : 0;
|
const priority = processed_obj.priority ? 1 : 0;
|
||||||
const sort = processed_obj.sort ?? '0';
|
const sort = processed_obj.sort ?? '0';
|
||||||
const updated = processed_obj.updated_on ?? processed_obj.created_on ?? new Date(0).toISOString();
|
const updated =
|
||||||
|
processed_obj.updated_on ??
|
||||||
|
processed_obj.created_on ??
|
||||||
|
new Date(0).toISOString();
|
||||||
const name = processed_obj.name ?? '';
|
const name = processed_obj.name ?? '';
|
||||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
(processed_obj as any).tmp_sort_1 =
|
||||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
`${group}_${priority}_${sort}_${updated}`;
|
||||||
if (specific_processor) processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
(processed_obj as any).tmp_sort_2 =
|
||||||
|
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||||
|
if (specific_processor)
|
||||||
|
processed_obj = await Promise.resolve(
|
||||||
|
specific_processor(processed_obj)
|
||||||
|
);
|
||||||
processed_obj_li.push(processed_obj as T);
|
processed_obj_li.push(processed_obj as T);
|
||||||
}
|
}
|
||||||
return processed_obj_li;
|
return processed_obj_li;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function process_ae_obj__event_presentation_props({ obj_li, log_lvl = 0 }: { obj_li: any[]; log_lvl?: number; }) {
|
export async function process_ae_obj__event_presentation_props({
|
||||||
return _process_generic_props({ obj_li, obj_type: 'event_presentation', log_lvl, specific_processor: (obj) => {
|
obj_li,
|
||||||
// Ensure linking IDs are the string versions for indexing
|
log_lvl = 0
|
||||||
if (obj.event_session_id_random) obj.event_session_id = obj.event_session_id_random;
|
}: {
|
||||||
if (obj.event_id_random) obj.event_id = obj.event_id_random;
|
obj_li: any[];
|
||||||
return obj;
|
log_lvl?: number;
|
||||||
}});
|
}) {
|
||||||
|
return _process_generic_props({
|
||||||
|
obj_li,
|
||||||
|
obj_type: 'event_presentation',
|
||||||
|
log_lvl,
|
||||||
|
specific_processor: (obj) => {
|
||||||
|
// Ensure linking IDs are the string versions for indexing
|
||||||
|
if (obj.event_session_id_random)
|
||||||
|
obj.event_session_id = obj.event_session_id_random;
|
||||||
|
if (obj.event_id_random) obj.event_id = obj.event_id_random;
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,9 @@ export async function load_ae_obj_id__event_presenter({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventPresenter | null> {
|
}): Promise<ae_EventPresenter | null> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** load_ae_obj_id__event_presenter() *** [V3] id=${event_presenter_id} (SWR)`);
|
console.log(
|
||||||
|
`*** load_ae_obj_id__event_presenter() *** [V3] id=${event_presenter_id} (SWR)`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. FAST PATH: Cache hit
|
// 1. FAST PATH: Cache hit
|
||||||
@@ -38,30 +40,71 @@ export async function load_ae_obj_id__event_presenter({
|
|||||||
const cached = await db_events.presenter.get(event_presenter_id);
|
const cached = await db_events.presenter.get(event_presenter_id);
|
||||||
if (cached) {
|
if (cached) {
|
||||||
// Background refresh (non-blocking)
|
// Background refresh (non-blocking)
|
||||||
_refresh_presenter_id_background({ api_cfg, event_presenter_id, view, try_cache, inc_file_li, log_lvl: 0 });
|
_refresh_presenter_id_background({
|
||||||
|
api_cfg,
|
||||||
|
event_presenter_id,
|
||||||
|
view,
|
||||||
|
try_cache,
|
||||||
|
inc_file_li,
|
||||||
|
log_lvl: 0
|
||||||
|
});
|
||||||
return cached;
|
return cached;
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. SLOW PATH: Wait for API
|
// 2. SLOW PATH: Wait for API
|
||||||
return await _refresh_presenter_id_background({ api_cfg, event_presenter_id, view, try_cache, inc_file_li, log_lvl });
|
return await _refresh_presenter_id_background({
|
||||||
|
api_cfg,
|
||||||
|
event_presenter_id,
|
||||||
|
view,
|
||||||
|
try_cache,
|
||||||
|
inc_file_li,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function _refresh_presenter_id_background({ api_cfg, event_presenter_id, view, try_cache, inc_file_li, log_lvl }: any) {
|
async function _refresh_presenter_id_background({
|
||||||
|
api_cfg,
|
||||||
|
event_presenter_id,
|
||||||
|
view,
|
||||||
|
try_cache,
|
||||||
|
inc_file_li,
|
||||||
|
log_lvl
|
||||||
|
}: any) {
|
||||||
if (typeof navigator !== 'undefined' && !navigator.onLine) return null;
|
if (typeof navigator !== 'undefined' && !navigator.onLine) return null;
|
||||||
try {
|
try {
|
||||||
const result = await api.get_ae_obj_v3({ api_cfg, obj_type: 'event_presenter', obj_id: event_presenter_id, view, log_lvl });
|
const result = await api.get_ae_obj({
|
||||||
|
api_cfg,
|
||||||
|
obj_type: 'event_presenter',
|
||||||
|
obj_id: event_presenter_id,
|
||||||
|
view,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
if (result) {
|
if (result) {
|
||||||
const processed = await process_ae_obj__event_presenter_props({ obj_li: [result], log_lvl });
|
const processed = await process_ae_obj__event_presenter_props({
|
||||||
|
obj_li: [result],
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
const processed_obj = processed[0];
|
const processed_obj = processed[0];
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'presenter', obj_li: [processed_obj], properties_to_save, log_lvl });
|
await db_save_ae_obj_li__ae_obj({
|
||||||
|
db_instance: db_events,
|
||||||
|
table_name: 'presenter',
|
||||||
|
obj_li: [processed_obj],
|
||||||
|
properties_to_save,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (inc_file_li) {
|
if (inc_file_li) {
|
||||||
processed_obj.event_file_li = await load_ae_obj_li__event_file({
|
processed_obj.event_file_li = await load_ae_obj_li__event_file({
|
||||||
api_cfg, for_obj_type: 'event_presenter', for_obj_id: event_presenter_id,
|
api_cfg,
|
||||||
enabled: 'all', limit: 25, try_cache: false, log_lvl
|
for_obj_type: 'event_presenter',
|
||||||
|
for_obj_id: event_presenter_id,
|
||||||
|
enabled: 'all',
|
||||||
|
limit: 25,
|
||||||
|
try_cache: false,
|
||||||
|
log_lvl
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return processed_obj;
|
return processed_obj;
|
||||||
@@ -104,7 +147,9 @@ export async function load_ae_obj_li__event_presenter({
|
|||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventPresenter[]> {
|
}): Promise<ae_EventPresenter[]> {
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`*** load_ae_obj_li__event_presenter() *** [V3] for=${for_obj_type}:${for_obj_id} (SWR)`);
|
console.log(
|
||||||
|
`*** load_ae_obj_li__event_presenter() *** [V3] for=${for_obj_type}:${for_obj_id} (SWR)`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. FAST PATH: Check cache using specific indices
|
// 1. FAST PATH: Check cache using specific indices
|
||||||
@@ -112,31 +157,94 @@ export async function load_ae_obj_li__event_presenter({
|
|||||||
try {
|
try {
|
||||||
let cached_li: any[] = [];
|
let cached_li: any[] = [];
|
||||||
if (for_obj_type === 'event_presentation') {
|
if (for_obj_type === 'event_presentation') {
|
||||||
cached_li = await db_events.presenter.where('event_presentation_id').equals(for_obj_id).toArray();
|
cached_li = await db_events.presenter
|
||||||
|
.where('event_presentation_id')
|
||||||
|
.equals(for_obj_id)
|
||||||
|
.toArray();
|
||||||
} else if (for_obj_type === 'event_session') {
|
} else if (for_obj_type === 'event_session') {
|
||||||
cached_li = await db_events.presenter.where('event_session_id').equals(for_obj_id).toArray();
|
cached_li = await db_events.presenter
|
||||||
|
.where('event_session_id')
|
||||||
|
.equals(for_obj_id)
|
||||||
|
.toArray();
|
||||||
} else if (for_obj_type === 'event') {
|
} else if (for_obj_type === 'event') {
|
||||||
cached_li = await db_events.presenter.where('event_id').equals(for_obj_id).toArray();
|
cached_li = await db_events.presenter
|
||||||
|
.where('event_id')
|
||||||
|
.equals(for_obj_id)
|
||||||
|
.toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cached_li && cached_li.length > 0) {
|
if (cached_li && cached_li.length > 0) {
|
||||||
// Background refresh (non-blocking)
|
// Background refresh (non-blocking)
|
||||||
_refresh_presenter_li_background({ api_cfg, for_obj_type, for_obj_id, inc_file_li, enabled, hidden, view, limit, offset, order_by_li, try_cache, log_lvl: 0 });
|
_refresh_presenter_li_background({
|
||||||
|
api_cfg,
|
||||||
|
for_obj_type,
|
||||||
|
for_obj_id,
|
||||||
|
inc_file_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
view,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
order_by_li,
|
||||||
|
try_cache,
|
||||||
|
log_lvl: 0
|
||||||
|
});
|
||||||
return cached_li;
|
return cached_li;
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. SLOW PATH: Wait for API
|
// 2. SLOW PATH: Wait for API
|
||||||
return await _refresh_presenter_li_background({ api_cfg, for_obj_type, for_obj_id, inc_file_li, enabled, hidden, view, limit, offset, order_by_li, try_cache, log_lvl });
|
return await _refresh_presenter_li_background({
|
||||||
|
api_cfg,
|
||||||
|
for_obj_type,
|
||||||
|
for_obj_id,
|
||||||
|
inc_file_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
view,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
order_by_li,
|
||||||
|
try_cache,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function _refresh_presenter_li_background({ api_cfg, for_obj_type, for_obj_id, inc_file_li, enabled, hidden, view, limit, offset, order_by_li, try_cache, log_lvl }: any) {
|
async function _refresh_presenter_li_background({
|
||||||
|
api_cfg,
|
||||||
|
for_obj_type,
|
||||||
|
for_obj_id,
|
||||||
|
inc_file_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
view,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
order_by_li,
|
||||||
|
try_cache,
|
||||||
|
log_lvl
|
||||||
|
}: any) {
|
||||||
if (typeof navigator !== 'undefined' && !navigator.onLine) return [];
|
if (typeof navigator !== 'undefined' && !navigator.onLine) return [];
|
||||||
try {
|
try {
|
||||||
const result_li = await api.get_ae_obj_li_v3({ api_cfg, obj_type: 'event_presenter', for_obj_type, for_obj_id, enabled, hidden, view, limit, offset, order_by_li, log_lvl });
|
const result_li = await api.get_ae_obj_li({
|
||||||
|
api_cfg,
|
||||||
|
obj_type: 'event_presenter',
|
||||||
|
for_obj_type,
|
||||||
|
for_obj_id,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
view,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
order_by_li,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
if (result_li) {
|
if (result_li) {
|
||||||
const processed = await process_ae_obj__event_presenter_props({ obj_li: result_li, log_lvl });
|
const processed = await process_ae_obj__event_presenter_props({
|
||||||
|
obj_li: result_li,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
|
|
||||||
// String-Only ID Vision: Ensure linking ID is set for indexing
|
// String-Only ID Vision: Ensure linking ID is set for indexing
|
||||||
processed.forEach((p) => {
|
processed.forEach((p) => {
|
||||||
@@ -155,7 +263,13 @@ async function _refresh_presenter_li_background({ api_cfg, for_obj_type, for_obj
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'presenter', obj_li: processed, properties_to_save, log_lvl });
|
await db_save_ae_obj_li__ae_obj({
|
||||||
|
db_instance: db_events,
|
||||||
|
table_name: 'presenter',
|
||||||
|
obj_li: processed,
|
||||||
|
properties_to_save,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
// CRITICAL FIX (2026-02-26): Yield to microtask queue so Dexie liveQuery observers
|
// CRITICAL FIX (2026-02-26): Yield to microtask queue so Dexie liveQuery observers
|
||||||
// fire before we return. Without this, component-mounted liveQueries may subscribe
|
// fire before we return. Without this, component-mounted liveQueries may subscribe
|
||||||
// to IDB *before* the write completes, causing empty results on cold-start.
|
// to IDB *before* the write completes, causing empty results on cold-start.
|
||||||
@@ -164,10 +278,15 @@ async function _refresh_presenter_li_background({ api_cfg, for_obj_type, for_obj
|
|||||||
|
|
||||||
// Background nested loads for refreshed items (FIRE AND FORGET)
|
// Background nested loads for refreshed items (FIRE AND FORGET)
|
||||||
if (inc_file_li) {
|
if (inc_file_li) {
|
||||||
processed.forEach(p => {
|
processed.forEach((p) => {
|
||||||
load_ae_obj_li__event_file({
|
load_ae_obj_li__event_file({
|
||||||
api_cfg, for_obj_type: 'event_presenter', for_obj_id: p.id,
|
api_cfg,
|
||||||
enabled: 'all', limit: 25, try_cache: false, log_lvl: 0
|
for_obj_type: 'event_presenter',
|
||||||
|
for_obj_id: p.id,
|
||||||
|
enabled: 'all',
|
||||||
|
limit: 25,
|
||||||
|
try_cache: false,
|
||||||
|
log_lvl: 0
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -180,128 +299,143 @@ async function _refresh_presenter_li_background({ api_cfg, for_obj_type, for_obj
|
|||||||
|
|
||||||
// Updated 2026-01-20 to V3
|
// Updated 2026-01-20 to V3
|
||||||
export async function create_ae_obj__event_presenter({
|
export async function create_ae_obj__event_presenter({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
event_presentation_id,
|
event_presentation_id,
|
||||||
data_kv,
|
data_kv,
|
||||||
try_cache = true,
|
try_cache = true,
|
||||||
log_lvl = 0
|
log_lvl = 0
|
||||||
}: {
|
}: {
|
||||||
api_cfg: any;
|
api_cfg: any;
|
||||||
event_presentation_id?: string;
|
event_presentation_id?: string;
|
||||||
data_kv: key_val;
|
data_kv: key_val;
|
||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventPresenter | null> {
|
}): Promise<ae_EventPresenter | null> {
|
||||||
if (!event_presentation_id) event_presentation_id = get(events_slct).event_presentation_id;
|
if (!event_presentation_id)
|
||||||
|
event_presentation_id = get(events_slct).event_presentation_id;
|
||||||
if (!event_presentation_id) {
|
if (!event_presentation_id) {
|
||||||
console.error('create_ae_obj__event_presenter: event_presentation_id is required');
|
console.error(
|
||||||
|
'create_ae_obj__event_presenter: event_presentation_id is required'
|
||||||
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const result = await api.create_nested_obj_v3({
|
const result = await api.create_nested_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
for_obj_type: 'event_presentation',
|
for_obj_type: 'event_presentation',
|
||||||
for_obj_id: event_presentation_id,
|
for_obj_id: event_presentation_id,
|
||||||
obj_type: 'event_presenter',
|
obj_type: 'event_presenter',
|
||||||
fields: { ...data_kv },
|
fields: { ...data_kv },
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
const processed = await process_ae_obj__event_presenter_props({ obj_li: [result], log_lvl });
|
const processed = await process_ae_obj__event_presenter_props({
|
||||||
const processed_obj = processed[0];
|
obj_li: [result],
|
||||||
if (try_cache) {
|
log_lvl
|
||||||
await db_save_ae_obj_li__ae_obj({
|
});
|
||||||
db_instance: db_events,
|
const processed_obj = processed[0];
|
||||||
table_name: 'presenter',
|
if (try_cache) {
|
||||||
obj_li: [processed_obj],
|
await db_save_ae_obj_li__ae_obj({
|
||||||
properties_to_save,
|
db_instance: db_events,
|
||||||
log_lvl
|
table_name: 'presenter',
|
||||||
});
|
obj_li: [processed_obj],
|
||||||
}
|
properties_to_save,
|
||||||
return processed_obj;
|
log_lvl
|
||||||
}
|
});
|
||||||
return null;
|
}
|
||||||
|
return processed_obj;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updated 2026-01-20 to V3
|
// Updated 2026-01-20 to V3
|
||||||
export async function delete_ae_obj_id__event_presenter({
|
export async function delete_ae_obj_id__event_presenter({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
event_presentation_id,
|
event_presentation_id,
|
||||||
event_presenter_id,
|
event_presenter_id,
|
||||||
method = 'delete',
|
method = 'delete',
|
||||||
try_cache = true,
|
try_cache = true,
|
||||||
log_lvl = 0
|
log_lvl = 0
|
||||||
}: {
|
}: {
|
||||||
api_cfg: any;
|
api_cfg: any;
|
||||||
event_presentation_id?: string;
|
event_presentation_id?: string;
|
||||||
event_presenter_id: string;
|
event_presenter_id: string;
|
||||||
method?: 'delete' | 'soft_delete' | 'disable' | 'hide';
|
method?: 'delete' | 'soft_delete' | 'disable' | 'hide';
|
||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
if (!event_presentation_id) event_presentation_id = get(events_slct).event_presentation_id;
|
if (!event_presentation_id)
|
||||||
|
event_presentation_id = get(events_slct).event_presentation_id;
|
||||||
if (!event_presentation_id) {
|
if (!event_presentation_id) {
|
||||||
console.error('delete_ae_obj_id__event_presenter: event_presentation_id is required');
|
console.error(
|
||||||
|
'delete_ae_obj_id__event_presenter: event_presentation_id is required'
|
||||||
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const result = await api.delete_nested_ae_obj_v3({
|
const result = await api.delete_nested_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
for_obj_type: 'event_presentation',
|
for_obj_type: 'event_presentation',
|
||||||
for_obj_id: event_presentation_id,
|
for_obj_id: event_presentation_id,
|
||||||
obj_type: 'event_presenter',
|
obj_type: 'event_presenter',
|
||||||
obj_id: event_presenter_id,
|
obj_id: event_presenter_id,
|
||||||
method,
|
method,
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
if (try_cache) await db_events.presenter.delete(event_presenter_id);
|
if (try_cache) await db_events.presenter.delete(event_presenter_id);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updated 2026-01-20 to V3
|
// Updated 2026-01-20 to V3
|
||||||
export async function update_ae_obj__event_presenter({
|
export async function update_ae_obj__event_presenter({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
event_presentation_id,
|
event_presentation_id,
|
||||||
event_presenter_id,
|
event_presenter_id,
|
||||||
data_kv,
|
data_kv,
|
||||||
try_cache = true,
|
try_cache = true,
|
||||||
log_lvl = 0
|
log_lvl = 0
|
||||||
}: {
|
}: {
|
||||||
api_cfg: any;
|
api_cfg: any;
|
||||||
event_presentation_id?: string;
|
event_presentation_id?: string;
|
||||||
event_presenter_id: string;
|
event_presenter_id: string;
|
||||||
data_kv: key_val;
|
data_kv: key_val;
|
||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventPresenter | null> {
|
}): Promise<ae_EventPresenter | null> {
|
||||||
if (!event_presentation_id) event_presentation_id = get(events_slct).event_presentation_id;
|
if (!event_presentation_id)
|
||||||
|
event_presentation_id = get(events_slct).event_presentation_id;
|
||||||
if (!event_presentation_id) {
|
if (!event_presentation_id) {
|
||||||
console.error('update_ae_obj__event_presenter: event_presentation_id is required');
|
console.error(
|
||||||
|
'update_ae_obj__event_presenter: event_presentation_id is required'
|
||||||
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const result = await api.update_nested_obj_v3({
|
const result = await api.update_nested_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
for_obj_type: 'event_presentation',
|
for_obj_type: 'event_presentation',
|
||||||
for_obj_id: event_presentation_id,
|
for_obj_id: event_presentation_id,
|
||||||
obj_type: 'event_presenter',
|
obj_type: 'event_presenter',
|
||||||
obj_id: event_presenter_id,
|
obj_id: event_presenter_id,
|
||||||
fields: data_kv,
|
fields: data_kv,
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
if (result) {
|
if (result) {
|
||||||
const processed = await process_ae_obj__event_presenter_props({ obj_li: [result], log_lvl });
|
const processed = await process_ae_obj__event_presenter_props({
|
||||||
const processed_obj = processed[0];
|
obj_li: [result],
|
||||||
if (try_cache) {
|
log_lvl
|
||||||
await db_save_ae_obj_li__ae_obj({
|
});
|
||||||
db_instance: db_events,
|
const processed_obj = processed[0];
|
||||||
table_name: 'presenter',
|
if (try_cache) {
|
||||||
obj_li: [processed_obj],
|
await db_save_ae_obj_li__ae_obj({
|
||||||
properties_to_save,
|
db_instance: db_events,
|
||||||
log_lvl
|
table_name: 'presenter',
|
||||||
});
|
obj_li: [processed_obj],
|
||||||
}
|
properties_to_save,
|
||||||
return processed_obj;
|
log_lvl
|
||||||
}
|
});
|
||||||
return null;
|
}
|
||||||
|
return processed_obj;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updated 2026-01-21 to Restore Full Aether Search Logic
|
// Updated 2026-01-21 to Restore Full Aether Search Logic
|
||||||
@@ -320,7 +454,11 @@ export async function search__event_presenter({
|
|||||||
view = 'default',
|
view = 'default',
|
||||||
limit = 25,
|
limit = 25,
|
||||||
offset = 0,
|
offset = 0,
|
||||||
order_by_li = [{ sort: 'ASC' }, { given_name: 'ASC' }, { family_name: 'ASC' }],
|
order_by_li = [
|
||||||
|
{ sort: 'ASC' },
|
||||||
|
{ given_name: 'ASC' },
|
||||||
|
{ family_name: 'ASC' }
|
||||||
|
],
|
||||||
try_cache = true,
|
try_cache = true,
|
||||||
log_lvl = 0
|
log_lvl = 0
|
||||||
}: {
|
}: {
|
||||||
@@ -342,29 +480,71 @@ export async function search__event_presenter({
|
|||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventPresenter[]> {
|
}): Promise<ae_EventPresenter[]> {
|
||||||
const search_query: any = { q: '', and: [{ field: 'event_id', op: 'eq', value: event_id }] };
|
const search_query: any = {
|
||||||
|
q: '',
|
||||||
|
and: [{ field: 'event_id', op: 'eq', value: event_id }]
|
||||||
|
};
|
||||||
const params: key_val = {};
|
const params: key_val = {};
|
||||||
if (fulltext_search_qry_str && fulltext_search_qry_str.length > 2)
|
if (fulltext_search_qry_str && fulltext_search_qry_str.length > 2)
|
||||||
params['ft_qry'] = { default_qry_str: fulltext_search_qry_str };
|
params['ft_qry'] = { default_qry_str: fulltext_search_qry_str };
|
||||||
if (ft_presenter_search_qry_str && ft_presenter_search_qry_str.length > 2)
|
if (ft_presenter_search_qry_str && ft_presenter_search_qry_str.length > 2)
|
||||||
params['ft_qry'] = { ...params['ft_qry'], event_presenter_li_qry_str: ft_presenter_search_qry_str };
|
params['ft_qry'] = {
|
||||||
if (like_search_qry_str) params['lk_qry'] = { default_qry_str: like_search_qry_str };
|
...params['ft_qry'],
|
||||||
|
event_presenter_li_qry_str: ft_presenter_search_qry_str
|
||||||
|
};
|
||||||
|
if (like_search_qry_str)
|
||||||
|
params['lk_qry'] = { default_qry_str: like_search_qry_str };
|
||||||
if (like_presentation_search_qry_str)
|
if (like_presentation_search_qry_str)
|
||||||
params['lk_qry'] = { ...params['lk_qry'], event_presentation_li_qry_str: like_presentation_search_qry_str };
|
params['lk_qry'] = {
|
||||||
|
...params['lk_qry'],
|
||||||
|
event_presentation_li_qry_str: like_presentation_search_qry_str
|
||||||
|
};
|
||||||
if (like_presenter_search_qry_str)
|
if (like_presenter_search_qry_str)
|
||||||
params['lk_qry'] = { ...params['lk_qry'], event_presenter_li_qry_str: like_presenter_search_qry_str };
|
params['lk_qry'] = {
|
||||||
if (agree !== null) search_query.and.push({ field: 'agree', op: 'eq', value: agree ? 1 : 0 });
|
...params['lk_qry'],
|
||||||
if (biography === true) search_query.and.push({ field: 'biography', op: 'ne', value: '' });
|
event_presenter_li_qry_str: like_presenter_search_qry_str
|
||||||
if (enabled === 'enabled') search_query.and.push({ field: 'enable', op: 'eq', value: 1 });
|
};
|
||||||
else if (enabled === 'not_enabled') search_query.and.push({ field: 'enable', op: 'eq', value: 0 });
|
if (agree !== null)
|
||||||
if (hidden === 'hidden') search_query.and.push({ field: 'hide', op: 'eq', value: 1 });
|
search_query.and.push({
|
||||||
else if (hidden === 'not_hidden') search_query.and.push({ field: 'hide', op: 'eq', value: 0 });
|
field: 'agree',
|
||||||
|
op: 'eq',
|
||||||
|
value: agree ? 1 : 0
|
||||||
|
});
|
||||||
|
if (biography === true)
|
||||||
|
search_query.and.push({ field: 'biography', op: 'ne', value: '' });
|
||||||
|
if (enabled === 'enabled')
|
||||||
|
search_query.and.push({ field: 'enable', op: 'eq', value: 1 });
|
||||||
|
else if (enabled === 'not_enabled')
|
||||||
|
search_query.and.push({ field: 'enable', op: 'eq', value: 0 });
|
||||||
|
if (hidden === 'hidden')
|
||||||
|
search_query.and.push({ field: 'hide', op: 'eq', value: 1 });
|
||||||
|
else if (hidden === 'not_hidden')
|
||||||
|
search_query.and.push({ field: 'hide', op: 'eq', value: 0 });
|
||||||
|
|
||||||
const result_li = await api.search_ae_obj_v3({ api_cfg, obj_type: 'event_presenter', search_query, order_by_li, params, view, limit, offset, log_lvl });
|
const result_li = await api.search_ae_obj({
|
||||||
|
api_cfg,
|
||||||
|
obj_type: 'event_presenter',
|
||||||
|
search_query,
|
||||||
|
order_by_li,
|
||||||
|
params,
|
||||||
|
view,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
if (result_li) {
|
if (result_li) {
|
||||||
const processed = await process_ae_obj__event_presenter_props({ obj_li: result_li, log_lvl });
|
const processed = await process_ae_obj__event_presenter_props({
|
||||||
|
obj_li: result_li,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'presenter', obj_li: processed, properties_to_save, log_lvl });
|
await db_save_ae_obj_li__ae_obj({
|
||||||
|
db_instance: db_events,
|
||||||
|
table_name: 'presenter',
|
||||||
|
obj_li: processed,
|
||||||
|
properties_to_save,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return processed;
|
return processed;
|
||||||
}
|
}
|
||||||
@@ -400,8 +580,16 @@ export async function email_sign_in__event_presenter({
|
|||||||
session_name?: string | null;
|
session_name?: string | null;
|
||||||
presentation_name?: string | null;
|
presentation_name?: string | null;
|
||||||
}) {
|
}) {
|
||||||
if (!to_email || !person_id || !person_passcode || !event_id || !event_presenter_id) {
|
if (
|
||||||
console.error('Missing required parameters for email_sign_in__event_presenter');
|
!to_email ||
|
||||||
|
!person_id ||
|
||||||
|
!person_passcode ||
|
||||||
|
!event_id ||
|
||||||
|
!event_presenter_id
|
||||||
|
) {
|
||||||
|
console.error(
|
||||||
|
'Missing required parameters for email_sign_in__event_presenter'
|
||||||
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const subject = `Pres Mgmt Hub Sign In Link for Presenter: ${to_name ?? 'Presenter'}`;
|
const subject = `Pres Mgmt Hub Sign In Link for Presenter: ${to_name ?? 'Presenter'}`;
|
||||||
@@ -420,10 +608,75 @@ export async function email_sign_in__event_presenter({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const properties_to_save = [
|
export const properties_to_save = [
|
||||||
'id', 'event_presenter_id', 'event_presenter_id_random', 'external_id', 'code', 'event_id', 'event_session_id', 'event_presentation_id', 'event_person_id', 'person_id', 'person_profile_id', 'person_id_random', 'person_profile_id_random', 'pronouns', 'informal_name', 'title_names', 'given_name', 'middle_name', 'family_name', 'designations', 'professional_title', 'full_name', 'affiliations', 'email', 'biography', 'agree', 'comments', 'passcode', 'hide_event_launcher', 'data_json', 'enable', 'hide', 'priority', 'sort', 'group', 'notes', 'created_on', 'updated_on', 'tmp_sort_1', 'tmp_sort_2', 'file_count', 'event_session_code', 'event_session_name', 'event_session_start_datetime', 'event_presentation_code', 'event_presentation_name', 'event_presentation_start_datetime', 'person_external_id', 'person_external_sys_id', 'person_given_name', 'person_family_name', 'person_full_name', 'person_professional_title', 'person_affiliations', 'person_primary_email', 'person_passcode'
|
'id',
|
||||||
|
'event_presenter_id',
|
||||||
|
'event_presenter_id_random',
|
||||||
|
'external_id',
|
||||||
|
'code',
|
||||||
|
'event_id',
|
||||||
|
'event_session_id',
|
||||||
|
'event_presentation_id',
|
||||||
|
'event_person_id',
|
||||||
|
'person_id',
|
||||||
|
'person_profile_id',
|
||||||
|
'person_id_random',
|
||||||
|
'person_profile_id_random',
|
||||||
|
'pronouns',
|
||||||
|
'informal_name',
|
||||||
|
'title_names',
|
||||||
|
'given_name',
|
||||||
|
'middle_name',
|
||||||
|
'family_name',
|
||||||
|
'designations',
|
||||||
|
'professional_title',
|
||||||
|
'full_name',
|
||||||
|
'affiliations',
|
||||||
|
'email',
|
||||||
|
'biography',
|
||||||
|
'agree',
|
||||||
|
'comments',
|
||||||
|
'passcode',
|
||||||
|
'hide_event_launcher',
|
||||||
|
'data_json',
|
||||||
|
'enable',
|
||||||
|
'hide',
|
||||||
|
'priority',
|
||||||
|
'sort',
|
||||||
|
'group',
|
||||||
|
'notes',
|
||||||
|
'created_on',
|
||||||
|
'updated_on',
|
||||||
|
'tmp_sort_1',
|
||||||
|
'tmp_sort_2',
|
||||||
|
'file_count',
|
||||||
|
'event_session_code',
|
||||||
|
'event_session_name',
|
||||||
|
'event_session_start_datetime',
|
||||||
|
'event_presentation_code',
|
||||||
|
'event_presentation_name',
|
||||||
|
'event_presentation_start_datetime',
|
||||||
|
'person_external_id',
|
||||||
|
'person_external_sys_id',
|
||||||
|
'person_given_name',
|
||||||
|
'person_family_name',
|
||||||
|
'person_full_name',
|
||||||
|
'person_professional_title',
|
||||||
|
'person_affiliations',
|
||||||
|
'person_primary_email',
|
||||||
|
'person_passcode'
|
||||||
];
|
];
|
||||||
|
|
||||||
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[]> {
|
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 (!obj_li || obj_li.length === 0) return [];
|
if (!obj_li || obj_li.length === 0) return [];
|
||||||
const processed_obj_li: T[] = [];
|
const processed_obj_li: T[] = [];
|
||||||
for (const original_obj of obj_li) {
|
for (const original_obj of obj_li) {
|
||||||
@@ -439,28 +692,50 @@ async function _process_generic_props<T extends Record<string, any>>({ obj_li, o
|
|||||||
if (processed_obj[randomIdKey]) {
|
if (processed_obj[randomIdKey]) {
|
||||||
(processed_obj as any).id = processed_obj[randomIdKey];
|
(processed_obj as any).id = processed_obj[randomIdKey];
|
||||||
(processed_obj as any)[baseIdKey] = processed_obj[randomIdKey];
|
(processed_obj as any)[baseIdKey] = processed_obj[randomIdKey];
|
||||||
}
|
} else if (processed_obj[baseIdKey])
|
||||||
else if (processed_obj[baseIdKey]) (processed_obj as any).id = processed_obj[baseIdKey];
|
(processed_obj as any).id = processed_obj[baseIdKey];
|
||||||
const group = processed_obj.group ?? '0';
|
const group = processed_obj.group ?? '0';
|
||||||
const priority = processed_obj.priority ? 1 : 0;
|
const priority = processed_obj.priority ? 1 : 0;
|
||||||
const sort = processed_obj.sort ?? '0';
|
const sort = processed_obj.sort ?? '0';
|
||||||
const updated = processed_obj.updated_on ?? processed_obj.created_on ?? new Date(0).toISOString();
|
const updated =
|
||||||
|
processed_obj.updated_on ??
|
||||||
|
processed_obj.created_on ??
|
||||||
|
new Date(0).toISOString();
|
||||||
const name = processed_obj.name ?? '';
|
const name = processed_obj.name ?? '';
|
||||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
(processed_obj as any).tmp_sort_1 =
|
||||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
`${group}_${priority}_${sort}_${updated}`;
|
||||||
if (specific_processor) processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
(processed_obj as any).tmp_sort_2 =
|
||||||
|
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||||
|
if (specific_processor)
|
||||||
|
processed_obj = await Promise.resolve(
|
||||||
|
specific_processor(processed_obj)
|
||||||
|
);
|
||||||
processed_obj_li.push(processed_obj as T);
|
processed_obj_li.push(processed_obj as T);
|
||||||
}
|
}
|
||||||
return processed_obj_li;
|
return processed_obj_li;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function process_ae_obj__event_presenter_props({ obj_li, log_lvl = 0 }: { obj_li: any[]; log_lvl?: number; }) {
|
export async function process_ae_obj__event_presenter_props({
|
||||||
return _process_generic_props({ obj_li, obj_type: 'event_presenter', log_lvl, specific_processor: (obj) => {
|
obj_li,
|
||||||
// String-Only ID Vision: Ensure linking IDs are the string versions for indexing
|
log_lvl = 0
|
||||||
if (obj.event_presenter_id_random) obj.event_presenter_id = obj.event_presenter_id_random;
|
}: {
|
||||||
if (obj.event_presentation_id_random) obj.event_presentation_id = obj.event_presentation_id_random;
|
obj_li: any[];
|
||||||
if (obj.event_session_id_random) obj.event_session_id = obj.event_session_id_random;
|
log_lvl?: number;
|
||||||
if (obj.event_id_random) obj.event_id = obj.event_id_random;
|
}) {
|
||||||
return obj;
|
return _process_generic_props({
|
||||||
}});
|
obj_li,
|
||||||
|
obj_type: 'event_presenter',
|
||||||
|
log_lvl,
|
||||||
|
specific_processor: (obj) => {
|
||||||
|
// String-Only ID Vision: Ensure linking IDs are the string versions for indexing
|
||||||
|
if (obj.event_presenter_id_random)
|
||||||
|
obj.event_presenter_id = obj.event_presenter_id_random;
|
||||||
|
if (obj.event_presentation_id_random)
|
||||||
|
obj.event_presentation_id = obj.event_presentation_id_random;
|
||||||
|
if (obj.event_session_id_random)
|
||||||
|
obj.event_session_id = obj.event_session_id_random;
|
||||||
|
if (obj.event_id_random) obj.event_id = obj.event_id_random;
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,9 @@ export async function load_ae_obj_id__event_session({
|
|||||||
}): Promise<ae_EventSession | null> {
|
}): Promise<ae_EventSession | null> {
|
||||||
const start_time = performance.now();
|
const start_time = performance.now();
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`🔎 [Trace] load_ae_obj_id__event_session: START (id=${event_session_id}, try_cache=${try_cache})`);
|
console.log(
|
||||||
|
`🔎 [Trace] load_ae_obj_id__event_session: START (id=${event_session_id}, try_cache=${try_cache})`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hierarchy Enforcement: Pulling presenters requires pulling presentations first
|
// Hierarchy Enforcement: Pulling presenters requires pulling presentations first
|
||||||
@@ -56,65 +58,167 @@ export async function load_ae_obj_id__event_session({
|
|||||||
const cached = await db_events.session.get(event_session_id);
|
const cached = await db_events.session.get(event_session_id);
|
||||||
if (cached) {
|
if (cached) {
|
||||||
const elapsed = (performance.now() - start_time).toFixed(2);
|
const elapsed = (performance.now() - start_time).toFixed(2);
|
||||||
if (log_lvl) console.log(`✅ [Trace] load_ae_obj_id: CACHE HIT at ${elapsed}ms. Returning stale shell for id=${event_session_id}`);
|
if (log_lvl)
|
||||||
|
console.log(
|
||||||
|
`✅ [Trace] load_ae_obj_id: CACHE HIT at ${elapsed}ms. Returning stale shell for id=${event_session_id}`
|
||||||
|
);
|
||||||
|
|
||||||
// Background tasks: refresh parent and warm child caches (non-blocking)
|
// Background tasks: refresh parent and warm child caches (non-blocking)
|
||||||
_refresh_session_id_background({
|
_refresh_session_id_background({
|
||||||
api_cfg, event_session_id, view, try_cache,
|
api_cfg,
|
||||||
inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li,
|
event_session_id,
|
||||||
enabled, hidden, limit, offset, log_lvl: log_lvl > 1 ? log_lvl : 0
|
view,
|
||||||
|
try_cache,
|
||||||
|
inc_file_li,
|
||||||
|
inc_all_file_li,
|
||||||
|
inc_presentation_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
log_lvl: log_lvl > 1 ? log_lvl : 0
|
||||||
});
|
});
|
||||||
|
|
||||||
// In SWR mode, we fire child loads in background to warm IDB for the view's LiveQueries
|
// In SWR mode, we fire child loads in background to warm IDB for the view's LiveQueries
|
||||||
_handle_nested_loads(cached, { api_cfg, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache, log_lvl: 0 });
|
_handle_nested_loads(cached, {
|
||||||
|
api_cfg,
|
||||||
|
inc_file_li,
|
||||||
|
inc_all_file_li,
|
||||||
|
inc_presentation_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
try_cache,
|
||||||
|
log_lvl: 0
|
||||||
|
});
|
||||||
|
|
||||||
return cached; // Return immediately without awaiting nested loads
|
return cached; // Return immediately without awaiting nested loads
|
||||||
} else if (log_lvl) {
|
} else if (log_lvl) {
|
||||||
console.log(`⏳ [Trace] load_ae_obj_id: CACHE MISS at ${(performance.now() - start_time).toFixed(2)}ms for id=${event_session_id}`);
|
console.log(
|
||||||
|
`⏳ [Trace] load_ae_obj_id: CACHE MISS at ${(performance.now() - start_time).toFixed(2)}ms for id=${event_session_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (log_lvl) console.error(`❌ [Trace] load_ae_obj_id: Cache access error:`, e);
|
if (log_lvl)
|
||||||
|
console.error(
|
||||||
|
`❌ [Trace] load_ae_obj_id: Cache access error:`,
|
||||||
|
e
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. SLOW PATH: Wait for API
|
// 2. SLOW PATH: Wait for API
|
||||||
if (log_lvl) console.log(`🚀 [Trace] load_ae_obj_id: Proceeding to API path for id=${event_session_id}`);
|
if (log_lvl)
|
||||||
return await _refresh_session_id_background({ api_cfg, event_session_id, view, try_cache, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, log_lvl });
|
console.log(
|
||||||
|
`🚀 [Trace] load_ae_obj_id: Proceeding to API path for id=${event_session_id}`
|
||||||
|
);
|
||||||
|
return await _refresh_session_id_background({
|
||||||
|
api_cfg,
|
||||||
|
event_session_id,
|
||||||
|
view,
|
||||||
|
try_cache,
|
||||||
|
inc_file_li,
|
||||||
|
inc_all_file_li,
|
||||||
|
inc_presentation_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal background refresh for a single session
|
* Internal background refresh for a single session
|
||||||
*/
|
*/
|
||||||
async function _refresh_session_id_background({ api_cfg, event_session_id, view, try_cache, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, log_lvl }: any) {
|
async function _refresh_session_id_background({
|
||||||
|
api_cfg,
|
||||||
|
event_session_id,
|
||||||
|
view,
|
||||||
|
try_cache,
|
||||||
|
inc_file_li,
|
||||||
|
inc_all_file_li,
|
||||||
|
inc_presentation_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
log_lvl
|
||||||
|
}: any) {
|
||||||
const start_time = performance.now();
|
const start_time = performance.now();
|
||||||
if (typeof navigator !== 'undefined' && !navigator.onLine) return null;
|
if (typeof navigator !== 'undefined' && !navigator.onLine) return null;
|
||||||
try {
|
try {
|
||||||
if (log_lvl) console.log(`📡 [Trace] _refresh_session_id: API Fetching id=${event_session_id}`);
|
if (log_lvl)
|
||||||
const result = await api.get_ae_obj_v3({ api_cfg, obj_type: 'event_session', obj_id: event_session_id, view, log_lvl });
|
console.log(
|
||||||
|
`📡 [Trace] _refresh_session_id: API Fetching id=${event_session_id}`
|
||||||
|
);
|
||||||
|
const result = await api.get_ae_obj({
|
||||||
|
api_cfg,
|
||||||
|
obj_type: 'event_session',
|
||||||
|
obj_id: event_session_id,
|
||||||
|
view,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
const processed = await process_ae_obj__event_session_props({ obj_li: [result], log_lvl });
|
const processed = await process_ae_obj__event_session_props({
|
||||||
|
obj_li: [result],
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
const processed_obj = processed[0];
|
const processed_obj = processed[0];
|
||||||
const elapsed = (performance.now() - start_time).toFixed(2);
|
const elapsed = (performance.now() - start_time).toFixed(2);
|
||||||
|
|
||||||
if (log_lvl) console.log(`📦 [Trace] _refresh_session_id: Received from API at ${elapsed}ms (id=${processed_obj.id})`);
|
if (log_lvl)
|
||||||
|
console.log(
|
||||||
|
`📦 [Trace] _refresh_session_id: Received from API at ${elapsed}ms (id=${processed_obj.id})`
|
||||||
|
);
|
||||||
|
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'session', obj_li: [processed_obj], properties_to_save, log_lvl });
|
await db_save_ae_obj_li__ae_obj({
|
||||||
|
db_instance: db_events,
|
||||||
|
table_name: 'session',
|
||||||
|
obj_li: [processed_obj],
|
||||||
|
properties_to_save,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
// CRITICAL FIX (2026-02-26): Yield to microtask queue so Dexie liveQuery observers
|
// CRITICAL FIX (2026-02-26): Yield to microtask queue so Dexie liveQuery observers
|
||||||
// fire before we return. Without this, component-mounted liveQueries may subscribe
|
// fire before we return. Without this, component-mounted liveQueries may subscribe
|
||||||
// to IDB *before* the write completes, causing empty results on cold-start.
|
// to IDB *before* the write completes, causing empty results on cold-start.
|
||||||
await Promise.resolve();
|
await Promise.resolve();
|
||||||
if (log_lvl) console.log(`💾 [Trace] _refresh_session_id: Saved to IDB cache.`);
|
if (log_lvl)
|
||||||
|
console.log(
|
||||||
|
`💾 [Trace] _refresh_session_id: Saved to IDB cache.`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// CRITICAL FIX (2026-02-26): Preserve parent's try_cache value when loading nested data.
|
// CRITICAL FIX (2026-02-26): Preserve parent's try_cache value when loading nested data.
|
||||||
// Previously set to `false`, which meant presentations/presenters were fetched from API
|
// Previously set to `false`, which meant presentations/presenters were fetched from API
|
||||||
// but NEVER written to IndexedDB, causing "refresh twice" bug on cold-start.
|
// but NEVER written to IndexedDB, causing "refresh twice" bug on cold-start.
|
||||||
// Now nested loads inherit parent's caching behavior for deterministic first-render.
|
// Now nested loads inherit parent's caching behavior for deterministic first-render.
|
||||||
return await _handle_nested_loads(processed_obj, { api_cfg, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache, log_lvl });
|
return await _handle_nested_loads(processed_obj, {
|
||||||
|
api_cfg,
|
||||||
|
inc_file_li,
|
||||||
|
inc_all_file_li,
|
||||||
|
inc_presentation_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
try_cache,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (log_lvl) console.error(`❌ [Trace] _refresh_session_id: API error for id=${event_session_id}:`, e);
|
if (log_lvl)
|
||||||
|
console.error(
|
||||||
|
`❌ [Trace] _refresh_session_id: API error for id=${event_session_id}:`,
|
||||||
|
e
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -122,29 +226,65 @@ async function _refresh_session_id_background({ api_cfg, event_session_id, view,
|
|||||||
/**
|
/**
|
||||||
* Helper to handle nested collection loads for a session
|
* Helper to handle nested collection loads for a session
|
||||||
*/
|
*/
|
||||||
async function _handle_nested_loads(session_obj: any, { api_cfg, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache, log_lvl }: any) {
|
async function _handle_nested_loads(
|
||||||
|
session_obj: any,
|
||||||
|
{
|
||||||
|
api_cfg,
|
||||||
|
inc_file_li,
|
||||||
|
inc_all_file_li,
|
||||||
|
inc_presentation_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
try_cache,
|
||||||
|
log_lvl
|
||||||
|
}: any
|
||||||
|
) {
|
||||||
const start_time = performance.now();
|
const start_time = performance.now();
|
||||||
const current_session_id = session_obj.id || session_obj.event_session_id;
|
const current_session_id = session_obj.id || session_obj.event_session_id;
|
||||||
if (!current_session_id) return session_obj;
|
if (!current_session_id) return session_obj;
|
||||||
|
|
||||||
const tasks = [];
|
const tasks = [];
|
||||||
if (inc_file_li) {
|
if (inc_file_li) {
|
||||||
tasks.push(load_ae_obj_li__event_file({
|
tasks.push(
|
||||||
api_cfg, for_obj_type: 'event_session', for_obj_id: current_session_id,
|
load_ae_obj_li__event_file({
|
||||||
enabled, limit: 15, try_cache, log_lvl
|
api_cfg,
|
||||||
}).then(res => session_obj.event_file_li = res));
|
for_obj_type: 'event_session',
|
||||||
|
for_obj_id: current_session_id,
|
||||||
|
enabled,
|
||||||
|
limit: 15,
|
||||||
|
try_cache,
|
||||||
|
log_lvl
|
||||||
|
}).then((res) => (session_obj.event_file_li = res))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inc_presentation_li) {
|
if (inc_presentation_li) {
|
||||||
tasks.push(load_ae_obj_li__event_presentation({
|
tasks.push(
|
||||||
api_cfg, for_obj_type: 'event_session', for_obj_id: current_session_id,
|
load_ae_obj_li__event_presentation({
|
||||||
inc_file_li: inc_all_file_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache, log_lvl
|
api_cfg,
|
||||||
}).then(res => session_obj.event_presentation_li = res));
|
for_obj_type: 'event_session',
|
||||||
|
for_obj_id: current_session_id,
|
||||||
|
inc_file_li: inc_all_file_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
try_cache,
|
||||||
|
log_lvl
|
||||||
|
}).then((res) => (session_obj.event_presentation_li = res))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tasks.length > 0) {
|
if (tasks.length > 0) {
|
||||||
await Promise.all(tasks);
|
await Promise.all(tasks);
|
||||||
if (log_lvl) console.log(`🔗 [Trace] _handle_nested_loads: Finished child collections in ${(performance.now() - start_time).toFixed(2)}ms`);
|
if (log_lvl)
|
||||||
|
console.log(
|
||||||
|
`🔗 [Trace] _handle_nested_loads: Finished child collections in ${(performance.now() - start_time).toFixed(2)}ms`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return session_obj;
|
return session_obj;
|
||||||
}
|
}
|
||||||
@@ -191,7 +331,9 @@ export async function load_ae_obj_li__event_session({
|
|||||||
}): Promise<ae_EventSession[]> {
|
}): Promise<ae_EventSession[]> {
|
||||||
const start_time = performance.now();
|
const start_time = performance.now();
|
||||||
if (log_lvl) {
|
if (log_lvl) {
|
||||||
console.log(`🔎 [Trace] load_ae_obj_li__event_session: START (for=${for_obj_type}:${for_obj_id}, try_cache=${try_cache})`);
|
console.log(
|
||||||
|
`🔎 [Trace] load_ae_obj_li__event_session: START (for=${for_obj_type}:${for_obj_id}, try_cache=${try_cache})`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hierarchy Enforcement: Pulling presenters requires pulling presentations first
|
// Hierarchy Enforcement: Pulling presenters requires pulling presentations first
|
||||||
@@ -201,226 +343,409 @@ export async function load_ae_obj_li__event_session({
|
|||||||
try {
|
try {
|
||||||
// Robust lookup logic
|
// Robust lookup logic
|
||||||
let query;
|
let query;
|
||||||
if (for_obj_type === 'event_location') query = db_events.session.where('event_location_id').equals(for_obj_id);
|
if (for_obj_type === 'event_location')
|
||||||
else if (for_obj_type === 'event') query = db_events.session.where('event_id').equals(for_obj_id);
|
query = db_events.session
|
||||||
|
.where('event_location_id')
|
||||||
|
.equals(for_obj_id);
|
||||||
|
else if (for_obj_type === 'event')
|
||||||
|
query = db_events.session.where('event_id').equals(for_obj_id);
|
||||||
else query = db_events.session.where('for_id').equals(for_obj_id);
|
else query = db_events.session.where('for_id').equals(for_obj_id);
|
||||||
|
|
||||||
const cached_li = await query.toArray();
|
const cached_li = await query.toArray();
|
||||||
|
|
||||||
if (cached_li && cached_li.length > 0) {
|
if (cached_li && cached_li.length > 0) {
|
||||||
const elapsed = (performance.now() - start_time).toFixed(2);
|
const elapsed = (performance.now() - start_time).toFixed(2);
|
||||||
if (log_lvl) console.log(`✅ [Trace] load_ae_obj_li: CACHE HIT at ${elapsed}ms (${cached_li.length} items).`);
|
if (log_lvl)
|
||||||
|
console.log(
|
||||||
|
`✅ [Trace] load_ae_obj_li: CACHE HIT at ${elapsed}ms (${cached_li.length} items).`
|
||||||
|
);
|
||||||
|
|
||||||
// Background refresh (non-blocking)
|
// Background refresh (non-blocking)
|
||||||
_refresh_session_li_background({
|
_refresh_session_li_background({
|
||||||
api_cfg, for_obj_type, for_obj_id, view,
|
api_cfg,
|
||||||
|
for_obj_type,
|
||||||
|
for_obj_id,
|
||||||
|
view,
|
||||||
// Optimization: Disable nested loads for list members to prevent request storms
|
// Optimization: Disable nested loads for list members to prevent request storms
|
||||||
inc_file_li: false, inc_all_file_li: false, inc_presentation_li: false, inc_presenter_li: false,
|
inc_file_li: false,
|
||||||
enabled, hidden, limit, offset, order_by_li, try_cache,
|
inc_all_file_li: false,
|
||||||
|
inc_presentation_li: false,
|
||||||
|
inc_presenter_li: false,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
order_by_li,
|
||||||
|
try_cache,
|
||||||
log_lvl: log_lvl > 1 ? log_lvl : 0
|
log_lvl: log_lvl > 1 ? log_lvl : 0
|
||||||
});
|
});
|
||||||
|
|
||||||
return cached_li;
|
return cached_li;
|
||||||
} else if (log_lvl) {
|
} else if (log_lvl) {
|
||||||
console.log(`⏳ [Trace] load_ae_obj_li: CACHE MISS at ${(performance.now() - start_time).toFixed(2)}ms for type=${for_obj_type} id=${for_obj_id}`);
|
console.log(
|
||||||
|
`⏳ [Trace] load_ae_obj_li: CACHE MISS at ${(performance.now() - start_time).toFixed(2)}ms for type=${for_obj_type} id=${for_obj_id}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (log_lvl) console.error(`❌ [Trace] load_ae_obj_li: Cache access error:`, e);
|
if (log_lvl)
|
||||||
|
console.error(
|
||||||
|
`❌ [Trace] load_ae_obj_li: Cache access error:`,
|
||||||
|
e
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return await _refresh_session_li_background({ api_cfg, for_obj_type, for_obj_id, view, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, order_by_li, try_cache, log_lvl });
|
return await _refresh_session_li_background({
|
||||||
|
api_cfg,
|
||||||
|
for_obj_type,
|
||||||
|
for_obj_id,
|
||||||
|
view,
|
||||||
|
inc_file_li,
|
||||||
|
inc_all_file_li,
|
||||||
|
inc_presentation_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
order_by_li,
|
||||||
|
try_cache,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function _refresh_session_li_background({ api_cfg, for_obj_type, for_obj_id, view, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, order_by_li, try_cache, log_lvl }: any) {
|
async function _refresh_session_li_background({
|
||||||
|
api_cfg,
|
||||||
|
for_obj_type,
|
||||||
|
for_obj_id,
|
||||||
|
view,
|
||||||
|
inc_file_li,
|
||||||
|
inc_all_file_li,
|
||||||
|
inc_presentation_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
order_by_li,
|
||||||
|
try_cache,
|
||||||
|
log_lvl
|
||||||
|
}: any) {
|
||||||
const start_time = performance.now();
|
const start_time = performance.now();
|
||||||
if (typeof navigator !== 'undefined' && !navigator.onLine) return [];
|
if (typeof navigator !== 'undefined' && !navigator.onLine) return [];
|
||||||
try {
|
try {
|
||||||
if (log_lvl) console.log(`📡 [Trace] _refresh_session_li: API Fetching for=${for_obj_type}:${for_obj_id} (view=${view})`);
|
if (log_lvl)
|
||||||
const result_li = await api.get_ae_obj_li_v3({ api_cfg, obj_type: 'event_session', for_obj_type, for_obj_id, view, enabled, hidden, limit, offset, order_by_li, log_lvl });
|
console.log(
|
||||||
|
`📡 [Trace] _refresh_session_li: API Fetching for=${for_obj_type}:${for_obj_id} (view=${view})`
|
||||||
|
);
|
||||||
|
const result_li = await api.get_ae_obj_li({
|
||||||
|
api_cfg,
|
||||||
|
obj_type: 'event_session',
|
||||||
|
for_obj_type,
|
||||||
|
for_obj_id,
|
||||||
|
view,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
order_by_li,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
|
|
||||||
if (result_li) {
|
if (result_li) {
|
||||||
const processed = await process_ae_obj__event_session_props({ obj_li: result_li, log_lvl });
|
const processed = await process_ae_obj__event_session_props({
|
||||||
|
obj_li: result_li,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
const elapsed = (performance.now() - start_time).toFixed(2);
|
const elapsed = (performance.now() - start_time).toFixed(2);
|
||||||
if (log_lvl) console.log(`📦 [Trace] _refresh_session_li: Received ${processed.length} items from API at ${elapsed}ms.`);
|
if (log_lvl)
|
||||||
|
console.log(
|
||||||
|
`📦 [Trace] _refresh_session_li: Received ${processed.length} items from API at ${elapsed}ms.`
|
||||||
|
);
|
||||||
|
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'session', obj_li: processed, properties_to_save, log_lvl });
|
await db_save_ae_obj_li__ae_obj({
|
||||||
if (log_lvl) console.log(`💾 [Trace] _refresh_session_li: Saved to IDB cache.`);
|
db_instance: db_events,
|
||||||
|
table_name: 'session',
|
||||||
|
obj_li: processed,
|
||||||
|
properties_to_save,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
|
if (log_lvl)
|
||||||
|
console.log(
|
||||||
|
`💾 [Trace] _refresh_session_li: Saved to IDB cache.`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fire nested loads for each session only if explicitly requested (usually only for single objects)
|
// Fire nested loads for each session only if explicitly requested (usually only for single objects)
|
||||||
if (inc_file_li || inc_presentation_li) {
|
if (inc_file_li || inc_presentation_li) {
|
||||||
processed.forEach(s => {
|
processed.forEach((s) => {
|
||||||
_handle_nested_loads(s, { api_cfg, inc_file_li, inc_all_file_li, inc_presentation_li, inc_presenter_li, enabled, hidden, limit, offset, try_cache, log_lvl: 0 });
|
_handle_nested_loads(s, {
|
||||||
|
api_cfg,
|
||||||
|
inc_file_li,
|
||||||
|
inc_all_file_li,
|
||||||
|
inc_presentation_li,
|
||||||
|
inc_presenter_li,
|
||||||
|
enabled,
|
||||||
|
hidden,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
try_cache,
|
||||||
|
log_lvl: 0
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return processed;
|
return processed;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (log_lvl) console.error(`❌ [Trace] _refresh_session_li: API error:`, e);
|
if (log_lvl)
|
||||||
|
console.error(`❌ [Trace] _refresh_session_li: API error:`, e);
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function create_ae_obj__event_session({
|
export async function create_ae_obj__event_session({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
event_id,
|
event_id,
|
||||||
data_kv,
|
data_kv,
|
||||||
try_cache = true,
|
try_cache = true,
|
||||||
log_lvl = 0
|
log_lvl = 0
|
||||||
}: {
|
}: {
|
||||||
api_cfg: any;
|
api_cfg: any;
|
||||||
event_id?: string;
|
event_id?: string;
|
||||||
data_kv: key_val;
|
data_kv: key_val;
|
||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventSession | null> {
|
}): Promise<ae_EventSession | null> {
|
||||||
if (!event_id) event_id = get(slct).event_id;
|
if (!event_id) event_id = get(slct).event_id;
|
||||||
if (!event_id) {
|
if (!event_id) {
|
||||||
console.error('create_ae_obj__event_session: event_id is required');
|
console.error('create_ae_obj__event_session: event_id is required');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const result = await api.create_nested_obj_v3({
|
const result = await api.create_nested_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
for_obj_type: 'event',
|
for_obj_type: 'event',
|
||||||
for_obj_id: event_id,
|
for_obj_id: event_id,
|
||||||
obj_type: 'event_session',
|
obj_type: 'event_session',
|
||||||
fields: { ...data_kv },
|
fields: { ...data_kv },
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
if (result) {
|
if (result) {
|
||||||
const processed = await process_ae_obj__event_session_props({ obj_li: [result], log_lvl });
|
const processed = await process_ae_obj__event_session_props({
|
||||||
const processed_obj = processed[0];
|
obj_li: [result],
|
||||||
if (try_cache) {
|
log_lvl
|
||||||
await db_save_ae_obj_li__ae_obj({
|
});
|
||||||
db_instance: db_events,
|
const processed_obj = processed[0];
|
||||||
table_name: 'session',
|
if (try_cache) {
|
||||||
obj_li: [processed_obj],
|
await db_save_ae_obj_li__ae_obj({
|
||||||
properties_to_save,
|
db_instance: db_events,
|
||||||
log_lvl
|
table_name: 'session',
|
||||||
});
|
obj_li: [processed_obj],
|
||||||
}
|
properties_to_save,
|
||||||
return processed_obj;
|
log_lvl
|
||||||
}
|
});
|
||||||
return null;
|
}
|
||||||
|
return processed_obj;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function delete_ae_obj_id__event_session({
|
export async function delete_ae_obj_id__event_session({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
event_id,
|
event_id,
|
||||||
event_session_id,
|
event_session_id,
|
||||||
method = 'delete',
|
method = 'delete',
|
||||||
try_cache = true,
|
try_cache = true,
|
||||||
log_lvl = 0
|
log_lvl = 0
|
||||||
}: {
|
}: {
|
||||||
api_cfg: any;
|
api_cfg: any;
|
||||||
event_id?: string;
|
event_id?: string;
|
||||||
event_session_id: string;
|
event_session_id: string;
|
||||||
method?: 'delete' | 'soft_delete' | 'disable' | 'hide';
|
method?: 'delete' | 'soft_delete' | 'disable' | 'hide';
|
||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}) {
|
}) {
|
||||||
if (!event_id) event_id = get(slct).event_id;
|
if (!event_id) event_id = get(slct).event_id;
|
||||||
if (!event_id) {
|
if (!event_id) {
|
||||||
console.error('delete_ae_obj_id__event_session: event_id is required');
|
console.error('delete_ae_obj_id__event_session: event_id is required');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const result = await api.delete_nested_ae_obj_v3({
|
const result = await api.delete_nested_ae_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
for_obj_type: 'event',
|
for_obj_type: 'event',
|
||||||
for_obj_id: event_id,
|
for_obj_id: event_id,
|
||||||
obj_type: 'event_session',
|
obj_type: 'event_session',
|
||||||
obj_id: event_session_id,
|
obj_id: event_session_id,
|
||||||
method,
|
method,
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
if (try_cache) await db_events.session.delete(event_session_id);
|
if (try_cache) await db_events.session.delete(event_session_id);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function update_ae_obj__event_session({
|
export async function update_ae_obj__event_session({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
event_id,
|
event_id,
|
||||||
event_session_id,
|
event_session_id,
|
||||||
data_kv,
|
data_kv,
|
||||||
try_cache = true,
|
try_cache = true,
|
||||||
log_lvl = 0
|
log_lvl = 0
|
||||||
}: {
|
}: {
|
||||||
api_cfg: any;
|
api_cfg: any;
|
||||||
event_id?: string;
|
event_id?: string;
|
||||||
event_session_id: string;
|
event_session_id: string;
|
||||||
data_kv: key_val;
|
data_kv: key_val;
|
||||||
try_cache?: boolean;
|
try_cache?: boolean;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventSession | null> {
|
}): Promise<ae_EventSession | null> {
|
||||||
if (!event_id) event_id = get(slct).event_id;
|
if (!event_id) event_id = get(slct).event_id;
|
||||||
if (!event_id) {
|
if (!event_id) {
|
||||||
console.error('update_ae_obj__event_session: event_id is required');
|
console.error('update_ae_obj__event_session: event_id is required');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const result = await api.update_nested_obj_v3({
|
const result = await api.update_nested_obj({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
for_obj_type: 'event',
|
for_obj_type: 'event',
|
||||||
for_obj_id: event_id,
|
for_obj_id: event_id,
|
||||||
obj_type: 'event_session',
|
obj_type: 'event_session',
|
||||||
obj_id: event_session_id,
|
obj_id: event_session_id,
|
||||||
fields: data_kv,
|
fields: data_kv,
|
||||||
log_lvl
|
log_lvl
|
||||||
});
|
});
|
||||||
if (result) {
|
if (result) {
|
||||||
const processed = await process_ae_obj__event_session_props({ obj_li: [result], log_lvl });
|
const processed = await process_ae_obj__event_session_props({
|
||||||
const processed_obj = processed[0];
|
obj_li: [result],
|
||||||
if (try_cache) {
|
log_lvl
|
||||||
await db_save_ae_obj_li__ae_obj({
|
});
|
||||||
db_instance: db_events,
|
const processed_obj = processed[0];
|
||||||
table_name: 'session',
|
if (try_cache) {
|
||||||
obj_li: [processed_obj],
|
await db_save_ae_obj_li__ae_obj({
|
||||||
properties_to_save,
|
db_instance: db_events,
|
||||||
log_lvl
|
table_name: 'session',
|
||||||
});
|
obj_li: [processed_obj],
|
||||||
}
|
properties_to_save,
|
||||||
return processed_obj;
|
log_lvl
|
||||||
}
|
});
|
||||||
return null;
|
}
|
||||||
|
return processed_obj;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function search__event_session({
|
export async function search__event_session({
|
||||||
api_cfg, event_id, fulltext_search_qry_str = '', ft_presenter_search_qry_str = '', like_search_qry_str = '', like_presentation_search_qry_str = '', like_presenter_search_qry_str = '', like_poc_name_qry_str = '', location_name = null, qry_files = null, qry_poc_agree = null, qry_poc_kv_json = null, qry_start_datetime = null, enabled = 'enabled', hidden = 'not_hidden', view = 'default', limit = 50, offset = 0, order_by_li = [{ sort: 'ASC' }, { start_datetime: 'ASC' }, { name: 'ASC' }], try_cache = true, log_lvl = 0
|
api_cfg,
|
||||||
|
event_id,
|
||||||
|
fulltext_search_qry_str = '',
|
||||||
|
ft_presenter_search_qry_str = '',
|
||||||
|
like_search_qry_str = '',
|
||||||
|
like_presentation_search_qry_str = '',
|
||||||
|
like_presenter_search_qry_str = '',
|
||||||
|
like_poc_name_qry_str = '',
|
||||||
|
location_name = null,
|
||||||
|
qry_files = null,
|
||||||
|
qry_poc_agree = null,
|
||||||
|
qry_poc_kv_json = null,
|
||||||
|
qry_start_datetime = null,
|
||||||
|
enabled = 'enabled',
|
||||||
|
hidden = 'not_hidden',
|
||||||
|
view = 'default',
|
||||||
|
limit = 50,
|
||||||
|
offset = 0,
|
||||||
|
order_by_li = [{ sort: 'ASC' }, { start_datetime: 'ASC' }, { name: 'ASC' }],
|
||||||
|
try_cache = true,
|
||||||
|
log_lvl = 0
|
||||||
}: {
|
}: {
|
||||||
api_cfg: any; event_id: string; fulltext_search_qry_str?: string; ft_presenter_search_qry_str?: string | null; like_search_qry_str?: string; like_presentation_search_qry_str?: string; like_presenter_search_qry_str?: string; like_poc_name_qry_str?: string; location_name?: null | string; qry_files?: null | boolean; qry_poc_agree?: null | boolean; qry_poc_kv_json?: null | boolean; qry_start_datetime?: string | null; enabled?: 'enabled' | 'all' | 'not_enabled'; hidden?: 'hidden' | 'all' | 'not_hidden'; view?: string; limit?: number; offset?: number; order_by_li?: any; try_cache?: boolean; log_lvl?: number;
|
api_cfg: any;
|
||||||
|
event_id: string;
|
||||||
|
fulltext_search_qry_str?: string;
|
||||||
|
ft_presenter_search_qry_str?: string | null;
|
||||||
|
like_search_qry_str?: string;
|
||||||
|
like_presentation_search_qry_str?: string;
|
||||||
|
like_presenter_search_qry_str?: string;
|
||||||
|
like_poc_name_qry_str?: string;
|
||||||
|
location_name?: null | string;
|
||||||
|
qry_files?: null | boolean;
|
||||||
|
qry_poc_agree?: null | boolean;
|
||||||
|
qry_poc_kv_json?: null | boolean;
|
||||||
|
qry_start_datetime?: string | null;
|
||||||
|
enabled?: 'enabled' | 'all' | 'not_enabled';
|
||||||
|
hidden?: 'hidden' | 'all' | 'not_hidden';
|
||||||
|
view?: string;
|
||||||
|
limit?: number;
|
||||||
|
offset?: number;
|
||||||
|
order_by_li?: any;
|
||||||
|
try_cache?: boolean;
|
||||||
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventSession[]> {
|
}): Promise<ae_EventSession[]> {
|
||||||
const search_query: any = { q: '', and: [{ field: 'event_id', op: 'eq', value: event_id }] };
|
const search_query: any = {
|
||||||
|
q: '',
|
||||||
|
and: [{ field: 'event_id', op: 'eq', value: event_id }]
|
||||||
|
};
|
||||||
if (fulltext_search_qry_str || ft_presenter_search_qry_str) {
|
if (fulltext_search_qry_str || ft_presenter_search_qry_str) {
|
||||||
const ft: any = {};
|
const ft: any = {};
|
||||||
if (fulltext_search_qry_str && fulltext_search_qry_str.length > 2) ft['default_qry_str'] = fulltext_search_qry_str;
|
if (fulltext_search_qry_str && fulltext_search_qry_str.length > 2)
|
||||||
if (ft_presenter_search_qry_str && ft_presenter_search_qry_str.length > 2) ft['event_presenter_li_qry_str'] = ft_presenter_search_qry_str;
|
ft['default_qry_str'] = fulltext_search_qry_str;
|
||||||
|
if (
|
||||||
|
ft_presenter_search_qry_str &&
|
||||||
|
ft_presenter_search_qry_str.length > 2
|
||||||
|
)
|
||||||
|
ft['event_presenter_li_qry_str'] = ft_presenter_search_qry_str;
|
||||||
if (Object.keys(ft).length) search_query.params = { ft_qry: ft };
|
if (Object.keys(ft).length) search_query.params = { ft_qry: ft };
|
||||||
}
|
}
|
||||||
if (enabled === 'enabled') search_query.and.push({ field: 'enable', op: 'eq', value: 1 });
|
if (enabled === 'enabled')
|
||||||
else if (enabled === 'not_enabled') search_query.and.push({ field: 'enable', op: 'eq', value: 0 });
|
search_query.and.push({ field: 'enable', op: 'eq', value: 1 });
|
||||||
if (hidden === 'hidden') search_query.and.push({ field: 'hide', op: 'eq', value: 1 });
|
else if (enabled === 'not_enabled')
|
||||||
else if (hidden === 'not_hidden') search_query.and.push({ field: 'hide', op: 'eq', value: 0 });
|
search_query.and.push({ field: 'enable', op: 'eq', value: 0 });
|
||||||
|
if (hidden === 'hidden')
|
||||||
|
search_query.and.push({ field: 'hide', op: 'eq', value: 1 });
|
||||||
|
else if (hidden === 'not_hidden')
|
||||||
|
search_query.and.push({ field: 'hide', op: 'eq', value: 0 });
|
||||||
|
|
||||||
if (location_name) {
|
if (location_name) {
|
||||||
search_query.and.push({ field: 'event_location_name', op: 'eq', value: location_name });
|
search_query.and.push({
|
||||||
|
field: 'event_location_name',
|
||||||
|
op: 'eq',
|
||||||
|
value: location_name
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const result_li = await api.search_ae_obj_v3({ api_cfg, obj_type: 'event_session', search_query, order_by_li, view, limit, offset, log_lvl });
|
const result_li = await api.search_ae_obj({
|
||||||
|
api_cfg,
|
||||||
|
obj_type: 'event_session',
|
||||||
|
search_query,
|
||||||
|
order_by_li,
|
||||||
|
view,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
|
|
||||||
// Handle V3 API envelope
|
// Handle V3 API envelope
|
||||||
let valid_result_li: ae_EventSession[] = [];
|
let valid_result_li: ae_EventSession[] = [];
|
||||||
if (Array.isArray(result_li)) {
|
if (Array.isArray(result_li)) {
|
||||||
valid_result_li = result_li;
|
valid_result_li = result_li;
|
||||||
} else if (result_li && typeof result_li === 'object' && Array.isArray((result_li as any).data)) {
|
} else if (
|
||||||
|
result_li &&
|
||||||
|
typeof result_li === 'object' &&
|
||||||
|
Array.isArray((result_li as any).data)
|
||||||
|
) {
|
||||||
valid_result_li = (result_li as any).data;
|
valid_result_li = (result_li as any).data;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (valid_result_li && valid_result_li.length > 0) {
|
if (valid_result_li && valid_result_li.length > 0) {
|
||||||
const processed = await process_ae_obj__event_session_props({ obj_li: valid_result_li, log_lvl });
|
const processed = await process_ae_obj__event_session_props({
|
||||||
|
obj_li: valid_result_li,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
if (try_cache) {
|
if (try_cache) {
|
||||||
await db_save_ae_obj_li__ae_obj({ db_instance: db_events, table_name: 'session', obj_li: processed, properties_to_save, log_lvl });
|
await db_save_ae_obj_li__ae_obj({
|
||||||
|
db_instance: db_events,
|
||||||
|
table_name: 'session',
|
||||||
|
obj_li: processed,
|
||||||
|
properties_to_save,
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return processed;
|
return processed;
|
||||||
}
|
}
|
||||||
@@ -429,18 +754,103 @@ export async function search__event_session({
|
|||||||
|
|
||||||
export const qry__event_session = search__event_session;
|
export const qry__event_session = search__event_session;
|
||||||
|
|
||||||
export async function email_sign_in__event_session({ api_cfg, to_email, to_name, base_url, person_id, person_passcode, event_id, event_session_id, session_name }: { api_cfg: any; to_email: string; to_name: string; base_url: string; person_id: string; person_passcode: string; event_id: string; event_session_id: string; session_name: string; }) {
|
export async function email_sign_in__event_session({
|
||||||
|
api_cfg,
|
||||||
|
to_email,
|
||||||
|
to_name,
|
||||||
|
base_url,
|
||||||
|
person_id,
|
||||||
|
person_passcode,
|
||||||
|
event_id,
|
||||||
|
event_session_id,
|
||||||
|
session_name
|
||||||
|
}: {
|
||||||
|
api_cfg: any;
|
||||||
|
to_email: string;
|
||||||
|
to_name: string;
|
||||||
|
base_url: string;
|
||||||
|
person_id: string;
|
||||||
|
person_passcode: string;
|
||||||
|
event_id: string;
|
||||||
|
event_session_id: string;
|
||||||
|
session_name: string;
|
||||||
|
}) {
|
||||||
const subject = `Pres Mgmt Hub Sign In Link for ${session_name}`;
|
const subject = `Pres Mgmt Hub Sign In Link for ${session_name}`;
|
||||||
const sign_in_url = encodeURI(`${base_url}/events/${event_id}/session/${event_session_id}?person_id=${person_id}&person_pass=${person_passcode}`);
|
const sign_in_url = encodeURI(
|
||||||
|
`${base_url}/events/${event_id}/session/${event_session_id}?person_id=${person_id}&person_pass=${person_passcode}`
|
||||||
|
);
|
||||||
const body_html = `<div>${to_name},<p>Your sign-in link for ${session_name}: <a href="${sign_in_url}">${sign_in_url}</a></p></div>`;
|
const body_html = `<div>${to_name},<p>Your sign-in link for ${session_name}: <a href="${sign_in_url}">${sign_in_url}</a></p></div>`;
|
||||||
return await api.send_email({ api_cfg, from_email: 'noreply+presmgmt@oneskyit.com', from_name: 'Aether Pres Mgmt', to_email, subject, body_html });
|
return await api.send_email({
|
||||||
|
api_cfg,
|
||||||
|
from_email: 'noreply+presmgmt@oneskyit.com',
|
||||||
|
from_name: 'Aether Pres Mgmt',
|
||||||
|
to_email,
|
||||||
|
subject,
|
||||||
|
body_html
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export const properties_to_save = [
|
export const properties_to_save = [
|
||||||
'id', 'event_session_id', 'event_session_id_random', 'external_id', 'code', 'for_type', 'for_id', 'for_id_random', 'type_code', 'event_id', 'event_location_id', 'poc_person_id', 'poc_agree', 'poc_kv_json', 'name', 'description', 'start_datetime', 'end_datetime', 'passcode', 'hide_event_launcher', 'alert', 'alert_msg', 'data_json', 'ux_mode', 'enable', 'hide', 'priority', 'sort', 'group', 'notes', 'created_on', 'updated_on', 'tmp_sort_1', 'tmp_sort_2', 'file_count', 'file_count_all', 'internal_use_count', 'event_file_id_li_json', 'poc_person_given_name', 'poc_person_family_name', 'poc_person_full_name', 'poc_person_primary_email', 'poc_person_passcode', 'event_name', 'event_location_code', 'event_location_name', 'event_presentation_li'
|
'id',
|
||||||
|
'event_session_id',
|
||||||
|
'event_session_id_random',
|
||||||
|
'external_id',
|
||||||
|
'code',
|
||||||
|
'for_type',
|
||||||
|
'for_id',
|
||||||
|
'for_id_random',
|
||||||
|
'type_code',
|
||||||
|
'event_id',
|
||||||
|
'event_location_id',
|
||||||
|
'poc_person_id',
|
||||||
|
'poc_agree',
|
||||||
|
'poc_kv_json',
|
||||||
|
'name',
|
||||||
|
'description',
|
||||||
|
'start_datetime',
|
||||||
|
'end_datetime',
|
||||||
|
'passcode',
|
||||||
|
'hide_event_launcher',
|
||||||
|
'alert',
|
||||||
|
'alert_msg',
|
||||||
|
'data_json',
|
||||||
|
'ux_mode',
|
||||||
|
'enable',
|
||||||
|
'hide',
|
||||||
|
'priority',
|
||||||
|
'sort',
|
||||||
|
'group',
|
||||||
|
'notes',
|
||||||
|
'created_on',
|
||||||
|
'updated_on',
|
||||||
|
'tmp_sort_1',
|
||||||
|
'tmp_sort_2',
|
||||||
|
'file_count',
|
||||||
|
'file_count_all',
|
||||||
|
'internal_use_count',
|
||||||
|
'event_file_id_li_json',
|
||||||
|
'poc_person_given_name',
|
||||||
|
'poc_person_family_name',
|
||||||
|
'poc_person_full_name',
|
||||||
|
'poc_person_primary_email',
|
||||||
|
'poc_person_passcode',
|
||||||
|
'event_name',
|
||||||
|
'event_location_code',
|
||||||
|
'event_location_name',
|
||||||
|
'event_presentation_li'
|
||||||
];
|
];
|
||||||
|
|
||||||
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[]> {
|
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 (!obj_li || obj_li.length === 0) return [];
|
if (!obj_li || obj_li.length === 0) return [];
|
||||||
const processed_obj_li: T[] = [];
|
const processed_obj_li: T[] = [];
|
||||||
for (const original_obj of obj_li) {
|
for (const original_obj of obj_li) {
|
||||||
@@ -456,22 +866,40 @@ async function _process_generic_props<T extends Record<string, any>>({ obj_li, o
|
|||||||
if (processed_obj[randomIdKey]) {
|
if (processed_obj[randomIdKey]) {
|
||||||
(processed_obj as any).id = processed_obj[randomIdKey];
|
(processed_obj as any).id = processed_obj[randomIdKey];
|
||||||
(processed_obj as any)[baseIdKey] = processed_obj[randomIdKey];
|
(processed_obj as any)[baseIdKey] = processed_obj[randomIdKey];
|
||||||
}
|
} else if (processed_obj[baseIdKey])
|
||||||
else if (processed_obj[baseIdKey]) (processed_obj as any).id = processed_obj[baseIdKey];
|
(processed_obj as any).id = processed_obj[baseIdKey];
|
||||||
|
|
||||||
const group = processed_obj.group ?? '0';
|
const group = processed_obj.group ?? '0';
|
||||||
const priority = processed_obj.priority ? 1 : 0;
|
const priority = processed_obj.priority ? 1 : 0;
|
||||||
const sort = processed_obj.sort ?? '0';
|
const sort = processed_obj.sort ?? '0';
|
||||||
const updated = processed_obj.updated_on ?? processed_obj.created_on ?? new Date(0).toISOString();
|
const updated =
|
||||||
|
processed_obj.updated_on ??
|
||||||
|
processed_obj.created_on ??
|
||||||
|
new Date(0).toISOString();
|
||||||
const name = processed_obj.name ?? '';
|
const name = processed_obj.name ?? '';
|
||||||
(processed_obj as any).tmp_sort_1 = `${group}_${priority}_${sort}_${updated}`;
|
(processed_obj as any).tmp_sort_1 =
|
||||||
(processed_obj as any).tmp_sort_2 = `${group}_${priority}_${sort}_${name}_${updated}`;
|
`${group}_${priority}_${sort}_${updated}`;
|
||||||
if (specific_processor) processed_obj = await Promise.resolve(specific_processor(processed_obj));
|
(processed_obj as any).tmp_sort_2 =
|
||||||
|
`${group}_${priority}_${sort}_${name}_${updated}`;
|
||||||
|
if (specific_processor)
|
||||||
|
processed_obj = await Promise.resolve(
|
||||||
|
specific_processor(processed_obj)
|
||||||
|
);
|
||||||
processed_obj_li.push(processed_obj as T);
|
processed_obj_li.push(processed_obj as T);
|
||||||
}
|
}
|
||||||
return processed_obj_li;
|
return processed_obj_li;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function process_ae_obj__event_session_props({ obj_li, log_lvl = 0 }: { obj_li: any[]; log_lvl?: number; }) {
|
export async function process_ae_obj__event_session_props({
|
||||||
return _process_generic_props({ obj_li, obj_type: 'event_session', log_lvl });
|
obj_li,
|
||||||
|
log_lvl = 0
|
||||||
|
}: {
|
||||||
|
obj_li: any[];
|
||||||
|
log_lvl?: number;
|
||||||
|
}) {
|
||||||
|
return _process_generic_props({
|
||||||
|
obj_li,
|
||||||
|
obj_type: 'event_session',
|
||||||
|
log_lvl
|
||||||
|
});
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,7 @@ export async function load_ae_obj_li__event_track({
|
|||||||
view?: string;
|
view?: string;
|
||||||
log_lvl?: number;
|
log_lvl?: number;
|
||||||
}): Promise<ae_EventTrack[]> {
|
}): Promise<ae_EventTrack[]> {
|
||||||
return await api.get_ae_obj_li_v3({
|
return await api.get_ae_obj_li({
|
||||||
api_cfg,
|
api_cfg,
|
||||||
obj_type: 'event_track',
|
obj_type: 'event_track',
|
||||||
for_obj_type: 'event',
|
for_obj_type: 'event',
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user