From 571f85cd0f3388e75215bda401705ef6c309b7fe Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Thu, 23 Apr 2026 13:46:31 +0200 Subject: [PATCH] feat(ui): wire CheckpointsTable + Drawer into IdentitySection (delete old Checkpoints) Co-Authored-By: Claude Sonnet 4.6 --- .../AppsTab/AppDeploymentPage/Checkpoints.tsx | 67 ------------------- .../pages/AppsTab/AppDeploymentPage/index.tsx | 43 ++++++++++-- 2 files changed, 36 insertions(+), 74 deletions(-) delete mode 100644 ui/src/pages/AppsTab/AppDeploymentPage/Checkpoints.tsx diff --git a/ui/src/pages/AppsTab/AppDeploymentPage/Checkpoints.tsx b/ui/src/pages/AppsTab/AppDeploymentPage/Checkpoints.tsx deleted file mode 100644 index 281bb0ad..00000000 --- a/ui/src/pages/AppsTab/AppDeploymentPage/Checkpoints.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { useState } from 'react'; -import { Button, Badge } from '@cameleer/design-system'; -import type { Deployment, AppVersion } from '../../../api/queries/admin/apps'; -import { timeAgo } from '../../../utils/format-utils'; -import styles from './AppDeploymentPage.module.css'; - -interface CheckpointsProps { - deployments: Deployment[]; - versions: AppVersion[]; - currentDeploymentId: string | null; - onRestore: (deploymentId: string) => void; -} - -export function Checkpoints({ deployments, versions, currentDeploymentId, onRestore }: CheckpointsProps) { - const [open, setOpen] = useState(false); - const versionMap = new Map(versions.map((v) => [v.id, v])); - - // Any deployment that captured a snapshot is restorable — that covers RUNNING, - // DEGRADED, and STOPPED (blue/green swap previous, user-stopped). Exclude the - // currently-running one and anything without a snapshot (FAILED, STARTING). - const checkpoints = deployments - .filter((d) => d.deployedConfigSnapshot && d.id !== currentDeploymentId) - .sort((a, b) => (b.deployedAt ?? '').localeCompare(a.deployedAt ?? '')); - - return ( -
- - {open && ( -
- {checkpoints.length === 0 && ( -
No past deployments yet.
- )} - {checkpoints.map((d) => { - const v = versionMap.get(d.appVersionId); - const jarAvailable = !!v; - return ( -
- - - {d.deployedAt ? timeAgo(d.deployedAt) : '—'} - - {!jarAvailable && ( - archived, JAR unavailable - )} - -
- ); - })} -
- )} -
- ); -} diff --git a/ui/src/pages/AppsTab/AppDeploymentPage/index.tsx b/ui/src/pages/AppsTab/AppDeploymentPage/index.tsx index 6c5d2054..702ce4ee 100644 --- a/ui/src/pages/AppsTab/AppDeploymentPage/index.tsx +++ b/ui/src/pages/AppsTab/AppDeploymentPage/index.tsx @@ -20,7 +20,8 @@ import type { Deployment } from '../../../api/queries/admin/apps'; import { useApplicationConfig, useUpdateApplicationConfig } from '../../../api/queries/commands'; import { PageLoader } from '../../../components/PageLoader'; import { IdentitySection } from './IdentitySection'; -import { Checkpoints } from './Checkpoints'; +import { CheckpointsTable } from './CheckpointsTable'; +import { CheckpointDetailDrawer } from './CheckpointDetailDrawer'; import { MonitoringTab } from './ConfigTabs/MonitoringTab'; import { ResourcesTab } from './ConfigTabs/ResourcesTab'; import { VariablesTab } from './ConfigTabs/VariablesTab'; @@ -90,6 +91,7 @@ export default function AppDeploymentPage() { const [tab, setTab] = useState('monitoring'); const [deleteConfirm, setDeleteConfirm] = useState(false); const [stopTarget, setStopTarget] = useState(null); + const [selectedCheckpointId, setSelectedCheckpointId] = useState(null); const lastDerivedRef = useRef(''); // Initialize name from app when it loads @@ -348,6 +350,15 @@ export default function AppDeploymentPage() { return true; // redeploy always enabled })(); + // Checkpoint drawer derivations + const jarRetentionCount = env?.jarRetentionCount ?? null; + const selectedDep = selectedCheckpointId + ? deployments.find((d) => d.id === selectedCheckpointId) ?? null + : null; + const selectedDepVersion = selectedDep + ? versions.find((v) => v.id === selectedDep.appVersionId) + : undefined; + // ── Loading guard ────────────────────────────────────────────────── if (envLoading || appsLoading) return ; if (!env) return
Select an environment first.
; @@ -435,12 +446,30 @@ export default function AppDeploymentPage() { deploying={deploymentInProgress} > {app && ( - + <> + + {selectedDep && ( + setSelectedCheckpointId(null)} + deployment={selectedDep} + version={selectedDepVersion} + appSlug={app.slug} + envSlug={selectedEnv ?? ''} + currentForm={form} + onRestore={(deploymentId) => { + handleRestore(deploymentId); + setSelectedCheckpointId(null); + }} + /> + )} + )}