fix: HIGH issues #13,#14,#18,#19,#20 — frontend state/sync: copy-paste selection, dynamic activeLayer, group creation, Yjs awareness protocol, connect sync

This commit is contained in:
A0 Orchestrator
2026-06-30 12:42:49 +02:00
parent 5a21fc0bfa
commit d09b1dfc2e
8 changed files with 353 additions and 62 deletions
+24 -8
View File
@@ -111,6 +111,7 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
// Right sidebar
const [activeRightPanel, setActiveRightPanel] = useState<RightPanel>('tool');
const [selectedElement, setSelectedElement] = useState<CADElement | null>(null);
const [selectedElementIds, setSelectedElementIds] = useState<string[]>([]);
const [layers, setLayers] = useState<CADLayer[]>(initialLayers);
const [activeLayerId, setActiveLayerId] = useState<string>('layer-0');
const [blocks, setBlocks] = useState<BlockDefinition[]>(initialBlocks);
@@ -191,6 +192,8 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
bgConfigRef.current = bgConfig;
const activeLayerIdRef = useRef(activeLayerId);
activeLayerIdRef.current = activeLayerId;
const selectedElementIdsRef = useRef(selectedElementIds);
selectedElementIdsRef.current = selectedElementIds;
// Clipboard (for copy/paste)
const clipboardRef = React.useRef<CADElement[] | null>(null);
@@ -642,11 +645,16 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
}, [blocks, activeLayerId, collab, drawingId, token]);
const handleSelectionChange = useCallback((selectedIds: string[]) => {
setSelectedElementIds(selectedIds);
if (selectedIds.length === 1) {
const el = elements.find(e => e.id === selectedIds[0]);
setSelectedElement(el ?? null);
} else {
} else if (selectedIds.length === 0) {
setSelectedElement(null);
} else {
// Multiple elements selected — keep the first one as a representative for the properties panel
const el = elements.find(e => e.id === selectedIds[0]);
setSelectedElement(el ?? null);
}
}, [elements]);
@@ -776,7 +784,8 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
if (action === 'undo') { handleUndo(); return; }
if (action === 'redo') { handleRedo(); return; }
if (action === 'copy') {
const selected = selectedElement ? [selectedElement] : [];
const ids = selectedElementIdsRef.current;
const selected = ids.length > 0 ? elements.filter(e => ids.includes(e.id)) : [];
const clip = selected.length > 0 ? selected : elements.slice(0, 1);
clipboardRef.current = clip;
setCommandHistory((prev) => [...prev, { prefix: '·', text: `${clip.length} Element(e) kopiert`, type: 'info' }]);
@@ -1136,10 +1145,17 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
// Group command: create group from currently selected elements
if (upper === 'GROUP' || upper === 'GRP') {
const gm = groupManagerRef.current;
// For now, group all elements (selection state is in InteractionEngine, not accessible here)
// In a full implementation, we'd need selected IDs from the interaction engine
setCommandHistory((prev) => [...prev, { prefix: '·', text: 'Gruppe erstellt (Auswahl im Canvas erforderlich)', type: 'info' }]);
setGroups(gm.getGroups());
const ids = selectedElementIdsRef.current;
if (ids.length < 2) {
setCommandHistory((prev) => [...prev, { prefix: '·', text: 'Gruppe: Mindestens 2 Elemente auswählen', type: 'info' }]);
return;
}
const group = gm.createGroup(ids);
const newGroups = gm.getGroups();
setGroups(newGroups);
// Sync group to Yjs CRDT for real-time collaboration
collab.setGroup(group);
setCommandHistory((prev) => [...prev, { prefix: '·', text: `Gruppe erstellt: ${group.name} (${ids.length} Elemente)`, type: 'info' }]);
return;
}
@@ -1194,7 +1210,7 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
setCommandHistory((prev) => [...prev, { prefix: '·', text: `Unbekannter Befehl: ${cmd}`, type: 'info' }]);
}
}
}, [handleUndo, handleRedo, handleRibbonAction]);
}, [handleUndo, handleRedo, handleRibbonAction, collab]);
const handleKISend = useCallback(async (text: string) => {
const userMsg: KIMessage = { id: `ki-${Date.now()}`, role: 'user', content: text };
@@ -1249,7 +1265,7 @@ const CADEditor: React.FC<CADEditorProps> = ({ projectId, token, onNavigateBack
handleKISend(suggestion.label);
}, [handleKISend]);
const activeLayerName = layers.find((l) => l.id === 'layer-0')?.name ?? '—';
const activeLayerName = layers.find((l) => l.id === activeLayerId)?.name ?? '—';
// ─── Render ─────────────────────────────────────────────
return (