AE-Shree commited on
Commit ·
ae81ce5
1
Parent(s): 99f9af4
Final Change
Browse files- frontend/dist/index.html +13 -13
- frontend/src/App.jsx +39 -1
- frontend/src/components/Dashboard.jsx +34 -26
frontend/dist/index.html
CHANGED
|
@@ -1,13 +1,13 @@
|
|
| 1 |
-
<!doctype html>
|
| 2 |
-
<html lang="en">
|
| 3 |
-
<head>
|
| 4 |
-
<meta charset="UTF-8" />
|
| 5 |
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 6 |
-
<title>CLM Dashboard</title>
|
| 7 |
-
<script type="module" crossorigin src="/assets/index-
|
| 8 |
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
| 9 |
-
</head>
|
| 10 |
-
<body
|
| 11 |
-
<div id="root"></div>
|
| 12 |
-
</body>
|
| 13 |
-
</html>
|
|
|
|
| 1 |
+
<!doctype html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="UTF-8" />
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 6 |
+
<title>CLM Dashboard</title>
|
| 7 |
+
<script type="module" crossorigin src="/assets/index-D8328XGk.js"></script>
|
| 8 |
+
<link rel="stylesheet" crossorigin href="/assets/index-DHB-7DK0.css">
|
| 9 |
+
</head>
|
| 10 |
+
<body style="margin:0;background:#f1f5f9">
|
| 11 |
+
<div id="root"></div>
|
| 12 |
+
</body>
|
| 13 |
+
</html>
|
frontend/src/App.jsx
CHANGED
|
@@ -1,6 +1,42 @@
|
|
| 1 |
import React from 'react'
|
| 2 |
import Dashboard from './components/Dashboard'
|
| 3 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
export default function App() {
|
| 5 |
return (
|
| 6 |
<div style={{ minHeight: '100vh', background: '#f1f5f9', fontFamily: 'system-ui,sans-serif' }}>
|
|
@@ -45,7 +81,9 @@ export default function App() {
|
|
| 45 |
|
| 46 |
{/* ── Content ── */}
|
| 47 |
<main style={{ maxWidth: 1400, margin: '0 auto', padding: 24 }}>
|
| 48 |
-
<
|
|
|
|
|
|
|
| 49 |
</main>
|
| 50 |
</div>
|
| 51 |
)
|
|
|
|
| 1 |
import React from 'react'
|
| 2 |
import Dashboard from './components/Dashboard'
|
| 3 |
|
| 4 |
+
class ErrorBoundary extends React.Component {
|
| 5 |
+
constructor(props) {
|
| 6 |
+
super(props)
|
| 7 |
+
this.state = { error: null }
|
| 8 |
+
}
|
| 9 |
+
static getDerivedStateFromError(error) {
|
| 10 |
+
return { error }
|
| 11 |
+
}
|
| 12 |
+
componentDidCatch(error, info) {
|
| 13 |
+
console.error('Dashboard crashed:', error, info)
|
| 14 |
+
}
|
| 15 |
+
render() {
|
| 16 |
+
if (this.state.error) {
|
| 17 |
+
return (
|
| 18 |
+
<div style={{ background: '#fef2f2', border: '1px solid #fca5a5',
|
| 19 |
+
borderRadius: 12, padding: 24, margin: 24, fontFamily: 'system-ui,sans-serif' }}>
|
| 20 |
+
<div style={{ fontSize: 18, fontWeight: 800, color: '#dc2626', marginBottom: 8 }}>
|
| 21 |
+
⚠️ The dashboard hit a render error
|
| 22 |
+
</div>
|
| 23 |
+
<div style={{ fontSize: 13, color: '#7f1d1d', marginBottom: 12,
|
| 24 |
+
fontFamily: 'monospace', background: '#fff', padding: 12, borderRadius: 8,
|
| 25 |
+
border: '1px solid #fecaca', whiteSpace: 'pre-wrap' }}>
|
| 26 |
+
{String(this.state.error?.message || this.state.error)}
|
| 27 |
+
</div>
|
| 28 |
+
<button onClick={() => this.setState({ error: null })}
|
| 29 |
+
style={{ background: '#dc2626', color: '#fff', border: 'none',
|
| 30 |
+
borderRadius: 8, padding: '10px 18px', fontWeight: 700, cursor: 'pointer' }}>
|
| 31 |
+
↻ Reset Dashboard
|
| 32 |
+
</button>
|
| 33 |
+
</div>
|
| 34 |
+
)
|
| 35 |
+
}
|
| 36 |
+
return this.props.children
|
| 37 |
+
}
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
export default function App() {
|
| 41 |
return (
|
| 42 |
<div style={{ minHeight: '100vh', background: '#f1f5f9', fontFamily: 'system-ui,sans-serif' }}>
|
|
|
|
| 81 |
|
| 82 |
{/* ── Content ── */}
|
| 83 |
<main style={{ maxWidth: 1400, margin: '0 auto', padding: 24 }}>
|
| 84 |
+
<ErrorBoundary>
|
| 85 |
+
<Dashboard />
|
| 86 |
+
</ErrorBoundary>
|
| 87 |
</main>
|
| 88 |
</div>
|
| 89 |
)
|
frontend/src/components/Dashboard.jsx
CHANGED
|
@@ -272,31 +272,35 @@ export default function Dashboard() {
|
|
| 272 |
esRef.current = es
|
| 273 |
|
| 274 |
es.onmessage = (ev) => {
|
| 275 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 276 |
|
| 277 |
if (msg.type === 'reset') {
|
| 278 |
-
setTasks(msg.tasks
|
| 279 |
-
setEnTrace([msg.energy])
|
| 280 |
-
setStTrace([msg.stress])
|
| 281 |
}
|
| 282 |
|
| 283 |
if (msg.type === 'step') {
|
| 284 |
-
setCurrentStep(msg.step)
|
| 285 |
-
setAction(msg.action)
|
| 286 |
-
setTasks(msg.tasks
|
| 287 |
-
setRwTrace(prev => [...prev, msg.reward])
|
| 288 |
-
setEnTrace(prev => [...prev, msg.energy])
|
| 289 |
-
setStTrace(prev => [...prev, msg.stress])
|
| 290 |
if (msg.schema_drift) setDrift(prev => [...prev, msg.schema_drift])
|
| 291 |
|
| 292 |
if (msg.done) {
|
| 293 |
episodeDone.current = true
|
| 294 |
-
const score = msg.final_score
|
| 295 |
setFinal(score)
|
| 296 |
setStreamDone(true)
|
| 297 |
setStreaming(false)
|
| 298 |
setHistory(prev => [
|
| 299 |
-
{ ep: prev.length + 1, score, difficulty: d, steps: msg.step },
|
| 300 |
...prev.slice(0, 9),
|
| 301 |
])
|
| 302 |
es.close(); esRef.current = null
|
|
@@ -304,7 +308,7 @@ export default function Dashboard() {
|
|
| 304 |
}
|
| 305 |
|
| 306 |
if (msg.type === 'error') {
|
| 307 |
-
setError(msg.message)
|
| 308 |
setStreaming(false)
|
| 309 |
es.close(); esRef.current = null
|
| 310 |
}
|
|
@@ -466,7 +470,7 @@ export default function Dashboard() {
|
|
| 466 |
background: '#f0fdf4', border: '1px solid #bbf7d0', borderRadius: 8,
|
| 467 |
padding: '6px 14px' }}>
|
| 468 |
✅ Episode #{episodeCount} Complete
|
| 469 |
-
{finalScore
|
| 470 |
</span>
|
| 471 |
)}
|
| 472 |
</div>
|
|
@@ -511,7 +515,7 @@ export default function Dashboard() {
|
|
| 511 |
Final results frozen below — all charts and task data preserved
|
| 512 |
</div>
|
| 513 |
</div>
|
| 514 |
-
{finalScore
|
| 515 |
<div style={{ background: 'rgba(255,255,255,0.2)', borderRadius: 12,
|
| 516 |
padding: '10px 20px', textAlign: 'center' }}>
|
| 517 |
<div style={{ fontSize: 11, color: '#d1fae5', fontWeight: 700,
|
|
@@ -640,17 +644,21 @@ export default function Dashboard() {
|
|
| 640 |
<div style={{ ...card({ marginBottom: 0 }), minWidth: 220 }}>
|
| 641 |
<div style={section}>Episode History</div>
|
| 642 |
<div style={{ fontFamily: 'monospace', fontSize: 11 }}>
|
| 643 |
-
{history.map(h =>
|
| 644 |
-
|
| 645 |
-
|
| 646 |
-
|
| 647 |
-
|
| 648 |
-
<
|
| 649 |
-
|
| 650 |
-
|
| 651 |
-
|
| 652 |
-
|
| 653 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 654 |
</div>
|
| 655 |
</div>
|
| 656 |
)}
|
|
|
|
| 272 |
esRef.current = es
|
| 273 |
|
| 274 |
es.onmessage = (ev) => {
|
| 275 |
+
let msg
|
| 276 |
+
try { msg = JSON.parse(ev.data) } catch { return }
|
| 277 |
+
if (!msg || typeof msg !== 'object') return
|
| 278 |
+
|
| 279 |
+
const num = (v, fallback = 0) => (typeof v === 'number' && !isNaN(v) ? v : fallback)
|
| 280 |
|
| 281 |
if (msg.type === 'reset') {
|
| 282 |
+
setTasks(Array.isArray(msg.tasks) ? msg.tasks : [])
|
| 283 |
+
setEnTrace([num(msg.energy, 1)])
|
| 284 |
+
setStTrace([num(msg.stress, 0)])
|
| 285 |
}
|
| 286 |
|
| 287 |
if (msg.type === 'step') {
|
| 288 |
+
setCurrentStep(num(msg.step, 0))
|
| 289 |
+
setAction(msg.action || null)
|
| 290 |
+
setTasks(Array.isArray(msg.tasks) ? msg.tasks : [])
|
| 291 |
+
setRwTrace(prev => [...prev, num(msg.reward)])
|
| 292 |
+
setEnTrace(prev => [...prev, num(msg.energy, 1)])
|
| 293 |
+
setStTrace(prev => [...prev, num(msg.stress, 0)])
|
| 294 |
if (msg.schema_drift) setDrift(prev => [...prev, msg.schema_drift])
|
| 295 |
|
| 296 |
if (msg.done) {
|
| 297 |
episodeDone.current = true
|
| 298 |
+
const score = typeof msg.final_score === 'number' ? msg.final_score : null
|
| 299 |
setFinal(score)
|
| 300 |
setStreamDone(true)
|
| 301 |
setStreaming(false)
|
| 302 |
setHistory(prev => [
|
| 303 |
+
{ ep: prev.length + 1, score, difficulty: d, steps: num(msg.step, 0) },
|
| 304 |
...prev.slice(0, 9),
|
| 305 |
])
|
| 306 |
es.close(); esRef.current = null
|
|
|
|
| 308 |
}
|
| 309 |
|
| 310 |
if (msg.type === 'error') {
|
| 311 |
+
setError(msg.message || 'Unknown error')
|
| 312 |
setStreaming(false)
|
| 313 |
es.close(); esRef.current = null
|
| 314 |
}
|
|
|
|
| 470 |
background: '#f0fdf4', border: '1px solid #bbf7d0', borderRadius: 8,
|
| 471 |
padding: '6px 14px' }}>
|
| 472 |
✅ Episode #{episodeCount} Complete
|
| 473 |
+
{typeof finalScore === 'number' ? ` · Score: ${finalScore.toFixed(4)}` : ''}
|
| 474 |
</span>
|
| 475 |
)}
|
| 476 |
</div>
|
|
|
|
| 515 |
Final results frozen below — all charts and task data preserved
|
| 516 |
</div>
|
| 517 |
</div>
|
| 518 |
+
{typeof finalScore === 'number' && (
|
| 519 |
<div style={{ background: 'rgba(255,255,255,0.2)', borderRadius: 12,
|
| 520 |
padding: '10px 20px', textAlign: 'center' }}>
|
| 521 |
<div style={{ fontSize: 11, color: '#d1fae5', fontWeight: 700,
|
|
|
|
| 644 |
<div style={{ ...card({ marginBottom: 0 }), minWidth: 220 }}>
|
| 645 |
<div style={section}>Episode History</div>
|
| 646 |
<div style={{ fontFamily: 'monospace', fontSize: 11 }}>
|
| 647 |
+
{history.map(h => {
|
| 648 |
+
const sc = typeof h.score === 'number' ? h.score : null
|
| 649 |
+
const col = sc == null ? '#64748b'
|
| 650 |
+
: sc >= 0.5 ? '#16a34a' : sc >= 0.3 ? '#f59e0b' : '#ef4444'
|
| 651 |
+
return (
|
| 652 |
+
<div key={h.ep} style={{ display: 'flex', gap: 8,
|
| 653 |
+
padding: '3px 0', borderBottom: '1px solid #f8fafc', color: col }}>
|
| 654 |
+
<span style={{ color: '#94a3b8', minWidth: 24 }}>#{h.ep}</span>
|
| 655 |
+
<span style={{ textTransform: 'capitalize', minWidth: 52,
|
| 656 |
+
color: '#475569' }}>{h.difficulty}</span>
|
| 657 |
+
<span style={{ fontWeight: 700 }}>{sc != null ? sc.toFixed(4) : '—'}</span>
|
| 658 |
+
<span style={{ color: '#94a3b8' }}>{h.steps ?? 0}s</span>
|
| 659 |
+
</div>
|
| 660 |
+
)
|
| 661 |
+
})}
|
| 662 |
</div>
|
| 663 |
</div>
|
| 664 |
)}
|