diff --git a/ui/src/pages/AppsTab/AppDeploymentPage/AppDeploymentPage.module.css b/ui/src/pages/AppsTab/AppDeploymentPage/AppDeploymentPage.module.css index b6e70075..e887b96e 100644 --- a/ui/src/pages/AppsTab/AppDeploymentPage/AppDeploymentPage.module.css +++ b/ui/src/pages/AppsTab/AppDeploymentPage/AppDeploymentPage.module.css @@ -219,6 +219,33 @@ font-size: 13px; } +/* StatusCard */ +.statusCard { + border: 1px solid var(--border); + border-radius: 6px; + padding: 14px; + background: var(--bg-surface); + display: flex; + flex-direction: column; + gap: 12px; +} +.statusCardHeader { display: flex; align-items: center; gap: 8px; } +.statusCardGrid { display: grid; grid-template-columns: 100px 1fr; gap: 6px 12px; font-size: 13px; } +.statusCardActions { display: flex; gap: 8px; } + +/* DeploymentTab */ +.deploymentTab { + display: flex; + flex-direction: column; + gap: 12px; + flex: 1 1 auto; + min-height: 0; +} +.logFill { flex: 1 1 auto; min-height: 200px; } + +/* HistoryDisclosure */ +.historyRow { margin-top: 16px; } + /* Env vars list */ .envVarsList { display: flex; diff --git a/ui/src/pages/AppsTab/AppDeploymentPage/DeploymentTab/StatusCard.tsx b/ui/src/pages/AppsTab/AppDeploymentPage/DeploymentTab/StatusCard.tsx new file mode 100644 index 00000000..0c7a2208 --- /dev/null +++ b/ui/src/pages/AppsTab/AppDeploymentPage/DeploymentTab/StatusCard.tsx @@ -0,0 +1,60 @@ +import { Badge, StatusDot, MonoText, Button } 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'; + +const STATUS_COLORS = { + RUNNING: 'success', STARTING: 'warning', FAILED: 'error', + STOPPED: 'auto', DEGRADED: 'warning', STOPPING: 'auto', +} as const; + +const DEPLOY_STATUS_DOT = { + RUNNING: 'live', STARTING: 'running', DEGRADED: 'stale', + STOPPING: 'stale', STOPPED: 'dead', FAILED: 'error', +} as const; + +function formatBytes(bytes: number): string { + if (bytes >= 1_048_576) return `${(bytes / 1_048_576).toFixed(1)} MB`; + if (bytes >= 1024) return `${(bytes / 1024).toFixed(1)} KB`; + return `${bytes} B`; +} + +interface Props { + deployment: Deployment; + version: AppVersion | null; + externalUrl: string; + onStop: () => void; + onStart: () => void; +} + +export function StatusCard({ deployment, version, externalUrl, onStop, onStart }: Props) { + const running = deployment.replicaStates?.filter((r) => r.status === 'RUNNING').length ?? 0; + const total = deployment.replicaStates?.length ?? 0; + + return ( +