105 lines
3.8 KiB
TypeScript
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>
|
|
)
|
|
}
|