Phase 4.5+4.6: Modul-Konfiguration pro Workspace + Sidebar useMemo Fix

4.5 Modul-Konfiguration pro Workspace:
- WorkspaceManager: Config-Editor pro Modul (JSON textarea)
- Pro Modul kann JSON config bearbeitet werden (z.B. sichtbare Ordner-IDs)
- Generisch: jedes Modul definiert selbst was in seiner config steht

4.6 Bugfixes:
- Sidebar useMemo: isModuleVisible zu Abhaengigkeiten hinzugefuegt
- Bei Workspacewechsel wird Sidebar jetzt sofort neu berechnet

Tests: 17 Backend + 13 Frontend = 30/30 bestanden
This commit is contained in:
Agent Zero
2026-08-03 13:58:27 +02:00
parent 07d4587499
commit ea797b033a
2 changed files with 39 additions and 9 deletions
+1 -1
View File
@@ -133,7 +133,7 @@ export function Sidebar() {
if (a.order !== b.order) return a.order - b.order;
return a.label.localeCompare(b.label);
});
}, [manifests, menuOrderData, user]);
}, [manifests, menuOrderData, user, isModuleVisible]);
const [expandedItems, setExpandedItems] = useState<Set<string>>(new Set());
@@ -45,6 +45,7 @@ export function WorkspaceManager() {
const [moduleWsId, setModuleWsId] = useState<string | null>(null);
const [moduleConfig, setModuleConfig] = useState<WorkspaceModule[]>([]);
const [configEditingKey, setConfigEditingKey] = useState<string | null>(null);
const workspaces = wsData?.items || [];
@@ -156,14 +157,43 @@ export function WorkspaceManager() {
{moduleConfig.map(m => {
const mod = availableModules.find(a => a.key === m.module_key);
return (
<label key={m.module_key} className="flex items-center gap-2 p-2 border border-gray-200 dark:border-gray-700 rounded-md cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800">
<div key={m.module_key} className={`p-2 border rounded-md ${m.is_visible ? 'border-blue-300 dark:border-blue-700 bg-blue-50 dark:bg-blue-900/10' : 'border-gray-200 dark:border-gray-700'}`}>
<label className="flex items-center gap-2 cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded p-1">
<input
type="checkbox"
checked={m.is_visible}
onChange={() => toggleModule(m.module_key)}
/>
<span className="text-sm">{mod?.label || m.module_key}</span>
<span className="text-sm flex-1">{mod?.label || m.module_key}</span>
{m.is_visible && (
<button
onClick={(e) => { e.preventDefault(); setModuleConfig(prev => prev.map(x => x.module_key === m.module_key ? { ...x, config: x.config } : x)); setConfigEditingKey(configEditingKey === m.module_key ? null : m.module_key); }}
className="text-xs px-1.5 py-0.5 border rounded hover:bg-gray-100 dark:hover:bg-gray-700"
title="Konfiguration bearbeiten"
>
</button>
)}
</label>
{m.is_visible && configEditingKey === m.module_key && (
<div className="mt-2 space-y-1">
<textarea
className="w-full text-xs font-mono p-1.5 border border-gray-300 dark:border-gray-600 rounded bg-white dark:bg-gray-900 h-20"
placeholder='{"visible_folder_ids": []}'
value={JSON.stringify(m.config || {}, null, 2)}
onChange={(e) => {
try {
const parsed = JSON.parse(e.target.value);
setModuleConfig(prev => prev.map(x => x.module_key === m.module_key ? { ...x, config: parsed } : x));
} catch {
// Invalid JSON — keep raw text for editing
}
}}
/>
<p className="text-xs text-gray-400">JSON-Konfiguration für dieses Modul (z.B. sichtbare Ordner-IDs)</p>
</div>
)}
</div>
);
})}
</div>