File size: 2,965 Bytes
1e49495
 
e9b7141
 
1e49495
 
 
 
 
e9b7141
 
 
 
 
1e49495
 
e9b7141
1e49495
 
e9b7141
 
1e49495
 
e9b7141
1e49495
 
e9b7141
 
1e49495
 
e9b7141
 
 
 
 
1e49495
 
e9b7141
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1e49495
19abe39
 
1e49495
 
19abe39
 
 
 
 
 
1e49495
19abe39
 
 
1e49495
19abe39
 
 
 
 
1e49495
19abe39
 
1e49495
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19abe39
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
const METRIC_FIELDS = [
  {
    key: 'progress',
    label: 'progress',
    color: 'var(--progress)',
    normalize: (v) => Math.min(Math.max(v || 0, 0), 1),
    format: (v) => (v != null ? v.toFixed(3) : 'β€”'),
  },
  {
    key: 'delta',
    label: 'delta',
    color: '#6ec6ff',
    normalize: (v) => Math.min(Math.max(v || 0, 0), 1),
    format: (v) => (v != null ? (v >= 0 ? '+' : '') + v.toFixed(3) : 'β€”'),
  },
  {
    key: 'kawasaki',
    label: 'kawasaki',
    color: 'var(--validity)',
    normalize: (v) => Math.min(Math.max(v || 0, 0), 1),
    format: (v) => (v != null ? v.toFixed(3) : 'β€”'),
  },
  {
    key: 'maekawa',
    label: 'maekawa',
    color: 'var(--validity)',
    normalize: (v) => Math.min(Math.max(v || 0, 0), 1),
    format: (v) => (v != null ? v.toFixed(3) : 'β€”'),
  },
  {
    key: 'blb',
    label: 'blb',
    color: 'var(--validity)',
    normalize: (v) => Math.min(Math.max(v || 0, 0), 1),
    format: (v) => (v != null ? v.toFixed(3) : 'β€”'),
  },
  {
    key: 'assignment_accuracy',
    label: 'assign acc',
    color: '#ffb74d',
    normalize: (v) => Math.min(Math.max(v || 0, 0), 1),
    format: (v) => (v != null ? v.toFixed(3) : 'β€”'),
  },
  {
    key: 'economy',
    label: 'economy',
    color: '#81c784',
    normalize: (v) => Math.min(Math.max(v || 0, 0), 1),
    format: (v) => (v != null ? v.toFixed(3) : 'β€”'),
  },
  {
    key: 'degree_sanity',
    label: 'deg sanity',
    color: 'var(--validity)',
    normalize: (v) => Math.min(Math.max(v || 0, 0), 1),
    format: (v) => (v != null ? v.toFixed(3) : 'β€”'),
  },
  {
    key: 'total',
    label: 'total',
    color: '#e0e0e0',
    normalize: (v) => Math.min(Math.max((v || 0) / 1.5, 0), 1),
    format: (v) => (v != null ? v.toFixed(3) : 'β€”'),
  },
];

function RewardRow({ label, color, pct, formattedValue, isDash, inverted }) {
  const barColor = inverted && pct > 0 ? 'var(--validity)' : color;
  return (
    <div className="reward-row">
      <span className="reward-label">{label}</span>
      <div className="reward-track">
        <div
          className="reward-bar"
          style={{ width: `${isDash ? 0 : pct}%`, background: barColor }}
        />
      </div>
      <span className={`reward-value${isDash ? ' dim' : ''}`}>
        {formattedValue}
      </span>
    </div>
  );
}

export default function RewardPanel({ metrics }) {
  return (
    <div className="reward-panel">
      {METRIC_FIELDS.map(({ key, label, color, normalize, format, inverted }) => {
        const raw = metrics ? metrics[key] : undefined;
        const isDash = raw === null || raw === undefined;
        const pct = isDash ? 0 : normalize(raw) * 100;
        return (
          <RewardRow
            key={key}
            label={label}
            color={color}
            pct={pct}
            formattedValue={isDash ? 'β€”' : format(raw)}
            isDash={isDash}
            inverted={!!inverted}
          />
        );
      })}
    </div>
  );
}