feat: Add Analysis page, run comparison, notifications, and config editor

Dashboard enhancements:
- Add Analysis page with tabs: Overview, Parameters, Pareto, Correlations, Constraints, Surrogate, Runs
- Add PlotlyCorrelationHeatmap for parameter-objective correlation analysis
- Add PlotlyFeasibilityChart for constraint satisfaction visualization
- Add PlotlySurrogateQuality for FEA vs NN prediction comparison
- Add PlotlyRunComparison for comparing optimization runs within a study

Real-time improvements:
- Replace watchdog file-watching with SQLite database polling for better Windows reliability
- Add DatabasePoller class with 2-second polling interval
- Enhanced WebSocket messages: trial_completed, new_best, pareto_update, progress

Desktop notifications:
- Add useNotifications hook using Web Notifications API
- Add NotificationSettings toggle component
- Notify users when new best solutions are found

Config editor:
- Add PUT /studies/{study_id}/config endpoint with auto-backup
- Add ConfigEditor modal with tabs: General, Variables, Objectives, Settings, JSON
- Prevents editing while optimization is running

Enhanced Pareto visualization:
- Add dark mode styling with transparent backgrounds
- Add stats bar showing Pareto, FEA, NN, and infeasible counts
- Add Pareto front connecting line for 2D view
- Add table showing top 10 Pareto-optimal solutions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Antoine
2025-12-05 19:57:20 -05:00
parent 5c660ff270
commit 5fb94fdf01
27 changed files with 5878 additions and 722 deletions

View File

@@ -10,7 +10,8 @@ import {
X,
RefreshCw,
AlertCircle,
FolderOpen
FolderOpen,
Plus
} from 'lucide-react';
import { useStudy } from '../context/StudyContext';
import { useClaudeTerminal } from '../context/ClaudeTerminalContext';
@@ -256,16 +257,29 @@ export const ClaudeTerminal: React.FC<ClaudeTerminalProps> = ({
// Set study context - sends context message to Claude silently
const setStudyContext = useCallback(() => {
if (!wsRef.current || wsRef.current.readyState !== WebSocket.OPEN || !selectedStudy?.id) return;
if (!wsRef.current || wsRef.current.readyState !== WebSocket.OPEN) return;
setSettingContext(true);
// Send context message with POS bootstrap instructions and study context
const contextMessage =
`You are helping with Atomizer optimization. ` +
`First read: .claude/skills/00_BOOTSTRAP.md for task routing. ` +
`Then follow the Protocol Execution Framework. ` +
`Study context: Working on "${selectedStudy.id}" at studies/${selectedStudy.id}/. ` +
`Use atomizer conda env. Acknowledge briefly.`;
let contextMessage: string;
if (selectedStudy?.id) {
// Existing study context
contextMessage =
`You are helping with Atomizer optimization. ` +
`First read: .claude/skills/00_BOOTSTRAP.md for task routing. ` +
`Then follow the Protocol Execution Framework. ` +
`Study context: Working on "${selectedStudy.id}" at studies/${selectedStudy.id}/. ` +
`Use atomizer conda env. Acknowledge briefly.`;
} else {
// No study selected - offer to create new study
contextMessage =
`You are helping with Atomizer optimization. ` +
`First read: .claude/skills/00_BOOTSTRAP.md for task routing. ` +
`No study is currently selected. ` +
`Read .claude/skills/guided-study-wizard.md and help the user create a new optimization study. ` +
`Use atomizer conda env. Start the guided wizard by asking what they want to optimize.`;
}
wsRef.current.send(JSON.stringify({ type: 'input', data: contextMessage + '\n' }));
// Mark as done after Claude has had time to process
@@ -325,33 +339,37 @@ export const ClaudeTerminal: React.FC<ClaudeTerminalProps> = ({
{isConnected ? 'Disconnect' : 'Connect'}
</button>
{/* Set Context button - always show, with different states */}
{/* Set Context button - works for both existing study and new study creation */}
<button
onClick={setStudyContext}
disabled={!selectedStudy?.id || !isConnected || settingContext || contextSet}
disabled={!isConnected || settingContext || contextSet}
className={`px-3 py-1.5 text-sm rounded-lg transition-colors flex items-center gap-2 ${
contextSet
? 'bg-green-600/20 text-green-400'
: !selectedStudy?.id || !isConnected
: !isConnected
? 'bg-dark-600 text-dark-400'
: 'bg-primary-600/20 text-primary-400 hover:bg-primary-600/30'
: selectedStudy?.id
? 'bg-primary-600/20 text-primary-400 hover:bg-primary-600/30'
: 'bg-yellow-600/20 text-yellow-400 hover:bg-yellow-600/30'
} disabled:opacity-50 disabled:cursor-not-allowed`}
title={
!selectedStudy?.id
? 'No study selected - select a study from Home page'
: !isConnected
? 'Connect first to set study context'
: contextSet
? 'Context already set'
: `Set context to study: ${selectedStudy.id}`
!isConnected
? 'Connect first to set context'
: contextSet
? 'Context already set'
: selectedStudy?.id
? `Set context to study: ${selectedStudy.id}`
: 'Start guided study creation wizard'
}
>
{settingContext ? (
<RefreshCw className="w-3 h-3 animate-spin" />
) : (
) : selectedStudy?.id ? (
<FolderOpen className="w-3 h-3" />
) : (
<Plus className="w-3 h-3" />
)}
{contextSet ? 'Context Set' : selectedStudy?.id ? 'Set Context' : 'No Study'}
{contextSet ? 'Context Set' : selectedStudy?.id ? 'Set Context' : 'New Study'}
</button>
{onToggleExpand && (