From dc098025c6f69d88317db293dd077906e111e2b1 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Sat, 16 Nov 2024 22:49:48 +0530 Subject: [PATCH 01/16] feat: options column --- src/components/molecules/RecordingsTable.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/molecules/RecordingsTable.tsx b/src/components/molecules/RecordingsTable.tsx index c5895193..1531c0a7 100644 --- a/src/components/molecules/RecordingsTable.tsx +++ b/src/components/molecules/RecordingsTable.tsx @@ -26,7 +26,7 @@ import { GenericModal } from '../atoms/GenericModal'; */ interface Column { - id: 'interpret' | 'name' | 'delete' | 'schedule' | 'integrate' | 'settings'; + id: 'interpret' | 'name' | 'delete' | 'schedule' | 'integrate' | 'settings' | 'options'; label: string; minWidth?: number; align?: 'right'; @@ -73,6 +73,11 @@ const columns: readonly Column[] = [ label: 'Delete', minWidth: 80, }, + { + id: 'options', + label: 'Options', + minWidth: 80, + }, ]; interface Data { From e8762859ccb02318d8b8de5ea835b0ed32af7e8a Mon Sep 17 00:00:00 2001 From: RohitR311 Date: Sat, 16 Nov 2024 23:06:34 +0530 Subject: [PATCH 02/16] feat: dropdown for edit, delete, duplicate robot --- src/components/molecules/RecordingsTable.tsx | 104 ++++++++++++++----- 1 file changed, 79 insertions(+), 25 deletions(-) diff --git a/src/components/molecules/RecordingsTable.tsx b/src/components/molecules/RecordingsTable.tsx index 1531c0a7..71a67f52 100644 --- a/src/components/molecules/RecordingsTable.tsx +++ b/src/components/molecules/RecordingsTable.tsx @@ -9,8 +9,8 @@ import TablePagination from '@mui/material/TablePagination'; import TableRow from '@mui/material/TableRow'; import { useEffect } from "react"; import { WorkflowFile } from "maxun-core"; -import { IconButton, Button, Box, Typography, TextField } from "@mui/material"; -import { Schedule, DeleteForever, Edit, PlayCircle, Settings, Power } from "@mui/icons-material"; +import { IconButton, Button, Box, Typography, TextField, MenuItem, Menu, ListItemIcon, ListItemText } from "@mui/material"; +import { Schedule, DeleteForever, Edit, PlayCircle, Settings, Power, ContentCopy, } from "@mui/icons-material"; import LinkIcon from '@mui/icons-material/Link'; import { useGlobalInfoStore } from "../../context/globalInfo"; import { deleteRecordingFromStorage, getStoredRecordings } from "../../api/storage"; @@ -18,7 +18,7 @@ import { Add } from "@mui/icons-material"; import { useNavigate } from 'react-router-dom'; import { stopRecording } from "../../api/recording"; import { GenericModal } from '../atoms/GenericModal'; - +import { Menu as MenuIcon } from '@mui/icons-material'; /** TODO: * 1. allow editing existing robot after persisting browser steps @@ -26,7 +26,7 @@ import { GenericModal } from '../atoms/GenericModal'; */ interface Column { - id: 'interpret' | 'name' | 'delete' | 'schedule' | 'integrate' | 'settings' | 'options'; + id: 'interpret' | 'name' | 'options' | 'schedule' | 'integrate' | 'settings'; label: string; minWidth?: number; align?: 'right'; @@ -68,11 +68,6 @@ const columns: readonly Column[] = [ label: 'Settings', minWidth: 80, }, - { - id: 'delete', - label: 'Delete', - minWidth: 80, - }, { id: 'options', label: 'Options', @@ -253,22 +248,27 @@ export const RecordingsTable = ({ handleEditRecording, handleRunRecording, handl handleIntegrateRecording(row.id, row.name, row.params || [])} /> ); - case 'delete': - return ( - - { - deleteRecordingFromStorage(row.id).then((result: boolean) => { - if (result) { - setRows([]); - notify('success', 'Recording deleted successfully'); - fetchRecordings(); - } - }) - }}> - - - - ); + case 'options': + return ( + + handleEditRecording(row.id, row.name)} + handleDelete={() => { + deleteRecordingFromStorage(row.id).then((result: boolean) => { + if (result) { + setRows([]); + notify('success', 'Recording deleted successfully'); + fetchRecordings(); + } + }) + }} + handleDuplicate={() => { + notify('info', 'Duplicating recording...'); + // Implement duplication logic here + }} + /> + + ); case 'settings': return ( @@ -382,6 +382,60 @@ const SettingsButton = ({ handleSettings }: SettingsButtonProps) => { ) } +interface OptionsButtonProps { + handleEdit: () => void; + handleDelete: () => void; + handleDuplicate: () => void; +} + +const OptionsButton = ({ handleEdit, handleDelete, handleDuplicate }: OptionsButtonProps) => { + const [anchorEl, setAnchorEl] = React.useState(null); + + const handleClick = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + + const handleClose = () => { + setAnchorEl(null); + }; + + return ( + <> + + + + + { handleEdit(); handleClose(); }}> + + + + Edit + + { handleDelete(); handleClose(); }}> + + + + Delete + + { handleDuplicate(); handleClose(); }}> + + + + Duplicate + + + + ); +}; + const modalStyle = { top: '50%', left: '50%', From ee2c4b385ebf1e7d078a3e85da92999f8d681f84 Mon Sep 17 00:00:00 2001 From: RohitR311 Date: Sun, 17 Nov 2024 00:30:38 +0530 Subject: [PATCH 03/16] feat: add handle edit robot modal --- src/components/molecules/RecordingsTable.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/molecules/RecordingsTable.tsx b/src/components/molecules/RecordingsTable.tsx index 71a67f52..84df8d0e 100644 --- a/src/components/molecules/RecordingsTable.tsx +++ b/src/components/molecules/RecordingsTable.tsx @@ -90,9 +90,10 @@ interface RecordingsTableProps { handleScheduleRecording: (id: string, fileName: string, params: string[]) => void; handleIntegrateRecording: (id: string, fileName: string, params: string[]) => void; handleSettingsRecording: (id: string, fileName: string, params: string[]) => void; + handleEditRobot: (id: string, name: string, params: string[]) => void; } -export const RecordingsTable = ({ handleEditRecording, handleRunRecording, handleScheduleRecording, handleIntegrateRecording, handleSettingsRecording }: RecordingsTableProps) => { +export const RecordingsTable = ({ handleEditRecording, handleRunRecording, handleScheduleRecording, handleIntegrateRecording, handleSettingsRecording, handleEditRobot }: RecordingsTableProps) => { const [page, setPage] = React.useState(0); const [rowsPerPage, setRowsPerPage] = React.useState(10); const [rows, setRows] = React.useState([]); @@ -252,7 +253,7 @@ export const RecordingsTable = ({ handleEditRecording, handleRunRecording, handl return ( handleEditRecording(row.id, row.name)} + handleEdit={() => handleEditRobot(row.id, row.name, row.params || [])} handleDelete={() => { deleteRecordingFromStorage(row.id).then((result: boolean) => { if (result) { From 38bdf17317b93d4bfd682f9466dfda07a2ae3e75 Mon Sep 17 00:00:00 2001 From: RohitR311 Date: Sun, 17 Nov 2024 00:31:36 +0530 Subject: [PATCH 04/16] feat: added robot edit modal --- src/components/molecules/RobotEdit.tsx | 135 +++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 src/components/molecules/RobotEdit.tsx diff --git a/src/components/molecules/RobotEdit.tsx b/src/components/molecules/RobotEdit.tsx new file mode 100644 index 00000000..d5fdceb4 --- /dev/null +++ b/src/components/molecules/RobotEdit.tsx @@ -0,0 +1,135 @@ +import React, { useState, useEffect } from 'react'; +import { GenericModal } from "../atoms/GenericModal"; +import { TextField, Typography, Box, Button } from "@mui/material"; +import { modalStyle } from "./AddWhereCondModal"; +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 RobotEditModal = ({ isOpen, handleStart, handleClose, initialSettings }: RobotSettingsProps) => { + const [robot, setRobot] = useState(null); + const [userEmail, setUserEmail] = 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', 'Could not find robot details. Please try again.'); + } + } + + 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 ( + + <> + Edit Robot + + { + robot && ( + <> + + {robot.recording.workflow?.[0]?.what?.[0]?.args?.[0]?.limit && ( + + )} + + + + + + + ) + } + + + + ); +}; From 464aeefddba46e4b98a536c23ed58ff2c525c822 Mon Sep 17 00:00:00 2001 From: RohitR311 Date: Sun, 17 Nov 2024 00:33:23 +0530 Subject: [PATCH 05/16] feat: added robot edit modal --- src/components/organisms/Recordings.tsx | 28 +++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/components/organisms/Recordings.tsx b/src/components/organisms/Recordings.tsx index 053a3479..ecb2b769 100644 --- a/src/components/organisms/Recordings.tsx +++ b/src/components/organisms/Recordings.tsx @@ -5,6 +5,7 @@ import { RunSettings, RunSettingsModal } from "../molecules/RunSettings"; import { ScheduleSettings, ScheduleSettingsModal } from "../molecules/ScheduleSettings"; import { IntegrationSettings, IntegrationSettingsModal } from "../molecules/IntegrationSettings"; import { RobotSettings, RobotSettingsModal } from "../molecules/RobotSettings"; +import { RobotEditModal } from '../molecules/RobotEdit'; interface RecordingsProps { handleEditRecording: (id: string, fileName: string) => void; @@ -18,10 +19,12 @@ export const Recordings = ({ handleEditRecording, handleRunRecording, setRecordi const [scheduleSettingsAreOpen, setScheduleSettingsAreOpen] = useState(false); const [integrateSettingsAreOpen, setIntegrateSettingsAreOpen] = useState(false); const [robotSettingsAreOpen, setRobotSettingsAreOpen] = useState(false); + const [robotEditAreOpen, setRobotEditAreOpen] = useState(false); const [params, setParams] = useState([]); const [selectedRecordingId, setSelectedRecordingId] = useState(''); const handleIntegrateRecording = (id: string, settings: IntegrationSettings) => {}; const handleSettingsRecording = (id: string, settings: RobotSettings) => {}; + const handleEditRobot = (id: string, settings: RobotSettings) => {}; const handleSettingsAndIntegrate = (id: string, name: string, params: string[]) => { if (params.length === 0) { @@ -75,6 +78,19 @@ export const Recordings = ({ handleEditRecording, handleRunRecording, setRecordi } } + const handleEditRobotOption = (id: string, name: string, params: string[]) => { + if (params.length === 0) { + setRobotEditAreOpen(true); + setRecordingInfo(id, name); + setSelectedRecordingId(id); + } else { + setParams(params); + setRobotEditAreOpen(true); + setRecordingInfo(id, name); + setSelectedRecordingId(id); + } + } + const handleClose = () => { setParams([]); setRunSettingsAreOpen(false); @@ -103,6 +119,13 @@ export const Recordings = ({ handleEditRecording, handleRunRecording, setRecordi setSelectedRecordingId(''); } + const handleRobotEditClose = () => { + setParams([]); + setRobotEditAreOpen(false); + setRecordingInfo('', ''); + setSelectedRecordingId(''); + } + return ( handleSettingsRecording(selectedRecordingId, settings)} /> + handleEditRobot(selectedRecordingId,settings)} + /> From fa523e528fecd83eeba59fda0f0cb40ea14f2920 Mon Sep 17 00:00:00 2001 From: RohitR311 Date: Sun, 17 Nov 2024 02:27:11 +0530 Subject: [PATCH 06/16] feat: save robot edit changes --- src/components/molecules/RobotEdit.tsx | 112 ++++++++++++++++++++----- 1 file changed, 91 insertions(+), 21 deletions(-) diff --git a/src/components/molecules/RobotEdit.tsx b/src/components/molecules/RobotEdit.tsx index d5fdceb4..f35e1048 100644 --- a/src/components/molecules/RobotEdit.tsx +++ b/src/components/molecules/RobotEdit.tsx @@ -3,7 +3,7 @@ import { GenericModal } from "../atoms/GenericModal"; import { TextField, Typography, Box, Button } from "@mui/material"; import { modalStyle } from "./AddWhereCondModal"; import { useGlobalInfoStore } from '../../context/globalInfo'; -import { getStoredRecording } from '../../api/storage'; +import { getStoredRecording, updateRecording } from '../../api/storage'; import { WhereWhatPair } from 'maxun-core'; import { getUserById } from "../../api/auth"; @@ -20,6 +20,11 @@ interface RobotWorkflow { workflow: WhereWhatPair[]; } +interface RobotEditOptions { + name: string; + limit?: number; +} + interface ScheduleConfig { runEvery: number; runEveryUnit: 'MINUTES' | 'HOURS' | 'DAYS' | 'WEEKS' | 'MONTHS'; @@ -55,9 +60,17 @@ interface RobotSettingsProps { export const RobotEditModal = ({ isOpen, handleStart, handleClose, initialSettings }: RobotSettingsProps) => { const [robot, setRobot] = useState(null); - const [userEmail, setUserEmail] = useState(null); + // const [settings, setSettings] = useState({ + // name: '', + // }); + + // const [userEmail, setUserEmail] = useState(null); const { recordingId, notify } = useGlobalInfoStore(); + // const handleChange = (field: keyof RobotEditOptions, value: string | number | boolean) => { + // setSettings(prev => ({ ...prev, [field]: value })); + // }; + useEffect(() => { if (isOpen) { getRobot(); @@ -73,22 +86,74 @@ export const RobotEditModal = ({ isOpen, handleStart, handleClose, initialSettin } } - const lastPair = robot?.recording.workflow[robot?.recording.workflow.length - 1]; + const handleRobotNameChange = (newName: string) => { + setRobot((prev) => + prev ? { ...prev, recording_meta: { ...prev.recording_meta, name: newName } } : prev + ); + }; + + const handleLimitChange = (newLimit: number) => { + setRobot((prev) => { + if (!prev) return prev; + + const updatedWorkflow = [...prev.recording.workflow]; + + if ( + updatedWorkflow.length > 0 && + updatedWorkflow[0]?.what && + updatedWorkflow[0].what.length > 0 && + updatedWorkflow[0].what[0].args && + updatedWorkflow[0].what[0].args.length > 0 && + updatedWorkflow[0].what[0].args[0] + ) { + updatedWorkflow[0].what[0].args[0].limit = newLimit; + } + + return { ...prev, recording: { ...prev.recording, workflow: updatedWorkflow } }; + }); + }; + const handleSave = async () => { + if (!robot) return; + + try { + const payload = { + name: robot.recording_meta.name, + limit: robot.recording.workflow[0]?.what[0]?.args?.[0]?.limit, + }; + + const success = await updateRecording(robot.recording_meta.id, payload); + + if (success) { + notify('success', 'Robot updated successfully.'); + handleStart(robot); // Inform parent about the updated robot + handleClose(); // Close the modal + + window.location.reload(); + } else { + notify('error', 'Failed to update the robot. Please try again.'); + } + } catch (error) { + notify('error', 'An error occurred while updating the robot.'); + console.error('Error updating robot:', error); + } + }; + + // 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]; + // 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]); + // 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 ( handleRobotNameChange(e.target.value)} style={{ marginBottom: '20px' }} /> - {robot.recording.workflow?.[0]?.what?.[0]?.args?.[0]?.limit && ( + {robot.recording.workflow?.[0]?.what?.[0]?.args?.[0]?.limit !== undefined && ( + handleLimitChange(parseInt(e.target.value, 10) || 0) + } + style={{ marginBottom: '20px' }} /> )} - + From baf8ce9ecb43cdeba550494d4f9d648d6df3ec20 Mon Sep 17 00:00:00 2001 From: RohitR311 Date: Sun, 17 Nov 2024 02:29:09 +0530 Subject: [PATCH 07/16] feat: add update recording api --- src/api/storage.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/api/storage.ts b/src/api/storage.ts index 9b4b06b2..0ad51e77 100644 --- a/src/api/storage.ts +++ b/src/api/storage.ts @@ -19,6 +19,20 @@ export const getStoredRecordings = async (): Promise => { } }; +export const updateRecording = async (id: string, data: { name?: string; limit?: number }): Promise => { + try { + const response = await axios.put(`${apiUrl}/storage/recordings/${id}`, data); + if (response.status === 200) { + return true; + } else { + throw new Error(`Couldn't update recording with id ${id}`); + } + } catch (error: any) { + console.error(`Error updating recording: ${error.message}`); + return false; + } +}; + export const getStoredRuns = async (): Promise => { try { const response = await axios.get(`${apiUrl}/storage/runs`); From e92bef2925551584db10949da4c4f5ee9aa70e4f Mon Sep 17 00:00:00 2001 From: RohitR311 Date: Sun, 17 Nov 2024 02:30:20 +0530 Subject: [PATCH 08/16] feat: add update route for robot --- server/src/routes/storage.ts | 89 ++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/server/src/routes/storage.ts b/server/src/routes/storage.ts index 228f60de..7a356b27 100644 --- a/server/src/routes/storage.ts +++ b/server/src/routes/storage.ts @@ -57,6 +57,95 @@ router.get('/recordings/:id', requireSignIn, async (req, res) => { } }) + +/** + * PUT endpoint to update the name and limit of a robot. + */ +router.put('/recordings/:id', requireSignIn, async (req: AuthenticatedRequest, res) => { + try { + const { id } = req.params; + const { name, limit } = req.body; + + // Validate input + if (!name && limit === undefined) { + return res.status(400).json({ error: 'Either "name" or "limit" must be provided.' }); + } + + // Fetch the robot by ID + const robot = await Robot.findOne({ where: { 'recording_meta.id': id } }); + + if (!robot) { + return res.status(404).json({ error: 'Robot not found.' }); + } + + // Update fields if provided + if (name) { + robot.set('recording_meta', { ...robot.recording_meta, name }); + } + + // Update the limit + if (limit !== undefined) { + const workflow = [...robot.recording.workflow]; // Create a copy of the workflow + + // Ensure the workflow structure is valid before updating + if ( + workflow.length > 0 && + workflow[0]?.what?.[0] + ) { + // Create a new workflow object with the updated limit + const updatedWorkflow = workflow.map((step, index) => { + if (index === 0) { // Assuming you want to update the first step + return { + ...step, + what: step.what.map((action, actionIndex) => { + if (actionIndex === 0) { // Assuming the first action needs updating + return { + ...action, + args: (action.args ?? []).map((arg, argIndex) => { + if (argIndex === 0) { // Assuming the first argument needs updating + return { ...arg, limit }; + } + return arg; + }), + }; + } + return action; + }), + }; + } + return step; + }); + + // Replace the workflow in the recording object + robot.set('recording', { ...robot.recording, workflow: updatedWorkflow }); + } else { + return res.status(400).json({ error: 'Invalid workflow structure for updating limit.' }); + } + } + + await robot.save(); + + const updatedRobot = await Robot.findOne({ where: { 'recording_meta.id': id } }); + console.log('After save:', updatedRobot); + + // Log the update + logger.log('info', `Robot with ID ${id} was updated successfully.`); + + return res.status(200).json({ message: 'Robot updated successfully', robot }); + } catch (error) { + // Safely handle the error type + if (error instanceof Error) { + logger.log('error', `Error updating robot with ID ${req.params.id}: ${error.message}`); + return res.status(500).json({ error: error.message }); + } else { + logger.log('error', `Unknown error updating robot with ID ${req.params.id}`); + return res.status(500).json({ error: 'An unknown error occurred.' }); + } + } +}); + + + /** * DELETE endpoint for deleting a recording from the storage. */ From 6622e4fa26369f2462a352d3a14420191760250e Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 18 Nov 2024 05:37:51 +0530 Subject: [PATCH 09/16] chore: console log cleanup --- src/components/molecules/RunsTable.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/molecules/RunsTable.tsx b/src/components/molecules/RunsTable.tsx index b1cb97ef..5091c6da 100644 --- a/src/components/molecules/RunsTable.tsx +++ b/src/components/molecules/RunsTable.tsx @@ -63,8 +63,6 @@ export const RunsTable = ( const [rowsPerPage, setRowsPerPage] = useState(10); const [rows, setRows] = useState([]); - console.log(`rows runs: ${JSON.stringify(rows)}`); - const { notify, rerenderRuns, setRerenderRuns } = useGlobalInfoStore(); const handleChangePage = (event: unknown, newPage: number) => { From 4fefe71d29ef2baa2a2aed65275c4dafdae164eb Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 18 Nov 2024 05:50:25 +0530 Subject: [PATCH 10/16] feat: include robotId and robotMetaId in run data interface --- src/components/molecules/RunsTable.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/molecules/RunsTable.tsx b/src/components/molecules/RunsTable.tsx index 5091c6da..3fde41a3 100644 --- a/src/components/molecules/RunsTable.tsx +++ b/src/components/molecules/RunsTable.tsx @@ -45,6 +45,8 @@ export interface Data { // task: string; log: string; runId: string; + robotId: string; + robotMetaId: string; interpreterSettings: RunSettings; serializableOutput: any; binaryOutput: any; From f6e08aa7664d8606375b42d8bf13af487cd8d0c1 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 18 Nov 2024 05:51:56 +0530 Subject: [PATCH 11/16] feat: group runs by robot meta id instead of robot name --- src/components/molecules/RunsTable.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/molecules/RunsTable.tsx b/src/components/molecules/RunsTable.tsx index 3fde41a3..f6d628df 100644 --- a/src/components/molecules/RunsTable.tsx +++ b/src/components/molecules/RunsTable.tsx @@ -105,12 +105,12 @@ export const RunsTable = ( fetchRuns(); }; - // Group runs by recording name + // Group runs by robot meta id const groupedRows = rows.reduce((acc, row) => { - if (!acc[row.name]) { - acc[row.name] = []; + if (!acc[row.robotMetaId]) { + acc[row.robotMetaId] = []; } - acc[row.name].push(row); + acc[row.robotMetaId].push(row); return acc; }, {} as Record); From cba24f2f4b1910f06c9c6e2bb14ff02c6796f1fa Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 18 Nov 2024 05:58:24 +0530 Subject: [PATCH 12/16] feat: render runs by robot id and display run name --- src/components/molecules/RunsTable.tsx | 30 ++++++++++++++------------ 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/components/molecules/RunsTable.tsx b/src/components/molecules/RunsTable.tsx index f6d628df..ddbe6686 100644 --- a/src/components/molecules/RunsTable.tsx +++ b/src/components/molecules/RunsTable.tsx @@ -120,10 +120,10 @@ export const RunsTable = ( All Runs - {Object.entries(groupedRows).map(([name, group]) => ( - + {Object.entries(groupedRows).map(([id, data]) => ( + }> - {name} + {data[0].name} @@ -142,17 +142,19 @@ export const RunsTable = ( - {group.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map((row) => ( - - ))} + {data + .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage) + .map((row) => ( + + ))}
From 67dfd84694f725e81d741a5e53e4ffd5503c54b2 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 18 Nov 2024 06:09:01 +0530 Subject: [PATCH 13/16] feat: display most recent run name --- src/components/molecules/RunsTable.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/molecules/RunsTable.tsx b/src/components/molecules/RunsTable.tsx index ddbe6686..dcb0cdd1 100644 --- a/src/components/molecules/RunsTable.tsx +++ b/src/components/molecules/RunsTable.tsx @@ -123,7 +123,7 @@ export const RunsTable = ( {Object.entries(groupedRows).map(([id, data]) => ( }> - {data[0].name} + {data[data.length - 1].name} From 874ee8d9e77ddfee533fbfea46453694ec2ec3c8 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 18 Nov 2024 06:11:34 +0530 Subject: [PATCH 14/16] chore: remove unused import --- src/components/molecules/RobotEdit.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/molecules/RobotEdit.tsx b/src/components/molecules/RobotEdit.tsx index f35e1048..ee8b8c8c 100644 --- a/src/components/molecules/RobotEdit.tsx +++ b/src/components/molecules/RobotEdit.tsx @@ -5,7 +5,6 @@ import { modalStyle } from "./AddWhereCondModal"; import { useGlobalInfoStore } from '../../context/globalInfo'; import { getStoredRecording, updateRecording } from '../../api/storage'; import { WhereWhatPair } from 'maxun-core'; -import { getUserById } from "../../api/auth"; interface RobotMeta { name: string; From 1af3e68ffd5d3010189bc9a17b9f87738abafb55 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 18 Nov 2024 06:12:17 +0530 Subject: [PATCH 15/16] chore: remove unused code --- src/components/molecules/RobotEdit.tsx | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/src/components/molecules/RobotEdit.tsx b/src/components/molecules/RobotEdit.tsx index ee8b8c8c..467679e1 100644 --- a/src/components/molecules/RobotEdit.tsx +++ b/src/components/molecules/RobotEdit.tsx @@ -59,17 +59,8 @@ interface RobotSettingsProps { export const RobotEditModal = ({ isOpen, handleStart, handleClose, initialSettings }: RobotSettingsProps) => { const [robot, setRobot] = useState(null); - // const [settings, setSettings] = useState({ - // name: '', - // }); - - // const [userEmail, setUserEmail] = useState(null); const { recordingId, notify } = useGlobalInfoStore(); - // const handleChange = (field: keyof RobotEditOptions, value: string | number | boolean) => { - // setSettings(prev => ({ ...prev, [field]: value })); - // }; - useEffect(() => { if (isOpen) { getRobot(); @@ -137,23 +128,6 @@ export const RobotEditModal = ({ isOpen, handleStart, handleClose, initialSettin } }; - // 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 ( Date: Mon, 18 Nov 2024 06:12:35 +0530 Subject: [PATCH 16/16] chore: lint --- src/components/molecules/RobotEdit.tsx | 50 +++++++++++++------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/components/molecules/RobotEdit.tsx b/src/components/molecules/RobotEdit.tsx index 467679e1..f26765a3 100644 --- a/src/components/molecules/RobotEdit.tsx +++ b/src/components/molecules/RobotEdit.tsx @@ -20,8 +20,8 @@ interface RobotWorkflow { } interface RobotEditOptions { - name: string; - limit?: number; + name: string; + limit?: number; } interface ScheduleConfig { @@ -85,9 +85,9 @@ export const RobotEditModal = ({ isOpen, handleStart, handleClose, initialSettin const handleLimitChange = (newLimit: number) => { setRobot((prev) => { if (!prev) return prev; - + const updatedWorkflow = [...prev.recording.workflow]; - + if ( updatedWorkflow.length > 0 && updatedWorkflow[0]?.what && @@ -98,33 +98,33 @@ export const RobotEditModal = ({ isOpen, handleStart, handleClose, initialSettin ) { updatedWorkflow[0].what[0].args[0].limit = newLimit; } - + return { ...prev, recording: { ...prev.recording, workflow: updatedWorkflow } }; }); }; const handleSave = async () => { if (!robot) return; - - try { - const payload = { - name: robot.recording_meta.name, - limit: robot.recording.workflow[0]?.what[0]?.args?.[0]?.limit, - }; - - const success = await updateRecording(robot.recording_meta.id, payload); - - if (success) { - notify('success', 'Robot updated successfully.'); - handleStart(robot); // Inform parent about the updated robot - handleClose(); // Close the modal - window.location.reload(); - } else { - notify('error', 'Failed to update the robot. Please try again.'); - } + try { + const payload = { + name: robot.recording_meta.name, + limit: robot.recording.workflow[0]?.what[0]?.args?.[0]?.limit, + }; + + const success = await updateRecording(robot.recording_meta.id, payload); + + if (success) { + notify('success', 'Robot updated successfully.'); + handleStart(robot); // Inform parent about the updated robot + handleClose(); // Close the modal + + window.location.reload(); + } else { + notify('error', 'Failed to update the robot. Please try again.'); + } } catch (error) { - notify('error', 'An error occurred while updating the robot.'); - console.error('Error updating robot:', error); + notify('error', 'An error occurred while updating the robot.'); + console.error('Error updating robot:', error); } }; @@ -159,7 +159,7 @@ export const RobotEditModal = ({ isOpen, handleStart, handleClose, initialSettin style={{ marginBottom: '20px' }} /> )} - +