fix(canvas): Bug fixes for node movement, drag-drop, config panel, and introspection

- SpecRenderer: Add localNodes state with applyNodeChanges for smooth node dragging
- SpecRenderer: Fix getDefaultNodeData() - extractor uses 'custom_function' type with function definition
- SpecRenderer: Fix constraint default - use constraint_type instead of type
- CanvasView: Show config panel INSTEAD of chat when node selected (not blocked)
- NodeConfigPanelV2: Enable showHeader for code editor toolbar (Generate/Snippets/Validate/Test buttons)
- NodeConfigPanelV2: Pass studyId to IntrospectionPanel
- IntrospectionPanel: Accept studyId prop and use correct API endpoint
- optimization.py: Search multiple directories for model files including 1_setup/model/
This commit is contained in:
2026-01-20 14:14:14 -05:00
parent cf8c57fdac
commit 47f8b50112
5 changed files with 1214 additions and 922 deletions

View File

@@ -20,6 +20,7 @@ import { useCanvasStore } from '../../../hooks/useCanvasStore';
interface IntrospectionPanelProps {
filePath: string;
studyId?: string;
onClose: () => void;
}
@@ -56,7 +57,7 @@ interface IntrospectionResult {
warnings: string[];
}
export function IntrospectionPanel({ filePath, onClose }: IntrospectionPanelProps) {
export function IntrospectionPanel({ filePath, studyId, onClose }: IntrospectionPanelProps) {
const [result, setResult] = useState<IntrospectionResult | null>(null);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
@@ -73,21 +74,37 @@ export function IntrospectionPanel({ filePath, onClose }: IntrospectionPanelProp
setIsLoading(true);
setError(null);
try {
const res = await fetch('/api/nx/introspect', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ file_path: filePath }),
});
if (!res.ok) throw new Error('Introspection failed');
let res;
// If we have a studyId, use the study-aware introspection endpoint
if (studyId) {
// Don't encode studyId - it may contain slashes for nested paths (e.g., M1_Mirror/study_name)
res = await fetch(`/api/optimization/studies/${studyId}/nx/introspect`);
} else {
// Fallback to direct path introspection
res = await fetch('/api/nx/introspect', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ file_path: filePath }),
});
}
if (!res.ok) {
const errData = await res.json().catch(() => ({}));
throw new Error(errData.detail || 'Introspection failed');
}
const data = await res.json();
setResult(data);
// Handle different response formats
setResult(data.introspection || data);
} catch (e) {
setError('Failed to introspect model');
console.error(e);
const msg = e instanceof Error ? e.message : 'Failed to introspect model';
setError(msg);
console.error('Introspection error:', e);
} finally {
setIsLoading(false);
}
}, [filePath]);
}, [filePath, studyId]);
useEffect(() => {
runIntrospection();