forked from BLC/AyposWeb
102 lines
3.2 KiB
TypeScript
102 lines
3.2 KiB
TypeScript
import React, { useState, useEffect, useCallback } from 'react';
|
|
import { Grid, Paper, Typography, Box, Divider } from '@mui/material';
|
|
import StorageIcon from '@mui/icons-material/Storage';
|
|
import ComputerIcon from '@mui/icons-material/Computer';
|
|
import { config } from '../../config/env';
|
|
import { VMPlacementData } from './types';
|
|
import { useSmartPolling } from './hooks';
|
|
|
|
const ENDPOINT = `${config.apiUrl}/prom/get_chart_data/vm_placement`;
|
|
|
|
const SummaryStats: React.FC = () => {
|
|
const fetchData = useCallback(async (): Promise<VMPlacementData> => {
|
|
const response = await fetch(ENDPOINT);
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to fetch data: ${response.status}`);
|
|
}
|
|
const jsonData = await response.json();
|
|
console.log('SummaryStats - Raw API response:', jsonData);
|
|
return jsonData;
|
|
}, []);
|
|
|
|
const { data, pollingInterval } = useSmartPolling<VMPlacementData>(
|
|
fetchData,
|
|
null,
|
|
5000, // min interval: 5 seconds
|
|
30000 // max interval: 30 seconds
|
|
);
|
|
|
|
const stats = React.useMemo(() => {
|
|
if (!data) {
|
|
return {
|
|
activeComputes: 0,
|
|
totalComputes: 0,
|
|
activeVMs: 0,
|
|
inactiveVMs: 0,
|
|
};
|
|
}
|
|
|
|
// Count from vm_placement object
|
|
let totalPMs = Object.keys(data.vm_placement).length;
|
|
let activePMs = Object.values(data.vm_placement).filter(pm => pm.power > 0).length;
|
|
let totalActiveVMs = 0;
|
|
let totalInactiveVMs = 0;
|
|
|
|
Object.values(data.vm_placement).forEach(pm => {
|
|
const vms = Object.values(pm.vms);
|
|
totalActiveVMs += vms.filter(vm => vm.state === 'active').length;
|
|
totalInactiveVMs += vms.filter(vm => vm.state === 'inactive').length;
|
|
});
|
|
|
|
return {
|
|
activeComputes: activePMs,
|
|
totalComputes: totalPMs,
|
|
activeVMs: totalActiveVMs,
|
|
inactiveVMs: totalInactiveVMs,
|
|
};
|
|
}, [data]);
|
|
|
|
return (
|
|
<Grid item xs={12} md={8}>
|
|
<Paper
|
|
sx={{
|
|
p: 2,
|
|
bgcolor: 'background.paper',
|
|
boxShadow: 3,
|
|
borderRadius: 1,
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
gap: 3
|
|
}}
|
|
>
|
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1.5 }}>
|
|
<StorageIcon sx={{ color: 'primary.main', fontSize: 28 }} />
|
|
<Box>
|
|
<Typography variant="body2" color="textSecondary" sx={{ mb: 0.5 }}>
|
|
Compute Nodes
|
|
</Typography>
|
|
<Typography variant="h6" sx={{ lineHeight: 1, fontWeight: 500 }}>
|
|
{stats.activeComputes}/{stats.totalComputes}
|
|
</Typography>
|
|
</Box>
|
|
</Box>
|
|
|
|
<Divider orientation="vertical" flexItem />
|
|
|
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1.5 }}>
|
|
<ComputerIcon sx={{ color: 'info.main', fontSize: 28 }} />
|
|
<Box>
|
|
<Typography variant="body2" color="textSecondary" sx={{ mb: 0.5 }}>
|
|
Virtual Machines
|
|
</Typography>
|
|
<Typography variant="h6" sx={{ lineHeight: 1, fontWeight: 500 }}>
|
|
{stats.activeVMs}/{stats.activeVMs + stats.inactiveVMs}
|
|
</Typography>
|
|
</Box>
|
|
</Box>
|
|
</Paper>
|
|
</Grid>
|
|
);
|
|
};
|
|
|
|
export default SummaryStats;
|