Compare commits
9 Commits
d58be34fe5
...
archive/f0
| Author | SHA1 | Date | |
|---|---|---|---|
| 0557d42207 | |||
| 59fc791b85 | |||
| c437926002 | |||
| 99a27fc079 | |||
| bebd226c80 | |||
| 4adea19981 | |||
| 6b7188350f | |||
| 20c74d49d9 | |||
| 131318da14 |
@@ -8,7 +8,7 @@
|
||||
},
|
||||
"jwt": {
|
||||
"secret": "@S2!q@@wXz$dCQ8JoVsHLpzaJ6JCfB",
|
||||
"expiresIn": 3600
|
||||
"expiresIn": 36000
|
||||
},
|
||||
"auth": {
|
||||
"admin": { "password": "A-InnoHUB_2025!", "admin": true },
|
||||
|
||||
6
e2e/demo.test.ts
Normal file
6
e2e/demo.test.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
test('home page has expected h1', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await expect(page.locator('h1')).toBeVisible();
|
||||
});
|
||||
@@ -20,21 +20,7 @@ export default ts.config(
|
||||
languageOptions: {
|
||||
globals: { ...globals.browser, ...globals.node }
|
||||
},
|
||||
rules: {
|
||||
'no-undef': 'off',
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
{
|
||||
args: 'all',
|
||||
argsIgnorePattern: '^_',
|
||||
caughtErrors: 'all',
|
||||
caughtErrorsIgnorePattern: '^_',
|
||||
destructuredArrayIgnorePattern: '^_',
|
||||
varsIgnorePattern: '^_',
|
||||
ignoreRestSiblings: true
|
||||
}
|
||||
]
|
||||
}
|
||||
rules: { 'no-undef': 'off' }
|
||||
},
|
||||
{
|
||||
files: ['**/*.svelte', '**/*.svelte.ts', '**/*.svelte.js'],
|
||||
|
||||
799
package-lock.json
generated
799
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
43
package.json
43
package.json
@@ -13,31 +13,31 @@
|
||||
"format": "prettier --write .",
|
||||
"lint": "prettier --check . && eslint .",
|
||||
"test:unit": "vitest",
|
||||
"test": "npm run test:unit -- --run && npm run test:e2e"
|
||||
"test": "npm run test:unit -- --run && npm run test:e2e",
|
||||
"test:e2e": "playwright test"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/compat": "^1.2.9",
|
||||
"@eslint/compat": "^1.2.5",
|
||||
"@eslint/js": "^9.18.0",
|
||||
"@playwright/test": "^1.49.1",
|
||||
"@sveltejs/adapter-auto": "^4.0.0",
|
||||
"@sveltejs/kit": "^2.21.3",
|
||||
"@sveltejs/vite-plugin-svelte": "^5.1.0",
|
||||
"@sveltejs/kit": "^2.16.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^5.0.0",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@testing-library/svelte": "^5.2.8",
|
||||
"@tsconfig/svelte": "^5.0.4",
|
||||
"@types/jsonwebtoken": "^9.0.9",
|
||||
"eslint": "^9.28.0",
|
||||
"eslint-config-prettier": "^10.1.5",
|
||||
"eslint-plugin-svelte": "^3.9.2",
|
||||
"globals": "^16.2.0",
|
||||
"jsdom": "^26.1.0",
|
||||
"prettier": "^3.5.3",
|
||||
"prettier-plugin-svelte": "^3.4.0",
|
||||
"svelte": "^5.33.18",
|
||||
"svelte-check": "^4.2.1",
|
||||
"typescript": "^5.8.3",
|
||||
"typescript-eslint": "^8.34.0",
|
||||
"vite": "^6.3.5",
|
||||
"vitest": "^3.2.3"
|
||||
"@testing-library/svelte": "^5.2.4",
|
||||
"eslint": "^9.18.0",
|
||||
"eslint-config-prettier": "^10.0.1",
|
||||
"eslint-plugin-svelte": "^3.0.0",
|
||||
"globals": "^16.0.0",
|
||||
"jsdom": "^26.0.0",
|
||||
"prettier": "^3.4.2",
|
||||
"prettier-plugin-svelte": "^3.3.3",
|
||||
"svelte": "^5.0.0",
|
||||
"svelte-check": "^4.0.0",
|
||||
"typescript": "^5.0.0",
|
||||
"typescript-eslint": "^8.20.0",
|
||||
"vite": "^6.2.5",
|
||||
"vitest": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@google/model-viewer": "^4.1.0",
|
||||
@@ -46,7 +46,8 @@
|
||||
"autoprefixer": "^10.4.21",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"minio": "^8.0.5",
|
||||
"postcss": "^8.5.4",
|
||||
"postcss": "^8.5.3",
|
||||
"svelte-cubed": "^0.2.1",
|
||||
"tailwindcss": "^3.4.17"
|
||||
}
|
||||
}
|
||||
|
||||
11
playwright.config.js
Normal file
11
playwright.config.js
Normal file
@@ -0,0 +1,11 @@
|
||||
/** @type {import('@playwright/test').PlaywrightTestConfig} */
|
||||
const config = {
|
||||
webServer: {
|
||||
command: 'npm run build && npm run preview',
|
||||
port: 4173
|
||||
},
|
||||
testDir: 'tests',
|
||||
testMatch: /(.+\.)?(test|spec)\.[jt]s/
|
||||
};
|
||||
|
||||
export default config;
|
||||
9
playwright.config.ts
Normal file
9
playwright.config.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { defineConfig } from '@playwright/test';
|
||||
|
||||
export default defineConfig({
|
||||
webServer: {
|
||||
command: 'npm run build && npm run preview',
|
||||
port: 4173
|
||||
},
|
||||
testDir: 'e2e'
|
||||
});
|
||||
4
src/error.html
Normal file
4
src/error.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<h1>Du wurdest automatisch ausgeloggt</h1>
|
||||
<p>Lösche deine Cookies aus dem Browser und logge dich neu ein</p>
|
||||
<p>Code %sveltekit.status%</p>
|
||||
<p>%sveltekit.error.message%</p>
|
||||
@@ -1,16 +1,16 @@
|
||||
import { decryptToken } from '$lib/auth';
|
||||
import type { Handle } from '@sveltejs/kit';
|
||||
|
||||
export const handle: Handle = ({ event, resolve }) => {
|
||||
/** @type {import('@sveltejs/kit').Handle} */
|
||||
export async function handle({ event, resolve }) {
|
||||
const jwt = event.cookies.get('session');
|
||||
try {
|
||||
if (jwt) {
|
||||
event.locals.user = decryptToken(jwt);
|
||||
return resolve(event);
|
||||
}
|
||||
} catch (_) {
|
||||
event.cookies.delete('session', {path: '/'});
|
||||
} catch (err) {
|
||||
await event.cookies.delete('session');
|
||||
event.locals.user = null;
|
||||
}
|
||||
return resolve(event);
|
||||
return await resolve(event);
|
||||
}
|
||||
@@ -46,7 +46,7 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
<script>
|
||||
export let type = 'info';
|
||||
let classNames = '';
|
||||
export { classNames as class };
|
||||
|
||||
@@ -173,7 +173,7 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
<script>
|
||||
export let href = null;
|
||||
export let type = 'button';
|
||||
export let size = 'md';
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
<script>
|
||||
import { page } from '$app/stores';
|
||||
import Trash from '$lib/icons/Trash.svelte';
|
||||
import Panel from '$lib/components/ui/Panel.svelte';
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
<script>
|
||||
import { fade } from 'svelte/transition';
|
||||
export let size = 'xl'; // https://tailwindcss.com/docs/max-width#class-reference
|
||||
export let open = false;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
<script>
|
||||
export let scroll = true;
|
||||
export let padding = true;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<script lang="ts">
|
||||
<script>
|
||||
export let title = 'Erfolgreich';
|
||||
export let show = false;
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
<script>
|
||||
export let padding = 'p-6';
|
||||
export let shadow = true;
|
||||
let classNames = '';
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
<script>
|
||||
import { clickOutside } from '$lib/helpers/clickOutside.js';
|
||||
import Check from '$lib/icons/Check.svelte';
|
||||
import Selector from '$lib/icons/Selector.svelte';
|
||||
|
||||
@@ -3,12 +3,12 @@ import { client } from '$lib/minio';
|
||||
/**
|
||||
* Check if caseNumber is used
|
||||
* @param {string} caseNumber
|
||||
* @returns {Promise<boolean}
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
export default async function caseNumberOccupied(caseNumber: string) {
|
||||
export default async function caseNumberOccupied(caseNumber) {
|
||||
const prefix = `${caseNumber}/config.json`;
|
||||
const promise = new Promise((resolve) => {
|
||||
const stream = client.listObjectsV2('tatort', prefix, false, '');
|
||||
let stream = client.listObjectsV2('tatort', prefix, false, '');
|
||||
stream.on('data', () => {
|
||||
stream.destroy();
|
||||
resolve(true);
|
||||
@@ -7,7 +7,7 @@ const GIGA = MEGA * KILO;
|
||||
* @param {number} size
|
||||
* @returns{string}
|
||||
*/
|
||||
export default function shortenFileSize(size: number) {
|
||||
export default function shortenFileSize(size) {
|
||||
const giga = Math.floor(size / GIGA);
|
||||
let remainder = size % GIGA;
|
||||
const mega = Math.floor(remainder / MEGA);
|
||||
@@ -9,7 +9,7 @@ const MONTH = YEAR / 12;
|
||||
* @param {Date} date
|
||||
* @returns string
|
||||
*/
|
||||
export default function timeElapsed(date: Date) {
|
||||
export default function timeElapsed(date) {
|
||||
const now = new Date();
|
||||
const age = Math.floor((now.getTime() - date.getTime()) / 1000);
|
||||
|
||||
19
src/lib/icons/Add-Process.svelte
Normal file
19
src/lib/icons/Add-Process.svelte
Normal file
@@ -0,0 +1,19 @@
|
||||
<script>
|
||||
let classNames = '';
|
||||
export { classNames as class };
|
||||
</script>
|
||||
|
||||
<svg
|
||||
class="h-6 w-6 text-gray-600 {classNames}"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M13.5 16.875h3.375m0 0h3.375m-3.375 0V13.5m0 3.375v3.375M6 10.5h2.25a2.25 2.25 0 002.25-2.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v2.25A2.25 2.25 0 006 10.5zm0 9.75h2.25A2.25 2.25 0 0010.5 18v-2.25a2.25 2.25 0 00-2.25-2.25H6a2.25 2.25 0 00-2.25 2.25V18A2.25 2.25 0 006 20.25zm9.75-9.75H18a2.25 2.25 0 002.25-2.25V6A2.25 2.25 0 0018 3.75h-2.25A2.25 2.25 0 0013.5 6v2.25a2.25 2.25 0 002.25 2.25z"
|
||||
/>
|
||||
</svg>
|
||||
14
src/lib/icons/Cube.svelte
Normal file
14
src/lib/icons/Cube.svelte
Normal file
@@ -0,0 +1,14 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class=" w-6 h-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M21 7.5l-2.25-1.313M21 7.5v2.25m0-2.25l-2.25 1.313M3 7.5l2.25-1.313M3 7.5l2.25 1.313M3 7.5v2.25m9 3l2.25-1.313M12 12.75l-2.25-1.313M12 12.75V15m0 6.75l2.25-1.313M12 21.75V19.5m0 2.25l-2.25-1.313m0-16.875L12 2.25l2.25 1.313M21 14.25v2.25l-2.25 1.313m-13.5 0L3 16.5v-2.25"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 483 B |
7
src/lib/icons/Edit.svelte
Normal file
7
src/lib/icons/Edit.svelte
Normal file
@@ -0,0 +1,7 @@
|
||||
<svg height="20" width="20" xmlns="http://www.w3.org/2000/svg"
|
||||
><path
|
||||
d="m14.996094 3-11.9921878 11.992188h-.0039062v4.007812h1 2 1.0078125v-.0039l11.9921875-11.9921938-.001953-.0019531.001953-.0019531-4-4-.002.00195zm-1.998047 3.4121094 2.589844 2.5898437-7.587891 7.5878909v-1.589844h-1-1v-1-.589844zm-7.998047 7.9980466v1.589844h1 1v1 .589844l-.4101562.410156h-1.5898438l-1-1v-1.589844z"
|
||||
fill="#373737"
|
||||
transform="translate(1 1)"
|
||||
/></svg
|
||||
>
|
||||
|
After Width: | Height: | Size: 451 B |
35
src/lib/icons/File-rect.svelte
Normal file
35
src/lib/icons/File-rect.svelte
Normal file
@@ -0,0 +1,35 @@
|
||||
<script>
|
||||
export let outline = false;
|
||||
let classNames = '';
|
||||
export { classNames as class };
|
||||
</script>
|
||||
|
||||
{#if outline}
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-6 h-6 {classNames}"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M2.25 15.75l5.159-5.159a2.25 2.25 0 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 013.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 001.5-1.5V6a1.5 1.5 0 00-1.5-1.5H3.75A1.5 1.5 0 002.25 6v12a1.5 1.5 0 001.5 1.5zm10.5-11.25h.008v.008h-.008V8.25zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z"
|
||||
/>
|
||||
</svg>
|
||||
{:else}
|
||||
<svg
|
||||
class="mx-auto h-12 w-12 text-gray-300 {classNames}"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M1.5 6a2.25 2.25 0 012.25-2.25h16.5A2.25 2.25 0 0122.5 6v12a2.25 2.25 0 01-2.25 2.25H3.75A2.25 2.25 0 011.5 18V6zM3 16.06V18c0 .414.336.75.75.75h16.5A.75.75 0 0021 18v-1.94l-2.69-2.689a1.5 1.5 0 00-2.12 0l-.88.879.97.97a.75.75 0 11-1.06 1.06l-5.16-5.159a1.5 1.5 0 00-2.12 0L3 16.061zm10.125-7.81a1.125 1.125 0 112.25 0 1.125 1.125 0 01-2.25 0z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
{/if}
|
||||
14
src/lib/icons/Folder.svelte
Normal file
14
src/lib/icons/Folder.svelte
Normal file
@@ -0,0 +1,14 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-6 h-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M2.25 12.75V12A2.25 2.25 0 014.5 9.75h15A2.25 2.25 0 0121.75 12v.75m-8.69-6.44l-2.12-2.12a1.5 1.5 0 00-1.061-.44H4.5A2.25 2.25 0 002.25 6v12a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9a2.25 2.25 0 00-2.25-2.25h-5.379a1.5 1.5 0 01-1.06-.44z"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 460 B |
19
src/lib/icons/List-icon.svelte
Normal file
19
src/lib/icons/List-icon.svelte
Normal file
@@ -0,0 +1,19 @@
|
||||
<script>
|
||||
let classNames = '';
|
||||
export { classNames as class };
|
||||
</script>
|
||||
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-6 h-6 {classNames}"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M8.25 6.75h12M8.25 12h12m-12 5.25h12M3.75 6.75h.007v.008H3.75V6.75zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zM3.75 12h.007v.008H3.75V12zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm-.375 5.25h.007v.008H3.75v-.008zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z"
|
||||
/>
|
||||
</svg>
|
||||
14
src/lib/icons/Profile.svelte
Normal file
14
src/lib/icons/Profile.svelte
Normal file
@@ -0,0 +1,14 @@
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-6 h-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M17.982 18.725A7.488 7.488 0 0012 15.75a7.488 7.488 0 00-5.982 2.975m11.963 0a9 9 0 10-11.963 0m11.963 0A8.966 8.966 0 0112 21a8.966 8.966 0 01-5.982-2.275M15 9.75a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 402 B |
9
src/routes/(angemeldet)/+layout.server.js
Normal file
9
src/routes/(angemeldet)/+layout.server.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
|
||||
/** @type {import('./$types').PageServerLoad} */
|
||||
export function load(event) {
|
||||
if (!event.locals.user && event.url.pathname !== '/anmeldung') throw redirect(303, '/anmeldung');
|
||||
return {
|
||||
user: event.locals.user
|
||||
};
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { redirect, type ServerLoadEvent } from '@sveltejs/kit';
|
||||
import type { PageServerLoad } from './view/[vorgang]/[tatort]/$types';
|
||||
|
||||
export const load: PageServerLoad = (event: ServerLoadEvent) => {
|
||||
if (!event.locals.user && event.url.pathname !== '/anmeldung') throw redirect(303, '/anmeldung');
|
||||
return {
|
||||
user: event.locals.user
|
||||
};
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
<script lang="ts">
|
||||
<script>
|
||||
import Chevron from '$lib/icons/Chevron-right.svelte';
|
||||
import Login from '$lib/icons/Login.svelte';
|
||||
import Profile from '$lib/icons/Profile.svelte';
|
||||
|
||||
export let data;
|
||||
</script>
|
||||
@@ -58,20 +60,9 @@
|
||||
href="/"
|
||||
class="px-4 py-1 -mr-4 flex items-center justify-center gap-x-2.5 text-sm font-semibold leading-6 text-gray-500 hover:bg-gray-200 hover:text-gray-700"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-6 h-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M17.982 18.725A7.488 7.488 0 0012 15.75a7.488 7.488 0 00-5.982 2.975m11.963 0a9 9 0 10-11.963 0m11.963 0A8.966 8.966 0 0112 21a8.966 8.966 0 01-5.982-2.275M15 9.75a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
/>
|
||||
</svg>
|
||||
<!--icon-->
|
||||
<Profile />
|
||||
|
||||
{data.user.id}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<style>
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
<script>
|
||||
import Panel from '$lib/components/ui/Panel.svelte';
|
||||
import AddProcess from '$lib/icons/Add-Process.svelte';
|
||||
import FileRect from '$lib/icons/File-rect.svelte';
|
||||
import ListIcon from '$lib/icons/List-icon.svelte';
|
||||
|
||||
export let data;
|
||||
export let outline = true;
|
||||
</script>
|
||||
|
||||
<div
|
||||
@@ -15,20 +17,7 @@
|
||||
<div
|
||||
class="flex h-11 w-11 items-center justify-center rounded-lg bg-gray-50 group-hover:bg-white"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-6 h-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M8.25 6.75h12M8.25 12h12m-12 5.25h12M3.75 6.75h.007v.008H3.75V6.75zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zM3.75 12h.007v.008H3.75V12zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm-.375 5.25h.007v.008H3.75v-.008zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z"
|
||||
/>
|
||||
</svg>
|
||||
<ListIcon class=" group-hover:text-indigo-600" />
|
||||
</div>
|
||||
<a href="/list" class="mt-6 block font-semibold text-gray-900">
|
||||
Liste
|
||||
@@ -39,7 +28,7 @@
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
{#if data.user.admin}
|
||||
<!--{#if data.user.admin}
|
||||
<div class="group relative rounded-lg p-6 text-sm leading-6 hover:bg-gray-50 w-1/4">
|
||||
<div
|
||||
class="flex h-11 w-11 items-center justify-center rounded-lg bg-gray-50 group-hover:bg-white"
|
||||
@@ -65,26 +54,13 @@
|
||||
</a>
|
||||
<p class="mt-1 text-gray-600">Stelle einen weiteren Tatort für die Anwendung bereit.</p>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}-->
|
||||
{#if data.user.admin}
|
||||
<div class="group relative rounded-lg p-6 text-sm leading-6 hover:bg-gray-50 w-1/4">
|
||||
<div
|
||||
class="flex h-11 w-11 items-center justify-center rounded-lg bg-gray-50 group-hover:bg-white"
|
||||
>
|
||||
<svg
|
||||
class="h-6 w-6 text-gray-600 group-hover:text-indigo-600"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M13.5 16.875h3.375m0 0h3.375m-3.375 0V13.5m0 3.375v3.375M6 10.5h2.25a2.25 2.25 0 002.25-2.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v2.25A2.25 2.25 0 006 10.5zm0 9.75h2.25A2.25 2.25 0 0010.5 18v-2.25a2.25 2.25 0 00-2.25-2.25H6a2.25 2.25 0 00-2.25 2.25V18A2.25 2.25 0 006 20.25zm9.75-9.75H18a2.25 2.25 0 002.25-2.25V6A2.25 2.25 0 0018 3.75h-2.25A2.25 2.25 0 0013.5 6v2.25a2.25 2.25 0 002.25 2.25z"
|
||||
/>
|
||||
</svg>
|
||||
<AddProcess class=" group-hover:text-indigo-600" />
|
||||
</div>
|
||||
<a href="/upload" class="mt-6 block font-semibold text-gray-900">
|
||||
Hinzufügen
|
||||
@@ -97,20 +73,7 @@
|
||||
<div
|
||||
class="flex h-11 w-11 items-center justify-center rounded-lg bg-gray-50 group-hover:bg-white"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-6 h-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M2.25 15.75l5.159-5.159a2.25 2.25 0 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0 013.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 001.5-1.5V6a1.5 1.5 0 00-1.5-1.5H3.75A1.5 1.5 0 002.25 6v12a1.5 1.5 0 001.5 1.5zm10.5-11.25h.008v.008h-.008V8.25zm.375 0a.375.375 0 11-.75 0 .375.375 0 01.75 0z"
|
||||
/>
|
||||
</svg>
|
||||
<FileRect class=" group-hover:text-indigo-600" {outline} />
|
||||
</div>
|
||||
<a href="/view" class="mt-6 block font-semibold text-gray-900">
|
||||
Ansicht
|
||||
@@ -120,3 +83,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { page } from '$app/stores';
|
||||
import Trash from '$lib/icons/Trash.svelte';
|
||||
import Folder from '$lib/icons/Folder.svelte';
|
||||
|
||||
/**
|
||||
* @type any[]
|
||||
@@ -71,20 +74,8 @@
|
||||
<li>
|
||||
<a href="/list/{item.name}" class="flex justify-between gap-x-6 py-5">
|
||||
<div class="flex gap-x-4">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-6 h-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M2.25 12.75V12A2.25 2.25 0 014.5 9.75h15A2.25 2.25 0 0121.75 12v.75m-8.69-6.44l-2.12-2.12a1.5 1.5 0 00-1.061-.44H4.5A2.25 2.25 0 002.25 6v12a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9a2.25 2.25 0 00-2.25-2.25h-5.379a1.5 1.5 0 01-1.06-.44z"
|
||||
/>
|
||||
</svg>
|
||||
<!-- Ordner -->
|
||||
<Folder />
|
||||
<div class="min-w-0 flex-auto">
|
||||
<span class="text-sm font-semibold leading-6 text-gray-900">{item.name}</span>
|
||||
<!-- Delete button -->
|
||||
@@ -94,13 +85,7 @@
|
||||
on:click|preventDefault={delete_item}
|
||||
aria-label="Vorgang {item.name} löschen"
|
||||
>
|
||||
<svg height="20" width="20" xmlns="http://www.w3.org/2000/svg"
|
||||
><path
|
||||
d="m8 3v1 1h1v-1h4v1h1v-1-1zm-4 3v1h14v-1zm2 2v11h1 9v-1-10h-1v10h-8v-10z"
|
||||
fill="#373737"
|
||||
transform="translate(1 1)"
|
||||
/></svg
|
||||
>
|
||||
<Trash />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { onMount, tick } from 'svelte';
|
||||
import shortenFileSize from '$lib/helper/shortenFileSize';
|
||||
import { page } from '$app/stores';
|
||||
|
||||
@@ -11,8 +11,14 @@
|
||||
import ModalTitle from '$lib/components/ui/Modal/ModalTitle.svelte';
|
||||
import ModalContent from '$lib/components/ui/Modal/ModalContent.svelte';
|
||||
import ModalFooter from '$lib/components/ui/Modal/ModalFooter.svelte';
|
||||
import Cube from '$lib/icons/Cube.svelte';
|
||||
import Edit from '$lib/icons/Edit.svelte';
|
||||
import Trash from '$lib/icons/Trash.svelte';
|
||||
|
||||
/** export let data; */
|
||||
/** @type {import('./$types').PageData} */
|
||||
export let data;
|
||||
|
||||
console.log(`--- ${data.user.admin}`);
|
||||
|
||||
interface ListItem {
|
||||
name: string;
|
||||
@@ -164,30 +170,19 @@
|
||||
<ul class="divide-y divide-gray-100">
|
||||
{#each list as item, i}
|
||||
<li>
|
||||
<a
|
||||
href="/view/{$page.params.vorgang}/{item.name}"
|
||||
class="flex justify-between gap-x-6 py-5"
|
||||
>
|
||||
<div class="flex gap-x-4">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-6 h-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M21 7.5l-2.25-1.313M21 7.5v2.25m0-2.25l-2.25 1.313M3 7.5l2.25-1.313M3 7.5l2.25 1.313M3 7.5v2.25m9 3l2.25-1.313M12 12.75l-2.25-1.313M12 12.75V15m0 6.75l2.25-1.313M12 21.75V19.5m0 2.25l-2.25-1.313m0-16.875L12 2.25l2.25 1.313M21 14.25v2.25l-2.25 1.313m-13.5 0L3 16.5v-2.25"
|
||||
/>
|
||||
</svg>
|
||||
<div class="min-w-0 flex-auto">
|
||||
<div class=" flex gap-x-4">
|
||||
<a
|
||||
href="/view/{$page.params.vorgang}/{item.name}"
|
||||
class=" flex justify-between gap-x-6 py-5"
|
||||
aria-label="zum 3D-modell"
|
||||
>
|
||||
<Cube />
|
||||
</a>
|
||||
<div class="min-w-0 flex-auto">
|
||||
{#if data.user.admin}
|
||||
<span
|
||||
style="display: inline-block; min-width: 5px;"
|
||||
id="label__{item.name}"
|
||||
class="text-sm font-semibold leading-6 text-gray-900"
|
||||
class="text-sm font-semibold leading-6 text-gray-900 inline-block min-w-1"
|
||||
contenteditable={!item.show_button}
|
||||
role="textbox"
|
||||
tabindex="0"
|
||||
@@ -201,6 +196,20 @@
|
||||
handle_input(ev, i);
|
||||
}}>{item.name}</span
|
||||
>
|
||||
|
||||
<input
|
||||
class="text-sm font-semibold leading-6 text-gray-900 inline-block min-w-1"
|
||||
type="text"
|
||||
name=""
|
||||
on:keydown|stopPropagation={// event needed to identify ID
|
||||
// TO-DO: check if event is needed or if index is sufficient
|
||||
async (ev) => {
|
||||
handle_input(ev, i);
|
||||
}}
|
||||
bind:value={item.name}
|
||||
id="label__{item.name}"
|
||||
/>
|
||||
<!-- disabled={item.show_button} -->
|
||||
<!-- https://iconduck.com/icons/192863/edit-rename -->
|
||||
|
||||
{#if item.show_button}
|
||||
@@ -222,13 +231,7 @@
|
||||
item.show_button = false;
|
||||
}}
|
||||
>
|
||||
<svg height="20" width="20" xmlns="http://www.w3.org/2000/svg"
|
||||
><path
|
||||
d="m14.996094 3-11.9921878 11.992188h-.0039062v4.007812h1 2 1.0078125v-.0039l11.9921875-11.9921938-.001953-.0019531.001953-.0019531-4-4-.002.00195zm-1.998047 3.4121094 2.589844 2.5898437-7.587891 7.5878909v-1.589844h-1-1v-1-.589844zm-7.998047 7.9980466v1.589844h1 1v1 .589844l-.4101562.410156h-1.5898438l-1-1v-1.589844z"
|
||||
fill="#373737"
|
||||
transform="translate(1 1)"
|
||||
/></svg
|
||||
>
|
||||
<Edit />
|
||||
</button>
|
||||
{/if}
|
||||
<button
|
||||
@@ -270,28 +273,26 @@
|
||||
}}
|
||||
aria-label="Datei löschen"
|
||||
>
|
||||
<svg height="20" width="20" xmlns="http://www.w3.org/2000/svg"
|
||||
><path
|
||||
d="m8 3v1 1h1v-1h4v1h1v-1-1zm-4 3v1h14v-1zm2 2v11h1 9v-1-10h-1v10h-8v-10z"
|
||||
fill="#373737"
|
||||
transform="translate(1 1)"
|
||||
/></svg
|
||||
>
|
||||
<Trash />
|
||||
</button>
|
||||
<p class="mt-1 truncate text-xs leading-5 text-gray-500">
|
||||
{shortenFileSize(item.size)}
|
||||
</p>
|
||||
</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>
|
||||
<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
|
||||
{:else}
|
||||
<span class="text-sm font-semibold leading-6 text-gray-900 inline-block min-w-1"
|
||||
>{item.name}</span
|
||||
>
|
||||
{/if}
|
||||
<p class="mt-1 truncate text-xs leading-5 text-gray-500">
|
||||
{shortenFileSize(item.size)}
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="hidden sm:flex sm:flex-col sm:items-end">
|
||||
<p class="text-sm leading-6 text-gray-900">3D Tatort</p>
|
||||
<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>
|
||||
</div>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
|
||||
@@ -3,25 +3,25 @@ import { json } from '@sveltejs/kit';
|
||||
|
||||
|
||||
// rename operation
|
||||
export async function PUT({ request }: {request: Request}) {
|
||||
export async function PUT({ request }) {
|
||||
const data = await request.json();
|
||||
|
||||
console.log(`--- ${request.url.split('/').at(-1)} +++ ${JSON.stringify(data)}`);
|
||||
|
||||
// Vorgang
|
||||
const vorgang = request.url.split('/').at(-1);
|
||||
let vorgang = request.url.split('/').at(-1)
|
||||
|
||||
// prepare copy, incl. check if new name exists already
|
||||
const old_name = data["old_name"];
|
||||
const src_full_path = `/tatort/${vorgang}/${old_name}`;
|
||||
const new_name = `${vorgang}/${data["new_name"]}`;
|
||||
let old_name = data["old_name"]
|
||||
let src_full_path = `/tatort/${vorgang}/${old_name}`
|
||||
let new_name = `${vorgang}/${data["new_name"]}`
|
||||
|
||||
try {
|
||||
await client.statObject('tatort', new_name);
|
||||
return json({ msg: 'Die Datei existiert bereits.' }, { status: 400 });
|
||||
let file_stats = await client.statObject('tatort', new_name)
|
||||
return json({ msg: 'Die Datei existiert bereits.' }, { status: 400 })
|
||||
} catch (error) {
|
||||
// continue operation
|
||||
console.log(error, 'continue operation');
|
||||
console.log('continue operation')
|
||||
}
|
||||
|
||||
// actual copy operation
|
||||
13
src/routes/(angemeldet)/list/[vorgang]/[tatort]/+server.js
Normal file
13
src/routes/(angemeldet)/list/[vorgang]/[tatort]/+server.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import { client } from '$lib/minio';
|
||||
import { json } from '@sveltejs/kit';
|
||||
|
||||
export async function DELETE({ request }) {
|
||||
|
||||
let url_fragments = request.url.split('/')
|
||||
let item = url_fragments.at(-1);
|
||||
let vorgang = url_fragments.at(-2);
|
||||
|
||||
await client.removeObject('tatort', `${vorgang}/${item}`)
|
||||
|
||||
return new Response(null, { status: 204 });
|
||||
};
|
||||
@@ -1,11 +0,0 @@
|
||||
import { client } from '$lib/minio';
|
||||
|
||||
export async function DELETE({ request }: { request: Request }) {
|
||||
const url_fragments = request.url.split('/');
|
||||
const item = url_fragments.at(-1);
|
||||
const vorgang = url_fragments.at(-2);
|
||||
|
||||
await client.removeObject('tatort', `${vorgang}/${item}`);
|
||||
|
||||
return new Response(null, { status: 204 });
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import caseNumberOccupied from '$lib/helper/caseNumberOccupied';
|
||||
|
||||
/** @type {import('./$types').Actions} */
|
||||
export const actions = {
|
||||
default: async ({ request }: {request: Request}) => {
|
||||
default: async ({ request }) => {
|
||||
const data = await request.formData();
|
||||
const caseNumber = data.get('caseNumber');
|
||||
const description = data.get('description');
|
||||
@@ -28,7 +28,7 @@ export const actions = {
|
||||
|
||||
const config = `${JSON.stringify({ caseNumber, description, version: 1 })}\n`;
|
||||
|
||||
await client.putObject('tatort', `${caseNumber}/config.json`, config, undefined, {
|
||||
await client.putObject('tatort', `${caseNumber}/config.json`, config, {
|
||||
'Content-Type': 'application/json'
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<script lang="ts">
|
||||
<script>
|
||||
import Alert from '$lib/components/ui/Alert.svelte';
|
||||
import Button from '$lib/components/ui/Button.svelte';
|
||||
import Modal from '$lib/components/ui/Modal/Modal.svelte';
|
||||
@@ -73,8 +73,24 @@
|
||||
<p class="block text-sm leading-6 text-red-900 mt-2">{form.error.description}</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<label for="code">
|
||||
<span >Zugangscode (optional) </span>
|
||||
</label>
|
||||
|
||||
<div class="mt-2">
|
||||
<div
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
id="code"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex items-center justify-end gap-x-6">
|
||||
<button type="button" class="text-sm font-semibold leading-6 text-gray-900">Cancel</button>
|
||||
<Button
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import path from 'path';
|
||||
import { writeFile } from 'fs/promises';
|
||||
import { createReadStream } from 'fs';
|
||||
/** import Minio from 'minio'; */
|
||||
import { Readable } from 'stream';
|
||||
/** const MINIO_ACCESS_KEY = 'tMhLrfog47lMm0HZ'; */
|
||||
import { client } from '$lib/minio';
|
||||
import { fail } from '@sveltejs/kit';
|
||||
|
||||
const isRequiredFieldValid = (value: unknown) => {
|
||||
function isRequiredFieldValid(value) {
|
||||
if (value == null) return false;
|
||||
|
||||
if (typeof value === 'string' || value instanceof String) return value.trim() !== '';
|
||||
@@ -12,7 +17,7 @@ const isRequiredFieldValid = (value: unknown) => {
|
||||
|
||||
/** @type {import('./$types').Actions} */
|
||||
export const actions = {
|
||||
url: async ({ request }: {request: Request}) => {
|
||||
url: async ({ request }) => {
|
||||
const data = await request.formData();
|
||||
const vorgang = data.get('vorgang');
|
||||
const name = data.get('name');
|
||||
@@ -25,20 +30,21 @@ export const actions = {
|
||||
if (!objectName.endsWith('.png')) objectName += '.png';
|
||||
break;
|
||||
case '':
|
||||
if (fileName?.toString().endsWith('.glb') && !objectName.endsWith('.glb')) objectName += '.glb';
|
||||
if (fileName.endsWith('.glb') && !objectName.endsWith('.glb')) objectName += '.glb';
|
||||
}
|
||||
|
||||
const url = await client.presignedPutObject('tatort', objectName);
|
||||
|
||||
return { url };
|
||||
},
|
||||
validate: async ({ request }: {request: Request}) => {
|
||||
validate: async ({ request }) => {
|
||||
const requestData = await request.formData();
|
||||
const data = Object.fromEntries(requestData);
|
||||
const vorgang = data.vorgang;
|
||||
const name = data.name;
|
||||
const zugangscode = data.zugangscode;
|
||||
let success = true;
|
||||
const err = {};
|
||||
let err = {};
|
||||
|
||||
if (isRequiredFieldValid(vorgang)) err.vorgang = null;
|
||||
else {
|
||||
@@ -52,12 +58,18 @@ export const actions = {
|
||||
success = false;
|
||||
}
|
||||
|
||||
if (isRequiredFieldValid(zugangscode)) err.zugangscode = null;
|
||||
else {
|
||||
err.zugangscode = 'Das Feld Zugangscode darf nicht leer bleiben.';
|
||||
success = false;
|
||||
}
|
||||
|
||||
if (success) return { success };
|
||||
|
||||
return fail(400, err);
|
||||
},
|
||||
|
||||
upload: async ({ request }: {request: Request}) => {
|
||||
upload: async ({ request }) => {
|
||||
const requestData = await request.formData();
|
||||
const data = Object.fromEntries(requestData);
|
||||
const vorgang = data.vorgang;
|
||||
@@ -69,7 +81,7 @@ export const actions = {
|
||||
console.log('O:', url);
|
||||
return { url };
|
||||
},
|
||||
upload3: async ({ request }: {request: Request}) => {
|
||||
upload3: async ({ request }) => {
|
||||
const requestData = await request.formData();
|
||||
const data = Object.fromEntries(requestData);
|
||||
const name = data.name;
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { deserialize } from '$app/forms';
|
||||
<script>
|
||||
import { deserialize, enhance } from '$app/forms';
|
||||
import Alert from '$lib/components/ui/Alert.svelte';
|
||||
import Button from '$lib/components/ui/Button.svelte';
|
||||
import Modal from '$lib/components/ui/Modal/Modal.svelte';
|
||||
@@ -8,15 +8,23 @@
|
||||
import ModalFooter from '$lib/components/ui/Modal/ModalFooter.svelte';
|
||||
import shortenFileSize from '$lib/helper/shortenFileSize.js';
|
||||
import Exclamation from '$lib/icons/Exclamation.svelte';
|
||||
import FileRect from '$lib/icons/File-rect.svelte';
|
||||
|
||||
export let form;
|
||||
|
||||
let open = false;
|
||||
let inProgress = false;
|
||||
let vorgang = '';
|
||||
const code_len = 8;
|
||||
let zugangscode = Math.random()
|
||||
.toString(36)
|
||||
.slice(2, 2 + code_len);
|
||||
let case_existing = undefined;
|
||||
let name = '';
|
||||
let etag: string | null = null;
|
||||
let files: FileList | null = null;
|
||||
/** @type {?string}*/
|
||||
let etag = null;
|
||||
/** @type {?FileList} */
|
||||
let files = null;
|
||||
|
||||
$: inProgress = form === null;
|
||||
|
||||
@@ -27,6 +35,7 @@
|
||||
let data = new FormData();
|
||||
data.append('vorgang', vorgang);
|
||||
data.append('name', name);
|
||||
data.append('zugangscode', zugangscode);
|
||||
const response = await fetch('?/validate', { method: 'POST', body: data });
|
||||
/** @type {import('@sveltejs/kit').ActionResult} */
|
||||
const result = deserialize(await response.text());
|
||||
@@ -69,7 +78,8 @@
|
||||
return null;
|
||||
}
|
||||
|
||||
async function buttonClick(event: MouseEvent) {
|
||||
/** @param {MouseEvent} event*/
|
||||
async function buttonClick(event) {
|
||||
if (!(await validateForm())) {
|
||||
event.preventDefault();
|
||||
return;
|
||||
@@ -104,42 +114,58 @@
|
||||
function swap_endian(val) {
|
||||
// from https://www.geeksforgeeks.org/bit-manipulation-swap-endianness-of-a-number/
|
||||
|
||||
let leftmost_byte = (val & eval(0x000000FF)) >> 0;
|
||||
let left_middle_byte = (val & eval(0x0000FF00)) >> 8;
|
||||
let right_middle_byte = (val & eval(0x00FF0000)) >> 16;
|
||||
let rightmost_byte = (val & eval(0xFF000000)) >> 24;
|
||||
let leftmost_byte = (val & eval(0x000000ff)) >> 0;
|
||||
let left_middle_byte = (val & eval(0x0000ff00)) >> 8;
|
||||
let right_middle_byte = (val & eval(0x00ff0000)) >> 16;
|
||||
let rightmost_byte = (val & eval(0xff000000)) >> 24;
|
||||
|
||||
leftmost_byte <<= 24;
|
||||
left_middle_byte <<= 16;
|
||||
right_middle_byte <<= 8;
|
||||
rightmost_byte <<= 0;
|
||||
|
||||
let res = (leftmost_byte | left_middle_byte | right_middle_byte | rightmost_byte)
|
||||
let res = leftmost_byte | left_middle_byte | right_middle_byte | rightmost_byte;
|
||||
|
||||
return res
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
async function check_valid_glb_file() {
|
||||
// GLD Header, magic value 0x46546C67, identifies data as binary glTF, 4 bytes
|
||||
// little endian!
|
||||
const GLD_MAGIC = 0x46546C67;
|
||||
const GLD_MAGIC = 0x46546c67;
|
||||
|
||||
// big endian!
|
||||
let file = files[0];
|
||||
let file_header = file.slice(0, 4)
|
||||
let header_bytes = await file_header.bytes()
|
||||
let file_header = file.slice(0, 4);
|
||||
let header_bytes = await file_header.bytes();
|
||||
let file_header_hex = '0x' + header_bytes.toHex().toString();
|
||||
|
||||
|
||||
if (GLD_MAGIC == swap_endian(file_header_hex)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// return true or false
|
||||
async function case_exists(case_no) {
|
||||
console.log('--- fired');
|
||||
// ping `/(angemeldet)/view` with caseNumber in POST body
|
||||
let url = '/view';
|
||||
let data = new FormData();
|
||||
data.append('caseNumber', case_no);
|
||||
const response = await fetch(url, { method: 'POST', body: data });
|
||||
|
||||
const code = response.status;
|
||||
|
||||
console.log(`+++ ${response.redirected}`);
|
||||
|
||||
if (code == 303) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="mx-auto max-w-2xl">
|
||||
@@ -174,6 +200,7 @@
|
||||
id="vorgang"
|
||||
autocomplete={vorgang}
|
||||
class="block flex-1 border-0 bg-transparent py-1.5 pl-1 text-gray-900 placeholder:text-gray-400 focus:ring-0 sm:text-sm sm:leading-6"
|
||||
on:input={() => case_exists(vorgang)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -209,6 +236,32 @@
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="zugangscode" class="block text-sm font-medium leading-6 text-gray-900"
|
||||
><span class="flex"
|
||||
>{#if formErrors?.zugangscode}
|
||||
<span class="inline-block mr-1"><Exclamation /></span>
|
||||
{/if} Zugangscode</span
|
||||
></label
|
||||
>
|
||||
<div class="mt-2">
|
||||
<div
|
||||
class="flex rounded-md shadow-sm ring-1 ring-inset ring-gray-300 focus-within:ring-2 focus-within:ring-inset focus-within:ring-indigo-600"
|
||||
>
|
||||
<input
|
||||
bind:value={zugangscode}
|
||||
type="text"
|
||||
name="zugangscode"
|
||||
id="zugangscode"
|
||||
class="block flex-1 border-0 bg-transparent py-1.5 pl-1 text-gray-900 placeholder:text-gray-400 focus:ring-0 sm:text-sm sm:leading-6"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{#if formErrors?.code}
|
||||
<p class="block text-sm leading-6 text-red-900 mt-2">{formErrors.code}</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="col-span-full">
|
||||
<label for="file" class="block text-sm font-medium leading-6 text-gray-900"
|
||||
><span class="flex"
|
||||
@@ -221,18 +274,7 @@
|
||||
class="mt-2 flex justify-center rounded-lg border border-dashed border-gray-900/25 px-6 py-10"
|
||||
>
|
||||
<div class="text-center">
|
||||
<svg
|
||||
class="mx-auto h-12 w-12 text-gray-300"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M1.5 6a2.25 2.25 0 012.25-2.25h16.5A2.25 2.25 0 0122.5 6v12a2.25 2.25 0 01-2.25 2.25H3.75A2.25 2.25 0 011.5 18V6zM3 16.06V18c0 .414.336.75.75.75h16.5A.75.75 0 0021 18v-1.94l-2.69-2.689a1.5 1.5 0 00-2.12 0l-.88.879.97.97a.75.75 0 11-1.06 1.06l-5.16-5.159a1.5 1.5 0 00-2.12 0L3 16.061zm10.125-7.81a1.125 1.125 0 112.25 0 1.125 1.125 0 01-2.25 0z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<FileRect />
|
||||
<div class="mt-4 flex text-sm leading-6 text-gray-600">
|
||||
<label
|
||||
for="file"
|
||||
|
||||
@@ -3,11 +3,13 @@ import { fail, redirect } from '@sveltejs/kit';
|
||||
|
||||
/** @type {import('./$types').Actions} */
|
||||
export const actions = {
|
||||
default: async ({ request }: {request: Request}) => {
|
||||
default: async ({ request }) => {
|
||||
const data = await request.formData();
|
||||
console.log(`--- ${Object.keys(data)}`)
|
||||
const caseNumber = data.get('caseNumber');
|
||||
|
||||
if (!caseNumber) {
|
||||
console.log('^^^ here')
|
||||
return fail(400, {
|
||||
success: false,
|
||||
caseNumber,
|
||||
@@ -15,13 +17,20 @@ export const actions = {
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof caseNumber === 'string' && !(await caseNumberOccupied(caseNumber))) {
|
||||
let res = (await caseNumberOccupied(caseNumber))
|
||||
console.log(`gibt es? ${res} + ${caseNumber}`)
|
||||
if (!(await caseNumberOccupied(caseNumber))) {
|
||||
console.log('^^^ there')
|
||||
return fail(400, {
|
||||
success: false,
|
||||
caseNumber,
|
||||
error: { caseNumber: 'Die Vorgangsnummer existiert in dieser Anwendung nicht.' }
|
||||
});
|
||||
}
|
||||
throw redirect(303, `/list/${caseNumber}`);
|
||||
else {
|
||||
throw redirect(303, `/list/${caseNumber}`);
|
||||
console.log(`---blabla ${caseNumber}`)
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
@@ -1,5 +1,10 @@
|
||||
<script lang="ts">
|
||||
<script>
|
||||
import Alert from '$lib/components/ui/Alert.svelte';
|
||||
import Button from '$lib/components/ui/Button.svelte';
|
||||
import Modal from '$lib/components/ui/Modal/Modal.svelte';
|
||||
import ModalTitle from '$lib/components/ui/Modal/ModalTitle.svelte';
|
||||
import ModalContent from '$lib/components/ui/Modal/ModalContent.svelte';
|
||||
import ModalFooter from '$lib/components/ui/Modal/ModalFooter.svelte';
|
||||
import Exclamation from '$lib/icons/Exclamation.svelte';
|
||||
|
||||
export let form;
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { client } from '$lib/minio';
|
||||
import type { PageServerLoad } from './$types';
|
||||
|
||||
/** @type {import('./$types').PageServerLoad} */
|
||||
export const load: PageServerLoad = async ({ params }) => {
|
||||
export async function load({ params }) {
|
||||
const { vorgang, tatort } = params;
|
||||
const url = await client.presignedUrl('GET', 'tatort', `${vorgang}/${tatort}`);
|
||||
return { url };
|
||||
@@ -1,4 +1,4 @@
|
||||
<script lang="ts">
|
||||
<script>
|
||||
import Panel from '$lib/components/ui/Panel.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import Button from '$lib/components/ui/Button.svelte';
|
||||
@@ -19,11 +19,18 @@
|
||||
let cameraAzimuth = 0;
|
||||
let cameraPolar = 0;
|
||||
|
||||
let frontView = cameraAzimuth === 0 && cameraPolar === 0 ? true : false;
|
||||
|
||||
let topView = cameraAzimuth === 0 && cameraPolar === 90 ? true : false;
|
||||
|
||||
let cameraZoom = 100;
|
||||
let xRotation = 0;
|
||||
let yRotation = 0;
|
||||
let zRotation = 0;
|
||||
|
||||
/**
|
||||
* @type {any}
|
||||
*/
|
||||
let modelViewer;
|
||||
|
||||
$: style = `width: ${progress}%`;
|
||||
@@ -31,7 +38,7 @@
|
||||
/**
|
||||
* @param {any} detail
|
||||
*/
|
||||
const onProgress = ({ detail }) => {
|
||||
function onProgress({ detail }) {
|
||||
progress = Math.ceil(detail.totalProgress * 100.0);
|
||||
if (progress == 100) {
|
||||
setTimeout(() => {
|
||||
@@ -82,7 +89,10 @@
|
||||
</script>
|
||||
|
||||
<div class="h-full model w-full bg-neutral-200 p-4 transition-all delay-250">
|
||||
<!-- xr-environment -->
|
||||
<model-viewer
|
||||
ar
|
||||
shadow-intensity="1"
|
||||
src={data.url}
|
||||
bind:this={modelViewer}
|
||||
touch-action="pan-y"
|
||||
@@ -101,7 +111,18 @@
|
||||
class:opacity-0={!hideProgressScreen}
|
||||
class:hidden={!hideProgressScreen}
|
||||
>
|
||||
<button slot="ar-button" id="ar-button"> 👋 Activate AR </button>
|
||||
|
||||
<div id="ar-prompt">AR-Prompt</div>
|
||||
|
||||
<button id="ar-failure"> AR is not tracking! </button>
|
||||
<div class="flex flex-col bg-white/50">
|
||||
<button
|
||||
on:click={() => {
|
||||
console.log(modelViewer.ar, modelViewer.getAttribute('ar-status'));
|
||||
}}>Test</button
|
||||
>
|
||||
|
||||
<!--3 Buttons-->
|
||||
<div class="p-2">
|
||||
<Button
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<script lang="ts">
|
||||
<script>
|
||||
import '../app.css';
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { dev } from '$app/environment';
|
||||
import { fail, redirect, type Cookies } from '@sveltejs/kit';
|
||||
import { fail, redirect } from '@sveltejs/kit';
|
||||
import { authenticate } from '$lib/auth';
|
||||
import type { RequestEvent } from '../(angemeldet)/$types';
|
||||
|
||||
const COOKIE_NAME = 'session';
|
||||
|
||||
/** @type {import('./$types').Actions} */
|
||||
export const actions = {
|
||||
login: async ({ request, cookies }: {request: Request, cookies: Cookies}) => {
|
||||
login: async ({ request, cookies }) => {
|
||||
const data = await request.formData();
|
||||
const user = data.get('user');
|
||||
const password = data.get('password');
|
||||
@@ -24,7 +23,7 @@ export const actions = {
|
||||
});
|
||||
throw redirect(303, '/');
|
||||
},
|
||||
logout: async (event: RequestEvent) => {
|
||||
logout: async (event) => {
|
||||
event.cookies.delete(COOKIE_NAME, {path: '/'});
|
||||
event.locals.user = null;
|
||||
return { success: true };
|
||||
@@ -1,4 +1,9 @@
|
||||
<script lang="ts">
|
||||
<script>
|
||||
import Panel from '$lib/components/ui/Panel.svelte';
|
||||
import Button from '$lib/components/ui/Button.svelte';
|
||||
import Alert from '$lib/components/ui/Alert.svelte';
|
||||
import Login from '$lib/icons/Login.svelte';
|
||||
|
||||
/** @type {import('./$types').ActionData} */
|
||||
export let form;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { client } from '$lib/minio';
|
||||
/** @type {import('./$types').RequestHandler} */
|
||||
export async function GET({ params }) {
|
||||
const prefix = params.vorgang ? `${params.vorgang}/` : '';
|
||||
const stream = client.listObjectsV2('tatort', prefix, false, '');
|
||||
let stream = client.listObjectsV2('tatort', prefix, false, '');
|
||||
const result = new ReadableStream({
|
||||
start(controller) {
|
||||
stream.on('data', (data) => {
|
||||
@@ -1,7 +1,8 @@
|
||||
import { client } from '$lib/minio';
|
||||
|
||||
/** @type {import('./$types').RequestHandler} */
|
||||
export async function GET() {
|
||||
const stream = client.listObjectsV2('tatort', '', true);
|
||||
var stream = client.listObjectsV2('tatort', '', true);
|
||||
const result = new ReadableStream({
|
||||
start(controller) {
|
||||
stream.on('data', (data) => {
|
||||
6
src/routes/api/upload/+server.js
Normal file
6
src/routes/api/upload/+server.js
Normal file
@@ -0,0 +1,6 @@
|
||||
import { client } from '$lib/minio';
|
||||
|
||||
/** @type {import('./$types').RequestHandler} */
|
||||
export async function GET(params) {
|
||||
console.log('GET', params);
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import type { RequestHandler } from "@sveltejs/kit";
|
||||
|
||||
export async function GET(params: RequestHandler) {
|
||||
console.log('GET', params);
|
||||
}
|
||||
14
static/1.svg
Normal file
14
static/1.svg
Normal file
@@ -0,0 +1,14 @@
|
||||
<svg
|
||||
class="h-6 w-6 text-gray-600 group-hover:text-indigo-600"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M13.5 16.875h3.375m0 0h3.375m-3.375 0V13.5m0 3.375v3.375M6 10.5h2.25a2.25 2.25 0 002.25-2.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v2.25A2.25 2.25 0 006 10.5zm0 9.75h2.25A2.25 2.25 0 0010.5 18v-2.25a2.25 2.25 0 00-2.25-2.25H6a2.25 2.25 0 00-2.25 2.25V18A2.25 2.25 0 006 20.25zm9.75-9.75H18a2.25 2.25 0 002.25-2.25V6A2.25 2.25 0 0018 3.75h-2.25A2.25 2.25 0 0013.5 6v2.25a2.25 2.25 0 002.25 2.25z"
|
||||
/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 714 B |
@@ -10,9 +10,7 @@
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"moduleResolution": "bundler"
|
||||
},
|
||||
"include": ["src/**/*", "src/node_modules"],
|
||||
"exclude": ["node_modules/*", "__sapper__/*", "public/*"]
|
||||
}
|
||||
// Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
|
||||
// except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user