zips are getting extracted
This commit is contained in:
Generated
+14
-4
@@ -2,7 +2,8 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="89f9fc3a-63ad-41cb-8d25-f07df352eb98" name="Changes" comment="">
|
<list default="true" id="89f9fc3a-63ad-41cb-8d25-f07df352eb98" name="Changes" comment="">
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/package.json" beforeDir="false" afterPath="$PROJECT_DIR$/package.json" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/pnpm-lock.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/pnpm-lock.yaml" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/routes/+page.svelte" beforeDir="false" afterPath="$PROJECT_DIR$/src/routes/+page.svelte" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/routes/+page.svelte" beforeDir="false" afterPath="$PROJECT_DIR$/src/routes/+page.svelte" afterDir="false" />
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
@@ -49,7 +50,7 @@
|
|||||||
<option name="presentableId" value="Default" />
|
<option name="presentableId" value="Default" />
|
||||||
<updated>1781169139290</updated>
|
<updated>1781169139290</updated>
|
||||||
<workItem from="1781169141138" duration="309000" />
|
<workItem from="1781169141138" duration="309000" />
|
||||||
<workItem from="1781251694220" duration="5262000" />
|
<workItem from="1781251694220" duration="5995000" />
|
||||||
</task>
|
</task>
|
||||||
<task id="LOCAL-00001" summary="adapts styling of rvg.legal">
|
<task id="LOCAL-00001" summary="adapts styling of rvg.legal">
|
||||||
<option name="closed" value="true" />
|
<option name="closed" value="true" />
|
||||||
@@ -59,7 +60,15 @@
|
|||||||
<option name="project" value="LOCAL" />
|
<option name="project" value="LOCAL" />
|
||||||
<updated>1781256112218</updated>
|
<updated>1781256112218</updated>
|
||||||
</task>
|
</task>
|
||||||
<option name="localTasksCounter" value="2" />
|
<task id="LOCAL-00002" summary="adds dropzone to add zips">
|
||||||
|
<option name="closed" value="true" />
|
||||||
|
<created>1781257473070</created>
|
||||||
|
<option name="number" value="00002" />
|
||||||
|
<option name="presentableId" value="LOCAL-00002" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1781257473070</updated>
|
||||||
|
</task>
|
||||||
|
<option name="localTasksCounter" value="3" />
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
@@ -70,7 +79,8 @@
|
|||||||
<component name="VcsManagerConfiguration">
|
<component name="VcsManagerConfiguration">
|
||||||
<option name="CLEAR_INITIAL_COMMIT_MESSAGE" value="true" />
|
<option name="CLEAR_INITIAL_COMMIT_MESSAGE" value="true" />
|
||||||
<MESSAGE value="adapts styling of rvg.legal" />
|
<MESSAGE value="adapts styling of rvg.legal" />
|
||||||
<option name="LAST_COMMIT_MESSAGE" value="adapts styling of rvg.legal" />
|
<MESSAGE value="adds dropzone to add zips" />
|
||||||
|
<option name="LAST_COMMIT_MESSAGE" value="adds dropzone to add zips" />
|
||||||
</component>
|
</component>
|
||||||
<component name="XDebuggerManager">
|
<component name="XDebuggerManager">
|
||||||
<breakpoint-manager>
|
<breakpoint-manager>
|
||||||
|
|||||||
+2
-1
@@ -31,6 +31,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@skeletonlabs/skeleton": "^4.15.2",
|
"@skeletonlabs/skeleton": "^4.15.2",
|
||||||
"@skeletonlabs/skeleton-svelte": "^4.15.2"
|
"@skeletonlabs/skeleton-svelte": "^4.15.2",
|
||||||
|
"fflate": "^0.8.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+8
@@ -14,6 +14,9 @@ importers:
|
|||||||
'@skeletonlabs/skeleton-svelte':
|
'@skeletonlabs/skeleton-svelte':
|
||||||
specifier: ^4.15.2
|
specifier: ^4.15.2
|
||||||
version: 4.15.2(svelte@5.56.3)
|
version: 4.15.2(svelte@5.56.3)
|
||||||
|
fflate:
|
||||||
|
specifier: ^0.8.3
|
||||||
|
version: 0.8.3
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@sveltejs/adapter-auto':
|
'@sveltejs/adapter-auto':
|
||||||
specifier: ^7.0.1
|
specifier: ^7.0.1
|
||||||
@@ -594,6 +597,9 @@ packages:
|
|||||||
picomatch:
|
picomatch:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
fflate@0.8.3:
|
||||||
|
resolution: {integrity: sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==}
|
||||||
|
|
||||||
fsevents@2.3.3:
|
fsevents@2.3.3:
|
||||||
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||||
@@ -1570,6 +1576,8 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
picomatch: 4.0.4
|
picomatch: 4.0.4
|
||||||
|
|
||||||
|
fflate@0.8.3: {}
|
||||||
|
|
||||||
fsevents@2.3.3:
|
fsevents@2.3.3:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
import { unzip } from "fflate";
|
||||||
|
|
||||||
|
export type ZipAttachmentKind = "pdf" | "image";
|
||||||
|
|
||||||
|
export type ZipAttachment = {
|
||||||
|
name: string;
|
||||||
|
path: string;
|
||||||
|
kind: ZipAttachmentKind;
|
||||||
|
data: Uint8Array;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ProcessedZipArchive = {
|
||||||
|
name: string;
|
||||||
|
attachments: ZipAttachment[];
|
||||||
|
xjustizNachrichtXml: Uint8Array | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const IMAGE_EXTENSIONS = new Set([
|
||||||
|
".avif",
|
||||||
|
".bmp",
|
||||||
|
".gif",
|
||||||
|
".heic",
|
||||||
|
".jpeg",
|
||||||
|
".jpg",
|
||||||
|
".jp2",
|
||||||
|
".png",
|
||||||
|
".tif",
|
||||||
|
".tiff",
|
||||||
|
".webp",
|
||||||
|
]);
|
||||||
|
|
||||||
|
const ZIP_META_FILE_NAME = "xjustiz_nachricht.xml";
|
||||||
|
|
||||||
|
const unzipArchive = (data: Uint8Array) =>
|
||||||
|
new Promise<Record<string, Uint8Array>>((resolve, reject) => {
|
||||||
|
unzip(data, (error, files) => {
|
||||||
|
if (error) {
|
||||||
|
reject(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(files);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const getBaseName = (path: string) => path.split("/").pop() ?? path;
|
||||||
|
|
||||||
|
const getExtension = (path: string) => {
|
||||||
|
const baseName = getBaseName(path).toLowerCase();
|
||||||
|
const lastDotIndex = baseName.lastIndexOf(".");
|
||||||
|
|
||||||
|
return lastDotIndex === -1 ? "" : baseName.slice(lastDotIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
const isPdf = (path: string) => getExtension(path) === ".pdf";
|
||||||
|
|
||||||
|
const isImage = (path: string) => IMAGE_EXTENSIONS.has(getExtension(path));
|
||||||
|
|
||||||
|
export const extractZipArchive = async (file: File): Promise<ProcessedZipArchive> => {
|
||||||
|
const archiveBytes = new Uint8Array(await file.arrayBuffer());
|
||||||
|
const files = await unzipArchive(archiveBytes);
|
||||||
|
|
||||||
|
const attachments: ZipAttachment[] = [];
|
||||||
|
let xjustizNachrichtXml: Uint8Array | null = null;
|
||||||
|
|
||||||
|
for (const [path, data] of Object.entries(files)) {
|
||||||
|
const baseName = getBaseName(path);
|
||||||
|
|
||||||
|
if (baseName.toLowerCase() === ZIP_META_FILE_NAME) {
|
||||||
|
xjustizNachrichtXml = data;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPdf(path)) {
|
||||||
|
attachments.push({
|
||||||
|
name: baseName,
|
||||||
|
path,
|
||||||
|
kind: "pdf",
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isImage(path)) {
|
||||||
|
attachments.push({
|
||||||
|
name: baseName,
|
||||||
|
path,
|
||||||
|
kind: "image",
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: file.name,
|
||||||
|
attachments,
|
||||||
|
xjustizNachrichtXml,
|
||||||
|
};
|
||||||
|
};
|
||||||
+44
-8
@@ -1,11 +1,32 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Card from "$lib/components/Card.svelte";
|
import Card from "$lib/components/Card.svelte";
|
||||||
import ZipDropzone from "$lib/components/ZipDropzone.svelte";
|
import ZipDropzone from "$lib/components/ZipDropzone.svelte";
|
||||||
|
import { extractZipArchive, type ProcessedZipArchive } from "$lib/zip-processing";
|
||||||
|
|
||||||
let selectedZipFiles: File[] = $state([]);
|
let selectedZipFiles: File[] = $state([]);
|
||||||
|
let processedZipFiles: ProcessedZipArchive[] = $state([]);
|
||||||
|
let pendingZipCount = $state(0);
|
||||||
|
|
||||||
const handleFilesSelected = (files: File[]) => {
|
const handleFilesSelected = (files: File[]) => {
|
||||||
selectedZipFiles = [...selectedZipFiles, ...files];
|
selectedZipFiles = [...selectedZipFiles, ...files];
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
void processZipFile(file);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const processZipFile = async (file: File) => {
|
||||||
|
pendingZipCount += 1;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const processedZipArchive = await extractZipArchive(file);
|
||||||
|
processedZipArchive.xjustizNachrichtXml
|
||||||
|
processedZipFiles = [...processedZipFiles, processedZipArchive];
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Failed to process ${file.name}`, error);
|
||||||
|
} finally {
|
||||||
|
pendingZipCount -= 1;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -15,16 +36,31 @@
|
|||||||
{:else}
|
{:else}
|
||||||
<div class="flex min-h-[calc(-180px+100vh)] w-full grow flex-col justify-center gap-4 px-4 py-6">
|
<div class="flex min-h-[calc(-180px+100vh)] w-full grow flex-col justify-center gap-4 px-4 py-6">
|
||||||
<div class="flex flex-row items-baseline justify-center gap-2">
|
<div class="flex flex-row items-baseline justify-center gap-2">
|
||||||
<h2 class="h1 text-[20px] font-bold text-primary-900">ZIP-Dateien geladen</h2>
|
<h2 class="h1 text-[20px] font-bold text-primary-900">ZIP-Dateien werden verarbeitet</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul class="mx-auto w-full max-w-3xl space-y-2">
|
<div class="mx-auto flex w-full max-w-3xl flex-col gap-3">
|
||||||
{#each selectedZipFiles as file}
|
<div class="rounded-container bg-primary-50 px-4 py-3 text-[14px] font-medium text-primary-900">
|
||||||
<li class="rounded-container bg-primary-50 px-4 py-3 text-[14px] font-medium text-primary-900">
|
{#if pendingZipCount > 0}
|
||||||
{file.name}
|
Noch {pendingZipCount} ZIP-Datei{pendingZipCount === 1 ? "" : "en"} in Bearbeitung.
|
||||||
</li>
|
{:else}
|
||||||
{/each}
|
Alle ZIP-Dateien wurden verarbeitet.
|
||||||
</ul>
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if processedZipFiles.length > 0}
|
||||||
|
<ul class="space-y-2">
|
||||||
|
{#each processedZipFiles as file}
|
||||||
|
<li class="rounded-container bg-primary-50 px-4 py-3 text-[14px] font-medium text-primary-900">
|
||||||
|
{file.name} - {file.attachments.length} relevante Datei{file.attachments.length === 1 ? "" : "en"}
|
||||||
|
{#if file.xjustizNachrichtXml}
|
||||||
|
- xjustiz_nachricht.xml vorhanden
|
||||||
|
{/if}
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{/snippet}
|
{/snippet}
|
||||||
|
|||||||
Reference in New Issue
Block a user