Merge pull request #865 from getmaxun/edit-page

feat: main layout revamp
This commit is contained in:
Karishma
2025-11-05 23:18:48 +05:30
committed by GitHub
8 changed files with 152 additions and 107 deletions

View File

@@ -580,7 +580,7 @@
"buttons": { "buttons": {
"stop": "Stop" "stop": "Stop"
}, },
"loading": "Loading data...", "loading": "Extracting data...",
"empty_output": "No output data available", "empty_output": "No output data available",
"captured_data": { "captured_data": {
"title": "Captured Data", "title": "Captured Data",

View File

@@ -26,7 +26,8 @@ const Container = styled(Box)`
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
margin-top: 50px; margin-top: 50px;
margin-left: 50px; margin-left: 70px;
margin-right: 70px;
`; `;
const ApiKeyManager = () => { const ApiKeyManager = () => {
@@ -108,7 +109,7 @@ const ApiKeyManager = () => {
return ( return (
<Container sx={{ alignSelf: 'flex-start' }}> <Container sx={{ alignSelf: 'flex-start' }}>
<Typography variant="body1" sx={{ marginTop: '10px', marginBottom: '40px' }}> <Typography variant="body1" sx={{ marginBottom: '40px' }}>
Start by creating an API key below. Then, Start by creating an API key below. Then,
<a href={`${apiUrl}/api-docs/`} target="_blank" rel="noopener noreferrer" style={{ textDecoration: 'none', marginLeft: '5px', marginRight: '5px' }}> <a href={`${apiUrl}/api-docs/`} target="_blank" rel="noopener noreferrer" style={{ textDecoration: 'none', marginLeft: '5px', marginRight: '5px' }}>
test your API test your API
@@ -139,7 +140,7 @@ const ApiKeyManager = () => {
<TableRow> <TableRow>
<TableCell>{apiKeyName}</TableCell> <TableCell>{apiKeyName}</TableCell>
<TableCell> <TableCell>
<Box sx={{ fontFamily: 'monospace', width: '10ch' }}> <Box sx={{ fontFamily: 'monospace', width: '20ch' }}>
{showKey ? `${apiKey?.substring(0, 10)}...` : '**********'} {showKey ? `${apiKey?.substring(0, 10)}...` : '**********'}
</Box> </Box>
</TableCell> </TableCell>
@@ -174,6 +175,5 @@ const ApiKeyManager = () => {
)} )}
</Container> </Container>
); );
}; }
export default ApiKeyManager; export default ApiKeyManager;

View File

@@ -72,7 +72,7 @@ export const MainMenu = ({ value = 'robots', handleChangeContent }: MainMenuProp
<Paper <Paper
sx={{ sx={{
height: '100%', height: '100%',
width: '250px', width: '230px',
backgroundColor: theme.palette.background.paper, backgroundColor: theme.palette.background.paper,
paddingTop: '0.5rem', paddingTop: '0.5rem',
color: defaultcolor, color: defaultcolor,

View File

@@ -156,19 +156,30 @@ const ProxyForm: React.FC = () => {
}, []); }, []);
return ( return (
<> <Box sx={{
<FormContainer> display: 'flex',
<Typography variant="h6" gutterBottom component="div" style={{ marginTop: '20px' }}> gap: 4,
p: 5,
width: '100%',
maxWidth: '100%',
boxSizing: 'border-box'
}}>
<Box sx={{
flex: 1,
minWidth: 0,
maxWidth: 600
}}>
<Typography variant="h6" gutterBottom component="div">
{t('proxy.title')} {t('proxy.title')}
</Typography> </Typography>
<Tabs value={tabIndex} onChange={handleTabChange} style={{ marginBottom: '10px' }}> <Tabs value={tabIndex} onChange={handleTabChange} sx={{ mb: 2 }}>
<Tab label={t('proxy.tab_standard')} /> <Tab label={t('proxy.tab_standard')} />
</Tabs> </Tabs>
{tabIndex === 0 && ( {tabIndex === 0 && (
isProxyConfigured ? ( isProxyConfigured ? (
<Box sx={{ maxWidth: 600, width: '100%', marginTop: '5px' }}> <Box sx={{ width: '100%', mt: 1 }}>
<TableContainer component={Paper} sx={{ marginBottom: '20px' }}> <TableContainer component={Paper} sx={{ mb: 2 }}>
<Table> <Table>
<TableHead> <TableHead>
<TableRow> <TableRow>
@@ -187,13 +198,13 @@ const ProxyForm: React.FC = () => {
<Button variant="outlined" color="primary" onClick={testProxy}> <Button variant="outlined" color="primary" onClick={testProxy}>
{t('proxy.test_proxy')} {t('proxy.test_proxy')}
</Button> </Button>
<Button variant="outlined" color="error" onClick={removeProxy} sx={{ marginLeft: '10px' }}> <Button variant="outlined" color="error" onClick={removeProxy} sx={{ ml: 1 }}>
{t('proxy.remove_proxy')} {t('proxy.remove_proxy')}
</Button> </Button>
</Box> </Box>
) : ( ) : (
<Box component="form" onSubmit={handleSubmit} sx={{ maxWidth: 500, width: '100%' }}> <Box component="form" onSubmit={handleSubmit} sx={{ width: '100%' }}>
<FormControl> <Box sx={{ mb: 2 }}>
<TextField <TextField
label={t('proxy.server_url')} label={t('proxy.server_url')}
name="server_url" name="server_url"
@@ -208,16 +219,16 @@ const ProxyForm: React.FC = () => {
</span> </span>
} }
/> />
</FormControl> </Box>
<FormControl> <Box sx={{ mb: 2 }}>
<FormControlLabel <FormControlLabel
control={<Switch checked={requiresAuth} onChange={handleAuthToggle} />} control={<Switch checked={requiresAuth} onChange={handleAuthToggle} />}
label={t('proxy.requires_auth')} label={t('proxy.requires_auth')}
/> />
</FormControl> </Box>
{requiresAuth && ( {requiresAuth && (
<> <>
<FormControl> <Box sx={{ mb: 2 }}>
<TextField <TextField
label={t('proxy.username')} label={t('proxy.username')}
name="username" name="username"
@@ -228,8 +239,8 @@ const ProxyForm: React.FC = () => {
error={!!errors.username} error={!!errors.username}
helperText={errors.username || ''} helperText={errors.username || ''}
/> />
</FormControl> </Box>
<FormControl> <Box sx={{ mb: 2 }}>
<TextField <TextField
label={t('proxy.password')} label={t('proxy.password')}
name="password" name="password"
@@ -241,7 +252,7 @@ const ProxyForm: React.FC = () => {
error={!!errors.password} error={!!errors.password}
helperText={errors.password || ''} helperText={errors.password || ''}
/> />
</FormControl> </Box>
</> </>
)} )}
<Button <Button
@@ -255,27 +266,34 @@ const ProxyForm: React.FC = () => {
</Button> </Button>
</Box> </Box>
))} ))}
</FormContainer> </Box>
<Alert severity="info" sx={{ marginTop: '80px', marginLeft: '50px', height: '250px', width: '600px' }}> {/* Instructions Section */}
<AlertTitle>{t('proxy.alert.title')}</AlertTitle> <Box sx={{
<br /> flex: 1,
<b>{t('proxy.alert.right_way')}</b> minWidth: 0,
<br /> maxWidth: 600
{t('proxy.alert.proxy_url')} http://proxy.com:1337 }}>
<br /> <Alert severity="info" sx={{ height: 'auto', minHeight: 250 }}>
{t('proxy.alert.username')} myusername <AlertTitle>{t('proxy.alert.title')}</AlertTitle>
<br /> <br />
{t('proxy.alert.password')} mypassword <b>{t('proxy.alert.right_way')}</b>
<br /> <br />
<br /> {t('proxy.alert.proxy_url')} http://proxy.com:1337
<b>{t('proxy.alert.wrong_way')}</b> <br />
<br /> {t('proxy.alert.username')} myusername
<br />
{t('proxy.alert.proxy_url')} http://myusername:mypassword@proxy.com:1337 {t('proxy.alert.password')} mypassword
</Alert> <br />
</> <br />
<b>{t('proxy.alert.wrong_way')}</b>
<br />
{t('proxy.alert.proxy_url')} http://myusername:mypassword@proxy.com:1337
</Alert>
</Box>
</Box>
); );
}; };
export default ProxyForm; export default ProxyForm;

View File

@@ -64,11 +64,10 @@ export const RobotConfigPage: React.FC<RobotConfigPageProps> = ({
margin: '50px auto', margin: '50px auto',
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
width: '1000px', width: '100%',
height: '100%', height: 'auto',
overflowY: 'auto', // Allow scrolling if content exceeds height boxSizing: 'border-box'
}}> }}>
{/* Header Section - Fixed Position */}
<Box sx={{ <Box sx={{
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
@@ -117,32 +116,29 @@ export const RobotConfigPage: React.FC<RobotConfigPageProps> = ({
</Box> </Box>
<Divider sx={{ mb: 4, flexShrink: 0 }} /> <Divider sx={{ mb: 4, flexShrink: 0 }} />
{/* Content Section */}
<Box sx={{ <Box sx={{
flex: 1, flex: 1,
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',
minHeight: 0, minHeight: 0,
mt: 2, mt: 1.8,
mb: 3, mb: 5,
}}> }}>
{children} {children}
</Box> </Box>
{/* Action Buttons */}
{(showSaveButton || showCancelButton || onBackToSelection) && ( {(showSaveButton || showCancelButton || onBackToSelection) && (
<Box <Box
sx={{ sx={{
display: 'flex', display: 'flex',
justifyContent: onBackToSelection ? 'space-between' : 'flex-start', justifyContent: onBackToSelection ? 'space-between' : 'flex-start',
gap: 2, gap: 2,
pt: 3, // Reduce padding top to minimize space above pt: 3,
borderTop: `1px solid ${theme.palette.divider}`, borderTop: `1px solid ${theme.palette.divider}`,
flexShrink: 0, flexShrink: 0,
width: '100%', width: '100%',
}} }}
> >
{/* Left side - Back to Selection button */}
{onBackToSelection && ( {onBackToSelection && (
<Button <Button
variant="outlined" variant="outlined"
@@ -157,7 +153,6 @@ export const RobotConfigPage: React.FC<RobotConfigPageProps> = ({
</Button> </Button>
)} )}
{/* Right side - Save/Cancel buttons */}
<Box sx={{ display: 'flex', gap: 2 }}> <Box sx={{ display: 'flex', gap: 2 }}>
{showCancelButton && ( {showCancelButton && (
<Button <Button
@@ -165,9 +160,7 @@ export const RobotConfigPage: React.FC<RobotConfigPageProps> = ({
onClick={handleBack} onClick={handleBack}
disabled={isLoading} disabled={isLoading}
sx={{ sx={{
color: '#ff00c3 !important', backgroundColor: 'inherit !important',
borderColor: '#ff00c3 !important',
backgroundColor: 'white !important',
}} > }} >
{cancelButtonText || t("buttons.cancel")} {cancelButtonText || t("buttons.cancel")}
</Button> </Button>
@@ -197,4 +190,4 @@ export const RobotConfigPage: React.FC<RobotConfigPageProps> = ({
)} )}
</Box> </Box>
); );
}; }

View File

@@ -7,7 +7,6 @@ import {
Box, Box,
Button, Button,
} from "@mui/material"; } from "@mui/material";
import { Schedule } from "@mui/icons-material";
import { Dropdown } from "../../ui/DropdownMui"; import { Dropdown } from "../../ui/DropdownMui";
import { validMomentTimezones } from "../../../constants/const"; import { validMomentTimezones } from "../../../constants/const";
import { useGlobalInfoStore } from "../../../context/globalInfo"; import { useGlobalInfoStore } from "../../../context/globalInfo";
@@ -188,8 +187,8 @@ export const ScheduleSettingsPage = ({
display: "flex", display: "flex",
flexDirection: "column", flexDirection: "column",
alignItems: "flex-start", alignItems: "flex-start",
"& > *": { marginBottom: "20px" }, gap: 3,
marginTop: "-20px", width: "100%",
}} }}
> >
<> <>
@@ -215,7 +214,7 @@ export const ScheduleSettingsPage = ({
{t("schedule_settings.at_around")}: {schedule.atTimeStart},{" "} {t("schedule_settings.at_around")}: {schedule.atTimeStart},{" "}
{schedule.timezone} {t("schedule_settings.timezone")} {schedule.timezone} {t("schedule_settings.timezone")}
</Typography> </Typography>
<Box mt={2} display="flex" justifyContent="space-between"> <Box sx={{ mt: 2, width: "100%" }}>
<Button <Button
onClick={deleteRobotSchedule} onClick={deleteRobotSchedule}
variant="outlined" variant="outlined"
@@ -231,7 +230,7 @@ export const ScheduleSettingsPage = ({
) : ( ) : (
<> <>
<Box sx={{ display: "flex", alignItems: "center", width: "100%" }}> <Box sx={{ display: "flex", alignItems: "center", width: "100%" }}>
<Typography sx={{ marginRight: "10px" }}> <Typography sx={{ width: "200px", flexShrink: 0 }}>
{t("schedule_settings.labels.run_once_every")} {t("schedule_settings.labels.run_once_every")}
</Typography> </Typography>
<TextField <TextField
@@ -263,7 +262,7 @@ export const ScheduleSettingsPage = ({
</Box> </Box>
<Box sx={{ display: "flex", alignItems: "center", width: "100%" }}> <Box sx={{ display: "flex", alignItems: "center", width: "100%" }}>
<Typography sx={{ marginBottom: "5px", marginRight: "25px" }}> <Typography sx={{ width: "200px", flexShrink: 0 }}>
{["MONTHS", "WEEKS"].includes(settings.runEveryUnit) {["MONTHS", "WEEKS"].includes(settings.runEveryUnit)
? t("schedule_settings.labels.start_from_label") ? t("schedule_settings.labels.start_from_label")
: t("schedule_settings.labels.start_from_label")} : t("schedule_settings.labels.start_from_label")}
@@ -288,7 +287,7 @@ export const ScheduleSettingsPage = ({
{settings.runEveryUnit === "MONTHS" && ( {settings.runEveryUnit === "MONTHS" && (
<Box sx={{ display: "flex", alignItems: "center", width: "100%" }}> <Box sx={{ display: "flex", alignItems: "center", width: "100%" }}>
<Typography sx={{ marginBottom: "5px", marginRight: "25px" }}> <Typography sx={{ width: "200px", flexShrink: 0 }}>
{t("schedule_settings.labels.on_day_of_month")} {t("schedule_settings.labels.on_day_of_month")}
</Typography> </Typography>
<TextField <TextField
@@ -305,10 +304,10 @@ export const ScheduleSettingsPage = ({
{["MINUTES", "HOURS"].includes(settings.runEveryUnit) ? ( {["MINUTES", "HOURS"].includes(settings.runEveryUnit) ? (
<Box sx={{ display: "flex", alignItems: "center", width: "100%" }}> <Box sx={{ display: "flex", alignItems: "center", width: "100%" }}>
<Box sx={{ marginRight: "20px" }}> <Typography sx={{ width: "200px", flexShrink: 0 }}>
<Typography sx={{ marginBottom: "5px" }}> {t("schedule_settings.labels.in_between")}
{t("schedule_settings.labels.in_between")} </Typography>
</Typography> <Box sx={{ display: "flex", gap: 1 }}>
<TextField <TextField
type="time" type="time"
value={settings.atTimeStart} value={settings.atTimeStart}
@@ -329,7 +328,7 @@ export const ScheduleSettingsPage = ({
</Box> </Box>
) : ( ) : (
<Box sx={{ display: "flex", alignItems: "center", width: "100%" }}> <Box sx={{ display: "flex", alignItems: "center", width: "100%" }}>
<Typography sx={{ marginBottom: "5px", marginRight: "10px" }}> <Typography sx={{ width: "200px", flexShrink: 0 }}>
{t("schedule_settings.at_around")} {t("schedule_settings.at_around")}
</Typography> </Typography>
<TextField <TextField
@@ -344,7 +343,7 @@ export const ScheduleSettingsPage = ({
)} )}
<Box sx={{ display: "flex", alignItems: "center", width: "100%" }}> <Box sx={{ display: "flex", alignItems: "center", width: "100%" }}>
<Typography sx={{ marginRight: "10px" }}> <Typography sx={{ width: "200px", flexShrink: 0 }}>
{t("schedule_settings.timezone")} {t("schedule_settings.timezone")}
</Typography> </Typography>
<Dropdown <Dropdown
@@ -370,4 +369,4 @@ export const ScheduleSettingsPage = ({
</Box> </Box>
</RobotConfigPage> </RobotConfigPage>
); );
}; }

View File

@@ -1,7 +1,7 @@
import React, { useCallback, useContext, useEffect } from 'react'; import React, { useCallback, useContext, useEffect } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { MainMenu } from "../components/dashboard/MainMenu"; import { MainMenu } from "../components/dashboard/MainMenu";
import { Stack } from "@mui/material"; import { Stack, Box } from "@mui/material";
import { Recordings } from "../components/robot/Recordings"; import { Recordings } from "../components/robot/Recordings";
import { Runs } from "../components/run/Runs"; import { Runs } from "../components/run/Runs";
import ProxyForm from '../components/proxy/ProxyForm'; import ProxyForm from '../components/proxy/ProxyForm';
@@ -318,12 +318,29 @@ export const MainPage = ({ handleEditRecording, initialContent }: MainPageProps)
} }
} }
return ( return (
<Stack direction='row' spacing={0} sx={{ minHeight: '900px' }}> <Box sx={{ display: 'flex', minHeight: 'calc(100vh - 64px)', width: '100%' }}>
<Stack sx={{ width: 250, flexShrink: 0 }}> <Box sx={{
width: 230,
flexShrink: 0,
position: 'sticky',
top: 64,
height: 'calc(100vh - 64px)',
overflowY: 'auto',
zIndex: 1000
}}>
<MainMenu value={content} handleChangeContent={setContent} /> <MainMenu value={content} handleChangeContent={setContent} />
</Stack> </Box>
<Box sx={{
flex: 1,
minWidth: 0,
overflow: 'auto',
minHeight: 'calc(100vh - 64px)',
width: 'calc(100% - 250px)'
}}>
{DisplayContent()} {DisplayContent()}
</Stack> </Box>
); </Box>
}; )
}

View File

@@ -13,6 +13,7 @@ import UserRoute from '../routes/userRoute';
import { Routes, Route, useNavigate, Navigate } from 'react-router-dom'; import { Routes, Route, useNavigate, Navigate } from 'react-router-dom';
import { NotFoundPage } from '../components/dashboard/NotFound'; import { NotFoundPage } from '../components/dashboard/NotFound';
import RobotCreate from '../components/robot/pages/RobotCreate'; import RobotCreate from '../components/robot/pages/RobotCreate';
import { Box } from '@mui/material';
export const PageWrapper = () => { export const PageWrapper = () => {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
@@ -84,40 +85,57 @@ export const PageWrapper = () => {
} }
} }
}, [location.pathname, navigate, setBrowserId, setRecordingId, setRecordingName, setRecordingUrl]); }, [location.pathname, navigate, setBrowserId, setRecordingId, setRecordingName, setRecordingUrl]);
const isAuthPage = location.pathname === '/login' || location.pathname === '/register';
const isRecordingPage = location.pathname === '/recording';
return ( return (
<div> <div>
<AuthProvider> <AuthProvider>
<SocketProvider> <SocketProvider>
<React.Fragment> <React.Fragment>
{/* {!browserId && location.pathname !== '/recording' && <NavBar recordingName={recordingName} isRecording={!!browserId} />} */} {/* Show NavBar only for main app pages, not for recording pages */}
{location.pathname !== '/recording' && <NavBar recordingName={recordingName} isRecording={false} />} {!isRecordingPage && (
<Routes> <Box sx={{
<Route element={<UserRoute />}> position: 'sticky',
<Route path="/" element={<Navigate to="/robots" replace />} /> top: 0,
<Route path="/robots/create" element={<RobotCreate />} /> zIndex: 1100,
<Route path="/robots/*" element={<MainPage handleEditRecording={handleEditRecording} initialContent="robots" />} /> backgroundColor: 'background.paper'
<Route path="/runs/*" element={<MainPage handleEditRecording={handleEditRecording} initialContent="runs" />} /> }}>
<Route path="/proxy" element={<MainPage handleEditRecording={handleEditRecording} initialContent="proxy" />} /> <NavBar recordingName={recordingName} isRecording={false} />
<Route path="/apikey" element={<MainPage handleEditRecording={handleEditRecording} initialContent="apikey" />} /> </Box>
</Route> )}
<Route element={<UserRoute />}> <Box sx={{
<Route path="/recording" element={ display: isAuthPage || isRecordingPage ? 'block' : 'flex',
<BrowserDimensionsProvider> minHeight: isAuthPage || isRecordingPage ? '100vh' : 'calc(100vh - 64px)'
<RecordingPage recordingName={recordingName} /> }}>
</BrowserDimensionsProvider> <Routes>
} /> <Route element={<UserRoute />}>
</Route> <Route path="/" element={<Navigate to="/robots" replace />} />
<Route <Route path="/robots/create" element={<RobotCreate />} />
path="/login" <Route path="/robots/*" element={<MainPage handleEditRecording={handleEditRecording} initialContent="robots" />} />
element={<Login />} <Route path="/runs/*" element={<MainPage handleEditRecording={handleEditRecording} initialContent="runs" />} />
/> <Route path="/proxy" element={<MainPage handleEditRecording={handleEditRecording} initialContent="proxy" />} />
<Route <Route path="/apikey" element={<MainPage handleEditRecording={handleEditRecording} initialContent="apikey" />} />
path="/register" </Route>
element={<Register />} <Route element={<UserRoute />}>
/> <Route path="/recording" element={
<Route path="*" element={<NotFoundPage />} /> <BrowserDimensionsProvider>
</Routes> <RecordingPage recordingName={recordingName} />
</BrowserDimensionsProvider>
} />
</Route>
<Route
path="/login"
element={<Login />}
/>
<Route
path="/register"
element={<Register />}
/>
<Route path="*" element={<NotFoundPage />} />
</Routes>
</Box>
</React.Fragment> </React.Fragment>
</SocketProvider> </SocketProvider>
</AuthProvider> </AuthProvider>