diff --git a/frontend/src/components/Jobs.jsx b/frontend/src/components/Jobs.jsx index bda7440..c37de2c 100644 --- a/frontend/src/components/Jobs.jsx +++ b/frontend/src/components/Jobs.jsx @@ -1,31 +1,45 @@ -import React, {useCallback, useEffect, useMemo, useState} from "react"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; import { - Box, - Button, - Chip, - Dialog, - DialogActions, - DialogContent, - DialogTitle, - IconButton, - Menu, - MenuItem, - Pagination, - Paper, - Select, - Table, - TableBody, - TableCell, - TableContainer, - TableHead, - TableRow, - TextField, - Typography, - useTheme, - InputAdornment} from "@mui/material"; -import {ArrowDownward, ArrowUpward, Clear, Error, FilterList, Refresh, Search, UnfoldMore} from "@mui/icons-material"; + Box, + Button, + Card, + CardContent, + Chip, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + InputAdornment, + Menu, + MenuItem, + Paper, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + TextField, + Typography, + useTheme, +} from "@mui/material"; +import { + Search, + Clear, + Refresh, + FilterList, + ArrowDownward, + ArrowUpward, + UnfoldMore, +} from "@mui/icons-material"; import axios from "axios"; -import {fetchAllNamespaces, fetchAllQueues} from "./utils"; +import { fetchAllNamespaces, fetchAllQueues } from "./utils"; + +const brandColor = "#eb301a"; +const brandColorLight = "#FDF5F3"; // Light background shade +const brandColorHover = "#F7694A"; // Slightly lighter for hover states + const Jobs = () => { const [jobs, setJobs] = useState([]); @@ -210,299 +224,295 @@ const Jobs = () => { }, []); return ( - - {error && ( - - {error} - - )} - - Volcano Jobs Status - + + - - - fetchJobs()} - sx={{padding: "4px"}} - > - - - - ), - endAdornment: searchText && ( - - - - ), - }} - /> - - + + Volcano Jobs Dashboard + + + + + {error && ( + + {error} + + )} + + + setSearchText(e.target.value)} + sx={{ + width: 300, + "& .MuiOutlinedInput-root": { + "&:hover fieldset": { + borderColor: brandColor, + }, + "&.Mui-focused fieldset": { + borderColor: brandColor, + }, + }, + }} + InputProps={{ + startAdornment: ( + + + + ), + endAdornment: searchText && ( + + setSearchText("")}> + + + + ), + }} + /> + - - + + + sx={{ + maxHeight: "calc(100vh - 300px)", + borderRadius: 2, + boxShadow: 1, + }} + > - - - - Name - - - Namespace - - setAnchorEl((prev) => ({...prev, namespace: null}))} - > - {allNamespaces.map((namespace) => ( - handleFilterClose("namespace", namespace)}> - {namespace} - - ))} - - - - Queue - - setAnchorEl((prev) => ({...prev, queue: null}))} - > - {allQueues.map((queue) => ( - handleFilterClose("queue", queue)} - selected={queue === filters.queue} - > - {queue} - - ))} - - - - Creation Time - - - - Status - - setAnchorEl((prev) => ({...prev, status: null}))} - > - {uniqueStatuses.map((status) => ( - handleFilterClose("status", status)}> - {status} - - ))} - - - - - - {sortedJobs.map((job) => ( - handleJobClick(job)} + + + {["Name", "Namespace", "Queue", "Creation Time", "Status"].map((header, index) => ( + + + {header} + {header !== "Name" && ( + + header === "Creation Time" + ? toggleSortDirection() + : handleFilterClick(header.toLowerCase(), e) + } + > + {header === "Creation Time" ? ( + sortDirection === "desc" ? ( + + ) : sortDirection === "asc" ? ( + + ) : ( + + ) + ) : ( + + )} + + )} + + {header !== "Name" && header !== "Creation Time" && ( + setAnchorEl((prev) => ({ ...prev, [header.toLowerCase()]: null }))} > - {job.metadata.name} - {job.metadata.namespace} - {job.spec.queue || "N/A"} - {new Date(job.metadata.creationTimestamp).toLocaleString()} - - - - - ))} - + {(header === "Namespace" + ? allNamespaces + : header === "Queue" + ? allQueues + : uniqueStatuses + ).map((item) => ( + handleFilterClose(header.toLowerCase(), item)} + > + {item} + + ))} + + )} + + ))} + + + + {sortedJobs.map((job) => ( + handleJobClick(job)} + sx={{ + cursor: "pointer", + "&:hover": { + bgcolor: brandColorLight, + transition: "background-color 0.2s", + }, + }} + > + {job.metadata.name} + {job.metadata.namespace} + {job.spec.queue || "N/A"} + + {new Date(job.metadata.creationTimestamp).toLocaleString()} + + + + + + ))} +
-
- + + - - - - Total Jobs: {totalJobs} - - + + + Total Jobs: {totalJobs} + - - + + + Page {pagination.page} of {Math.ceil(totalJobs / pagination.rowsPerPage)} + + + +
+ + + + + - Job YAML - {selectedJobName} - - -
-                    
-                
-                
-                    
-                        
-                    
-                
-            
+ Job YAML - {selectedJobName} + + +
+            
+            
+              
+            
+          
         
-    );
-};
-
-export default Jobs;
\ No newline at end of file
+      );
+    };
+    
+    export default Jobs;
+    
\ No newline at end of file