Merge branch 'develop' into fast-loader
This commit is contained in:
@@ -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",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { default as axios } from "axios";
|
import { default as axios } from "axios";
|
||||||
import { WorkflowFile } from "maxun-core";
|
import { WorkflowFile } from "maxun-core";
|
||||||
import { RunSettings } from "../components/run/RunSettings";
|
import { RunSettings } from "../components/run/RunSettings";
|
||||||
import { ScheduleSettings } from "../components/robot/ScheduleSettings";
|
import { ScheduleSettings } from "../components/robot/pages/ScheduleSettingsPage";
|
||||||
import { CreateRunResponse, ScheduleRunResponse } from "../pages/MainPage";
|
import { CreateRunResponse, ScheduleRunResponse } from "../pages/MainPage";
|
||||||
import { apiUrl } from "../apiConfig";
|
import { apiUrl } from "../apiConfig";
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -534,24 +534,9 @@ export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture
|
|||||||
const isDarkMode = theme.darkMode;
|
const isDarkMode = theme.darkMode;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper sx={{ height: panelHeight, width: 'auto', alignItems: "center", background: 'inherit', overflow: 'hidden' }} id="browser-actions" elevation={0}>
|
<Paper sx={{ height: panelHeight, width: 'auto', alignItems: "center", background: 'inherit' }} id="browser-actions" elevation={0}>
|
||||||
<ActionDescriptionBox isDarkMode={isDarkMode} />
|
<ActionDescriptionBox isDarkMode={isDarkMode} />
|
||||||
<Box
|
<Box display="flex" flexDirection="column" gap={2} style={{ margin: '13px' }}>
|
||||||
display="flex"
|
|
||||||
flexDirection="column"
|
|
||||||
gap={2}
|
|
||||||
style={{ margin: '13px' }}
|
|
||||||
sx={{
|
|
||||||
height: 'calc(100% - 26px)',
|
|
||||||
overflowY: 'auto',
|
|
||||||
overflowX: 'hidden',
|
|
||||||
'&::-webkit-scrollbar': {
|
|
||||||
display: 'none'
|
|
||||||
},
|
|
||||||
msOverflowStyle: 'none',
|
|
||||||
scrollbarWidth: 'none'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{!isAnyActionActive && (
|
{!isAnyActionActive && (
|
||||||
<>
|
<>
|
||||||
{showCaptureList && (
|
{showCaptureList && (
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -189,7 +182,7 @@ export const RobotConfigPage: React.FC<RobotConfigPageProps> = ({
|
|||||||
boxShadow: 'none',
|
boxShadow: 'none',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isLoading ? t("buttons.saving") : (saveButtonText || t("buttons.save"))}
|
{isLoading ? t("Saving...") : (saveButtonText || t("buttons.save"))}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
@@ -197,4 +190,4 @@ export const RobotConfigPage: React.FC<RobotConfigPageProps> = ({
|
|||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -41,17 +41,14 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
const [editingField, setEditingField] = useState<{listId: number, fieldKey: string} | null>(null);
|
const [editingField, setEditingField] = useState<{listId: number, fieldKey: string} | null>(null);
|
||||||
const [editingValue, setEditingValue] = useState<string>('');
|
const [editingValue, setEditingValue] = useState<string>('');
|
||||||
|
|
||||||
const [editingListName, setEditingListName] = useState<number | null>(null);
|
|
||||||
const [editingListNameValue, setEditingListNameValue] = useState<string>('');
|
|
||||||
|
|
||||||
const [editingTextGroupName, setEditingTextGroupName] = useState<boolean>(false);
|
const [editingTextGroupName, setEditingTextGroupName] = useState<boolean>(false);
|
||||||
const [editingTextGroupNameValue, setEditingTextGroupNameValue] = useState<string>('Text Data');
|
const [editingTextGroupNameValue, setEditingTextGroupNameValue] = useState<string>('Text Data');
|
||||||
|
|
||||||
const [editingTextLabel, setEditingTextLabel] = useState<number | null>(null);
|
const [editing, setEditing] = useState<{
|
||||||
const [editingTextLabelValue, setEditingTextLabelValue] = useState<string>('');
|
stepId: number | null;
|
||||||
|
type: 'list' | 'text' | 'screenshot' | null;
|
||||||
const [editingScreenshotName, setEditingScreenshotName] = useState<number | null>(null);
|
value: string;
|
||||||
const [editingScreenshotNameValue, setEditingScreenshotNameValue] = useState<string>('');
|
}>({ stepId: null, type: null, value: '' });
|
||||||
|
|
||||||
const logEndRef = useRef<HTMLDivElement | null>(null);
|
const logEndRef = useRef<HTMLDivElement | null>(null);
|
||||||
const autoFocusedListIds = useRef<Set<number>>(new Set());
|
const autoFocusedListIds = useRef<Set<number>>(new Set());
|
||||||
@@ -125,30 +122,6 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleStartEditListName = (listId: number, currentName: string) => {
|
|
||||||
setEditingListName(listId);
|
|
||||||
setEditingListNameValue(currentName);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSaveListName = () => {
|
|
||||||
if (editingListName !== null) {
|
|
||||||
const trimmedName = editingListNameValue.trim();
|
|
||||||
const finalName = trimmedName || `List Data ${captureListData.findIndex(l => l.id === editingListName) + 1}`;
|
|
||||||
|
|
||||||
updateListStepName(editingListName, finalName);
|
|
||||||
|
|
||||||
// Use ref-synced version of browserSteps via emitForStepId
|
|
||||||
const listStep = browserSteps.find(step => step.id === editingListName);
|
|
||||||
if (listStep?.actionId) {
|
|
||||||
// small async delay ensures React state commit
|
|
||||||
setTimeout(() => emitForStepId(listStep.actionId!), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
setEditingListName(null);
|
|
||||||
setEditingListNameValue('');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleStartEditTextGroupName = () => {
|
const handleStartEditTextGroupName = () => {
|
||||||
setEditingTextGroupName(true);
|
setEditingTextGroupName(true);
|
||||||
setEditingTextGroupNameValue(currentTextGroupName);
|
setEditingTextGroupNameValue(currentTextGroupName);
|
||||||
@@ -158,7 +131,6 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
const trimmedName = editingTextGroupNameValue.trim();
|
const trimmedName = editingTextGroupNameValue.trim();
|
||||||
const finalName = trimmedName || 'Text Data';
|
const finalName = trimmedName || 'Text Data';
|
||||||
|
|
||||||
console.log("SAVING TEXT GROUP NAME:", finalName);
|
|
||||||
setCurrentTextGroupName(finalName);
|
setCurrentTextGroupName(finalName);
|
||||||
setEditingTextGroupName(false);
|
setEditingTextGroupName(false);
|
||||||
|
|
||||||
@@ -169,34 +141,6 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
}, 0);
|
}, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const handleStartEditTextLabel = (textId: number, currentLabel: string) => {
|
|
||||||
setEditingTextLabel(textId);
|
|
||||||
setEditingTextLabelValue(currentLabel);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSaveTextLabel = () => {
|
|
||||||
if (editingTextLabel !== null && editingTextLabelValue.trim()) {
|
|
||||||
const textStep = browserSteps.find(step => step.id === editingTextLabel);
|
|
||||||
const actionId = textStep?.actionId;
|
|
||||||
|
|
||||||
updateBrowserTextStepLabel(editingTextLabel, editingTextLabelValue.trim());
|
|
||||||
|
|
||||||
// Emit updated action to backend after state update completes
|
|
||||||
if (actionId) {
|
|
||||||
setTimeout(() => emitForStepId(actionId), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
setEditingTextLabel(null);
|
|
||||||
setEditingTextLabelValue('');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCancelTextLabel = () => {
|
|
||||||
setEditingTextLabel(null);
|
|
||||||
setEditingTextLabelValue('');
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleDeleteTextStep = (textId: number) => {
|
const handleDeleteTextStep = (textId: number) => {
|
||||||
const textStep = browserSteps.find(step => step.id === textId);
|
const textStep = browserSteps.find(step => step.id === textId);
|
||||||
const actionId = textStep?.actionId;
|
const actionId = textStep?.actionId;
|
||||||
@@ -210,36 +154,36 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleStartEditScreenshotName = (screenshotStepId: number, currentName: string) => {
|
const startEdit = (stepId: number, type: 'list' | 'text' | 'screenshot', currentValue: string) => {
|
||||||
setEditingScreenshotName(screenshotStepId);
|
setEditing({ stepId, type, value: currentValue });
|
||||||
setEditingScreenshotNameValue(currentName);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSaveScreenshotName = () => {
|
const saveEdit = () => {
|
||||||
if (editingScreenshotName !== null) {
|
const { stepId, type, value } = editing;
|
||||||
const trimmedName = editingScreenshotNameValue.trim();
|
if (stepId == null || !type) return;
|
||||||
const screenshotSteps = browserSteps.filter(step => step.type === 'screenshot');
|
|
||||||
const screenshotIndex = screenshotSteps.findIndex(s => s.id === editingScreenshotName);
|
|
||||||
const finalName = trimmedName || `Screenshot ${screenshotIndex + 1}`;
|
|
||||||
|
|
||||||
updateScreenshotStepName(editingScreenshotName, finalName);
|
|
||||||
|
|
||||||
const screenshotStep = browserSteps.find(step => step.id === editingScreenshotName);
|
const finalValue = value.trim();
|
||||||
if (screenshotStep?.actionId) {
|
if (!finalValue) {
|
||||||
const originalName = screenshotStep.name?.trim() || "";
|
setEditing({ stepId: null, type: null, value: '' });
|
||||||
const trimmedName = editingScreenshotNameValue.trim();
|
return;
|
||||||
|
|
||||||
// 🚫 Only emit if name actually changed
|
|
||||||
if (trimmedName && trimmedName !== originalName) {
|
|
||||||
setTimeout(() => emitForStepId(screenshotStep.actionId!), 500);
|
|
||||||
} else {
|
|
||||||
console.log("🧠 Skipping emit — screenshot name unchanged.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setEditingScreenshotName(null);
|
|
||||||
setEditingScreenshotNameValue('');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type === 'list') {
|
||||||
|
updateListStepName(stepId, finalValue);
|
||||||
|
} else if (type === 'text') {
|
||||||
|
updateBrowserTextStepLabel(stepId, finalValue);
|
||||||
|
} else if (type === 'screenshot') {
|
||||||
|
updateScreenshotStepName(stepId, finalValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
const step = browserSteps.find(s => s.id === stepId);
|
||||||
|
if (step?.actionId) setTimeout(() => emitForStepId(step.actionId!), 0);
|
||||||
|
|
||||||
|
setEditing({ stepId: null, type: null, value: '' });
|
||||||
|
};
|
||||||
|
|
||||||
|
const cancelEdit = () => {
|
||||||
|
setEditing({ stepId: null, type: null, value: '' });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -354,8 +298,6 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let shouldOpenDrawer = false;
|
let shouldOpenDrawer = false;
|
||||||
let switchToTextTab = false;
|
|
||||||
let switchToScreenshotTab = false;
|
|
||||||
|
|
||||||
if (hasScrapeListAction && captureListData.length > 0 && captureListData[0]?.data?.length > 0) {
|
if (hasScrapeListAction && captureListData.length > 0 && captureListData[0]?.data?.length > 0) {
|
||||||
setShowPreviewData(true);
|
setShowPreviewData(true);
|
||||||
@@ -371,7 +313,6 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
if (captureTextData.length > lastTextDataLength.current) {
|
if (captureTextData.length > lastTextDataLength.current) {
|
||||||
userClosedDrawer.current = false;
|
userClosedDrawer.current = false;
|
||||||
shouldOpenDrawer = true;
|
shouldOpenDrawer = true;
|
||||||
switchToTextTab = true;
|
|
||||||
}
|
}
|
||||||
lastTextDataLength.current = captureTextData.length;
|
lastTextDataLength.current = captureTextData.length;
|
||||||
}
|
}
|
||||||
@@ -381,23 +322,35 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
if (screenshotData.length > lastScreenshotDataLength.current) {
|
if (screenshotData.length > lastScreenshotDataLength.current) {
|
||||||
userClosedDrawer.current = false;
|
userClosedDrawer.current = false;
|
||||||
shouldOpenDrawer = true;
|
shouldOpenDrawer = true;
|
||||||
switchToScreenshotTab = true;
|
|
||||||
}
|
}
|
||||||
lastScreenshotDataLength.current = screenshotData.length;
|
lastScreenshotDataLength.current = screenshotData.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getLatestCaptureType = () => {
|
||||||
|
for (let i = browserSteps.length - 1; i >= 0; i--) {
|
||||||
|
const type = browserSteps[i].type;
|
||||||
|
if (type === "list" || type === "text" || type === "screenshot") {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
if (shouldOpenDrawer) {
|
if (shouldOpenDrawer) {
|
||||||
setIsOpen(true);
|
setIsOpen(true);
|
||||||
if (switchToTextTab) {
|
const latestType = getLatestCaptureType();
|
||||||
setTimeout(() => {
|
|
||||||
const textTabIndex = getAvailableTabs().findIndex(tab => tab.id === 'captureText');
|
setTimeout(() => {
|
||||||
if (textTabIndex !== -1) {
|
if (latestType === "text") {
|
||||||
setActiveTab(textTabIndex);
|
const idx = getAvailableTabs().findIndex(t => t.id === "captureText");
|
||||||
}
|
if (idx !== -1) setActiveTab(idx);
|
||||||
}, 100);
|
|
||||||
} else if (switchToScreenshotTab) {
|
} else if (latestType === "list") {
|
||||||
setTimeout(() => {
|
const idx = getAvailableTabs().findIndex(t => t.id === "captureList");
|
||||||
const screenshotTabIndex = getAvailableTabs().findIndex(tab => tab.id === 'captureScreenshot');
|
if (idx !== -1) setActiveTab(idx);
|
||||||
|
|
||||||
|
} else if (latestType === "screenshot") {
|
||||||
|
const screenshotTabIndex = getAvailableTabs().findIndex(tab => tab.id === "captureScreenshot");
|
||||||
if (screenshotTabIndex !== -1) {
|
if (screenshotTabIndex !== -1) {
|
||||||
setActiveTab(screenshotTabIndex);
|
setActiveTab(screenshotTabIndex);
|
||||||
const latestIndex = screenshotData.length - 1;
|
const latestIndex = screenshotData.length - 1;
|
||||||
@@ -406,17 +359,17 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
if (!autoFocusedScreenshotIndices.current.has(latestIndex)) {
|
if (!autoFocusedScreenshotIndices.current.has(latestIndex)) {
|
||||||
autoFocusedScreenshotIndices.current.add(latestIndex);
|
autoFocusedScreenshotIndices.current.add(latestIndex);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const screenshotSteps = browserSteps.filter(step => step.type === 'screenshot') as Array<{ id: number; name?: string; type: 'screenshot' }>;
|
const screenshotSteps = browserSteps.filter(step => step.type === "screenshot");
|
||||||
const latestScreenshotStep = screenshotSteps[latestIndex];
|
const latestScreenshotStep = screenshotSteps[latestIndex];
|
||||||
if (latestScreenshotStep) {
|
if (latestScreenshotStep) {
|
||||||
const screenshotName = latestScreenshotStep.name || `Screenshot ${latestIndex + 1}`;
|
const screenshotName = latestScreenshotStep.name || `Screenshot ${latestIndex + 1}`;
|
||||||
handleStartEditScreenshotName(latestScreenshotStep.id, screenshotName);
|
startEdit(latestScreenshotStep.id, 'screenshot', screenshotName);
|
||||||
}
|
}
|
||||||
}, 300);
|
}, 300);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 100);
|
}
|
||||||
}
|
}, 100);
|
||||||
}
|
}
|
||||||
}, [hasScrapeListAction, hasScrapeSchemaAction, hasScreenshotAction, captureListData, captureTextData, screenshotData, setIsOpen, getText]);
|
}, [hasScrapeListAction, hasScrapeSchemaAction, hasScreenshotAction, captureListData, captureTextData, screenshotData, setIsOpen, getText]);
|
||||||
|
|
||||||
@@ -424,7 +377,7 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
if (captureListData.length > 0 && isOpen && captureStage === 'initial') {
|
if (captureListData.length > 0 && isOpen && captureStage === 'initial') {
|
||||||
const latestListIndex = captureListData.length - 1;
|
const latestListIndex = captureListData.length - 1;
|
||||||
const latestList = captureListData[latestListIndex];
|
const latestList = captureListData[latestListIndex];
|
||||||
if (latestList && latestList.data && latestList.data.length > 0 && !editingListName) {
|
if (latestList && latestList.data && latestList.data.length > 0 && editing.type !== 'list') {
|
||||||
const previousLength = previousDataLengths.current.get(latestList.id) || 0;
|
const previousLength = previousDataLengths.current.get(latestList.id) || 0;
|
||||||
const currentLength = latestList.data.length;
|
const currentLength = latestList.data.length;
|
||||||
|
|
||||||
@@ -433,7 +386,7 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
autoFocusedListIds.current.add(latestList.id);
|
autoFocusedListIds.current.add(latestList.id);
|
||||||
setActiveListTab(latestListIndex);
|
setActiveListTab(latestListIndex);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
handleStartEditListName(latestList.id, latestList.name || `List Data ${latestListIndex + 1}`);
|
startEdit(latestList.id, 'list', latestList.name || `List Data ${latestListIndex + 1}`);
|
||||||
}, 300);
|
}, 300);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -579,7 +532,7 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{captureListData.map((listItem, index) => {
|
{captureListData.map((listItem, index) => {
|
||||||
const isEditing = editingListName === listItem.id;
|
const isEditing = editing.stepId === listItem.id && editing.type === 'list';
|
||||||
const isActive = activeListTab === index;
|
const isActive = activeListTab === index;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -597,10 +550,7 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onDoubleClick={() => {
|
onDoubleClick={() => {
|
||||||
handleStartEditListName(
|
startEdit(listItem.id, 'list', listItem.name || `List Data ${index + 1}`)
|
||||||
listItem.id,
|
|
||||||
listItem.name || `List Data ${index + 1}`
|
|
||||||
);
|
|
||||||
}}
|
}}
|
||||||
sx={{
|
sx={{
|
||||||
px: 3,
|
px: 3,
|
||||||
@@ -638,15 +588,12 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
>
|
>
|
||||||
{isEditing ? (
|
{isEditing ? (
|
||||||
<TextField
|
<TextField
|
||||||
value={editingListNameValue}
|
value={editing.value}
|
||||||
onChange={(e) => setEditingListNameValue(e.target.value)}
|
onChange={(e) => setEditing({ ...editing, value: e.target.value })}
|
||||||
onBlur={handleSaveListName}
|
onBlur={saveEdit}
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.key === 'Enter') handleSaveListName();
|
if (e.key === 'Enter') saveEdit();
|
||||||
if (e.key === 'Escape') {
|
if (e.key === 'Escape') cancelEdit();
|
||||||
setEditingListName(null);
|
|
||||||
setEditingListNameValue('');
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
autoFocus
|
autoFocus
|
||||||
size="small"
|
size="small"
|
||||||
@@ -842,7 +789,7 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
if (!screenshotStep) return null;
|
if (!screenshotStep) return null;
|
||||||
|
|
||||||
const isActive = activeScreenshotTab === index;
|
const isActive = activeScreenshotTab === index;
|
||||||
const isEditing = editingScreenshotName === screenshotStep.id;
|
const isEditing = editing.stepId === screenshotStep.id && editing.type === 'screenshot';
|
||||||
const screenshotName = screenshotStep.name || `Screenshot ${index + 1}`;
|
const screenshotName = screenshotStep.name || `Screenshot ${index + 1}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -858,9 +805,7 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
setActiveScreenshotTab(index);
|
setActiveScreenshotTab(index);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onDoubleClick={() => {
|
onDoubleClick={() => startEdit(screenshotStep.id, 'screenshot', screenshotName)}
|
||||||
handleStartEditScreenshotName(screenshotStep.id, screenshotName);
|
|
||||||
}}
|
|
||||||
sx={{
|
sx={{
|
||||||
px: 3,
|
px: 3,
|
||||||
py: 1.25,
|
py: 1.25,
|
||||||
@@ -895,15 +840,12 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
>
|
>
|
||||||
{isEditing ? (
|
{isEditing ? (
|
||||||
<TextField
|
<TextField
|
||||||
value={editingScreenshotNameValue}
|
value={editing.value}
|
||||||
onChange={(e) => setEditingScreenshotNameValue(e.target.value)}
|
onChange={(e) => setEditing({ ...editing, value: e.target.value })}
|
||||||
onBlur={handleSaveScreenshotName}
|
onBlur={saveEdit}
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.key === 'Enter') handleSaveScreenshotName();
|
if (e.key === 'Enter') saveEdit();
|
||||||
if (e.key === 'Escape') {
|
if (e.key === 'Escape') cancelEdit();
|
||||||
setEditingScreenshotName(null);
|
|
||||||
setEditingScreenshotNameValue('');
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
autoFocus
|
autoFocus
|
||||||
size="small"
|
size="small"
|
||||||
@@ -1059,7 +1001,7 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{captureTextData.map((textStep: any, index) => {
|
{captureTextData.map((textStep: any, index) => {
|
||||||
const isEditing = editingTextLabel === textStep.id;
|
const isEditing = editing.stepId === textStep.id && editing.type === 'text';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TableRow
|
<TableRow
|
||||||
@@ -1083,12 +1025,12 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
{isEditing ? (
|
{isEditing ? (
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, minWidth: '200px' }}>
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, minWidth: '200px' }}>
|
||||||
<TextField
|
<TextField
|
||||||
value={editingTextLabelValue}
|
value={editing.value}
|
||||||
onChange={(e) => setEditingTextLabelValue(e.target.value)}
|
onChange={(e) => setEditing({ ...editing, value: e.target.value })}
|
||||||
onBlur={handleSaveTextLabel}
|
onBlur={saveEdit}
|
||||||
onKeyDown={(e) => {
|
onKeyDown={(e) => {
|
||||||
if (e.key === 'Enter') handleSaveTextLabel();
|
if (e.key === 'Enter') saveEdit();
|
||||||
if (e.key === 'Escape') handleCancelTextLabel();
|
if (e.key === 'Escape') cancelEdit();
|
||||||
}}
|
}}
|
||||||
autoFocus
|
autoFocus
|
||||||
size="small"
|
size="small"
|
||||||
@@ -1102,7 +1044,7 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
/>
|
/>
|
||||||
<IconButton
|
<IconButton
|
||||||
size="small"
|
size="small"
|
||||||
onClick={handleSaveTextLabel}
|
onClick={saveEdit}
|
||||||
sx={{
|
sx={{
|
||||||
color: '#4caf50',
|
color: '#4caf50',
|
||||||
padding: '4px'
|
padding: '4px'
|
||||||
@@ -1124,7 +1066,7 @@ export const InterpretationLog: React.FC<InterpretationLogProps> = ({ isOpen, se
|
|||||||
textDecoration: 'underline'
|
textDecoration: 'underline'
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onClick={() => handleStartEditTextLabel(textStep.id, textStep.label)}
|
onClick={() => startEdit(textStep.id, 'text', textStep.label)}
|
||||||
>
|
>
|
||||||
{textStep.label}
|
{textStep.label}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|||||||
@@ -615,7 +615,7 @@ export const RunContent = ({ row, currentLog, interpretationInProgress, logEndRe
|
|||||||
return (
|
return (
|
||||||
<Box sx={{ width: '100%' }}>
|
<Box sx={{ width: '100%' }}>
|
||||||
<TabContext value={tab}>
|
<TabContext value={tab}>
|
||||||
<TabPanel value='output' sx={{ width: '100%', maxWidth: '1000px' }}>
|
<TabPanel value='output' sx={{ width: '100%', maxWidth: '900px' }}>
|
||||||
{row.status === 'running' || row.status === 'queued' ? (
|
{row.status === 'running' || row.status === 'queued' ? (
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||||
<CircularProgress size={22} sx={{ marginRight: '10px' }} />
|
<CircularProgress size={22} sx={{ marginRight: '10px' }} />
|
||||||
|
|||||||
@@ -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';
|
||||||
@@ -11,7 +11,7 @@ import { createAndRunRecording, createRunForStoredRecording, CreateRunResponseWi
|
|||||||
import { io, Socket } from "socket.io-client";
|
import { io, Socket } from "socket.io-client";
|
||||||
import { stopRecording } from "../api/recording";
|
import { stopRecording } from "../api/recording";
|
||||||
import { RunSettings } from "../components/run/RunSettings";
|
import { RunSettings } from "../components/run/RunSettings";
|
||||||
import { ScheduleSettings } from "../components/robot/ScheduleSettings";
|
import { ScheduleSettings } from "../components/robot/pages/ScheduleSettingsPage";
|
||||||
import { apiUrl } from "../apiConfig";
|
import { apiUrl } from "../apiConfig";
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { AuthContext } from '../context/auth';
|
import { AuthContext } from '../context/auth';
|
||||||
@@ -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>
|
||||||
};
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -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,44 +85,61 @@ 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
|
<BrowserDimensionsProvider>
|
||||||
path="/recording-setup"
|
<RecordingPage recordingName={recordingName} />
|
||||||
element={<div />}
|
</BrowserDimensionsProvider>
|
||||||
/>
|
} />
|
||||||
<Route path="*" element={<NotFoundPage />} />
|
</Route>
|
||||||
</Routes>
|
<Route
|
||||||
|
path="/login"
|
||||||
|
element={<Login />}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path="/register"
|
||||||
|
element={<Register />}
|
||||||
|
/>
|
||||||
|
<Route
|
||||||
|
path="/recording-setup"
|
||||||
|
element={<div />}
|
||||||
|
/>
|
||||||
|
<Route path="*" element={<NotFoundPage />} />
|
||||||
|
</Routes>
|
||||||
|
</Box>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
</SocketProvider>
|
</SocketProvider>
|
||||||
</AuthProvider>
|
</AuthProvider>
|
||||||
|
|||||||
Reference in New Issue
Block a user