A working Data Store element/component again!!! Saving!
This commit is contained in:
@@ -4,12 +4,12 @@ import { api } from '$lib/api/api';
|
||||
import type { ae_DataStore } from '$lib/types/ae_types';
|
||||
|
||||
/**
|
||||
* Fetches a data_store object by its unique code.
|
||||
* Fetches a data_store object by its unique code (V3).
|
||||
*
|
||||
* @param api_cfg - The API configuration object.
|
||||
* @param code - The code of the data store to fetch.
|
||||
* @param data_type - The expected data type ('text', 'json', 'html', 'md', 'sql').
|
||||
* @param save_idb - Whether to save the fetched data to localStorage.
|
||||
* @param save_idb - Whether to save the fetched data to IndexedDB (Dexie).
|
||||
* @param timeout - The request timeout in milliseconds.
|
||||
* @param log_lvl - The logging level.
|
||||
* @returns The data from the data store (e.g., text content or JSON object).
|
||||
@@ -34,60 +34,52 @@ export async function load_ae_obj_by_code__data_store({
|
||||
}
|
||||
|
||||
if (!code) {
|
||||
console.log(`*ae_func* No code provided!`);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!api_cfg.account_id) {
|
||||
console.log(`*ae_func* No account_id found in API config!`);
|
||||
if (log_lvl) console.log(`*ae_func* No code provided!`);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const get_ds_result = await api.get_data_store_obj_w_code({
|
||||
api_cfg: api_cfg,
|
||||
data_store_code: code,
|
||||
data_type: data_type,
|
||||
timeout: timeout,
|
||||
log_lvl: log_lvl
|
||||
const get_ds_result = await api.get_data_store_v3({
|
||||
api_cfg,
|
||||
code,
|
||||
log_lvl
|
||||
});
|
||||
|
||||
if (!get_ds_result) {
|
||||
console.log('*ae_func* No results returned.');
|
||||
if (log_lvl) console.log('*ae_func* No results returned.');
|
||||
return null;
|
||||
}
|
||||
|
||||
if (log_lvl) {
|
||||
console.log(`*ae_func* Got a result for code ${code}`);
|
||||
}
|
||||
const ds_id = get_ds_result.data_store_id_random || get_ds_result.id_random;
|
||||
|
||||
if (!get_ds_result.data_store_id_random) {
|
||||
console.log('*ae_func* Something went wrong? No data store ID found.');
|
||||
if (!ds_id) {
|
||||
if (log_lvl) console.log('*ae_func* Something went wrong? No data store ID found.');
|
||||
return null;
|
||||
}
|
||||
|
||||
let return_this: any = null;
|
||||
|
||||
// Simplified data extraction
|
||||
if (data_type === 'html') {
|
||||
return_this = get_ds_result.html;
|
||||
} else if (data_type === 'json') {
|
||||
return_this = get_ds_result.json;
|
||||
} else {
|
||||
return_this = get_ds_result.text;
|
||||
}
|
||||
// Map content fields for convenience
|
||||
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 mapped_ds: ae_DataStore = {
|
||||
...get_ds_result,
|
||||
id: ds_id,
|
||||
text: text_val,
|
||||
html: text_val, // Map text to html by default
|
||||
json: json_val
|
||||
};
|
||||
|
||||
if (save_idb && browser) {
|
||||
const key_prefix = 'ae_ds__';
|
||||
if (log_lvl) {
|
||||
console.log(`*ae_func* localStorage key: ${code}, value:`, get_ds_result);
|
||||
}
|
||||
localStorage.setItem(`${key_prefix}${code}`, JSON.stringify(get_ds_result));
|
||||
const { db_core } = await import('./db_core');
|
||||
await db_core.data_store.put(mapped_ds);
|
||||
}
|
||||
|
||||
return return_this;
|
||||
if (data_type === 'html') return mapped_ds.html;
|
||||
if (data_type === 'json') return mapped_ds.json;
|
||||
return mapped_ds.text;
|
||||
|
||||
} catch (error) {
|
||||
console.log('*ae_func* No results returned or failed.', error);
|
||||
if (log_lvl) console.error('*ae_func* Fetch failed.', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import { db_core } from '$lib/ae_core/db_core';
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
import type { ae_DataStore } from '$lib/types/ae_types';
|
||||
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
@@ -28,7 +29,7 @@
|
||||
ds_loaded?: boolean;
|
||||
debug?: boolean;
|
||||
ds_loading_status?: string;
|
||||
val_sql?: null | key_val;
|
||||
val_sql?: null | any;
|
||||
}
|
||||
|
||||
let {
|
||||
@@ -57,62 +58,81 @@
|
||||
let ds_submit_results: Promise<any> | key_val | undefined = $state();
|
||||
|
||||
// Dexie LiveQuery for data store
|
||||
// This derived observable will automatically update when dependencies change
|
||||
let lq__ds_obj = $derived(
|
||||
liveQuery(async () => {
|
||||
const current_code = ds_code;
|
||||
const account_id = $slct.account_id;
|
||||
const account_id = $ae_loc.account_id;
|
||||
const current_for_type = for_type;
|
||||
const current_for_id = for_id;
|
||||
|
||||
if (!current_code) return null;
|
||||
|
||||
if (log_lvl > 1) console.log(`ae_e_data_store [${current_code}]: LQ Lookup...`, { account_id, current_for_type, current_for_id });
|
||||
if (log_lvl) console.log(`ae_e_data_store [${current_code}]: LQ Lookup...`, { account_id, current_for_type, current_for_id });
|
||||
|
||||
// Hierarchical Local Lookup (Specific -> Account -> Global)
|
||||
let result = null;
|
||||
|
||||
// 1. Specific Lookup
|
||||
if (current_for_type && current_for_id) {
|
||||
result = await db_core.data_store
|
||||
.where('[code+for_type+for_id_random]')
|
||||
.equals([current_code, current_for_type, current_for_id])
|
||||
.first();
|
||||
}
|
||||
// 0. Code Only Lookup
|
||||
// NOTE: Why this works. There should only be one record per code in the *local* Dexie DB. This is correct in 99.9% of cases.
|
||||
if (log_lvl) console.log(`ae_e_data_store [${current_code}]: Trying Specific Code Lookup...`);
|
||||
result = await db_core.data_store
|
||||
.where('code')
|
||||
.equals(current_code)
|
||||
.first();
|
||||
|
||||
// 2. Account Lookup
|
||||
if (!result && account_id) {
|
||||
result = await db_core.data_store
|
||||
.where('[code+account_id_random+for_type]')
|
||||
.equals([current_code, account_id, null])
|
||||
.first();
|
||||
}
|
||||
// // 1. Specific Lookup
|
||||
// if (current_for_type && current_for_id) {
|
||||
// result = await db_core.data_store
|
||||
// .where('[code+for_type+for_id_random]')
|
||||
// .equals([current_code, current_for_type, current_for_id])
|
||||
// .first();
|
||||
// }
|
||||
|
||||
// 3. Global Lookup
|
||||
if (!result) {
|
||||
result = await db_core.data_store
|
||||
.where('[code+account_id_random+for_type]')
|
||||
.equals([current_code, null, null])
|
||||
.first();
|
||||
}
|
||||
// // 2. Account Lookup
|
||||
// if (!result && account_id) {
|
||||
// result = await db_core.data_store
|
||||
// .where('[code+account_id_random+for_type]')
|
||||
// .equals([current_code, account_id, null])
|
||||
// .first();
|
||||
// }
|
||||
|
||||
if (log_lvl > 1) console.log(`ae_e_data_store [${current_code}]: LQ Result:`, result);
|
||||
|
||||
// Update loaded status
|
||||
ds_loaded = !!result;
|
||||
if (result) ds_loading_status = 'loaded';
|
||||
// // 3. Global Lookup
|
||||
// if (!result) {
|
||||
// result = await db_core.data_store
|
||||
// .where('[code+account_id_random+for_type]')
|
||||
// .equals([current_code, null, null])
|
||||
// .first();
|
||||
// }
|
||||
|
||||
return result;
|
||||
})
|
||||
);
|
||||
|
||||
// Sync status and bound props when the live data changes
|
||||
$effect(() => {
|
||||
const entry = $lq__ds_obj as ae_DataStore | null;
|
||||
|
||||
untrack(() => {
|
||||
ds_loaded = !!entry;
|
||||
if (entry) {
|
||||
ds_loading_status = 'loaded';
|
||||
// Handle val_sql binding if type is sql
|
||||
if (ds_type === 'sql') {
|
||||
val_sql = entry.text || entry.html || null;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Initial Trigger & Context Change Guard
|
||||
$effect(() => {
|
||||
const account_id = $slct.account_id;
|
||||
const api_ready = !!$ae_api?.base_url;
|
||||
|
||||
if (browser && api_ready && account_id) {
|
||||
// Only trigger if not loaded or if we want a fresh check
|
||||
if (!trigger) trigger = 'load__ds__code';
|
||||
const entry = $lq__ds_obj;
|
||||
|
||||
if (browser && api_ready && !entry && ds_loading_status === 'starting') {
|
||||
trigger = 'load__ds__code';
|
||||
}
|
||||
});
|
||||
|
||||
@@ -137,7 +157,7 @@
|
||||
async function load_data_store() {
|
||||
ds_loading_status = 'loading';
|
||||
const api_cfg = untrack(() => $ae_api);
|
||||
|
||||
|
||||
if (log_lvl) console.log(`ae_e_data_store [${ds_code}]: Fetching...`);
|
||||
|
||||
try {
|
||||
@@ -150,11 +170,14 @@
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
|
||||
// V3 API structured check
|
||||
const is_error = ds_results?.meta?.success === false;
|
||||
const status_code = ds_results?.meta?.status_code || (ds_results === false ? 500 : 200);
|
||||
|
||||
// Fallback to Global if not found or unauthorized for account
|
||||
if (!ds_results || status_code === 403 || status_code === 401) {
|
||||
if (log_lvl) console.log(`ae_e_data_store [${ds_code}]: Trying global fallback.`);
|
||||
// Fallback to Global if not found (404), unauthorized (403/401), or explicitly failed
|
||||
if (!ds_results || is_error || status_code === 404 || status_code === 403 || status_code === 401) {
|
||||
if (log_lvl) console.log(`ae_e_data_store [${ds_code}]: Not found in context (Status ${status_code}). Trying global fallback.`);
|
||||
|
||||
ds_results = await api.get_data_store_v3({
|
||||
api_cfg,
|
||||
code: ds_code,
|
||||
@@ -163,18 +186,25 @@
|
||||
});
|
||||
}
|
||||
|
||||
const ds_id = ds_results?.data_store_id_random || ds_results?.id_random || ds_results?.id || ds_results?.data_store_id;
|
||||
const ds_id = ds_results?.data_store_id || ds_results?.id;
|
||||
|
||||
if (ds_results && ds_id) {
|
||||
// Map fields correctly for V3 alignment
|
||||
const text_val = ds_results.text || '';
|
||||
const json_val = ds_results.json || (ds_results.json_str ? JSON.parse(ds_results.json_str) : null);
|
||||
|
||||
// Save to Dexie
|
||||
const ds_to_save = {
|
||||
const ds_to_save: ae_DataStore = {
|
||||
...ds_results,
|
||||
id: ds_id,
|
||||
data_store_id: ds_id,
|
||||
data_store_id_random: ds_id,
|
||||
data_store_id: ds_results.data_store_id || ds_id,
|
||||
// data_store_id_random: ds_id,
|
||||
account_id: ds_results.account_id_random || ds_results.account_id,
|
||||
account_id_random: ds_results.account_id_random || ds_results.account_id,
|
||||
updated_on: ds_results.updated_on || new Date().toISOString()
|
||||
// account_id_random: ds_results.account_id_random || ds_results.account_id,
|
||||
updated_on: ds_results.updated_on || new Date().toISOString(),
|
||||
text: text_val,
|
||||
html: text_val, // Default map text to html
|
||||
json: json_val
|
||||
};
|
||||
|
||||
await db_core.data_store.put(ds_to_save);
|
||||
@@ -214,10 +244,17 @@
|
||||
account_id_random: data_store_di.ds_use_account_id ? (data_store_di.ds_account_id ?? $slct.account_id) : null
|
||||
};
|
||||
|
||||
const content_val = data_store_di.ds_value;
|
||||
if (data_store_do.type === 'json') {
|
||||
data_store_do.json = data_store_di.ds_value;
|
||||
data_store_do.json = content_val;
|
||||
try {
|
||||
// Ensure it's valid JSON if stringified
|
||||
if (typeof content_val === 'string') JSON.parse(content_val);
|
||||
} catch (e) {
|
||||
console.error("Invalid JSON content");
|
||||
}
|
||||
} else {
|
||||
data_store_do.text = data_store_di.ds_value;
|
||||
data_store_do.text = content_val;
|
||||
}
|
||||
|
||||
const api_cfg = untrack(() => $ae_api);
|
||||
@@ -270,17 +307,21 @@
|
||||
</script>
|
||||
|
||||
<div class="ae__elem__data_store relative {class_li}" class:hidden={hide}>
|
||||
|
||||
{#if $lq__ds_obj}
|
||||
{#if debug || $ae_loc.debug === 'debug'}
|
||||
<pre class="text-[10px] bg-black/10 p-2 rounded mb-2">
|
||||
ID: {$lq__ds_obj.id}
|
||||
Code: {$lq__ds_obj.code}
|
||||
Name: {$lq__ds_obj.name}
|
||||
Type: {$lq__ds_obj.type}
|
||||
Created: {$lq__ds_obj.created_on}
|
||||
Updated: {$lq__ds_obj.updated_on}
|
||||
Account: {$lq__ds_obj.account_id_random || 'Global / NULL'}
|
||||
Debug is ON!
|
||||
<pre class="text-[10px] bg-black/10 p-2 rounded mb-2 overflow-x-auto">
|
||||
ID: {$lq__ds_obj.id}
|
||||
Code: {$lq__ds_obj.code}
|
||||
Name: {$lq__ds_obj.name}
|
||||
Type: {$lq__ds_obj.type}
|
||||
Created: {$lq__ds_obj.created_on}
|
||||
Updated: {$lq__ds_obj.updated_on}
|
||||
Account: {$lq__ds_obj.account_id_random || 'Global / NULL'}
|
||||
</pre>
|
||||
|
||||
<hr />
|
||||
{/if}
|
||||
|
||||
<Modal
|
||||
@@ -330,7 +371,7 @@ Account: {$lq__ds_obj.account_id_random || 'Global / NULL'}
|
||||
class="textarea font-mono text-sm"
|
||||
rows="15"
|
||||
placeholder="Enter content here..."
|
||||
>{$lq__ds_obj.type === 'json' ? JSON.stringify($lq__ds_obj.json, null, 2) : ($lq__ds_obj.text || $lq__ds_obj.html || '')}</textarea>
|
||||
>{$lq__ds_obj.type === 'json' ? (typeof $lq__ds_obj.json === 'string' ? $lq__ds_obj.json : JSON.stringify($lq__ds_obj.json, null, 2)) : ($lq__ds_obj.text || $lq__ds_obj.html || '')}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between items-center pt-4">
|
||||
@@ -348,17 +389,21 @@ Account: {$lq__ds_obj.account_id_random || 'Global / NULL'}
|
||||
</form>
|
||||
</Modal>
|
||||
|
||||
{#if $lq__ds_obj.type === 'html' && $lq__ds_obj.html}
|
||||
{@html $lq__ds_obj.html}
|
||||
{:else if $lq__ds_obj.type === 'text' && $lq__ds_obj.text}
|
||||
<div class="whitespace-pre-wrap">{$lq__ds_obj.text}</div>
|
||||
{#if show_view}
|
||||
{#if $lq__ds_obj.type === 'html' && $lq__ds_obj.html}
|
||||
{@html $lq__ds_obj.html}
|
||||
{:else if $lq__ds_obj.type === 'text' && $lq__ds_obj.text}
|
||||
<div class="whitespace-pre-wrap">{$lq__ds_obj.text}</div>
|
||||
{:else if $lq__ds_obj.type === 'sql' && $lq__ds_obj.text}
|
||||
{#if debug}<div class="font-mono text-xs opacity-50">SQL: {$lq__ds_obj.text}</div>{/if}
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
{#if $ae_loc.edit_mode && ($ae_loc.manager_access || (show_edit_btn && $ae_loc.administrator_access))}
|
||||
<button
|
||||
type="button"
|
||||
class="absolute top-0 right-0 btn btn-sm variant-soft-warning opacity-20 hover:opacity-100 z-10"
|
||||
onclick={() => { show_edit = true; show_view = false; }}
|
||||
ondblclick={() => { show_edit = true; show_view = false; }}
|
||||
title="Edit Data Store: {ds_code}"
|
||||
>
|
||||
<span class="fas fa-edit"></span>
|
||||
@@ -376,9 +421,3 @@ Account: {$lq__ds_obj.account_id_random || 'Global / NULL'}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="postcss">
|
||||
.ae__elem__data_store {
|
||||
/* Base styles */
|
||||
}
|
||||
</style>
|
||||
@@ -1,20 +1,28 @@
|
||||
<script lang="ts">
|
||||
import AE_Element_Data_Store_V3 from '$lib/elements/element_data_store_v3_alpha.svelte';
|
||||
import AE_Element_Data_Store_V3 from '$lib/elements/element_data_store_v3.svelte';
|
||||
import { ae_loc } from '$lib/stores/ae_stores';
|
||||
import { db_core } from '$lib/ae_core/db_core';
|
||||
|
||||
let test_code_global = 'hub__site__root_page_header'; // Expected to be a global default
|
||||
let test_name_global = 'Global Header Test - hub__site__root_page_header';
|
||||
let test_code_account = 'hub__site__root_page_header';
|
||||
let test_name_account = 'Account Header Test - hub__site__root_page_header';
|
||||
let test_code_specific = 'event_launcher_main_info';
|
||||
let test_name_specific = 'Event Specific Test - event_launcher_main_info';
|
||||
// let test_code_global = 'hub__site__root_page_header'; // Expected to be a global default
|
||||
// let test_name_global = 'Global Header Test - hub__site__root_page_header';
|
||||
// let test_code_account = 'hub__site__root_page_header';
|
||||
// let test_name_account = 'Account Header Test - hub__site__root_page_header';
|
||||
// let test_code_specific = 'event_launcher_main_info';
|
||||
// let test_name_specific = 'Event Specific Test - event_launcher_main_info';
|
||||
|
||||
|
||||
let test_null_act_and_for = 'events__leads__overview'; // Expecting the Global Default
|
||||
let test_code_account = 'hub__site__root_page_header'; // Expecting the Account Default
|
||||
let test_code_and_for = 'event_launcher_main_info'; // Expecting the Specific Record (Event ID)
|
||||
let test_event_id = 'pjrcghqwert';
|
||||
|
||||
|
||||
let log_lvl = 2;
|
||||
let refresh_trigger = $state(0);
|
||||
|
||||
async function clear_cache() {
|
||||
if (log_lvl) console.log('Asking to confirm clearing Data Store cache...');
|
||||
|
||||
if (confirm('Are you sure you want to clear the local Data Store cache?')) {
|
||||
await db_core.data_store.clear();
|
||||
refresh_trigger++;
|
||||
@@ -42,14 +50,14 @@
|
||||
{#key refresh_trigger}
|
||||
<section class="card p-4 space-y-4 variant-soft-primary">
|
||||
<h2 class="h3">Scenario 1: Global Default</h2>
|
||||
<p class="text-sm">Fetching code <code>{test_code_global}</code>. Should fall back to <code>account_id = NULL</code> if not found for account.</p>
|
||||
<p class="text-sm">Fetching code <code>{test_null_act_and_for}</code>. Should fall back to <code>account_id = NULL</code> if not found for account.</p>
|
||||
<div class="bg-surface-100-800-token p-4 rounded-lg border border-surface-500/20">
|
||||
<!-- <AE_Element_Data_Store_V3
|
||||
ds_code={test_code_global}
|
||||
ds_name={test_name_global}
|
||||
<AE_Element_Data_Store_V3
|
||||
ds_code={test_null_act_and_for}
|
||||
ds_name={'Global Default Test'}
|
||||
{log_lvl}
|
||||
debug={true}
|
||||
/> -->
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -57,27 +65,27 @@
|
||||
<h2 class="h3">Scenario 2: Account Default</h2>
|
||||
<p class="text-sm">Fetching code <code>{test_code_account}</code> for Account ID: <code>{$ae_loc.account_id}</code>.</p>
|
||||
<div class="bg-surface-100-800-token p-4 rounded-lg border border-surface-500/20">
|
||||
<!-- <AE_Element_Data_Store_V3
|
||||
<AE_Element_Data_Store_V3
|
||||
ds_code={test_code_account}
|
||||
ds_name={test_name_account}
|
||||
ds_name={'Account Default Test'}
|
||||
{log_lvl}
|
||||
debug={true}
|
||||
/> -->
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="card p-4 space-y-4 variant-soft-tertiary">
|
||||
<h2 class="h3">Scenario 3: Specific Record (Event Override)</h2>
|
||||
<p class="text-sm">Fetching code <code>{test_code_specific}</code> linked to <code>for_type: event</code> and <code>for_id: {test_event_id}</code>.</p>
|
||||
<p class="text-sm">Fetching code <code>{test_code_and_for}</code> linked to <code>for_type: event</code> and <code>for_id: {test_event_id}</code>.</p>
|
||||
<div class="bg-surface-100-800-token p-4 rounded-lg border border-surface-500/20">
|
||||
<!-- <AE_Element_Data_Store_V3
|
||||
ds_code={test_code_specific}
|
||||
ds_name={test_name_specific}
|
||||
<AE_Element_Data_Store_V3
|
||||
ds_code={test_code_and_for}
|
||||
ds_name={'Specific Record Test'}
|
||||
for_type="event"
|
||||
for_id={test_event_id}
|
||||
{log_lvl}
|
||||
debug={true}
|
||||
/> -->
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
{/key}
|
||||
|
||||
Reference in New Issue
Block a user