Refine journal entry config
Polish the Journal Entry Config modal to match the desired section outline, hide alert messaging unless enabled, update the shared draft typing for entry flows, and replace deprecated privacy icons. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -7,13 +7,11 @@ import {
|
||||
ArrowDownToLine,
|
||||
ArrowUpToLine,
|
||||
Check,
|
||||
CircleAlert,
|
||||
CodeXml,
|
||||
Copy,
|
||||
FileDown,
|
||||
Fingerprint,
|
||||
FingerprintPattern,
|
||||
Minus,
|
||||
Plus,
|
||||
RefreshCcw,
|
||||
Settings,
|
||||
Shapes,
|
||||
@@ -29,13 +27,16 @@ import { ae_loc, ae_api } from '$lib/stores/ae_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';
|
||||
import type {
|
||||
ae_Journal,
|
||||
ae_JournalEntryDraft
|
||||
} from '$lib/types/ae_types';
|
||||
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
show?: boolean;
|
||||
journal: ae_Journal;
|
||||
tmp_entry_obj: ae_JournalEntry; // Bindable
|
||||
tmp_entry_obj: ae_JournalEntryDraft; // Bindable
|
||||
on_save: () => void;
|
||||
on_force_reset?: () => void;
|
||||
on_show_export?: () => void;
|
||||
@@ -77,6 +78,12 @@ function tab_button_class(is_active: boolean): string {
|
||||
async function handle_update_entry() {
|
||||
try {
|
||||
// WHITELISTED BASE TABLE COLUMNS ONLY
|
||||
const journal_entry_id = tmp_entry_obj.journal_entry_id;
|
||||
if (!journal_entry_id) {
|
||||
console.error('Journal entry ID missing for update.');
|
||||
return;
|
||||
}
|
||||
|
||||
const data_kv = {
|
||||
name: tmp_entry_obj.name,
|
||||
short_name: tmp_entry_obj.short_name,
|
||||
@@ -86,6 +93,7 @@ async function handle_update_entry() {
|
||||
type_code: tmp_entry_obj.type_code,
|
||||
topic_code: tmp_entry_obj.topic_code,
|
||||
tags: tmp_entry_obj.tags,
|
||||
passcode_hash: tmp_entry_obj.passcode_hash,
|
||||
private: tmp_entry_obj.private,
|
||||
public: tmp_entry_obj.public,
|
||||
personal: tmp_entry_obj.personal,
|
||||
@@ -105,7 +113,7 @@ async function handle_update_entry() {
|
||||
|
||||
await journals_func.update_ae_obj__journal_entry({
|
||||
api_cfg: $ae_api,
|
||||
journal_entry_id: tmp_entry_obj.journal_entry_id,
|
||||
journal_entry_id,
|
||||
data_kv: data_kv,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
@@ -119,6 +127,12 @@ async function handle_admin_delete_action() {
|
||||
const delete_method = can_delete ? 'delete' : 'disable';
|
||||
const action_label = can_delete ? 'delete' : 'remove';
|
||||
const confirm_label = can_delete ? 'delete' : 'remove';
|
||||
const journal_entry_id = tmp_entry_obj.journal_entry_id;
|
||||
|
||||
if (!journal_entry_id) {
|
||||
console.error('Journal entry ID missing for delete action.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!confirm(`Are you sure you want to ${confirm_label} this journal entry?`)) {
|
||||
return;
|
||||
@@ -127,7 +141,7 @@ async function handle_admin_delete_action() {
|
||||
try {
|
||||
await journals_func.delete_ae_obj_id__journal_entry({
|
||||
api_cfg: $ae_api,
|
||||
journal_entry_id: tmp_entry_obj.journal_entry_id,
|
||||
journal_entry_id,
|
||||
method: delete_method,
|
||||
log_lvl
|
||||
});
|
||||
@@ -149,7 +163,7 @@ async function handle_admin_delete_action() {
|
||||
size="lg"
|
||||
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">
|
||||
footerClass="mt-auto flex w-full shrink-0 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()}
|
||||
<h3 class="flex flex-1 items-center gap-2 text-lg font-bold">
|
||||
<Settings class="text-primary-500" />
|
||||
@@ -338,6 +352,25 @@ async function handle_admin_delete_action() {
|
||||
}}
|
||||
class="input" />
|
||||
</label>
|
||||
|
||||
{#if !journal?.cfg_json?.hide_btn_template}
|
||||
<label class={field_card_class}>
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={tmp_entry_obj.template}
|
||||
onchange={() => {
|
||||
handle_update_entry();
|
||||
on_save();
|
||||
}}
|
||||
class="checkbox checkbox-primary" />
|
||||
<div class="flex flex-col">
|
||||
<span class="font-bold">Template</span>
|
||||
<span class="text-xs opacity-60">
|
||||
Mark this entry as a reusable template
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
{/if}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
@@ -346,118 +379,27 @@ async function handle_admin_delete_action() {
|
||||
<section class={panel_class}>
|
||||
<h2 class={panel_title_class}>
|
||||
<ShieldCheck size="1.2em" class="text-primary-500" />
|
||||
Status & Security
|
||||
Status
|
||||
</h2>
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<label class={field_card_class}>
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={tmp_entry_obj.enable}
|
||||
onchange={() => {
|
||||
handle_update_entry();
|
||||
on_save();
|
||||
}}
|
||||
class="checkbox checkbox-primary" />
|
||||
<div class="flex flex-col">
|
||||
<span class="font-bold">Enabled</span>
|
||||
<span class="text-xs opacity-60"
|
||||
>Allow access to this entry</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class={field_card_class}>
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={tmp_entry_obj.hide}
|
||||
onchange={() => {
|
||||
handle_update_entry();
|
||||
on_save();
|
||||
}}
|
||||
class="checkbox checkbox-primary" />
|
||||
<div class="flex flex-col">
|
||||
<span class="font-bold">Hidden</span>
|
||||
<span class="text-xs opacity-60"
|
||||
>Hide from standard lists</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class={field_card_class}>
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={tmp_entry_obj.priority}
|
||||
onchange={() => {
|
||||
handle_update_entry();
|
||||
on_save();
|
||||
}}
|
||||
class="checkbox checkbox-primary" />
|
||||
<div class="flex flex-col">
|
||||
<span class="font-bold">Priority Entry</span>
|
||||
<span class="text-xs opacity-60"
|
||||
>Star or pin to top</span>
|
||||
</div>
|
||||
</label>
|
||||
<div class="bg-surface-500/5 border-surface-500/10 flex items-center justify-between rounded-lg border p-3">
|
||||
<div class="flex flex-col">
|
||||
<span class="text-sm font-bold"
|
||||
>Sort Order</span>
|
||||
<span class="text-xs opacity-60"
|
||||
>Manual list position</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<button
|
||||
type="button"
|
||||
class="btn-icon btn-icon-sm preset-tonal-surface"
|
||||
onclick={() => {
|
||||
tmp_entry_obj.sort =
|
||||
(tmp_entry_obj.sort ?? 0) - 1;
|
||||
{#if tmp_entry_obj.alert}
|
||||
<label class="label md:col-span-2 flex flex-col items-start gap-1">
|
||||
<span class="text-sm font-bold opacity-70"
|
||||
>Alert Message</span>
|
||||
<textarea
|
||||
bind:value={tmp_entry_obj.alert_msg}
|
||||
class="textarea min-h-24 w-full"
|
||||
placeholder="Optional alert or notice shown with the entry"
|
||||
onchange={() => {
|
||||
handle_update_entry();
|
||||
on_save();
|
||||
}}><Minus size="1em" /></button>
|
||||
<span
|
||||
class="w-8 text-center font-mono text-lg font-bold"
|
||||
>{tmp_entry_obj.sort ?? 0}</span>
|
||||
<button
|
||||
type="button"
|
||||
class="btn-icon btn-icon-sm preset-tonal-surface"
|
||||
onclick={() => {
|
||||
tmp_entry_obj.sort =
|
||||
(tmp_entry_obj.sort ?? 0) + 1;
|
||||
handle_update_entry();
|
||||
on_save();
|
||||
}}><Plus size="1em" /></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
}}></textarea>
|
||||
<span class="text-xs opacity-60">
|
||||
Shown when Alert is enabled.
|
||||
</span>
|
||||
</label>
|
||||
{/if}
|
||||
|
||||
<section class={panel_class}>
|
||||
<h2 class={panel_title_class}>
|
||||
<Fingerprint size="1.2em" class="text-primary-500" />
|
||||
Privacy Flags
|
||||
</h2>
|
||||
<p class="text-xs opacity-60">
|
||||
Visibility and audience controls for the entry itself.
|
||||
</p>
|
||||
<AE_Object_Flags
|
||||
bind:obj={tmp_entry_obj}
|
||||
show_labels={false}
|
||||
on_toggle={() => {
|
||||
handle_update_entry();
|
||||
on_save();
|
||||
}}
|
||||
hide_alert={journal?.cfg_json?.hide_btn_alert}
|
||||
hide_private={journal?.cfg_json?.hide_btn_private}
|
||||
hide_public={journal?.cfg_json?.hide_btn_public}
|
||||
hide_personal={journal?.cfg_json?.hide_btn_personal}
|
||||
hide_professional={journal?.cfg_json
|
||||
?.hide_btn_professional}
|
||||
hide_template={journal?.cfg_json?.hide_btn_template} />
|
||||
</section>
|
||||
|
||||
<section class={panel_class}>
|
||||
<h2 class={panel_title_class}>
|
||||
<CircleAlert size="1.2em" class="text-primary-500" />
|
||||
Alerts & Messaging
|
||||
</h2>
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<label class={field_card_class}>
|
||||
<input
|
||||
type="checkbox"
|
||||
@@ -469,22 +411,103 @@ async function handle_admin_delete_action() {
|
||||
class="checkbox checkbox-primary" />
|
||||
<div class="flex flex-col">
|
||||
<span class="font-bold">Alert</span>
|
||||
<span class="text-xs opacity-60"
|
||||
>Flag this entry for emphasis</span>
|
||||
<span class="text-xs opacity-60">
|
||||
Action required or reminder.
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
<label class="label md:col-span-2">
|
||||
<span class="text-sm font-bold opacity-70"
|
||||
>Alert Message</span>
|
||||
<textarea
|
||||
bind:value={tmp_entry_obj.alert_msg}
|
||||
class="textarea min-h-24"
|
||||
placeholder="Optional note shown with the alert"
|
||||
|
||||
<label class={field_card_class}>
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={tmp_entry_obj.priority}
|
||||
onchange={() => {
|
||||
handle_update_entry();
|
||||
on_save();
|
||||
}}></textarea>
|
||||
}}
|
||||
class="checkbox checkbox-primary" />
|
||||
<div class="flex flex-col">
|
||||
<span class="font-bold">Priority Entry</span>
|
||||
<span class="text-xs opacity-60">
|
||||
Pin this entry ahead of the standard order.
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<label class="bg-surface-500/5 border-surface-500/10 flex items-center justify-between rounded-lg border p-3">
|
||||
<div class="flex flex-col">
|
||||
<span class="text-sm font-bold">Sort Order</span>
|
||||
<span class="text-xs opacity-60">
|
||||
Lower numbers appear earlier in lists.
|
||||
</span>
|
||||
</div>
|
||||
<input
|
||||
type="number"
|
||||
bind:value={tmp_entry_obj.sort}
|
||||
class="input input-sm w-24 text-right" />
|
||||
</label>
|
||||
|
||||
<label class={field_card_class}>
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={tmp_entry_obj.hide}
|
||||
onchange={() => {
|
||||
handle_update_entry();
|
||||
on_save();
|
||||
}}
|
||||
class="checkbox checkbox-primary" />
|
||||
<div class="flex flex-col">
|
||||
<span class="font-bold">Hidden</span>
|
||||
<span class="text-xs opacity-60">
|
||||
Hide from standard lists.
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class={panel_class}>
|
||||
<h2 class={panel_title_class}>
|
||||
<FingerprintPattern size="1.2em" class="text-primary-500" />
|
||||
Security and Privacy
|
||||
</h2>
|
||||
<div class="space-y-4 rounded-xl border border-surface-500/10 bg-surface-500/5 p-4">
|
||||
<label class="label flex flex-col items-start gap-1">
|
||||
<span class="text-sm font-bold opacity-70"
|
||||
>Passcode</span>
|
||||
<input
|
||||
type="password"
|
||||
bind:value={tmp_entry_obj.passcode_hash}
|
||||
class="input w-full"
|
||||
placeholder="journal_entry.passcode_hash"
|
||||
onchange={() => {
|
||||
handle_update_entry();
|
||||
on_save();
|
||||
}} />
|
||||
<span class="text-xs opacity-60">
|
||||
Stored on the entry as passcode_hash.
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<div class="space-y-2">
|
||||
<p class="text-xs font-semibold uppercase tracking-wider opacity-60">
|
||||
Visibility and audience
|
||||
</p>
|
||||
<AE_Object_Flags
|
||||
bind:obj={tmp_entry_obj}
|
||||
show_labels={false}
|
||||
on_toggle={() => {
|
||||
handle_update_entry();
|
||||
on_save();
|
||||
}}
|
||||
hide_alert={true}
|
||||
hide_private={journal?.cfg_json?.hide_btn_private}
|
||||
hide_public={journal?.cfg_json?.hide_btn_public}
|
||||
hide_personal={journal?.cfg_json?.hide_btn_personal}
|
||||
hide_professional={journal?.cfg_json
|
||||
?.hide_btn_professional}
|
||||
hide_template={true} />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -513,26 +536,23 @@ async function handle_admin_delete_action() {
|
||||
</section>
|
||||
{/if}
|
||||
|
||||
{#if $ae_loc.trusted_access || $ae_loc.manager_access || $ae_loc.administrator_access}
|
||||
<section class={panel_class}>
|
||||
<h2 class={panel_title_class}>
|
||||
<Settings size="1.2em" class="text-primary-500" />
|
||||
Admin
|
||||
</h2>
|
||||
<details class="rounded-xl border border-surface-500/20 bg-surface-500/5 shadow-sm">
|
||||
<summary class="flex cursor-pointer items-center gap-2 border-b border-surface-500/20 px-4 py-3 text-lg font-bold">
|
||||
<Settings size="1.2em" class="text-primary-500" />
|
||||
Admin
|
||||
</summary>
|
||||
<div class="space-y-4 p-4">
|
||||
<p class="text-xs opacity-60">
|
||||
Trusted access and above only. Notes are for staff
|
||||
use; managers and admins see Delete while trusted
|
||||
access sees Remove.
|
||||
Trusted access and above only. Notes are for staff use; managers and admins see Delete while trusted access sees Remove.
|
||||
</p>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
<label class="label">
|
||||
<span class="text-sm font-bold opacity-70"
|
||||
>Notes</span>
|
||||
<span class="text-sm font-bold opacity-70">Notes</span>
|
||||
<textarea
|
||||
bind:value={tmp_entry_obj.notes}
|
||||
class="textarea min-h-24"
|
||||
placeholder="Rarely used staff/admin note"
|
||||
placeholder="Rarely used special case admin/staff notes"
|
||||
onchange={() => {
|
||||
handle_update_entry();
|
||||
on_save();
|
||||
@@ -551,8 +571,9 @@ async function handle_admin_delete_action() {
|
||||
class="checkbox checkbox-primary" />
|
||||
<div class="flex flex-col">
|
||||
<span class="font-bold">Enabled</span>
|
||||
<span class="text-xs opacity-60"
|
||||
>Default access state for this entry</span>
|
||||
<span class="text-xs opacity-60">
|
||||
Allow default access for AE object type; essentially marked for deletion.
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
|
||||
@@ -573,8 +594,8 @@ async function handle_admin_delete_action() {
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{/if}
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
{:else if tab === 'json'}
|
||||
<div class="h-full min-h-100">
|
||||
@@ -605,4 +626,4 @@ async function handle_admin_delete_action() {
|
||||
Done
|
||||
</button>
|
||||
{/snippet}
|
||||
</Modal>
|
||||
</Modal>
|
||||
|
||||
Reference in New Issue
Block a user