feat(ui): CheckpointsTable emits grid fragment + locale sub-line

This commit is contained in:
hsiegeln
2026-04-23 17:03:31 +02:00
parent 77f5c82dfe
commit 177673ba62

View File

@@ -38,91 +38,96 @@ export function CheckpointsTable({
const hidden = checkpoints.length - visible.length;
return (
<div className={styles.checkpointsSection}>
<button
type="button"
className={styles.checkpointsHeader}
onClick={() => setOpen((v) => !v)}
aria-expanded={open}
>
<span className={styles.checkpointsChevron}>{open ? '\u25BE' : '\u25B8'}</span>
<span>Checkpoints</span>
{' '}
<span className={styles.checkpointsCount}>({checkpoints.length})</span>
</button>
<>
<span className={styles.configLabel}>Checkpoints</span>
<div className={styles.checkpointsTriggerCell}>
<button
type="button"
className={styles.checkpointsTrigger}
onClick={() => setOpen((v) => !v)}
aria-expanded={open}
>
<span className={styles.checkpointsChevron}>{open ? '\u25BE' : '\u25B8'}</span>
{open ? 'Collapse' : 'Expand'} ({checkpoints.length})
</button>
</div>
{open && (
<div className={styles.checkpointsTable}>
<table>
<thead>
<tr>
<th>Version</th>
<th>JAR</th>
<th>Deployed by</th>
<th>Deployed</th>
<th>Strategy</th>
<th>Outcome</th>
<th aria-label="open"></th>
</tr>
</thead>
<tbody>
{visible.map((d) => {
const v = versionMap.get(d.appVersionId);
const archived = !v;
const strategyLabel =
d.deploymentStrategy === 'BLUE_GREEN' ? 'blue/green' : 'rolling';
return (
<tr
key={d.id}
className={archived ? styles.checkpointArchived : undefined}
onClick={() => onSelect(d.id)}
>
<td>
<Badge label={v ? `v${v.version}` : '?'} color="auto" />
</td>
<td className={styles.jarCell}>
{v ? (
<span className={styles.jarName}>{v.jarFilename}</span>
) : (
<>
<span className={styles.jarStrike}>JAR pruned</span>
<div className={styles.archivedHint}>archived JAR pruned</div>
</>
)}
</td>
<td>
{d.createdBy ?? <span className={styles.muted}></span>}
</td>
<td>
{d.deployedAt && timeAgo(d.deployedAt)}
<div className={styles.isoSubline}>{d.deployedAt}</div>
</td>
<td>
<span className={styles.strategyPill}>{strategyLabel}</span>
</td>
<td>
<span
className={`${styles.outcomePill} ${styles[`outcome-${d.status}` as keyof typeof styles] || ''}`}
>
{d.status}
</span>
</td>
<td className={styles.chevron}></td>
</tr>
);
})}
</tbody>
</table>
{hidden > 0 && !expanded && (
<button
type="button"
className={styles.showOlderBtn}
onClick={() => setExpanded(true)}
>
Show older ({hidden}) archived, postmortem only
</button>
)}
<div className={styles.checkpointsTableFullRow}>
<div className={styles.checkpointsTable}>
<table>
<thead>
<tr>
<th>Version</th>
<th>JAR</th>
<th>Deployed by</th>
<th>Deployed</th>
<th>Strategy</th>
<th>Outcome</th>
<th aria-label="open"></th>
</tr>
</thead>
<tbody>
{visible.map((d) => {
const v = versionMap.get(d.appVersionId);
const archived = !v;
const strategyLabel =
d.deploymentStrategy === 'BLUE_GREEN' ? 'blue/green' : 'rolling';
return (
<tr
key={d.id}
className={archived ? styles.checkpointArchived : undefined}
onClick={() => onSelect(d.id)}
>
<td>
<Badge label={v ? `v${v.version}` : '?'} color="auto" />
</td>
<td className={styles.jarCell}>
{v ? (
<span className={styles.jarName}>{v.jarFilename}</span>
) : (
<>
<span className={styles.jarStrike}>JAR pruned</span>
<div className={styles.archivedHint}>archived JAR pruned</div>
</>
)}
</td>
<td>
{d.createdBy ?? <span className={styles.muted}></span>}
</td>
<td>
{d.deployedAt && timeAgo(d.deployedAt)}
<div className={styles.isoSubline}>
{d.deployedAt && new Date(d.deployedAt).toLocaleString()}
</div>
</td>
<td>
<span className={styles.strategyPill}>{strategyLabel}</span>
</td>
<td>
<span
className={`${styles.outcomePill} ${styles[`outcome-${d.status}` as keyof typeof styles] || ''}`}
>
{d.status}
</span>
</td>
<td className={styles.chevron}></td>
</tr>
);
})}
</tbody>
</table>
{hidden > 0 && !expanded && (
<button
type="button"
className={styles.showOlderBtn}
onClick={() => setExpanded(true)}
>
Show older ({hidden}) archived, postmortem only
</button>
)}
</div>
</div>
)}
</div>
</>
);
}