Files
sgeUpdated/sge-frontend/src/views/DataCenter.js

342 lines
12 KiB
JavaScript

import React, { useState, useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { Card, CardHeader, CardTitle, Button } from "reactstrap";
import DataTable from "react-data-table-component";
import { ChevronDown, RefreshCw, Server, Monitor } from "react-feather";
import { useTranslation } from "react-i18next";
import { useSnackbar } from "notistack";
import { getDataCenters } from "../redux/actions/dataCenter";
import SpinnerComponent from "../@core/components/spinner/Fallback-spinner";
const DataCenter = () => {
const { t } = useTranslation();
const { enqueueSnackbar } = useSnackbar();
const dispatch = useDispatch();
// Redux state
const dataCenterStore = useSelector((state) => state.dataCenter);
const [refreshInterval, setRefreshInterval] = useState(null);
const getAllPhysicalMachines = (dataCenter) => {
// Physical machines are directly in the dataCenter object, not in projects
const pms = dataCenter.physicalMachines || [];
return pms;
};
// Table columns following your pattern
const initialColumns = [
{
name: "External ID",
selector: (row) => row.externalId,
sortable: true,
minWidth: "100px",
},
{
name: "Data Centers",
selector: (row) => row.dataCenter,
sortable: true,
minWidth: "200px",
},
// Projects - Based on API response, this field might not exist or be structured differently
// {
// name: "Projects",
// selector: (row) => row.projects?.length || 0,
// sortable: true,
// minWidth: "200px",
// cell: (row) => (
// <div>
// {row.projects && row.projects.length > 0 ? (
// <div className="d-flex flex-column">
// {row.projects.map((project, index) => (
// <div
// key={project.id}
// className={`badge badge-light-primary ${
// index > 0 ? "mt-1" : ""
// }`}
// >
// {project.name}
// </div>
// ))}
// </div>
// ) : (
// <span className="text-muted">-</span>
// )}
// </div>
// ),
// },
// Physical Machines
{
name: "Physical Machines",
selector: (row) => getAllPhysicalMachines(row),
sortable: false,
minWidth: "200px",
cell: (row) => {
const pms = getAllPhysicalMachines(row);
return (
<div className="d-flex align-items-center">
<Server size={16} className="mr-1" />
<span>{pms.length} machines</span>
</div>
);
},
},
{
name: "Virtual Machines",
selector: (row) => {
const pms = getAllPhysicalMachines(row);
const vms = pms.reduce(
(acc, pm) => {
if (!pm.vms) return acc;
return {
active:
acc.active +
pm.vms.filter((vm) => vm.state?.toLowerCase() === "active")
.length,
total: acc.total + pm.vms.length,
};
},
{ active: 0, total: 0 }
);
return vms.total;
},
sortable: true,
minWidth: "200px",
cell: (row) => {
const pms = getAllPhysicalMachines(row);
const vms = pms.reduce(
(acc, pm) => {
if (!pm.vms) return acc;
return {
active:
acc.active +
pm.vms.filter((vm) => vm.state?.toLowerCase() === "active")
.length,
total: acc.total + pm.vms.length,
};
},
{ active: 0, total: 0 }
);
return (
<div className="d-flex align-items-center">
<Monitor size={16} className="mr-2" />
<div>
<div className="font-weight-bold">{vms.total} Total</div>
<div className="small">
<span className="text-success">{vms.active} Active</span>
<span className="text-muted mx-1"></span>
<span className="text-warning">
{vms.total - vms.active} Inactive
</span>
</div>
</div>
</div>
);
},
},
];
// Fetch data on component mount
useEffect(() => {
dispatch(getDataCenters());
// Set up auto-refresh every 2 minutes
const interval = setInterval(() => {
dispatch(getDataCenters());
}, 2 * 60 * 1000);
setRefreshInterval(interval);
return () => {
if (interval) clearInterval(interval);
};
}, [dispatch]);
// Handle errors
useEffect(() => {
if (dataCenterStore.error) {
enqueueSnackbar(dataCenterStore.error, {
variant: "error",
preventDuplicate: true,
});
}
}, [dataCenterStore.error, enqueueSnackbar]);
const handleRefresh = () => {
dispatch(getDataCenters());
};
// Expandable component for showing physical machines and VMs
const ExpandableComponent = ({ data }) => {
const physicalMachines = getAllPhysicalMachines(data);
console.log("▶️ Expandable Data", physicalMachines);
return (
<div className="expandable-content p-3">
<h6 className="mb-3">Physical Machines:</h6>
{physicalMachines.length === 0 && (
<p className="text-muted ml-3">No physical machines</p>
)}
{physicalMachines.map((pm) => (
<div key={pm.id} className="mb-3 border rounded p-3">
<h6 className="text-primary">{pm.name}</h6>
{/* All VMs */}
<div className="mb-2 d-flex justify-content-between align-items-center">
<h6 className="mb-0">
<Monitor size={16} className="mr-1" />
Virtual Machines ({pm.vms?.length || 0})
</h6>
</div>
{pm.vms?.length > 0 ? (
<div className="table-responsive mt-2">
<table className="table table-bordered table-hover">
<thead className="thead-light">
<tr>
<th>Name</th>
<th>Status</th>
<th>Power (W)</th>
<th>Configuration</th>
<th>Host</th>
</tr>
</thead>
<tbody>
{pm.vms.map((vm) => {
const isActive =
vm.state && ["ACTIVE", "active"].includes(vm.state);
return (
<tr key={vm.id}>
<td>
<span className="font-weight-bold">
{vm.vmName || vm.vm_name}
</span>
</td>
<td>
<div
className={`d-inline-block px-2 py-1 rounded-pill ${
isActive
? "bg-light-success text-success"
: "bg-light-warning text-warning"
}`}
>
{vm.state}
</div>
</td>
<td>
{vm.power ? (
<span>{vm.power.toFixed(2)}</span>
) : (
<span className="text-muted">-</span>
)}
</td>
<td>
<div className="d-flex align-items-center">
<div className="mr-3">
<small className="text-muted d-block">
CPU
</small>
<span>
{vm.config?.cpu ||
(vm.confg && vm.confg[1]) ||
"-"}
</span>
</div>
<div className="mr-3">
<small className="text-muted d-block">
RAM
</small>
<span>
{vm.config?.ram ||
(vm.confg && vm.confg[2]) ||
"-"}{" "}
GB
</span>
</div>
<div>
<small className="text-muted d-block">
Disk
</small>
<span>
{vm.config?.disk ||
(vm.confg && vm.confg[3]) ||
"-"}{" "}
GB
</span>
</div>
</div>
</td>
<td>
<div className="d-flex align-items-center">
<Server size={14} className="mr-1" />
<span>
{vm.host ||
vm.hostingPm ||
(vm.confg && vm.confg[4]) ||
"-"}
</span>
</div>
</td>
</tr>
);
})}
</tbody>
</table>
</div>
) : (
<div className="text-center p-3 bg-light-secondary rounded">
<Monitor size={24} className="text-muted mb-1" />
<p className="text-muted mb-0">No virtual machines found</p>
</div>
)}
</div>
))}
</div>
);
};
return (
<div style={{ marginTop: "2%" }}>
<Card>
<CardHeader className="border-bottom">
<CardTitle tag="h4">Test</CardTitle>
<Button
className="ml-2"
color="primary"
onClick={handleRefresh}
disabled={dataCenterStore.loading}
>
<RefreshCw size={15} />
<span className="align-middle ml-50">
{dataCenterStore.loading ? "Refreshing..." : "Refresh"}
</span>
</Button>
</CardHeader>
<DataTable
noHeader
columns={initialColumns}
data={dataCenterStore.dataCenters}
sortIcon={<ChevronDown size={10} />}
expandableRows
expandableRowsComponent={ExpandableComponent}
progressPending={dataCenterStore.loading}
progressComponent={
<div className="d-flex justify-content-center p-3">
<SpinnerComponent />
</div>
}
noDataComponent={
<div className="d-flex flex-column align-items-center p-3">
<Server size={48} className="text-muted mb-2" />
<p className="text-muted">No data centers found</p>
</div>
}
className="react-dataTable"
/>
</Card>
</div>
);
};
export default DataCenter;