/** * Task F4 – UI für LibraryProviderExtensions. * * Lädt alle übergebenen Provider (builtin/user/global) und rendert je Ordner * eine Sektion mit Thumbnail-Blöcken. Jeder Block ist als DragSource an den * bestehenden 'text/global-block-data'-Kanal angebunden (DragDrop → Canvas). */ import React, { useEffect, useState } from 'react'; import type { LibraryProviderExtension, LibBlock } from '../plugins/types'; interface Props { providers: LibraryProviderExtension[]; } interface Section { key: string; label: string; blocks: LibBlock[]; } const LibraryProviderPanel: React.FC = ({ providers }) => { const [sections, setSections] = useState([]); useEffect(() => { let cancelled = false; (async () => { const out: Section[] = []; for (const provider of providers) { try { const folders = await provider.listFolders(); for (const folder of folders) { try { const blocks = await provider.listBlocks(folder.id); if (blocks.length > 0) { out.push({ key: `${provider.id}/${folder.id}`, label: folder.label, blocks }); } } catch { // Ordner bei Fehler überspringen } } } catch { // Provider bei Fehler überspringen } } if (!cancelled) setSections(out); })(); return () => { cancelled = true; }; }, [providers]); const handleDragStart = (e: React.DragEvent, block: LibBlock) => { const payload = typeof block.payload === 'string' ? block.payload : JSON.stringify(block.payload ?? []); e.dataTransfer.setData('text/global-block-data', payload); e.dataTransfer.effectAllowed = 'copy'; }; if (sections.length === 0) return null; return (
{sections.map((section) => (
{section.label}
{section.blocks.map((block) => ( ))}
))}
); }; export default LibraryProviderPanel;