Files
cameleer-server/ui/src/components/DeploymentProgress.tsx
hsiegeln a4a569a253
All checks were successful
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 1m55s
CI / docker (push) Successful in 1m7s
CI / deploy-feature (push) Has been skipped
CI / deploy (push) Successful in 1m6s
fix: improve deployment progress UI and prevent duplicate deployment rows
- Redesign DeploymentProgress component: track-based layout with amber
  brand color, checkmarks for completed steps, user-friendly labels
  (Prepare, Image, Network, Launch, Verify, Activate, Live)
- Delete terminal (STOPPED/FAILED) deployments before creating new ones
  for the same app+environment, preventing duplicate rows in the UI
- Update CLAUDE.md with comprehensive key class locations, correct deploy
  stages, database migration reference, and REST endpoint summary

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 23:10:59 +02:00

70 lines
2.2 KiB
TypeScript

import styles from './DeploymentProgress.module.css';
const STAGES = [
{ key: 'PRE_FLIGHT', label: 'Prepare' },
{ key: 'PULL_IMAGE', label: 'Image' },
{ key: 'CREATE_NETWORK', label: 'Network' },
{ key: 'START_REPLICAS', label: 'Launch' },
{ key: 'HEALTH_CHECK', label: 'Verify' },
{ key: 'SWAP_TRAFFIC', label: 'Activate' },
{ key: 'COMPLETE', label: 'Live' },
];
interface DeploymentProgressProps {
currentStage: string | null;
failed?: boolean;
}
export function DeploymentProgress({ currentStage, failed }: DeploymentProgressProps) {
if (!currentStage) return null;
const currentIndex = STAGES.findIndex((s) => s.key === currentStage);
return (
<div className={styles.container}>
<div className={styles.track}>
<div
className={`${styles.trackFill} ${failed ? styles.trackFailed : ''}`}
style={{ width: `${(currentIndex / (STAGES.length - 1)) * 100}%` }}
/>
</div>
<div className={styles.steps}>
{STAGES.map((stage, i) => {
const isCompleted = i < currentIndex;
const isActive = i === currentIndex && !failed;
const isFailed = i === currentIndex && failed;
return (
<div key={stage.key} className={styles.step}>
<div
className={[
styles.dot,
isCompleted ? styles.completed : '',
isActive ? styles.active : '',
isFailed ? styles.failed : '',
].join(' ')}
>
{isCompleted && (
<svg width="8" height="8" viewBox="0 0 12 12" fill="none">
<path d="M2 6l3 3 5-5" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
</svg>
)}
</div>
<span
className={[
styles.label,
isCompleted ? styles.labelDone : '',
isActive ? styles.labelActive : '',
isFailed ? styles.labelFailed : '',
].join(' ')}
>
{stage.label}
</span>
</div>
);
})}
</div>
</div>
);
}