feat(cluster-health): add visibility options (#3210)

This commit is contained in:
Meier Lukas
2025-05-24 17:49:49 +02:00
committed by GitHub
parent 2dc871e531
commit 939df8f6d1
4 changed files with 236 additions and 127 deletions
@@ -72,126 +72,156 @@ export const ClusterHealthMonitoring = ({
const cpuPercent = maxCpu ? (usedCpu / maxCpu) * 100 : 0;
const memPercent = maxMem ? (usedMem / maxMem) * 100 : 0;
const defaultValue = [options.visibleClusterSections.at(0) ?? "node"];
const isTiny = width < 256;
return (
<Stack h="100%" p="xs" gap={isTiny ? "xs" : "md"}>
<Group justify="center" wrap="nowrap">
<Text fz={isTiny ? 8 : "xs"} tt="uppercase" fw={700} c="dimmed" ta="center">
{formatUptime(uptime, t)}
</Text>
</Group>
<SummaryHeader cpu={cpuPercent} memory={memPercent} isTiny={isTiny} />
<Accordion variant="contained" chevronPosition="right" multiple defaultValue={["node"]}>
<ResourceAccordionItem
value="node"
title={t("widget.healthMonitoring.cluster.resource.node.name")}
icon={IconServer}
badge={addBadgeColor({
activeCount: activeNodes,
totalCount: healthData.nodes.length,
sectionIndicatorRequirement: options.sectionIndicatorRequirement,
})}
isTiny={isTiny}
>
<ResourceTable type="node" data={healthData.nodes} isTiny={isTiny} />
</ResourceAccordionItem>
{options.showUptime && (
<Group justify="center" wrap="nowrap">
<Text fz={isTiny ? 8 : "xs"} tt="uppercase" fw={700} c="dimmed" ta="center">
{formatUptime(uptime, t)}
</Text>
</Group>
)}
<SummaryHeader
cpu={{
value: cpuPercent,
hidden: !options.cpu,
}}
memory={{
value: memPercent,
hidden: !options.memory,
}}
isTiny={isTiny}
/>
{options.visibleClusterSections.length >= 1 && (
<Accordion variant="contained" chevronPosition="right" multiple defaultValue={defaultValue}>
{options.visibleClusterSections.includes("node") && (
<ResourceAccordionItem
value="node"
title={t("widget.healthMonitoring.cluster.resource.node.name")}
icon={IconServer}
badge={addBadgeColor({
activeCount: activeNodes,
totalCount: healthData.nodes.length,
sectionIndicatorRequirement: options.sectionIndicatorRequirement,
})}
isTiny={isTiny}
>
<ResourceTable type="node" data={healthData.nodes} isTiny={isTiny} />
</ResourceAccordionItem>
)}
<ResourceAccordionItem
value="qemu"
title={t("widget.healthMonitoring.cluster.resource.qemu.name")}
icon={IconDeviceLaptop}
badge={addBadgeColor({
activeCount: activeVMs,
totalCount: healthData.vms.length,
sectionIndicatorRequirement: options.sectionIndicatorRequirement,
})}
isTiny={isTiny}
>
<ResourceTable type="qemu" data={healthData.vms} isTiny={isTiny} />
</ResourceAccordionItem>
{options.visibleClusterSections.includes("qemu") && (
<ResourceAccordionItem
value="qemu"
title={t("widget.healthMonitoring.cluster.resource.qemu.name")}
icon={IconDeviceLaptop}
badge={addBadgeColor({
activeCount: activeVMs,
totalCount: healthData.vms.length,
sectionIndicatorRequirement: options.sectionIndicatorRequirement,
})}
isTiny={isTiny}
>
<ResourceTable type="qemu" data={healthData.vms} isTiny={isTiny} />
</ResourceAccordionItem>
)}
<ResourceAccordionItem
value="lxc"
title={t("widget.healthMonitoring.cluster.resource.lxc.name")}
icon={IconCube}
badge={addBadgeColor({
activeCount: activeLXCs,
totalCount: healthData.lxcs.length,
sectionIndicatorRequirement: options.sectionIndicatorRequirement,
})}
isTiny={isTiny}
>
<ResourceTable type="lxc" data={healthData.lxcs} isTiny={isTiny} />
</ResourceAccordionItem>
{options.visibleClusterSections.includes("lxc") && (
<ResourceAccordionItem
value="lxc"
title={t("widget.healthMonitoring.cluster.resource.lxc.name")}
icon={IconCube}
badge={addBadgeColor({
activeCount: activeLXCs,
totalCount: healthData.lxcs.length,
sectionIndicatorRequirement: options.sectionIndicatorRequirement,
})}
isTiny={isTiny}
>
<ResourceTable type="lxc" data={healthData.lxcs} isTiny={isTiny} />
</ResourceAccordionItem>
)}
<ResourceAccordionItem
value="storage"
title={t("widget.healthMonitoring.cluster.resource.storage.name")}
icon={IconDatabase}
badge={addBadgeColor({
activeCount: activeStorage,
totalCount: healthData.storages.length,
sectionIndicatorRequirement: options.sectionIndicatorRequirement,
})}
isTiny={isTiny}
>
<ResourceTable type="storage" data={healthData.storages} isTiny={isTiny} />
</ResourceAccordionItem>
</Accordion>
{options.visibleClusterSections.includes("storage") && (
<ResourceAccordionItem
value="storage"
title={t("widget.healthMonitoring.cluster.resource.storage.name")}
icon={IconDatabase}
badge={addBadgeColor({
activeCount: activeStorage,
totalCount: healthData.storages.length,
sectionIndicatorRequirement: options.sectionIndicatorRequirement,
})}
isTiny={isTiny}
>
<ResourceTable type="storage" data={healthData.storages} isTiny={isTiny} />
</ResourceAccordionItem>
)}
</Accordion>
)}
</Stack>
);
};
interface SummaryHeaderProps {
cpu: number;
memory: number;
cpu: { value: number; hidden: boolean };
memory: { value: number; hidden: boolean };
isTiny: boolean;
}
const SummaryHeader = ({ cpu, memory, isTiny }: SummaryHeaderProps) => {
const t = useI18n();
if (cpu.hidden && memory.hidden) return null;
return (
<Center>
<Group wrap="wrap" justify="center" gap="xs">
<Flex direction="row">
<RingProgress
roundCaps
size={isTiny ? 32 : 48}
thickness={isTiny ? 2 : 4}
label={
<Center>
<IconCpu size={isTiny ? 12 : 20} />
</Center>
}
sections={[{ value: cpu, color: cpu > 75 ? "orange" : "green" }]}
/>
<Stack align="center" justify="center" gap={0}>
<Text fw={500} size={isTiny ? "xs" : "sm"}>
{t("widget.healthMonitoring.cluster.summary.cpu")}
</Text>
<Text size={isTiny ? "8px" : "xs"}>{cpu.toFixed(1)}%</Text>
</Stack>
</Flex>
<Flex>
<RingProgress
roundCaps
size={isTiny ? 32 : 48}
thickness={isTiny ? 2 : 4}
label={
<Center>
<IconBrain size={isTiny ? 12 : 20} />
</Center>
}
sections={[{ value: memory, color: memory > 75 ? "orange" : "green" }]}
/>
<Stack align="center" justify="center" gap={0}>
<Text size={isTiny ? "xs" : "sm"} fw={500}>
{t("widget.healthMonitoring.cluster.summary.memory")}
</Text>
<Text size={isTiny ? "8px" : "xs"}>{memory.toFixed(1)}%</Text>
</Stack>
</Flex>
{!cpu.hidden && (
<Flex direction="row">
<RingProgress
roundCaps
size={isTiny ? 32 : 48}
thickness={isTiny ? 2 : 4}
label={
<Center>
<IconCpu size={isTiny ? 12 : 20} />
</Center>
}
sections={[{ value: cpu.value, color: cpu.value > 75 ? "orange" : "green" }]}
/>
<Stack align="center" justify="center" gap={0}>
<Text fw={500} size={isTiny ? "xs" : "sm"}>
{t("widget.healthMonitoring.cluster.summary.cpu")}
</Text>
<Text size={isTiny ? "8px" : "xs"}>{cpu.value.toFixed(1)}%</Text>
</Stack>
</Flex>
)}
{!memory.hidden && (
<Flex>
<RingProgress
roundCaps
size={isTiny ? 32 : 48}
thickness={isTiny ? 2 : 4}
label={
<Center>
<IconBrain size={isTiny ? 12 : 20} />
</Center>
}
sections={[{ value: memory.value, color: memory.value > 75 ? "orange" : "green" }]}
/>
<Stack align="center" justify="center" gap={0}>
<Text size={isTiny ? "xs" : "sm"} fw={500}>
{t("widget.healthMonitoring.cluster.summary.memory")}
</Text>
<Text size={isTiny ? "8px" : "xs"}>{memory.value.toFixed(1)}%</Text>
</Stack>
</Flex>
)}
</Group>
</Center>
);