Merge pull request #358 from getmaxun/improve-ui

feat(ui): runs & robots loader
This commit is contained in:
Karishma Shukla
2025-01-18 19:02:24 +05:30
committed by GitHub
2 changed files with 148 additions and 138 deletions

View File

@@ -11,7 +11,7 @@ import TableRow from '@mui/material/TableRow';
import { useEffect } from "react"; import { useEffect } from "react";
import { WorkflowFile } from "maxun-core"; import { WorkflowFile } from "maxun-core";
import SearchIcon from '@mui/icons-material/Search'; import SearchIcon from '@mui/icons-material/Search';
import { IconButton, Button, Box, Typography, TextField, MenuItem, Menu, ListItemIcon, ListItemText } from "@mui/material"; import { IconButton, Button, Box, Typography, TextField, MenuItem, Menu, ListItemIcon, ListItemText, CircularProgress } from "@mui/material";
import { Schedule, DeleteForever, Edit, PlayCircle, Settings, Power, ContentCopy, MoreHoriz } from "@mui/icons-material"; import { Schedule, DeleteForever, Edit, PlayCircle, Settings, Power, ContentCopy, MoreHoriz } from "@mui/icons-material";
import { useGlobalInfoStore } from "../../context/globalInfo"; import { useGlobalInfoStore } from "../../context/globalInfo";
import { checkRunsForRecording, deleteRecordingFromStorage, getStoredRecordings } from "../../api/storage"; import { checkRunsForRecording, deleteRecordingFromStorage, getStoredRecordings } from "../../api/storage";
@@ -200,101 +200,107 @@ export const RecordingsTable = ({ handleEditRecording, handleRunRecording, handl
</IconButton> </IconButton>
</Box> </Box>
</Box> </Box>
<TableContainer component={Paper} sx={{ width: '100%', overflow: 'hidden', marginTop: '15px' }}> {rows.length === 0 ? (
<Table stickyHeader aria-label="sticky table"> <Box display="flex" justifyContent="center" alignItems="center" height="50%">
<TableHead> <CircularProgress />
<TableRow> </Box>
{columns.map((column) => ( ) : (
<TableCell <TableContainer component={Paper} sx={{ width: '100%', overflow: 'hidden', marginTop: '15px' }}>
key={column.id} <Table stickyHeader aria-label="sticky table">
align={column.align} <TableHead>
style={{ minWidth: column.minWidth }} <TableRow>
> {columns.map((column) => (
{column.label} <TableCell
</TableCell> key={column.id}
))} align={column.align}
</TableRow> style={{ minWidth: column.minWidth }}
</TableHead> >
<TableBody> {column.label}
{filteredRows.length !== 0 ? filteredRows </TableCell>
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) ))}
.map((row) => { </TableRow>
return ( </TableHead>
<TableRow hover role="checkbox" tabIndex={-1} key={row.id}> <TableBody>
{columns.map((column) => { {filteredRows.length !== 0 ? filteredRows
// @ts-ignore .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
const value: any = row[column.id]; .map((row) => {
if (value !== undefined) { return (
return ( <TableRow hover role="checkbox" tabIndex={-1} key={row.id}>
<TableCell key={column.id} align={column.align}> {columns.map((column) => {
{value} // @ts-ignore
</TableCell> const value: any = row[column.id];
); if (value !== undefined) {
} else { return (
switch (column.id) { <TableCell key={column.id} align={column.align}>
case 'interpret': {value}
return ( </TableCell>
<TableCell key={column.id} align={column.align}> );
<InterpretButton handleInterpret={() => handleRunRecording(row.id, row.name, row.params || [])} /> } else {
</TableCell> switch (column.id) {
); case 'interpret':
case 'schedule': return (
return ( <TableCell key={column.id} align={column.align}>
<TableCell key={column.id} align={column.align}> <InterpretButton handleInterpret={() => handleRunRecording(row.id, row.name, row.params || [])} />
<ScheduleButton handleSchedule={() => handleScheduleRecording(row.id, row.name, row.params || [])} /> </TableCell>
</TableCell> );
); case 'schedule':
case 'integrate': return (
return ( <TableCell key={column.id} align={column.align}>
<TableCell key={column.id} align={column.align}> <ScheduleButton handleSchedule={() => handleScheduleRecording(row.id, row.name, row.params || [])} />
<IntegrateButton handleIntegrate={() => handleIntegrateRecording(row.id, row.name, row.params || [])} /> </TableCell>
</TableCell> );
); case 'integrate':
case 'options': return (
return ( <TableCell key={column.id} align={column.align}>
<TableCell key={column.id} align={column.align}> <IntegrateButton handleIntegrate={() => handleIntegrateRecording(row.id, row.name, row.params || [])} />
<OptionsButton </TableCell>
handleEdit={() => handleEditRobot(row.id, row.name, row.params || [])} );
handleDuplicate={() => { case 'options':
handleDuplicateRobot(row.id, row.name, row.params || []); return (
}} <TableCell key={column.id} align={column.align}>
handleDelete={() => { <OptionsButton
handleEdit={() => handleEditRobot(row.id, row.name, row.params || [])}
handleDuplicate={() => {
handleDuplicateRobot(row.id, row.name, row.params || []);
}}
handleDelete={() => {
checkRunsForRecording(row.id).then((result: boolean) => { checkRunsForRecording(row.id).then((result: boolean) => {
if (result) { if (result) {
notify('warning', t('recordingtable.notifications.delete_warning')); notify('warning', t('recordingtable.notifications.delete_warning'));
} }
}) })
deleteRecordingFromStorage(row.id).then((result: boolean) => { deleteRecordingFromStorage(row.id).then((result: boolean) => {
if (result) { if (result) {
setRows([]); setRows([]);
notify('success', t('recordingtable.notifications.delete_success')); notify('success', t('recordingtable.notifications.delete_success'));
fetchRecordings(); fetchRecordings();
} }
}) })
}} }}
/> />
</TableCell> </TableCell>
); );
case 'settings': case 'settings':
return ( return (
<TableCell key={column.id} align={column.align}> <TableCell key={column.id} align={column.align}>
<SettingsButton handleSettings={() => handleSettingsRecording(row.id, row.name, row.params || [])} /> <SettingsButton handleSettings={() => handleSettingsRecording(row.id, row.name, row.params || [])} />
</TableCell> </TableCell>
); );
default: default:
return null; return null;
}
} }
} })}
})} </TableRow>
</TableRow> );
); })
}) : null}
: null} </TableBody>
</TableBody> </Table>
</Table> </TableContainer>
</TableContainer> )}
<TablePagination <TablePagination
rowsPerPageOptions={[10, 25, 50]} rowsPerPageOptions={[10, 25, 50]}
component="div" component="div"

View File

@@ -9,7 +9,7 @@ import TableContainer from '@mui/material/TableContainer';
import TableHead from '@mui/material/TableHead'; import TableHead from '@mui/material/TableHead';
import TablePagination from '@mui/material/TablePagination'; import TablePagination from '@mui/material/TablePagination';
import TableRow from '@mui/material/TableRow'; import TableRow from '@mui/material/TableRow';
import { Accordion, AccordionSummary, AccordionDetails, Typography, Box, TextField } from '@mui/material'; import { Accordion, AccordionSummary, AccordionDetails, Typography, Box, TextField, CircularProgress } from '@mui/material';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import SearchIcon from '@mui/icons-material/Search'; import SearchIcon from '@mui/icons-material/Search';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
@@ -18,7 +18,6 @@ import { getStoredRuns } from "../../api/storage";
import { RunSettings } from "./RunSettings"; import { RunSettings } from "./RunSettings";
import { CollapsibleRow } from "./ColapsibleRow"; import { CollapsibleRow } from "./ColapsibleRow";
// Export columns before the component
export const columns: readonly Column[] = [ export const columns: readonly Column[] = [
{ id: 'runStatus', label: 'Status', minWidth: 80 }, { id: 'runStatus', label: 'Status', minWidth: 80 },
{ id: 'name', label: 'Name', minWidth: 80 }, { id: 'name', label: 'Name', minWidth: 80 },
@@ -70,7 +69,6 @@ export const RunsTable: React.FC<RunsTableProps> = ({
const { t } = useTranslation(); const { t } = useTranslation();
const navigate = useNavigate(); const navigate = useNavigate();
// Update column labels using translation if needed
const translatedColumns = columns.map(column => ({ const translatedColumns = columns.map(column => ({
...column, ...column,
label: t(`runstable.${column.id}`, column.label) label: t(`runstable.${column.id}`, column.label)
@@ -162,48 +160,54 @@ export const RunsTable: React.FC<RunsTableProps> = ({
sx={{ width: '250px' }} sx={{ width: '250px' }}
/> />
</Box> </Box>
<TableContainer component={Paper} sx={{ width: '100%', overflow: 'hidden' }}> {rows.length === 0 ? (
{Object.entries(groupedRows).map(([id, data]) => ( <Box display="flex" justifyContent="center" alignItems="center" height="50%">
<Accordion key={id} onChange={(event, isExpanded) => handleAccordionChange(id, isExpanded)}> <CircularProgress />
<AccordionSummary expandIcon={<ExpandMoreIcon />}> </Box>
<Typography variant="h6">{data[data.length - 1].name}</Typography> ) : (
</AccordionSummary> <TableContainer component={Paper} sx={{ width: '100%', overflow: 'hidden' }}>
<AccordionDetails> {Object.entries(groupedRows).map(([id, data]) => (
<Table stickyHeader aria-label="sticky table"> <Accordion key={id} onChange={(event, isExpanded) => handleAccordionChange(id, isExpanded)}>
<TableHead> <AccordionSummary expandIcon={<ExpandMoreIcon />}>
<TableRow> <Typography variant="h6">{data[data.length - 1].name}</Typography>
<TableCell /> </AccordionSummary>
{translatedColumns.map((column) => ( <AccordionDetails>
<TableCell <Table stickyHeader aria-label="sticky table">
key={column.id} <TableHead>
align={column.align} <TableRow>
style={{ minWidth: column.minWidth }} <TableCell />
> {translatedColumns.map((column) => (
{column.label} <TableCell
</TableCell> key={column.id}
))} align={column.align}
</TableRow> style={{ minWidth: column.minWidth }}
</TableHead> >
<TableBody> {column.label}
{data </TableCell>
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) ))}
.map((row) => ( </TableRow>
<CollapsibleRow </TableHead>
row={row} <TableBody>
handleDelete={handleDelete} {data
key={`row-${row.id}`} .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
isOpen={runId === row.runId && runningRecordingName === row.name} .map((row) => (
currentLog={currentInterpretationLog} <CollapsibleRow
abortRunHandler={abortRunHandler} row={row}
runningRecordingName={runningRecordingName} handleDelete={handleDelete}
/> key={`row-${row.id}`}
))} isOpen={runId === row.runId && runningRecordingName === row.name}
</TableBody> currentLog={currentInterpretationLog}
</Table> abortRunHandler={abortRunHandler}
</AccordionDetails> runningRecordingName={runningRecordingName}
</Accordion> />
))} ))}
</TableContainer> </TableBody>
</Table>
</AccordionDetails>
</Accordion>
))}
</TableContainer>
)}
<TablePagination <TablePagination
rowsPerPageOptions={[10, 25, 50]} rowsPerPageOptions={[10, 25, 50]}
component="div" component="div"