File size: 2,827 Bytes
f271df0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
/**
 * Multi-gate readiness skeleton: Scenario / Coverage / Regression / Safety / Release
 * (+ quality / launch when wired).
 */
import Box from '@mui/material/Box';
import Chip from '@mui/material/Chip';
import Typography from '@mui/material/Typography';
import { CheckCircle2, CircleDashed, XCircle } from 'lucide-react';
import { useGateStatus } from '../../services/platform';
import { ErrorNote, LoadingBox, SectionCard } from '../labeleval/shared';

const DISPLAY_ORDER = ['scenario', 'coverage', 'regression', 'safety', 'quality', 'launch', 'release'];

function statusChip(passed: boolean | null, ready: boolean) {
  if (!ready) {
    return <Chip size="small" icon={<CircleDashed size={14} />} label="Skeleton" variant="outlined" />;
  }
  if (passed === true) {
    return <Chip size="small" color="success" icon={<CheckCircle2 size={14} />} label="Pass" />;
  }
  if (passed === false) {
    return <Chip size="small" color="error" icon={<XCircle size={14} />} label="Fail" />;
  }
  return <Chip size="small" label="Pending inputs" variant="outlined" />;
}

export default function GateStatusPanel({
  candidateRunId,
  baselineRunId,
  refreshKey = 0,
}: {
  candidateRunId: string | null;
  baselineRunId: string | null;
  refreshKey?: number;
}) {
  const poll = useGateStatus(candidateRunId, baselineRunId, refreshKey);

  if (poll.error && !poll.data) return <ErrorNote error={poll.error} />;
  if (poll.loading && !poll.data) return <LoadingBox label="Loading gate status…" />;
  const data = poll.data;
  if (!data) return null;

  const byType = Object.fromEntries(data.gates.map((g) => [g.gate_type, g]));

  return (
    <SectionCard
      title="Multi-gate readiness"
      action={
        <Typography variant="caption" color="text.secondary">
          {data.summary.release_ready
            ? 'Release ready'
            : `${data.summary.unwired_count} gates still Phase 2–6 stubs`}
        </Typography>
      }
    >
      <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
        {DISPLAY_ORDER.map((type) => {
          const g = byType[type];
          if (!g) return null;
          return (
            <Box
              key={type}
              sx={{
                display: 'flex',
                alignItems: 'center',
                gap: 1.5,
                py: 0.75,
                borderBottom: '1px solid #232a31',
              }}
            >
              <Typography sx={{ minWidth: 110, fontWeight: 600, textTransform: 'capitalize' }}>
                {type}
              </Typography>
              {statusChip(g.passed, g.ready)}
              <Typography variant="body2" color="text.secondary" sx={{ flex: 1 }}>
                {g.message}
              </Typography>
            </Box>
          );
        })}
      </Box>
    </SectionCard>
  );
}