Files
Atomizer/docs/04_USER_GUIDES/DASHBOARD_REACT_IMPLEMENTATION.md
Anto01 e3bdb08a22 feat: Major update with validators, skills, dashboard, and docs reorganization
- Add validation framework (config, model, results, study validators)
- Add Claude Code skills (create-study, run-optimization, generate-report,
  troubleshoot, analyze-model)
- Add Atomizer Dashboard (React frontend + FastAPI backend)
- Reorganize docs into structured directories (00-09)
- Add neural surrogate modules and training infrastructure
- Add multi-objective optimization support

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 19:23:58 -05:00

16 KiB

Dashboard React Implementation - Progress Report

Date: November 21, 2025 Status: 🔄 In Progress - Configuration Complete, Components Ready


What Has Been Completed

1. Project Structure Created

atomizer-dashboard/frontend/
├── src/
│   ├── components/         # Reusable UI components ✅
│   ├── hooks/             # Custom React hooks ✅
│   ├── pages/             # Page components (empty - ready for Dashboard.tsx)
│   ├── types/             # TypeScript type definitions ✅
│   ├── utils/             # Utility functions (empty - ready for API utils)
│   ├── index.css          # Tailwind CSS styles ✅
│   └── (main.tsx, App.tsx pending)
├── public/                # Static assets
├── index.html             # HTML entry point ✅
├── package.json           # Dependencies ✅
├── tsconfig.json          # TypeScript config ✅
├── vite.config.ts         # Vite config with proxy ✅
├── tailwind.config.js     # Tailwind CSS config ✅
└── postcss.config.js      # PostCSS config ✅

2. Configuration Files

3. TypeScript Types

File: src/types/index.ts

Complete type definitions for:

  • Study - Study metadata
  • Trial - Optimization trial data
  • PrunedTrial - Pruned trial diagnostics
  • WebSocketMessage - WebSocket message types
  • ConvergenceDataPoint - Chart data for convergence plot
  • ParameterSpaceDataPoint - Chart data for parameter space
  • All API response types

4. Custom Hooks

File: src/hooks/useWebSocket.ts

Professional WebSocket hook with:

  • Automatic connection management
  • Reconnection with exponential backoff (up to 5 attempts)
  • Type-safe message handling
  • Callback system for different message types
  • Connection status tracking

Usage:

const { isConnected, lastMessage } = useWebSocket({
  studyId: selectedStudyId,
  onTrialCompleted: (trial) => setTrials(prev => [trial, ...prev]),
  onNewBest: (trial) => showAlert('New best trial!'),
  onProgress: (progress) => updateProgress(progress),
  onTrialPruned: (pruned) => showWarning(pruned.pruning_cause),
});

5. Reusable UI Components

Created professional, typed components:

Card.tsx

  • Wrapper for content sections
  • Optional title prop
  • Tailwind CSS card styling

MetricCard.tsx

  • Display key metrics (total trials, best value, etc.)
  • Customizable label and value color
  • Responsive design

Badge.tsx

  • Status indicators (success, warning, error, info)
  • Variant-based styling
  • Used for study status display

StudyCard.tsx

  • Study list item component
  • Progress bar visualization
  • Active state highlighting
  • Click handler for study selection

6. Tailwind CSS Setup

File: src/index.css

Custom utility classes:

  • .card - Card container styling
  • .btn, .btn-primary, .btn-secondary - Button variants
  • .input - Form input styling
  • .badge-* - Badge variants
  • Custom scrollbar styling for dark theme

🔨 Next Steps - Manual Completion Required

Since npm is not available in the current environment, you'll need to complete the following steps manually:

Step 1: Install Dependencies

cd atomizer-dashboard/frontend
npm install

This will install:

  • React, React DOM, React Router
  • Recharts for charts
  • TailwindCSS, Autoprefixer, PostCSS
  • Vite and TypeScript
  • ESLint for code quality

Step 2: Create Remaining Components

I've prepared the structure, but you'll need to create:

src/main.tsx (React entry point)

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './index.css';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
);

src/App.tsx (Main application component)

import { useState, useEffect } from 'react';
import Dashboard from './pages/Dashboard';
import type { Study } from './types';

function App() {
  const [studies, setStudies] = useState<Study[]>([]);
  const [selectedStudyId, setSelectedStudyId] = useState<string | null>(null);

  useEffect(() => {
    // Fetch studies from API
    fetch('/api/optimization/studies')
      .then(res => res.json())
      .then(data => {
        setStudies(data.studies);
        if (data.studies.length > 0) {
          setSelectedStudyId(data.studies[0].id);
        }
      })
      .catch(err => console.error('Failed to load studies:', err));
  }, []);

  return (
    <div className="min-h-screen bg-dark-700">
      <Dashboard
        studies={studies}
        selectedStudyId={selectedStudyId}
        onStudySelect={setSelectedStudyId}
      />
    </div>
  );
}

export default App;

src/pages/Dashboard.tsx (Main dashboard page)

This is the core component that needs to be created. It should:

  • Use the useWebSocket hook for real-time updates
  • Display study list in sidebar using StudyCard components
  • Show metrics using MetricCard components
  • Render convergence and parameter space charts with Recharts
  • Handle trial feed display
  • Show pruning alerts

Template structure:

import { useState, useEffect } from 'react';
import { useWebSocket } from '../hooks/useWebSocket';
import { Card } from '../components/Card';
import { MetricCard } from '../components/MetricCard';
import { StudyCard } from '../components/StudyCard';
import type { Study, Trial } from '../types';
// Import Recharts components for charts

interface DashboardProps {
  studies: Study[];
  selectedStudyId: string | null;
  onStudySelect: (studyId: string) => void;
}

export default function Dashboard({ studies, selectedStudyId, onStudySelect }: DashboardProps) {
  const [trials, setTrials] = useState<Trial[]>([]);
  const [bestValue, setBestValue] = useState<number>(Infinity);

  // WebSocket connection
  const { isConnected } = useWebSocket({
    studyId: selectedStudyId,
    onTrialCompleted: (trial) => {
      setTrials(prev => [trial, ...prev].slice(0, 20));
      if (trial.objective < bestValue) {
        setBestValue(trial.objective);
      }
    },
    onNewBest: (trial) => {
      console.log('New best trial:', trial);
      // Show alert
    },
    onTrialPruned: (pruned) => {
      console.log('Trial pruned:', pruned);
      // Show warning
    },
  });

  // Load initial trial history when study changes
  useEffect(() => {
    if (selectedStudyId) {
      fetch(`/api/optimization/studies/${selectedStudyId}/history?limit=20`)
        .then(res => res.json())
        .then(data => {
          setTrials(data.trials.reverse());
          if (data.trials.length > 0) {
            setBestValue(Math.min(...data.trials.map(t => t.objective)));
          }
        })
        .catch(err => console.error('Failed to load history:', err));
    }
  }, [selectedStudyId]);

  return (
    <div className="container mx-auto p-6">
      {/* Header */}
      <header className="mb-8">
        <h1 className="text-3xl font-bold text-primary-400">
          Atomizer Dashboard
        </h1>
        <p className="text-dark-200 mt-2">
          Real-time optimization monitoring
        </p>
      </header>

      <div className="grid grid-cols-12 gap-6">
        {/* Sidebar - Study List */}
        <aside className="col-span-3">
          <Card title="Active Studies">
            <div className="space-y-3">
              {studies.map(study => (
                <StudyCard
                  key={study.id}
                  study={study}
                  isActive={study.id === selectedStudyId}
                  onClick={() => onStudySelect(study.id)}
                />
              ))}
            </div>
          </Card>
        </aside>

        {/* Main Content */}
        <main className="col-span-9">
          {/* Metrics Grid */}
          <div className="grid grid-cols-4 gap-4 mb-6">
            <MetricCard label="Total Trials" value={trials.length} />
            <MetricCard
              label="Best Value"
              value={bestValue === Infinity ? '-' : bestValue.toFixed(4)}
              valueColor="text-green-400"
            />
            <MetricCard
              label="Connection"
              value={isConnected ? 'Connected' : 'Disconnected'}
              valueColor={isConnected ? 'text-green-400' : 'text-red-400'}
            />
            <MetricCard label="Pruned" value={0} valueColor="text-yellow-400" />
          </div>

          {/* Charts */}
          <div className="grid grid-cols-2 gap-6 mb-6">
            <Card title="Convergence Plot">
              {/* Add Recharts LineChart here */}
              <div className="h-64 flex items-center justify-center text-dark-300">
                Convergence chart will go here
              </div>
            </Card>

            <Card title="Parameter Space">
              {/* Add Recharts ScatterChart here */}
              <div className="h-64 flex items-center justify-center text-dark-300">
                Parameter space chart will go here
              </div>
            </Card>
          </div>

          {/* Trial Feed */}
          <Card title="Recent Trials">
            <div className="space-y-2 max-h-96 overflow-y-auto">
              {trials.map(trial => (
                <div
                  key={trial.trial_number}
                  className={`p-3 rounded-lg ${
                    trial.objective === bestValue
                      ? 'bg-green-900 border-l-4 border-green-400'
                      : 'bg-dark-500'
                  }`}
                >
                  <div className="flex justify-between mb-1">
                    <span className="font-semibold text-primary-400">
                      Trial #{trial.trial_number}
                    </span>
                    <span className="font-mono text-green-400">
                      {trial.objective.toFixed(4)} Hz
                    </span>
                  </div>
                  <div className="text-xs text-dark-200">
                    {Object.entries(trial.design_variables).map(([key, val]) => (
                      <span key={key} className="mr-3">
                        {key}: {val.toFixed(2)}
                      </span>
                    ))}
                  </div>
                </div>
              ))}
            </div>
          </Card>
        </main>
      </div>
    </div>
  );
}

Step 3: Add Recharts Integration

In the Dashboard component, add the convergence and parameter space charts using Recharts:

import {
  LineChart, Line, ScatterChart, Scatter,
  XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer
} from 'recharts';

// Convergence chart
const convergenceData = trials.map((trial, idx) => ({
  trial_number: trial.trial_number,
  objective: trial.objective,
  best_so_far: Math.min(...trials.slice(0, idx + 1).map(t => t.objective)),
}));

<ResponsiveContainer width="100%" height={250}>
  <LineChart data={convergenceData}>
    <CartesianGrid strokeDasharray="3 3" stroke="#334155" />
    <XAxis dataKey="trial_number" stroke="#94a3b8" />
    <YAxis stroke="#94a3b8" />
    <Tooltip
      contentStyle={{ backgroundColor: '#1e293b', border: 'none' }}
      labelStyle={{ color: '#e2e8f0' }}
    />
    <Legend />
    <Line type="monotone" dataKey="objective" stroke="#60a5fa" name="Objective" />
    <Line type="monotone" dataKey="best_so_far" stroke="#10b981" name="Best So Far" />
  </LineChart>
</ResponsiveContainer>

// Parameter space chart (similar structure with ScatterChart)

Step 4: Run Development Server

npm run dev

The React app will be available at http://localhost:3000

The Vite proxy will forward:

  • /api/*http://localhost:8000/api/*
  • WebSocket connections automatically

📊 Architecture Summary

Data Flow

Backend (FastAPI) :8000
    ↓ REST API
React App :3000 (Vite dev server with proxy)
    ↓ WebSocket
useWebSocket hook → Dashboard component → UI updates

Component Hierarchy

App
└── Dashboard
    ├── Sidebar
    │   └── StudyCard (multiple)
    ├── Metrics Grid
    │   └── MetricCard (multiple)
    ├── Charts
    │   ├── Card (Convergence)
    │   │   └── LineChart (Recharts)
    │   └── Card (Parameter Space)
    │       └── ScatterChart (Recharts)
    └── Trial Feed
        └── Card
            └── Trial Items

🚀 Benefits of React Implementation

vs. Current HTML Dashboard

  1. Component Reusability - UI components can be used across pages
  2. Type Safety - TypeScript catches errors at compile time
  3. Better State Management - React state + hooks vs. manual DOM manipulation
  4. Easier Testing - React Testing Library for component tests
  5. Professional Architecture - Scalable for adding Configurator and Results pages
  6. Hot Module Replacement - Instant updates during development
  7. Better Performance - React's virtual DOM optimizations

📁 Files Created

Configuration (Complete)

  • package.json
  • vite.config.ts
  • tsconfig.json
  • tsconfig.node.json
  • tailwind.config.js
  • postcss.config.js
  • index.html

Source Files (Complete)

  • src/index.css
  • src/types/index.ts
  • src/hooks/useWebSocket.ts
  • src/components/Card.tsx
  • src/components/MetricCard.tsx
  • src/components/Badge.tsx
  • src/components/StudyCard.tsx

Source Files (Pending - Templates Provided Above)

  • src/main.tsx
  • src/App.tsx
  • src/pages/Dashboard.tsx

🐛 Troubleshooting

npm not found

  • Install Node.js from nodejs.org
  • Verify: node --version and npm --version

Dependency installation fails

  • Delete node_modules and package-lock.json
  • Run npm install again
  • Check for network/proxy issues

TypeScript errors

  • Run npm run build to see all errors
  • Check tsconfig.json settings
  • Ensure all imports use correct paths

WebSocket connection fails

  • Ensure backend is running on port 8000
  • Check Vite proxy configuration in vite.config.ts
  • Verify CORS settings in backend

Charts not displaying

  • Check Recharts is installed: npm list recharts
  • Verify data format matches Recharts API
  • Check browser console for errors

📚 Next Steps After Manual Completion

  1. Test the Dashboard

    • Start backend: python -m uvicorn api.main:app --reload
    • Start frontend: npm run dev
    • Open browser: http://localhost:3000
    • Select a study and verify real-time updates
  2. Add Enhancements

    • Data export buttons
    • Pruning alert toasts
    • Study control buttons (future)
    • Parameter importance chart (if Protocol 9 data available)
  3. Build for Production

    • npm run build
    • Serve dist/ folder from FastAPI static files
  4. Add More Pages

    • Study Configurator page
    • Results Viewer page
    • Add React Router for navigation

Status: Configuration and foundation complete. Ready for manual npm install and component completion.

Next Session: Complete Dashboard.tsx, integrate Recharts, test end-to-end.