-
Notifications
You must be signed in to change notification settings - Fork 1.1k
feat: move create robot from modal to page #812
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
Conversation
WalkthroughAdds a dedicated RobotCreate page and route (/robots/create), updates RecordingsTable to navigate directly to it, and implements the recording initiation flow within RobotCreate, including validation, optional discard of an active recording, state/session updates, and redirection. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant RecordingsTable
participant Router
participant RobotCreate
participant BrowserState as Browser/Recording State
participant Session as SessionStorage
participant Notifier as Notifications
participant API as Backend (stopRecording)
participant Tab as New Tab
User->>RecordingsTable: Click "New Recording"
RecordingsTable->>Router: navigate('/robots/create')
Router->>RobotCreate: Render form
User->>RobotCreate: Enter URL + Start Recording
RobotCreate->>RobotCreate: Validate URL
alt Invalid URL
RobotCreate->>Notifier: Show error
else Valid URL
RobotCreate->>BrowserState: canCreateBrowserInState("recording")?
alt Can create
RobotCreate->>Session: Save browserId, recordingUrl, initialUrl, needsLogin, sessionId
RobotCreate->>Tab: Open recording setup
RobotCreate->>Router: navigate('/robots')
else Blocked and active browser exists
RobotCreate->>User: Show warning modal
alt Discard and continue
RobotCreate->>API: stopRecording(activeBrowserId)
API-->>RobotCreate: ok
RobotCreate->>Notifier: Show termination notice
RobotCreate->>Session: Save session values
RobotCreate->>Tab: Open recording setup
RobotCreate->>Router: navigate('/robots')
else Cancel
RobotCreate-->>User: Stay on page
end
else Blocked, no active browser
RobotCreate->>Notifier: Show limit notice
end
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20–30 minutes Possibly related issues
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
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. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/components/robot/RecordingsTable.tsx (1)
368-371
: Addnoopener,noreferrer
towindow.open
in retrain flow.Same tabnabbing risk exists here.
- window.openedRecordingWindow = window.open(`/recording-setup?session=${sessionId}`, '_blank'); + window.openedRecordingWindow = window.open(`/recording-setup?session=${sessionId}`, '_blank', 'noopener,noreferrer'); ... - window.openedRecordingWindow = window.open(`/recording-setup?session=${sessionId}`, '_blank'); + window.openedRecordingWindow = window.open(`/recording-setup?session=${sessionId}`, '_blank', 'noopener,noreferrer');Also applies to: 387-390
🧹 Nitpick comments (9)
src/components/robot/pages/RobotCreate.tsx (6)
41-45
: Tighten URL validation and input type.Guard against empty/invalid/unsafe schemes and use an URL input for better UX.
- if (!url.trim()) { - notify('error', 'Please enter a valid URL'); - return; - } + const isHttpUrl = (s: string) => { + try { + const u = new URL(s); + return u.protocol === 'http:' || u.protocol === 'https:'; + } catch { return false; } + }; + if (!isHttpUrl(url.trim())) { + notify('error', t('robot_create.errors.invalid_url')); + return; + }- <TextField + <TextField + type="url" placeholder="Example: https://www.ycombinator.com/companies/"Also applies to: 169-176
71-76
: Prefer collision-resistant session IDs.Use
crypto.randomUUID()
when available.- const sessionId = Date.now().toString(); + const sessionId = (window.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`); ... - const sessionId = Date.now().toString(); + const sessionId = (window.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random()}`);Also applies to: 105-111
28-29
: Remove unused imports/state.
setRecordingId
,AuthContext
, anduser
are not used.-import { AuthContext } from '../../../context/auth'; ... - const { setBrowserId, setRecordingUrl, notify, setRecordingId } = useGlobalInfoStore(); + const { setBrowserId, setRecordingUrl, notify } = useGlobalInfoStore(); ... - const { state } = React.useContext(AuthContext); - const { user } = state; + // AuthContext not needed here; remove import and usage.Also applies to: 21-22, 36-38
197-209
: Localize user‑facing strings.Several literals bypass i18n (titles, placeholders, labels, button text, alt/aria). Replace with
t(...)
keys.Example:
- <Typography variant="h5" component="h1"> - New Data Extraction Robot - </Typography> + <Typography variant="h5" component="h1"> + {t('robot_create.title')} + </Typography>- {isLoading ? 'Starting...' : 'Start Recording'} + {isLoading ? t('robot_create.button.starting') : t('robot_create.button.start')}Also localize: back aria-label, placeholder, checkbox label, helper section titles/descriptions, image alt.
Also applies to: 149-151, 168-176, 188-189, 216-222, 251-256, 287-291, 164-165, 145-145
169-176
: Optional: prefill with current domain on focus (UX).You can auto‑insert
https://
if the user starts typing without scheme to reduce errors.
339-349
: Responsive modal width.Fixed
width: '30%'
can be too narrow/too wide. Use breakpoints.- width: '30%', + width: { xs: '92%', sm: 520, md: 560 },src/pages/PageWrapper.tsx (1)
15-15
: Code‑split the new page to reduce initial bundle.Load
RobotCreate
lazily and wrap the route withSuspense
.-import RobotCreate from '../components/robot/pages/RobotCreate'; +const RobotCreate = React.lazy(() => import('../components/robot/pages/RobotCreate'));- <Route path="/robots/create" element={<RobotCreate />} /> + <Route + path="/robots/create" + element={ + <React.Suspense fallback={null}> + <RobotCreate /> + </React.Suspense> + } + />Also applies to: 98-99
src/components/robot/RecordingsTable.tsx (2)
605-639
: Remove legacy “New Recording” modal and related state.After routing to
/robots/create
, this modal and its state (isModalOpen
, URL field, login checkbox,startRecording
,setBrowserRecordingUrl
) are unreachable.- const [isModalOpen, setModalOpen] = React.useState(false); ... - <GenericModal isOpen={isModalOpen} onClose={() => setModalOpen(false)} modalStyle={modalStyle}> - <div style={{ padding: '10px' }}> - <Typography variant="h6" gutterBottom>{t('recordingtable.modal.title')}</Typography> - <TextField - label={t('recordingtable.modal.label')} - variant="outlined" - fullWidth - value={recordingUrl} - onChange={setBrowserRecordingUrl} - style={{ marginBottom: '10px', marginTop: '20px' }} - /> - <FormControlLabel - control={ - <Checkbox - checked={isLogin} - onChange={(e) => setIsLogin(e.target.checked)} - color="primary" - /> - } - label={t('recordingtable.modal.login_title')} - style={{ marginBottom: '10px' }} - /> - <br /> - <Button - variant="contained" - color="primary" - onClick={startRecording} - disabled={!recordingUrl} - > - {t('recordingtable.modal.button')} - </Button> - </div> - </GenericModal>Follow‑up: remove now‑unused imports (
FormControlLabel
,Checkbox
), state (isModalOpen
,isLogin
), and functions (startRecording
,setBrowserRecordingUrl
).Also applies to: 154-159, 617-627, 631-637
779-789
: Optional: align modal width with page modal.Consider adopting the responsive widths suggested in RobotCreate for consistency.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/components/robot/RecordingsTable.tsx
(1 hunks)src/components/robot/pages/RobotCreate.tsx
(1 hunks)src/pages/PageWrapper.tsx
(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/components/robot/pages/RobotCreate.tsx (3)
src/context/globalInfo.tsx (1)
useGlobalInfoStore
(165-165)src/api/recording.ts (1)
stopRecording
(17-23)src/components/ui/GenericModal.tsx (1)
GenericModal
(13-29)
🔇 Additional comments (2)
src/components/robot/RecordingsTable.tsx (1)
281-283
: LGTM: direct navigation to the create page.Simplifies the flow and centralizes logic in the new page.
src/components/robot/pages/RobotCreate.tsx (1)
103-104
: Drop theisLogin
suggestion—noisLogin
key is used anywhere;needsLogin
is consistently new and has no conflicting consumers.Likely an incorrect or invalid review comment.
window.open(`/recording-setup?session=${sessionId}`, '_blank'); | ||
window.sessionStorage.setItem('nextTabIsRecording', 'true'); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prevent tabnabbing: add noopener,noreferrer
to window.open
.
Opening a new tab without noopener
lets the child tab access window.opener
. Harden both opens.
- window.open(`/recording-setup?session=${sessionId}`, '_blank');
+ window.open(`/recording-setup?session=${sessionId}`, '_blank', 'noopener,noreferrer');
...
- window.open(`/recording-setup?session=${sessionId}`, '_blank');
+ window.open(`/recording-setup?session=${sessionId}`, '_blank', 'noopener,noreferrer');
Also applies to: 108-110
🤖 Prompt for AI Agents
In src/components/robot/pages/RobotCreate.tsx around lines 74-76 (and also apply
same change at lines 108-110), window.open is called without rel attributes so
the newly opened tab can access window.opener; update both window.open calls to
include the third argument with 'noopener,noreferrer' (or set rel via anchor
equivalent) to prevent tabnabbing and remove window.opener access, e.g., open
with window.open(url, '_blank', 'noopener,noreferrer') or use an anchor with
rel="noopener noreferrer".
onClick={() => window.open("https://www.youtube.com/@MaxunOSS/videos", "_blank")} | ||
> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Harden external link opens.
Add noopener,noreferrer
to window.open
for YouTube and docs cards.
- onClick={() => window.open("https://www.youtube.com/@MaxunOSS/videos", "_blank")}
+ onClick={() => window.open("https://www.youtube.com/@MaxunOSS/videos", "_blank", "noopener,noreferrer")}
...
- onClick={() => window.open("https://docs.maxun.dev", "_blank")}
+ onClick={() => window.open("https://docs.maxun.dev", "_blank", "noopener,noreferrer")}
Also applies to: 268-269
🤖 Prompt for AI Agents
In src/components/robot/pages/RobotCreate.tsx around lines 232-233 (and also
apply same change at 268-269), the external links opened with window.open lack
noopener and noreferrer protections; update the window.open calls to include
those flags by passing them as the third argument (e.g. window.open(url,
"_blank", "noopener,noreferrer")) and optionally nulling the opener on the
returned window (const w = window.open(...); if (w) w.opener = null) to fully
harden the external link openings.
What this PR does?
closes #793
Moves the create robot UI from modal to dedicated create robot page.
Summary by CodeRabbit
New Features
Refactor