From 63c8968f874c83a8d654bd2ddf75c08bfb607098 Mon Sep 17 00:00:00 2001 From: Agent Zero Date: Fri, 28 Aug 2026 12:25:17 +0200 Subject: [PATCH] task(F1-frontend): library export/import buttons in block library tree --- frontend/src/components/BlockLibraryTree.tsx | 51 ++++++++++++++++++++ frontend/src/services/api.ts | 30 ++++++++++++ 2 files changed, 81 insertions(+) diff --git a/frontend/src/components/BlockLibraryTree.tsx b/frontend/src/components/BlockLibraryTree.tsx index 236edc9..df06de7 100644 --- a/frontend/src/components/BlockLibraryTree.tsx +++ b/frontend/src/components/BlockLibraryTree.tsx @@ -9,6 +9,8 @@ import { createGlobalBlock, renameGlobalBlock, deleteGlobalBlock, + exportLibrary, + importLibrary, } from '../services/api'; interface BlockLibraryTreeProps { @@ -38,6 +40,7 @@ const BlockLibraryTree: React.FC = ({ token, onBlockDragS } | null>(null); const [loading, setLoading] = useState(true); const fileInputRef = useRef(null); + const wcadInputRef = useRef(null); const [dragOverFolderId, setDragOverFolderId] = useState(null); const loadData = useCallback(async () => { @@ -59,6 +62,39 @@ const BlockLibraryTree: React.FC = ({ token, onBlockDragS loadData(); }, [loadData]); + // ─── Task F1: Library-Paket Export/Import ──────────────── + + const handleLibraryExport = useCallback(async () => { + try { + const pkg = await exportLibrary(token); + const blob = new Blob([JSON.stringify(pkg, null, 2)], { type: 'application/json' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = `web-cad-library-${new Date().toISOString().slice(0, 10)}.wcadlib`; + a.click(); + URL.revokeObjectURL(url); + } catch (err) { + alert(`Library-Export fehlgeschlagen: ${err instanceof Error ? err.message : String(err)}`); + } + }, [token]); + + const handleWcadFile = useCallback(async (e: React.ChangeEvent) => { + const file = e.target.files?.[0]; + if (!file) return; + try { + const text = await file.text(); + const pkg = JSON.parse(text); + const result = await importLibrary(token, pkg); + alert(`Bibliothek importiert: ${result.imported_blocks} Blöcke, ${result.imported_folders} Ordner`); + await loadData(); + } catch (err) { + alert(`Library-Import fehlgeschlagen: ${err instanceof Error ? err.message : String(err)}`); + } finally { + e.target.value = ''; + } + }, [token, loadData]); + // Build tree structure from flat lists const buildTree = useCallback((): FolderNode[] => { const folderMap = new Map(); @@ -366,6 +402,20 @@ const BlockLibraryTree: React.FC = ({ token, onBlockDragS
handleContextMenu(e, 'root', null, null)}>
🌐 Globale Bibliothek + + +
{tree.map(node => renderFolderNode(node, 0))} diff --git a/frontend/src/services/api.ts b/frontend/src/services/api.ts index 36758c1..6d72498 100644 --- a/frontend/src/services/api.ts +++ b/frontend/src/services/api.ts @@ -812,3 +812,33 @@ export async function deleteGuest(token: string, id: string): Promise { }); if (!res.ok) throw new Error(`Failed to delete guest: ${res.status}`); } + +// ─── Library Paket Export/Import (Task F1) ───────────── +export interface WcadlibPackage { + format: 'wcadlib'; + version: number; + exported_at?: string; + folders: Array<{ id: string; name: string; parent_id: string | null }>; + blocks: Array<{ name: string; folder_id: string | null; block_data: string; svg_data: string | null }>; +} + +export async function exportLibrary(token: string): Promise { + const res = await fetch(`${API_BASE}/api/global-blocks/export`, { + headers: authHeaders(token), + }); + if (!res.ok) throw new Error(`Failed to export library: ${res.status}`); + return res.json(); +} + +export async function importLibrary(token: string, pkg: { format: string; version?: number; folders?: Array<{ id: string; name: string; parent_id: string | null }>; blocks: Array<{ name: string; folder_id: string | null; block_data: string; svg_data: string | null }> }): Promise<{ imported_blocks: number; imported_folders: number }> { + const res = await fetch(`${API_BASE}/api/global-blocks/import`, { + method: 'POST', + headers: authHeaders(token), + body: JSON.stringify(pkg), + }); + if (!res.ok) { + const err = await res.text(); + throw new Error(`Failed to import library: ${res.status} ${err}`); + } + return res.json(); +}