Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: reset remote browser recording state #314

Open
wants to merge 12 commits into
base: develop
Choose a base branch
from
Open

Conversation

RohitR311
Copy link
Collaborator

@RohitR311 RohitR311 commented Jan 2, 2025

Functionality to reset remote browser recording environment state

Maxun._.Open.Source.No.Code.Web.Data.Extraction.Platform.-.Brave.2025-01-03.19-54-16.mp4

Summary by CodeRabbit

  • Localization

    • Added German, English, Spanish, Japanese, and Chinese translations for new reset functionality
    • Introduced new buttons, confirmation messages, and notifications for resetting browser environment
  • New Features

    • Added reset functionality to browser recording
    • Implemented new context management for workflow and initial URL
    • Enhanced browser recording save and right side panel components
  • User Experience

    • Added clearer instructions and feedback for reset actions
    • Improved state management for recording and workflow processes

@RohitR311 RohitR311 marked this pull request as draft January 2, 2025 18:59
Copy link

coderabbitai bot commented Jan 2, 2025

Walkthrough

The pull request introduces comprehensive localization updates across multiple language files (German, English, Spanish, Japanese, and Chinese) to support a new reset functionality in the browser recording interface. Simultaneously, the changes modify several React components to implement this reset feature, including updates to context management, state handling, and user interface components. The modifications enhance the application's workflow management, add new state variables, and improve user interaction by providing clearer reset and confirmation options.

Changes

File Change Summary
public/locales/*.json Added localized translations for new reset buttons, confirmation messages, and notifications across German, English, Spanish, Japanese, and Chinese language files
src/context/browserActions.tsx Added new state variables workflow, showPaginationOptions, and showLimitOptions to ActionContextProps
src/context/globalInfo.tsx Introduced initialUrl state and setter method to global context
src/components/browser/BrowserRecordingSave.tsx Implemented reset functionality with new modals, state management, and event handlers
src/components/recorder/RightSidePanel.tsx Removed local workflow state, now using context for workflow management
src/components/robot/RecordingsTable.tsx Added setBrowserRecordingUrl function and setInitialUrl to state management

Poem

🐰 A Rabbit's Reset Rhyme 🔄

With buttons shiny and new,
Reset the world, start anew!
Captures cleared, path refreshed,
No worries, no recording stressed!
Hop along, reset with glee! 🌈


🪧 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.
    • Generate unit testing code for this file.
    • 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 generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • 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 generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

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. (Beta)
  • @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 January 3, 2025 14:27
@RohitR311 RohitR311 requested a review from amhsirak January 3, 2025 14:27
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: 0

🧹 Nitpick comments (6)
src/components/molecules/BrowserRecordingSave.tsx (3)

49-91: performReset function is robust.
This function systematically resets global states, ends actions, clears data, and updates the UI. However:

  1. Consider adding error handling in case any asynchronous call inside fails.
  2. Review if calling socket.emit('new-recording') in all scenarios is always desired.

133-149: Discard Confirmation Modal
Including a dedicated confirm/cancel step is good UX. Consider adding a short explanation of what data is lost upon disposal.


150-168: Reset Confirmation Modal
The textual prompts and button labels appear user-friendly. Check if you want to reinforce that all workflow steps will be cleared.

src/context/browserActions.tsx (1)

45-45: [workflow, setWorkflow]
Providing a default of emptyWorkflow ensures consistent initialization. Consider potential concurrency issues if multiple components modify workflow simultaneously.

src/components/molecules/RecordingsTable.tsx (1)

145-148: setBrowserRecordingUrl helper
This local function updates both initialUrl and recordingUrl. This keeps them in sync effectively. Watch for edge cases where the user empties the URL or sets invalid protocols.

src/components/organisms/RightSidePanel.tsx (1)

51-52: Commented-out states
showPaginationOptions and showLimitOptions are commented out—likely replaced by context-based states. Remove these lines if they’re no longer needed.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 9394fc3 and 014bce0.

📒 Files selected for processing (10)
  • public/locales/de.json (2 hunks)
  • public/locales/en.json (2 hunks)
  • public/locales/es.json (2 hunks)
  • public/locales/ja.json (2 hunks)
  • public/locales/zh.json (2 hunks)
  • src/components/molecules/BrowserRecordingSave.tsx (3 hunks)
  • src/components/molecules/RecordingsTable.tsx (3 hunks)
  • src/components/organisms/RightSidePanel.tsx (2 hunks)
  • src/context/browserActions.tsx (5 hunks)
  • src/context/globalInfo.tsx (4 hunks)
🔇 Additional comments (34)
src/components/molecules/BrowserRecordingSave.tsx (11)

1-1: Consider consistent import grouping.
The new import from React is fine, but consider grouping React imports together for clarity.


5-6: Great addition for better context usage.
Imports for useActionContext and useBrowserSteps enhance modular state management.


11-12: Neat constant usage.
Using emptyWorkflow and useSocketStore fosters consistent app-wide state and clarity.


16-17: Modal states are well-introduced.
Adding separate states for the discard and reset modals improves readability.


18-18: Verify all destructured properties.
Be sure each property is used. If any remain unused, consider removing them to keep context usage clean.


21-21: Socket usage is clear.
Extracting socket from useSocketStore is straightforward and consistent with the rest of the code.


23-36: Comprehensive destructuring.
All the action context properties are neatly destructured. Keep track of any potential concurrency or race conditions when simultaneously stopping multiple actions.


38-38: Browser steps reference.
Ensure that repeated calls to deleteBrowserStep in different parts of your code do not cause race conditions or inconsistent states.


109-115: Discard button logic is clear.
Users can confirm or cancel discarding the recording. Check if additional cleanup is necessary when discarding extensive data to prevent stale states.


118-131: Reset button integration.
A separate reset button with a distinct modal fosters a clear user flow. The code is easy to read and maintain.


178-178: Export statement
Exporting the component with a default name matches your existing pattern.

src/context/globalInfo.tsx (4)

23-24: New properties for initialUrl management
Storing an initialUrl and its setter in the global context is a solid addition. Verify usage across all components to avoid confusion between initialUrl and recordingUrl.
[approve]


54-54: Default initialUrl
Initializing initialUrl with 'https://' is sensible. Revisit this default if an empty value becomes more practical.


78-78: Stateful context
Using useState<string>(globalInfoStore.initialUrl) ensures the provider picks up the stored default. Double-check that any dynamic updates remain synchronized.
[approve]


126-127: Context value now includes initialUrl
Including initialUrl and setInitialUrl in the context provider is valuable for cross-component usage. Excellent approach to centralizing URL state.

src/context/browserActions.tsx (4)

3-4: Imports for workflow constants
Importing WorkflowFile from maxun-core & emptyWorkflow from shared constants is well-structured.


18-25: Extended action context properties
You’ve added workflow, showPaginationOptions, showLimitOptions, and their setters. This is a beneficial expansion, but ensure components that rely on these states handle them correctly to avoid partial updates or re-renders at unexpected times.


55-56: Flags for pagination & limit
Managing showPaginationOptions and showLimitOptions in context streamlines their usage. Confirm that resetting them is done whenever the user restarts or discards a process.


108-115: Exposed states in the Provider
Exposing new states and setter methods is well done. Keep an eye on debugging logs to ensure your app transitions remain intuitive.

src/components/molecules/RecordingsTable.tsx (2)

88-88: Context destructuring expanded
Including setInitialUrl ensures initial and final recording URLs remain synced. Check thoroughly for potential confusion if a user sets one but not the other.


315-315: Modal onChange referencing
Calling setBrowserRecordingUrl on change is apt. Ensure you sanitize or validate user input if you plan to store or re-emit this URL in any external calls.

src/components/organisms/RightSidePanel.tsx (2)

62-62: Increased reliance on context
Fully destructuring context properties (showPaginationOptions, showLimitOptions, etc.) centralizes logic. Verify that side effects remain minimal.


70-70: Effect dependencies
Replacing prior dependencies with [] avoids unintentional re-renders. Confirm this effect’s behavior if workflowHandler or id changes.

public/locales/zh.json (3)

166-166: LGTM! Reset button text added.

The Chinese translation "重置" is accurate and commonly used for "Reset" functionality.


230-232: LGTM! Reset confirmation modal messages added.

The translations are accurate and maintain consistency:

  • Confirmation prompt: "您确定要重置吗?"
  • Warning message clearly explains the reset behavior

235-237: LGTM! Reset notification messages added.

The translations accurately convey the state changes:

  • Recording termination
  • Environment reset
  • Successful reset confirmation
public/locales/ja.json (3)

166-166: LGTM! Reset button text added.

The Japanese translation "リセット" is accurate and commonly used for "Reset" functionality.


230-232: LGTM! Reset confirmation modal messages added.

The translations are accurate and maintain consistency:

  • Confirmation prompt: "リセットしてもよろしいですか?"
  • Warning message clearly explains the reset behavior

235-237: LGTM! Reset notification messages added.

The translations accurately convey the state changes:

  • Recording termination
  • Environment reset
  • Successful reset confirmation
public/locales/en.json (3)

164-164: LGTM! Reset button texts added.

Added both "Reset" and "Confirm" button texts for the reset functionality.

Also applies to: 167-167


231-233: LGTM! Reset confirmation modal messages added.

The messages are clear and informative:

  • Confirmation prompt is straightforward
  • Warning message clearly explains the consequences of resetting

236-238: LGTM! Reset notification messages added.

The notifications provide clear feedback about:

  • Recording termination
  • Environment reset status
  • Successful reset confirmation
public/locales/es.json (1)

166-166: LGTM! Spanish translations are accurate and well-structured.

The Spanish translations for the reset functionality are semantically correct and maintain natural language flow:

  • "Reiniciar" is the appropriate translation for the reset button
  • Modal messages clearly communicate the reset action and its consequences
  • Notification messages provide clear feedback about the reset operations

Also applies to: 230-232, 235-237

public/locales/de.json (1)

165-165: LGTM! German translations are accurate and well-structured.

The German translations for the reset functionality are semantically correct and maintain natural language flow:

  • "Zurücksetzen" is the appropriate translation for the reset button
  • Modal messages clearly communicate the reset action and its consequences
  • Notification messages provide clear feedback about the reset operations
  • Consistently uses the formal "Sie" form, which is appropriate for business software

Also applies to: 229-232, 234-236

@RohitR311 RohitR311 added the Type: Feature New features label Jan 3, 2025
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: 1

🧹 Nitpick comments (1)
src/components/molecules/BrowserRecordingSave.tsx (1)

25-38: Consider grouping related actions for better maintainability.

The large number of destructured actions from useActionContext suggests an opportunity for grouping related functionality.

Consider grouping related actions into objects:

- const { 
-   stopGetText, 
-   stopGetList, 
-   stopGetScreenshot,
-   stopPaginationMode,
-   stopLimitMode,
-   setCaptureStage,
-   updatePaginationType,
-   updateLimitType,
-   updateCustomLimit,
-   setShowLimitOptions,
-   setShowPaginationOptions,
-   setWorkflow,
- } = useActionContext();
+ const {
+   stopActions: {
+     stopGetText,
+     stopGetList,
+     stopGetScreenshot,
+     stopPaginationMode,
+     stopLimitMode,
+   },
+   updateActions: {
+     setCaptureStage,
+     updatePaginationType,
+     updateLimitType,
+     updateCustomLimit,
+   },
+   uiActions: {
+     setShowLimitOptions,
+     setShowPaginationOptions,
+   },
+   workflowActions: {
+     setWorkflow,
+   },
+ } = useActionContext();
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 014bce0 and 96f4c85.

📒 Files selected for processing (1)
  • src/components/molecules/BrowserRecordingSave.tsx (3 hunks)
🔇 Additional comments (4)
src/components/molecules/BrowserRecordingSave.tsx (4)

1-13: LGTM! Well-organized imports.

The new imports for browser actions, steps context, and socket store are appropriately added to support the reset functionality.


17-19: LGTM! Clear modal state management.

The separation of modal states (openDiscardModal and openResetModal) improves code clarity and maintainability.


129-148: LGTM! Well-implemented UI with good accessibility.

The reset functionality UI is cleanly implemented with proper accessibility attributes and clear user feedback.


167-189: LGTM! Clear reset confirmation flow.

The reset confirmation modal provides appropriate warnings and clear actions for users.

Comment on lines 51 to 93
const performReset = () => {
stopGetText();
stopGetList();
stopGetScreenshot();
stopPaginationMode();
stopLimitMode();

setShowLimitOptions(false);
setShowPaginationOptions(false);
setCaptureStage('initial');

updatePaginationType('');
updateLimitType('');
updateCustomLimit('');

setCurrentWorkflowActionsState({
hasScrapeListAction: false,
hasScreenshotAction: false,
hasScrapeSchemaAction: false
});

setWorkflow(emptyWorkflow);

resetInterpretationLog();

// Clear all browser steps
browserSteps.forEach(step => {
deleteBrowserStep(step.id);
});

if (socket) {
socket?.emit('new-recording');
socket.emit('input:url', initialUrl);
// Update the URL in the navbar to match
setRecordingUrl(initialUrl);
}

// Close the reset confirmation modal
setOpenResetModal(false);

// Notify user
notify('info', t('browser_recording.notifications.environment_reset'));
};
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for socket operations and state reset.

The performReset function handles multiple aspects of state reset but lacks error handling for socket operations and state mutations.

Consider adding try-catch blocks and socket error handling:

 const performReset = () => {
+  try {
     stopGetText();
     stopGetList();
     stopGetScreenshot();
     stopPaginationMode();
     stopLimitMode();
     
     setShowLimitOptions(false);
     setShowPaginationOptions(false);
     setCaptureStage('initial');

     updatePaginationType('');
     updateLimitType('');
     updateCustomLimit('');

     setCurrentWorkflowActionsState({
       hasScrapeListAction: false,
       hasScreenshotAction: false,
       hasScrapeSchemaAction: false
     });

     setWorkflow(emptyWorkflow);

     resetInterpretationLog();

     // Clear all browser steps
     browserSteps.forEach(step => {
       deleteBrowserStep(step.id);
     });
    
     if (socket) {
+      const socketPromises = [
+        new Promise((resolve, reject) => {
+          socket.emit('new-recording', null, (error: any) => {
+            if (error) reject(error);
+            resolve(null);
+          });
+        }),
+        new Promise((resolve, reject) => {
+          socket.emit('input:url', initialUrl, (error: any) => {
+            if (error) reject(error);
+            resolve(null);
+          });
+        })
+      ];
+      
+      Promise.all(socketPromises)
+        .then(() => {
+          setRecordingUrl(initialUrl);
+          setOpenResetModal(false);
+          notify('info', t('browser_recording.notifications.environment_reset'));
+        })
+        .catch((error) => {
+          console.error('Socket error during reset:', error);
+          notify('error', t('browser_recording.notifications.reset_failed'));
+        });
+    } else {
       setOpenResetModal(false);
       notify('info', t('browser_recording.notifications.environment_reset'));
+    }
+  } catch (error) {
+    console.error('Error during reset:', error);
+    notify('error', t('browser_recording.notifications.reset_failed'));
+    setOpenResetModal(false);
+  }
 };
📝 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 performReset = () => {
stopGetText();
stopGetList();
stopGetScreenshot();
stopPaginationMode();
stopLimitMode();
setShowLimitOptions(false);
setShowPaginationOptions(false);
setCaptureStage('initial');
updatePaginationType('');
updateLimitType('');
updateCustomLimit('');
setCurrentWorkflowActionsState({
hasScrapeListAction: false,
hasScreenshotAction: false,
hasScrapeSchemaAction: false
});
setWorkflow(emptyWorkflow);
resetInterpretationLog();
// Clear all browser steps
browserSteps.forEach(step => {
deleteBrowserStep(step.id);
});
if (socket) {
socket?.emit('new-recording');
socket.emit('input:url', initialUrl);
// Update the URL in the navbar to match
setRecordingUrl(initialUrl);
}
// Close the reset confirmation modal
setOpenResetModal(false);
// Notify user
notify('info', t('browser_recording.notifications.environment_reset'));
};
const performReset = () => {
try {
stopGetText();
stopGetList();
stopGetScreenshot();
stopPaginationMode();
stopLimitMode();
setShowLimitOptions(false);
setShowPaginationOptions(false);
setCaptureStage('initial');
updatePaginationType('');
updateLimitType('');
updateCustomLimit('');
setCurrentWorkflowActionsState({
hasScrapeListAction: false,
hasScreenshotAction: false,
hasScrapeSchemaAction: false
});
setWorkflow(emptyWorkflow);
resetInterpretationLog();
// Clear all browser steps
browserSteps.forEach(step => {
deleteBrowserStep(step.id);
});
if (socket) {
const socketPromises = [
new Promise((resolve, reject) => {
socket.emit('new-recording', null, (error: any) => {
if (error) reject(error);
resolve(null);
});
}),
new Promise((resolve, reject) => {
socket.emit('input:url', initialUrl, (error: any) => {
if (error) reject(error);
resolve(null);
});
})
];
Promise.all(socketPromises)
.then(() => {
setRecordingUrl(initialUrl);
setOpenResetModal(false);
notify('info', t('browser_recording.notifications.environment_reset'));
})
.catch((error) => {
console.error('Socket error during reset:', error);
notify('error', t('browser_recording.notifications.reset_failed'));
});
} else {
setOpenResetModal(false);
notify('info', t('browser_recording.notifications.environment_reset'));
}
} catch (error) {
console.error('Error during reset:', error);
notify('error', t('browser_recording.notifications.reset_failed'));
setOpenResetModal(false);
}
};

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: 1

🔭 Outside diff range comments (2)
src/components/recorder/RightSidePanel.tsx (2)

Line range hint 73-91: Refactor useEffect for better separation of concerns.

The current implementation combines socket event handling and periodic fetching in a single effect. This makes it harder to maintain and test. Consider:

  1. Separating socket event handling and periodic fetching into different effects
  2. Adding cleanup for in-flight fetch requests to prevent race conditions
// Split into two effects
useEffect(() => {
  if (socket) {
    socket.on("workflow", workflowHandler);
    return () => socket.off("workflow", workflowHandler);
  }
}, [socket, workflowHandler]);

useEffect(() => {
  if (!id) return;
  
  let isSubscribed = true;
  const controller = new AbortController();
  
  const fetchWithInterval = async () => {
    try {
      const response = await fetchWorkflow(id, (data) => {
        if (isSubscribed) workflowHandler(data);
      });
    } catch (error) {
      console.error('Failed to fetch workflow:', error);
    }
  };

  fetchWithInterval();
  const interval = setInterval(fetchWithInterval, 15 * 60 * 1000);
  
  return () => {
    isSubscribed = false;
    controller.abort();
    clearInterval(interval);
  };
}, [id, workflowHandler]);

Line range hint 1-1: Add error boundary for better error handling.

The component handles various error states but lacks a proper error boundary to catch and handle runtime errors gracefully.

// Create a new file: ErrorBoundary.tsx
import React, { Component, ErrorInfo, ReactNode } from 'react';

interface Props {
  children: ReactNode;
  fallback?: ReactNode;
}

interface State {
  hasError: boolean;
  error?: Error;
}

export class ErrorBoundary extends Component<Props, State> {
  public state: State = {
    hasError: false
  };

  public static getDerivedStateFromError(error: Error): State {
    return { hasError: true, error };
  }

  public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
    console.error('Uncaught error:', error, errorInfo);
  }

  public render() {
    if (this.state.hasError) {
      return this.props.fallback || <h1>Something went wrong.</h1>;
    }

    return this.props.children;
  }
}

// Wrap the RightSidePanel component with ErrorBoundary in parent component
<ErrorBoundary>
  <RightSidePanel onFinishCapture={handleFinishCapture} />
</ErrorBoundary>
🧹 Nitpick comments (8)
src/components/robot/RecordingsTable.tsx (2)

88-88: Consider grouping related state values together.

For better readability, consider grouping related state values together in the destructuring. For example, group URL-related states (recordingUrl, setRecordingUrl, initialUrl, setInitialUrl) and recording-related states (recordingName, setRecordingName, recordingId, setRecordingId).

- const { notify, setRecordings, browserId, setBrowserId, setInitialUrl, recordingUrl, setRecordingUrl, recordingName, setRecordingName, recordingId, setRecordingId } = useGlobalInfoStore();
+ const { 
+   // Browser state
+   browserId, setBrowserId,
+   // URL state
+   recordingUrl, setRecordingUrl, setInitialUrl,
+   // Recording metadata
+   recordingName, setRecordingName, recordingId, setRecordingId,
+   // Utilities
+   notify, setRecordings 
+ } = useGlobalInfoStore();

315-315: Add visual validation feedback to the URL input field.

Consider enhancing the TextField with error states and helper text for better user feedback during URL validation.

 <TextField
   label={t('recordingtable.modal.label')}
   variant="outlined"
   fullWidth
   value={recordingUrl}
-  onChange={setBrowserRecordingUrl}
+  onChange={syncBrowserRecordingUrls}
+  error={recordingUrl && recordingUrl !== 'https://' && !recordingUrl.match(/^https?:\/\/.+/)}
+  helperText={recordingUrl && recordingUrl !== 'https://' && !recordingUrl.match(/^https?:\/\/.+/) 
+    ? t('recordingtable.modal.invalid_url') 
+    : undefined}
   style={{ marginBottom: '20px', marginTop: '20px' }}
 />
src/components/recorder/RightSidePanel.tsx (4)

52-53: Remove commented-out code.

These state variables are now managed through context and are no longer needed. Clean up the codebase by removing the commented-out code.

-  // const [showPaginationOptions, setShowPaginationOptions] = useState(false);
-  // const [showLimitOptions, setShowLimitOptions] = useState(false);

68-71: Clean up workflowHandler implementation.

  1. Remove the commented-out code.
  2. Consider memoizing the callback with all its dependencies.
 const workflowHandler = useCallback((data: WorkflowFile) => {
   setWorkflow(data);
-  //setRecordingLength(data.workflow.length);
 }, [setWorkflow])

Line range hint 315-347: Improve type safety and readability of getListSettingsObject.

The current implementation has several areas for improvement:

  1. Add type safety for the limit parsing
  2. Extract field mapping logic to a separate function
  3. Add error handling for invalid limit values
const mapFieldsToSettings = (fields: Record<string, any>) => {
  return Object.entries(fields).reduce((acc, [id, field]) => {
    if (field.selectorObj?.selector) {
      acc[field.label] = {
        selector: field.selectorObj.selector,
        tag: field.selectorObj.tag,
        attribute: field.selectorObj.attribute,
      };
    }
    return acc;
  }, {} as Record<string, { selector: string; tag?: string; attribute?: string }>);
};

const getListSettingsObject = useCallback(() => {
  const limit = limitType === 'custom' 
    ? parseInt(customLimit, 10) 
    : parseInt(limitType, 10);

  if (isNaN(limit) || limit <= 0) {
    throw new Error('Invalid limit value');
  }

  const listStep = browserSteps.find(
    step => step.type === 'list' && 
    step.listSelector && 
    Object.keys(step.fields).length > 0
  );

  if (!listStep) return null;

  return {
    listSelector: listStep.listSelector,
    fields: mapFieldsToSettings(listStep.fields),
    pagination: { 
      type: paginationType, 
      selector: listStep.pagination?.selector 
    },
    limit,
  };
}, [browserSteps, paginationType, limitType, customLimit]);

Line range hint 1-1: Optimize component performance and organization.

The component is large and handles multiple responsibilities, which can impact performance and maintainability. Consider:

  1. Breaking down into smaller, focused components
  2. Memoizing expensive computations
  3. Using React.memo for child components

Example structure:

// TextCapturePanel.tsx
export const TextCapturePanel = React.memo(({ /* props */ }) => {
  // Text capture related logic and UI
});

// ListCapturePanel.tsx
export const ListCapturePanel = React.memo(({ /* props */ }) => {
  // List capture related logic and UI
});

// ScreenshotPanel.tsx
export const ScreenshotPanel = React.memo(({ /* props */ }) => {
  // Screenshot related logic and UI
});

// RightSidePanel.tsx
export const RightSidePanel: React.FC<RightSidePanelProps> = ({ onFinishCapture }) => {
  // Core panel logic
  return (
    <Paper>
      <TextCapturePanel />
      <ListCapturePanel />
      <ScreenshotPanel />
    </Paper>
  );
};
src/components/browser/BrowserRecordingSave.tsx (2)

17-20: Consider splitting component responsibilities.

The component is handling multiple concerns including recording management, modal state, menu state, and global state management. Consider extracting some of these responsibilities into separate components or custom hooks for better maintainability.

Example structure:

// useRecordingReset.ts
export const useRecordingReset = () => {
  const { stopGetText, stopGetList, /* other actions */ } = useActionContext();
  const performReset = () => { /* reset logic */ };
  return { performReset };
};

// useModalState.ts
export const useModalState = () => {
  const [openDiscardModal, setOpenDiscardModal] = useState(false);
  const [openResetModal, setOpenResetModal] = useState(false);
  return { openDiscardModal, setOpenDiscardModal, openResetModal, setOpenResetModal };
};

Also applies to: 25-38


Line range hint 121-154: Improve styling implementation.

Consider the following improvements:

  1. Extract inline styles to a styled-components or separate CSS file
  2. Move hardcoded color values to theme constants
  3. Use MUI's theme spacing instead of hardcoded pixel values

Example refactor:

// styles.ts
import { styled } from '@mui/material/styles';

export const StyledButton = styled(Button)(({ theme }) => ({
  marginLeft: theme.spacing(3),
  color: theme.palette.error.main,
  borderColor: theme.palette.error.main,
  backgroundColor: theme.palette.grey[100],
}));

export const StyledIconButton = styled(IconButton)(({ theme }) => ({
  color: theme.palette.common.white,
}));

Also applies to: 159-171, 174-204

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 96f4c85 and e17e5ba.

📒 Files selected for processing (4)
  • src/components/browser/BrowserRecordingSave.tsx (5 hunks)
  • src/components/recorder/RightSidePanel.tsx (2 hunks)
  • src/components/robot/RecordingsTable.tsx (3 hunks)
  • src/context/globalInfo.tsx (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/context/globalInfo.tsx
🔇 Additional comments (4)
src/components/browser/BrowserRecordingSave.tsx (4)

2-2: LGTM! Import statements are well-organized.

All new imports are properly structured and necessary for the reset functionality implementation.

Also applies to: 5-6, 11-13


95-101: LGTM! Event handlers are properly implemented.

The menu event handlers are concise and correctly typed.


51-93: Enhance error handling in reset operations.

The performReset function performs multiple cleanup operations sequentially. Consider:

  1. Adding error handling for each operation
  2. Handling potential race conditions during cleanup
  3. Ensuring socket operations are properly queued

Example enhancement:

const performReset = async () => {
  try {
    // Group related operations
    await Promise.all([
      stopGetText(),
      stopGetList(),
      stopGetScreenshot(),
      stopPaginationMode(),
      stopLimitMode()
    ]);

    // Update UI state
    setShowLimitOptions(false);
    setShowPaginationOptions(false);
    setCaptureStage('initial');

    // Clear browser steps
    await Promise.all(
      browserSteps.map(step => deleteBrowserStep(step.id))
    );

    // Socket operations
    if (socket?.connected) {
      await Promise.all([
        new Promise(resolve => socket.emit('new-recording', resolve)),
        new Promise(resolve => socket.emit('input:url', initialUrl, resolve))
      ]);
      setRecordingUrl(initialUrl);
    }

    setOpenResetModal(false);
    notify('info', t('browser_recording.notifications.environment_reset'));
  } catch (error) {
    notify('error', t('browser_recording.notifications.reset_failed'));
    console.error('Reset failed:', error);
  }
};

16-16: Verify localization string availability.

Ensure all translation keys used in the component are available in all language files.

Also applies to: 92-92, 166-167, 176-179, 186-187, 196-197

✅ Verification successful

Translation keys are properly implemented

All required translation keys are present in the localization files with the correct namespace structure. The component's usage of useTranslation hook is valid.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify translation keys exist in all language files

# List of translation keys to check
KEYS=(
  'browser_recording.notifications.environment_reset'
  'browser_recording.modal.confirm_reset'
  'browser_recording.modal.reset_warning'
  'right_panel.buttons.confirm_reset'
  'right_panel.buttons.cancel'
)

# Check each key in all language files
for key in "${KEYS[@]}"; do
  echo "Checking key: $key"
  for locale in public/locales/*.json; do
    jq --arg key "$key" 'path(.. | select(. == $key))' "$locale"
  done
done

Length of output: 4504


Script:

#!/bin/bash
# Check locale files existence and structure
echo "=== Listing locale files ==="
ls -l public/locales/

echo -e "\n=== Sampling content structure of en.json ==="
jq '.' public/locales/en.json | head -n 20

echo -e "\n=== Searching for partial key matches ==="
for locale in public/locales/*.json; do
  echo "=== Checking $locale for 'browser_recording' or 'right_panel' ==="
  jq 'paths | select(.[] | strings | contains("browser_recording") or contains("right_panel"))' "$locale" | head -n 5
done

Length of output: 3184


Script:

#!/bin/bash
echo "=== Checking right_panel structure in en.json ==="
jq '.right_panel' public/locales/en.json

echo -e "\n=== Searching for related keys ==="
for term in "recording" "reset" "environment"; do
  echo -e "\n=== Keys containing '$term' in en.json ==="
  jq 'paths as $p | select(getpath($p) | strings and (contains("'$term'") or contains("'${term^}'"))?) | $p | join(".")' public/locales/en.json
done

Length of output: 3733

Comment on lines +145 to +148
const setBrowserRecordingUrl = (event: React.ChangeEvent<HTMLInputElement>) => {
setInitialUrl(event.target.value);
setRecordingUrl(event.target.value);
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add URL validation and consider renaming the function.

  1. The function updates both initialUrl and recordingUrl but lacks URL validation.
  2. The function name could be more specific about its dual purpose.

Consider this implementation:

- const setBrowserRecordingUrl = (event: React.ChangeEvent<HTMLInputElement>) => {
-   setInitialUrl(event.target.value);
-   setRecordingUrl(event.target.value);
- }
+ const syncBrowserRecordingUrls = (event: React.ChangeEvent<HTMLInputElement>) => {
+   const url = event.target.value;
+   try {
+     // Basic URL validation
+     if (url && url !== 'https://' && !url.match(/^https?:\/\/.+/)) {
+       throw new Error('Invalid URL format');
+     }
+     setInitialUrl(url);
+     setRecordingUrl(url);
+   } catch (error) {
+     notify('error', 'Please enter a valid URL starting with http:// or https://');
+   }
+ }

Committable suggestion skipped: line range outside the PR's diff.

@RohitR311 RohitR311 requested a review from amhsirak January 10, 2025 06:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Feature New features
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants