import { Grid, gridClasses } from '@mui/material'; import { dSizeStr } from 'format-data-size'; import { FC, ReactNode, useMemo } from 'react'; import { BLUE, GREY, PURPLE, RED } from '../../lib/consts/DEFAULT_THEME'; import { toAnvilDetail, toAnvilMemoryCalcable, toAnvilSharedStorageOverview, } from '../../lib/api_converters'; import Divider from '../Divider'; import FlexBox from '../FlexBox'; import Spinner from '../Spinner'; import StackBar from '../Bars/StackBar'; import { BodyText, InlineMonoText, MonoText } from '../Text'; import useFetch from '../../hooks/useFetch'; const N_100 = BigInt(100); const MAP_TO_ANVIL_STATE_COLOUR = { degraded: RED, not_ready: PURPLE, optimal: BLUE, }; const MAP_TO_HOST_STATE_COLOUR: Record = { offline: PURPLE, online: BLUE, }; const AnvilSummary: FC = (props) => { const { anvilUuid, refreshInterval = 5000 } = props; const { data: rAnvil, loading: loadingAnvil } = useFetch( `/anvil/${anvilUuid}`, { refreshInterval, }, ); const anvil = useMemo( () => rAnvil && toAnvilDetail(rAnvil), [rAnvil], ); const { data: cpu, loading: loadingCpu } = useFetch( `/anvil/${anvilUuid}/cpu`, { refreshInterval, }, ); const cpuSubnodes = useMemo( () => cpu && Object.values(cpu.hosts), [cpu], ); const { data: rMemory, loading: loadingMemory } = useFetch( `/anvil/${anvilUuid}/memory`, { refreshInterval, }, ); const memory = useMemo( () => rMemory && toAnvilMemoryCalcable(rMemory), [rMemory], ); const { data: rStorages, loading: loadingStorages } = useFetch(`/anvil/${anvilUuid}/store`, { refreshInterval, }); const storages = useMemo( () => rStorages && toAnvilSharedStorageOverview(rStorages), [rStorages], ); const loading = useMemo( () => [loadingAnvil, loadingCpu, loadingMemory, loadingStorages].some( (cond) => cond, ), [loadingAnvil, loadingCpu, loadingMemory, loadingStorages], ); const anvilSummary = useMemo( () => anvil && ( {anvil.state} ), [anvil], ); const hostsSummary = useMemo( () => anvil && ( .${gridClasses.item}:nth-child(-n + 4)`]: { marginBottom: '-.6em', }, }} > {Object.values(anvil.hosts).map((host) => { const { name, serverCount, state, stateProgress, uuid } = host; const stateColour: string = MAP_TO_HOST_STATE_COLOUR[state] ?? GREY; let stateValue: string = state; let servers: ReactNode; if (['offline', 'online'].includes(state)) { servers = {serverCount}; } else { stateValue = `${stateProgress}%`; } return [ {name} , {stateValue} , , {servers && Servers} , {servers} , ]; })} ), [anvil], ); const cpuSummary = useMemo( () => cpu && cpuSubnodes && ( Vendor{' '} {cpuSubnodes[0].vendor} .${gridClasses.item}:nth-child(-n + 2)`]: { marginBottom: '-.6em', }, }} > Cores {cpu.cores} Threads {cpu.threads} ), [cpu, cpuSubnodes], ); const memorySummary = useMemo( () => memory && ( Free {dSizeStr(memory.total - (memory.reserved + memory.allocated), { toUnit: 'ibyte', })} / {dSizeStr(memory.total, { toUnit: 'ibyte' })} ), [memory], ); const storeSummary = useMemo( () => storages && ( Total free {dSizeStr(storages.totalFree, { toUnit: 'ibyte' })} / {dSizeStr(storages.totalSize, { toUnit: 'ibyte' })} ), [storages], ); return loading ? ( ) : ( .${gridClasses.item}:nth-child(odd)`]: { alignItems: 'center', display: 'flex', height: '2.2em', }, }} > Node {anvilSummary} Subnodes {hostsSummary} CPU {cpuSummary} Memory {memorySummary} Storage {storeSummary} ); }; export default AnvilSummary;