proper asset creation/deletion, also raw file view in admin as well

This commit is contained in:
user
2026-03-01 18:22:49 +02:00
parent 6c2b917088
commit 9716deead7
10 changed files with 524 additions and 69 deletions

View File

@@ -0,0 +1,115 @@
<script lang="ts">
import Icon from "$lib/components/atoms/icon.svelte";
import MaxWidthWrapper from "$lib/components/molecules/max-width-wrapper.svelte";
import { Button } from "$lib/components/ui/button";
import * as Card from "$lib/components/ui/card";
import { Input } from "$lib/components/ui/input";
import * as Table from "$lib/components/ui/table";
import { mainNavTree } from "$lib/core/constants";
import { filesVM } from "$lib/domains/files/files.vm.svelte";
import { breadcrumbs } from "$lib/global.stores";
import FileArchive from "@lucide/svelte/icons/file-archive";
import RefreshCw from "@lucide/svelte/icons/refresh-cw";
import Search from "@lucide/svelte/icons/search";
import { onMount } from "svelte";
const filesNavItem = mainNavTree.find((item) => item.url === "/files");
breadcrumbs.set(filesNavItem ? [filesNavItem] : [{ title: "Files", url: "/files" }]);
onMount(async () => {
await filesVM.fetchFiles();
});
</script>
<MaxWidthWrapper cls="space-y-4">
<Card.Root>
<Card.Header>
<div class="flex items-center justify-between gap-4">
<div class="flex items-center gap-2">
<Icon icon={FileArchive} cls="h-5 w-5 text-primary" />
<Card.Title>Files</Card.Title>
<span class="text-muted-foreground text-xs">
{filesVM.total} total
</span>
</div>
<Button
variant="outline"
size="sm"
onclick={() => void filesVM.fetchFiles()}
disabled={filesVM.loading}
>
<Icon
icon={RefreshCw}
cls={`h-4 w-4 mr-2 ${filesVM.loading ? "animate-spin" : ""}`}
/>
Refresh
</Button>
</div>
<div class="relative mt-3 max-w-sm">
<Icon
icon={Search}
cls="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground"
/>
<Input
class="pl-10"
placeholder="Search by filename..."
bind:value={filesVM.search}
oninput={() => {
filesVM.page = 1;
void filesVM.fetchFiles();
}}
/>
</div>
</Card.Header>
<Card.Content>
{#if !filesVM.loading && filesVM.files.length === 0}
<div class="py-10 text-center text-sm text-muted-foreground">
No files found.
</div>
{:else}
<Table.Root>
<Table.Header>
<Table.Row>
<Table.Head>File</Table.Head>
<Table.Head>MIME</Table.Head>
<Table.Head>Size</Table.Head>
<Table.Head>Status</Table.Head>
<Table.Head>Uploaded</Table.Head>
<Table.Head>R2 URL</Table.Head>
</Table.Row>
</Table.Header>
<Table.Body>
{#each filesVM.files as item (item.id)}
<Table.Row>
<Table.Cell>
<div class="font-medium">{item.originalName}</div>
<div class="font-mono text-xs text-muted-foreground">
{item.id}
</div>
</Table.Cell>
<Table.Cell>{item.mimeType}</Table.Cell>
<Table.Cell>{filesVM.formatSize(item.size)}</Table.Cell>
<Table.Cell>{item.status}</Table.Cell>
<Table.Cell>
{new Date(item.uploadedAt).toLocaleString()}
</Table.Cell>
<Table.Cell>
<a
href={item.r2Url}
target="_blank"
rel="noreferrer"
class="text-xs text-primary underline"
>
Open
</a>
</Table.Cell>
</Table.Row>
{/each}
</Table.Body>
</Table.Root>
{/if}
</Card.Content>
</Card.Root>
</MaxWidthWrapper>