From 41ae15d453d58b2aa8c9c83a4a7cd7f2a9a05781 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 6 Oct 2025 18:04:51 +0530 Subject: [PATCH 01/76] chore: move duplicate modal to legacy --- legacy/src/RobotDuplicate.tsx | 172 ++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 legacy/src/RobotDuplicate.tsx diff --git a/legacy/src/RobotDuplicate.tsx b/legacy/src/RobotDuplicate.tsx new file mode 100644 index 00000000..bee1ef5b --- /dev/null +++ b/legacy/src/RobotDuplicate.tsx @@ -0,0 +1,172 @@ +import React, { useState, useEffect } from 'react'; +import { GenericModal } from "../ui/GenericModal"; +import { TextField, Typography, Box, Button } from "@mui/material"; +import { modalStyle } from "../recorder/AddWhereCondModal"; +import { useGlobalInfoStore } from '../../context/globalInfo'; +import { duplicateRecording, getStoredRecording } from '../../api/storage'; +import { WhereWhatPair } from 'maxun-core'; +import { useTranslation } from 'react-i18next'; + +interface RobotMeta { + name: string; + id: string; + createdAt: string; + pairs: number; + updatedAt: string; + params: any[]; +} + +interface RobotWorkflow { + workflow: WhereWhatPair[]; +} + +interface ScheduleConfig { + runEvery: number; + runEveryUnit: 'MINUTES' | 'HOURS' | 'DAYS' | 'WEEKS' | 'MONTHS'; + startFrom: 'SUNDAY' | 'MONDAY' | 'TUESDAY' | 'WEDNESDAY' | 'THURSDAY' | 'FRIDAY' | 'SATURDAY'; + atTimeStart?: string; + atTimeEnd?: string; + timezone: string; + lastRunAt?: Date; + nextRunAt?: Date; + cronExpression?: string; +} + +export interface RobotSettings { + id: string; + userId?: number; + recording_meta: RobotMeta; + recording: RobotWorkflow; + google_sheet_email?: string | null; + google_sheet_name?: string | null; + google_sheet_id?: string | null; + google_access_token?: string | null; + google_refresh_token?: string | null; + schedule?: ScheduleConfig | null; +} + +interface RobotSettingsProps { + isOpen: boolean; + handleStart: (settings: RobotSettings) => void; + handleClose: () => void; + initialSettings?: RobotSettings | null; + +} + +export const RobotDuplicationModal = ({ isOpen, handleStart, handleClose, initialSettings }: RobotSettingsProps) => { + const { t } = useTranslation(); + const [targetUrl, setTargetUrl] = useState(''); + const [robot, setRobot] = useState(null); + const { recordingId, notify, setRerenderRobots } = useGlobalInfoStore(); + + useEffect(() => { + if (isOpen) { + getRobot(); + } + }, [isOpen]); + + useEffect(() => { + if (robot) { + const lastPair = robot?.recording.workflow[robot?.recording.workflow.length - 1]; + const url = lastPair?.what.find(action => action.action === "goto")?.args?.[0]; + setTargetUrl(url); + } + }, [robot]); + + const getRobot = async () => { + if (recordingId) { + const robot = await getStoredRecording(recordingId); + setRobot(robot); + } else { + notify('error', t('robot_duplication.notifications.robot_not_found')); + } + } + + const handleTargetUrlChange = (e: React.ChangeEvent) => { + setTargetUrl(e.target.value); + }; + + const handleSave = async () => { + if (!robot || !targetUrl) { + notify('error', t('robot_duplication.notifications.url_required')); + return; + } + + try { + const success = await duplicateRecording(robot.recording_meta.id, targetUrl); + + if (success) { + setRerenderRobots(true); + + notify('success', t('robot_duplication.notifications.duplicate_success')); + handleStart(robot); + handleClose(); + } else { + notify('error', t('robot_duplication.notifications.duplicate_error')); + } + } catch (error) { + notify('error', t('robot_duplication.notifications.unknown_error')); + console.error('Error updating Target URL:', error); + } + }; + + return ( + + <> + + {t('robot_duplication.title')} + + + { + robot && ( + <> + + {t('robot_duplication.descriptions.purpose')} + +
+ producthunt.com/topics/api', + url2: 'producthunt.com/topics/database' + }) + }} /> +
+ + {t('robot_duplication.descriptions.warning')} + + + + + + + + ) + } +
+ +
+ ); +}; From 259a2e9caa05cf43ea0d2d4f3abcee932b964668 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 6 Oct 2025 18:05:13 +0530 Subject: [PATCH 02/76] chore: move duplicate modal to legacy --- legacy/src/RobotEdit.tsx | 586 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 586 insertions(+) create mode 100644 legacy/src/RobotEdit.tsx diff --git a/legacy/src/RobotEdit.tsx b/legacy/src/RobotEdit.tsx new file mode 100644 index 00000000..3b110ba1 --- /dev/null +++ b/legacy/src/RobotEdit.tsx @@ -0,0 +1,586 @@ +import React, { useState, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; +import { GenericModal } from "../ui/GenericModal"; +import { TextField, Typography, Box, Button, IconButton, InputAdornment } from "@mui/material"; +import { Visibility, VisibilityOff } from '@mui/icons-material'; +import { modalStyle } from "../recorder/AddWhereCondModal"; +import { useGlobalInfoStore } from '../../context/globalInfo'; +import { getStoredRecording, updateRecording } from '../../api/storage'; +import { WhereWhatPair } from 'maxun-core'; + +interface RobotMeta { + name: string; + id: string; + createdAt: string; + pairs: number; + updatedAt: string; + params: any[]; +} + +interface RobotWorkflow { + workflow: WhereWhatPair[]; +} + +interface ScheduleConfig { + runEvery: number; + runEveryUnit: 'MINUTES' | 'HOURS' | 'DAYS' | 'WEEKS' | 'MONTHS'; + startFrom: 'SUNDAY' | 'MONDAY' | 'TUESDAY' | 'WEDNESDAY' | 'THURSDAY' | 'FRIDAY' | 'SATURDAY'; + atTimeStart?: string; + atTimeEnd?: string; + timezone: string; + lastRunAt?: Date; + nextRunAt?: Date; + cronExpression?: string; +} + +export interface RobotSettings { + id: string; + userId?: number; + recording_meta: RobotMeta; + recording: RobotWorkflow; + google_sheet_email?: string | null; + google_sheet_name?: string | null; + google_sheet_id?: string | null; + google_access_token?: string | null; + google_refresh_token?: string | null; + schedule?: ScheduleConfig | null; +} + +interface RobotSettingsProps { + isOpen: boolean; + handleStart: (settings: RobotSettings) => void; + handleClose: () => void; + initialSettings?: RobotSettings | null; +} + +interface CredentialInfo { + value: string; + type: string; +} + +interface Credentials { + [key: string]: CredentialInfo; +} + +interface CredentialVisibility { + [key: string]: boolean; +} + +interface GroupedCredentials { + passwords: string[]; + emails: string[]; + usernames: string[]; + others: string[]; +} + +interface ScrapeListLimit { + pairIndex: number; + actionIndex: number; + argIndex: number; + currentLimit: number; +} + +export const RobotEditModal = ({ isOpen, handleStart, handleClose, initialSettings }: RobotSettingsProps) => { + const { t } = useTranslation(); + const [credentials, setCredentials] = useState({}); + const { recordingId, notify, setRerenderRobots } = useGlobalInfoStore(); + const [robot, setRobot] = useState(null); + const [credentialGroups, setCredentialGroups] = useState({ + passwords: [], + emails: [], + usernames: [], + others: [] + }); + const [showPasswords, setShowPasswords] = useState({}); + const [scrapeListLimits, setScrapeListLimits] = useState([]); + + const isEmailPattern = (value: string): boolean => { + return value.includes('@'); + }; + + const isUsernameSelector = (selector: string): boolean => { + return selector.toLowerCase().includes('username') || + selector.toLowerCase().includes('user') || + selector.toLowerCase().includes('email'); + }; + + const determineCredentialType = (selector: string, info: CredentialInfo): 'password' | 'email' | 'username' | 'other' => { + if (info.type === 'password' || selector.toLowerCase().includes('password')) { + return 'password'; + } + if (isEmailPattern(info.value) || selector.toLowerCase().includes('email')) { + return 'email'; + } + if (isUsernameSelector(selector)) { + return 'username'; + } + return 'other'; + }; + + useEffect(() => { + if (isOpen) { + getRobot(); + } + }, [isOpen]); + + useEffect(() => { + if (robot?.recording?.workflow) { + const extractedCredentials = extractInitialCredentials(robot.recording.workflow); + setCredentials(extractedCredentials); + setCredentialGroups(groupCredentialsByType(extractedCredentials)); + + findScrapeListLimits(robot.recording.workflow); + } + }, [robot]); + + const findScrapeListLimits = (workflow: WhereWhatPair[]) => { + const limits: ScrapeListLimit[] = []; + + workflow.forEach((pair, pairIndex) => { + if (!pair.what) return; + + pair.what.forEach((action, actionIndex) => { + if (action.action === 'scrapeList' && action.args && action.args.length > 0) { + // Check if first argument has a limit property + const arg = action.args[0]; + if (arg && typeof arg === 'object' && 'limit' in arg) { + limits.push({ + pairIndex, + actionIndex, + argIndex: 0, + currentLimit: arg.limit + }); + } + } + }); + }); + + setScrapeListLimits(limits); + }; + + function extractInitialCredentials(workflow: any[]): Credentials { + const credentials: Credentials = {}; + + const isPrintableCharacter = (char: string): boolean => { + return char.length === 1 && !!char.match(/^[\x20-\x7E]$/); + }; + + workflow.forEach(step => { + if (!step.what) return; + + let currentSelector = ''; + let currentValue = ''; + let currentType = ''; + let i = 0; + + while (i < step.what.length) { + const action = step.what[i]; + + if (!action.action || !action.args?.[0]) { + i++; + continue; + } + + const selector = action.args[0]; + + // Handle full word type actions first + if (action.action === 'type' && + action.args?.length >= 2 && + typeof action.args[1] === 'string' && + action.args[1].length > 1) { + + if (!credentials[selector]) { + credentials[selector] = { + value: action.args[1], + type: action.args[2] || 'text' + }; + } + i++; + continue; + } + + // Handle character-by-character sequences (both type and press) + if ((action.action === 'type' || action.action === 'press') && + action.args?.length >= 2 && + typeof action.args[1] === 'string') { + + if (selector !== currentSelector) { + if (currentSelector && currentValue) { + credentials[currentSelector] = { + value: currentValue, + type: currentType || 'text' + }; + } + currentSelector = selector; + currentValue = credentials[selector]?.value || ''; + currentType = action.args[2] || credentials[selector]?.type || 'text'; + } + + const character = action.args[1]; + + if (isPrintableCharacter(character)) { + currentValue += character; + } else if (character === 'Backspace') { + currentValue = currentValue.slice(0, -1); + } + + if (!currentType && action.args[2]?.toLowerCase() === 'password') { + currentType = 'password'; + } + + let j = i + 1; + while (j < step.what.length) { + const nextAction = step.what[j]; + if (!nextAction.action || !nextAction.args?.[0] || + nextAction.args[0] !== selector || + (nextAction.action !== 'type' && nextAction.action !== 'press')) { + break; + } + if (nextAction.args[1] === 'Backspace') { + currentValue = currentValue.slice(0, -1); + } else if (isPrintableCharacter(nextAction.args[1])) { + currentValue += nextAction.args[1]; + } + j++; + } + + credentials[currentSelector] = { + value: currentValue, + type: currentType + }; + + i = j; + } else { + i++; + } + } + + if (currentSelector && currentValue) { + credentials[currentSelector] = { + value: currentValue, + type: currentType || 'text' + }; + } + }); + + return credentials; + } + + const groupCredentialsByType = (credentials: Credentials): GroupedCredentials => { + return Object.entries(credentials).reduce((acc: GroupedCredentials, [selector, info]) => { + const credentialType = determineCredentialType(selector, info); + + switch (credentialType) { + case 'password': + acc.passwords.push(selector); + break; + case 'email': + acc.emails.push(selector); + break; + case 'username': + acc.usernames.push(selector); + break; + default: + acc.others.push(selector); + } + + return acc; + }, { passwords: [], emails: [], usernames: [], others: [] }); + }; + + const getRobot = async () => { + if (recordingId) { + const robot = await getStoredRecording(recordingId); + setRobot(robot); + } else { + notify('error', t('robot_edit.notifications.update_failed')); + } + }; + + const handleClickShowPassword = (selector: string) => { + setShowPasswords(prev => ({ + ...prev, + [selector]: !prev[selector] + })); + }; + + const handleRobotNameChange = (newName: string) => { + setRobot((prev) => + prev ? { ...prev, recording_meta: { ...prev.recording_meta, name: newName } } : prev + ); + }; + + const handleCredentialChange = (selector: string, value: string) => { + setCredentials(prev => ({ + ...prev, + [selector]: { + ...prev[selector], + value + } + })); + }; + + const handleLimitChange = (pairIndex: number, actionIndex: number, argIndex: number, newLimit: number) => { + setRobot((prev) => { + if (!prev) return prev; + + const updatedWorkflow = [...prev.recording.workflow]; + if ( + updatedWorkflow.length > pairIndex && + updatedWorkflow[pairIndex]?.what && + updatedWorkflow[pairIndex].what.length > actionIndex && + updatedWorkflow[pairIndex].what[actionIndex].args && + updatedWorkflow[pairIndex].what[actionIndex].args.length > argIndex + ) { + updatedWorkflow[pairIndex].what[actionIndex].args[argIndex].limit = newLimit; + + setScrapeListLimits(prev => { + return prev.map(item => { + if (item.pairIndex === pairIndex && + item.actionIndex === actionIndex && + item.argIndex === argIndex) { + return { ...item, currentLimit: newLimit }; + } + return item; + }); + }); + } + + return { ...prev, recording: { ...prev.recording, workflow: updatedWorkflow } }; + }); + }; + + const handleTargetUrlChange = (newUrl: string) => { + setRobot((prev) => { + if (!prev) return prev; + + const updatedWorkflow = [...prev.recording.workflow]; + const lastPairIndex = updatedWorkflow.length - 1; + + if (lastPairIndex >= 0) { + const gotoAction = updatedWorkflow[lastPairIndex]?.what?.find(action => action.action === "goto"); + if (gotoAction && gotoAction.args && gotoAction.args.length > 0) { + gotoAction.args[0] = newUrl; + } + } + + return { ...prev, recording: { ...prev.recording, workflow: updatedWorkflow } }; + }); + }; + + const renderAllCredentialFields = () => { + return ( + <> + {renderCredentialFields( + credentialGroups.usernames, + t('Username'), + 'text' + )} + + {renderCredentialFields( + credentialGroups.emails, + t('Email'), + 'text' + )} + + {renderCredentialFields( + credentialGroups.passwords, + t('Password'), + 'password' + )} + + {renderCredentialFields( + credentialGroups.others, + t('Other'), + 'text' + )} + + ); + }; + + const renderCredentialFields = (selectors: string[], headerText: string, defaultType: 'text' | 'password' = 'text') => { + if (selectors.length === 0) return null; + + return ( + <> + {selectors.map((selector, index) => { + const isVisible = showPasswords[selector]; + + return ( + handleCredentialChange(selector, e.target.value)} + style={{ marginBottom: '20px' }} + InputProps={{ + endAdornment: ( + + handleClickShowPassword(selector)} + edge="end" + disabled={!credentials[selector]?.value} + > + {isVisible ? : } + + + ), + }} + /> + ); + })} + + ); + }; + + const renderScrapeListLimitFields = () => { + if (scrapeListLimits.length === 0) return null; + + return ( + <> + + {t('List Limits')} + + + {scrapeListLimits.map((limitInfo, index) => ( + { + const value = parseInt(e.target.value, 10); + if (value >= 1) { + handleLimitChange( + limitInfo.pairIndex, + limitInfo.actionIndex, + limitInfo.argIndex, + value + ); + } + }} + inputProps={{ min: 1 }} + style={{ marginBottom: '20px' }} + /> + ))} + + ); + }; + + const handleSave = async () => { + if (!robot) return; + + try { + const credentialsForPayload = Object.entries(credentials).reduce((acc, [selector, info]) => { + const enforceType = info.type === 'password' ? 'password' : 'text'; + + acc[selector] = { + value: info.value, + type: enforceType + }; + return acc; + }, {} as Record); + + const lastPair = robot.recording.workflow[robot.recording.workflow.length - 1]; + const targetUrl = lastPair?.what.find(action => action.action === "goto")?.args?.[0]; + + const payload = { + name: robot.recording_meta.name, + limits: scrapeListLimits.map(limit => ({ + pairIndex: limit.pairIndex, + actionIndex: limit.actionIndex, + argIndex: limit.argIndex, + limit: limit.currentLimit + })), + credentials: credentialsForPayload, + targetUrl: targetUrl, + }; + + const success = await updateRecording(robot.recording_meta.id, payload); + + if (success) { + setRerenderRobots(true); + + notify('success', t('robot_edit.notifications.update_success')); + handleStart(robot); + handleClose(); + } else { + notify('error', t('robot_edit.notifications.update_failed')); + } + } catch (error) { + notify('error', t('robot_edit.notifications.update_error')); + console.error('Error updating robot:', error); + } + }; + + const lastPair = robot?.recording.workflow[robot?.recording.workflow.length - 1]; + const targetUrl = lastPair?.what.find(action => action.action === "goto")?.args?.[0]; + + return ( + + <> + + {t('robot_edit.title')} + + + {robot && ( + <> + handleRobotNameChange(e.target.value)} + style={{ marginBottom: '20px' }} + /> + + handleTargetUrlChange(e.target.value)} + style={{ marginBottom: '20px' }} + /> + + {renderScrapeListLimitFields()} + + {(Object.keys(credentials).length > 0) && ( + <> + + {t('Input Texts')} + + {renderAllCredentialFields()} + + )} + + + + + + + )} + + + + ); +}; \ No newline at end of file From 8cb7c52693cc3a471afe7dd316b022acc520654c Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 6 Oct 2025 18:05:30 +0530 Subject: [PATCH 03/76] chore: move duplicate modal to legacy --- legacy/src/RobotSettings.tsx | 173 +++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 legacy/src/RobotSettings.tsx diff --git a/legacy/src/RobotSettings.tsx b/legacy/src/RobotSettings.tsx new file mode 100644 index 00000000..c91b4f11 --- /dev/null +++ b/legacy/src/RobotSettings.tsx @@ -0,0 +1,173 @@ +import React, { useState, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; +import { GenericModal } from "../ui/GenericModal"; +import { TextField, Typography, Box } from "@mui/material"; +import { useGlobalInfoStore } from '../../context/globalInfo'; +import { getStoredRecording } from '../../api/storage'; +import { WhereWhatPair } from 'maxun-core'; +import { getUserById } from "../../api/auth"; + +interface RobotMeta { + name: string; + id: string; + createdAt: string; + pairs: number; + updatedAt: string; + params: any[]; +} + +interface RobotWorkflow { + workflow: WhereWhatPair[]; +} + +interface ScheduleConfig { + runEvery: number; + runEveryUnit: 'MINUTES' | 'HOURS' | 'DAYS' | 'WEEKS' | 'MONTHS'; + startFrom: 'SUNDAY' | 'MONDAY' | 'TUESDAY' | 'WEDNESDAY' | 'THURSDAY' | 'FRIDAY' | 'SATURDAY'; + atTimeStart?: string; + atTimeEnd?: string; + timezone: string; + lastRunAt?: Date; + nextRunAt?: Date; + cronExpression?: string; +} + +export interface RobotSettings { + id: string; + userId?: number; + recording_meta: RobotMeta; + recording: RobotWorkflow; + google_sheet_email?: string | null; + google_sheet_name?: string | null; + google_sheet_id?: string | null; + google_access_token?: string | null; + google_refresh_token?: string | null; + schedule?: ScheduleConfig | null; +} + +interface RobotSettingsProps { + isOpen: boolean; + handleStart: (settings: RobotSettings) => void; + handleClose: () => void; + initialSettings?: RobotSettings | null; +} + +export const RobotSettingsModal = ({ isOpen, handleStart, handleClose, initialSettings }: RobotSettingsProps) => { + const { t } = useTranslation(); + const [userEmail, setUserEmail] = useState(null); + const [robot, setRobot] = useState(null); + const { recordingId, notify } = useGlobalInfoStore(); + + useEffect(() => { + if (isOpen) { + getRobot(); + } + }, [isOpen]); + + const getRobot = async () => { + if (recordingId) { + const robot = await getStoredRecording(recordingId); + setRobot(robot); + } else { + notify('error', t('robot_settings.errors.robot_not_found')); + } + } + + const lastPair = robot?.recording.workflow[robot?.recording.workflow.length - 1]; + + // Find the `goto` action in `what` and retrieve its arguments + const targetUrl = lastPair?.what.find(action => action.action === "goto")?.args?.[0]; + + useEffect(() => { + const fetchUserEmail = async () => { + if (robot && robot.userId) { + const userData = await getUserById(robot.userId.toString()); + if (userData && userData.user) { + setUserEmail(userData.user.email); + } + } + }; + fetchUserEmail(); + }, [robot?.userId]); + + return ( + + <> + + {t('robot_settings.title')} + + + { + robot && ( + <> + + + {robot.recording.workflow?.[0]?.what?.[0]?.args?.[0]?.limit !== undefined && ( + + )} + + + + ) + } + + + + ); +}; + +export const modalStyle = { +top: "50%", +left: "50%", +transform: "translate(-50%, -50%)", +width: "30%", +backgroundColor: "background.paper", +p: 4, +height: "fit-content", +display: "block", +padding: "20px", +}; From 9441545b525d4c8be0ca45ab7571c47c892e583e Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 6 Oct 2025 18:16:02 +0530 Subject: [PATCH 04/76] fix: remove box padding --- src/components/robot/pages/ScheduleSettingsPage.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/robot/pages/ScheduleSettingsPage.tsx b/src/components/robot/pages/ScheduleSettingsPage.tsx index 5108d485..1835d123 100644 --- a/src/components/robot/pages/ScheduleSettingsPage.tsx +++ b/src/components/robot/pages/ScheduleSettingsPage.tsx @@ -188,7 +188,6 @@ export const ScheduleSettingsPage = ({ display: "flex", flexDirection: "column", alignItems: "flex-start", - padding: "20px", "& > *": { marginBottom: "20px" }, }} > From 9e06d14214e16a7227ffc007e4c371c54767e359 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 6 Oct 2025 18:17:29 +0530 Subject: [PATCH 05/76] feat: set margin top --- src/components/robot/pages/ScheduleSettingsPage.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/robot/pages/ScheduleSettingsPage.tsx b/src/components/robot/pages/ScheduleSettingsPage.tsx index 1835d123..e386cfec 100644 --- a/src/components/robot/pages/ScheduleSettingsPage.tsx +++ b/src/components/robot/pages/ScheduleSettingsPage.tsx @@ -189,6 +189,7 @@ export const ScheduleSettingsPage = ({ flexDirection: "column", alignItems: "flex-start", "& > *": { marginBottom: "20px" }, + marginTop: "-20px", }} > <> From df7aadbec045be61fb5b56ced69c9fb338fd7498 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 6 Oct 2025 18:23:06 +0530 Subject: [PATCH 06/76] chore: move schedule modal to legacy --- legacy/src/ScheduleSettings.tsx | 314 ++++++++++++++++++++++++++++++++ 1 file changed, 314 insertions(+) create mode 100644 legacy/src/ScheduleSettings.tsx diff --git a/legacy/src/ScheduleSettings.tsx b/legacy/src/ScheduleSettings.tsx new file mode 100644 index 00000000..7a28d2dc --- /dev/null +++ b/legacy/src/ScheduleSettings.tsx @@ -0,0 +1,314 @@ +import React, { useState, useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; +import { GenericModal } from "../ui/GenericModal"; +import { MenuItem, TextField, Typography, Box } from "@mui/material"; +import { Dropdown } from "../ui/DropdownMui"; +import Button from "@mui/material/Button"; +import { validMomentTimezones } from '../../constants/const'; +import { useGlobalInfoStore } from '../../context/globalInfo'; +import { getSchedule, deleteSchedule } from '../../api/storage'; + +interface ScheduleSettingsProps { + isOpen: boolean; + handleStart: (settings: ScheduleSettings) => Promise; + handleClose: () => void; + initialSettings?: ScheduleSettings | null; +} + +export interface ScheduleSettings { + runEvery: number; + runEveryUnit: string; + startFrom: string; + dayOfMonth?: string; + atTimeStart?: string; + atTimeEnd?: string; + timezone: string; +} + +export const ScheduleSettingsModal = ({ isOpen, handleStart, handleClose, initialSettings }: ScheduleSettingsProps) => { + const { t } = useTranslation(); + const [schedule, setSchedule] = useState(null); + const [settings, setSettings] = useState({ + runEvery: 1, + runEveryUnit: 'HOURS', + startFrom: 'MONDAY', + dayOfMonth: '1', + atTimeStart: '00:00', + atTimeEnd: '01:00', + timezone: 'UTC' + }); + + useEffect(() => { + if (initialSettings) { + setSettings(initialSettings); + } + }, [initialSettings]); + + const handleChange = (field: keyof ScheduleSettings, value: string | number | boolean) => { + setSettings(prev => ({ ...prev, [field]: value })); + }; + + const textStyle = { + width: '150px', + height: '52px', + marginRight: '10px', + }; + + const dropDownStyle = { + marginTop: '2px', + width: '150px', + height: '59px', + marginRight: '10px', + }; + + const units = [ + 'MINUTES', + 'HOURS', + 'DAYS', + 'WEEKS', + 'MONTHS' + ]; + + const days = [ + 'MONDAY', + 'TUESDAY', + 'WEDNESDAY', + 'THURSDAY', + 'FRIDAY', + 'SATURDAY', + 'SUNDAY' + ]; + + const { recordingId, notify } = useGlobalInfoStore(); + + const deleteRobotSchedule = () => { + if (recordingId) { + deleteSchedule(recordingId); + setSchedule(null); + notify('success', t('Schedule deleted successfully')); + } else { + console.error('No recording id provided'); + } + + setSettings({ + runEvery: 1, + runEveryUnit: 'HOURS', + startFrom: 'MONDAY', + dayOfMonth: '', + atTimeStart: '00:00', + atTimeEnd: '01:00', + timezone: 'UTC' + }); + }; + + const getRobotSchedule = async () => { + if (recordingId) { + const scheduleData = await getSchedule(recordingId); + setSchedule(scheduleData); + } else { + console.error('No recording id provided'); + } + } + + useEffect(() => { + if (isOpen) { + const fetchSchedule = async () => { + await getRobotSchedule(); + }; + fetchSchedule(); + } + }, [isOpen]); + + const getDayOrdinal = (day: string | undefined) => { + if (!day) return ''; + const lastDigit = day.slice(-1); + const lastTwoDigits = day.slice(-2); + + // Special cases for 11, 12, 13 + if (['11', '12', '13'].includes(lastTwoDigits)) { + return t('schedule_settings.labels.on_day.th'); + } + + // Other cases + switch (lastDigit) { + case '1': return t('schedule_settings.labels.on_day.st'); + case '2': return t('schedule_settings.labels.on_day.nd'); + case '3': return t('schedule_settings.labels.on_day.rd'); + default: return t('schedule_settings.labels.on_day.th'); + } + }; + + return ( + + *': { marginBottom: '20px' }, + }}> + {t('schedule_settings.title')} + <> + {schedule !== null ? ( + <> + {t('schedule_settings.run_every')}: {schedule.runEvery} {schedule.runEveryUnit.toLowerCase()} + {['MONTHS', 'WEEKS'].includes(settings.runEveryUnit) ? t('schedule_settings.start_from') : t('schedule_settings.start_from')}: {schedule.startFrom.charAt(0).toUpperCase() + schedule.startFrom.slice(1).toLowerCase()} + {schedule.runEveryUnit === 'MONTHS' && ( + {t('schedule_settings.on_day')}: {schedule.dayOfMonth}{getDayOrdinal(schedule.dayOfMonth)} of the month + )} + {t('schedule_settings.at_around')}: {schedule.atTimeStart}, {schedule.timezone} {t('schedule_settings.timezone')} + + + + + ) : ( + <> + + {t('schedule_settings.labels.run_once_every')} + handleChange('runEvery', parseInt(e.target.value))} + sx={textStyle} + inputProps={{ min: 1 }} + /> + handleChange('runEveryUnit', e.target.value)} + sx={dropDownStyle} + > + {units.map((unit) => ( + {unit.charAt(0).toUpperCase() + unit.slice(1).toLowerCase()} + ))} + + + + + + {['MONTHS', 'WEEKS'].includes(settings.runEveryUnit) ? t('schedule_settings.labels.start_from_label') : t('schedule_settings.labels.start_from_label')} + + handleChange('startFrom', e.target.value)} + sx={dropDownStyle} + > + {days.map((day) => ( + + {day.charAt(0).toUpperCase() + day.slice(1).toLowerCase()} + + ))} + + + + {settings.runEveryUnit === 'MONTHS' && ( + + {t('schedule_settings.labels.on_day_of_month')} + handleChange('dayOfMonth', e.target.value)} + sx={textStyle} + inputProps={{ min: 1, max: 31 }} + /> + + )} + + {['MINUTES', 'HOURS'].includes(settings.runEveryUnit) ? ( + + + {t('schedule_settings.labels.in_between')} + handleChange('atTimeStart', e.target.value)} + sx={textStyle} + /> + handleChange('atTimeEnd', e.target.value)} + sx={textStyle} + /> + + + ) : ( + + {t('schedule_settings.at_around')} + handleChange('atTimeStart', e.target.value)} + sx={textStyle} + /> + + )} + + + {t('schedule_settings.timezone')} + handleChange('timezone', e.target.value)} + sx={dropDownStyle} + > + {validMomentTimezones.map((tz) => ( + {tz.charAt(0).toUpperCase() + tz.slice(1).toLowerCase()} + ))} + + + + + + + + )} + + + + ); +}; + +const modalStyle = { + top: '50%', + left: '50%', + transform: 'translate(-50%, -50%)', + width: '40%', + backgroundColor: 'background.paper', + p: 4, + height: 'fit-content', + display: 'block', + padding: '20px', +}; \ No newline at end of file From b6456641ca1121210713fc5557a7503cb6074cde Mon Sep 17 00:00:00 2001 From: Rohit Rajan Date: Wed, 8 Oct 2025 22:17:05 +0530 Subject: [PATCH 07/76] feat: filter atomic child elements --- src/helpers/clientSelectorGenerator.ts | 192 +++++++++++++++++++------ 1 file changed, 151 insertions(+), 41 deletions(-) diff --git a/src/helpers/clientSelectorGenerator.ts b/src/helpers/clientSelectorGenerator.ts index 385aa8ec..0ecb148a 100644 --- a/src/helpers/clientSelectorGenerator.ts +++ b/src/helpers/clientSelectorGenerator.ts @@ -555,36 +555,24 @@ class ClientSelectorGenerator { */ private isMeaningfulElement(element: HTMLElement): boolean { const tagName = element.tagName.toLowerCase(); - - // Fast path for common meaningful elements - if (["a", "img", "input", "button", "select"].includes(tagName)) { - return true; + + if (tagName === "img") { + return element.hasAttribute("src"); + } + + if (element.children.length > 0) { + return false; } const text = (element.textContent || "").trim(); const hasHref = element.hasAttribute("href"); - const hasSrc = element.hasAttribute("src"); - - // Quick checks first - if (text.length > 0 || hasHref || hasSrc) { + + if (text.length > 0) { return true; } - const isCustomElement = tagName.includes("-"); - - // For custom elements, be more lenient about what's considered meaningful - if (isCustomElement) { - const hasChildren = element.children.length > 0; - const hasSignificantAttributes = Array.from(element.attributes).some( - (attr) => !["class", "style", "id"].includes(attr.name.toLowerCase()) - ); - - return ( - hasChildren || - hasSignificantAttributes || - element.hasAttribute("role") || - element.hasAttribute("aria-label") - ); + if (tagName === "a" && hasHref) { + return true; } return false; @@ -2561,12 +2549,9 @@ class ClientSelectorGenerator { const MAX_MEANINGFUL_ELEMENTS = 300; const MAX_NODES_TO_CHECK = 1200; - const MAX_DEPTH = 12; + const MAX_DEPTH = 20; let nodesChecked = 0; - let adjustedMaxDepth = MAX_DEPTH; - const elementDensityThreshold = 50; - const depths: number[] = [0]; let queueIndex = 0; @@ -2576,14 +2561,10 @@ class ClientSelectorGenerator { queueIndex++; nodesChecked++; - if (currentDepth <= 3 && meaningfulDescendants.length > elementDensityThreshold) { - adjustedMaxDepth = Math.max(6, adjustedMaxDepth - 2); - } - if ( nodesChecked > MAX_NODES_TO_CHECK || meaningfulDescendants.length >= MAX_MEANINGFUL_ELEMENTS || - currentDepth > adjustedMaxDepth + currentDepth > MAX_DEPTH ) { break; } @@ -2592,7 +2573,7 @@ class ClientSelectorGenerator { meaningfulDescendants.push(element); } - if (currentDepth >= adjustedMaxDepth) { + if (currentDepth >= MAX_DEPTH) { continue; } @@ -2607,7 +2588,7 @@ class ClientSelectorGenerator { } } - if (element.shadowRoot && currentDepth < adjustedMaxDepth - 1) { + if (element.shadowRoot && currentDepth < MAX_DEPTH - 1) { const shadowChildren = element.shadowRoot.children; const shadowLimit = Math.min(shadowChildren.length, 20); for (let i = 0; i < shadowLimit; i++) { @@ -2716,22 +2697,46 @@ class ClientSelectorGenerator { } if (!addPositionToAll) { - const meaningfulAttrs = ["role", "type", "name", "src", "aria-label"]; + const meaningfulAttrs = ["role", "type"]; for (const attrName of meaningfulAttrs) { if (element.hasAttribute(attrName)) { const value = element.getAttribute(attrName)!.replace(/'/g, "\\'"); - return `${tagName}[@${attrName}='${value}']`; + const isCommonAttribute = this.isAttributeCommonAcrossLists( + element, + attrName, + value, + otherListElements + ); + if (isCommonAttribute) { + return `${tagName}[@${attrName}='${value}']`; + } } } } const testId = element.getAttribute("data-testid"); if (testId && !addPositionToAll) { - return `${tagName}[@data-testid='${testId}']`; + const isCommon = this.isAttributeCommonAcrossLists( + element, + "data-testid", + testId, + otherListElements + ); + if (isCommon) { + return `${tagName}[@data-testid='${testId}']`; + } } if (element.id && !element.id.match(/^\d/) && !addPositionToAll) { - return `${tagName}[@id='${element.id}']`; + const isCommon = this.isAttributeCommonAcrossLists( + element, + "id", + element.id, + otherListElements + ); + if (isCommon) { + return `${tagName}[@id='${element.id}']`; + } } if (!addPositionToAll) { @@ -2742,7 +2747,15 @@ class ClientSelectorGenerator { attr.name !== "data-mx-id" && attr.value ) { - return `${tagName}[@${attr.name}='${attr.value}']`; + const isCommon = this.isAttributeCommonAcrossLists( + element, + attr.name, + attr.value, + otherListElements + ); + if (isCommon) { + return `${tagName}[@${attr.name}='${attr.value}']`; + } } } } @@ -2906,12 +2919,70 @@ class ClientSelectorGenerator { const result = pathParts.length > 0 ? "/" + pathParts.join("/") : null; this.pathCache.set(targetElement, result); - + return result; } + private isAttributeCommonAcrossLists( + targetElement: HTMLElement, + attrName: string, + attrValue: string, + otherListElements: HTMLElement[] + ): boolean { + if (otherListElements.length === 0) { + return true; + } + + const targetPath = this.getElementPath(targetElement); + + for (const otherListElement of otherListElements) { + const correspondingElement = this.findCorrespondingElement( + otherListElement, + targetPath + ); + if (correspondingElement) { + const otherValue = correspondingElement.getAttribute(attrName); + if (otherValue !== attrValue) { + return false; + } + } + } + + return true; + } + + private getElementPath(element: HTMLElement): number[] { + const path: number[] = []; + let current: HTMLElement | null = element; + + while (current && current.parentElement) { + const siblings = Array.from(current.parentElement.children); + path.unshift(siblings.indexOf(current)); + current = current.parentElement; + } + + return path; + } + + private findCorrespondingElement( + rootElement: HTMLElement, + path: number[] + ): HTMLElement | null { + let current: HTMLElement = rootElement; + + for (const index of path) { + const children = Array.from(current.children); + if (index >= children.length) { + return null; + } + current = children[index] as HTMLElement; + } + + return current; + } + private getCommonClassesAcrossLists( - targetElement: HTMLElement, + targetElement: HTMLElement, otherListElements: HTMLElement[] ): string[] { if (otherListElements.length === 0) { @@ -3919,9 +3990,48 @@ class ClientSelectorGenerator { ); if (!deepestElement) return null; + if (!this.isMeaningfulElementCached(deepestElement)) { + const atomicChild = this.findAtomicChildAtPoint(deepestElement, x, y); + if (atomicChild) { + return atomicChild; + } + } + return deepestElement; } + private findAtomicChildAtPoint( + parent: HTMLElement, + x: number, + y: number + ): HTMLElement | null { + const stack: HTMLElement[] = [parent]; + const visited = new Set(); + + while (stack.length > 0) { + const element = stack.pop()!; + if (visited.has(element)) continue; + visited.add(element); + + if (element !== parent && this.isMeaningfulElementCached(element)) { + const rect = element.getBoundingClientRect(); + if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) { + return element; + } + } + + for (let i = element.children.length - 1; i >= 0; i--) { + const child = element.children[i] as HTMLElement; + const rect = child.getBoundingClientRect(); + if (x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom) { + stack.push(child); + } + } + } + + return null; + } + /** * Helper methods used by the unified getDeepestElementFromPoint */ From ede319f6ac392bf5d9b441e84b3229484539c580 Mon Sep 17 00:00:00 2001 From: Karishma Date: Wed, 8 Oct 2025 23:48:20 +0530 Subject: [PATCH 08/76] fix: match theme on checking action description --- src/components/action/ActionDescriptionBox.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/action/ActionDescriptionBox.tsx b/src/components/action/ActionDescriptionBox.tsx index d36db407..e0a7efbb 100644 --- a/src/components/action/ActionDescriptionBox.tsx +++ b/src/components/action/ActionDescriptionBox.tsx @@ -102,7 +102,7 @@ const ActionDescriptionBox = ({ isDarkMode }: { isDarkMode: boolean }) => { sx={{ color: isDarkMode ? 'white' : 'default', '&.Mui-checked': { - color: '#ff33cc', + color: '#ff00c3', }, }} /> @@ -138,4 +138,4 @@ const ActionDescriptionBox = ({ isDarkMode }: { isDarkMode: boolean }) => { ); }; -export default ActionDescriptionBox; \ No newline at end of file +export default ActionDescriptionBox; From 3a8950b0dc6006886e6a8fc1b5409ba9adad09ae Mon Sep 17 00:00:00 2001 From: amhsirak Date: Wed, 8 Oct 2025 23:56:49 +0530 Subject: [PATCH 09/76] feat: use PlayArrow icon for runs --- src/components/dashboard/MainMenu.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/dashboard/MainMenu.tsx b/src/components/dashboard/MainMenu.tsx index 05846b75..dd921d7c 100644 --- a/src/components/dashboard/MainMenu.tsx +++ b/src/components/dashboard/MainMenu.tsx @@ -4,7 +4,7 @@ import Tab from '@mui/material/Tab'; import Box from '@mui/material/Box'; import { useNavigate, useLocation } from 'react-router-dom'; import { Paper, Button, useTheme, Modal, Typography, Stack, TextField, InputAdornment, IconButton } from "@mui/material"; -import { AutoAwesome, FormatListBulleted, VpnKey, Usb, CloudQueue, Description, Favorite, ContentCopy, SlowMotionVideo } from "@mui/icons-material"; +import { AutoAwesome, FormatListBulleted, VpnKey, Usb, CloudQueue, Description, Favorite, ContentCopy, SlowMotionVideo, PlayArrow } from "@mui/icons-material"; import { useTranslation } from 'react-i18next'; import { useGlobalInfoStore } from "../../context/globalInfo"; @@ -90,7 +90,7 @@ export const MainMenu = ({ value = 'robots', handleChangeContent }: MainMenuProp sx={{ alignItems: 'flex-start' }} > } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} onClick={handleRobotsClick} /> - } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} /> + } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} /> } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} /> } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} /> From 33a9e34f3004b553508156fd06191203aef367cb Mon Sep 17 00:00:00 2001 From: amhsirak Date: Thu, 9 Oct 2025 00:00:01 +0530 Subject: [PATCH 10/76] feat: set icon size to 20 --- src/components/dashboard/MainMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/dashboard/MainMenu.tsx b/src/components/dashboard/MainMenu.tsx index dd921d7c..f4a82756 100644 --- a/src/components/dashboard/MainMenu.tsx +++ b/src/components/dashboard/MainMenu.tsx @@ -89,7 +89,7 @@ export const MainMenu = ({ value = 'robots', handleChangeContent }: MainMenuProp orientation="vertical" sx={{ alignItems: 'flex-start' }} > - } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} onClick={handleRobotsClick} /> + } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} onClick={handleRobotsClick} /> } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} /> } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} /> } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} /> From 9cfded79e6019a68fc2e73bd1866cc2034663953 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Thu, 9 Oct 2025 00:00:15 +0530 Subject: [PATCH 11/76] feat: set icon size to 20 --- src/components/dashboard/MainMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/dashboard/MainMenu.tsx b/src/components/dashboard/MainMenu.tsx index f4a82756..d4b87eac 100644 --- a/src/components/dashboard/MainMenu.tsx +++ b/src/components/dashboard/MainMenu.tsx @@ -90,7 +90,7 @@ export const MainMenu = ({ value = 'robots', handleChangeContent }: MainMenuProp sx={{ alignItems: 'flex-start' }} > } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} onClick={handleRobotsClick} /> - } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} /> + } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} /> } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} /> } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} /> From 8c448e47d473d304a7c9e88e3c1afdd115ae9b43 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Thu, 9 Oct 2025 00:00:24 +0530 Subject: [PATCH 12/76] feat: set icon size to 20 --- src/components/dashboard/MainMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/dashboard/MainMenu.tsx b/src/components/dashboard/MainMenu.tsx index d4b87eac..b930bad5 100644 --- a/src/components/dashboard/MainMenu.tsx +++ b/src/components/dashboard/MainMenu.tsx @@ -91,7 +91,7 @@ export const MainMenu = ({ value = 'robots', handleChangeContent }: MainMenuProp > } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} onClick={handleRobotsClick} /> } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} /> - } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} /> + } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} /> } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} />
From 08bb44ffa9684f3a5e2e9337cedbd192922bc9a3 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Thu, 9 Oct 2025 00:00:32 +0530 Subject: [PATCH 13/76] feat: set icon size to 20 --- src/components/dashboard/MainMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/dashboard/MainMenu.tsx b/src/components/dashboard/MainMenu.tsx index b930bad5..a42491b6 100644 --- a/src/components/dashboard/MainMenu.tsx +++ b/src/components/dashboard/MainMenu.tsx @@ -92,7 +92,7 @@ export const MainMenu = ({ value = 'robots', handleChangeContent }: MainMenuProp } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} onClick={handleRobotsClick} /> } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} /> } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} /> - } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} /> + } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} />
From 8fc992baa92c663fb24b02a2dbf4f1db0676f533 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Thu, 9 Oct 2025 00:01:25 +0530 Subject: [PATCH 14/76] feat: set icon size to 20 --- src/components/dashboard/MainMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/dashboard/MainMenu.tsx b/src/components/dashboard/MainMenu.tsx index a42491b6..2b184718 100644 --- a/src/components/dashboard/MainMenu.tsx +++ b/src/components/dashboard/MainMenu.tsx @@ -111,7 +111,7 @@ export const MainMenu = ({ value = 'robots', handleChangeContent }: MainMenuProp target="_blank" rel="noopener noreferrer" variant="outlined" - startIcon={} + startIcon={} fullWidth > Documentation From 5f9d7d8671d41f15023334a5c19474d0180a0c2d Mon Sep 17 00:00:00 2001 From: amhsirak Date: Thu, 9 Oct 2025 00:02:18 +0530 Subject: [PATCH 15/76] fix: revert --- src/components/dashboard/MainMenu.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/dashboard/MainMenu.tsx b/src/components/dashboard/MainMenu.tsx index 2b184718..83b6a853 100644 --- a/src/components/dashboard/MainMenu.tsx +++ b/src/components/dashboard/MainMenu.tsx @@ -99,7 +99,7 @@ export const MainMenu = ({ value = 'robots', handleChangeContent }: MainMenuProp @@ -111,7 +111,7 @@ export const MainMenu = ({ value = 'robots', handleChangeContent }: MainMenuProp target="_blank" rel="noopener noreferrer" variant="outlined" - startIcon={} + startIcon={} fullWidth > Documentation From b31b3c9c7fc79e6f1e06c95deb551b268e71c20c Mon Sep 17 00:00:00 2001 From: amhsirak Date: Thu, 9 Oct 2025 00:02:28 +0530 Subject: [PATCH 16/76] feat: set icon size to 20 --- src/components/dashboard/MainMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/dashboard/MainMenu.tsx b/src/components/dashboard/MainMenu.tsx index 83b6a853..0746287f 100644 --- a/src/components/dashboard/MainMenu.tsx +++ b/src/components/dashboard/MainMenu.tsx @@ -99,7 +99,7 @@ export const MainMenu = ({ value = 'robots', handleChangeContent }: MainMenuProp From 6219e4f601d7a499dfdf274cf5d899b21d105d26 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Thu, 9 Oct 2025 00:02:46 +0530 Subject: [PATCH 17/76] feat: set icon size to 20 --- src/components/dashboard/MainMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/dashboard/MainMenu.tsx b/src/components/dashboard/MainMenu.tsx index 0746287f..3282747a 100644 --- a/src/components/dashboard/MainMenu.tsx +++ b/src/components/dashboard/MainMenu.tsx @@ -133,7 +133,7 @@ export const MainMenu = ({ value = 'robots', handleChangeContent }: MainMenuProp href='https://app.maxun.dev/' target="_blank" rel="noopener noreferrer" - sx={buttonStyles} startIcon={}> + sx={buttonStyles} startIcon={}> Join Maxun Cloud - From ef65fb3e27fa7bd4e6ef791166efa58745d21068 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Thu, 9 Oct 2025 00:03:52 +0530 Subject: [PATCH 19/76] chore: remove unused imports --- src/components/dashboard/MainMenu.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/dashboard/MainMenu.tsx b/src/components/dashboard/MainMenu.tsx index 5e58069c..26abd6f7 100644 --- a/src/components/dashboard/MainMenu.tsx +++ b/src/components/dashboard/MainMenu.tsx @@ -3,8 +3,8 @@ import Tabs from '@mui/material/Tabs'; import Tab from '@mui/material/Tab'; import Box from '@mui/material/Box'; import { useNavigate, useLocation } from 'react-router-dom'; -import { Paper, Button, useTheme, Modal, Typography, Stack, TextField, InputAdornment, IconButton } from "@mui/material"; -import { AutoAwesome, FormatListBulleted, VpnKey, Usb, CloudQueue, Description, Favorite, ContentCopy, SlowMotionVideo, PlayArrow } from "@mui/icons-material"; +import { Paper, Button, useTheme, Modal, Typography, Stack } from "@mui/material"; +import { AutoAwesome, VpnKey, Usb, CloudQueue, Description, Favorite, SlowMotionVideo, PlayArrow } from "@mui/icons-material"; import { useTranslation } from 'react-i18next'; import { useGlobalInfoStore } from "../../context/globalInfo"; From 76459832a269358fcb89c738560495b854aca11b Mon Sep 17 00:00:00 2001 From: Rohit Rajan Date: Sat, 11 Oct 2025 11:44:14 +0530 Subject: [PATCH 20/76] fix: disable postCSS processing --- src/components/recorder/DOMBrowserRenderer.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/recorder/DOMBrowserRenderer.tsx b/src/components/recorder/DOMBrowserRenderer.tsx index 7fcafdeb..a212f14b 100644 --- a/src/components/recorder/DOMBrowserRenderer.tsx +++ b/src/components/recorder/DOMBrowserRenderer.tsx @@ -908,6 +908,7 @@ export const DOMBrowserRenderer: React.FC = ({ rebuild(snapshotData.snapshot, { doc: iframeDoc, mirror: mirror, + hackCss: false, cache: { stylesWithHoverClass: new Map() }, afterAppend: (node) => { if (node.nodeType === Node.TEXT_NODE && node.textContent) { From ce2e28aea13d386196ebd0dea6fce6c370f15672 Mon Sep 17 00:00:00 2001 From: Rohit Rajan Date: Mon, 13 Oct 2025 10:47:45 +0530 Subject: [PATCH 21/76] fix: prioritize link elements --- src/helpers/clientSelectorGenerator.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/helpers/clientSelectorGenerator.ts b/src/helpers/clientSelectorGenerator.ts index 0ecb148a..d4e5051c 100644 --- a/src/helpers/clientSelectorGenerator.ts +++ b/src/helpers/clientSelectorGenerator.ts @@ -560,21 +560,20 @@ class ClientSelectorGenerator { return element.hasAttribute("src"); } + if (tagName === "a" && element.hasAttribute("href")) { + return true; + } + if (element.children.length > 0) { return false; } const text = (element.textContent || "").trim(); - const hasHref = element.hasAttribute("href"); if (text.length > 0) { return true; } - if (tagName === "a" && hasHref) { - return true; - } - return false; } From 511e1c92060a0c62fea1ed80fa66851172afc078 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 16:40:07 +0530 Subject: [PATCH 22/76] fix: change mode --- src/components/dashboard/NavBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/dashboard/NavBar.tsx b/src/components/dashboard/NavBar.tsx index 24e11d09..2d10a3ab 100644 --- a/src/components/dashboard/NavBar.tsx +++ b/src/components/dashboard/NavBar.tsx @@ -158,7 +158,7 @@ export const NavBar: React.FC = ({ }; const renderThemeToggle = () => ( - + Date: Mon, 13 Oct 2025 16:41:24 +0530 Subject: [PATCH 23/76] feat: no hover on mode toggle --- src/components/dashboard/NavBar.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/components/dashboard/NavBar.tsx b/src/components/dashboard/NavBar.tsx index 2d10a3ab..a8770466 100644 --- a/src/components/dashboard/NavBar.tsx +++ b/src/components/dashboard/NavBar.tsx @@ -163,9 +163,6 @@ export const NavBar: React.FC = ({ onClick={toggleTheme} sx={{ color: darkMode ? '#ffffff' : '#0000008A', - '&:hover': { - background: 'inherit' - } }} > {darkMode ? : } From 73ee83a9a0aec0bc2068fafebf1e535e197b826e Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 16:42:32 +0530 Subject: [PATCH 24/76] feat: disable hover styles for icon button --- src/context/theme-provider.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/context/theme-provider.tsx b/src/context/theme-provider.tsx index 75dd4b8b..b7fe5902 100644 --- a/src/context/theme-provider.tsx +++ b/src/context/theme-provider.tsx @@ -160,9 +160,9 @@ const darkTheme = createTheme({ }, '&.MuiIconButton-colorError': { color: '#f44336', - "&:hover": { - backgroundColor: 'rgba(244, 67, 54, 0.08)', - }, + // "&:hover": { + // backgroundColor: 'rgba(244, 67, 54, 0.08)', + // }, }, }, }, From a091df4c17ca394c26eb10b08a8ec6ea1ad714c1 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 16:43:04 +0530 Subject: [PATCH 25/76] feat: disable hover styles for icon button --- src/context/theme-provider.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/context/theme-provider.tsx b/src/context/theme-provider.tsx index b7fe5902..d9a6d745 100644 --- a/src/context/theme-provider.tsx +++ b/src/context/theme-provider.tsx @@ -155,9 +155,9 @@ const darkTheme = createTheme({ styleOverrides: { root: { color: '#ffffff', - "&:hover": { - backgroundColor: 'rgba(255, 0, 195, 0.08)', - }, + // "&:hover": { + // backgroundColor: 'rgba(255, 0, 195, 0.08)', + // }, '&.MuiIconButton-colorError': { color: '#f44336', // "&:hover": { From 995cfba23447b39b84d62b7827bb13cbad2c77e8 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 16:52:51 +0530 Subject: [PATCH 26/76] chore: lint --- src/components/dashboard/MainMenu.tsx | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/components/dashboard/MainMenu.tsx b/src/components/dashboard/MainMenu.tsx index 05846b75..7cfb2ff7 100644 --- a/src/components/dashboard/MainMenu.tsx +++ b/src/components/dashboard/MainMenu.tsx @@ -89,10 +89,28 @@ export const MainMenu = ({ value = 'robots', handleChangeContent }: MainMenuProp orientation="vertical" sx={{ alignItems: 'flex-start' }} > - } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} onClick={handleRobotsClick} /> - } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} /> - } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} /> - } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} /> + } + iconPosition="start" + sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} + onClick={handleRobotsClick} /> + } + iconPosition="start" + sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} /> + } + iconPosition="start" + sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} /> + } + iconPosition="start" + sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} />
From 7f998e79080cbc09beac7393072c7c7b5fe7be08 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 16:53:16 +0530 Subject: [PATCH 27/76] feat: disable ripple --- src/components/dashboard/MainMenu.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/dashboard/MainMenu.tsx b/src/components/dashboard/MainMenu.tsx index 7cfb2ff7..7797a65c 100644 --- a/src/components/dashboard/MainMenu.tsx +++ b/src/components/dashboard/MainMenu.tsx @@ -94,6 +94,7 @@ export const MainMenu = ({ value = 'robots', handleChangeContent }: MainMenuProp label={t('mainmenu.recordings')} icon={} iconPosition="start" + disableRipple={true} sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} onClick={handleRobotsClick} /> Date: Mon, 13 Oct 2025 16:53:24 +0530 Subject: [PATCH 28/76] feat: disable ripple --- src/components/dashboard/MainMenu.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/dashboard/MainMenu.tsx b/src/components/dashboard/MainMenu.tsx index 7797a65c..8a7e2849 100644 --- a/src/components/dashboard/MainMenu.tsx +++ b/src/components/dashboard/MainMenu.tsx @@ -101,6 +101,7 @@ export const MainMenu = ({ value = 'robots', handleChangeContent }: MainMenuProp label={t('mainmenu.runs')} icon={} iconPosition="start" + disableRipple={true} sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} /> Date: Mon, 13 Oct 2025 16:53:33 +0530 Subject: [PATCH 29/76] feat: disable ripple --- src/components/dashboard/MainMenu.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/dashboard/MainMenu.tsx b/src/components/dashboard/MainMenu.tsx index 8a7e2849..2151753f 100644 --- a/src/components/dashboard/MainMenu.tsx +++ b/src/components/dashboard/MainMenu.tsx @@ -107,6 +107,7 @@ export const MainMenu = ({ value = 'robots', handleChangeContent }: MainMenuProp label={t('mainmenu.proxy')} icon={} iconPosition="start" + disableRipple={true} sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} /> Date: Mon, 13 Oct 2025 16:53:44 +0530 Subject: [PATCH 30/76] feat: disable ripple --- src/components/dashboard/MainMenu.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/dashboard/MainMenu.tsx b/src/components/dashboard/MainMenu.tsx index 2151753f..3f499dc1 100644 --- a/src/components/dashboard/MainMenu.tsx +++ b/src/components/dashboard/MainMenu.tsx @@ -113,6 +113,7 @@ export const MainMenu = ({ value = 'robots', handleChangeContent }: MainMenuProp label={t('mainmenu.apikey')} icon={} iconPosition="start" + disableRipple={true} sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} />
From 6a13605d0c6eb613c8c987c9c67ac8988dcbb1c7 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 17:10:33 +0530 Subject: [PATCH 31/76] feat: change dark mode default bg --- src/context/theme-provider.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/context/theme-provider.tsx b/src/context/theme-provider.tsx index 75dd4b8b..93d984a3 100644 --- a/src/context/theme-provider.tsx +++ b/src/context/theme-provider.tsx @@ -93,8 +93,8 @@ const darkTheme = createTheme({ contrastText: '#ffffff', }, background: { - default: '#121212', - paper: '#1e1e1e', + default: '#000000ff', + paper: '#080808ff', }, text: { primary: '#ffffff', From 8c5b2856aa785b2e8fbcad428a86f7338ad2f692 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 17:13:08 +0530 Subject: [PATCH 32/76] feat: change dark mode bg colors --- src/context/theme-provider.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/context/theme-provider.tsx b/src/context/theme-provider.tsx index 93d984a3..748d36d1 100644 --- a/src/context/theme-provider.tsx +++ b/src/context/theme-provider.tsx @@ -202,21 +202,21 @@ const darkTheme = createTheme({ MuiPaper: { styleOverrides: { root: { - backgroundColor: '#1e1e1e', + backgroundColor: '#080808ff', }, }, }, MuiAppBar: { styleOverrides: { root: { - backgroundColor: '#121212', + backgroundColor: '#080808ff', }, }, }, MuiDrawer: { styleOverrides: { paper: { - backgroundColor: '#121212', + backgroundColor: '#080808ff', }, }, }, From 46c217446acecd93ebd0cd04e3daf301049343e9 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 17:14:02 +0530 Subject: [PATCH 33/76] feat: sync dark mode bg navbar --- src/components/dashboard/NavBar.tsx | 2 +- src/components/robot/RobotDuplicate.tsx | 172 ------- src/components/robot/RobotEdit.tsx | 586 ---------------------- src/components/robot/RobotSettings.tsx | 173 ------- src/components/robot/ScheduleSettings.tsx | 314 ------------ 5 files changed, 1 insertion(+), 1246 deletions(-) delete mode 100644 src/components/robot/RobotDuplicate.tsx delete mode 100644 src/components/robot/RobotEdit.tsx delete mode 100644 src/components/robot/RobotSettings.tsx delete mode 100644 src/components/robot/ScheduleSettings.tsx diff --git a/src/components/dashboard/NavBar.tsx b/src/components/dashboard/NavBar.tsx index 24e11d09..7526de70 100644 --- a/src/components/dashboard/NavBar.tsx +++ b/src/components/dashboard/NavBar.tsx @@ -601,7 +601,7 @@ export const NavBar: React.FC = ({ const NavBarWrapper = styled.div<{ mode: 'light' | 'dark' }>` grid-area: navbar; - background-color: ${({ mode }) => (mode === 'dark' ? '#1e2124' : '#ffffff')}; + background-color: ${({ mode }) => (mode === 'dark' ? '#080808ff' : '#ffffff')}; padding: 5px; display: flex; justify-content: space-between; diff --git a/src/components/robot/RobotDuplicate.tsx b/src/components/robot/RobotDuplicate.tsx deleted file mode 100644 index bee1ef5b..00000000 --- a/src/components/robot/RobotDuplicate.tsx +++ /dev/null @@ -1,172 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { GenericModal } from "../ui/GenericModal"; -import { TextField, Typography, Box, Button } from "@mui/material"; -import { modalStyle } from "../recorder/AddWhereCondModal"; -import { useGlobalInfoStore } from '../../context/globalInfo'; -import { duplicateRecording, getStoredRecording } from '../../api/storage'; -import { WhereWhatPair } from 'maxun-core'; -import { useTranslation } from 'react-i18next'; - -interface RobotMeta { - name: string; - id: string; - createdAt: string; - pairs: number; - updatedAt: string; - params: any[]; -} - -interface RobotWorkflow { - workflow: WhereWhatPair[]; -} - -interface ScheduleConfig { - runEvery: number; - runEveryUnit: 'MINUTES' | 'HOURS' | 'DAYS' | 'WEEKS' | 'MONTHS'; - startFrom: 'SUNDAY' | 'MONDAY' | 'TUESDAY' | 'WEDNESDAY' | 'THURSDAY' | 'FRIDAY' | 'SATURDAY'; - atTimeStart?: string; - atTimeEnd?: string; - timezone: string; - lastRunAt?: Date; - nextRunAt?: Date; - cronExpression?: string; -} - -export interface RobotSettings { - id: string; - userId?: number; - recording_meta: RobotMeta; - recording: RobotWorkflow; - google_sheet_email?: string | null; - google_sheet_name?: string | null; - google_sheet_id?: string | null; - google_access_token?: string | null; - google_refresh_token?: string | null; - schedule?: ScheduleConfig | null; -} - -interface RobotSettingsProps { - isOpen: boolean; - handleStart: (settings: RobotSettings) => void; - handleClose: () => void; - initialSettings?: RobotSettings | null; - -} - -export const RobotDuplicationModal = ({ isOpen, handleStart, handleClose, initialSettings }: RobotSettingsProps) => { - const { t } = useTranslation(); - const [targetUrl, setTargetUrl] = useState(''); - const [robot, setRobot] = useState(null); - const { recordingId, notify, setRerenderRobots } = useGlobalInfoStore(); - - useEffect(() => { - if (isOpen) { - getRobot(); - } - }, [isOpen]); - - useEffect(() => { - if (robot) { - const lastPair = robot?.recording.workflow[robot?.recording.workflow.length - 1]; - const url = lastPair?.what.find(action => action.action === "goto")?.args?.[0]; - setTargetUrl(url); - } - }, [robot]); - - const getRobot = async () => { - if (recordingId) { - const robot = await getStoredRecording(recordingId); - setRobot(robot); - } else { - notify('error', t('robot_duplication.notifications.robot_not_found')); - } - } - - const handleTargetUrlChange = (e: React.ChangeEvent) => { - setTargetUrl(e.target.value); - }; - - const handleSave = async () => { - if (!robot || !targetUrl) { - notify('error', t('robot_duplication.notifications.url_required')); - return; - } - - try { - const success = await duplicateRecording(robot.recording_meta.id, targetUrl); - - if (success) { - setRerenderRobots(true); - - notify('success', t('robot_duplication.notifications.duplicate_success')); - handleStart(robot); - handleClose(); - } else { - notify('error', t('robot_duplication.notifications.duplicate_error')); - } - } catch (error) { - notify('error', t('robot_duplication.notifications.unknown_error')); - console.error('Error updating Target URL:', error); - } - }; - - return ( - - <> - - {t('robot_duplication.title')} - - - { - robot && ( - <> - - {t('robot_duplication.descriptions.purpose')} - -
- producthunt.com/topics/api', - url2: 'producthunt.com/topics/database' - }) - }} /> -
- - {t('robot_duplication.descriptions.warning')} - - - - - - - - ) - } -
- -
- ); -}; diff --git a/src/components/robot/RobotEdit.tsx b/src/components/robot/RobotEdit.tsx deleted file mode 100644 index 3b110ba1..00000000 --- a/src/components/robot/RobotEdit.tsx +++ /dev/null @@ -1,586 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { useTranslation } from 'react-i18next'; -import { GenericModal } from "../ui/GenericModal"; -import { TextField, Typography, Box, Button, IconButton, InputAdornment } from "@mui/material"; -import { Visibility, VisibilityOff } from '@mui/icons-material'; -import { modalStyle } from "../recorder/AddWhereCondModal"; -import { useGlobalInfoStore } from '../../context/globalInfo'; -import { getStoredRecording, updateRecording } from '../../api/storage'; -import { WhereWhatPair } from 'maxun-core'; - -interface RobotMeta { - name: string; - id: string; - createdAt: string; - pairs: number; - updatedAt: string; - params: any[]; -} - -interface RobotWorkflow { - workflow: WhereWhatPair[]; -} - -interface ScheduleConfig { - runEvery: number; - runEveryUnit: 'MINUTES' | 'HOURS' | 'DAYS' | 'WEEKS' | 'MONTHS'; - startFrom: 'SUNDAY' | 'MONDAY' | 'TUESDAY' | 'WEDNESDAY' | 'THURSDAY' | 'FRIDAY' | 'SATURDAY'; - atTimeStart?: string; - atTimeEnd?: string; - timezone: string; - lastRunAt?: Date; - nextRunAt?: Date; - cronExpression?: string; -} - -export interface RobotSettings { - id: string; - userId?: number; - recording_meta: RobotMeta; - recording: RobotWorkflow; - google_sheet_email?: string | null; - google_sheet_name?: string | null; - google_sheet_id?: string | null; - google_access_token?: string | null; - google_refresh_token?: string | null; - schedule?: ScheduleConfig | null; -} - -interface RobotSettingsProps { - isOpen: boolean; - handleStart: (settings: RobotSettings) => void; - handleClose: () => void; - initialSettings?: RobotSettings | null; -} - -interface CredentialInfo { - value: string; - type: string; -} - -interface Credentials { - [key: string]: CredentialInfo; -} - -interface CredentialVisibility { - [key: string]: boolean; -} - -interface GroupedCredentials { - passwords: string[]; - emails: string[]; - usernames: string[]; - others: string[]; -} - -interface ScrapeListLimit { - pairIndex: number; - actionIndex: number; - argIndex: number; - currentLimit: number; -} - -export const RobotEditModal = ({ isOpen, handleStart, handleClose, initialSettings }: RobotSettingsProps) => { - const { t } = useTranslation(); - const [credentials, setCredentials] = useState({}); - const { recordingId, notify, setRerenderRobots } = useGlobalInfoStore(); - const [robot, setRobot] = useState(null); - const [credentialGroups, setCredentialGroups] = useState({ - passwords: [], - emails: [], - usernames: [], - others: [] - }); - const [showPasswords, setShowPasswords] = useState({}); - const [scrapeListLimits, setScrapeListLimits] = useState([]); - - const isEmailPattern = (value: string): boolean => { - return value.includes('@'); - }; - - const isUsernameSelector = (selector: string): boolean => { - return selector.toLowerCase().includes('username') || - selector.toLowerCase().includes('user') || - selector.toLowerCase().includes('email'); - }; - - const determineCredentialType = (selector: string, info: CredentialInfo): 'password' | 'email' | 'username' | 'other' => { - if (info.type === 'password' || selector.toLowerCase().includes('password')) { - return 'password'; - } - if (isEmailPattern(info.value) || selector.toLowerCase().includes('email')) { - return 'email'; - } - if (isUsernameSelector(selector)) { - return 'username'; - } - return 'other'; - }; - - useEffect(() => { - if (isOpen) { - getRobot(); - } - }, [isOpen]); - - useEffect(() => { - if (robot?.recording?.workflow) { - const extractedCredentials = extractInitialCredentials(robot.recording.workflow); - setCredentials(extractedCredentials); - setCredentialGroups(groupCredentialsByType(extractedCredentials)); - - findScrapeListLimits(robot.recording.workflow); - } - }, [robot]); - - const findScrapeListLimits = (workflow: WhereWhatPair[]) => { - const limits: ScrapeListLimit[] = []; - - workflow.forEach((pair, pairIndex) => { - if (!pair.what) return; - - pair.what.forEach((action, actionIndex) => { - if (action.action === 'scrapeList' && action.args && action.args.length > 0) { - // Check if first argument has a limit property - const arg = action.args[0]; - if (arg && typeof arg === 'object' && 'limit' in arg) { - limits.push({ - pairIndex, - actionIndex, - argIndex: 0, - currentLimit: arg.limit - }); - } - } - }); - }); - - setScrapeListLimits(limits); - }; - - function extractInitialCredentials(workflow: any[]): Credentials { - const credentials: Credentials = {}; - - const isPrintableCharacter = (char: string): boolean => { - return char.length === 1 && !!char.match(/^[\x20-\x7E]$/); - }; - - workflow.forEach(step => { - if (!step.what) return; - - let currentSelector = ''; - let currentValue = ''; - let currentType = ''; - let i = 0; - - while (i < step.what.length) { - const action = step.what[i]; - - if (!action.action || !action.args?.[0]) { - i++; - continue; - } - - const selector = action.args[0]; - - // Handle full word type actions first - if (action.action === 'type' && - action.args?.length >= 2 && - typeof action.args[1] === 'string' && - action.args[1].length > 1) { - - if (!credentials[selector]) { - credentials[selector] = { - value: action.args[1], - type: action.args[2] || 'text' - }; - } - i++; - continue; - } - - // Handle character-by-character sequences (both type and press) - if ((action.action === 'type' || action.action === 'press') && - action.args?.length >= 2 && - typeof action.args[1] === 'string') { - - if (selector !== currentSelector) { - if (currentSelector && currentValue) { - credentials[currentSelector] = { - value: currentValue, - type: currentType || 'text' - }; - } - currentSelector = selector; - currentValue = credentials[selector]?.value || ''; - currentType = action.args[2] || credentials[selector]?.type || 'text'; - } - - const character = action.args[1]; - - if (isPrintableCharacter(character)) { - currentValue += character; - } else if (character === 'Backspace') { - currentValue = currentValue.slice(0, -1); - } - - if (!currentType && action.args[2]?.toLowerCase() === 'password') { - currentType = 'password'; - } - - let j = i + 1; - while (j < step.what.length) { - const nextAction = step.what[j]; - if (!nextAction.action || !nextAction.args?.[0] || - nextAction.args[0] !== selector || - (nextAction.action !== 'type' && nextAction.action !== 'press')) { - break; - } - if (nextAction.args[1] === 'Backspace') { - currentValue = currentValue.slice(0, -1); - } else if (isPrintableCharacter(nextAction.args[1])) { - currentValue += nextAction.args[1]; - } - j++; - } - - credentials[currentSelector] = { - value: currentValue, - type: currentType - }; - - i = j; - } else { - i++; - } - } - - if (currentSelector && currentValue) { - credentials[currentSelector] = { - value: currentValue, - type: currentType || 'text' - }; - } - }); - - return credentials; - } - - const groupCredentialsByType = (credentials: Credentials): GroupedCredentials => { - return Object.entries(credentials).reduce((acc: GroupedCredentials, [selector, info]) => { - const credentialType = determineCredentialType(selector, info); - - switch (credentialType) { - case 'password': - acc.passwords.push(selector); - break; - case 'email': - acc.emails.push(selector); - break; - case 'username': - acc.usernames.push(selector); - break; - default: - acc.others.push(selector); - } - - return acc; - }, { passwords: [], emails: [], usernames: [], others: [] }); - }; - - const getRobot = async () => { - if (recordingId) { - const robot = await getStoredRecording(recordingId); - setRobot(robot); - } else { - notify('error', t('robot_edit.notifications.update_failed')); - } - }; - - const handleClickShowPassword = (selector: string) => { - setShowPasswords(prev => ({ - ...prev, - [selector]: !prev[selector] - })); - }; - - const handleRobotNameChange = (newName: string) => { - setRobot((prev) => - prev ? { ...prev, recording_meta: { ...prev.recording_meta, name: newName } } : prev - ); - }; - - const handleCredentialChange = (selector: string, value: string) => { - setCredentials(prev => ({ - ...prev, - [selector]: { - ...prev[selector], - value - } - })); - }; - - const handleLimitChange = (pairIndex: number, actionIndex: number, argIndex: number, newLimit: number) => { - setRobot((prev) => { - if (!prev) return prev; - - const updatedWorkflow = [...prev.recording.workflow]; - if ( - updatedWorkflow.length > pairIndex && - updatedWorkflow[pairIndex]?.what && - updatedWorkflow[pairIndex].what.length > actionIndex && - updatedWorkflow[pairIndex].what[actionIndex].args && - updatedWorkflow[pairIndex].what[actionIndex].args.length > argIndex - ) { - updatedWorkflow[pairIndex].what[actionIndex].args[argIndex].limit = newLimit; - - setScrapeListLimits(prev => { - return prev.map(item => { - if (item.pairIndex === pairIndex && - item.actionIndex === actionIndex && - item.argIndex === argIndex) { - return { ...item, currentLimit: newLimit }; - } - return item; - }); - }); - } - - return { ...prev, recording: { ...prev.recording, workflow: updatedWorkflow } }; - }); - }; - - const handleTargetUrlChange = (newUrl: string) => { - setRobot((prev) => { - if (!prev) return prev; - - const updatedWorkflow = [...prev.recording.workflow]; - const lastPairIndex = updatedWorkflow.length - 1; - - if (lastPairIndex >= 0) { - const gotoAction = updatedWorkflow[lastPairIndex]?.what?.find(action => action.action === "goto"); - if (gotoAction && gotoAction.args && gotoAction.args.length > 0) { - gotoAction.args[0] = newUrl; - } - } - - return { ...prev, recording: { ...prev.recording, workflow: updatedWorkflow } }; - }); - }; - - const renderAllCredentialFields = () => { - return ( - <> - {renderCredentialFields( - credentialGroups.usernames, - t('Username'), - 'text' - )} - - {renderCredentialFields( - credentialGroups.emails, - t('Email'), - 'text' - )} - - {renderCredentialFields( - credentialGroups.passwords, - t('Password'), - 'password' - )} - - {renderCredentialFields( - credentialGroups.others, - t('Other'), - 'text' - )} - - ); - }; - - const renderCredentialFields = (selectors: string[], headerText: string, defaultType: 'text' | 'password' = 'text') => { - if (selectors.length === 0) return null; - - return ( - <> - {selectors.map((selector, index) => { - const isVisible = showPasswords[selector]; - - return ( - handleCredentialChange(selector, e.target.value)} - style={{ marginBottom: '20px' }} - InputProps={{ - endAdornment: ( - - handleClickShowPassword(selector)} - edge="end" - disabled={!credentials[selector]?.value} - > - {isVisible ? : } - - - ), - }} - /> - ); - })} - - ); - }; - - const renderScrapeListLimitFields = () => { - if (scrapeListLimits.length === 0) return null; - - return ( - <> - - {t('List Limits')} - - - {scrapeListLimits.map((limitInfo, index) => ( - { - const value = parseInt(e.target.value, 10); - if (value >= 1) { - handleLimitChange( - limitInfo.pairIndex, - limitInfo.actionIndex, - limitInfo.argIndex, - value - ); - } - }} - inputProps={{ min: 1 }} - style={{ marginBottom: '20px' }} - /> - ))} - - ); - }; - - const handleSave = async () => { - if (!robot) return; - - try { - const credentialsForPayload = Object.entries(credentials).reduce((acc, [selector, info]) => { - const enforceType = info.type === 'password' ? 'password' : 'text'; - - acc[selector] = { - value: info.value, - type: enforceType - }; - return acc; - }, {} as Record); - - const lastPair = robot.recording.workflow[robot.recording.workflow.length - 1]; - const targetUrl = lastPair?.what.find(action => action.action === "goto")?.args?.[0]; - - const payload = { - name: robot.recording_meta.name, - limits: scrapeListLimits.map(limit => ({ - pairIndex: limit.pairIndex, - actionIndex: limit.actionIndex, - argIndex: limit.argIndex, - limit: limit.currentLimit - })), - credentials: credentialsForPayload, - targetUrl: targetUrl, - }; - - const success = await updateRecording(robot.recording_meta.id, payload); - - if (success) { - setRerenderRobots(true); - - notify('success', t('robot_edit.notifications.update_success')); - handleStart(robot); - handleClose(); - } else { - notify('error', t('robot_edit.notifications.update_failed')); - } - } catch (error) { - notify('error', t('robot_edit.notifications.update_error')); - console.error('Error updating robot:', error); - } - }; - - const lastPair = robot?.recording.workflow[robot?.recording.workflow.length - 1]; - const targetUrl = lastPair?.what.find(action => action.action === "goto")?.args?.[0]; - - return ( - - <> - - {t('robot_edit.title')} - - - {robot && ( - <> - handleRobotNameChange(e.target.value)} - style={{ marginBottom: '20px' }} - /> - - handleTargetUrlChange(e.target.value)} - style={{ marginBottom: '20px' }} - /> - - {renderScrapeListLimitFields()} - - {(Object.keys(credentials).length > 0) && ( - <> - - {t('Input Texts')} - - {renderAllCredentialFields()} - - )} - - - - - - - )} - - - - ); -}; \ No newline at end of file diff --git a/src/components/robot/RobotSettings.tsx b/src/components/robot/RobotSettings.tsx deleted file mode 100644 index c91b4f11..00000000 --- a/src/components/robot/RobotSettings.tsx +++ /dev/null @@ -1,173 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { useTranslation } from 'react-i18next'; -import { GenericModal } from "../ui/GenericModal"; -import { TextField, Typography, Box } from "@mui/material"; -import { useGlobalInfoStore } from '../../context/globalInfo'; -import { getStoredRecording } from '../../api/storage'; -import { WhereWhatPair } from 'maxun-core'; -import { getUserById } from "../../api/auth"; - -interface RobotMeta { - name: string; - id: string; - createdAt: string; - pairs: number; - updatedAt: string; - params: any[]; -} - -interface RobotWorkflow { - workflow: WhereWhatPair[]; -} - -interface ScheduleConfig { - runEvery: number; - runEveryUnit: 'MINUTES' | 'HOURS' | 'DAYS' | 'WEEKS' | 'MONTHS'; - startFrom: 'SUNDAY' | 'MONDAY' | 'TUESDAY' | 'WEDNESDAY' | 'THURSDAY' | 'FRIDAY' | 'SATURDAY'; - atTimeStart?: string; - atTimeEnd?: string; - timezone: string; - lastRunAt?: Date; - nextRunAt?: Date; - cronExpression?: string; -} - -export interface RobotSettings { - id: string; - userId?: number; - recording_meta: RobotMeta; - recording: RobotWorkflow; - google_sheet_email?: string | null; - google_sheet_name?: string | null; - google_sheet_id?: string | null; - google_access_token?: string | null; - google_refresh_token?: string | null; - schedule?: ScheduleConfig | null; -} - -interface RobotSettingsProps { - isOpen: boolean; - handleStart: (settings: RobotSettings) => void; - handleClose: () => void; - initialSettings?: RobotSettings | null; -} - -export const RobotSettingsModal = ({ isOpen, handleStart, handleClose, initialSettings }: RobotSettingsProps) => { - const { t } = useTranslation(); - const [userEmail, setUserEmail] = useState(null); - const [robot, setRobot] = useState(null); - const { recordingId, notify } = useGlobalInfoStore(); - - useEffect(() => { - if (isOpen) { - getRobot(); - } - }, [isOpen]); - - const getRobot = async () => { - if (recordingId) { - const robot = await getStoredRecording(recordingId); - setRobot(robot); - } else { - notify('error', t('robot_settings.errors.robot_not_found')); - } - } - - const lastPair = robot?.recording.workflow[robot?.recording.workflow.length - 1]; - - // Find the `goto` action in `what` and retrieve its arguments - const targetUrl = lastPair?.what.find(action => action.action === "goto")?.args?.[0]; - - useEffect(() => { - const fetchUserEmail = async () => { - if (robot && robot.userId) { - const userData = await getUserById(robot.userId.toString()); - if (userData && userData.user) { - setUserEmail(userData.user.email); - } - } - }; - fetchUserEmail(); - }, [robot?.userId]); - - return ( - - <> - - {t('robot_settings.title')} - - - { - robot && ( - <> - - - {robot.recording.workflow?.[0]?.what?.[0]?.args?.[0]?.limit !== undefined && ( - - )} - - - - ) - } - - - - ); -}; - -export const modalStyle = { -top: "50%", -left: "50%", -transform: "translate(-50%, -50%)", -width: "30%", -backgroundColor: "background.paper", -p: 4, -height: "fit-content", -display: "block", -padding: "20px", -}; diff --git a/src/components/robot/ScheduleSettings.tsx b/src/components/robot/ScheduleSettings.tsx deleted file mode 100644 index 7a28d2dc..00000000 --- a/src/components/robot/ScheduleSettings.tsx +++ /dev/null @@ -1,314 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { useTranslation } from 'react-i18next'; -import { GenericModal } from "../ui/GenericModal"; -import { MenuItem, TextField, Typography, Box } from "@mui/material"; -import { Dropdown } from "../ui/DropdownMui"; -import Button from "@mui/material/Button"; -import { validMomentTimezones } from '../../constants/const'; -import { useGlobalInfoStore } from '../../context/globalInfo'; -import { getSchedule, deleteSchedule } from '../../api/storage'; - -interface ScheduleSettingsProps { - isOpen: boolean; - handleStart: (settings: ScheduleSettings) => Promise; - handleClose: () => void; - initialSettings?: ScheduleSettings | null; -} - -export interface ScheduleSettings { - runEvery: number; - runEveryUnit: string; - startFrom: string; - dayOfMonth?: string; - atTimeStart?: string; - atTimeEnd?: string; - timezone: string; -} - -export const ScheduleSettingsModal = ({ isOpen, handleStart, handleClose, initialSettings }: ScheduleSettingsProps) => { - const { t } = useTranslation(); - const [schedule, setSchedule] = useState(null); - const [settings, setSettings] = useState({ - runEvery: 1, - runEveryUnit: 'HOURS', - startFrom: 'MONDAY', - dayOfMonth: '1', - atTimeStart: '00:00', - atTimeEnd: '01:00', - timezone: 'UTC' - }); - - useEffect(() => { - if (initialSettings) { - setSettings(initialSettings); - } - }, [initialSettings]); - - const handleChange = (field: keyof ScheduleSettings, value: string | number | boolean) => { - setSettings(prev => ({ ...prev, [field]: value })); - }; - - const textStyle = { - width: '150px', - height: '52px', - marginRight: '10px', - }; - - const dropDownStyle = { - marginTop: '2px', - width: '150px', - height: '59px', - marginRight: '10px', - }; - - const units = [ - 'MINUTES', - 'HOURS', - 'DAYS', - 'WEEKS', - 'MONTHS' - ]; - - const days = [ - 'MONDAY', - 'TUESDAY', - 'WEDNESDAY', - 'THURSDAY', - 'FRIDAY', - 'SATURDAY', - 'SUNDAY' - ]; - - const { recordingId, notify } = useGlobalInfoStore(); - - const deleteRobotSchedule = () => { - if (recordingId) { - deleteSchedule(recordingId); - setSchedule(null); - notify('success', t('Schedule deleted successfully')); - } else { - console.error('No recording id provided'); - } - - setSettings({ - runEvery: 1, - runEveryUnit: 'HOURS', - startFrom: 'MONDAY', - dayOfMonth: '', - atTimeStart: '00:00', - atTimeEnd: '01:00', - timezone: 'UTC' - }); - }; - - const getRobotSchedule = async () => { - if (recordingId) { - const scheduleData = await getSchedule(recordingId); - setSchedule(scheduleData); - } else { - console.error('No recording id provided'); - } - } - - useEffect(() => { - if (isOpen) { - const fetchSchedule = async () => { - await getRobotSchedule(); - }; - fetchSchedule(); - } - }, [isOpen]); - - const getDayOrdinal = (day: string | undefined) => { - if (!day) return ''; - const lastDigit = day.slice(-1); - const lastTwoDigits = day.slice(-2); - - // Special cases for 11, 12, 13 - if (['11', '12', '13'].includes(lastTwoDigits)) { - return t('schedule_settings.labels.on_day.th'); - } - - // Other cases - switch (lastDigit) { - case '1': return t('schedule_settings.labels.on_day.st'); - case '2': return t('schedule_settings.labels.on_day.nd'); - case '3': return t('schedule_settings.labels.on_day.rd'); - default: return t('schedule_settings.labels.on_day.th'); - } - }; - - return ( - - *': { marginBottom: '20px' }, - }}> - {t('schedule_settings.title')} - <> - {schedule !== null ? ( - <> - {t('schedule_settings.run_every')}: {schedule.runEvery} {schedule.runEveryUnit.toLowerCase()} - {['MONTHS', 'WEEKS'].includes(settings.runEveryUnit) ? t('schedule_settings.start_from') : t('schedule_settings.start_from')}: {schedule.startFrom.charAt(0).toUpperCase() + schedule.startFrom.slice(1).toLowerCase()} - {schedule.runEveryUnit === 'MONTHS' && ( - {t('schedule_settings.on_day')}: {schedule.dayOfMonth}{getDayOrdinal(schedule.dayOfMonth)} of the month - )} - {t('schedule_settings.at_around')}: {schedule.atTimeStart}, {schedule.timezone} {t('schedule_settings.timezone')} - - - - - ) : ( - <> - - {t('schedule_settings.labels.run_once_every')} - handleChange('runEvery', parseInt(e.target.value))} - sx={textStyle} - inputProps={{ min: 1 }} - /> - handleChange('runEveryUnit', e.target.value)} - sx={dropDownStyle} - > - {units.map((unit) => ( - {unit.charAt(0).toUpperCase() + unit.slice(1).toLowerCase()} - ))} - - - - - - {['MONTHS', 'WEEKS'].includes(settings.runEveryUnit) ? t('schedule_settings.labels.start_from_label') : t('schedule_settings.labels.start_from_label')} - - handleChange('startFrom', e.target.value)} - sx={dropDownStyle} - > - {days.map((day) => ( - - {day.charAt(0).toUpperCase() + day.slice(1).toLowerCase()} - - ))} - - - - {settings.runEveryUnit === 'MONTHS' && ( - - {t('schedule_settings.labels.on_day_of_month')} - handleChange('dayOfMonth', e.target.value)} - sx={textStyle} - inputProps={{ min: 1, max: 31 }} - /> - - )} - - {['MINUTES', 'HOURS'].includes(settings.runEveryUnit) ? ( - - - {t('schedule_settings.labels.in_between')} - handleChange('atTimeStart', e.target.value)} - sx={textStyle} - /> - handleChange('atTimeEnd', e.target.value)} - sx={textStyle} - /> - - - ) : ( - - {t('schedule_settings.at_around')} - handleChange('atTimeStart', e.target.value)} - sx={textStyle} - /> - - )} - - - {t('schedule_settings.timezone')} - handleChange('timezone', e.target.value)} - sx={dropDownStyle} - > - {validMomentTimezones.map((tz) => ( - {tz.charAt(0).toUpperCase() + tz.slice(1).toLowerCase()} - ))} - - - - - - - - )} - - - - ); -}; - -const modalStyle = { - top: '50%', - left: '50%', - transform: 'translate(-50%, -50%)', - width: '40%', - backgroundColor: 'background.paper', - p: 4, - height: 'fit-content', - display: 'block', - padding: '20px', -}; \ No newline at end of file From 4b28db25d14325ae00dde83a965e3541f3070be9 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 17:15:53 +0530 Subject: [PATCH 34/76] fix: match border bottom --- src/components/dashboard/NavBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/dashboard/NavBar.tsx b/src/components/dashboard/NavBar.tsx index 7526de70..7073b071 100644 --- a/src/components/dashboard/NavBar.tsx +++ b/src/components/dashboard/NavBar.tsx @@ -605,7 +605,7 @@ const NavBarWrapper = styled.div<{ mode: 'light' | 'dark' }>` padding: 5px; display: flex; justify-content: space-between; - border-bottom: 1px solid ${({ mode }) => (mode === 'dark' ? '#333' : '#e0e0e0')}; + border-bottom: 1px solid ${({ mode }) => (mode === 'dark' ? '#080808ff' : '#e0e0e0')}; `; const ProjectName = styled.b<{ mode: 'light' | 'dark' }>` From c955ae339a0faacbe7c14ad8cc9c869625c52b14 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 17:16:41 +0530 Subject: [PATCH 35/76] feat: sync dark mode divider bg --- src/context/theme-provider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/context/theme-provider.tsx b/src/context/theme-provider.tsx index 748d36d1..26e77298 100644 --- a/src/context/theme-provider.tsx +++ b/src/context/theme-provider.tsx @@ -230,7 +230,7 @@ const darkTheme = createTheme({ MuiDivider: { styleOverrides: { root: { - borderColor: 'rgba(255, 255, 255, 0.12)', + borderColor: '#080808ff', }, }, }, From 87ddfbd56df781728b25203a710e8487f518af5c Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 17:17:13 +0530 Subject: [PATCH 36/76] feat: sync dark mode table cell border bottom --- src/context/theme-provider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/context/theme-provider.tsx b/src/context/theme-provider.tsx index 26e77298..4d9f8bb6 100644 --- a/src/context/theme-provider.tsx +++ b/src/context/theme-provider.tsx @@ -223,7 +223,7 @@ const darkTheme = createTheme({ MuiTableCell: { styleOverrides: { root: { - borderBottom: '1px solid rgba(255, 255, 255, 0.12)', + borderBottom: '1px solid #080808ff', }, }, }, From d5668e5da73de024dedfeb0621e36e0069732cb6 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 17:18:16 +0530 Subject: [PATCH 37/76] feat: inherit bg btn dark mode --- src/context/theme-provider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/context/theme-provider.tsx b/src/context/theme-provider.tsx index 4d9f8bb6..21b79504 100644 --- a/src/context/theme-provider.tsx +++ b/src/context/theme-provider.tsx @@ -112,7 +112,7 @@ const darkTheme = createTheme({ color: '#ffffff', "&:hover": { borderColor: '#ffffff', - backgroundColor: 'rgba(255, 255, 255, 0.08)', + backgroundColor: 'inherit', }, }, }, From 44d713fd5d6ed3cced4f22946f783291f04e480d Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 17:18:48 +0530 Subject: [PATCH 38/76] feat: change dark theme border color paper --- src/context/theme-provider.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/context/theme-provider.tsx b/src/context/theme-provider.tsx index 21b79504..ccc4fda1 100644 --- a/src/context/theme-provider.tsx +++ b/src/context/theme-provider.tsx @@ -203,6 +203,7 @@ const darkTheme = createTheme({ styleOverrides: { root: { backgroundColor: '#080808ff', + border: '1px solid #121111ff', }, }, }, From f0d808c29b02d36a807ba0a0ac5676c74afb2921 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 17:25:48 +0530 Subject: [PATCH 39/76] fix: match border bottom clr --- src/components/dashboard/NavBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/dashboard/NavBar.tsx b/src/components/dashboard/NavBar.tsx index 7073b071..5910e9b5 100644 --- a/src/components/dashboard/NavBar.tsx +++ b/src/components/dashboard/NavBar.tsx @@ -605,7 +605,7 @@ const NavBarWrapper = styled.div<{ mode: 'light' | 'dark' }>` padding: 5px; display: flex; justify-content: space-between; - border-bottom: 1px solid ${({ mode }) => (mode === 'dark' ? '#080808ff' : '#e0e0e0')}; + border-bottom: 1px solid ${({ mode }) => (mode === 'dark' ? '#121111ff' : '#e0e0e0')}; `; const ProjectName = styled.b<{ mode: 'light' | 'dark' }>` From 341602a91570f1e9e99e4501a6cccfbe9503cdad Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 17:26:52 +0530 Subject: [PATCH 40/76] feat: inherit bg --- src/pages/Login.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx index 2d34bd81..da036a17 100644 --- a/src/pages/Login.tsx +++ b/src/pages/Login.tsx @@ -80,7 +80,7 @@ const Login = () => { maxHeight: "100vh", mt: 6, padding: 4, - backgroundColor: darkMode ? "#121212" : "#ffffff", + backgroundColor: "inherit", }} > Date: Mon, 13 Oct 2025 17:27:41 +0530 Subject: [PATCH 41/76] feat: -rm mt --- src/pages/Register.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/Register.tsx b/src/pages/Register.tsx index bc4faf27..ca049391 100644 --- a/src/pages/Register.tsx +++ b/src/pages/Register.tsx @@ -71,7 +71,6 @@ const Register = () => { justifyContent: "center", alignItems: "center", maxHeight: "100vh", - mt: 6, padding: 4, backgroundColor: darkMode ? "#121212" : "#ffffff", }} From f0542a4a7640ba459c3ba2b43a652d9480ffbf83 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 17:28:32 +0530 Subject: [PATCH 42/76] feat: change card color --- src/pages/Register.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/Register.tsx b/src/pages/Register.tsx index ca049391..e4b78e64 100644 --- a/src/pages/Register.tsx +++ b/src/pages/Register.tsx @@ -80,7 +80,7 @@ const Register = () => { onSubmit={submitForm} sx={{ textAlign: "center", - backgroundColor: darkMode ? "#1e1e1e" : "#ffffff", + backgroundColor: darkMode ? "#121111ff" : "#ffffff", color: darkMode ? "#ffffff" : "#333333", padding: 6, borderRadius: 5, From ba8a5a12294cb340f694c9e83a54d0e0d9772f82 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 17:28:49 +0530 Subject: [PATCH 43/76] feat: inherit bg --- src/pages/Register.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/Register.tsx b/src/pages/Register.tsx index e4b78e64..850559e9 100644 --- a/src/pages/Register.tsx +++ b/src/pages/Register.tsx @@ -72,7 +72,7 @@ const Register = () => { alignItems: "center", maxHeight: "100vh", padding: 4, - backgroundColor: darkMode ? "#121212" : "#ffffff", + backgroundColor: "inherit", }} > Date: Mon, 13 Oct 2025 17:29:21 +0530 Subject: [PATCH 44/76] feat: inherit bg --- src/pages/Login.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx index da036a17..ed84c211 100644 --- a/src/pages/Login.tsx +++ b/src/pages/Login.tsx @@ -88,7 +88,7 @@ const Login = () => { onSubmit={submitForm} sx={{ textAlign: "center", - backgroundColor: darkMode ? "#1e1e1e" : "#ffffff", + backgroundColor: darkMode ? "#121111ff" : "#ffffff", color: darkMode ? "#ffffff" : "#333333", padding: 6, borderRadius: 5, From 552dc4b4169379c52efcb20fa8723bbc7bac654d Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 17:33:29 +0530 Subject: [PATCH 45/76] feat: larger logo --- src/pages/Register.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pages/Register.tsx b/src/pages/Register.tsx index 850559e9..41ac133e 100644 --- a/src/pages/Register.tsx +++ b/src/pages/Register.tsx @@ -71,6 +71,7 @@ const Register = () => { justifyContent: "center", alignItems: "center", maxHeight: "100vh", + mt: 6, padding: 4, backgroundColor: "inherit", }} @@ -96,8 +97,8 @@ const Register = () => { logo Date: Mon, 13 Oct 2025 17:33:45 +0530 Subject: [PATCH 46/76] feat: larger logo --- src/pages/Login.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx index ed84c211..dd0d0b03 100644 --- a/src/pages/Login.tsx +++ b/src/pages/Login.tsx @@ -100,7 +100,8 @@ const Login = () => { width: "100%", }} > - logo + logo {t('login.title')} From 180e5718e9dd5af1a858f0cf16cb3f2fb01c72ae Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 17:41:12 +0530 Subject: [PATCH 47/76] feat: change background of recorder in dm --- src/pages/RecordingPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/RecordingPage.tsx b/src/pages/RecordingPage.tsx index 7dbed8b2..6e362471 100644 --- a/src/pages/RecordingPage.tsx +++ b/src/pages/RecordingPage.tsx @@ -61,7 +61,7 @@ export const RecordingPage = ({ recordingName }: RecordingPageProps) => { useEffect(() => { if (darkMode) { - document.body.style.background = 'rgba(18,18,18,1)'; + document.body.style.background = '#080808ff'; } else { document.body.style.background = 'radial-gradient(circle, rgba(255, 255, 255, 1) 0%, rgba(232, 191, 222, 1) 100%, rgba(255, 255, 255, 1) 100%)'; From db6e7d62cf23773d1ba499e8ded01e6f886fa770 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 17:46:18 +0530 Subject: [PATCH 48/76] feat: change bg browser tabs dm --- src/components/browser/BrowserTabs.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/browser/BrowserTabs.tsx b/src/components/browser/BrowserTabs.tsx index f34fda37..3a721f4b 100644 --- a/src/components/browser/BrowserTabs.tsx +++ b/src/components/browser/BrowserTabs.tsx @@ -49,7 +49,7 @@ export const BrowserTabs = ( background: 'white', borderRadius: '5px 5px 0px 0px', '&.Mui-selected': { - backgroundColor: ` ${isDarkMode ? "#2a2a2a" : "#f5f5f5"}`, + backgroundColor: ` ${isDarkMode ? "121111ff" : "#f5f5f5"}`, color: '#ff00c3', // Slightly lighter text when selected }, }} From b78a21ec1748b9d11e345244e2385013df401e95 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 17:46:52 +0530 Subject: [PATCH 49/76] feat: sync bg browser nav dm --- src/components/browser/BrowserNavBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/browser/BrowserNavBar.tsx b/src/components/browser/BrowserNavBar.tsx index a06b7b4e..8df8df10 100644 --- a/src/components/browser/BrowserNavBar.tsx +++ b/src/components/browser/BrowserNavBar.tsx @@ -14,7 +14,7 @@ import { useThemeMode } from '../../context/theme-provider'; const StyledNavBar = styled.div<{ browserWidth: number; isDarkMode: boolean }>` display: flex; padding: 12px 0px; - background-color: ${({ isDarkMode }) => (isDarkMode ? '#2C2F33' : '#f6f6f6')}; + background-color: ${({ isDarkMode }) => (isDarkMode ? '#1d1c1cff' : '#f6f6f6')}; width: ${({ browserWidth }) => browserWidth}px; border-radius: 0px 5px 0px 0px; `; From 1b68ec84bd3a0a363786259b5450d91216a9d0e1 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 17:47:03 +0530 Subject: [PATCH 50/76] feat: sync bg browser nav dm --- src/components/browser/BrowserNavBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/browser/BrowserNavBar.tsx b/src/components/browser/BrowserNavBar.tsx index 8df8df10..f5ee382d 100644 --- a/src/components/browser/BrowserNavBar.tsx +++ b/src/components/browser/BrowserNavBar.tsx @@ -20,7 +20,7 @@ const StyledNavBar = styled.div<{ browserWidth: number; isDarkMode: boolean }>` `; const IconButton = styled(NavBarButton) <{ mode: string }>` - background-color: ${({ mode }) => (mode === 'dark' ? '#2C2F33' : '#f6f6f6')}; + background-color: ${({ mode }) => (mode === 'dark' ? '1d1c1cff' : '#f6f6f6')}; transition: background-color 0.3s ease, transform 0.1s ease; color: ${({ mode }) => (mode === 'dark' ? '#FFFFFF' : '#333')}; cursor: pointer; From c8582c6426c5254723bf963b7363e810c7915c16 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 17:47:26 +0530 Subject: [PATCH 51/76] feat: sync bg browser nav dm --- src/components/browser/BrowserNavBar.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/browser/BrowserNavBar.tsx b/src/components/browser/BrowserNavBar.tsx index f5ee382d..e651ed26 100644 --- a/src/components/browser/BrowserNavBar.tsx +++ b/src/components/browser/BrowserNavBar.tsx @@ -20,12 +20,12 @@ const StyledNavBar = styled.div<{ browserWidth: number; isDarkMode: boolean }>` `; const IconButton = styled(NavBarButton) <{ mode: string }>` - background-color: ${({ mode }) => (mode === 'dark' ? '1d1c1cff' : '#f6f6f6')}; + background-color: ${({ mode }) => (mode === 'dark' ? '#1d1c1cff' : '#f6f6f6')}; transition: background-color 0.3s ease, transform 0.1s ease; color: ${({ mode }) => (mode === 'dark' ? '#FFFFFF' : '#333')}; cursor: pointer; &:hover { - background-color: ${({ mode }) => (mode === 'dark' ? '#586069' : '#D0D0D0')}; + background-color: ${({ mode }) => (mode === 'dark' ? '#1d1c1cff' : '#D0D0D0')}; } `; From bdf726dcc5c892ba6fdbceb7e6a70d1176145377 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 17:49:14 +0530 Subject: [PATCH 52/76] feat: sync action description box dark mode bg --- src/components/action/ActionDescriptionBox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/action/ActionDescriptionBox.tsx b/src/components/action/ActionDescriptionBox.tsx index d36db407..e8c11cd5 100644 --- a/src/components/action/ActionDescriptionBox.tsx +++ b/src/components/action/ActionDescriptionBox.tsx @@ -16,7 +16,7 @@ const CustomBoxContainer = styled.div` min-height: 100px; height: auto; border-radius: 5px; - background-color: ${({ isDarkMode }) => (isDarkMode ? '#313438' : 'white')}; + background-color: ${({ isDarkMode }) => (isDarkMode ? '#1d1c1cff' : 'white')}; color: ${({ isDarkMode }) => (isDarkMode ? 'white' : 'black')}; margin: 80px 13px 25px 13px; box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.1); From 242c73f46eafb2d794a7bf1f4c6b1c3672a0ddee Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 17:49:29 +0530 Subject: [PATCH 53/76] feat: sync action description box dark mode bg --- src/components/action/ActionDescriptionBox.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/action/ActionDescriptionBox.tsx b/src/components/action/ActionDescriptionBox.tsx index e8c11cd5..ac730b06 100644 --- a/src/components/action/ActionDescriptionBox.tsx +++ b/src/components/action/ActionDescriptionBox.tsx @@ -31,7 +31,7 @@ const Triangle = styled.div` height: 0; border-left: 20px solid transparent; border-right: 20px solid transparent; - border-bottom: 20px solid ${({ isDarkMode }) => (isDarkMode ? '#313438' : 'white')}; + border-bottom: 20px solid ${({ isDarkMode }) => (isDarkMode ? '#1d1c1cff' : 'white')}; `; const Logo = styled.img` From f61daeec3dfd07e431eb40a69fb0d1d1aea982e2 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 17:50:38 +0530 Subject: [PATCH 54/76] feat: remove unwanted textfield capture text sx styles --- src/components/recorder/RightSidePanel.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/recorder/RightSidePanel.tsx b/src/components/recorder/RightSidePanel.tsx index bf0a10c4..1938a2ee 100644 --- a/src/components/recorder/RightSidePanel.tsx +++ b/src/components/recorder/RightSidePanel.tsx @@ -1080,7 +1080,6 @@ export const RightSidePanel: React.FC = ({ onFinishCapture ) }} - sx={{ background: isDarkMode ? "#1E2124" : 'white', color: isDarkMode ? "white" : 'black' }} /> Date: Mon, 13 Oct 2025 17:52:09 +0530 Subject: [PATCH 55/76] feat: capture actions box dark mode bg --- src/components/recorder/RightSidePanel.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/recorder/RightSidePanel.tsx b/src/components/recorder/RightSidePanel.tsx index 1938a2ee..037e32c4 100644 --- a/src/components/recorder/RightSidePanel.tsx +++ b/src/components/recorder/RightSidePanel.tsx @@ -1059,7 +1059,7 @@ export const RightSidePanel: React.FC = ({ onFinishCapture {browserSteps.map(step => ( - handleMouseEnter(step.id)} onMouseLeave={() => handleMouseLeave(step.id)} sx={{ padding: '10px', margin: '11px', borderRadius: '5px', position: 'relative', background: isDarkMode ? "#1E2124" : 'white', color: isDarkMode ? "white" : 'black' }}> + handleMouseEnter(step.id)} onMouseLeave={() => handleMouseLeave(step.id)} sx={{ padding: '10px', margin: '11px', borderRadius: '5px', position: 'relative', background: isDarkMode ? "#1d1c1cff" : 'white', color: isDarkMode ? "white" : 'black' }}> { step.type === 'text' && ( <> From 270782917fbe35ea1049cd899dac02fa6a08a765 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 17:56:02 +0530 Subject: [PATCH 56/76] feat: sync dark mode bg output preview --- src/components/run/InterpretationLog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/run/InterpretationLog.tsx b/src/components/run/InterpretationLog.tsx index faf965e9..d0382120 100644 --- a/src/components/run/InterpretationLog.tsx +++ b/src/components/run/InterpretationLog.tsx @@ -193,7 +193,7 @@ export const InterpretationLog: React.FC = ({ isOpen, se onOpen={toggleDrawer(true)} PaperProps={{ sx: { - background: `${darkMode ? '#1e2124' : 'white'}`, + background: `${darkMode ? '#1d1c1cff' : 'white'}`, color: `${darkMode ? 'white' : 'black'}`, padding: '10px', height: outputPreviewHeight, From 6108629ff9615a82acbf92bfc2870bba24941bd7 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 17:56:54 +0530 Subject: [PATCH 57/76] feat: remove unwated styled --- src/components/run/InterpretationLog.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/run/InterpretationLog.tsx b/src/components/run/InterpretationLog.tsx index d0382120..ec6a9d9b 100644 --- a/src/components/run/InterpretationLog.tsx +++ b/src/components/run/InterpretationLog.tsx @@ -216,8 +216,6 @@ export const InterpretationLog: React.FC = ({ isOpen, se sx={{ display: 'flex', borderBottom: '1px solid', - borderColor: darkMode ? '#3a4453' : '#dee2e6', - backgroundColor: darkMode ? '#2a3441' : '#f8f9fa' }} > {availableTabs.map((tab, index) => ( From da50be7d8c3dfc51b649e331d47b700c8d7f6b39 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 17:59:48 +0530 Subject: [PATCH 58/76] feat: output preview revamp --- src/components/run/InterpretationLog.tsx | 60 +++++++++++++++--------- 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/src/components/run/InterpretationLog.tsx b/src/components/run/InterpretationLog.tsx index ec6a9d9b..c0c9d8fd 100644 --- a/src/components/run/InterpretationLog.tsx +++ b/src/components/run/InterpretationLog.tsx @@ -22,9 +22,10 @@ import { useBrowserSteps } from '../../context/browserSteps'; interface InterpretationLogProps { isOpen: boolean; setIsOpen: (isOpen: boolean) => void; + tutorialMode?: boolean; } -export const InterpretationLog: React.FC = ({ isOpen, setIsOpen }) => { +export const InterpretationLog: React.FC = ({ isOpen, setIsOpen, tutorialMode = false }) => { const { t } = useTranslation(); const [captureListData, setCaptureListData] = useState([]); @@ -68,6 +69,7 @@ export const InterpretationLog: React.FC = ({ isOpen, se } }, [captureListData.length, captureTextData.length, screenshotData.length]); + useEffect(() => { const textSteps = browserSteps.filter(step => step.type === 'text'); if (textSteps.length > 0) { @@ -144,6 +146,16 @@ export const InterpretationLog: React.FC = ({ isOpen, se } }, [hasScrapeListAction, hasScrapeSchemaAction, hasScreenshotAction, setIsOpen]); + useEffect(() => { + if ( + tutorialMode && + (hasScrapeListAction || hasScrapeSchemaAction || hasScreenshotAction) + ) { + setShowPreviewData(true); + setIsOpen(true); // auto-open drawer + } + }, [tutorialMode, hasScrapeListAction, hasScrapeSchemaAction, hasScreenshotAction, setIsOpen]); + const { darkMode } = useThemeMode(); const getCaptureTextColumns = captureTextData.length > 0 ? Object.keys(captureTextData[0]) : []; @@ -216,6 +228,8 @@ export const InterpretationLog: React.FC = ({ isOpen, se sx={{ display: 'flex', borderBottom: '1px solid', + borderColor: darkMode ? '#080808ff' : '#dee2e6', + backgroundColor: darkMode ? '#080808ff' : '#f8f9fa' }} > {availableTabs.map((tab, index) => ( @@ -226,15 +240,15 @@ export const InterpretationLog: React.FC = ({ isOpen, se px: 4, py: 2, cursor: 'pointer', - borderBottom: activeTab === index ? '2px solid' : 'none', + // borderBottom: activeTab === index ? '2px solid' : 'none', borderColor: activeTab === index ? (darkMode ? '#ff00c3' : '#ff00c3') : 'transparent', - backgroundColor: activeTab === index ? (darkMode ? '#34404d' : '#e9ecef') : 'transparent', + backgroundColor: activeTab === index ? (darkMode ? '#121111ff' : '#e9ecef') : 'transparent', color: darkMode ? 'white' : 'black', fontWeight: activeTab === index ? 500 : 400, textAlign: 'center', position: 'relative', '&:hover': { - backgroundColor: activeTab !== index ? (darkMode ? '#303b49' : '#e2e6ea') : undefined + backgroundColor: activeTab !== index ? (darkMode ? '#121111ff' : '#e2e6ea') : undefined } }} > @@ -286,8 +300,8 @@ export const InterpretationLog: React.FC = ({ isOpen, se key={index} sx={{ borderBottom: '1px solid', - borderColor: darkMode ? '#3a4453' : '#dee2e6', - backgroundColor: darkMode ? '#2a3441' : '#f8f9fa' + borderColor: darkMode ? '#080808ff' : '#dee2e6', + backgroundColor: darkMode ? '#080808ff' : '#f8f9fa' }} > {field.label} @@ -297,16 +311,16 @@ export const InterpretationLog: React.FC = ({ isOpen, se {(captureListData[captureListPage]?.data || []) - .slice(0, Math.min(captureListData[captureListPage]?.limit || 10, 5)) + .slice(0, tutorialMode ? (captureListData[captureListPage]?.data?.length || 0) : Math.min(captureListData[captureListPage]?.limit || 10, 5)) .map((row: any, rowIndex: any) => ( - {Object.values(captureListData[captureListPage]?.fields || {}).map((field: any, colIndex) => ( @@ -317,7 +331,7 @@ export const InterpretationLog: React.FC = ({ isOpen, se py: 2 }} > - {row[field.label]} + {typeof row[field.label] === 'object' ? JSON.stringify(row[field.label]) : String(row[field.label] || '')} ))} @@ -377,7 +391,7 @@ export const InterpretationLog: React.FC = ({ isOpen, se )} {(activeTab === availableTabs.findIndex(tab => tab.id === 'captureText') || singleContentType === 'captureText') && captureTextData.length > 0 && ( - + @@ -385,8 +399,8 @@ export const InterpretationLog: React.FC = ({ isOpen, se Label @@ -394,8 +408,8 @@ export const InterpretationLog: React.FC = ({ isOpen, se Value @@ -408,7 +422,7 @@ export const InterpretationLog: React.FC = ({ isOpen, se key={column} sx={{ borderBottom: index < getCaptureTextColumns.length - 1 ? '1px solid' : 'none', - borderColor: darkMode ? '#3a4453' : '#dee2e6' + borderColor: darkMode ? '#080808ff' : '#dee2e6' }} > = ({ isOpen, se py: 2 }} > - {captureTextData[0][column]} + {typeof captureTextData[0][column] === 'object' ? JSON.stringify(captureTextData[0][column]) : String(captureTextData[0][column] || '')} ))} @@ -445,7 +459,9 @@ export const InterpretationLog: React.FC = ({ isOpen, se {t('interpretation_log.messages.successful_training')} - setShowPreviewData(true)} /> + {!tutorialMode && ( + setShowPreviewData(true)} /> + )} ) : ( From 60b96596cd201545c6f6d7e11901168bf494cfb8 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 18:00:59 +0530 Subject: [PATCH 59/76] feat: sync dark mode w cloud --- src/context/theme-provider.tsx | 36 +++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/src/context/theme-provider.tsx b/src/context/theme-provider.tsx index ccc4fda1..1bff81f7 100644 --- a/src/context/theme-provider.tsx +++ b/src/context/theme-provider.tsx @@ -94,7 +94,7 @@ const darkTheme = createTheme({ }, background: { default: '#000000ff', - paper: '#080808ff', + paper: '#000000ff', }, text: { primary: '#ffffff', @@ -127,14 +127,14 @@ const darkTheme = createTheme({ borderColor: '#ff00c3', color: '#ff00c3', "&:hover": { - backgroundColor: 'rgba(255, 0, 195, 0.08)', + // backgroundColor: 'rgba(255, 0, 195, 0.08)', borderColor: '#ff66d9', }, '&.MuiButton-outlinedError': { borderColor: '#f44336', color: '#f44336', "&:hover": { - backgroundColor: 'rgba(244, 67, 54, 0.08)', + // backgroundColor: 'rgba(244, 67, 54, 0.08)', borderColor: '#d32f2f', }, }, @@ -155,14 +155,14 @@ const darkTheme = createTheme({ styleOverrides: { root: { color: '#ffffff', - "&:hover": { - backgroundColor: 'rgba(255, 0, 195, 0.08)', - }, + // "&:hover": { + // backgroundColor: 'rgba(255, 0, 195, 0.08)', + // }, '&.MuiIconButton-colorError': { color: '#f44336', - "&:hover": { - backgroundColor: 'rgba(244, 67, 54, 0.08)', - }, + // "&:hover": { + // backgroundColor: 'rgba(244, 67, 54, 0.08)', + // }, }, }, }, @@ -181,7 +181,7 @@ const darkTheme = createTheme({ MuiAlert: { styleOverrides: { standardInfo: { - backgroundColor: "rgba(255, 0, 195, 0.15)", + // backgroundColor: "rgba(255, 0, 195, 0.15)", color: "#ff66d9", "& .MuiAlert-icon": { color: "#ff66d9", @@ -202,8 +202,8 @@ const darkTheme = createTheme({ MuiPaper: { styleOverrides: { root: { - backgroundColor: '#080808ff', - border: '1px solid #121111ff', + backgroundColor: '#000000ff', + border: '1px solid #080808ff', }, }, }, @@ -231,10 +231,18 @@ const darkTheme = createTheme({ MuiDivider: { styleOverrides: { root: { - borderColor: '#080808ff', + borderColor: '#494949ff', }, }, }, + // MuiTextField:{ + // styleOverrides: { + // root: { + // '& .MuiInputBase-root': { + // backgroundColor: '#1d1c1cff', + // }, + // } + // }} }, }); @@ -274,4 +282,4 @@ const ThemeModeProvider = ({ children }: { children: React.ReactNode }) => { ); }; -export default ThemeModeProvider; +export default ThemeModeProvider; \ No newline at end of file From fcf1f68177c93e144aed4c96363c1401aca46271 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 18:02:11 +0530 Subject: [PATCH 60/76] feat: use divider instead of hr --- src/components/dashboard/MainMenu.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/dashboard/MainMenu.tsx b/src/components/dashboard/MainMenu.tsx index 05846b75..2cfaab03 100644 --- a/src/components/dashboard/MainMenu.tsx +++ b/src/components/dashboard/MainMenu.tsx @@ -3,7 +3,7 @@ import Tabs from '@mui/material/Tabs'; import Tab from '@mui/material/Tab'; import Box from '@mui/material/Box'; import { useNavigate, useLocation } from 'react-router-dom'; -import { Paper, Button, useTheme, Modal, Typography, Stack, TextField, InputAdornment, IconButton } from "@mui/material"; +import { Paper, Button, useTheme, Modal, Typography, Stack, TextField, InputAdornment, IconButton, Divider } from "@mui/material"; import { AutoAwesome, FormatListBulleted, VpnKey, Usb, CloudQueue, Description, Favorite, ContentCopy, SlowMotionVideo } from "@mui/icons-material"; import { useTranslation } from 'react-i18next'; import { useGlobalInfoStore } from "../../context/globalInfo"; @@ -94,7 +94,7 @@ export const MainMenu = ({ value = 'robots', handleChangeContent }: MainMenuProp } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} /> } iconPosition="start" sx={{ justifyContent: 'flex-start', textAlign: 'left', fontSize: 'medium' }} /> -
+
- + {/* */} {columns.map((column) => ( ))} - + {/* */} {visibleRows.map((row) => ( Date: Mon, 13 Oct 2025 18:05:53 +0530 Subject: [PATCH 64/76] fix: background color override for mui alert dark theme --- src/context/theme-provider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/context/theme-provider.tsx b/src/context/theme-provider.tsx index 1bff81f7..ef16069f 100644 --- a/src/context/theme-provider.tsx +++ b/src/context/theme-provider.tsx @@ -181,7 +181,7 @@ const darkTheme = createTheme({ MuiAlert: { styleOverrides: { standardInfo: { - // backgroundColor: "rgba(255, 0, 195, 0.15)", + backgroundColor: "rgba(255, 0, 195, 0.15)", color: "#ff66d9", "& .MuiAlert-icon": { color: "#ff66d9", From 820444218dc72555d288ef8cfbd70c03a0f2af86 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 20:04:06 +0530 Subject: [PATCH 65/76] fix: missing # --- src/components/browser/BrowserTabs.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/browser/BrowserTabs.tsx b/src/components/browser/BrowserTabs.tsx index 3a721f4b..e375fb93 100644 --- a/src/components/browser/BrowserTabs.tsx +++ b/src/components/browser/BrowserTabs.tsx @@ -49,7 +49,7 @@ export const BrowserTabs = ( background: 'white', borderRadius: '5px 5px 0px 0px', '&.Mui-selected': { - backgroundColor: ` ${isDarkMode ? "121111ff" : "#f5f5f5"}`, + backgroundColor: ` ${isDarkMode ? "#121111ff" : "#f5f5f5"}`, color: '#ff00c3', // Slightly lighter text when selected }, }} From 0f771bba258805c0eb6f4ae27817b5e8e3721a02 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 20:07:15 +0530 Subject: [PATCH 66/76] fix: -rm tutorial mode --- src/components/run/InterpretationLog.tsx | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/src/components/run/InterpretationLog.tsx b/src/components/run/InterpretationLog.tsx index c0c9d8fd..7180014b 100644 --- a/src/components/run/InterpretationLog.tsx +++ b/src/components/run/InterpretationLog.tsx @@ -22,10 +22,9 @@ import { useBrowserSteps } from '../../context/browserSteps'; interface InterpretationLogProps { isOpen: boolean; setIsOpen: (isOpen: boolean) => void; - tutorialMode?: boolean; } -export const InterpretationLog: React.FC = ({ isOpen, setIsOpen, tutorialMode = false }) => { +export const InterpretationLog: React.FC = ({ isOpen, setIsOpen }) => { const { t } = useTranslation(); const [captureListData, setCaptureListData] = useState([]); @@ -146,15 +145,6 @@ export const InterpretationLog: React.FC = ({ isOpen, se } }, [hasScrapeListAction, hasScrapeSchemaAction, hasScreenshotAction, setIsOpen]); - useEffect(() => { - if ( - tutorialMode && - (hasScrapeListAction || hasScrapeSchemaAction || hasScreenshotAction) - ) { - setShowPreviewData(true); - setIsOpen(true); // auto-open drawer - } - }, [tutorialMode, hasScrapeListAction, hasScrapeSchemaAction, hasScreenshotAction, setIsOpen]); const { darkMode } = useThemeMode(); @@ -311,14 +301,13 @@ export const InterpretationLog: React.FC = ({ isOpen, se {(captureListData[captureListPage]?.data || []) - .slice(0, tutorialMode ? (captureListData[captureListPage]?.data?.length || 0) : Math.min(captureListData[captureListPage]?.limit || 10, 5)) + .slice(0, Math.min(captureListData[captureListPage]?.limit || 10, 5)) .map((row: any, rowIndex: any) => ( = ({ isOpen, se {t('interpretation_log.messages.successful_training')} - {!tutorialMode && ( - setShowPreviewData(true)} /> - )} ) : ( From 3f0e252638f911b7b89ede0f8ed5c93e4a833e75 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 20:23:28 +0530 Subject: [PATCH 67/76] fix: output preview button --- src/components/run/InterpretationLog.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/run/InterpretationLog.tsx b/src/components/run/InterpretationLog.tsx index 7180014b..49e4a704 100644 --- a/src/components/run/InterpretationLog.tsx +++ b/src/components/run/InterpretationLog.tsx @@ -448,6 +448,7 @@ export const InterpretationLog: React.FC = ({ isOpen, se {t('interpretation_log.messages.successful_training')} + setShowPreviewData(true)} /> ) : ( From bf2882fc353587351f839a288d32aa064d69276f Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 20:34:03 +0530 Subject: [PATCH 68/76] feat: remove language typography --- src/components/dashboard/NavBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/dashboard/NavBar.tsx b/src/components/dashboard/NavBar.tsx index 24e11d09..41398e6d 100644 --- a/src/components/dashboard/NavBar.tsx +++ b/src/components/dashboard/NavBar.tsx @@ -519,7 +519,7 @@ export const NavBar: React.FC = ({ marginRight: "8px", }} > - {t("Language")} + Date: Mon, 13 Oct 2025 20:36:51 +0530 Subject: [PATCH 69/76] feat: !margin --- src/components/dashboard/NavBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/dashboard/NavBar.tsx b/src/components/dashboard/NavBar.tsx index 41398e6d..798db433 100644 --- a/src/components/dashboard/NavBar.tsx +++ b/src/components/dashboard/NavBar.tsx @@ -519,7 +519,7 @@ export const NavBar: React.FC = ({ marginRight: "8px", }} > - + Date: Mon, 13 Oct 2025 20:38:02 +0530 Subject: [PATCH 70/76] feat: reduce margin right --- src/components/dashboard/NavBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/dashboard/NavBar.tsx b/src/components/dashboard/NavBar.tsx index 798db433..c72c4f69 100644 --- a/src/components/dashboard/NavBar.tsx +++ b/src/components/dashboard/NavBar.tsx @@ -516,7 +516,7 @@ export const NavBar: React.FC = ({ alignItems: "center", borderRadius: "5px", padding: "8px", - marginRight: "8px", + marginRight: "-4px", }} > From 524c0c6ba92b771691fa4341f7459fa971567855 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 20:38:53 +0530 Subject: [PATCH 71/76] feat: use translate iocn --- src/components/dashboard/NavBar.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/dashboard/NavBar.tsx b/src/components/dashboard/NavBar.tsx index c72c4f69..ea49e1cf 100644 --- a/src/components/dashboard/NavBar.tsx +++ b/src/components/dashboard/NavBar.tsx @@ -30,7 +30,8 @@ import { Language, Description, LightMode, - DarkMode + DarkMode, + Translate } from "@mui/icons-material"; import { useNavigate } from 'react-router-dom'; import { AuthContext } from '../../context/auth'; @@ -519,7 +520,7 @@ export const NavBar: React.FC = ({ marginRight: "-4px", }} > - + Date: Mon, 13 Oct 2025 20:39:07 +0530 Subject: [PATCH 72/76] feat: use translate icon --- src/components/dashboard/NavBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/dashboard/NavBar.tsx b/src/components/dashboard/NavBar.tsx index ea49e1cf..7a1247fe 100644 --- a/src/components/dashboard/NavBar.tsx +++ b/src/components/dashboard/NavBar.tsx @@ -395,7 +395,7 @@ export const NavBar: React.FC = ({ {t('navbar.menu_items.logout')} - {t('navbar.menu_items.language')} + {t('navbar.menu_items.language')}
{ From 4e6a2c3a96f71e77ab030e7aa72595767fc71728 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 20:40:04 +0530 Subject: [PATCH 73/76] fix: proper margin b/w icons --- src/components/dashboard/NavBar.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/dashboard/NavBar.tsx b/src/components/dashboard/NavBar.tsx index 7a1247fe..941eb89f 100644 --- a/src/components/dashboard/NavBar.tsx +++ b/src/components/dashboard/NavBar.tsx @@ -517,10 +517,10 @@ export const NavBar: React.FC = ({ alignItems: "center", borderRadius: "5px", padding: "8px", - marginRight: "-4px", + marginRight: "4px", }} > - + Date: Tue, 14 Oct 2025 20:39:12 +0530 Subject: [PATCH 74/76] chore: remove unused import --- src/components/dashboard/NavBar.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/dashboard/NavBar.tsx b/src/components/dashboard/NavBar.tsx index 941eb89f..c97dbf10 100644 --- a/src/components/dashboard/NavBar.tsx +++ b/src/components/dashboard/NavBar.tsx @@ -27,7 +27,6 @@ import { GitHub, Update, Close, - Language, Description, LightMode, DarkMode, From 4860f790dbc7b0b4feddda4c60cef9a38636e1ee Mon Sep 17 00:00:00 2001 From: Karishma Date: Tue, 14 Oct 2025 20:39:36 +0530 Subject: [PATCH 75/76] fix: larger logo --- src/components/dashboard/NavBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/dashboard/NavBar.tsx b/src/components/dashboard/NavBar.tsx index c97dbf10..c9fef007 100644 --- a/src/components/dashboard/NavBar.tsx +++ b/src/components/dashboard/NavBar.tsx @@ -236,7 +236,7 @@ export const NavBar: React.FC = ({ cursor: 'pointer' }} onClick={() => navigate('/')}> - +
{t('navbar.project_name')}
Date: Wed, 22 Oct 2025 01:06:13 +0530 Subject: [PATCH 76/76] feat: disable mui tabs indicator animation --- src/components/dashboard/MainMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/dashboard/MainMenu.tsx b/src/components/dashboard/MainMenu.tsx index 6fe6cf2e..f94936b2 100644 --- a/src/components/dashboard/MainMenu.tsx +++ b/src/components/dashboard/MainMenu.tsx @@ -87,7 +87,7 @@ export const MainMenu = ({ value = 'robots', handleChangeContent }: MainMenuProp textColor="primary" indicatorColor="primary" orientation="vertical" - sx={{ alignItems: 'flex-start' }} + sx={{ alignItems: 'flex-start', '& .MuiTabs-indicator': { display: 'none' }} >