This commit is contained in:
Himanshi Tyagi 2025-05-23 21:21:36 +02:00 committed by GitHub
commit 4ba98f8601
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 252 additions and 26 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;

9
package-lock.json generated
View File

@ -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",

View File

@ -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"
}
}