From 1371c2edd9d62f7cce18b7f2404d572390e988e4 Mon Sep 17 00:00:00 2001 From: chihlasm Date: Sat, 4 Apr 2026 07:52:28 +0000 Subject: [PATCH] feat: add AIAssistPanel with replace and merge modes Co-Authored-By: Claude Opus 4.6 (1M context) --- .../network/panels/AIAssistPanel.tsx | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 frontend/src/components/network/panels/AIAssistPanel.tsx diff --git a/frontend/src/components/network/panels/AIAssistPanel.tsx b/frontend/src/components/network/panels/AIAssistPanel.tsx new file mode 100644 index 00000000..53db5c3b --- /dev/null +++ b/frontend/src/components/network/panels/AIAssistPanel.tsx @@ -0,0 +1,131 @@ +import { useState, useCallback } from 'react' +import { Sparkles, ChevronUp, ChevronDown, AlertTriangle } from 'lucide-react' +import { cn } from '@/lib/utils' +import { networkDiagramsApi } from '@/api' +import type { AIGenerateResponse } from '@/types' + +interface AIAssistPanelProps { + onGenerate: (result: AIGenerateResponse, mode: 'replace' | 'merge') => void + getExistingBounds: () => { minX: number; maxX: number; minY: number; maxY: number } | null + hasNodes: boolean +} + +export function AIAssistPanel({ onGenerate, getExistingBounds, hasNodes }: AIAssistPanelProps) { + const [expanded, setExpanded] = useState(false) + const [description, setDescription] = useState('') + const [mode, setMode] = useState<'replace' | 'merge'>('replace') + const [loading, setLoading] = useState(false) + const [error, setError] = useState(null) + + const handleGenerate = useCallback(async () => { + if (!description.trim()) return + setLoading(true) + setError(null) + try { + const result = await networkDiagramsApi.aiGenerate({ + description: description.trim(), + mode, + existingBounds: mode === 'merge' ? getExistingBounds() : null, + }) + onGenerate(result, mode) + setDescription('') + setExpanded(false) + } catch (err: unknown) { + const msg = err instanceof Error ? err.message : 'Generation failed. Please try again.' + setError(msg) + } finally { + setLoading(false) + } + }, [description, mode, onGenerate, getExistingBounds]) + + if (!expanded) { + return ( +
+ +
+ ) + } + + return ( +
+
+
+ + AI Generate +
+ +
+ +
+
+ + +
+ + {mode === 'replace' && hasNodes && ( +
+ +

+ This will replace your current diagram. Save first if needed. +

+
+ )} + +