Merge pull request #773 from getmaxun/accord-fix
fix: accordion collapses on run completion
This commit is contained in:
@@ -90,6 +90,7 @@
|
|||||||
"runs": "Alle Ausführungen",
|
"runs": "Alle Ausführungen",
|
||||||
"runStatus": "Status",
|
"runStatus": "Status",
|
||||||
"runName": "Name",
|
"runName": "Name",
|
||||||
|
"name": "Name",
|
||||||
"startedAt": "Gestartet am",
|
"startedAt": "Gestartet am",
|
||||||
"finishedAt": "Beendet am",
|
"finishedAt": "Beendet am",
|
||||||
"delete": "Löschen",
|
"delete": "Löschen",
|
||||||
|
|||||||
@@ -90,6 +90,7 @@
|
|||||||
"runs":"All Runs",
|
"runs":"All Runs",
|
||||||
"runStatus":"Status",
|
"runStatus":"Status",
|
||||||
"runName":"Name",
|
"runName":"Name",
|
||||||
|
"name":"Name",
|
||||||
"startedAt":"Started At",
|
"startedAt":"Started At",
|
||||||
"finishedAt":"Finished At",
|
"finishedAt":"Finished At",
|
||||||
"delete":"Delete",
|
"delete":"Delete",
|
||||||
|
|||||||
@@ -90,6 +90,7 @@
|
|||||||
"runs": "Todas las ejecuciones",
|
"runs": "Todas las ejecuciones",
|
||||||
"runStatus": "Estado",
|
"runStatus": "Estado",
|
||||||
"runName": "Nombre",
|
"runName": "Nombre",
|
||||||
|
"name": "Nombre",
|
||||||
"startedAt": "Iniciado el",
|
"startedAt": "Iniciado el",
|
||||||
"finishedAt": "Finalizado el",
|
"finishedAt": "Finalizado el",
|
||||||
"delete": "Eliminar",
|
"delete": "Eliminar",
|
||||||
|
|||||||
@@ -90,6 +90,7 @@
|
|||||||
"runs": "すべての実行",
|
"runs": "すべての実行",
|
||||||
"runStatus": "ステータス",
|
"runStatus": "ステータス",
|
||||||
"runName": "名前",
|
"runName": "名前",
|
||||||
|
"name": "名前",
|
||||||
"startedAt": "開始日時",
|
"startedAt": "開始日時",
|
||||||
"finishedAt": "終了日時",
|
"finishedAt": "終了日時",
|
||||||
"delete": "削除",
|
"delete": "削除",
|
||||||
|
|||||||
@@ -90,6 +90,7 @@
|
|||||||
"runs": "Tüm Çalıştırmalar",
|
"runs": "Tüm Çalıştırmalar",
|
||||||
"runStatus": "Durum",
|
"runStatus": "Durum",
|
||||||
"runName": "Ad",
|
"runName": "Ad",
|
||||||
|
"name": "Ad",
|
||||||
"startedAt": "Başlama",
|
"startedAt": "Başlama",
|
||||||
"finishedAt": "Bitiş",
|
"finishedAt": "Bitiş",
|
||||||
"delete": "Sil",
|
"delete": "Sil",
|
||||||
|
|||||||
@@ -90,6 +90,7 @@
|
|||||||
"runs": "所有运行记录",
|
"runs": "所有运行记录",
|
||||||
"runStatus": "状态",
|
"runStatus": "状态",
|
||||||
"runName": "名称",
|
"runName": "名称",
|
||||||
|
"name": "名称",
|
||||||
"startedAt": "开始时间",
|
"startedAt": "开始时间",
|
||||||
"finishedAt": "结束时间",
|
"finishedAt": "结束时间",
|
||||||
"delete": "删除",
|
"delete": "删除",
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import {
|
|||||||
Menu,
|
Menu,
|
||||||
ListItemIcon,
|
ListItemIcon,
|
||||||
ListItemText,
|
ListItemText,
|
||||||
|
CircularProgress,
|
||||||
FormControlLabel,
|
FormControlLabel,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
CircularProgress,
|
CircularProgress,
|
||||||
@@ -155,7 +156,7 @@ export const RecordingsTable = ({
|
|||||||
const [searchTerm, setSearchTerm] = React.useState('');
|
const [searchTerm, setSearchTerm] = React.useState('');
|
||||||
const [isWarningModalOpen, setWarningModalOpen] = React.useState(false);
|
const [isWarningModalOpen, setWarningModalOpen] = React.useState(false);
|
||||||
const [activeBrowserId, setActiveBrowserId] = React.useState('');
|
const [activeBrowserId, setActiveBrowserId] = React.useState('');
|
||||||
const [isLoading, setIsLoading] = React.useState(true);
|
const [isFetching, setIsFetching] = React.useState(true);
|
||||||
|
|
||||||
const columns = useMemo(() => [
|
const columns = useMemo(() => [
|
||||||
{ id: 'interpret', label: t('recordingtable.run'), minWidth: 80 },
|
{ id: 'interpret', label: t('recordingtable.run'), minWidth: 80 },
|
||||||
@@ -273,7 +274,7 @@ export const RecordingsTable = ({
|
|||||||
console.error('Error fetching recordings:', error);
|
console.error('Error fetching recordings:', error);
|
||||||
notify('error', t('recordingtable.notifications.fetch_error'));
|
notify('error', t('recordingtable.notifications.fetch_error'));
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsFetching(false);
|
||||||
}
|
}
|
||||||
}, [setRecordings, notify, t]);
|
}, [setRecordings, notify, t]);
|
||||||
|
|
||||||
@@ -516,7 +517,7 @@ export const RecordingsTable = ({
|
|||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{isLoading ? (
|
{isFetching ? (
|
||||||
<Box
|
<Box
|
||||||
display="flex"
|
display="flex"
|
||||||
justifyContent="center"
|
justifyContent="center"
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import { GenericModal } from "../ui/GenericModal";
|
|||||||
import { modalStyle } from "../recorder/AddWhereCondModal";
|
import { modalStyle } from "../recorder/AddWhereCondModal";
|
||||||
import { getUserById } from "../../api/auth";
|
import { getUserById } from "../../api/auth";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useNavigate } from "react-router-dom";
|
|
||||||
|
|
||||||
interface RunTypeChipProps {
|
interface RunTypeChipProps {
|
||||||
runByUserId?: string;
|
runByUserId?: string;
|
||||||
@@ -22,9 +21,9 @@ interface RunTypeChipProps {
|
|||||||
const RunTypeChip: React.FC<RunTypeChipProps> = ({ runByUserId, runByScheduledId, runByAPI }) => {
|
const RunTypeChip: React.FC<RunTypeChipProps> = ({ runByUserId, runByScheduledId, runByAPI }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
if (runByUserId) return <Chip label={t('runs_table.run_type_chips.manual_run')} color="primary" variant="outlined" />;
|
|
||||||
if (runByScheduledId) return <Chip label={t('runs_table.run_type_chips.scheduled_run')} color="primary" variant="outlined" />;
|
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 (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" />;
|
return <Chip label={t('runs_table.run_type_chips.unknown_run_type')} color="primary" variant="outlined" />;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -32,21 +31,20 @@ interface CollapsibleRowProps {
|
|||||||
row: Data;
|
row: Data;
|
||||||
handleDelete: () => void;
|
handleDelete: () => void;
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
|
onToggleExpanded: (shouldExpand: boolean) => void;
|
||||||
currentLog: string;
|
currentLog: string;
|
||||||
abortRunHandler: (runId: string, robotName: string, browserId: string) => void;
|
abortRunHandler: (runId: string, robotName: string, browserId: string) => void;
|
||||||
runningRecordingName: string;
|
runningRecordingName: string;
|
||||||
urlRunId: string | null;
|
urlRunId: string | null;
|
||||||
}
|
}
|
||||||
export const CollapsibleRow = ({ row, handleDelete, isOpen, currentLog, abortRunHandler, runningRecordingName, urlRunId }: CollapsibleRowProps) => {
|
export const CollapsibleRow = ({ row, handleDelete, isOpen, onToggleExpanded, currentLog, abortRunHandler, runningRecordingName, urlRunId }: CollapsibleRowProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigate = useNavigate();
|
|
||||||
const [open, setOpen] = useState(isOpen);
|
|
||||||
const [openSettingsModal, setOpenSettingsModal] = useState(false);
|
const [openSettingsModal, setOpenSettingsModal] = useState(false);
|
||||||
const [userEmail, setUserEmail] = useState<string | null>(null);
|
const [userEmail, setUserEmail] = useState<string | null>(null);
|
||||||
const runByLabel = row.runByUserId
|
const runByLabel = row.runByScheduleId
|
||||||
? `${userEmail}`
|
? `${row.runByScheduleId}`
|
||||||
: row.runByScheduleId
|
: row.runByUserId
|
||||||
? `${row.runByScheduleId}`
|
? `${userEmail}`
|
||||||
: row.runByAPI
|
: row.runByAPI
|
||||||
? 'API'
|
? 'API'
|
||||||
: 'Unknown';
|
: 'Unknown';
|
||||||
@@ -63,18 +61,9 @@ export const CollapsibleRow = ({ row, handleDelete, isOpen, currentLog, abortRun
|
|||||||
abortRunHandler(row.runId, row.name, row.browserId);
|
abortRunHandler(row.runId, row.name, row.browserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setOpen(urlRunId === row.runId || isOpen);
|
|
||||||
}, [urlRunId, row.runId, isOpen]);
|
|
||||||
|
|
||||||
const handleRowExpand = () => {
|
const handleRowExpand = () => {
|
||||||
const newOpen = !open;
|
const newOpen = !isOpen;
|
||||||
setOpen(newOpen);
|
onToggleExpanded(newOpen);
|
||||||
navigate(
|
|
||||||
newOpen
|
|
||||||
? `/runs/${row.robotMetaId}/run/${row.runId}`
|
|
||||||
: `/runs/${row.robotMetaId}`
|
|
||||||
);
|
|
||||||
//scrollToLogBottom();
|
//scrollToLogBottom();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -103,7 +92,7 @@ export const CollapsibleRow = ({ row, handleDelete, isOpen, currentLog, abortRun
|
|||||||
size="small"
|
size="small"
|
||||||
onClick={handleRowExpand}
|
onClick={handleRowExpand}
|
||||||
>
|
>
|
||||||
{open ? <KeyboardArrowUp /> : <KeyboardArrowDown />}
|
{isOpen ? <KeyboardArrowUp /> : <KeyboardArrowDown />}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
{columns.map((column) => {
|
{columns.map((column) => {
|
||||||
@@ -165,10 +154,10 @@ export const CollapsibleRow = ({ row, handleDelete, isOpen, currentLog, abortRun
|
|||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
label={
|
label={
|
||||||
row.runByUserId
|
row.runByScheduleId
|
||||||
? t('runs_table.run_settings_modal.labels.run_by_user')
|
? t('runs_table.run_settings_modal.labels.run_by_schedule')
|
||||||
: row.runByScheduleId
|
: row.runByUserId
|
||||||
? t('runs_table.run_settings_modal.labels.run_by_schedule')
|
? t('runs_table.run_settings_modal.labels.run_by_user')
|
||||||
: t('runs_table.run_settings_modal.labels.run_by_api')
|
: t('runs_table.run_settings_modal.labels.run_by_api')
|
||||||
}
|
}
|
||||||
value={runByLabel}
|
value={runByLabel}
|
||||||
@@ -197,7 +186,7 @@ export const CollapsibleRow = ({ row, handleDelete, isOpen, currentLog, abortRun
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={6}>
|
<TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={6}>
|
||||||
<Collapse in={open} timeout="auto" unmountOnExit>
|
<Collapse in={isOpen} timeout="auto" unmountOnExit>
|
||||||
<RunContent row={row} abortRunHandler={handleAbort} currentLog={currentLog}
|
<RunContent row={row} abortRunHandler={handleAbort} currentLog={currentLog}
|
||||||
logEndRef={logEndRef} interpretationInProgress={runningRecordingName === row.name} />
|
logEndRef={logEndRef} interpretationInProgress={runningRecordingName === row.name} />
|
||||||
</Collapse>
|
</Collapse>
|
||||||
|
|||||||
@@ -134,16 +134,83 @@ export const RunsTable: React.FC<RunsTableProps> = ({
|
|||||||
|
|
||||||
const [rows, setRows] = useState<Data[]>([]);
|
const [rows, setRows] = useState<Data[]>([]);
|
||||||
const [searchTerm, setSearchTerm] = useState('');
|
const [searchTerm, setSearchTerm] = useState('');
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isFetching, setIsFetching] = useState(true);
|
||||||
|
|
||||||
const [paginationStates, setPaginationStates] = useState<PaginationState>({});
|
const [paginationStates, setPaginationStates] = useState<PaginationState>({});
|
||||||
|
const [expandedRows, setExpandedRows] = useState<Set<string>>(new Set());
|
||||||
|
const [expandedAccordions, setExpandedAccordions] = useState<Set<string>>(new Set());
|
||||||
|
|
||||||
const { notify, rerenderRuns, setRerenderRuns } = useGlobalInfoStore();
|
const { notify, rerenderRuns, setRerenderRuns } = useGlobalInfoStore();
|
||||||
|
|
||||||
const handleAccordionChange = useCallback((robotMetaId: string, isExpanded: boolean) => {
|
const handleAccordionChange = useCallback((robotMetaId: string, isExpanded: boolean) => {
|
||||||
|
setExpandedAccordions(prev => {
|
||||||
|
const newSet = new Set(prev);
|
||||||
|
if (isExpanded) {
|
||||||
|
newSet.add(robotMetaId);
|
||||||
|
} else {
|
||||||
|
newSet.delete(robotMetaId);
|
||||||
|
}
|
||||||
|
return newSet;
|
||||||
|
});
|
||||||
|
|
||||||
navigate(isExpanded ? `/runs/${robotMetaId}` : '/runs');
|
navigate(isExpanded ? `/runs/${robotMetaId}` : '/runs');
|
||||||
}, [navigate]);
|
}, [navigate]);
|
||||||
|
|
||||||
|
const handleRowExpand = useCallback((runId: string, robotMetaId: string, shouldExpand: boolean) => {
|
||||||
|
setExpandedRows(prev => {
|
||||||
|
const newSet = new Set(prev);
|
||||||
|
if (shouldExpand) {
|
||||||
|
newSet.add(runId);
|
||||||
|
} else {
|
||||||
|
newSet.delete(runId);
|
||||||
|
}
|
||||||
|
return newSet;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update URL navigation
|
||||||
|
navigate(
|
||||||
|
shouldExpand
|
||||||
|
? `/runs/${robotMetaId}/run/${runId}`
|
||||||
|
: `/runs/${robotMetaId}`
|
||||||
|
);
|
||||||
|
}, [navigate]);
|
||||||
|
|
||||||
|
// Sync expandedRows and expandedAccordions with URL params
|
||||||
|
useEffect(() => {
|
||||||
|
if (urlRunId) {
|
||||||
|
setExpandedRows(prev => {
|
||||||
|
const newSet = new Set(prev);
|
||||||
|
newSet.add(urlRunId);
|
||||||
|
return newSet;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (urlRobotMetaId) {
|
||||||
|
setExpandedAccordions(prev => {
|
||||||
|
const newSet = new Set(prev);
|
||||||
|
newSet.add(urlRobotMetaId);
|
||||||
|
return newSet;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [urlRunId, urlRobotMetaId]);
|
||||||
|
|
||||||
|
// Auto-expand currently running robot (but allow manual collapse)
|
||||||
|
useEffect(() => {
|
||||||
|
if (runId && runningRecordingName) {
|
||||||
|
const currentRunningRow = rows.find(row =>
|
||||||
|
row.runId === runId && row.name === runningRecordingName
|
||||||
|
);
|
||||||
|
|
||||||
|
if (currentRunningRow) {
|
||||||
|
setExpandedRows(prev => {
|
||||||
|
const newSet = new Set(prev);
|
||||||
|
newSet.add(currentRunningRow.runId);
|
||||||
|
return newSet;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [runId, runningRecordingName, rows]);
|
||||||
|
|
||||||
const handleAccordionPageChange = useCallback((event: unknown, newPage: number) => {
|
const handleAccordionPageChange = useCallback((event: unknown, newPage: number) => {
|
||||||
setAccordionPage(newPage);
|
setAccordionPage(newPage);
|
||||||
}, []);
|
}, []);
|
||||||
@@ -226,7 +293,7 @@ export const RunsTable: React.FC<RunsTableProps> = ({
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
notify('error', t('runstable.notifications.fetch_error'));
|
notify('error', t('runstable.notifications.fetch_error'));
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsFetching(false);
|
||||||
}
|
}
|
||||||
}, [notify, t]);
|
}, [notify, t]);
|
||||||
|
|
||||||
@@ -234,7 +301,7 @@ export const RunsTable: React.FC<RunsTableProps> = ({
|
|||||||
let mounted = true;
|
let mounted = true;
|
||||||
|
|
||||||
if (rows.length === 0 || rerenderRuns) {
|
if (rows.length === 0 || rerenderRuns) {
|
||||||
setIsLoading(true);
|
setIsFetching(true);
|
||||||
fetchRuns().then(() => {
|
fetchRuns().then(() => {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setRerenderRuns(false);
|
setRerenderRuns(false);
|
||||||
@@ -330,14 +397,15 @@ export const RunsTable: React.FC<RunsTableProps> = ({
|
|||||||
key={`row-${row.id}`}
|
key={`row-${row.id}`}
|
||||||
row={row}
|
row={row}
|
||||||
handleDelete={handleDelete}
|
handleDelete={handleDelete}
|
||||||
isOpen={urlRunId === row.runId || (runId === row.runId && runningRecordingName === row.name)}
|
isOpen={expandedRows.has(row.runId)}
|
||||||
|
onToggleExpanded={(shouldExpand) => handleRowExpand(row.runId, row.robotMetaId, shouldExpand)}
|
||||||
currentLog={currentInterpretationLog}
|
currentLog={currentInterpretationLog}
|
||||||
abortRunHandler={abortRunHandler}
|
abortRunHandler={abortRunHandler}
|
||||||
runningRecordingName={runningRecordingName}
|
runningRecordingName={runningRecordingName}
|
||||||
urlRunId={urlRunId}
|
urlRunId={urlRunId}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
}, [paginationStates, runId, runningRecordingName, currentInterpretationLog, abortRunHandler, handleDelete, accordionSortConfigs]);
|
}, [getPaginationState, accordionSortConfigs, expandedRows, handleRowExpand, handleDelete, currentInterpretationLog, abortRunHandler, runningRecordingName, urlRunId]);
|
||||||
|
|
||||||
const renderSortIcon = useCallback((column: Column, robotMetaId: string) => {
|
const renderSortIcon = useCallback((column: Column, robotMetaId: string) => {
|
||||||
const sortConfig = accordionSortConfigs[robotMetaId];
|
const sortConfig = accordionSortConfigs[robotMetaId];
|
||||||
@@ -382,7 +450,7 @@ export const RunsTable: React.FC<RunsTableProps> = ({
|
|||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{isLoading? (
|
{isFetching ? (
|
||||||
<Box
|
<Box
|
||||||
display="flex"
|
display="flex"
|
||||||
justifyContent="center"
|
justifyContent="center"
|
||||||
@@ -427,11 +495,12 @@ export const RunsTable: React.FC<RunsTableProps> = ({
|
|||||||
.map(([robotMetaId, data]) => (
|
.map(([robotMetaId, data]) => (
|
||||||
<Accordion
|
<Accordion
|
||||||
key={robotMetaId}
|
key={robotMetaId}
|
||||||
|
expanded={expandedAccordions.has(robotMetaId)}
|
||||||
onChange={(event, isExpanded) => handleAccordionChange(robotMetaId, isExpanded)}
|
onChange={(event, isExpanded) => handleAccordionChange(robotMetaId, isExpanded)}
|
||||||
TransitionProps={{ unmountOnExit: true }} // Optimize accordion rendering
|
TransitionProps={{ unmountOnExit: true }} // Optimize accordion rendering
|
||||||
>
|
>
|
||||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||||
<Typography variant="h6">{data[0].name}</Typography>
|
<Typography variant="h6">{data[data.length - 1].name}</Typography>
|
||||||
</AccordionSummary>
|
</AccordionSummary>
|
||||||
<AccordionDetails>
|
<AccordionDetails>
|
||||||
<Table stickyHeader aria-label="sticky table">
|
<Table stickyHeader aria-label="sticky table">
|
||||||
|
|||||||
Reference in New Issue
Block a user