diff --git a/src/components/robot/pages/RobotConfigPage.tsx b/src/components/robot/pages/RobotConfigPage.tsx index 5923842a..902518eb 100644 --- a/src/components/robot/pages/RobotConfigPage.tsx +++ b/src/components/robot/pages/RobotConfigPage.tsx @@ -1,14 +1,15 @@ import React from 'react'; -import { - Box, - Typography, - Button, +import { + Box, + Typography, + Button, IconButton, Divider, useTheme } from '@mui/material'; import { ArrowBack } from '@mui/icons-material'; import { useNavigate, useLocation } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; interface RobotConfigPageProps { title: string; @@ -23,6 +24,7 @@ interface RobotConfigPageProps { icon?: React.ReactNode; onBackToSelection?: () => void; backToSelectionText?: string; + onArrowBack?: () => void; // Optional prop for custom back action } export const RobotConfigPage: React.FC = ({ @@ -30,50 +32,72 @@ export const RobotConfigPage: React.FC = ({ children, onSave, onCancel, - saveButtonText = "Save", - cancelButtonText = "Cancel", + saveButtonText, + cancelButtonText, showSaveButton = true, showCancelButton = true, isLoading = false, icon, onBackToSelection, - backToSelectionText = "← Back" + backToSelectionText, + onArrowBack, }) => { + const navigate = useNavigate(); + const location = useLocation(); const theme = useTheme(); + const { t } = useTranslation(); const handleBack = () => { if (onCancel) { onCancel(); + } else { + // Try to determine the correct path based on current URL + const currentPath = location.pathname; + const basePath = currentPath.includes('/prebuilt-robots') ? '/prebuilt-robots' : '/robots'; + navigate(basePath); } }; return ( - - @@ -82,9 +106,9 @@ export const RobotConfigPage: React.FC = ({ {icon} )} - = ({ - {children} + {/* Action Buttons */} {(showSaveButton || showCancelButton || onBackToSelection) && ( + {/* Left side - Back to Selection button */} {onBackToSelection && ( )} + {/* Right side - Save/Cancel buttons */} - {showCancelButton && ( - - )} - {showSaveButton && onSave && ( - + )} + {showSaveButton && onSave && ( + - )} + }} + > + {isLoading ? t("buttons.saving") : (saveButtonText || t("buttons.save"))} + + )} )} diff --git a/src/components/robot/pages/RobotDuplicatePage.tsx b/src/components/robot/pages/RobotDuplicatePage.tsx index e88be19d..b02cecde 100644 --- a/src/components/robot/pages/RobotDuplicatePage.tsx +++ b/src/components/robot/pages/RobotDuplicatePage.tsx @@ -19,10 +19,17 @@ import { useNavigate, useLocation } from "react-router-dom"; interface RobotMeta { name: string; id: string; + prebuiltId?: string; createdAt: string; pairs: number; updatedAt: string; params: any[]; + type?: string; + description?: string; + usedByUsers?: number[]; + subscriptionLevel?: number; + access?: string; + sample?: any[]; url?: string; } @@ -73,7 +80,7 @@ export const RobotDuplicatePage = ({ handleStart }: RobotSettingsProps) => { const [targetUrl, setTargetUrl] = useState(""); const [robot, setRobot] = useState(null); const [isLoading, setIsLoading] = useState(false); - const { recordingId, notify, setRerenderRobots } = + const { recordingId, notify, setRerenderRobots} = useGlobalInfoStore(); useEffect(() => { @@ -132,7 +139,10 @@ export const RobotDuplicatePage = ({ handleStart }: RobotSettingsProps) => { t("robot_duplication.notifications.duplicate_success") ); handleStart(robot); - navigate("/robots"); + const basePath = location.pathname.includes("/prebuilt-robots") + ? "/prebuilt-robots" + : "/robots"; + navigate(basePath); } else { notify("error", t("robot_duplication.notifications.duplicate_error")); } @@ -145,7 +155,10 @@ export const RobotDuplicatePage = ({ handleStart }: RobotSettingsProps) => { }; const handleCancel = () => { - navigate("/robots"); + const basePath = location.pathname.includes("/prebuilt-robots") + ? "/prebuilt-robots" + : "/robots"; + navigate(basePath); }; return ( @@ -156,6 +169,7 @@ export const RobotDuplicatePage = ({ handleStart }: RobotSettingsProps) => { saveButtonText={t("robot_duplication.buttons.duplicate")} cancelButtonText={t("robot_duplication.buttons.cancel")} isLoading={isLoading} + showCancelButton={false} > <> @@ -188,4 +202,4 @@ export const RobotDuplicatePage = ({ handleStart }: RobotSettingsProps) => { ); -}; +}; \ No newline at end of file diff --git a/src/components/robot/pages/RobotEditPage.tsx b/src/components/robot/pages/RobotEditPage.tsx index deaf3d76..bce3a5ea 100644 --- a/src/components/robot/pages/RobotEditPage.tsx +++ b/src/components/robot/pages/RobotEditPage.tsx @@ -18,10 +18,17 @@ import { useNavigate, useLocation } from "react-router-dom"; interface RobotMeta { name: string; id: string; + prebuiltId?: string; createdAt: string; pairs: number; updatedAt: string; params: any[]; + type?: string; + description?: string; + usedByUsers?: number[]; + subscriptionLevel?: number; + access?: string; + sample?: any[]; url?: string; } @@ -33,13 +40,13 @@ interface ScheduleConfig { runEvery: number; runEveryUnit: "MINUTES" | "HOURS" | "DAYS" | "WEEKS" | "MONTHS"; startFrom: - | "SUNDAY" - | "MONDAY" - | "TUESDAY" - | "WEDNESDAY" - | "THURSDAY" - | "FRIDAY" - | "SATURDAY"; + | "SUNDAY" + | "MONDAY" + | "TUESDAY" + | "WEDNESDAY" + | "THURSDAY" + | "FRIDAY" + | "SATURDAY"; atTimeStart?: string; atTimeEnd?: string; timezone: string; @@ -173,6 +180,7 @@ export const RobotEditPage = ({ handleStart }: RobotSettingsProps) => { 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({ @@ -214,6 +222,7 @@ export const RobotEditPage = ({ handleStart }: RobotSettingsProps) => { const selector = action.args[0]; + // Handle full word type actions first if ( action.action === "type" && action.args?.length >= 2 && @@ -230,6 +239,7 @@ export const RobotEditPage = ({ handleStart }: RobotSettingsProps) => { continue; } + // Handle character-by-character sequences (both type and press) if ( (action.action === "type" || action.action === "press") && action.args?.length >= 2 && @@ -582,7 +592,8 @@ export const RobotEditPage = ({ handleStart }: RobotSettingsProps) => { setRerenderRobots(true); notify("success", t("robot_edit.notifications.update_success")); handleStart(robot); - navigate("/robots"); + const basePath = "/robots"; + navigate(basePath); } else { notify("error", t("robot_edit.notifications.update_failed")); } @@ -595,7 +606,8 @@ export const RobotEditPage = ({ handleStart }: RobotSettingsProps) => { }; const handleCancel = () => { - navigate("/robots"); + const basePath = "/robots"; + navigate(basePath); }; const lastPair = @@ -610,6 +622,7 @@ export const RobotEditPage = ({ handleStart }: RobotSettingsProps) => { onCancel={handleCancel} saveButtonText={t("robot_edit.save")} cancelButtonText={t("robot_edit.cancel")} + showCancelButton={false} isLoading={isLoading} > <> @@ -640,4 +653,4 @@ export const RobotEditPage = ({ handleStart }: RobotSettingsProps) => { ); -}; +}; \ No newline at end of file diff --git a/src/components/robot/pages/RobotIntegrationPage.tsx b/src/components/robot/pages/RobotIntegrationPage.tsx index bffe8da8..9b941a3d 100644 --- a/src/components/robot/pages/RobotIntegrationPage.tsx +++ b/src/components/robot/pages/RobotIntegrationPage.tsx @@ -72,16 +72,16 @@ export const RobotIntegrationPage = ({ const { t } = useTranslation(); const navigate = useNavigate(); const location = useLocation(); - + const pathSegments = location.pathname.split('/'); const robotsIndex = pathSegments.findIndex(segment => segment === 'robots' || segment === 'prebuilt-robots'); const integrateIndex = pathSegments.findIndex(segment => segment === 'integrate'); - - const robotIdFromUrl = robotsIndex !== -1 && robotsIndex + 1 < pathSegments.length - ? pathSegments[robotsIndex + 1] + + const robotIdFromUrl = robotsIndex !== -1 && robotsIndex + 1 < pathSegments.length + ? pathSegments[robotsIndex + 1] : null; - - const integrationType = integrateIndex !== -1 && integrateIndex + 1 < pathSegments.length + + const integrationType = integrateIndex !== -1 && integrateIndex + 1 < pathSegments.length ? pathSegments[integrateIndex + 1] as "googleSheets" | "airtable" | "webhook" : preSelectedIntegrationType || null; @@ -114,7 +114,7 @@ export const RobotIntegrationPage = ({ const [urlError, setUrlError] = useState(null); const { recordingId: recordingIdFromStore, notify, setRerenderRobots, setRecordingId } = useGlobalInfoStore(); - + const recordingId = robotIdFromUrl || recordingIdFromStore; useEffect(() => { @@ -137,7 +137,7 @@ export const RobotIntegrationPage = ({ const redirectUrl = `${window.location.origin}${basePath}/${recordingId}/integrate/googleSheets`; window.location.href = `${apiUrl}/auth/google?robotId=${recordingId}&redirectUrl=${encodeURIComponent(redirectUrl)}`; }; - + const authenticateWithAirtable = () => { if (!recordingId) { console.error("Cannot authenticate: recordingId is null"); @@ -251,7 +251,7 @@ export const RobotIntegrationPage = ({ const deleteWebhookSetting = async (webhookId: string) => { if (!recordingId) return; try { - setLoading(true); + setLoading(true); const response = await removeWebhook(webhookId, recordingId); if (response.ok) { setSettings((prev) => ({ ...prev, webhooks: (prev.webhooks || []).filter((webhook) => webhook.id !== webhookId) })); @@ -612,7 +612,7 @@ export const RobotIntegrationPage = ({ case "webhook": return "Webhook Integration"; default: - return "Integration Settings"; + return "Integration"; } }; @@ -677,40 +677,85 @@ export const RobotIntegrationPage = ({ else return date.toLocaleDateString("en-US", { year: "numeric", month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" }); }; + const handleBack = () => { + if (!recordingId) { + console.error("Cannot navigate: recordingId is null"); + return; + } + + setSelectedIntegrationType(null); + setSettings({ ...settings, integrationType: "airtable" }); + const basePath = robotPath === "prebuilt-robots" ? "/prebuilt-robots" : "/robots"; + navigate(`${basePath}/${recordingId}/integrate`); + }; + // --- MAIN RENDER --- if (!selectedIntegrationType && !integrationType) { return ( - navigate(`/${robotPath}/${recordingId}/integrate`)}> -
-
-
+ +
+
+
@@ -725,15 +770,17 @@ export const RobotIntegrationPage = ({ ); } - const handleBack = () => { - if (!recordingId) return; - setSelectedIntegrationType(null); - const basePath = robotPath === "prebuilt-robots" ? "/prebuilt-robots" : "/robots"; - navigate(`${basePath}/${recordingId}/integrate`); - }; - return ( - +
{(selectedIntegrationType === "googleSheets" || integrationType === "googleSheets") && ( @@ -763,9 +810,9 @@ export const RobotIntegrationPage = ({ {settings.webhooks.map((webhook) => ( {webhook.url} - {webhook.events.map((event) => ())} + {webhook.events.map((event) => ())} {formatLastCalled(webhook.lastCalledAt)} - toggleWebhookStatusSetting(webhook.id)} size="small"/> + toggleWebhookStatusSetting(webhook.id)} size="small" /> testWebhookSetting(webhook.id)} disabled={loading || !webhook.active} title="Test"> editWebhookSetting(webhook)} disabled={loading} title="Edit"> @@ -780,7 +827,7 @@ export const RobotIntegrationPage = ({ {!showWebhookForm && ( - { setNewWebhook({ ...newWebhook, url: e.target.value }); if (urlError) setUrlError(null); }} error={!!urlError} helperText={urlError} required aria-describedby="webhook-url-help"/> + { setNewWebhook({ ...newWebhook, url: e.target.value }); if (urlError) setUrlError(null); }} error={!!urlError} helperText={urlError} required aria-describedby="webhook-url-help" /> setNewWebhook({ ...newWebhook, events: [e.target.value] })} sx={{ minWidth: "200px" }} required> Run finished Run failed @@ -796,13 +843,13 @@ export const RobotIntegrationPage = ({ {editingWebhook ? "Edit Webhook" : "Add New Webhook"} - { setNewWebhook({ ...newWebhook, url: e.target.value }); if (urlError) setUrlError(null); }} sx={{ marginBottom: "15px" }} placeholder="https://your-api.com/webhook/endpoint" required error={!!urlError} helperText={urlError}/> + { setNewWebhook({ ...newWebhook, url: e.target.value }); if (urlError) setUrlError(null); }} sx={{ marginBottom: "15px" }} placeholder="https://your-api.com/webhook/endpoint" required error={!!urlError} helperText={urlError} /> setNewWebhook({ ...newWebhook, events: typeof e.target.value === "string" ? [e.target.value] : e.target.value })} - SelectProps={{ multiple: true, renderValue: (selected) => ({(selected as string[]).map((value) => ())}),}} sx={{ marginBottom: "20px" }} required> + SelectProps={{ multiple: true, renderValue: (selected) => ({(selected as string[]).map((value) => ())}), }} sx={{ marginBottom: "20px" }} required> Run finished Run failed - setNewWebhook({ ...newWebhook, active: e.target.checked })}/>} label="Active" sx={{ marginBottom: "10px" }}/> + setNewWebhook({ ...newWebhook, active: e.target.checked })} />} label="Active" sx={{ marginBottom: "10px" }} />