feat(framework): implement AE Obj Field Editor v3 and test playground
- Created consolidated AE_Obj_Field_Editor_V3 component using Svelte 5 Runes.
- Standardized on V3 CRUD API (PATCH /v3/crud/{obj_type}/{obj_id}).
- Implemented local state guards to prevent reactivity loops.
- Added support for multiple field types (text, textarea, select, checkbox, tiptap).
- Created a dedicated testing playground with real Demo account data.
- Updated the PROJECT_AE_OBJECT_FIELD_EDITOR_V3_UPGRADE.md plan.
This commit is contained in:
222
src/routes/testing/ae_obj_field_editor_v3/+page.svelte
Normal file
222
src/routes/testing/ae_obj_field_editor_v3/+page.svelte
Normal file
@@ -0,0 +1,222 @@
|
||||
<script lang="ts">
|
||||
import AE_Obj_Field_Editor_V3 from '$lib/elements/element_ae_obj_field_editor_v3.svelte';
|
||||
import { ae_loc, ae_api } from '$lib/stores/ae_stores';
|
||||
import { liveQuery } from 'dexie';
|
||||
import { db_journals } from '$lib/ae_journals/db_journals';
|
||||
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 { LoaderCircle, Database, Settings2, Edit, FileText } from 'lucide-svelte';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let log_lvl = $state(1);
|
||||
|
||||
// Provided Test IDs
|
||||
let test_journal_id = $state('SWFK-48-89-90'); // 'BVYE-94-46-29'
|
||||
let test_journal_entry_id = $state('xRx-Y4-h3-fU');
|
||||
|
||||
// Fetch objects from API on mount to ensure local DB is populated
|
||||
onMount(async () => {
|
||||
if (log_lvl) console.log('Test Page: Initializing data from server...');
|
||||
try {
|
||||
await Promise.all([
|
||||
load_ae_obj_id__journal({
|
||||
api_cfg: $ae_api,
|
||||
journal_id: test_journal_id,
|
||||
log_lvl
|
||||
}),
|
||||
load_ae_obj_id__journal_entry({
|
||||
api_cfg: $ae_api,
|
||||
journal_entry_id: test_journal_entry_id,
|
||||
log_lvl
|
||||
})
|
||||
]);
|
||||
} catch (e) {
|
||||
console.error('Test Page: Error loading initial data', e);
|
||||
}
|
||||
});
|
||||
|
||||
// Dexie LiveQueries
|
||||
let lq__test_journal = $derived(
|
||||
liveQuery(async () => {
|
||||
return await db_journals.journal.get(test_journal_id);
|
||||
})
|
||||
);
|
||||
|
||||
let lq__test_journal_entry = $derived(
|
||||
liveQuery(async () => {
|
||||
return await db_journals.journal_entry.get(test_journal_entry_id);
|
||||
})
|
||||
);
|
||||
|
||||
function handle_success(data: any) {
|
||||
console.log('Test Page: Patch Success!', data);
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="p-8 space-y-8 max-w-6xl mx-auto h-full overflow-y-auto">
|
||||
<header class="border-b border-surface-500/30 pb-4 flex justify-between items-center">
|
||||
<div>
|
||||
<h1 class="h1">AE Obj Field Editor V3 Test</h1>
|
||||
<p class="opacity-70 font-mono text-xs">IDs: Journal={test_journal_id} | Entry={test_journal_entry_id}</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-4">
|
||||
<label class="flex items-center gap-2 cursor-pointer bg-surface-200 dark:bg-surface-800 px-3 py-1.5 rounded-full shadow-inner">
|
||||
<span class="text-xs font-bold uppercase opacity-70">Edit Mode</span>
|
||||
<input type="checkbox" bind:checked={$ae_loc.edit_mode} class="checkbox" />
|
||||
</label>
|
||||
<button class="btn variant-filled-primary" onclick={() => window.location.reload()}>
|
||||
<span class="fas fa-sync mr-2"></span> Reload Page
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
|
||||
<!-- COLUMN 1: JOURNAL TEST -->
|
||||
<div class="space-y-8">
|
||||
<h2 class="h2 flex items-center gap-2"><Database /> Journal Properties</h2>
|
||||
|
||||
{#if $lq__test_journal}
|
||||
<section class="card p-6 space-y-6 variant-soft-primary shadow-lg border border-primary-500/20">
|
||||
<div class="field_group">
|
||||
<label for="j_name" class="label text-xs font-bold opacity-50 mb-1 uppercase tracking-tighter">Journal Name</label>
|
||||
<AE_Obj_Field_Editor_V3
|
||||
id="j_name"
|
||||
object_type="journal"
|
||||
object_id={test_journal_id}
|
||||
field_name="name"
|
||||
bind:current_value={$lq__test_journal.name}
|
||||
field_type="text"
|
||||
{log_lvl}
|
||||
on_success={handle_success}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="field_group">
|
||||
<label for="j_type" class="label text-xs font-bold opacity-50 mb-1 uppercase tracking-tighter">Type Code</label>
|
||||
<AE_Obj_Field_Editor_V3
|
||||
id="j_type"
|
||||
object_type="journal"
|
||||
object_id={test_journal_id}
|
||||
field_name="type_code"
|
||||
bind:current_value={$lq__test_journal.type_code}
|
||||
field_type="select"
|
||||
select_options={{
|
||||
'personal': 'Personal Journal',
|
||||
'work': 'Work Log',
|
||||
'shared': 'Shared Notes',
|
||||
'ai_brain': 'AI Context'
|
||||
}}
|
||||
{log_lvl}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="field_group">
|
||||
<label for="j_summary" class="label text-xs font-bold opacity-50 mb-1 uppercase tracking-tighter">Summary</label>
|
||||
<AE_Obj_Field_Editor_V3
|
||||
id="j_summary"
|
||||
object_type="journal"
|
||||
object_id={test_journal_id}
|
||||
field_name="summary"
|
||||
bind:current_value={$lq__test_journal.summary}
|
||||
field_type="textarea"
|
||||
display_block={true}
|
||||
{log_lvl}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
{:else}
|
||||
<div class="card p-10 flex flex-col items-center justify-center opacity-50 gap-4 variant-soft-surface">
|
||||
<LoaderCircle size="32" class="animate-spin" />
|
||||
<p class="text-sm font-bold">Loading Journal {test_journal_id}...</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- COLUMN 2: JOURNAL ENTRY TEST -->
|
||||
<div class="space-y-8">
|
||||
<h2 class="h2 flex items-center gap-2"><FileText /> Journal Entry Properties</h2>
|
||||
|
||||
{#if $lq__test_journal_entry}
|
||||
<section class="card p-6 space-y-6 variant-soft-secondary shadow-lg border border-secondary-500/20">
|
||||
<div class="field_group">
|
||||
<label for="e_name" class="label text-xs font-bold opacity-50 mb-1 uppercase tracking-tighter">Entry Title</label>
|
||||
<AE_Obj_Field_Editor_V3
|
||||
id="e_name"
|
||||
object_type="journal_entry"
|
||||
object_id={test_journal_entry_id}
|
||||
field_name="name"
|
||||
bind:current_value={$lq__test_journal_entry.name}
|
||||
field_type="text"
|
||||
{log_lvl}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="field_group">
|
||||
<label for="e_enabled" class="label text-xs font-bold opacity-50 mb-1 uppercase tracking-tighter">Status</label>
|
||||
<AE_Obj_Field_Editor_V3
|
||||
id="e_enabled"
|
||||
object_type="journal_entry"
|
||||
object_id={test_journal_entry_id}
|
||||
field_name="enable"
|
||||
bind:current_value={$lq__test_journal_entry.enable}
|
||||
field_type="checkbox"
|
||||
{log_lvl}
|
||||
/>
|
||||
</div>
|
||||
<div class="field_group">
|
||||
<label for="e_priority" class="label text-xs font-bold opacity-50 mb-1 uppercase tracking-tighter">Priority</label>
|
||||
<AE_Obj_Field_Editor_V3
|
||||
id="e_priority"
|
||||
object_type="journal_entry"
|
||||
object_id={test_journal_entry_id}
|
||||
field_name="priority"
|
||||
bind:current_value={$lq__test_journal_entry.priority}
|
||||
field_type="checkbox"
|
||||
{log_lvl}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field_group">
|
||||
<label class="label text-xs font-bold opacity-50 mb-1 uppercase tracking-tighter">Content (TipTap)</label>
|
||||
<AE_Obj_Field_Editor_V3
|
||||
object_type="journal_entry"
|
||||
object_id={test_journal_entry_id}
|
||||
field_name="content"
|
||||
bind:current_value={$lq__test_journal_entry.content}
|
||||
field_type="tiptap"
|
||||
display_block={true}
|
||||
{log_lvl}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
{:else}
|
||||
<div class="card p-10 flex flex-col items-center justify-center opacity-50 gap-4 variant-soft-surface">
|
||||
<LoaderCircle size="32" class="animate-spin" />
|
||||
<p class="text-sm font-bold">Loading Entry {test_journal_entry_id}...</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- DEBUG FOOTER -->
|
||||
<section class="card p-4 space-y-4">
|
||||
<h2 class="h3">Debug Context</h2>
|
||||
<div class="grid grid-cols-2 lg:grid-cols-4 gap-4 text-xs font-mono">
|
||||
<div class="bg-surface-900 text-success-500 p-2 rounded">
|
||||
<strong>Edit Mode:</strong> {$ae_loc.edit_mode}
|
||||
</div>
|
||||
<div class="bg-surface-900 text-success-500 p-2 rounded">
|
||||
<strong>Account ID:</strong> {$ae_loc.account_id}
|
||||
</div>
|
||||
<div class="bg-surface-900 text-success-500 p-2 rounded">
|
||||
<strong>Journal Status:</strong> {$lq__test_journal ? 'Cached' : 'Pending'}
|
||||
</div>
|
||||
<div class="bg-surface-900 text-success-500 p-2 rounded">
|
||||
<strong>Entry Status:</strong> {$lq__test_journal_entry ? 'Cached' : 'Pending'}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
Reference in New Issue
Block a user