Files
Umbrella/frontend/src/routes/files/Index.svelte

213 lines
6.1 KiB
Svelte
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script>
import { onMount } from 'svelte';
import { useTinyRouter } from 'svelte-tiny-router';
import { api } from '../../urls.svelte';
import { error, yikes } from '../../warn.svelte';
import { t } from '../../translations.svelte';
import { user } from '../../user.svelte';
const image_extensions = ['jpg','jpeg','gif','png','svg','webp'];
const router = useTinyRouter();
let children = $state({});
let new_dir = $state(null);
let files = $state();
let parent = $state(false);
let form = $state(false);
let path = $state(null);
let delete_allowed = $state(false);
let available = $derived.by(isAvailable);
function isAvailable(){
if (!new_dir) return false;
if (children){
if (children.dirs) {
for (let key of Object.values(children.dirs)){
if (key == new_dir) return false;
}
}
if (children.files) {
for (let key of Object.values(children.files)){
if (key == new_dir) return false;
}
}
}
return true;
}
async function create_dir(ev){
ev.preventDefault();
ev.stopPropagation();
const url = api('files'+path+'/'+new_dir);
const res = await fetch(url,{
credentials: 'include',
method: 'POST'
});
if (res.ok) {
handleDirectory(res);
new_dir = null;
} else {
error(res);
}
return false;
}
function dropDir(p,name){
if (confirm(t('confirm_delete',{element:name})+"\n\n"+t('deletes_nested'))) dropElement(p);
}
async function dropElement(url){
const res = await fetch(url,{
credentials: 'include',
method: 'DELETE'
});
if (res.ok) {
handleDirectory(res);
} else {
error(res);
}
}
function dropFile(p,name){
if (confirm(t('confirm_delete',{element:name}))) dropElement(p);
}
async function handleDirectory(res){
let json = await res.json();
children.dirs = json.dirs ? json.dirs : {};
children.files = json.files ? json.files : {};
children.title = json.title ? json.title : path;
delete_allowed = json.delete;
yikes();
}
function is_image(file){
let parts = file.toLowerCase().split('.');
let ext = parts.pop();
return image_extensions.includes(ext);
}
async function loadChildren(p){
p = p.substring(6);
if (p == '') p = '/';
children = { dirs : {}, files : {}, title : p};
path = p;
if (p == '/'){
children.dirs[`/user/${user.id}`] = t('my_files');
children.dirs['/project'] = t('projects')
children.dirs['/company'] = t('companies');
parent = false;
form = false;
} else {
const url = api(`files${p}`);
const res = await fetch(url,{credentials:'include'});
if (res.ok){
parent = p.substring(0, p.lastIndexOf("/"));
if (parent == '/user'||p=='/project'||p=='/company') parent = '/';
form = !(p=='/company'||p=='/project'||p=='/user');
handleDirectory(res);
} else {
error(res);
}
}
}
function markdown(file){
let parts = file.split('/');
let md = `![${parts.pop()}](/api/files${file})`;
navigator.clipboard.writeText(md);
}
function onclick(ev){
ev.preventDefault();
ev.stopPropagation();
var target = ev.target;
while (target && !target.href) target=target.parentNode;
let href = target.getAttribute('href');
if (href) {
router.navigate(href);
loadChildren(href);
}
return false;
}
async function upload_file(ev){
ev.preventDefault();
const url = api('files'+path+'/'+files[0].name);
const resp = await fetch(url, {
credentials: 'include',
method: 'POST',
headers: {
"Content-Type": "application/unknown",
},
body: files[0]
});
if (resp.ok){
handleDirectory(resp);
files = null;
} else {
error(resp);
}
return false;
}
onMount(() => loadChildren(window.location.pathname));
</script>
<h1>{t('files')} {children?.title}</h1>
<ul>
{#if parent}
<li class="dir parent">
<span class="symbol"></span>
<a href={'/files'+parent} {onclick}>..</a>
</li>
{/if}
{#if children?.dirs}
{#each Object.entries(children.dirs) as [k,v]}
<li class="dir">
<span class="symbol"></span>
<a href={'/files'+k} {onclick}>{v}</a>
{#if delete_allowed}
<button class="symbol" onclick={e => dropDir(`/api/files${k}`,v)}></button>
{/if}
</li>
{/each}
{/if}
{#if form}
<li class="action">
<form onsubmit={create_dir} >
<span class="symbol">+</span>
<input type="text" bind:value={new_dir} />
<button type="submit" disabled={!available} >{t('create_new_object',{object:t('directory')})}</button>
</form>
</li>
{/if}
{#if children.files}
{#each Object.entries(children.files) as [k,v]}
<li class="file">
<span class="symbol"></span>
<a href={`/api/files${k}`} target="_blank">{v}</a>
{#if is_image(k)}
<button class="symbol" title={'markdown_code'} onclick={e => markdown(k)}></button>
{/if}
{#if delete_allowed}
<button class="symbol" title={t('delete_object',{'object':t('file')})} onclick={e => dropFile(`/api/files${k}`,v)}></button>
{/if}
</li>
{/each}
{/if}
{#if form}
<li class="action">
<form onsubmit={upload_file}>
<span class="symbol">+</span>
<input type="file" bind:files />
<button disabled={!files}>{t('upload_file')}</button>
</form>
</li>
{/if}
</ul>