Files
parcer/src/components/run/ColapsibleRow.tsx

233 lines
9.8 KiB
TypeScript
Raw Normal View History

2024-06-24 22:32:34 +05:30
import { useEffect, useRef, useState } from "react";
import * as React from "react";
import TableRow from "@mui/material/TableRow";
import TableCell from "@mui/material/TableCell";
2024-10-28 20:41:16 +05:30
import { Box, Collapse, IconButton, Typography, Chip, TextField } from "@mui/material";
import { Button } from "@mui/material";
2024-10-28 20:41:16 +05:30
import { DeleteForever, KeyboardArrowDown, KeyboardArrowUp, Settings } from "@mui/icons-material";
2024-06-24 22:32:34 +05:30
import { deleteRunFromStorage } from "../../api/storage";
2025-01-09 20:03:34 +05:30
import { columns, Data } from "./RunsTable";
import { RunContent } from "./RunContent";
2025-01-09 19:49:20 +05:30
import { GenericModal } from "../ui/GenericModal";
2025-01-09 20:09:46 +05:30
import { modalStyle } from "../recorder/AddWhereCondModal";
2024-10-28 21:18:33 +05:30
import { getUserById } from "../../api/auth";
import { useTranslation } from "react-i18next";
import { useTheme } from "@mui/material/styles";
2024-10-28 20:41:16 +05:30
interface RunTypeChipProps {
runByUserId?: string;
runByScheduledId?: string;
runByAPI: boolean;
}
const RunTypeChip: React.FC<RunTypeChipProps> = ({ runByUserId, runByScheduledId, runByAPI }) => {
const { t } = useTranslation();
if (runByScheduledId) return <Chip label={t('runs_table.run_type_chips.scheduled_run')} color="primary" variant="outlined" />;
if (runByAPI) return <Chip label={t('runs_table.run_type_chips.api')} color="primary" variant="outlined" />;
if (runByUserId) return <Chip label={t('runs_table.run_type_chips.manual_run')} color="primary" variant="outlined" />;
return <Chip label={t('runs_table.run_type_chips.unknown_run_type')} color="primary" variant="outlined" />;
2024-10-28 20:41:16 +05:30
};
2024-06-24 22:32:34 +05:30
interface CollapsibleRowProps {
row: Data;
handleDelete: () => void;
isOpen: boolean;
onToggleExpanded: (shouldExpand: boolean) => void;
2024-06-24 22:32:34 +05:30
currentLog: string;
2025-06-12 11:17:27 +05:30
abortRunHandler: (runId: string, robotName: string, browserId: string) => void;
2024-06-24 22:32:34 +05:30
runningRecordingName: string;
urlRunId: string | null;
2024-06-24 22:32:34 +05:30
}
export const CollapsibleRow = ({ row, handleDelete, isOpen, onToggleExpanded, currentLog, abortRunHandler, runningRecordingName, urlRunId }: CollapsibleRowProps) => {
const { t } = useTranslation();
const theme = useTheme();
const [isDeleteOpen, setDeleteOpen] = useState(false);
2024-10-28 20:41:16 +05:30
const [openSettingsModal, setOpenSettingsModal] = useState(false);
2024-10-28 21:18:33 +05:30
const [userEmail, setUserEmail] = useState<string | null>(null);
const runByLabel = row.runByScheduleId
? `${row.runByScheduleId}`
: row.runByUserId
? `${userEmail}`
2024-10-28 20:41:34 +05:30
: row.runByAPI
? 'API'
: 'Unknown';
2025-01-10 12:27:47 +05:30
2024-10-19 03:55:36 +05:30
const logEndRef = useRef<HTMLDivElement | null>(null);
2024-06-24 22:32:34 +05:30
const scrollToLogBottom = () => {
if (logEndRef.current) {
logEndRef.current.scrollIntoView({ behavior: "smooth" });
}
}
const handleAbort = () => {
2025-06-12 11:17:27 +05:30
abortRunHandler(row.runId, row.name, row.browserId);
2024-06-24 22:32:34 +05:30
}
2025-01-10 12:27:47 +05:30
const handleRowExpand = () => {
const newOpen = !isOpen;
onToggleExpanded(newOpen);
2025-01-10 12:33:39 +05:30
//scrollToLogBottom();
2025-01-10 12:27:47 +05:30
};
2025-01-10 12:33:39 +05:30
// useEffect(() => {
// scrollToLogBottom();
// }, [currentLog])
2024-06-24 22:32:34 +05:30
2024-10-28 21:18:33 +05:30
useEffect(() => {
const fetchUserEmail = async () => {
if (row.runByUserId) {
const userData = await getUserById(row.runByUserId);
if (userData && userData.user) {
setUserEmail(userData.user.email);
}
}
};
fetchUserEmail();
}, [row.runByUserId]);
const handleConfirmDelete = async () => {
try {
const res = await deleteRunFromStorage(`${row.runId}`);
if (res) {
handleDelete();
}
} finally {
setDeleteOpen(false);
}
};
2024-06-24 22:32:34 +05:30
return (
<React.Fragment>
<TableRow sx={{ '& > *': { borderBottom: 'unset' } }} hover role="checkbox" tabIndex={-1} key={row.id}>
<TableCell>
<IconButton
aria-label="expand row"
size="small"
2025-01-10 12:27:47 +05:30
onClick={handleRowExpand}
2024-06-24 22:32:34 +05:30
>
{isOpen ? <KeyboardArrowUp /> : <KeyboardArrowDown />}
2024-06-24 22:32:34 +05:30
</IconButton>
</TableCell>
{columns.map((column) => {
// @ts-ignore
2024-10-19 03:55:36 +05:30
const value: any = row[column.id];
2024-06-24 22:32:34 +05:30
if (value !== undefined) {
return (
<TableCell key={column.id} align={column.align}>
2024-10-28 20:41:16 +05:30
{value}
2024-06-24 22:32:34 +05:30
</TableCell>
);
} else {
switch (column.id) {
2024-10-28 20:41:16 +05:30
case 'runStatus':
2025-01-09 17:17:48 +05:30
return (
2024-10-28 20:14:02 +05:30
<TableCell key={column.id} align={column.align}>
{row.status === 'success' && <Chip label={t('runs_table.run_status_chips.success')} color="success" variant="outlined" />}
{row.status === 'running' && <Chip label={t('runs_table.run_status_chips.running')} color="warning" variant="outlined" />}
{row.status === 'scheduled' && <Chip label={t('runs_table.run_status_chips.scheduled')} variant="outlined" />}
2025-03-12 19:31:19 +05:30
{row.status === 'queued' && <Chip label={t('runs_table.run_status_chips.queued')} variant="outlined" />}
{row.status === 'failed' && <Chip label={t('runs_table.run_status_chips.failed')} color="error" variant="outlined" />}
2025-04-08 19:01:21 +05:30
{row.status === 'aborted' && <Chip label={t('runs_table.run_status_chips.aborted')} color="error" variant="outlined" />}
2024-10-28 20:14:02 +05:30
</TableCell>
)
2024-06-24 22:32:34 +05:30
case 'delete':
return (
<TableCell key={column.id} align={column.align}>
<IconButton aria-label="delete" size="small" onClick={() => setDeleteOpen(true)}>
2024-10-19 03:55:36 +05:30
<DeleteForever />
2024-06-24 22:32:34 +05:30
</IconButton>
</TableCell>
);
2024-10-28 20:41:16 +05:30
case 'settings':
return (
<TableCell key={column.id} align={column.align}>
<IconButton aria-label="settings" size="small" onClick={() => setOpenSettingsModal(true)}>
<Settings />
</IconButton>
<GenericModal
isOpen={openSettingsModal}
onClose={() => setOpenSettingsModal(false)}
modalStyle={modalStyle}
>
<>
<Typography variant="h5" style={{ marginBottom: '20px' }}>
{t('runs_table.run_settings_modal.title')}
</Typography>
2024-10-28 20:41:16 +05:30
<Box style={{ display: 'flex', flexDirection: 'column', gap: '20px' }}>
2024-10-28 21:18:49 +05:30
<TextField
label={t('runs_table.run_settings_modal.labels.run_id')}
2024-10-28 20:44:16 +05:30
value={row.runId}
InputProps={{ readOnly: true }}
/>
2024-10-28 20:41:16 +05:30
<TextField
label={
row.runByScheduleId
? t('runs_table.run_settings_modal.labels.run_by_schedule')
: row.runByUserId
? t('runs_table.run_settings_modal.labels.run_by_user')
2025-01-09 17:17:48 +05:30
: t('runs_table.run_settings_modal.labels.run_by_api')
}
2024-10-28 20:41:16 +05:30
value={runByLabel}
InputProps={{ readOnly: true }}
/>
<Box style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
<Typography variant="body1">
{t('runs_table.run_settings_modal.labels.run_type')}:
</Typography>
2025-01-09 17:17:48 +05:30
<RunTypeChip
runByUserId={row.runByUserId}
runByScheduledId={row.runByScheduleId}
runByAPI={row.runByAPI ?? false}
/>
2024-10-28 20:41:16 +05:30
</Box>
</Box>
</>
</GenericModal>
</TableCell>
)
2024-06-24 22:32:34 +05:30
default:
return null;
}
}
})}
</TableRow>
<TableRow>
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={6}>
<Collapse in={isOpen} timeout="auto" unmountOnExit>
2024-06-24 22:32:34 +05:30
<RunContent row={row} abortRunHandler={handleAbort} currentLog={currentLog}
2024-10-19 03:55:36 +05:30
logEndRef={logEndRef} interpretationInProgress={runningRecordingName === row.name} />
2024-06-24 22:32:34 +05:30
</Collapse>
</TableCell>
</TableRow>
<GenericModal isOpen={isDeleteOpen} onClose={() => setDeleteOpen(false)} modalStyle={{ ...modalStyle, padding: 0, backgroundColor: 'transparent', width: 'auto', maxWidth: '520px' }}>
<Box sx={{ padding: theme.spacing(3), borderRadius: 2, backgroundColor: theme.palette.mode === 'dark' ? theme.palette.grey[900] : theme.palette.background.paper, color: theme.palette.text.primary, width: { xs: '90vw', sm: '460px', md: '420px' }, maxWidth: '90vw', boxSizing: 'border-box', mx: 'auto' }}>
<Typography variant="h6" sx={{ fontWeight: 600 }}>
{t('runs_table.delete_confirm.title', {
name: row.name,
defaultValue: 'Delete run "{{name}}"?'
})}
</Typography>
<Typography variant="body1" sx={{ mb: 2 }}>
{t('runs_table.delete_confirm.message', {
name: row.name,
defaultValue: 'Are you sure you want to delete the run "{{name}}"?'
})}
</Typography>
<Box display="flex" justifyContent="flex-end" gap={1}>
<Button onClick={() => setDeleteOpen(false)} variant="outlined">
{t('common.cancel', { defaultValue: 'Cancel' })}
</Button>
<Button
onClick={handleConfirmDelete} variant="contained" color="primary" sx={{ '&:hover': { backgroundColor: theme.palette.primary.dark } }}>
{t('common.delete', { defaultValue: 'Delete' })}
</Button>
</Box>
</Box>
</GenericModal>
2024-06-24 22:32:34 +05:30
</React.Fragment>
);
}