[release] v0.12.0-unstable7
This commit is contained in:
parent
9d1cd315bc
commit
d3a4d615b2
5 changed files with 275 additions and 44 deletions
|
@ -147,7 +147,9 @@ const PlotComponent = ({ title, data, defaultSlot = 'latest' }) => {
|
|||
},
|
||||
|
||||
formatter: (num) => {
|
||||
if (Math.abs(num) >= 1e9) {
|
||||
if (Math.abs(num) >= 1e12) {
|
||||
return (num / 1e12).toFixed(1) + 'T'; // Convert to Millions
|
||||
} else if (Math.abs(num) >= 1e9) {
|
||||
return (num / 1e9).toFixed(1) + 'G'; // Convert to Millions
|
||||
} else if (Math.abs(num) >= 1e6) {
|
||||
return (num / 1e6).toFixed(1) + 'M'; // Convert to Millions
|
||||
|
|
260
client/src/pages/dashboard/components/table.jsx
Normal file
260
client/src/pages/dashboard/components/table.jsx
Normal file
|
@ -0,0 +1,260 @@
|
|||
import { useEffect, useState } from 'react';
|
||||
// material-ui
|
||||
import {
|
||||
Avatar,
|
||||
AvatarGroup,
|
||||
Box,
|
||||
Button,
|
||||
Grid,
|
||||
List,
|
||||
ListItemAvatar,
|
||||
ListItemButton,
|
||||
ListItemSecondaryAction,
|
||||
ListItemText,
|
||||
MenuItem,
|
||||
Stack,
|
||||
TextField,
|
||||
Typography,
|
||||
Alert,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
Table,
|
||||
TableBody
|
||||
} from '@mui/material';
|
||||
import MainCard from '../../../components/MainCard';
|
||||
|
||||
// material-ui
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
|
||||
// third-party
|
||||
import ReactApexChart from 'react-apexcharts';
|
||||
import { object } from 'prop-types';
|
||||
|
||||
function formatDate(now, time) {
|
||||
// use as UTC
|
||||
// now.setMinutes(now.getMinutes() - now.getTimezoneOffset());
|
||||
|
||||
const year = now.getFullYear();
|
||||
const month = String(now.getMonth() + 1).padStart(2, '0'); // Months are 0-based
|
||||
const day = String(now.getDate()).padStart(2, '0');
|
||||
const hours = String(now.getHours()).padStart(2, '0');
|
||||
const minutes = String(now.getMinutes()).padStart(2, '0');
|
||||
const seconds = String(now.getSeconds()).padStart(2, '0');
|
||||
|
||||
return time ? `${year}-${month}-${day} ${hours}:${minutes}:${seconds}` : `${year}-${month}-${day}`;
|
||||
}
|
||||
|
||||
function descendingComparator(a, b, orderBy) {
|
||||
if (b[orderBy] < a[orderBy]) {
|
||||
return -1;
|
||||
}
|
||||
if (b[orderBy] > a[orderBy]) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function getComparator(order, orderBy) {
|
||||
return order === 'desc' ? (a, b) => descendingComparator(a, b, orderBy) : (a, b) => -descendingComparator(a, b, orderBy);
|
||||
}
|
||||
|
||||
function stableSort(array, comparator) {
|
||||
const stabilizedThis = array.map((el, index) => [el, index]);
|
||||
stabilizedThis.sort((a, b) => {
|
||||
const order = comparator(a[0], b[0]);
|
||||
if (order !== 0) {
|
||||
return order;
|
||||
}
|
||||
return a[1] - b[1];
|
||||
});
|
||||
return stabilizedThis.map((el) => el[0]);
|
||||
}
|
||||
|
||||
function formatter(num) {
|
||||
if (Math.abs(num) >= 1e12) {
|
||||
return (num / 1e12).toFixed(1) + 'T'; // Convert to Millions
|
||||
} else if (Math.abs(num) >= 1e9) {
|
||||
return (num / 1e9).toFixed(1) + 'G'; // Convert to Millions
|
||||
} else if (Math.abs(num) >= 1e6) {
|
||||
return (num / 1e6).toFixed(1) + 'M'; // Convert to Millions
|
||||
} else if (Math.abs(num) >= 1e3) {
|
||||
return (num / 1e3).toFixed(1) + 'K'; // Convert to Thousands
|
||||
} else {
|
||||
return num.toString();
|
||||
}
|
||||
}
|
||||
|
||||
function toUTC(date, time) {
|
||||
let now = new Date(date);
|
||||
now.setMinutes(now.getMinutes() + now.getTimezoneOffset());
|
||||
return formatDate(now, time);
|
||||
}
|
||||
|
||||
function OrderTableHead({ order, orderBy, headCells }) {
|
||||
return (
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
{headCells.map((headCell) => (
|
||||
<TableCell
|
||||
key={headCell.id}
|
||||
align={headCell.align}
|
||||
padding={headCell.disablePadding ? 'none' : 'normal'}
|
||||
sortDirection={orderBy === headCell.id ? order : false}
|
||||
>
|
||||
{headCell.label}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
);
|
||||
}
|
||||
|
||||
const TableComponent = ({ title, data, defaultSlot = 'latest' }) => {
|
||||
const [slot, setSlot] = useState(defaultSlot);
|
||||
const theme = useTheme();
|
||||
const { primary, secondary } = theme.palette.text;
|
||||
const line = theme.palette.divider;
|
||||
const [series, setSeries] = useState([]);
|
||||
const [order] = useState('asc');
|
||||
const [orderBy] = useState('name');
|
||||
const [headCells, setHeadCells] = useState([]);
|
||||
const [rows, setRows] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
let heads = {};
|
||||
let fnrows = [];
|
||||
|
||||
data.forEach((item) => {
|
||||
let k = item.Key.split('.')
|
||||
let v = item.Values.length ? item.Values[item.Values.length - 1] : 0;
|
||||
let name = k[k.length - 1];
|
||||
let cat = k[k.length - 2];
|
||||
|
||||
heads[cat] = true;
|
||||
|
||||
if(!fnrows.find((row) => row.name === name)) {
|
||||
fnrows.push({
|
||||
name,
|
||||
[cat]: formatter(v.Value)
|
||||
});
|
||||
} else {
|
||||
fnrows.find((row) => row.name === name)[cat] = formatter(v.Value);
|
||||
}
|
||||
});
|
||||
|
||||
let fnhc = [
|
||||
{
|
||||
id: 'name',
|
||||
align: 'left',
|
||||
disablePadding: false,
|
||||
label: 'Name'
|
||||
},
|
||||
];
|
||||
|
||||
Object.keys(heads).forEach((head) => {
|
||||
fnhc.push({
|
||||
id: head,
|
||||
align: 'right',
|
||||
disablePadding: false,
|
||||
label: head
|
||||
});
|
||||
});
|
||||
|
||||
setHeadCells(fnhc);
|
||||
setRows(fnrows);
|
||||
|
||||
}, [data, slot]);
|
||||
|
||||
|
||||
return <Grid item xs={12} md={5} lg={4}>
|
||||
<Grid container alignItems="center" justifyContent="space-between">
|
||||
<Grid item>
|
||||
<Typography variant="h5">{title}</Typography>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Stack direction="row" alignItems="center" spacing={0}>
|
||||
<Button
|
||||
size="small"
|
||||
onClick={() => setSlot('latest')}
|
||||
color={slot === 'latest' ? 'primary' : 'secondary'}
|
||||
variant={slot === 'latest' ? 'outlined' : 'text'}
|
||||
>
|
||||
Latest
|
||||
</Button>
|
||||
<Button
|
||||
size="small"
|
||||
onClick={() => setSlot('hourly')}
|
||||
color={slot === 'hourly' ? 'primary' : 'secondary'}
|
||||
variant={slot === 'hourly' ? 'outlined' : 'text'}
|
||||
>
|
||||
Hourly
|
||||
</Button>
|
||||
<Button
|
||||
size="small"
|
||||
onClick={() => setSlot('daily')}
|
||||
color={slot === 'daily' ? 'primary' : 'secondary'}
|
||||
variant={slot === 'daily' ? 'outlined' : 'text'}
|
||||
>
|
||||
Daily
|
||||
</Button>
|
||||
</Stack>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<MainCard content={false} sx={{ mt: 1.5 }}>
|
||||
<Box>
|
||||
<TableContainer
|
||||
sx={{
|
||||
width: '100%',
|
||||
overflowX: 'auto',
|
||||
position: 'relative',
|
||||
display: 'block',
|
||||
maxWidth: '100%',
|
||||
'& td, & th': { whiteSpace: 'nowrap' }
|
||||
}}
|
||||
>
|
||||
<Table
|
||||
aria-labelledby="tableTitle"
|
||||
sx={{
|
||||
'& .MuiTableCell-root:first-child': {
|
||||
pl: 2
|
||||
},
|
||||
'& .MuiTableCell-root:last-child': {
|
||||
pr: 3
|
||||
}
|
||||
}}
|
||||
>
|
||||
<OrderTableHead headCells={headCells} order={order} orderBy={orderBy} />
|
||||
<TableBody>
|
||||
{stableSort(rows, getComparator(order, orderBy)).map((row, index) => {
|
||||
const isItemSelected = false // isSelected(row.trackingNo);
|
||||
const labelId = `enhanced-table-checkbox-${index}`;
|
||||
|
||||
return (
|
||||
<TableRow
|
||||
hover
|
||||
role="checkbox"
|
||||
sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
|
||||
aria-checked={isItemSelected}
|
||||
tabIndex={-1}
|
||||
key={row.trackingNo}
|
||||
selected={isItemSelected}
|
||||
>
|
||||
{headCells.map((headCell) => {
|
||||
return <TableCell align={
|
||||
headCell.align
|
||||
}>{row[headCell.id]}</TableCell>
|
||||
})}
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Box>
|
||||
</MainCard>
|
||||
</Grid>
|
||||
}
|
||||
|
||||
export default TableComponent;
|
|
@ -39,6 +39,7 @@ import IsLoggedIn from '../../isLoggedIn';
|
|||
import * as API from '../../api';
|
||||
import AnimateButton from '../../components/@extended/AnimateButton';
|
||||
import PlotComponent from './components/plot';
|
||||
import TableComponent from './components/table';
|
||||
|
||||
// avatar style
|
||||
const avatarSX = {
|
||||
|
@ -177,47 +178,15 @@ const DashboardDefault = () => {
|
|||
|
||||
<PlotComponent title={'Resources'} data={[metrics["cosmos.system.cpu.0"], metrics["cosmos.system.ram"]]}/>
|
||||
|
||||
<Grid item xs={12} md={5} lg={4}>
|
||||
<Grid container alignItems="center" justifyContent="space-between">
|
||||
<Grid item>
|
||||
<Typography variant="h5">Income Overview</Typography>
|
||||
</Grid>
|
||||
<Grid item />
|
||||
</Grid>
|
||||
<MainCard sx={{ mt: 2 }} content={false}>
|
||||
<Box sx={{ p: 3, pb: 0 }}>
|
||||
<Stack spacing={2}>
|
||||
<Typography variant="h6" color="textSecondary">
|
||||
This Week Statistics
|
||||
</Typography>
|
||||
<Typography variant="h3">$7,650</Typography>
|
||||
</Stack>
|
||||
</Box>
|
||||
<MonthlyBarChart />
|
||||
</MainCard>
|
||||
</Grid>
|
||||
<TableComponent title="Containers - Network" data={
|
||||
Object.keys(metrics).filter((key) => key.startsWith("cosmos.system.docker.cpu") || key.startsWith("cosmos.system.docker.ram")).map((key) => metrics[key])
|
||||
}/>
|
||||
|
||||
<PlotComponent title={'Network'} data={[metrics["cosmos.system.netTx"], metrics["cosmos.system.netRx"]]}/>
|
||||
|
||||
<Grid item xs={12} md={5} lg={4}>
|
||||
<Grid container alignItems="center" justifyContent="space-between">
|
||||
<Grid item>
|
||||
<Typography variant="h5">Income Overview</Typography>
|
||||
</Grid>
|
||||
<Grid item />
|
||||
</Grid>
|
||||
<MainCard sx={{ mt: 2 }} content={false}>
|
||||
<Box sx={{ p: 3, pb: 0 }}>
|
||||
<Stack spacing={2}>
|
||||
<Typography variant="h6" color="textSecondary">
|
||||
This Week Statistics
|
||||
</Typography>
|
||||
<Typography variant="h3">$7,650</Typography>
|
||||
</Stack>
|
||||
</Box>
|
||||
<MonthlyBarChart />
|
||||
</MainCard>
|
||||
</Grid>
|
||||
<TableComponent title="Containers - Network" data={
|
||||
Object.keys(metrics).filter((key) => key.startsWith("cosmos.system.docker.net")).map((key) => metrics[key])
|
||||
}/>
|
||||
|
||||
{/* row 3 */}
|
||||
<Grid item xs={12} md={7} lg={8}>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "cosmos-server",
|
||||
"version": "0.12.0-unstable6",
|
||||
"version": "0.12.0-unstable7",
|
||||
"description": "",
|
||||
"main": "test-server.js",
|
||||
"bugs": {
|
||||
|
|
|
@ -54,10 +54,10 @@ func GetSystemMetrics() {
|
|||
// Get Network Usage
|
||||
netIO, err := net.IOCounters(false)
|
||||
|
||||
netIOTest, _ := net.IOCounters(true)
|
||||
for _, v := range netIOTest {
|
||||
utils.Debug("Metrics - Network " + v.Name + " : " + strconv.Itoa(int(v.BytesRecv)) + " / " + strconv.Itoa(int(v.BytesSent)) + " / " + strconv.Itoa(int(v.Errin + v.Errout)) + " / " + strconv.Itoa(int(v.Dropin + v.Dropout)))
|
||||
}
|
||||
// netIOTest, _ := net.IOCounters(true)
|
||||
// for _, v := range netIOTest {
|
||||
// utils.Debug("Metrics - Network " + v.Name + " : " + strconv.Itoa(int(v.BytesRecv)) + " / " + strconv.Itoa(int(v.BytesSent)) + " / " + strconv.Itoa(int(v.Errin + v.Errout)) + " / " + strconv.Itoa(int(v.Dropin + v.Dropout)))
|
||||
// }
|
||||
|
||||
PushSetMetric("system.netRx", int(netIO[0].BytesRecv), DataDef{
|
||||
Max: 0,
|
||||
|
|
Loading…
Reference in a new issue