feat: Add WebSocket live updates and convergence visualization

Phase 4 - Live Updates:
- Create useOptimizationStream hook for real-time trial updates
- Replace polling with WebSocket subscription in SpecRenderer
- Auto-report errors to ErrorPanel via panel store
- Add progress tracking (FEA count, NN count, best trial)

Phase 5 - Convergence Visualization:
- Add ConvergenceSparkline component for mini line charts
- Add ProgressRing component for circular progress indicator
- Update ObjectiveNode to show convergence trend sparkline
- Add history field to ObjectiveNodeData schema
- Add live progress indicator centered on canvas when running

Bug fixes:
- Fix TypeScript errors in FloatingIntrospectionPanel (type casts)
- Fix ValidationPanel using wrong store method (selectNode vs setSelectedNodeId)
- Fix NodeConfigPanelV2 unused state variable
- Fix specValidator source.extractor_id path
- Clean up unused imports across components
This commit is contained in:
2026-01-21 21:48:35 -05:00
parent c224b16ac3
commit 2cb8dccc3a
10 changed files with 764 additions and 167 deletions

View File

@@ -5,7 +5,7 @@
* returning structured errors that can be displayed in the ValidationPanel.
*/
import { AtomizerSpec, DesignVariable, Extractor, Objective, Constraint } from '../../types/atomizer-spec';
import { AtomizerSpec } from '../../types/atomizer-spec';
import { ValidationError, ValidationData } from '../../hooks/usePanelStore';
// ============================================================================
@@ -178,9 +178,9 @@ const validationRules: ValidationRule[] = [
edge => edge.target === obj.id && edge.source.startsWith('ext_')
);
// Also check if source_extractor_id is set
const hasDirectSource = obj.source_extractor_id &&
spec.extractors.some(e => e.id === obj.source_extractor_id);
// Also check if source.extractor_id is set
const hasDirectSource = obj.source?.extractor_id &&
spec.extractors.some(e => e.id === obj.source.extractor_id);
if (!hasSource && !hasDirectSource) {
return {