Files
omnex/web/src/components/PodStatusPanel.tsx
T
Xor290 a9811fbb10
ci-api / test (push) Successful in 23m31s
ci-web / test (push) Successful in 14m33s
chore: update
2026-08-03 12:11:14 +02:00

105 lines
3.8 KiB
TypeScript

import { Badge, Box, Flex, HStack, Icon, Progress, SimpleGrid, Stack, Text } from '@chakra-ui/react'
import type { ComponentState, DemoDetails } from '../lib/api'
import { podStatusColor, podStatusLabel } from '../lib/format'
export const PODSTATUS_COMPONENTS: { key: keyof DemoDetails['state']; label: string }[] = [
{ key: 'api', label: 'Backend' },
{ key: 'web', label: 'Frontend' },
{ key: 'db', label: 'PostgreSQL' },
{ key: 'dbm', label: 'Redis' },
]
// PodStatusPanel : vue d'ensemble des 4 composants d'une démo (statut + CPU/mémoire live).
export function PodStatusPanel({ state }: { state: DemoDetails['state'] }) {
const allRunning = PODSTATUS_COMPONENTS.every((c) => state[c.key].phase === 'Running')
const downCount = PODSTATUS_COMPONENTS.filter((c) => state[c.key].phase !== 'Running').length
return (
<Stack spacing={3}>
<HStack spacing={2}>
<Box
w="8px"
h="8px"
borderRadius="full"
bg={allRunning ? 'green.400' : 'red.400'}
flexShrink={0}
/>
<Text fontSize="sm" fontWeight="medium">
{allRunning
? 'Tous les services sont opérationnels'
: `${downCount} service${downCount > 1 ? 's' : ''} indisponible${downCount > 1 ? 's' : ''}`}
</Text>
</HStack>
{/* 1 colonne jusqu'à lg : à "sm" (480px), 2 colonnes serraient trop les
cartes (CPU/mémoire en mono + badge) et forçaient un débordement
horizontal — surtout dans le contexte carte mobile, déjà à l'étroit
avec son propre padding. */}
<SimpleGrid columns={{ base: 1, lg: 4 }} spacing={3}>
{PODSTATUS_COMPONENTS.map((c) => (
<ComponentCard key={c.key} title={c.label} cs={state[c.key]} />
))}
</SimpleGrid>
</Stack>
)
}
function ComponentCard({ title, cs }: { title: string; cs: ComponentState }) {
const cpuPct = cs.cpu_limit_milli > 0 ? Math.min(100, Math.round((cs.cpu_milli / cs.cpu_limit_milli) * 100)) : 0
const memPct = cs.memory_limit_mi > 0 ? Math.min(100, Math.round((cs.memory_mi / cs.memory_limit_mi) * 100)) : 0
return (
<Box p={3} borderWidth="1px" borderRadius="lg" bg="bg-surface" minW={0}>
<HStack justify="space-between" mb={3}>
<Text fontSize="sm" fontWeight="semibold" noOfLines={1}>
{title}
</Text>
<HStack spacing={1.5}>
<Box w="7px" h="7px" borderRadius="full" bg={`${podStatusColor(cs.phase)}.400`} flexShrink={0} />
<Badge colorScheme={podStatusColor(cs.phase)} fontSize="10px">
{podStatusLabel(cs.phase)}
</Badge>
</HStack>
</HStack>
<Stack spacing={2}>
<Box>
<Flex justify="space-between" fontSize="xs" color="gray.500" mb={1}>
<Text>CPU</Text>
<Text fontFamily="mono">
{cs.cpu_milli}m / {cs.cpu_limit_milli}m
</Text>
</Flex>
<Progress
value={cpuPct}
size="xs"
borderRadius="full"
colorScheme={cpuPct > 85 ? 'red' : cpuPct > 60 ? 'orange' : 'primary'}
/>
</Box>
<Box>
<Flex justify="space-between" fontSize="xs" color="gray.500" mb={1}>
<Text>Mémoire</Text>
<Text fontFamily="mono">
{cs.memory_mi}Mi / {cs.memory_limit_mi}Mi
</Text>
</Flex>
<Progress
value={memPct}
size="xs"
borderRadius="full"
colorScheme={memPct > 85 ? 'red' : memPct > 60 ? 'orange' : 'primary'}
/>
</Box>
</Stack>
</Box>
)
}
export function ChevronIcon(props: React.ComponentProps<typeof Icon>) {
return (
<Icon viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={3} {...props}>
<path strokeLinecap="round" strokeLinejoin="round" d="M9 18l6-6-6-6" />
</Icon>
)
}