Merge pull request #336 from getmaxun/routing

feat: routing
This commit is contained in:
Karishma Shukla
2025-01-10 12:37:08 +05:30
committed by GitHub
6 changed files with 143 additions and 183 deletions

View File

@@ -2,6 +2,7 @@ import React from 'react';
import Tabs from '@mui/material/Tabs';
import Tab from '@mui/material/Tab';
import Box from '@mui/material/Box';
import { useNavigate } from 'react-router-dom';
import { Paper, Button, useTheme } from "@mui/material";
import { AutoAwesome, FormatListBulleted, VpnKey, Usb, Article, CloudQueue, Code, } from "@mui/icons-material";
import { apiUrl } from "../../apiConfig";
@@ -13,11 +14,13 @@ interface MainMenuProps {
handleChangeContent: (newValue: string) => void;
}
export const MainMenu = ({ value = 'recordings', handleChangeContent }: MainMenuProps) => {
export const MainMenu = ({ value = 'robots', handleChangeContent }: MainMenuProps) => {
const theme = useTheme();
const { t } = useTranslation();
const navigate = useNavigate();
const handleChange = (event: React.SyntheticEvent, newValue: string) => {
navigate(`/${newValue}`);
handleChangeContent(newValue);
};
@@ -65,7 +68,7 @@ export const MainMenu = ({ value = 'recordings', handleChangeContent }: MainMenu
textAlign: 'left',
fontSize: 'medium',
}}
value="recordings"
value="robots"
label={t('mainmenu.recordings')}
icon={<AutoAwesome />}
iconPosition="start"

View File

@@ -1,12 +1,13 @@
import React, { useState } from 'react';
import React, { useState } from "react";
import { RecordingsTable } from "./RecordingsTable";
import { Grid } from "@mui/material";
import { RunSettings, RunSettingsModal } from "../run/RunSettings";
import { ScheduleSettings, ScheduleSettingsModal } from "./ScheduleSettings";
import { IntegrationSettings, IntegrationSettingsModal } from "../integration/IntegrationSettings";
import { RobotSettings, RobotSettingsModal } from "./RobotSettings";
import { RobotEditModal } from './RobotEdit';
import { RobotDuplicationModal } from './RobotDuplicate';
import { RobotEditModal } from "./RobotEdit";
import { RobotDuplicationModal } from "./RobotDuplicate";
import { useNavigate, useLocation, useParams } from "react-router-dom";
interface RecordingsProps {
handleEditRecording: (id: string, fileName: string) => void;
@@ -15,181 +16,115 @@ interface RecordingsProps {
setRecordingInfo: (id: string, name: string) => void;
}
export const Recordings = ({ handleEditRecording, handleRunRecording, setRecordingInfo, handleScheduleRecording }: RecordingsProps) => {
const [runSettingsAreOpen, setRunSettingsAreOpen] = useState(false);
const [scheduleSettingsAreOpen, setScheduleSettingsAreOpen] = useState(false);
const [integrateSettingsAreOpen, setIntegrateSettingsAreOpen] = useState(false);
const [robotSettingsAreOpen, setRobotSettingsAreOpen] = useState(false);
const [robotEditAreOpen, setRobotEditAreOpen] = useState(false);
const [robotDuplicateAreOpen, setRobotDuplicateAreOpen] = useState(false);
export const Recordings = ({
handleEditRecording,
handleRunRecording,
setRecordingInfo,
handleScheduleRecording,
}: RecordingsProps) => {
const navigate = useNavigate();
const location = useLocation();
const { selectedRecordingId } = useParams();
const [params, setParams] = useState<string[]>([]);
const [selectedRecordingId, setSelectedRecordingId] = useState<string>('');
const handleIntegrateRecording = (id: string, settings: IntegrationSettings) => { };
const handleSettingsRecording = (id: string, settings: RobotSettings) => { };
const handleEditRobot = (id: string, settings: RobotSettings) => { };
const handleDuplicateRobot = (id: string, settings: RobotSettings) => { };
const handleSettingsAndIntegrate = (id: string, name: string, params: string[]) => {
if (params.length === 0) {
setIntegrateSettingsAreOpen(true);
setRecordingInfo(id, name);
setSelectedRecordingId(id);
} else {
setParams(params);
setIntegrateSettingsAreOpen(true);
setRecordingInfo(id, name);
setSelectedRecordingId(id);
}
}
const handleSettingsAndRun = (id: string, name: string, params: string[]) => {
if (params.length === 0) {
setRunSettingsAreOpen(true);
setRecordingInfo(id, name);
setSelectedRecordingId(id);
} else {
setParams(params);
setRunSettingsAreOpen(true);
setRecordingInfo(id, name);
setSelectedRecordingId(id);
}
}
const handleSettingsAndSchedule = (id: string, name: string, params: string[]) => {
if (params.length === 0) {
setScheduleSettingsAreOpen(true);
setRecordingInfo(id, name);
setSelectedRecordingId(id);
} else {
setParams(params);
setScheduleSettingsAreOpen(true);
setRecordingInfo(id, name);
setSelectedRecordingId(id);
}
}
const handleRobotSettings = (id: string, name: string, params: string[]) => {
if (params.length === 0) {
setRobotSettingsAreOpen(true);
setRecordingInfo(id, name);
setSelectedRecordingId(id);
} else {
setParams(params);
setRobotSettingsAreOpen(true);
setRecordingInfo(id, name);
setSelectedRecordingId(id);
}
}
const handleEditRobotOption = (id: string, name: string, params: string[]) => {
if (params.length === 0) {
setRobotEditAreOpen(true);
setRecordingInfo(id, name);
setSelectedRecordingId(id);
} else {
setParams(params);
setRobotEditAreOpen(true);
setRecordingInfo(id, name);
setSelectedRecordingId(id);
}
}
const handleDuplicateRobotOption = (id: string, name: string, params: string[]) => {
if (params.length === 0) {
setRobotDuplicateAreOpen(true);
setRecordingInfo(id, name);
setSelectedRecordingId(id);
} else {
setParams(params);
setRobotDuplicateAreOpen(true);
setRecordingInfo(id, name);
setSelectedRecordingId(id);
}
}
const handleNavigate = (path: string, id: string, name: string, params: string[]) => {
setParams(params);
setRecordingInfo(id, name);
navigate(path);
};
const handleClose = () => {
setParams([]);
setRunSettingsAreOpen(false);
setRecordingInfo('', '');
setSelectedRecordingId('');
}
setRecordingInfo("", "");
navigate("/robots"); // Navigate back to the main robots page
};
const handleIntegrateClose = () => {
setParams([]);
setIntegrateSettingsAreOpen(false);
setRecordingInfo('', '');
setSelectedRecordingId('');
}
// Determine which modal to open based on the current route
const getCurrentModal = () => {
const currentPath = location.pathname;
const handleScheduleClose = () => {
setParams([]);
setScheduleSettingsAreOpen(false);
setRecordingInfo('', '');
setSelectedRecordingId('');
}
const handleRobotSettingsClose = () => {
setParams([]);
setRobotSettingsAreOpen(false);
setRecordingInfo('', '');
setSelectedRecordingId('');
}
const handleRobotEditClose = () => {
setParams([]);
setRobotEditAreOpen(false);
setRecordingInfo('', '');
setSelectedRecordingId('');
}
const handleRobotDuplicateClose = () => {
setParams([]);
setRobotDuplicateAreOpen(false);
setRecordingInfo('', '');
setSelectedRecordingId('');
}
if (currentPath.endsWith("/run")) {
return (
<RunSettingsModal
isOpen={true}
handleClose={handleClose}
handleStart={handleRunRecording}
isTask={params.length !== 0}
params={params}
/>
);
} else if (currentPath.endsWith("/schedule")) {
return (
<ScheduleSettingsModal
isOpen={true}
handleClose={handleClose}
handleStart={handleScheduleRecording}
/>
);
} else if (currentPath.endsWith("/integrate")) {
return (
<IntegrationSettingsModal
isOpen={true}
handleClose={handleClose}
handleStart={() => {}}
/>
);
} else if (currentPath.endsWith("/settings")) {
return (
<RobotSettingsModal
isOpen={true}
handleClose={handleClose}
handleStart={() => {}}
/>
);
} else if (currentPath.endsWith("/edit")) {
return (
<RobotEditModal
isOpen={true}
handleClose={handleClose}
handleStart={() => {}}
/>
);
} else if (currentPath.endsWith("/duplicate")) {
return (
<RobotDuplicationModal
isOpen={true}
handleClose={handleClose}
handleStart={() => {}}
/>
);
}
return null;
};
return (
<React.Fragment>
<RunSettingsModal isOpen={runSettingsAreOpen}
handleClose={handleClose}
handleStart={(settings) => handleRunRecording(settings)}
isTask={params.length !== 0}
params={params}
/>
<ScheduleSettingsModal isOpen={scheduleSettingsAreOpen}
handleClose={handleScheduleClose}
handleStart={(settings) => handleScheduleRecording(settings)}
/>
<IntegrationSettingsModal isOpen={integrateSettingsAreOpen}
handleClose={handleIntegrateClose}
handleStart={(settings) => handleIntegrateRecording(selectedRecordingId, settings)}
/>
<RobotSettingsModal isOpen={robotSettingsAreOpen}
handleClose={handleRobotSettingsClose}
handleStart={(settings) => handleSettingsRecording(selectedRecordingId, settings)}
/>
<RobotEditModal isOpen={robotEditAreOpen}
handleClose={handleRobotEditClose}
handleStart={(settings) => handleEditRobot(selectedRecordingId, settings)}
/>
<RobotDuplicationModal isOpen={robotDuplicateAreOpen}
handleClose={handleRobotDuplicateClose}
handleStart={(settings) => handleDuplicateRobot(selectedRecordingId, settings)}
/>
<Grid container direction="column" sx={{ padding: '30px' }}>
{getCurrentModal()}
<Grid container direction="column" sx={{ padding: "30px" }}>
<Grid item xs>
<RecordingsTable
handleEditRecording={handleEditRecording}
handleRunRecording={handleSettingsAndRun}
handleScheduleRecording={handleSettingsAndSchedule}
handleIntegrateRecording={handleSettingsAndIntegrate}
handleSettingsRecording={handleRobotSettings}
handleEditRobot={handleEditRobotOption}
handleDuplicateRobot={handleDuplicateRobotOption}
handleRunRecording={(id, name, params) =>
handleNavigate(`/robots/${id}/run`, id, name, params)
}
handleScheduleRecording={(id, name, params) =>
handleNavigate(`/robots/${id}/schedule`, id, name, params)
}
handleIntegrateRecording={(id, name, params) =>
handleNavigate(`/robots/${id}/integrate`, id, name, params)
}
handleSettingsRecording={(id, name, params) =>
handleNavigate(`/robots/${id}/settings`, id, name, params)
}
handleEditRobot={(id, name, params) =>
handleNavigate(`/robots/${id}/edit`, id, name, params)
}
handleDuplicateRobot={(id, name, params) =>
handleNavigate(`/robots/${id}/duplicate`, id, name, params)
}
/>
</Grid>
</Grid>
</React.Fragment>
);
}
};

View File

@@ -11,6 +11,7 @@ import { GenericModal } from "../ui/GenericModal";
import { modalStyle } from "../recorder/AddWhereCondModal";
import { getUserById } from "../../api/auth";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
interface RunTypeChipProps {
runByUserId?: string;
@@ -37,6 +38,7 @@ interface CollapsibleRowProps {
}
export const CollapsibleRow = ({ row, handleDelete, isOpen, currentLog, abortRunHandler, runningRecordingName }: CollapsibleRowProps) => {
const { t } = useTranslation();
const navigate = useNavigate();
const [open, setOpen] = useState(isOpen);
const [openSettingsModal, setOpenSettingsModal] = useState(false);
const [userEmail, setUserEmail] = useState<string | null>(null);
@@ -47,7 +49,7 @@ export const CollapsibleRow = ({ row, handleDelete, isOpen, currentLog, abortRun
: row.runByAPI
? 'API'
: 'Unknown';
const logEndRef = useRef<HTMLDivElement | null>(null);
const scrollToLogBottom = () => {
@@ -60,9 +62,20 @@ export const CollapsibleRow = ({ row, handleDelete, isOpen, currentLog, abortRun
abortRunHandler();
}
useEffect(() => {
scrollToLogBottom();
}, [currentLog])
const handleRowExpand = () => {
const newOpen = !open;
setOpen(newOpen);
if (newOpen) {
navigate(`/runs/${row.robotMetaId}/run/${row.runId}`);
} else {
navigate(`/runs/${row.robotMetaId}`);
}
//scrollToLogBottom();
};
// useEffect(() => {
// scrollToLogBottom();
// }, [currentLog])
useEffect(() => {
const fetchUserEmail = async () => {
@@ -83,10 +96,7 @@ export const CollapsibleRow = ({ row, handleDelete, isOpen, currentLog, abortRun
<IconButton
aria-label="expand row"
size="small"
onClick={() => {
setOpen(!open);
scrollToLogBottom();
}}
onClick={handleRowExpand}
>
{open ? <KeyboardArrowUp /> : <KeyboardArrowDown />}
</IconButton>

View File

@@ -12,7 +12,7 @@ import TableRow from '@mui/material/TableRow';
import { Accordion, AccordionSummary, AccordionDetails, Typography, Box, TextField } from '@mui/material';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import SearchIcon from '@mui/icons-material/Search';
import { useNavigate } from 'react-router-dom';
import { useGlobalInfoStore } from "../../context/globalInfo";
import { getStoredRuns } from "../../api/storage";
import { RunSettings } from "./RunSettings";
@@ -68,6 +68,7 @@ export const RunsTable: React.FC<RunsTableProps> = ({
runningRecordingName
}) => {
const { t } = useTranslation();
const navigate = useNavigate();
// Update column labels using translation if needed
const translatedColumns = columns.map(column => ({
@@ -82,6 +83,14 @@ export const RunsTable: React.FC<RunsTableProps> = ({
const { notify, rerenderRuns, setRerenderRuns } = useGlobalInfoStore();
const handleAccordionChange = (robotMetaId: string, isExpanded: boolean) => {
if (isExpanded) {
navigate(`/runs/${robotMetaId}`);
} else {
navigate(`/runs`);
}
};
const handleChangePage = (event: unknown, newPage: number) => {
setPage(newPage);
};
@@ -155,7 +164,7 @@ export const RunsTable: React.FC<RunsTableProps> = ({
</Box>
<TableContainer component={Paper} sx={{ width: '100%', overflow: 'hidden' }}>
{Object.entries(groupedRows).map(([id, data]) => (
<Accordion key={id}>
<Accordion key={id} onChange={(event, isExpanded) => handleAccordionChange(id, isExpanded)}>
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
<Typography variant="h6">{data[data.length - 1].name}</Typography>
</AccordionSummary>

View File

@@ -18,6 +18,7 @@ import { apiUrl } from "../apiConfig";
interface MainPageProps {
handleEditRecording: (id: string, fileName: string) => void;
initialContent: string;
}
export interface CreateRunResponse {
@@ -30,9 +31,9 @@ export interface ScheduleRunResponse {
runId: string;
}
export const MainPage = ({ handleEditRecording }: MainPageProps) => {
export const MainPage = ({ handleEditRecording, initialContent }: MainPageProps) => {
const { t } = useTranslation();
const [content, setContent] = React.useState('recordings');
const [content, setContent] = React.useState(initialContent);
const [sockets, setSockets] = React.useState<Socket[]>([]);
const [runningRecordingId, setRunningRecordingId] = React.useState('');
const [runningRecordingName, setRunningRecordingName] = React.useState('');
@@ -123,7 +124,7 @@ export const MainPage = ({ handleEditRecording }: MainPageProps) => {
const DisplayContent = () => {
switch (content) {
case 'recordings':
case 'robots':
return <Recordings
handleEditRecording={handleEditRecording}
handleRunRecording={handleRunRecording}

View File

@@ -11,8 +11,8 @@ import { AlertSnackbar } from "../components/ui/AlertSnackbar";
import Login from './Login';
import Register from './Register';
import UserRoute from '../routes/userRoute';
import { Routes, Route, useNavigate } from 'react-router-dom';
import { AppBar } from '@mui/material';
import { Routes, Route, useNavigate, Navigate } from 'react-router-dom';
import { Runs } from '../components/run/Runs';
export const PageWrapper = () => {
const [open, setOpen] = useState(false);
@@ -51,12 +51,14 @@ export const PageWrapper = () => {
<AuthProvider>
<SocketProvider>
<React.Fragment>
{!browserId && <NavBar recordingName={recordingName} isRecording={!!browserId} />}
<Routes>
<Route element={<UserRoute />}>
<Route path="/" element={<MainPage handleEditRecording={handleEditRecording} />} />
<Route path="/" element={<Navigate to="/robots" replace />} />
<Route path="/robots/*" element={<MainPage handleEditRecording={handleEditRecording} initialContent="robots" />} />
<Route path="/runs/*" element={<MainPage handleEditRecording={handleEditRecording} initialContent="runs" />} />
<Route path="/proxy" element={<MainPage handleEditRecording={handleEditRecording} initialContent="proxy" />} />
<Route path="/apikey" element={<MainPage handleEditRecording={handleEditRecording} initialContent="apikey" />} />
</Route>
<Route element={<UserRoute />}>
<Route path="/recording" element={