Merge branch 'development' into f094_create_tests

This commit is contained in:
2025-09-03 13:05:02 +02:00
9 changed files with 126 additions and 88 deletions

2
.gitignore vendored
View File

@@ -2,6 +2,8 @@ test-results
node_modules node_modules
config.json config.json
src/lib/data/tatort.db
# Output # Output
.output .output
.vercel .vercel

33
package-lock.json generated
View File

@@ -1479,6 +1479,12 @@
"win32" "win32"
] ]
}, },
"node_modules/@standard-schema/spec": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
"integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==",
"license": "MIT"
},
"node_modules/@sveltejs/acorn-typescript": { "node_modules/@sveltejs/acorn-typescript": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz", "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz",
@@ -1502,9 +1508,9 @@
} }
}, },
"node_modules/@sveltejs/adapter-node": { "node_modules/@sveltejs/adapter-node": {
"version": "5.2.13", "version": "5.3.1",
"resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-5.2.13.tgz", "resolved": "https://registry.npmjs.org/@sveltejs/adapter-node/-/adapter-node-5.3.1.tgz",
"integrity": "sha512-yS2TVFmIrxjGhYaV5/iIUrJ3mJl6zjaYn0lBD70vTLnYvJeqf3cjvLXeXCUCuYinhSBoyF4DpfGla49BnIy7sQ==", "integrity": "sha512-PSoGfa9atkmuixe7jvuS2tsUohVZF20So87ASzfMRGTTNqEd8s48KAodlv3CzHwq9XO/BM8KsQLpqqsr/6dmuA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@rollup/plugin-commonjs": "^28.0.1", "@rollup/plugin-commonjs": "^28.0.1",
@@ -1517,16 +1523,17 @@
} }
}, },
"node_modules/@sveltejs/kit": { "node_modules/@sveltejs/kit": {
"version": "2.26.0", "version": "2.37.0",
"resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.26.0.tgz", "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.37.0.tgz",
"integrity": "sha512-TUxMYoK6Yim4uRIW0L7TXtlEtyLchy90PmInI7d1lPAPMchkBEvN3nVMkn5iTMUobxdLE5nR/YEU/4aYqezMuQ==", "integrity": "sha512-xgKtpjQ6Ry4mdShd01ht5AODUsW7+K1iValPDq7QX8zI1hWOKREH9GjG8SRCN5tC4K7UXmMhuQam7gbLByVcnw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@standard-schema/spec": "^1.0.0",
"@sveltejs/acorn-typescript": "^1.0.5", "@sveltejs/acorn-typescript": "^1.0.5",
"@types/cookie": "^0.6.0", "@types/cookie": "^0.6.0",
"acorn": "^8.14.1", "acorn": "^8.14.1",
"cookie": "^0.6.0", "cookie": "^0.6.0",
"devalue": "^5.1.0", "devalue": "^5.3.2",
"esm-env": "^1.2.2", "esm-env": "^1.2.2",
"kleur": "^4.1.5", "kleur": "^4.1.5",
"magic-string": "^0.30.5", "magic-string": "^0.30.5",
@@ -1542,9 +1549,15 @@
"node": ">=18.13" "node": ">=18.13"
}, },
"peerDependencies": { "peerDependencies": {
"@opentelemetry/api": "^1.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0", "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0",
"svelte": "^4.0.0 || ^5.0.0-next.0", "svelte": "^4.0.0 || ^5.0.0-next.0",
"vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0" "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0"
},
"peerDependenciesMeta": {
"@opentelemetry/api": {
"optional": true
}
} }
}, },
"node_modules/@sveltejs/vite-plugin-svelte": { "node_modules/@sveltejs/vite-plugin-svelte": {
@@ -3139,9 +3152,9 @@
} }
}, },
"node_modules/devalue": { "node_modules/devalue": {
"version": "5.1.1", "version": "5.3.2",
"resolved": "https://registry.npmjs.org/devalue/-/devalue-5.1.1.tgz", "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.3.2.tgz",
"integrity": "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==", "integrity": "sha512-UDsjUbpQn9kvm68slnrs+mfxwFkIflOhkanmyabZ8zOYk8SMEIbJ3TK+88g70hSIeytu4y18f0z/hYHMTrXIWw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/didyoumean": { "node_modules/didyoumean": {

View File

@@ -0,0 +1 @@
<p class="flex justify-center m-4">In dieser Liste sind keine Einträge vorhanden</p>

BIN
src/lib/data/tatort.db Normal file

Binary file not shown.

View File

@@ -3,7 +3,6 @@
import FileRect from '$lib/icons/File-rect.svelte'; import FileRect from '$lib/icons/File-rect.svelte';
import ListIcon from '$lib/icons/List-icon.svelte'; import ListIcon from '$lib/icons/List-icon.svelte';
export let data; export let data;
export let outline = true; export let outline = true;
</script> </script>
@@ -20,7 +19,7 @@
<ListIcon class=" group-hover:text-indigo-600" /> <ListIcon class=" group-hover:text-indigo-600" />
</div> </div>
<a href="/list" class="mt-6 block font-semibold text-gray-900"> <a href="/list" class="mt-6 block font-semibold text-gray-900">
Liste Vorgänge
<span class="absolute inset-0"></span> <span class="absolute inset-0"></span>
</a> </a>
<p class="mt-1 text-gray-600"> <p class="mt-1 text-gray-600">

View File

@@ -1,11 +1,14 @@
<script lang="ts"> <script lang="ts">
import Trash from '$lib/icons/Trash.svelte'; import Trash from '$lib/icons/Trash.svelte';
import Folder from '$lib/icons/Folder.svelte'; import Folder from '$lib/icons/Folder.svelte';
import EmptyList from '$lib/components/EmptyList.svelte';
import type { PageData } from '../$types'; import type { PageData } from '../$types';
// let { data } = $props();
export let data: PageData; export let data: PageData;
let vorgangList = data.vorgangList;
const vorgangList = data.vorgangList; let isEmptyList = vorgangList.length === 0;
async function delete_item(ev: Event) { async function delete_item(ev: Event) {
let delete_item = window.confirm('Bist du sicher?'); let delete_item = window.confirm('Bist du sicher?');
@@ -41,34 +44,38 @@
</div> </div>
<div class="mx-auto flex justify-center max-w-7xl h-full"> <div class="mx-auto flex justify-center max-w-7xl h-full">
<ul role="list" class="divide-y divide-gray-100"> <ul role="list" class="divide-y divide-gray-100">
{#each vorgangList as vorgangItem} {#if isEmptyList}
<li> <EmptyList></EmptyList>
<a {:else}
href="/list/{vorgangItem.vorgangToken}?pin={vorgangItem.vorgangPIN}" {#each vorgangList as vorgangItem}
class="flex justify-between gap-x-6 py-5" <li>
> <a
<div class="flex gap-x-4"> href="/list/{vorgangItem.vorgangToken}?pin={vorgangItem.vorgangPIN}"
<Folder /> class="flex justify-between gap-x-6 py-5"
<div class="min-w-0 flex-auto"> >
<span class="text-sm font-semibold leading-6 text-gray-900" <div class="flex gap-x-4">
>{vorgangItem.vorgangName}</span <Folder />
> <div class="min-w-0 flex-auto">
<button <span class="text-sm font-semibold leading-6 text-gray-900"
style="padding: 2px" >{vorgangItem.vorgangName}</span
id="del__{vorgangItem.vorgangToken}" >
on:click|preventDefault={delete_item} <button
aria-label="Vorgang {vorgangItem.name} löschen" style="padding: 2px"
> id="del__{vorgangItem.vorgangToken}"
<Trash /> on:click|preventDefault={delete_item}
</button> aria-label="Vorgang {vorgangItem.name} löschen"
>
<Trash />
</button>
</div>
</div> </div>
</div> <div class="hidden sm:flex sm:flex-col sm:items-end">
<div class="hidden sm:flex sm:flex-col sm:items-end"> <p class="text-sm leading-6 text-gray-900">Vorgang</p>
<p class="text-sm leading-6 text-gray-900">Vorgang</p> </div>
</div> </a>
</a> </li>
</li> {/each}
{/each} {/if}
</ul> </ul>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,12 @@
// export async function load({fetch}){
// const vorgangResponse = await fetch(`/api/list`);
// const vorgangList = await vorgangResponse.json();
// return {
// vorgangList,
// }
// }

View File

@@ -11,11 +11,11 @@
import Cube from '$lib/icons/Cube.svelte'; import Cube from '$lib/icons/Cube.svelte';
import { invalidate, invalidateAll } from '$app/navigation'; import { invalidate, invalidateAll } from '$app/navigation';
import NameItemEditor from '$lib/components/NameItemEditor.svelte'; import NameItemEditor from '$lib/components/NameItemEditor.svelte';
import EmptyList from '$lib/components/EmptyList.svelte';
//Seite für die Tatort-Liste //Seite für die Tatort-Liste
let { data } = $props(); let { data } = $props();
console.log('tatorte: debug ', data);
interface ListItem { interface ListItem {
//sollte Typ Vorgang sein, aber der einfachheit ist es noch ListItem, damit die Komponente NameItemEditor für Vorgang und Tatort eingesetzt werden kann //sollte Typ Vorgang sein, aber der einfachheit ist es noch ListItem, damit die Komponente NameItemEditor für Vorgang und Tatort eingesetzt werden kann
name: string; name: string;
@@ -30,6 +30,7 @@
let crimesList: ListItem[] = $state(data.crimesList); let crimesList: ListItem[] = $state(data.crimesList);
const vorgangPIN: string = data.vorgang.vorgangPIN; const vorgangPIN: string = data.vorgang.vorgangPIN;
let vorgangToken: string = data.vorgang.vorgangToken; let vorgangToken: string = data.vorgang.vorgangToken;
let isEmptyList = $derived(crimesList.length === 0);
//Variablen für Modal //Variablen für Modal
let open = $state(false); let open = $state(false);
@@ -147,55 +148,61 @@ Mit freundlichen Grüßen,
{#if admin} {#if admin}
Zugangs-PIN: {vorgangPIN} Zugangs-PIN: {vorgangPIN}
<a class="pt-2 pb-6" href={constructMailToLink()}><Button>Share Link</Button></a> <a class="pt-2 pb-6" href={constructMailToLink()}
><Button disabled={isEmptyList}>Share Link</Button></a
>
{/if} {/if}
</div> </div>
<div class="mx-auto flex justify-center max-w-7xl h-full"> <div class="mx-auto flex justify-center max-w-7xl h-full">
<ul class="divide-y divide-gray-100"> <ul class="divide-y divide-gray-100">
{#each data.crimesList as item, crimeListItemIndex} {#if isEmptyList}
<li> <EmptyList></EmptyList>
<div class=" flex gap-x-4"> {:else}
<a {#each data.crimesList as item, crimeListItemIndex}
href="/view/{vorgangToken}/{item.name}?pin={vorgangPIN}" <li>
class=" flex justify-between gap-x-6 py-5" <div class=" flex gap-x-4">
aria-label="/view/{vorgangToken}/{item.name}?pin={vorgangPIN}" <a
title={item.name} href="/view/{vorgangToken}/{item.name}?pin={vorgangPIN}"
> class=" flex justify-between gap-x-6 py-5"
<Cube /> aria-label="/view/{vorgangToken}/{item.name}?pin={vorgangPIN}"
</a> title={item.name}
<div class="min-w-0 flex-auto"> >
{#if admin} <Cube />
<NameItemEditor </a>
list={data.crimesList} <div class="min-w-0 flex-auto">
editedName={data.crimeNames[crimeListItemIndex]} {#if admin}
currentName={item.name} <NameItemEditor
onSave={handleSave} list={data.crimesList}
onDelete={handleDelete} editedName={data.crimeNames[crimeListItemIndex]}
></NameItemEditor> currentName={item.name}
{:else} onSave={handleSave}
<span class="text-sm font-semibold leading-6 text-gray-900 inline-block min-w-1" onDelete={handleDelete}
>{item.name}</span ></NameItemEditor>
> {:else}
{/if} <span class="text-sm font-semibold leading-6 text-gray-900 inline-block min-w-1"
{#if item.size} >{item.name}</span
<p class="mt-1 truncate text-xs leading-5 text-gray-500"> >
{shortenFileSize(item.size)} {/if}
{#if item.size}
<p class="mt-1 truncate text-xs leading-5 text-gray-500">
{shortenFileSize(item.size)}
</p>
{/if}
</div>
</div>
<div class="hidden sm:flex sm:flex-col sm:items-end">
<p class="text-sm leading-6 text-gray-900">3D Tatort</p>
{#if item.lastModified}
<p class="mt-1 text-xs leading-5 text-gray-500">
Zuletzt geändert <time datetime="2023-01-23T13:23Z"
>{timeElapsed(new Date(item.lastModified))}</time
>
</p> </p>
{/if} {/if}
</div> </div>
</div> </li>
<div class="hidden sm:flex sm:flex-col sm:items-end"> {/each}
<p class="text-sm leading-6 text-gray-900">3D Tatort</p> {/if}
{#if item.lastModified}
<p class="mt-1 text-xs leading-5 text-gray-500">
Zuletzt geändert <time datetime="2023-01-23T13:23Z"
>{timeElapsed(new Date(item.lastModified))}</time
>
</p>
{/if}
</div>
</li>
{/each}
</ul> </ul>
</div> </div>

View File

@@ -1,4 +1,3 @@
import { redirect } from '@sveltejs/kit';
export async function load({fetch, params, url}){ export async function load({fetch, params, url}){
const vorgangResponse = await fetch(`/api/list`); const vorgangResponse = await fetch(`/api/list`);
@@ -14,9 +13,7 @@ export async function load({fetch, params, url}){
//Variabeln für NameItemEditor //Variabeln für NameItemEditor
const crimeNames: string[] = crimesList.map((l) => l.name); const crimeNames: string[] = crimesList.map((l) => l.name);
if (crimesList.length === 0) {
throw redirect(302, '/upload'); // weiterleiten auf die hinzufügen seite
}
return { return {
vorgang, vorgang,
vorgangList, vorgangList,