Skip to content

Conversation

RohitR311
Copy link
Collaborator

@RohitR311 RohitR311 commented Aug 4, 2025

What this PR does?

Revamps the UI for Robot configuration actions such as schedule, edit, settings, duplicate to have their own page instead of a modal component.

2025-08-04.23-12-24.mp4

Summary by CodeRabbit

  • New Features

    • Introduced dedicated pages for robot configuration, editing, duplication, integration, scheduling, and settings, providing a more streamlined and comprehensive user experience.
    • Added support for managing robot integrations with Google Sheets, Airtable, and Webhooks, including authentication, configuration, and validation flows.
    • Enabled full-page management of robot scheduling, with intuitive forms for frequency, timing, and timezone selection.
    • Added localized "Close" button labels for robot settings dialogs in multiple languages including English, German, Spanish, Japanese, Turkish, and Chinese.
  • Refactor

    • Replaced modal-based robot configuration and integration with full-page components for improved navigation and usability.

@RohitR311 RohitR311 added Type: Enhancement Improvements to existing features Scope: UI/UX Issues/PRs related to UI/UX labels Aug 4, 2025
@RohitR311 RohitR311 marked this pull request as draft August 4, 2025 17:11
Copy link

coderabbitai bot commented Aug 4, 2025

Walkthrough

This change refactors the robot configuration and integration UI from modal-based components to dedicated page components. It introduces several new page components for robot settings, editing, duplication, scheduling, and integrations, and updates the main Recordings component to route to these pages instead of rendering modals. The routing and rendering logic are adjusted accordingly.

Changes

Cohort / File(s) Change Summary
Main Robot Recordings Component Refactor
src/components/robot/Recordings.tsx
Refactored to replace modal-based robot configuration and integration with dedicated page components. Routing and conditional rendering logic updated to support new page-based UI. Modal imports and usage removed in favor of page imports and rendering. Introduced isConfigPage boolean to detect configuration-related routes and conditionally render page components directly. Removed useParams for selectedRecordingId.
Robot Configuration Page Layout
src/components/robot/pages/RobotConfigPage.tsx
Introduced a new reusable layout component for robot configuration pages, supporting flexible header, footer, and action button arrangements with customizable buttons, icons, and loading states. Utilizes Material-UI components and theming for consistent styling.
Robot Duplicate Page
src/components/robot/pages/RobotDuplicatePage.tsx
Added a page component for duplicating a robot recording with a new target URL. Handles fetching robot data, editing the URL, saving the duplicate, notifications, and navigation. Uses RobotConfigPage as layout. Manages loading and error states, and integrates with global notification and rerender contexts.
Robot Edit Page
src/components/robot/pages/RobotEditPage.tsx
Added a page component for editing robot settings, including credentials, workflow limits, and target URL. Manages data fetching, credential grouping and visibility toggling, input handling, API updates, notifications, and navigation. Uses Material-UI and integrates translation and global state.
Robot Integration Page
src/components/robot/pages/RobotIntegrationPage.tsx
Added a comprehensive integration management page for Google Sheets, Airtable, and Webhooks. Manages authentication flows, integration settings, CRUD operations for webhooks, validation, UI state, error handling, and notifications. Supports fetching and updating integration data, navigation controls, and displays forms and tables for webhook management.
Robot Settings Page
src/components/robot/pages/RobotSettingsPage.tsx
Added a page component displaying robot metadata and settings in read-only mode. Fetches robot and creator data, derives target URL, and renders details with cancel navigation. Wrapped in RobotConfigPage layout. Integrates internationalization and error handling.
Schedule Settings Page
src/components/robot/pages/ScheduleSettingsPage.tsx
Added a page component for managing robot scheduling settings, including creation, editing, deletion, validation, UI state, and API interaction. Uses localized text and consistent layout with RobotConfigPage. Handles schedule parameters such as interval, unit, start day, day of month, time range, and timezone.
Localization Updates
public/locales/*.json
Added new "buttons" object with a "close" label in multiple locale JSON files (de.json, en.json, es.json, ja.json, tr.json, zh.json) under the robot_settings section to support UI close button text in various languages. No other localization keys were modified.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant RecordingsPage
    participant Router
    participant ConfigPage
    participant API

    User->>RecordingsPage: Navigates to robot configuration/integration
    RecordingsPage->>Router: Matches config/integration route
    Router->>ConfigPage: Renders appropriate page component
    ConfigPage->>API: Fetches robot data/settings
    API-->>ConfigPage: Returns data
    User->>ConfigPage: Interacts (edit, save, duplicate, schedule, integrate)
    ConfigPage->>API: Sends updates (if applicable)
    API-->>ConfigPage: Confirms changes
    ConfigPage->>Router: Navigates back or to next step
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

  • feat: routing #336: Refactors src/components/robot/Recordings.tsx focusing on modal handling and navigation via route-based modal display, related to routing and modal changes in this PR.
  • feat: edit robot target url #485: Adds and modifies robot editing functionality, aligning with the new page-based robot editing introduced here.
  • fix: open modal to fetch spreadsheets after google oauth  #390: Adds cookie-based notification and modal opening logic in Recordings.tsx for Google OAuth success, touching related code areas but focusing on modal handling rather than page-based routing.

Suggested labels

Type: Feature

Suggested reviewers

  • amhsirak

Poem

A bunny hopped through code so wide,
Swapping modals for pages with pride.
Robots now configure with ease,
On full new screens—what a breeze!
With tidy routes and layouts neat,
This update’s truly quite a feat.
🐇✨

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2a5989f and 8b81756.

📒 Files selected for processing (9)
  • public/locales/de.json (1 hunks)
  • public/locales/en.json (1 hunks)
  • public/locales/es.json (1 hunks)
  • public/locales/ja.json (1 hunks)
  • public/locales/tr.json (1 hunks)
  • public/locales/zh.json (1 hunks)
  • src/components/robot/pages/RobotConfigPage.tsx (1 hunks)
  • src/components/robot/pages/RobotIntegrationPage.tsx (1 hunks)
  • src/components/robot/pages/RobotSettingsPage.tsx (1 hunks)
✅ Files skipped from review due to trivial changes (4)
  • public/locales/zh.json
  • public/locales/tr.json
  • public/locales/es.json
  • public/locales/en.json
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/components/robot/pages/RobotIntegrationPage.tsx
  • src/components/robot/pages/RobotSettingsPage.tsx
  • src/components/robot/pages/RobotConfigPage.tsx
🔇 Additional comments (2)
public/locales/ja.json (1)

430-433: Addition looks correct – JSON remains valid and translation is accurate

The newly-added buttons.close key is correctly placed, the comma after the "errors" block keeps the JSON syntactically valid, and the Japanese string “閉じる” is appropriate and consistent with existing terminology.

public/locales/de.json (1)

429-432: Translation Key “robot_settings.buttons.close” Verified & JSON Valid

  • public/locales/de.json is valid JSON.
  • robot_settings.buttons.close exists in all locale files (de, en, es, ja, tr, zh).

No further action needed.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch config-pages

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@RohitR311 RohitR311 marked this pull request as ready for review August 4, 2025 17:41
@RohitR311 RohitR311 requested a review from amhsirak August 4, 2025 17:41
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 16

♻️ Duplicate comments (3)
src/components/robot/pages/RobotDuplicatePage.tsx (1)

19-63: Use shared type definitions.

These interfaces are duplicated across multiple files.

src/components/robot/pages/RobotSettingsPage.tsx (2)

12-56: Use shared type definitions.

These interfaces are duplicated across multiple files.


74-85: Improve error handling specificity.

Same error handling issue as in other robot page components.

🧹 Nitpick comments (6)
src/components/robot/pages/RobotEditPage.tsx (1)

369-408: Simplify nested array bounds checking.

The function has good defensive programming but the deeply nested conditions reduce readability.

const handleLimitChange = (
  pairIndex: number,
  actionIndex: number,
  argIndex: number,
  newLimit: number
) => {
  setRobot((prev) => {
    if (!prev) return prev;
    
    const updatedWorkflow = [...prev.recording.workflow];
    const pair = updatedWorkflow[pairIndex];
    
    if (!pair?.what?.[actionIndex]?.args?.[argIndex]) {
      return prev;
    }
    
    pair.what[actionIndex].args[argIndex].limit = newLimit;
    
    setScrapeListLimits((prevLimits) => 
      prevLimits.map((item) => 
        (item.pairIndex === pairIndex && 
         item.actionIndex === actionIndex && 
         item.argIndex === argIndex)
          ? { ...item, currentLimit: newLimit }
          : item
      )
    );
    
    return {
      ...prev,
      recording: { ...prev.recording, workflow: updatedWorkflow },
    };
  });
};
src/components/robot/pages/RobotConfigPage.tsx (1)

51-60: Make the layout responsive instead of fixed width.

The component uses a fixed width of 1000px which can cause issues on smaller screens.

sx={{ 
  maxWidth: 1000, 
  margin: 'auto', 
  px: 4,
  py: 3,
  minHeight: '80vh',
  display: 'flex',
  flexDirection: 'column',
  width: '100%', // Remove fixed width
  // Add responsive padding
  px: { xs: 2, sm: 3, md: 4 },
}}
src/components/robot/pages/ScheduleSettingsPage.tsx (1)

71-96: Improve error handling and logging.

The error handling doesn't log the actual error, making debugging difficult.

} catch (error) {
  console.error("Failed to delete schedule:", error);
  notify("error", t("schedule_settings.errors.delete_failed"));
}
src/components/robot/Recordings.tsx (1)

5-8: Remove unused import ScheduleSettings

The ScheduleSettings type is imported but only used in the component's props interface. Consider importing it where it's actually used to reduce coupling.

-import {
-  ScheduleSettings,
-  ScheduleSettingsPage,
-} from "./pages/ScheduleSettingsPage";
+import { ScheduleSettingsPage } from "./pages/ScheduleSettingsPage";

Then import ScheduleSettings from the appropriate location where it's defined and used.

src/components/robot/pages/RobotIntegrationPage.tsx (2)

491-497: Use theme variables instead of hard-coded colors and styles

The component uses hard-coded colors and inline styles which reduces maintainability and consistency. Consider using Material-UI theme variables.

-<Alert severity="info" sx={{ marginTop: "10px", border: "1px solid #ff00c3" }}>
+<Alert severity="info" sx={{ marginTop: 1.25, border: (theme) => `1px solid ${theme.palette.primary.main}` }}>

-style={{ marginLeft: "4px", fontWeight: "bold" }}
+sx={{ ml: 0.5, fontWeight: 'bold' }}

-style={{ display: "flex", flexDirection: "column", alignItems: "center", background: 'white', color: '#ff00c3' }}
+sx={{ 
+  display: "flex", 
+  flexDirection: "column", 
+  alignItems: "center", 
+  bgcolor: 'background.paper', 
+  color: 'primary.main' 
+}}

Also applies to: 549-554, 693-696, 703-706, 713-716


769-773: Improve accessibility with proper ARIA labels

The icon buttons in the webhook table lack proper accessibility labels for screen readers.

-<IconButton size="small" onClick={() => testWebhookSetting(webhook.id)} disabled={loading || !webhook.active} title="Test"><ScienceIcon fontSize="small" /></IconButton>
-<IconButton size="small" onClick={() => editWebhookSetting(webhook)} disabled={loading} title="Edit"><EditIcon fontSize="small" /></IconButton>
-<IconButton size="small" onClick={() => deleteWebhookSetting(webhook.id)} disabled={loading} title="Delete"><DeleteIcon fontSize="small" /></IconButton>
+<IconButton size="small" onClick={() => testWebhookSetting(webhook.id)} disabled={loading || !webhook.active} aria-label="Test webhook"><ScienceIcon fontSize="small" /></IconButton>
+<IconButton size="small" onClick={() => editWebhookSetting(webhook)} disabled={loading} aria-label="Edit webhook"><EditIcon fontSize="small" /></IconButton>
+<IconButton size="small" onClick={() => deleteWebhookSetting(webhook.id)} disabled={loading} aria-label="Delete webhook"><DeleteIcon fontSize="small" /></IconButton>
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3fa00c8 and 150434a.

📒 Files selected for processing (7)
  • src/components/robot/Recordings.tsx (4 hunks)
  • src/components/robot/pages/RobotConfigPage.tsx (1 hunks)
  • src/components/robot/pages/RobotDuplicatePage.tsx (1 hunks)
  • src/components/robot/pages/RobotEditPage.tsx (1 hunks)
  • src/components/robot/pages/RobotIntegrationPage.tsx (1 hunks)
  • src/components/robot/pages/RobotSettingsPage.tsx (1 hunks)
  • src/components/robot/pages/ScheduleSettingsPage.tsx (1 hunks)
🧰 Additional context used
🪛 Biome (2.1.2)
src/components/robot/pages/RobotDuplicatePage.tsx

[error] 167-167: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

🪛 ast-grep (0.38.6)
src/components/robot/pages/RobotDuplicatePage.tsx

[warning] 166-166: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

Comment on lines 127 to 134
color: '#ff00c3',
borderColor: '#ff00c3',
bgcolor: 'whitesmoke',
'&:hover': {
bgcolor: '#f0f0f0',
borderColor: '#cc0099'
}
}}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Use theme colors instead of hardcoded values.

The component uses hardcoded colors (#ff00c3, #cc0099, whitesmoke) instead of theme colors, making it difficult to maintain consistency and support theming.

// Add to theme or use theme palette
const theme = useTheme();

// Define custom colors in theme
const primaryBrand = theme.palette.primary.main || '#ff00c3';
const primaryBrandDark = theme.palette.primary.dark || '#cc0099';

// Use in styles
sx={{
  color: primaryBrand,
  borderColor: primaryBrand,
  bgcolor: theme.palette.grey[100], // instead of 'whitesmoke'
  '&:hover': {
    bgcolor: theme.palette.grey[200],
    borderColor: primaryBrandDark
  }
}}

Also applies to: 147-152, 168-171

🤖 Prompt for AI Agents
In src/components/robot/pages/RobotConfigPage.tsx around lines 127 to 134,
replace the hardcoded color values (#ff00c3, #cc0099, whitesmoke) with colors
from the theme palette to ensure consistency and support theming. Use the
useTheme hook to access the theme, then define variables for primaryBrand and
primaryBrandDark from theme.palette.primary.main and theme.palette.primary.dark
respectively, and replace 'whitesmoke' with theme.palette.grey[100]. Apply these
theme colors in the sx style object for color, borderColor, and bgcolor,
including hover styles. Repeat this approach for lines 147-152 and 168-171 as
well.

Comment on lines +98 to +109
const getRobot = async () => {
if (recordingId) {
try {
const robot = await getStoredRecording(recordingId);
setRobot(robot);
} catch (error) {
notify("error", t("robot_duplication.notifications.robot_not_found"));
}
} else {
notify("error", t("robot_duplication.notifications.robot_not_found"));
}
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Distinguish between different error scenarios.

Like in RobotEditPage, the error handling shows the same message for different scenarios.

const getRobot = async () => {
  if (!recordingId) {
    notify("error", t("robot_duplication.notifications.no_recording_id"));
    return;
  }
  
  try {
    const robot = await getStoredRecording(recordingId);
    setRobot(robot);
  } catch (error) {
    console.error("Failed to fetch robot:", error);
    notify("error", t("robot_duplication.notifications.fetch_failed"));
  }
};
🤖 Prompt for AI Agents
In src/components/robot/pages/RobotDuplicatePage.tsx around lines 98 to 109, the
error handling currently uses the same notification message for missing
recordingId and fetch failures. Refactor the getRobot function to first check if
recordingId is missing and notify with a specific "no_recording_id" message,
then in the catch block log the error to the console and notify with a distinct
"fetch_failed" message to clearly distinguish the error scenarios.

Comment on lines +166 to +173
<span
dangerouslySetInnerHTML={{
__html: t("robot_duplication.descriptions.example", {
url1: "<code>producthunt.com/topics/api</code>",
url2: "<code>producthunt.com/topics/database</code>",
}),
}}
/>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

⚠️ Potential issue

Replace dangerouslySetInnerHTML with safe React components.

Using dangerouslySetInnerHTML poses XSS risks and bypasses React's built-in protections. Even though the content comes from translations, it's safer to use React components.

// Instead of dangerouslySetInnerHTML, create a safe component:
const ExampleDescription = () => {
  const { t } = useTranslation();
  return (
    <span>
      {t("robot_duplication.descriptions.example_prefix")}
      <code>producthunt.com/topics/api</code>
      {t("robot_duplication.descriptions.example_middle")}
      <code>producthunt.com/topics/database</code>
      {t("robot_duplication.descriptions.example_suffix")}
    </span>
  );
};

// Then use it in the render:
<ExampleDescription />

Alternatively, update your translation file to use placeholders and render safely:

<span>
  {t("robot_duplication.descriptions.example", {
    interpolation: { escapeValue: false },
    components: {
      code1: <code>producthunt.com/topics/api</code>,
      code2: <code>producthunt.com/topics/database</code>
    }
  })}
</span>
🧰 Tools
🪛 Biome (2.1.2)

[error] 167-167: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

🪛 ast-grep (0.38.6)

[warning] 166-166: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

🤖 Prompt for AI Agents
In src/components/robot/pages/RobotDuplicatePage.tsx around lines 166 to 173,
replace the usage of dangerouslySetInnerHTML with safe React components to avoid
XSS risks. Refactor the code to either create a dedicated React component that
assembles the translated text and code elements separately or update the
translation to use placeholders and render the code elements as React components
within the translation call. This ensures the content is safely rendered without
bypassing React's protections.

Comment on lines +18 to +62
interface RobotMeta {
name: string;
id: string;
createdAt: string;
pairs: number;
updatedAt: string;
params: any[];
url?: string;
}

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;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Extract shared interfaces to avoid duplication.

These interfaces (RobotMeta, RobotWorkflow, ScheduleConfig, RobotSettings) are duplicated across multiple files (RobotEditPage, RobotDuplicatePage, RobotSettingsPage). This violates the DRY principle and makes maintenance difficult.

Create a shared types file:

// src/components/robot/types/robot.types.ts
export interface RobotMeta {
  name: string;
  id: string;
  createdAt: string;
  pairs: number;
  updatedAt: string;
  params: any[];
  url?: string;
}

export interface RobotWorkflow {
  workflow: WhereWhatPair[];
}

export 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;
}

Then import from this shared file in each component.

🤖 Prompt for AI Agents
In src/components/robot/pages/RobotEditPage.tsx lines 18 to 62, the interfaces
RobotMeta, RobotWorkflow, ScheduleConfig, and RobotSettings are duplicated and
should be extracted to a shared types file to follow the DRY principle. Create a
new file src/components/robot/types/robot.types.ts and move these interface
definitions there. Then, remove these interfaces from RobotEditPage.tsx and
import them from the new shared types file. Repeat this import update in other
files where these interfaces are duplicated.

Comment on lines +192 to +302
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];

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;
}

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;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Refactor complex credential extraction logic.

The extractInitialCredentials function is 110 lines long with deeply nested loops and complex control flow. This makes it difficult to understand, test, and maintain.

Break down the function into smaller, focused functions:

function extractInitialCredentials(workflow: any[]): Credentials {
  const credentials: Credentials = {};
  
  workflow.forEach((step) => {
    if (!step.what) return;
    processWorkflowStep(step.what, credentials);
  });
  
  return credentials;
}

function processWorkflowStep(actions: any[], credentials: Credentials) {
  let context = createProcessingContext();
  
  for (let i = 0; i < actions.length;) {
    const action = actions[i];
    
    if (shouldSkipAction(action)) {
      i++;
      continue;
    }
    
    if (isSimpleTypeAction(action)) {
      handleSimpleTypeAction(action, credentials);
      i++;
    } else if (isCharacterSequenceAction(action)) {
      i = processCharacterSequence(actions, i, credentials, context);
    } else {
      i++;
    }
  }
  
  finalizeContext(context, credentials);
}

// Additional helper functions for isPrintableCharacter, processCharacterSequence, etc.
🤖 Prompt for AI Agents
In src/components/robot/pages/RobotEditPage.tsx around lines 192 to 302, the
extractInitialCredentials function is overly long and complex with nested loops
and conditionals. Refactor by splitting it into smaller helper functions: create
a main extractInitialCredentials that iterates workflow steps and calls a new
processWorkflowStep function to handle each step's actions. Further break down
logic into focused helpers like isPrintableCharacter, shouldSkipAction,
isSimpleTypeAction, handleSimpleTypeAction, processCharacterSequence, and
finalizeContext. This modular approach improves readability, testability, and
maintainability.

Comment on lines +100 to +114
useEffect(() => {
const fetchUserEmail = async () => {
if (robot && robot.userId) {
try {
const userData = await getUserById(robot.userId.toString());
if (userData && userData.user) {
setUserEmail(userData.user.email);
}
} catch (error) {
console.error("Failed to fetch user email:", error);
}
}
};
fetchUserEmail();
}, [robot?.userId]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Notify users when creator information fails to load.

The error is only logged to console without user notification, leading to a silent failure where the creator field appears empty.

useEffect(() => {
  const fetchUserEmail = async () => {
    if (robot && robot.userId) {
      try {
        const userData = await getUserById(robot.userId.toString());
        if (userData && userData.user) {
          setUserEmail(userData.user.email);
        }
      } catch (error) {
        console.error("Failed to fetch user email:", error);
        setUserEmail(t("robot_settings.errors.creator_unavailable"));
        // Optionally show a notification
        notify("warning", t("robot_settings.errors.creator_fetch_failed"));
      }
    }
  };
  fetchUserEmail();
}, [robot?.userId]);
🤖 Prompt for AI Agents
In src/components/robot/pages/RobotSettingsPage.tsx around lines 100 to 114, the
fetchUserEmail function only logs errors to the console when failing to load the
creator's email, causing silent failures. Modify the catch block to set a
user-friendly error message in the userEmail state and trigger a warning
notification to inform users that the creator information could not be fetched,
using the existing translation keys and notify function.

Comment on lines +111 to +116
useEffect(() => {
const fetchSchedule = async () => {
await getRobotSchedule();
};
fetchSchedule();
}, []);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Fix useEffect dependencies.

The useEffect uses getRobotSchedule without including it in the dependency array, which could lead to stale closures.

useEffect(() => {
  const fetchSchedule = async () => {
    if (recordingId) {
      try {
        const scheduleData = await getSchedule(recordingId);
        setSchedule(scheduleData);
      } catch (error) {
        console.error("Failed to fetch robot schedule:", error);
      }
    }
  };
  fetchSchedule();
}, [recordingId]); // Add recordingId as dependency
🤖 Prompt for AI Agents
In src/components/robot/pages/ScheduleSettingsPage.tsx around lines 111 to 116,
the useEffect hook calls getRobotSchedule but does not include it or relevant
dependencies in the dependency array, risking stale closures. Update the
useEffect to include all necessary dependencies such as recordingId and
getRobotSchedule (or the equivalent function) in the dependency array. Also, add
proper error handling inside the async function and conditionally fetch the
schedule only when recordingId is available.

Comment on lines +203 to +206
{["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()}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove redundant ternary conditions.

Both branches of the ternary operator return the same translation key, making the condition redundant.

-  {["MONTHS", "WEEKS"].includes(settings.runEveryUnit)
-    ? t("schedule_settings.start_from")
-    : t("schedule_settings.start_from")}
+  {t("schedule_settings.start_from")}

If different labels are intended for different units, update the translation keys:

{["MONTHS", "WEEKS"].includes(settings.runEveryUnit)
  ? t("schedule_settings.start_from_day")
  : t("schedule_settings.start_from_time")}

Also applies to: 267-270

🤖 Prompt for AI Agents
In src/components/robot/pages/ScheduleSettingsPage.tsx around lines 203 to 206,
the ternary condition is redundant because both branches return the same
translation key. Remove the ternary operator and use a single call to
t("schedule_settings.start_from"). If different labels are intended for
different units, update the keys accordingly as suggested. Also apply the same
fix to lines 267 to 270.

Comment on lines +103 to +110
<RobotIntegrationPage handleStart={() => {}} robotPath={"robots"} />
);
} else if (currentPath.endsWith("/settings")) {
return (
<RobotSettingsModal
isOpen={true}
handleClose={handleClose}
handleStart={() => {}}
/>
);
return <RobotSettingsPage handleStart={() => {}} />;
} else if (currentPath.endsWith("/edit")) {
return (
<RobotEditModal
isOpen={true}
handleClose={handleClose}
handleStart={() => {}}
/>
);
return <RobotEditPage handleStart={() => {}} />;
} else if (currentPath.endsWith("/duplicate")) {
return (
<RobotDuplicationModal
isOpen={true}
handleClose={handleClose}
handleStart={() => {}}
/>
);
return <RobotDuplicatePage handleStart={() => {}} />;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify the necessity of empty handleStart callbacks

Most page components receive empty handleStart callbacks. This suggests either:

  1. These components don't need this prop and it should be removed
  2. The implementation is incomplete

Please verify if these callbacks are required and implement them if needed, or remove the prop from the component interfaces.


🏁 Script executed:

#!/bin/bash
# Check if handleStart is used in the page components
echo "Checking RobotIntegrationPage for handleStart usage:"
ast-grep --pattern 'handleStart' src/components/robot/pages/RobotIntegrationPage.tsx

echo -e "\nChecking other page components:"
fd -e tsx . src/components/robot/pages/ --exec ast-grep --pattern 'handleStart' {}

Length of output: 613


Remove unused handleStart props from integration & settings pages

Both RobotIntegrationPage and RobotSettingsPage never invoke the handleStart callback (as confirmed by AST grep), so passing an empty no-op adds dead code. You can simplify the routing logic by removing the prop from these pages’ interfaces and from their JSX, while retaining it (and supplying a real handler) only where it’s actually used (RobotEditPage, RobotDuplicatePage, ScheduleSettingsPage).

Locations to update:

  • src/components/robot/Recordings.tsx – lines rendering RobotIntegrationPage & RobotSettingsPage
  • src/components/robot/pages/RobotIntegrationPage.tsx – remove handleStart from the props interface
  • src/components/robot/pages/RobotSettingsPage.tsx – remove handleStart from the props interface

Suggested diff in Recordings.tsx:

-     <RobotIntegrationPage handleStart={() => {}} robotPath="robots" />
+     <RobotIntegrationPage robotPath="robots" />

-   } else if (currentPath.endsWith("/settings")) {
-     return <RobotSettingsPage handleStart={() => {}} />;
+   } else if (currentPath.endsWith("/settings")) {
+     return <RobotSettingsPage />;

And drop handleStart?: … from those pages’ Props definitions.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<RobotIntegrationPage handleStart={() => {}} robotPath={"robots"} />
);
} else if (currentPath.endsWith("/settings")) {
return (
<RobotSettingsModal
isOpen={true}
handleClose={handleClose}
handleStart={() => {}}
/>
);
return <RobotSettingsPage handleStart={() => {}} />;
} else if (currentPath.endsWith("/edit")) {
return (
<RobotEditModal
isOpen={true}
handleClose={handleClose}
handleStart={() => {}}
/>
);
return <RobotEditPage handleStart={() => {}} />;
} else if (currentPath.endsWith("/duplicate")) {
return (
<RobotDuplicationModal
isOpen={true}
handleClose={handleClose}
handleStart={() => {}}
/>
);
return <RobotDuplicatePage handleStart={() => {}} />;
<RobotIntegrationPage robotPath="robots" />
);
} else if (currentPath.endsWith("/settings")) {
return <RobotSettingsPage />;
} else if (currentPath.endsWith("/edit")) {
return <RobotEditPage handleStart={() => {}} />;
} else if (currentPath.endsWith("/duplicate")) {
return <RobotDuplicatePage handleStart={() => {}} />;
🤖 Prompt for AI Agents
In src/components/robot/Recordings.tsx around lines 103 to 110, remove the
unused handleStart prop from the JSX elements rendering RobotIntegrationPage and
RobotSettingsPage since these components do not use this prop. Additionally, in
src/components/robot/pages/RobotIntegrationPage.tsx and
src/components/robot/pages/RobotSettingsPage.tsx, remove handleStart from their
props interfaces to clean up dead code and simplify the components' interfaces.

Comment on lines +115 to +122
const currentPath = location.pathname;
const isConfigPage =
currentPath.includes("/schedule") ||
currentPath.includes("/integrate") ||
currentPath.includes("/settings") ||
currentPath.includes("/edit") ||
currentPath.includes("/duplicate") ||
currentPath.includes("/run");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve route pattern matching for better maintainability

The current approach with multiple includes() checks is verbose and error-prone. Consider using a more maintainable pattern.

-  const currentPath = location.pathname;
-  const isConfigPage =
-    currentPath.includes("/schedule") ||
-    currentPath.includes("/integrate") ||
-    currentPath.includes("/settings") ||
-    currentPath.includes("/edit") ||
-    currentPath.includes("/duplicate") ||
-    currentPath.includes("/run");
+  const currentPath = location.pathname;
+  const configRoutes = ["/schedule", "/integrate", "/settings", "/edit", "/duplicate", "/run"];
+  const isConfigPage = configRoutes.some(route => currentPath.includes(route));

This makes it easier to add or remove routes in the future.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const currentPath = location.pathname;
const isConfigPage =
currentPath.includes("/schedule") ||
currentPath.includes("/integrate") ||
currentPath.includes("/settings") ||
currentPath.includes("/edit") ||
currentPath.includes("/duplicate") ||
currentPath.includes("/run");
const currentPath = location.pathname;
const configRoutes = ["/schedule", "/integrate", "/settings", "/edit", "/duplicate", "/run"];
const isConfigPage = configRoutes.some(route => currentPath.includes(route));
🤖 Prompt for AI Agents
In src/components/robot/Recordings.tsx around lines 115 to 122, replace the
multiple includes() checks for route matching with a single, maintainable
pattern. Use an array of route segments and check if any of them match the
current path using a method like some() combined with includes(). This will
simplify the code and make it easier to add or remove routes in the future.

@amhsirak amhsirak merged commit 6bbb9ee into develop Aug 25, 2025
1 check passed
@coderabbitai coderabbitai bot mentioned this pull request Aug 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: UI/UX Issues/PRs related to UI/UX Type: Enhancement Improvements to existing features

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants