diff --git a/cameleer-server-app/src/main/java/com/cameleer/server/app/storage/PostgresDeploymentRepository.java b/cameleer-server-app/src/main/java/com/cameleer/server/app/storage/PostgresDeploymentRepository.java index c653f25c..4edddeaf 100644 --- a/cameleer-server-app/src/main/java/com/cameleer/server/app/storage/PostgresDeploymentRepository.java +++ b/cameleer-server-app/src/main/java/com/cameleer/server/app/storage/PostgresDeploymentRepository.java @@ -140,10 +140,12 @@ public class PostgresDeploymentRepository implements DeploymentRepository { } public Optional findLatestSuccessfulByAppAndEnv(UUID appId, UUID envId) { + // DEGRADED deploys also carry a snapshot (executor writes before the RUNNING/DEGRADED + // split), and represent a config that reached COMPLETE stage — restorable for the user. var results = jdbc.query( "SELECT " + SELECT_COLS + " FROM deployments " + "WHERE app_id = ? AND environment_id = ? " - + "AND status = 'RUNNING' AND deployed_config_snapshot IS NOT NULL " + + "AND status IN ('RUNNING', 'DEGRADED') AND deployed_config_snapshot IS NOT NULL " + "ORDER BY deployed_at DESC NULLS LAST LIMIT 1", (rs, rowNum) -> mapRow(rs), appId, envId); return results.isEmpty() ? Optional.empty() : Optional.of(results.get(0)); diff --git a/ui/src/pages/AppsTab/AppDeploymentPage/Checkpoints.tsx b/ui/src/pages/AppsTab/AppDeploymentPage/Checkpoints.tsx index 3b447ce1..95efba77 100644 --- a/ui/src/pages/AppsTab/AppDeploymentPage/Checkpoints.tsx +++ b/ui/src/pages/AppsTab/AppDeploymentPage/Checkpoints.tsx @@ -15,9 +15,15 @@ export function Checkpoints({ deployments, versions, currentDeploymentId, onRest const [open, setOpen] = useState(false); const versionMap = new Map(versions.map((v) => [v.id, v])); - // Only successful deployments (RUNNING with a deployedAt). Exclude the currently-running one. + // Deployments that reached COMPLETE stage and captured a snapshot (RUNNING or DEGRADED). + // Exclude the currently-running one. const checkpoints = deployments - .filter((d) => d.deployedAt && d.status === 'RUNNING' && d.id !== currentDeploymentId) + .filter( + (d) => + d.deployedAt && + (d.status === 'RUNNING' || d.status === 'DEGRADED') && + d.id !== currentDeploymentId, + ) .sort((a, b) => (b.deployedAt ?? '').localeCompare(a.deployedAt ?? '')); return (