Merge 967cf4ba28
into 32f205fcc1
This commit is contained in:
commit
4ba98f8601
|
@ -1,12 +1,22 @@
|
|||
import React from "react";
|
||||
import { Box, Typography, Pagination, Select, MenuItem } from "@mui/material";
|
||||
import React, { useState } from "react";
|
||||
import { Box, Typography, Pagination, Select, MenuItem, Button, Tooltip } from "@mui/material";
|
||||
import { Download, List, Grid as GridIcon } from "lucide-react";
|
||||
|
||||
const QueuePagination = ({
|
||||
pagination,
|
||||
totalQueues,
|
||||
handleChangeRowsPerPage,
|
||||
handleChangePage,
|
||||
onExportQueues, // New prop for export functionality
|
||||
onToggleViewMode // New prop for toggling view mode
|
||||
}) => {
|
||||
const [viewMode, setViewMode] = useState("table"); // "table" or "grid"
|
||||
|
||||
const handleViewModeChange = (mode) => {
|
||||
setViewMode(mode);
|
||||
onToggleViewMode(mode);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
|
@ -16,15 +26,55 @@ const QueuePagination = ({
|
|||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Select
|
||||
value={pagination.rowsPerPage}
|
||||
onChange={handleChangeRowsPerPage}
|
||||
size="small"
|
||||
>
|
||||
<MenuItem value={5}>5 per page</MenuItem>
|
||||
<MenuItem value={10}>10 per page</MenuItem>
|
||||
<MenuItem value={20}>20 per page</MenuItem>
|
||||
</Select>
|
||||
<Box display="flex" alignItems="center">
|
||||
<Select
|
||||
value={pagination.rowsPerPage}
|
||||
onChange={handleChangeRowsPerPage}
|
||||
size="small"
|
||||
>
|
||||
<MenuItem value={5}>5 per page</MenuItem>
|
||||
<MenuItem value={10}>10 per page</MenuItem>
|
||||
<MenuItem value={20}>20 per page</MenuItem>
|
||||
</Select>
|
||||
|
||||
{/* View mode toggle buttons */}
|
||||
<Box ml={2} display="flex" alignItems="center">
|
||||
<Tooltip title="Table View">
|
||||
<Button
|
||||
variant={viewMode === "table" ? "contained" : "outlined"}
|
||||
size="small"
|
||||
sx={{ minWidth: '40px', p: 1, mr: 1 }}
|
||||
onClick={() => handleViewModeChange("table")}
|
||||
>
|
||||
<List size={16} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip title="Grid View">
|
||||
<Button
|
||||
variant={viewMode === "grid" ? "contained" : "outlined"}
|
||||
size="small"
|
||||
sx={{ minWidth: '40px', p: 1 }}
|
||||
onClick={() => handleViewModeChange("grid")}
|
||||
>
|
||||
<GridIcon size={16} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
|
||||
{/* Export button */}
|
||||
<Tooltip title="Export Queues">
|
||||
<Button
|
||||
variant="outlined"
|
||||
size="small"
|
||||
startIcon={<Download size={16} />}
|
||||
onClick={onExportQueues}
|
||||
sx={{ ml: 2 }}
|
||||
>
|
||||
Export
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
|
@ -50,4 +100,4 @@ const QueuePagination = ({
|
|||
);
|
||||
};
|
||||
|
||||
export default QueuePagination;
|
||||
export default QueuePagination;
|
|
@ -0,0 +1,92 @@
|
|||
import React from "react";
|
||||
import {
|
||||
Box,
|
||||
Grid,
|
||||
Card,
|
||||
CardContent,
|
||||
Typography,
|
||||
Chip,
|
||||
Divider
|
||||
} from "@mui/material";
|
||||
|
||||
const QueueGridView = ({ queues, handleQueueClick }) => {
|
||||
// Helper function to determine status color
|
||||
const getStatusColor = (status) => {
|
||||
switch (status?.toLowerCase()) {
|
||||
case "open":
|
||||
return "success";
|
||||
case "closed":
|
||||
return "error";
|
||||
case "pending":
|
||||
return "warning";
|
||||
default:
|
||||
return "default";
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box sx={{ flexGrow: 1, mt: 2 }}>
|
||||
<Grid container spacing={2}>
|
||||
{queues.map((queue) => (
|
||||
<Grid item xs={12} sm={6} md={4} lg={3} key={queue.metadata.name}>
|
||||
<Card
|
||||
sx={{
|
||||
height: '100%',
|
||||
cursor: 'pointer',
|
||||
transition: 'transform 0.2s, box-shadow 0.2s',
|
||||
'&:hover': {
|
||||
transform: 'translateY(-4px)',
|
||||
boxShadow: 3
|
||||
}
|
||||
}}
|
||||
onClick={() => handleQueueClick(queue)}
|
||||
>
|
||||
<CardContent>
|
||||
<Box display="flex" justifyContent="space-between" alignItems="center" mb={1}>
|
||||
<Typography variant="h6" component="div" noWrap>
|
||||
{queue.metadata.name}
|
||||
</Typography>
|
||||
<Chip
|
||||
label={queue.status?.state || "Unknown"}
|
||||
size="small"
|
||||
color={getStatusColor(queue.status?.state)}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Typography variant="body2" color="text.secondary" gutterBottom>
|
||||
Namespace: {queue.metadata.namespace || "default"}
|
||||
</Typography>
|
||||
|
||||
<Divider sx={{ my: 1.5 }} />
|
||||
|
||||
<Typography variant="subtitle2">
|
||||
Allocated Resources:
|
||||
</Typography>
|
||||
|
||||
<Box mt={1}>
|
||||
<Typography variant="body2">
|
||||
CPU: {queue.status?.allocated?.cpu || "N/A"}
|
||||
</Typography>
|
||||
<Typography variant="body2">
|
||||
Memory: {queue.status?.allocated?.memory || "N/A"}
|
||||
</Typography>
|
||||
<Typography variant="body2">
|
||||
Pods: {queue.status?.allocated?.pods || "N/A"}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Divider sx={{ my: 1.5 }} />
|
||||
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
Created: {new Date(queue.metadata.creationTimestamp).toLocaleDateString()}
|
||||
</Typography>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default QueueGridView;
|
|
@ -7,6 +7,7 @@ import QueueTable from "./QueueTable/QueueTable";
|
|||
import QueuePagination from "./QueuePagination";
|
||||
import QueueYamlDialog from "./QueueYamlDialog";
|
||||
import TitleComponent from "../Titlecomponent";
|
||||
import QueueGridView from "./QueueTable/QueueGridView";
|
||||
|
||||
const Queues = () => {
|
||||
const [queues, setQueues] = useState([]);
|
||||
|
@ -24,6 +25,8 @@ const Queues = () => {
|
|||
field: null,
|
||||
direction: "asc",
|
||||
});
|
||||
// New state for view mode
|
||||
const [viewMode, setViewMode] = useState("table"); // "table" or "grid"
|
||||
|
||||
const fetchQueues = useCallback(async () => {
|
||||
setLoading(true);
|
||||
|
@ -135,6 +138,64 @@ const Queues = () => {
|
|||
setPagination((prev) => ({ ...prev, page: 1 }));
|
||||
}, []);
|
||||
|
||||
// New handler for toggling view mode
|
||||
const handleToggleViewMode = (mode) => {
|
||||
setViewMode(mode);
|
||||
};
|
||||
|
||||
// New handler for exporting queues data
|
||||
const handleExportQueues = () => {
|
||||
exportQueuesData(sortedQueues);
|
||||
};
|
||||
|
||||
// New function to export queues data as CSV
|
||||
const exportQueuesData = (queues) => {
|
||||
// Create a simplified version of the queues data for export
|
||||
const exportData = queues.map(queue => {
|
||||
return {
|
||||
name: queue.metadata?.name || '',
|
||||
namespace: queue.metadata?.namespace || 'default',
|
||||
state: queue.status?.state || 'Unknown',
|
||||
cpu: queue.status?.allocated?.cpu || 'N/A',
|
||||
memory: queue.status?.allocated?.memory || 'N/A',
|
||||
pods: queue.status?.allocated?.pods || 'N/A',
|
||||
creationTime: queue.metadata?.creationTimestamp || ''
|
||||
};
|
||||
});
|
||||
|
||||
// Convert data to CSV format
|
||||
const headers = ["Name", "Namespace", "State", "CPU", "Memory", "Pods", "Creation Time"];
|
||||
const csvContent = [
|
||||
headers.join(","),
|
||||
...exportData.map(row =>
|
||||
[
|
||||
row.name,
|
||||
row.namespace,
|
||||
row.state,
|
||||
row.cpu,
|
||||
row.memory,
|
||||
row.pods,
|
||||
new Date(row.creationTime).toLocaleString()
|
||||
].join(",")
|
||||
)
|
||||
].join("\n");
|
||||
|
||||
// Create download link
|
||||
const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
// Create temporary link and trigger download
|
||||
const link = document.createElement("a");
|
||||
link.setAttribute("href", url);
|
||||
link.setAttribute("download", `volcano-queues-${new Date().toISOString().split('T')[0]}.csv`);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
|
||||
// Cleanup
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(url);
|
||||
};
|
||||
|
||||
const uniqueStates = useMemo(() => {
|
||||
return [
|
||||
"All",
|
||||
|
@ -225,25 +286,38 @@ const Queues = () => {
|
|||
refreshLabel="Refresh Queues"
|
||||
/>
|
||||
</Box>
|
||||
<QueueTable
|
||||
sortedQueues={sortedQueues}
|
||||
allocatedFields={allocatedFields}
|
||||
handleQueueClick={handleQueueClick}
|
||||
handleSort={handleSort}
|
||||
sortConfig={sortConfig}
|
||||
filters={filters}
|
||||
handleFilterClick={handleFilterClick}
|
||||
anchorEl={anchorEl}
|
||||
uniqueStates={uniqueStates}
|
||||
handleFilterClose={handleFilterClose}
|
||||
setAnchorEl={setAnchorEl}
|
||||
/>
|
||||
|
||||
{/* Conditional rendering based on view mode */}
|
||||
{viewMode === "table" ? (
|
||||
<QueueTable
|
||||
sortedQueues={sortedQueues}
|
||||
allocatedFields={allocatedFields}
|
||||
handleQueueClick={handleQueueClick}
|
||||
handleSort={handleSort}
|
||||
sortConfig={sortConfig}
|
||||
filters={filters}
|
||||
handleFilterClick={handleFilterClick}
|
||||
anchorEl={anchorEl}
|
||||
uniqueStates={uniqueStates}
|
||||
handleFilterClose={handleFilterClose}
|
||||
setAnchorEl={setAnchorEl}
|
||||
/>
|
||||
) : (
|
||||
<QueueGridView
|
||||
queues={sortedQueues}
|
||||
handleQueueClick={handleQueueClick}
|
||||
/>
|
||||
)}
|
||||
|
||||
<QueuePagination
|
||||
pagination={pagination}
|
||||
totalQueues={totalQueues}
|
||||
handleChangeRowsPerPage={handleChangeRowsPerPage}
|
||||
handleChangePage={handleChangePage}
|
||||
onExportQueues={handleExportQueues} // New prop
|
||||
onToggleViewMode={handleToggleViewMode} // New prop
|
||||
/>
|
||||
|
||||
<QueueYamlDialog
|
||||
openDialog={openDialog}
|
||||
handleCloseDialog={handleCloseDialog}
|
||||
|
@ -254,4 +328,4 @@ const Queues = () => {
|
|||
);
|
||||
};
|
||||
|
||||
export default Queues;
|
||||
export default Queues;
|
|
@ -19,6 +19,7 @@
|
|||
"@mui/material": "^6.4.8",
|
||||
"bootstrap": "^5.3.3",
|
||||
"fortawesome": "^0.0.1-security",
|
||||
"lucide-react": "^0.511.0",
|
||||
"react-bootstrap": "^2.10.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -8806,6 +8807,14 @@
|
|||
"yallist": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/lucide-react": {
|
||||
"version": "0.511.0",
|
||||
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.511.0.tgz",
|
||||
"integrity": "sha512-VK5a2ydJ7xm8GvBeKLS9mu1pVK6ucef9780JVUjw6bAjJL/QXnd4Y0p7SPeOUMC27YhzNCZvm5d/QX0Tp3rc0w==",
|
||||
"peerDependencies": {
|
||||
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lz-string": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
"@mui/material": "^6.4.8",
|
||||
"bootstrap": "^5.3.3",
|
||||
"fortawesome": "^0.0.1-security",
|
||||
"lucide-react": "^0.511.0",
|
||||
"react-bootstrap": "^2.10.9"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue