diff --git a/documentation/BOOTSTRAP__AI_Agent_Quickstart.md b/documentation/BOOTSTRAP__AI_Agent_Quickstart.md index 0757fbee..cc456b26 100644 --- a/documentation/BOOTSTRAP__AI_Agent_Quickstart.md +++ b/documentation/BOOTSTRAP__AI_Agent_Quickstart.md @@ -177,6 +177,25 @@ async function load_ae_obj_id__my_obj({ api_cfg, obj_id }) { } ``` +### Shared/Common Aether object fields +The core fields for almost all Aether objects are: +* id/id_random +* code - string +* name - string +* summary - string +* content - string +* alert - boolean +* alert_msg - text +* priority - boolean +* sort - int +* group - string +* hide - boolean +* enable - boolean +* default_qry_str - special concat string index +* notes - text +* created_on - timestamp +* updated_on - timestamp + ### ID convention — never use `_id_random` fields The V3 API uses random string IDs (e.g. `event_file_id = "aBc123"`). The `*_id_random` fields are legacy aliases. The integer version of the ID is never returned by the API. Always use the short form: @@ -229,7 +248,7 @@ When looking up a single object by its string ID, always use `.where().equals(). --- -## 6. Naming Conventions +## 6. Naming Conventions (snake_case; no camelCase) | Pattern | Example | Used for | |---|---|---| diff --git a/src/lib/ae_elements/AE_Object_Flags.svelte b/src/lib/ae_elements/AE_Object_Flags.svelte index 9b2a90d4..b29cd15a 100644 --- a/src/lib/ae_elements/AE_Object_Flags.svelte +++ b/src/lib/ae_elements/AE_Object_Flags.svelte @@ -6,7 +6,6 @@ */ import { Siren, - MessageSquareWarning, Fingerprint, Globe, BookHeart, @@ -15,10 +14,11 @@ import { Settings } from '@lucide/svelte'; import { ae_loc } from '$lib/stores/ae_stores'; +import type { ae_JournalEntry } from '$lib/types/ae_types'; interface Props { // The object containing the flags (bindable) - obj: any; + obj: ae_JournalEntry; // Visibility configuration (optional overrides) show_labels?: boolean; @@ -49,9 +49,38 @@ let { container_class = 'flex flex-row flex-wrap gap-1 items-center justify-evenly py-2 border-y border-surface-500/10' }: Props = $props(); -function handle_toggle(prop: string) { - obj[prop] = !obj[prop]; - if (onToggle) onToggle(prop, obj[prop]); +function emit_toggle(prop: string, value: boolean) { + if (onToggle) onToggle(prop, value); +} + +function toggle_alert() { + obj.alert = !obj.alert; + emit_toggle('alert', !!obj.alert); +} + +function toggle_private() { + obj.private = !obj.private; + emit_toggle('private', !!obj.private); +} + +function toggle_public() { + obj.public = !obj.public; + emit_toggle('public', !!obj.public); +} + +function toggle_personal() { + obj.personal = !obj.personal; + emit_toggle('personal', !!obj.personal); +} + +function toggle_professional() { + obj.professional = !obj.professional; + emit_toggle('professional', !!obj.professional); +} + +function toggle_template() { + obj.template = !obj.template; + emit_toggle('template', !!obj.template); } @@ -63,81 +92,69 @@ function handle_toggle(prop: string) { {/if} - {#if !hide_alert} {/if} - {#if !hide_private} {/if} - {#if !hide_public} {/if} - {#if !hide_personal} {/if} - {#if !hide_professional} {/if} - {#if !hide_template && $ae_loc.edit_mode} {/if} diff --git a/src/routes/journals/ae_comp__modal_journal_entry_config.svelte b/src/routes/journals/ae_comp__modal_journal_entry_config.svelte index 011ec1fe..0a0a47aa 100644 --- a/src/routes/journals/ae_comp__modal_journal_entry_config.svelte +++ b/src/routes/journals/ae_comp__modal_journal_entry_config.svelte @@ -7,10 +7,9 @@ import { ArrowDownToLine, ArrowUpToLine, Check, - Clock, + CircleAlert, CodeXml, Copy, - Database, FileDown, Fingerprint, Minus, @@ -24,22 +23,19 @@ import { X, Zap } from '@lucide/svelte'; +import { goto } from '$app/navigation'; import { Modal } from 'flowbite-svelte'; import { ae_loc, ae_api } from '$lib/stores/ae_stores'; -import { - journals_loc, - journals_sess -} from '$lib/ae_journals/ae_journals_stores'; import { journals_func } from '$lib/ae_journals/ae_journals_functions'; import AE_Comp_Editor_CodeMirror from '$lib/elements/element_editor_codemirror.svelte'; import AE_Object_Flags from '$lib/ae_elements/AE_Object_Flags.svelte'; +import type { ae_Journal, ae_JournalEntry } from '$lib/types/ae_types'; interface Props { log_lvl?: number; show?: boolean; - entry: any; - journal: any; - tmp_entry_obj: any; // Bindable + journal: ae_Journal; + tmp_entry_obj: ae_JournalEntry; // Bindable on_save: () => void; on_force_reset?: () => void; on_show_export?: () => void; @@ -50,7 +46,6 @@ interface Props { let { log_lvl = $bindable(0), show = $bindable(false), - entry, journal, tmp_entry_obj = $bindable(), on_save, @@ -62,7 +57,15 @@ let { let tab: 'actions' | 'meta' | 'security' | 'json' = $state('actions'); -const normalize_date = (val: string | null) => (val ? val.slice(0, 16) : null); +const normalize_date = (val?: string | Date | null) => { + if (!val) return null; + if (val instanceof Date) return val.toISOString().slice(0, 16); + return val.slice(0, 16); +}; + +const panel_class = 'space-y-4 rounded-xl border border-surface-500/20 bg-surface-500/5 p-4 shadow-sm'; +const panel_title_class = 'flex items-center gap-2 border-b border-surface-500/20 pb-2 text-lg font-bold'; +const field_card_class = 'bg-surface-500/5 border-surface-500/10 flex cursor-pointer items-center space-x-3 rounded-lg border p-3 transition-colors hover:bg-surface-500/10'; async function handle_update_entry() { try { @@ -103,6 +106,32 @@ async function handle_update_entry() { console.error('Error updating journal entry:', error); } } + +async function handle_admin_delete_action() { + const can_delete = $ae_loc.manager_access || $ae_loc.administrator_access; + const delete_method = can_delete ? 'delete' : 'disable'; + const action_label = can_delete ? 'delete' : 'remove'; + const confirm_label = can_delete ? 'delete' : 'remove'; + + if (!confirm(`Are you sure you want to ${confirm_label} this journal entry?`)) { + return; + } + + try { + await journals_func.delete_ae_obj_id__journal_entry({ + api_cfg: $ae_api, + journal_entry_id: tmp_entry_obj.journal_entry_id, + method: delete_method, + log_lvl + }); + + show = false; + await goto(`/journals/${tmp_entry_obj.journal_id}`); + } catch (error) { + console.error(`Error attempting to ${action_label} journal entry:`, error); + alert(`Failed to ${action_label} journal entry.`); + } +} + class="relative mx-auto flex h-[calc(100dvh-2rem)] max-h-[calc(100dvh-2rem)] w-full flex-col rounded-xl border border-surface-200-800 bg-surface-50-900 text-surface-950-50 shadow-xl" + headerClass="flex w-full flex-row items-center justify-between gap-2 rounded-t-xl border-b border-surface-200-800 bg-surface-100-900 p-4" + footerClass="flex w-full flex-row items-center justify-center gap-2 rounded-b-xl border-t border-surface-200-800 bg-surface-100-900 p-4"> {#snippet header()}

@@ -127,7 +156,7 @@ async function handle_update_entry() { {/snippet} -
+
@@ -166,51 +195,62 @@ async function handle_update_entry() {
{#if tab === 'actions'} -
-
- - - - +
+
+

+ + Quick Actions +

+
+ + + + +
-
-

+
+

+ Quick Category -

+

{#each journal?.cfg_json?.category_li ?? [] as cat (cat.code)}
{:else if tab === 'meta'} -
- +
+
+

+ + Entry Details +

+
+ - - -
- - -
+
{:else if tab === 'security'} -
-
-

- +
+
+

+ Status & Security

-
-
-

-
+
Sort Order @@ -400,12 +429,17 @@ async function handle_update_entry() {
-
-

+
+

+ Privacy Flags -

+

+

+ Visibility and audience controls for the entry itself. +

{ handle_update_entry(); on_save(); @@ -419,15 +453,50 @@ async function handle_update_entry() { hide_template={journal?.cfg_json?.hide_btn_template} />
+
+

+ + Alerts & Messaging +

+
+ + +
+
+ {#if tmp_entry_obj.private && !tmp_entry_obj.content && tmp_entry_obj.content_encrypted} -
-
-

- Disaster Recovery -

-

+

+

+ + Disaster Recovery +

+
+

If the encryption passcode is lost, the data is unrecoverable. You can force a reset to plain text to reuse this entry ID. @@ -445,24 +514,85 @@ async function handle_update_entry() {

{/if} -
- -
+ {#if $ae_loc.trusted_access || $ae_loc.manager_access || $ae_loc.administrator_access} +
+

+ + Admin +

+

+ Trusted access and above only. Notes are for staff + use; managers and admins see Delete while trusted + access sees Remove. +

+ +
+ + +
+ + + +
+
+
+ {/if}
{:else if tab === 'json'} -
- +
+
+

+ + Raw Entry JSON +

+

+ Read-only view of the current bound entry object. +

+ +
{/if}
@@ -470,10 +600,10 @@ async function handle_update_entry() { {#snippet footer()} {/snippet} - + \ No newline at end of file