Lots of work with linking files to Journal Entries.
This commit is contained in:
152
src/lib/ae_core/ae_comp__hosted_files_download_button.svelte
Normal file
152
src/lib/ae_core/ae_comp__hosted_files_download_button.svelte
Normal file
@@ -0,0 +1,152 @@
|
||||
<script lang="ts">
|
||||
// *** Import Svelte specific
|
||||
|
||||
// Eventually this should use Lucide icons instead of FontAwesome
|
||||
// import {
|
||||
// ArrowDown01, ArrowDown10, ArrowDownUp,
|
||||
// BookHeart, BriefcaseBusiness,
|
||||
// CalendarClock, CalendarOff, Clock, CodeXml, Copy,
|
||||
// Eye, EyeOff,
|
||||
// Flag, FlagOff, FileX, Fingerprint,
|
||||
// Globe, Group,
|
||||
// Hash, History,
|
||||
// LockKeyhole, LockKeyholeOpen,
|
||||
// MessageSquareWarning, Menu, Minus,
|
||||
// NotebookPen, NotebookText, NotepadTextDashed,
|
||||
// Pencil, PenLine, Plus,
|
||||
// RemoveFormatting,
|
||||
// Search, Settings,
|
||||
// Shapes, Share2, ShieldCheck, ShieldMinus, Siren, Skull,
|
||||
// SquareLibrary,
|
||||
// Tags, Trash2, TypeOutline,
|
||||
// X
|
||||
// } from '@lucide/svelte';
|
||||
|
||||
// *** Import Aether specific variables and functions
|
||||
import type { key_val } from '$lib/ae_stores';
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
import { api } from '$lib/api';
|
||||
import { ae_snip, ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
|
||||
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
hosted_file_id: null|string;
|
||||
hosted_file_obj: null|key_val;
|
||||
filename?: null|string;
|
||||
max_length?: number;
|
||||
auto_download?: boolean;
|
||||
linked_to_type?: null|string;
|
||||
linked_to_id?: null|string;
|
||||
download_complete?: null|boolean;
|
||||
download_percent?: number;
|
||||
download_status_msg?: string;
|
||||
classes?: string;
|
||||
}
|
||||
|
||||
let {
|
||||
log_lvl = 0,
|
||||
hosted_file_id,
|
||||
hosted_file_obj,
|
||||
filename = $bindable(null),
|
||||
max_length = $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'),
|
||||
classes = 'btn btn-sm lg:btn-md variant-ghost-tertiary hover:variant-filled-tertiary min-w-48'
|
||||
}: Props = $props();
|
||||
|
||||
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(() => {
|
||||
if ($ae_sess?.api_download_kv[hosted_file_obj?.hosted_file_id_random]?.percent_completed) {
|
||||
download_percent = $ae_sess.api_download_kv[hosted_file_obj?.hosted_file_id_random].percent_completed;
|
||||
}
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
{#if hosted_file_id && hosted_file_obj}
|
||||
<button
|
||||
type="button"
|
||||
disabled={!$ae_loc.trusted_access}
|
||||
class="{classes ?? 'btn'}"
|
||||
onclick={() => {
|
||||
download_complete = false;
|
||||
download_status_msg = 'Downloading...';
|
||||
ae_promises[hosted_file_obj.hosted_file_id_random] = api.download_hosted_file({
|
||||
api_cfg: $ae_api,
|
||||
hosted_file_id: hosted_file_obj.hosted_file_id_random,
|
||||
return_file: true,
|
||||
filename: filename ?? hosted_file_obj.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;
|
||||
});
|
||||
}}
|
||||
|
||||
title={`Download this file:\n${filename ?? hosted_file_obj.filename}\n[API] SHA256: ${hosted_file_obj?.hash_sha256.slice(0, 10)}...\nHosted ID: ${hosted_file_obj.hosted_file_id_random}\n Linked to: ${linked_to_type} ID: ${linked_to_id}`}
|
||||
>
|
||||
{#await ae_promises[hosted_file_obj.hosted_file_id_random]}
|
||||
<span class="fas fa-spinner fa-spin mx-1"></span>
|
||||
<span class="">
|
||||
Downloading
|
||||
{#if $ae_sess.api_download_kv[hosted_file_obj.hosted_file_id_random]}
|
||||
{$ae_sess.api_download_kv[hosted_file_obj.hosted_file_id_random].percent_completed}%
|
||||
{/if}
|
||||
:
|
||||
</span>
|
||||
{:then}
|
||||
<span class="fas fa-{ae_util.file_extension_icon(hosted_file_obj?.extension)}"></span>
|
||||
|
||||
{/await}
|
||||
|
||||
{#if download_complete === null}
|
||||
<span class="text-red-800 dark:text-red-200">File not found</span>
|
||||
{:else if download_complete === false}
|
||||
<span class="text-red-800 dark:text-red-200">Failed to download!</span>
|
||||
{/if}
|
||||
|
||||
<span class="grow">
|
||||
{ae_util.shorten_filename({filename: filename ?? hosted_file_obj?.filename, max_length: max_length})}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
{:else}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
disabled
|
||||
class="{classes ?? 'btn'}"
|
||||
title="No file selected"
|
||||
>
|
||||
<span class="fas fa-{ae_util.file_extension_icon(hosted_file_obj?.extension)}"></span>
|
||||
<span class="grow">
|
||||
No file info
|
||||
</span>
|
||||
</button>
|
||||
|
||||
{/if}
|
||||
@@ -58,7 +58,7 @@ export interface Journal {
|
||||
|
||||
cfg_json?: null|key_val; // This is the configuration JSON for the journal
|
||||
|
||||
data_json?: null|string; // We always need to store something extra...
|
||||
data_json?: null|key_val; // We always need to store something extra...
|
||||
|
||||
ux_mode?: null|string; // 'mobile' or 'desktop'
|
||||
|
||||
@@ -229,7 +229,7 @@ export interface Journal_Entry {
|
||||
related_entry_id_li?: null|key_val; // List of related journal entry IDs
|
||||
|
||||
// cfg_json?: null|key_val; // This is the configuration JSON for the journal entry
|
||||
data_json?: null|string; // We always need to store something extra...
|
||||
data_json?: null|key_val; // We always need to store something extra...
|
||||
|
||||
// This only allows for basic access to the content.
|
||||
passcode_read?: null|string; // For LLM (AI) generated summary...???
|
||||
|
||||
@@ -99,7 +99,8 @@ ae_tmp.show__direct_download = $ae_loc.core?.show__direct_download ?? false;
|
||||
hidden: 'not_hidden',
|
||||
limit: 250,
|
||||
// params: params,
|
||||
try_cache: true
|
||||
try_cache: true,
|
||||
log_lvl: 2
|
||||
});
|
||||
|
||||
// ae_tmp.show__file_li = false;
|
||||
|
||||
307
src/routes/journals/ae_comp__journal_entry_obj_file_li.svelte
Normal file
307
src/routes/journals/ae_comp__journal_entry_obj_file_li.svelte
Normal file
@@ -0,0 +1,307 @@
|
||||
<script lang="ts">
|
||||
|
||||
// *** Import Aether specific variables and functions
|
||||
import type { key_val } from '$lib/ae_stores';
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
import { core_func } from '$lib/ae_core/ae_core_functions';
|
||||
import { ae_snip, ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
|
||||
import { journals_loc, journals_sess, journals_slct, journals_trig, journals_prom } from '$lib/ae_journals/ae_journals_stores';
|
||||
import { journals_func } from '$lib/ae_journals/ae_journals_functions';
|
||||
|
||||
import Comp_hosted_files_upload from '$lib/ae_core/ae_comp__hosted_files_upload.svelte';
|
||||
import Element_manage_hosted_file_li_wrap from '$lib/element_manage_hosted_file_li_all.svelte';
|
||||
|
||||
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
link_to_type: string;
|
||||
link_to_id: string;
|
||||
lq__journal_entry_obj: any;
|
||||
}
|
||||
|
||||
let {
|
||||
log_lvl = 0,
|
||||
link_to_type,
|
||||
link_to_id,
|
||||
lq__journal_entry_obj,
|
||||
}: Props = $props();
|
||||
|
||||
let ae_promises: key_val = $state({});
|
||||
let hosted_file_kv: key_val = $state($lq__journal_entry_obj?.data_json?.hosted_file_kv ?? {}); // WARNING: This does no seem to set soon enough. Added an effect to set it as a backup.
|
||||
// let hosted_file_li: [string, any][] = $state([]);
|
||||
let hosted_file_obj_li: any[] = $state($lq__journal_entry_obj?.data_json?.hosted_file_obj_li ?? []);
|
||||
let hosted_file_id_li: string[] = $state([]);
|
||||
let upload_complete: boolean = $state(false);
|
||||
|
||||
let slct_hosted_file_kv: key_val = $state({});
|
||||
let slct_hosted_file_id: string|null = $state(null);
|
||||
let slct_hosted_file_obj: any = $state(null);
|
||||
|
||||
let rem_hosted_file_id: string|null = $state(null);
|
||||
|
||||
async function update_journal_entry() {
|
||||
// hosted_file_kv = lq__journal_entry_obj.data_json.hosted_file_kv;
|
||||
// hosted_file_obj_li = [... $lq__journal_entry_obj?.data_json?.hosted_file_obj_li];
|
||||
// hosted_file_kv = {
|
||||
// ...$lq__journal_entry_obj?.data_json?.hosted_file_kv,
|
||||
// };
|
||||
|
||||
let data_kv: key_val = {'data_json' : $lq__journal_entry_obj?.data_json ?? {}};
|
||||
|
||||
data_kv.data_json = {
|
||||
hosted_file_kv: hosted_file_kv,
|
||||
// ...$lq__journal_entry_obj?.data_json,
|
||||
// hosted_file_kv: {
|
||||
// ...slct_hosted_file_kv,
|
||||
// },
|
||||
// hosted_file_obj_li: hosted_file_obj_li
|
||||
};
|
||||
console.log('data_kv', data_kv);
|
||||
|
||||
try {
|
||||
const response = await journals_func.update_ae_obj__journal_entry({
|
||||
api_cfg: $ae_api,
|
||||
journal_entry_id: $lq__journal_entry_obj?.journal_entry_id,
|
||||
data_kv: data_kv,
|
||||
log_lvl: 1,
|
||||
});
|
||||
console.log('Journal entry updated successfully:', response);
|
||||
} catch (error) {
|
||||
console.error('Error updating journal entry:', error);
|
||||
alert('Failed to update journal entry.');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
$effect(() => {
|
||||
// if ($lq__journal_entry_obj && Object.keys(slct_hosted_file_kv ?? {}).length && slct_hosted_file_kv != hosted_file_kv) {
|
||||
// hosted_file_kv = {
|
||||
// hosted_file_kv,
|
||||
// ...slct_hosted_file_kv
|
||||
// };
|
||||
// console.log('hosted_file_kv', hosted_file_kv);
|
||||
// slct_hosted_file_kv = {};
|
||||
// update_journal_entry();
|
||||
// }
|
||||
|
||||
if (!Object.keys(hosted_file_kv ?? {}).length && $lq__journal_entry_obj?.data_json?.hosted_file_kv) {
|
||||
hosted_file_kv = $lq__journal_entry_obj?.data_json?.hosted_file_kv;
|
||||
}
|
||||
|
||||
if ($lq__journal_entry_obj && slct_hosted_file_id && slct_hosted_file_obj) {
|
||||
hosted_file_kv = {
|
||||
...hosted_file_kv,
|
||||
[slct_hosted_file_id]: slct_hosted_file_obj
|
||||
};
|
||||
slct_hosted_file_id = null;
|
||||
slct_hosted_file_obj = null;
|
||||
|
||||
update_journal_entry();
|
||||
|
||||
// slct_hosted_file_obj = $lq__journal_entry_obj?.data_json?.hosted_file_obj_li?.find((obj: any) => obj.hosted_file_id == slct_hosted_file_id);
|
||||
// console.log('slct_hosted_file_obj', slct_hosted_file_obj);
|
||||
}
|
||||
|
||||
if ($lq__journal_entry_obj && rem_hosted_file_id) {
|
||||
console.log('rem_hosted_file_id', rem_hosted_file_id);
|
||||
|
||||
delete hosted_file_kv[rem_hosted_file_id];
|
||||
rem_hosted_file_id = null;
|
||||
update_journal_entry();
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<section
|
||||
class:hidden={!$ae_loc.edit_mode}
|
||||
class="ae_section journal_entry__hosted_file border border-gray-200 rounded p-2 space-y-2"
|
||||
>
|
||||
|
||||
<h3 class="h3">Upload/Manage Hosted File</h3>
|
||||
|
||||
<!-- {Object.keys($lq__journal_entry_obj?.data_json?.hosted_file_kv ?? {}).length} selected -->
|
||||
<!-- {Object.keys(hosted_file_kv ?? {}).length} selected -->
|
||||
<!-- {Object.keys(slct_hosted_file_kv ?? {}).length} to add -->
|
||||
|
||||
|
||||
|
||||
|
||||
{#if $ae_loc.trusted_access}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm variant-ghost-warning hover:variant-filled-warning float-right"
|
||||
title="Toggle between Upload and Select from Hosted Files"
|
||||
onclick={() => {
|
||||
if ($ae_sess.files.add_to_use_files_method == 'upload') {
|
||||
$ae_sess.files.add_to_use_files_method = 'select';
|
||||
} else {
|
||||
$ae_sess.files.add_to_use_files_method = 'upload';
|
||||
}
|
||||
}}
|
||||
>
|
||||
<span class="fas fa-exchange-alt m-1"></span>
|
||||
Upload/Select
|
||||
</button>
|
||||
|
||||
<div
|
||||
class:hidden={$ae_sess.files.add_to_use_files_method != 'upload'}
|
||||
class="upload"
|
||||
>
|
||||
<Comp_hosted_files_upload
|
||||
class_li="border border-gray-300 rounded-md p-2 bg-gray-100 hover:bg-gray-200"
|
||||
link_to_type={link_to_type}
|
||||
link_to_id={link_to_id}
|
||||
bind:hosted_file_id_li={hosted_file_id_li}
|
||||
bind:hosted_file_obj_li={hosted_file_obj_li}
|
||||
bind:upload_complete={upload_complete}
|
||||
log_lvl={log_lvl}
|
||||
>
|
||||
{#snippet label()}
|
||||
<span >
|
||||
<div>
|
||||
<span class="fas fa-upload"></span>
|
||||
<strong class="bg-green-100 p-1">Upload Journal Entry files</strong>
|
||||
</div>
|
||||
<span class="text-sm text-gray-600 dark:text-gray-400 italic">
|
||||
<strong>Aether hosted files only</strong>
|
||||
</span>
|
||||
</span>
|
||||
{/snippet}
|
||||
</Comp_hosted_files_upload>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class:hidden={$ae_sess.files.add_to_use_files_method != 'select'}
|
||||
class=""
|
||||
>
|
||||
<!-- link_to_type={'journal_entry'} -->
|
||||
<!-- link_to_id={$lq__journal_entry_obj?.journal_entry_id} -->
|
||||
<Element_manage_hosted_file_li_wrap
|
||||
link_to_type={'account'}
|
||||
link_to_id={$ae_loc?.account_id}
|
||||
allow_basic={true}
|
||||
allow_moderator={true}
|
||||
class_li={''}
|
||||
bind:slct_hosted_file_kv={slct_hosted_file_kv}
|
||||
bind:slct_hosted_file_id={slct_hosted_file_id}
|
||||
bind:slct_hosted_file_obj={slct_hosted_file_obj}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if !Object.keys(hosted_file_kv ?? {}).length}
|
||||
No file(s) uploaded yet.
|
||||
{:else}
|
||||
<!-- {Object.keys(hosted_file_kv ?? {}).length} -->
|
||||
<!-- <pre>
|
||||
{JSON.stringify(hosted_file_kv)}
|
||||
</pre> -->
|
||||
|
||||
{#each Object.entries(hosted_file_kv) as [hosted_file_id, hosted_file_obj]}
|
||||
<div
|
||||
class="flex flex-row flex-wrap gap-1 items-center justify-center w-full"
|
||||
>
|
||||
|
||||
<label for="filename" class="flex-grow">
|
||||
<span class="text-sm text-gray-600 dark:text-gray-400 italic">
|
||||
<span class="fas fa-file-alt"></span>
|
||||
<strong class="bg-green-100 p-1">Filename</strong>
|
||||
</span>
|
||||
<input type="text" id="filename" name="filename" value={(hosted_file_obj?.filename ? hosted_file_obj?.filename : 'unknown')} class="input w-full">
|
||||
</label>
|
||||
|
||||
<label for="extension max-w-20">
|
||||
<span class="text-sm text-gray-600 dark:text-gray-400 italic">
|
||||
<span class="fas fa-file-code"></span>
|
||||
<strong class="bg-green-100 p-1">File Extension</strong>
|
||||
{#if !$ae_loc.administrator_access}
|
||||
<span class="fas fa-lock" title="Field is locked"></span>
|
||||
{:else}
|
||||
<span class="fas fa-unlock" title="Field is unlocked"></span>
|
||||
{/if}
|
||||
</span>
|
||||
<input
|
||||
type="text"
|
||||
id="extension"
|
||||
name="extension"
|
||||
value={(hosted_file_obj?.extension ? hosted_file_obj?.extension : 'ext')}
|
||||
readonly={!$ae_loc.administrator_access}
|
||||
class="input w-full max-w-20"
|
||||
>
|
||||
</label>
|
||||
|
||||
<button
|
||||
disabled={!$ae_loc.administrator_access}
|
||||
type="button"
|
||||
onclick={() => {
|
||||
if (confirm('Are you sure you want to remove the file?')) {
|
||||
// First - Attempt to delete the hosted file
|
||||
ae_promises.journal_entry_obj__hosted_file = core_func.delete_ae_obj_id__hosted_file({
|
||||
api_cfg: $ae_api,
|
||||
hosted_file_id: hosted_file_id,
|
||||
link_to_type: link_to_type,
|
||||
link_to_id: link_to_id,
|
||||
rm_orphan: true,
|
||||
fake_delete: true,
|
||||
log_lvl: log_lvl
|
||||
})
|
||||
.then(function (delete_result) {
|
||||
// Second - If deleted, then update the journal_entry_obj
|
||||
console.log(`File removed. Now update the journal_entry_obj`);
|
||||
|
||||
rem_hosted_file_id = hosted_file_id;
|
||||
// update_journal_entry();
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log('Something went wrong.');
|
||||
console.log(error);
|
||||
return false;
|
||||
})
|
||||
.finally(() => {
|
||||
// We need to do all of this since the DB object has changed and the SLCT object does automatically update (yet...??? Svelte 5?).
|
||||
slct_hosted_file_obj.hosted_file_id = null;
|
||||
slct_hosted_file_obj.file_path = null;
|
||||
slct_hosted_file_obj.filename = null;
|
||||
slct_hosted_file_obj.file_extension = null;
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
}}
|
||||
class="btn btn-sm variant-soft-error"
|
||||
>
|
||||
{#await ae_promises.journal_entry_obj__hosted_file}
|
||||
<span class="fas fa-spinner fa-spin m-1"></span>
|
||||
{:then}
|
||||
<span class="fas fa-trash-alt m-1"></span>
|
||||
Remove File
|
||||
{/await}
|
||||
<!-- <span class="fas fa-trash-alt m-1"></span>
|
||||
Remove File -->
|
||||
</button>
|
||||
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
<!-- <label for="file_path">File Path
|
||||
{#if !$ae_loc.administrator_access}
|
||||
<span class="fas fa-lock" title="Field is locked"></span>
|
||||
{:else}
|
||||
<span class="fas fa-unlock" title="Field is unlocked"></span>
|
||||
{/if}
|
||||
<input
|
||||
type="text"
|
||||
id="file_path"
|
||||
name="file_path"
|
||||
value={(slct_hosted_file_obj.file_path ? slct_hosted_file_obj.file_path : '')}
|
||||
readonly={!$ae_loc.administrator_access}
|
||||
class="input w-full"
|
||||
>
|
||||
</label> -->
|
||||
|
||||
{/if}
|
||||
|
||||
</section>
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
BookHeart, BriefcaseBusiness,
|
||||
CalendarClock, CalendarOff, Clock, CodeXml, Copy,
|
||||
Eye, EyeOff,
|
||||
Flag, FlagOff, FileX, Fingerprint,
|
||||
Flag, FlagOff, FileDown, FileX, Fingerprint,
|
||||
Globe, Group,
|
||||
Hash, History,
|
||||
LockKeyhole, LockKeyholeOpen,
|
||||
@@ -36,11 +36,14 @@ import E_app_codemirror_v5 from '$lib/e_app_codemirror_v5.svelte';
|
||||
import type { key_val } from '$lib/ae_stores';
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
import { core_func } from '$lib/ae_core/ae_core_functions';
|
||||
import { api } from '$lib/api';
|
||||
import { ae_snip, ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
|
||||
import { journals_loc, journals_sess, journals_slct, journals_trig, journals_prom } from '$lib/ae_journals/ae_journals_stores';
|
||||
import { journals_func } from '$lib/ae_journals/ae_journals_functions';
|
||||
import Comp_journal_entry_file_li from './ae_comp__journal_entry_obj_file_li.svelte';
|
||||
import Comp_hosted_files_upload from '$lib/ae_core/ae_comp__hosted_files_upload.svelte';
|
||||
import Element_manage_hosted_file_li_wrap from '$lib/element_manage_hosted_file_li_all.svelte';
|
||||
import Comp_hosted_files_download_button from '$lib/ae_core/ae_comp__hosted_files_download_button.svelte';
|
||||
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
@@ -305,10 +308,10 @@ async function update_journal_entry() {
|
||||
// log_lvl = 1;
|
||||
|
||||
// append slct_hosted_file_kv to data_json.hosted_file_kv
|
||||
if (!tmp_entry_obj.data_json.hosted_file_kv) {
|
||||
tmp_entry_obj.data_json.hosted_file_kv = {};
|
||||
}
|
||||
tmp_entry_obj.data_json.hosted_file_kv = $journals_loc.entry.hosted_file_kv;
|
||||
// if (!tmp_entry_obj.data_json.hosted_file_kv) {
|
||||
// tmp_entry_obj.data_json.hosted_file_kv = {};
|
||||
// }
|
||||
// tmp_entry_obj.data_json.hosted_file_kv = $journals_loc.entry.hosted_file_kv;
|
||||
|
||||
let data_kv: key_val = {
|
||||
alert: tmp_entry_obj?.alert,
|
||||
@@ -2266,198 +2269,40 @@ tabindex={$ae_loc.edit_mode ? 0 : -1} -->
|
||||
{/if}
|
||||
|
||||
|
||||
<hr class="divider my-2" />
|
||||
|
||||
|
||||
{#if $lq__journal_entry_obj?.journal_entry_id}
|
||||
<section
|
||||
class:hidden={!$ae_loc.edit_mode}
|
||||
class="ae_section journal_entry__hosted_file border border-gray-200 rounded p-2 space-y-2"
|
||||
>
|
||||
<Comp_journal_entry_file_li
|
||||
log_lvl={log_lvl}
|
||||
link_to_type="journal_entry"
|
||||
link_to_id={$lq__journal_entry_obj?.journal_entry_id}
|
||||
lq__journal_entry_obj={lq__journal_entry_obj}
|
||||
/>
|
||||
|
||||
<h3 class="h3">Upload/Manage Hosted File</h3>
|
||||
<!-- Object.keys(hosted_file_kv ?? {}).length -->
|
||||
{#if $lq__journal_entry_obj?.data_json?.hosted_file_kv}
|
||||
<div class="flex flex-row flex-wrap gap-1 items-center justify-center w-full">
|
||||
<span class="">
|
||||
<!-- <SquareDownload size="1em" class="mx-1 inline-block"/> -->
|
||||
<FileDown size="1em" class="mx-1 inline-block" />
|
||||
<span class="text-sm text-gray-500 hidden sm:inline">
|
||||
Download Files:
|
||||
</span>
|
||||
</span>
|
||||
|
||||
{#if !tmp_entry_obj?.data_json?.hosted_file_kv}
|
||||
No file(s) uploaded yet.
|
||||
{#each Object.entries($lq__journal_entry_obj?.data_json?.hosted_file_kv) as [key, hosted_file_obj]}
|
||||
|
||||
{#if $ae_loc.trusted_access}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm variant-ghost-warning hover:variant-filled-warning float-right"
|
||||
title="Toggle between Upload and Select from Hosted Files"
|
||||
onclick={() => {
|
||||
if ($ae_sess.files.add_to_use_files_method == 'upload') {
|
||||
$ae_sess.files.add_to_use_files_method = 'select';
|
||||
} else {
|
||||
$ae_sess.files.add_to_use_files_method = 'upload';
|
||||
}
|
||||
}}
|
||||
>
|
||||
<span class="fas fa-exchange-alt m-1"></span>
|
||||
Upload/Select
|
||||
</button>
|
||||
|
||||
<div
|
||||
class:hidden={$ae_sess.files.add_to_use_files_method != 'upload'}
|
||||
class="upload"
|
||||
>
|
||||
<Comp_hosted_files_upload
|
||||
class_li="border border-gray-300 rounded-md p-2 bg-gray-100 hover:bg-gray-200"
|
||||
link_to_type="journal_entry"
|
||||
link_to_id={tmp_entry_obj.journal_entry_id}
|
||||
bind:hosted_file_id_li={tmp_entry_obj.hosted_file_id_li}
|
||||
bind:hosted_file_obj_li={tmp_entry_obj.hosted_file_obj_li}
|
||||
bind:upload_complete={tmp_entry_obj.upload_complete}
|
||||
log_lvl={log_lvl}
|
||||
>
|
||||
{#snippet label()}
|
||||
<span >
|
||||
<div>
|
||||
<span class="fas fa-upload"></span>
|
||||
<strong class="bg-green-100 p-1">Upload Journal Entry files</strong>
|
||||
</div>
|
||||
<span class="text-sm text-gray-600 dark:text-gray-400 italic">
|
||||
<strong>Aether hosted files only</strong>
|
||||
</span>
|
||||
</span>
|
||||
{/snippet}
|
||||
</Comp_hosted_files_upload>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class:hidden={$ae_sess.files.add_to_use_files_method != 'select'}
|
||||
class=""
|
||||
>
|
||||
<!-- link_to_type={'journal_entry'} -->
|
||||
<!-- link_to_id={$lq__journal_entry_obj?.journal_entry_id} -->
|
||||
<Element_manage_hosted_file_li_wrap
|
||||
link_to_type={'account'}
|
||||
link_to_id={$ae_loc?.account_id}
|
||||
allow_basic={true}
|
||||
allow_moderator={true}
|
||||
class_li={''}
|
||||
bind:slct_hosted_file_kv={slct_hosted_file_kv}
|
||||
bind:slct_hosted_file_id={slct_hosted_file_id}
|
||||
bind:slct_hosted_file_obj={slct_hosted_file_obj}
|
||||
/>
|
||||
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{:else}
|
||||
|
||||
<button
|
||||
disabled={!$ae_loc.administrator_access}
|
||||
type="button"
|
||||
onclick={() => {
|
||||
if (confirm('Are you sure you want to remove the file?')) {
|
||||
|
||||
|
||||
// First - Attempt to delete the hosted file
|
||||
ae_promises.journal_entry_obj__hosted_file = core_func.delete_ae_obj_id__hosted_file({
|
||||
api_cfg: $ae_api,
|
||||
hosted_file_id: tmp_entry_obj.hosted_file_id,
|
||||
link_to_type: 'journal_entry',
|
||||
link_to_id: $lq__journal_entry_obj?.journal_entry_id,
|
||||
rm_orphan: true,
|
||||
fake_delete: false,
|
||||
log_lvl: log_lvl
|
||||
})
|
||||
.then(function (delete_result) {
|
||||
// Second - If deleted, then update the journal_entry_obj
|
||||
console.log(`File removed. Now update the journal_entry_obj`);
|
||||
|
||||
update_journal_entry();
|
||||
|
||||
// ae_promises.journal_entry_obj = archives_func.update_ae_obj__journal_entry({
|
||||
// api_cfg: $ae_api,
|
||||
// journal_entry_id: $lq__journal_entry_obj?.journal_entry_id,
|
||||
// data_kv: {
|
||||
// hosted_file_id_random: null,
|
||||
// file_path: null,
|
||||
// filename: null,
|
||||
// file_extension: null,
|
||||
// journal_entry_type: null,
|
||||
// },
|
||||
// log_lvl: log_lvl
|
||||
// })
|
||||
// .then(function (journal_entry_obj_update_result) {
|
||||
// // We need to do all of this since the DB object has changed and the SLCT object does automatically update (yet...??? Svelte 5?).
|
||||
// // tmp_entry_obj = $lq__journal_entry_obj;
|
||||
// })
|
||||
// .catch(function (error) {
|
||||
// console.log('Something went wrong.');
|
||||
// console.log(error);
|
||||
// return false;
|
||||
// });
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.log('Something went wrong.');
|
||||
console.log(error);
|
||||
return false;
|
||||
})
|
||||
.finally(() => {
|
||||
// We need to do all of this since the DB object has changed and the SLCT object does automatically update (yet...??? Svelte 5?).
|
||||
tmp_entry_obj.hosted_file_id = null;
|
||||
tmp_entry_obj.file_path = null;
|
||||
tmp_entry_obj.filename = null;
|
||||
tmp_entry_obj.file_extension = null;
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}}
|
||||
class="novi_btn btn btn-sm variant-soft-error float-right"
|
||||
>
|
||||
{#await ae_promises.journal_entry_obj__hosted_file}
|
||||
<span class="fas fa-spinner fa-spin m-1"></span>
|
||||
{:then}
|
||||
<span class="fas fa-trash-alt m-1"></span>
|
||||
Remove File
|
||||
{/await}
|
||||
<!-- <span class="fas fa-trash-alt m-1"></span>
|
||||
Remove File -->
|
||||
</button>
|
||||
|
||||
<!-- <label for="file_path">File Path
|
||||
{#if !$ae_loc.administrator_access}
|
||||
<span class="fas fa-lock" title="Field is locked"></span>
|
||||
{:else}
|
||||
<span class="fas fa-unlock" title="Field is unlocked"></span>
|
||||
{/if}
|
||||
<input
|
||||
type="text"
|
||||
id="file_path"
|
||||
name="file_path"
|
||||
value={(tmp_entry_obj.file_path ? tmp_entry_obj.file_path : '')}
|
||||
readonly={!$ae_loc.administrator_access}
|
||||
class="input w-full"
|
||||
>
|
||||
</label> -->
|
||||
|
||||
<label for="filename">Filename
|
||||
<input type="text" id="filename" name="filename" value={(tmp_entry_obj.filename ? tmp_entry_obj.filename : 'unknown')} class="input w-full">
|
||||
</label>
|
||||
|
||||
<label for="file_extension">File Extension
|
||||
{#if !$ae_loc.administrator_access}
|
||||
<span class="fas fa-lock" title="Field is locked"></span>
|
||||
{:else}
|
||||
<span class="fas fa-unlock" title="Field is unlocked"></span>
|
||||
{/if}
|
||||
<input
|
||||
type="text"
|
||||
id="file_extension"
|
||||
name="file_extension"
|
||||
value={(tmp_entry_obj.file_extension ? tmp_entry_obj.file_extension : 'ext')}
|
||||
readonly={!$ae_loc.administrator_access}
|
||||
class="input w-24"
|
||||
>
|
||||
</label>
|
||||
<Comp_hosted_files_download_button
|
||||
hosted_file_id={hosted_file_obj?.hosted_file_id_random ?? ''}
|
||||
hosted_file_obj={hosted_file_obj}
|
||||
linked_to_type="journal_entry"
|
||||
linked_to_id={$lq__journal_entry_obj?.journal_entry_id}
|
||||
/>
|
||||
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
{:else}
|
||||
<section
|
||||
class="ae_section journal_entry__hosted_file border border-gray-200 rounded p-2 space-y-2"
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Modal } from 'flowbite-svelte';
|
||||
import {
|
||||
CalendarClock, Check, CodeXml, Copy,
|
||||
Eye, EyeOff,
|
||||
FileLock, Fingerprint, Flag, FlagOff,
|
||||
FileLock, Files, Fingerprint, Flag, FlagOff,
|
||||
Group,
|
||||
ListPlus, Lock,
|
||||
NotebookPen, NotebookText, NotepadTextDashed,
|
||||
@@ -343,12 +343,28 @@ $effect(() => {
|
||||
</span>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="flex flex-row flex-wrap gap-2 items-center justify-end">
|
||||
<!-- Linked file count -->
|
||||
<div
|
||||
class="ae_linked_file_count flex flex-row flex-wrap gap-0.5 items-center justify-start"
|
||||
class:hidden={!journals_journal_entry_obj?.data_json?.hosted_file_kv}
|
||||
>
|
||||
<Files class="mx-1 inline-block" />
|
||||
<span class="text-xs text-gray-500 hidden md:inline">Linked files:</span>
|
||||
<span class="font-semibold text-sm text-gray-500">
|
||||
{journals_journal_entry_obj?.data_json?.hosted_file_kv
|
||||
? Object.keys(journals_journal_entry_obj?.data_json?.hosted_file_kv).length
|
||||
: 0}×
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Tags for journal entry. Comma delimited list. -->
|
||||
{#if journals_journal_entry_obj.tags && journals_journal_entry_obj.tags.length}
|
||||
<div class="tags flex flex-wrap gap-1 items-center justify-start p-1">
|
||||
<div class="tags flex flex-row flex-wrap gap-0.5 items-center justify-start p-1">
|
||||
<Tags class="mx-1 inline-block"/>
|
||||
<span class="text-sm text-gray-500 hidden md:inline">Tags:</span>
|
||||
<span class="text-xs text-gray-500 hidden md:inline">Tags:</span>
|
||||
|
||||
{#each journals_journal_entry_obj.tags.split(',') as tag}
|
||||
<span
|
||||
|
||||
Reference in New Issue
Block a user