-
Notifications
You must be signed in to change notification settings - Fork 1.7k
feat: integrate sync eng #2924
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: integrate sync eng #2924
Conversation
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughReplaces sandbox-first file handling with a branch-scoped CodeFileSystem and FS-driven sync; refactors the right-panel code editor to a per-file filesystem model with a forwarded-ref API; propagates branchId through models/tools/UI; removes many legacy image/sync/template/preload managers, pages, and tests. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant UI as CodeTab (UI)
participant Tree as FileTree
participant FS as CodeFileSystem
participant Sync as SyncEngine
participant SB as Sandbox/Provider
UI->>Tree: select/open(filePath)
Tree->>FS: readFile(filePath)
FS-->>Tree: content
Tree-->>UI: render editor (CodeEditor)
UI->>FS: writeFile(path, content)
FS->>FS: update JSX index (if JSX/TSX)
FS-->>UI: ack
par background sync
Sync->>FS: detect local modifications
Sync->>SB: pushModifiedFilesToSandbox(files)
SB-->>Sync: ack
end
sequenceDiagram
autonumber
participant Parent as App (Parent)
participant Child as IFrame (Preload)
participant State as Preload State
Parent->>Child: setFrameId(...)
Parent->>Child: setBranchId(branchId)
Child->>State: store frameId/branchId
Child->>Parent: getBranchId() (if missing)
Parent-->>Child: branchId
Note over Parent,Child: branchId used for metadata lookups and tool ops
Estimated code review effort🎯 5 (Critical) | ⏱️ ~150 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (3)
🧰 Additional context used📓 Path-based instructions (6)apps/web/client/src/app/**/*.tsx📄 CodeRabbit inference engine (AGENTS.md)
Files:
apps/web/client/src/**/*.{ts,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
apps/web/client/src/**/*.tsx📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{ts,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
apps/web/client/src/app/**/*.{ts,tsx}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
{apps,packages}/**/*.{ts,tsx}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
🧠 Learnings (2)📚 Learning: 2025-09-16T19:22:52.461ZApplied to files:
📚 Learning: 2025-09-14T01:44:21.209ZApplied to files:
🧬 Code graph analysis (3)apps/web/client/src/app/_components/login-button.tsx (3)
apps/web/client/src/app/login/page.tsx (2)
apps/web/client/src/app/_components/auth-modal.tsx (2)
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 |
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
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: 4
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
apps/web/client/src/app/project/[id]/_components/left-panel/brand-tab/index.tsx(1 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx(2 hunks)apps/web/client/src/app/project/[id]/_hooks/use-start-project.tsx(1 hunks)apps/web/client/src/app/test-sync-engine/page.tsx(1 hunks)apps/web/client/src/components/store/editor/sandbox/index.ts(7 hunks)apps/web/client/src/services/sync-engine/index.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
apps/web/client/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/**/*.{ts,tsx}: Use path aliases @/* and ~/* for imports that map to apps/web/client/src/*
Avoid hardcoded user-facing text; use next-intl messages/hooks insteadUse path aliases @/* and ~/* for imports mapping to src/*
Files:
apps/web/client/src/services/sync-engine/index.tsapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsxapps/web/client/src/app/project/[id]/_hooks/use-start-project.tsxapps/web/client/src/app/test-sync-engine/page.tsxapps/web/client/src/components/store/editor/sandbox/index.tsapps/web/client/src/app/project/[id]/_components/left-panel/brand-tab/index.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Do not use the any type unless necessary
Files:
apps/web/client/src/services/sync-engine/index.tsapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsxapps/web/client/src/app/project/[id]/_hooks/use-start-project.tsxapps/web/client/src/app/test-sync-engine/page.tsxapps/web/client/src/components/store/editor/sandbox/index.tsapps/web/client/src/app/project/[id]/_components/left-panel/brand-tab/index.tsx
{apps,packages}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Avoid using the any type unless absolutely necessary
Files:
apps/web/client/src/services/sync-engine/index.tsapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsxapps/web/client/src/app/project/[id]/_hooks/use-start-project.tsxapps/web/client/src/app/test-sync-engine/page.tsxapps/web/client/src/components/store/editor/sandbox/index.tsapps/web/client/src/app/project/[id]/_components/left-panel/brand-tab/index.tsx
apps/web/client/src/app/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/app/**/*.tsx: Default to Server Components; add 'use client' when using events, state/effects, browser APIs, or client‑only libraries
Do not use process.env in client code; import env from @/env insteadAvoid hardcoded user-facing text; use next-intl messages/hooks
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsxapps/web/client/src/app/project/[id]/_hooks/use-start-project.tsxapps/web/client/src/app/test-sync-engine/page.tsxapps/web/client/src/app/project/[id]/_components/left-panel/brand-tab/index.tsx
apps/web/client/src/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/**/*.tsx: Create MobX store instances with useState(() => new Store()) for stable references across renders
Keep the active MobX store in a useRef and perform async cleanup with setTimeout(() => storeRef.current?.clear(), 0) to avoid route-change races
Avoid useMemo for creating MobX store instances
Avoid putting the MobX store instance in effect dependency arrays if it causes loops; split concerns by domain
apps/web/client/src/**/*.tsx: Create MobX store instances with useState(() => new Store()) for stable identities across renders
Keep the active MobX store in a useRef and clean up asynchronously with setTimeout(() => storeRef.current?.clear(), 0)
Do not use useMemo to create MobX stores
Avoid placing MobX store instances in effect dependency arrays if it causes loops; split concerns instead
observer components must be client components; place a single client boundary at the feature entry; child observers need not repeat 'use client'
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsxapps/web/client/src/app/project/[id]/_hooks/use-start-project.tsxapps/web/client/src/app/test-sync-engine/page.tsxapps/web/client/src/app/project/[id]/_components/left-panel/brand-tab/index.tsx
apps/web/client/src/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Default to Server Components; add 'use client' only when using events, state/effects, browser APIs, or client-only libs
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsxapps/web/client/src/app/project/[id]/_hooks/use-start-project.tsxapps/web/client/src/app/test-sync-engine/page.tsxapps/web/client/src/app/project/[id]/_components/left-panel/brand-tab/index.tsx
🧠 Learnings (3)
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
PR: onlook-dev/onlook#0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/**/*.{ts,tsx} : Use path aliases @/* and ~/* for imports that map to apps/web/client/src/*
Applied to files:
apps/web/client/src/services/sync-engine/index.tsapps/web/client/src/app/test-sync-engine/page.tsx
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
PR: onlook-dev/onlook#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/**/*.{ts,tsx} : Use path aliases @/* and ~/* for imports mapping to src/*
Applied to files:
apps/web/client/src/services/sync-engine/index.tsapps/web/client/src/app/test-sync-engine/page.tsx
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
PR: onlook-dev/onlook#0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/app/**/*.tsx : Default to Server Components; add 'use client' when using events, state/effects, browser APIs, or client‑only libraries
Applied to files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
🧬 Code graph analysis (1)
apps/web/client/src/components/store/editor/sandbox/index.ts (4)
apps/web/client/src/components/store/editor/sandbox/session.ts (1)
SessionManager(8-217)packages/file-system/src/fs.ts (1)
FileSystem(13-562)packages/models/src/sandbox/files.ts (1)
SandboxFile(17-17)packages/code-provider/src/types.ts (2)
ListFilesOutputFile(49-53)WatchEvent(102-105)
🔇 Additional comments (3)
apps/web/client/src/services/sync-engine/index.ts (1)
2-2: Re-export path update looks goodUsing the hyphenated module path keeps the barrel export aligned with the renamed file; no further changes needed.
apps/web/client/src/app/project/[id]/_hooks/use-start-project.tsx (1)
56-60: Reconnection trigger hooked up cleanlyThe new effect ties the reconnect to tab reactivation while pulling from the centralized
sandbox.session, which lines up with the broader sync-engine migration.apps/web/client/src/app/test-sync-engine/page.tsx (1)
13-13: Import path update aligns with new module layoutThanks for updating the hook import to the hyphenated path; this keeps the test page tracking the sync-engine re-export structure.
apps/web/client/src/app/project/[id]/_components/left-panel/brand-tab/index.tsx
Outdated
Show resolved
Hide resolved
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
Outdated
Show resolved
Hide resolved
|
|
||
| // File system | ||
| const rootDir = `/${editorEngine.projectId}/${editorEngine.branches.activeBranch.id}`; | ||
| // const { fs, isInitializing: fsInitializing, error: fsError } = useFS(rootDir); |
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.
There is commented-out code for the useFS hook. Remove unused code if it’s no longer required to reduce confusion.
| // const { fs, isInitializing: fsInitializing, error: fsError } = useFS(rootDir); |
| // Get file icon based on extension | ||
| const getFileIcon = () => { | ||
| const extension = node.data.extension?.toLowerCase(); | ||
| const extension = node.data.path.split('.').pop()?.toLowerCase(); |
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.
The file icon logic attempts to check for extensions starting with '.', but the extracted extension from 'split' does not include the dot. Adjust the case labels (e.g. use 'js' instead of '.js') or prepend the dot to the extracted extension.
| const extension = node.data.path.split('.').pop()?.toLowerCase(); | |
| const extension = '.' + node.data.path.split('.').pop()?.toLowerCase(); |
| {contextMenuItems.find(item => item.label === 'Create File') && ( | ||
| <button | ||
| onClick={() => { | ||
| const fileName = prompt('Enter file name:'); |
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.
User input is obtained via prompt for file and directory creation without sanitization. Consider adding basic input validation to avoid potential issues.
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: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx (1)
47-79: Restore file-icon matching by fixing the extension switch
extensionis now justjs,tsx, etc., but the switch still looks for values like.js. Because the cases never match, every non-directory fallback renders the default icon. Update the switch (or reintroduce the dot prefix) so icons reflect actual file types again.Apply this diff to normalize the extension handling:
- const extension = node.data.path.split('.').pop()?.toLowerCase(); + const extension = node.data.path.split('.').pop()?.toLowerCase(); ... - switch (extension) { - case '.js': - case '.jsx': - case '.ts': - case '.tsx': + switch (`.${extension ?? ''}`) { + case '.js': + case '.jsx': + case '.ts': + case '.tsx':apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx (1)
435-438: Avoid treating directories as files in the tree selection
FileNodeno longer exposesisDirectory, so this check always treats directories as files. Selecting a folder now tries to open it and will error. Switch the predicate to the newtype === 'directory'shape before invokingloadFile.- if (nodes.length > 0 && !nodes[0].data.isDirectory) { + if (nodes.length > 0 && nodes[0].data.type !== 'directory') {apps/web/client/src/services/sync-engine/sync-engine.ts (1)
342-375: Restore exclude filtering during recursive directory syncThe new
syncDirectoryContentstraversal no longer callsshouldSyncon nested entries. If a sandbox change arrives for an allowed parent (e.g.src/), we now blindly recreate excluded descendants such assrc/node_modules/**. That defeats the exclusion list and can overwhelm the local FS with large folders we explicitly skip. Please reintroduce the filter before creating directories or reading files.- for (const item of dirContents.files) { + for (const item of dirContents.files) { const itemSandboxPath = `${sandboxPath}/${item.name}`; const itemLocalPath = `${localDirPath}/${item.name}`; + if (!this.shouldSync(itemLocalPath)) { + continue; + } + if (item.type === 'directory') { // Create subdirectory console.log(`[Sync] Creating subdirectory ${itemLocalPath}`);
🧹 Nitpick comments (4)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/unsaved-changes-dialog.tsx (1)
12-34: Localize the dialog copyThis component hardcodes user-facing strings. Per our web-client guidelines, route this through next-intl (or the established localization helper) so the dialog can be translated.
As per coding guidelines
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor-area.tsx (1)
33-45: Externalize the user-facing stringsStrings such as “Loading file...” and “Open a file or select an element on the page.” should be sourced from next-intl rather than hardcoded so that we comply with localization guidelines. Please move them into the message catalogs and pull them in via the intl hooks.
As per coding guidelines
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree.tsx (1)
27-238: Localize the sidebar stringsLabels like “Files”, “No files found”, “Search files”, and “Refresh files” are hardcoded. Please surface them through the next-intl messages so that the sidebar can be translated.
As per coding guidelines
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsx (1)
4-4: Prefer the configured path alias for local importsPer the client coding guidelines we should use the
@/*/~/*aliases for imports underapps/web/client/src. Please switch this relative import to the alias-based path.-import type { FileNode } from '../types'; +import type { FileNode } from '@/app/project/[id]/_components/right-panel/code-tab/types';
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (16)
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-block.tsx(1 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-diff.tsx(1 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/code-controls.tsx(0 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor-area.tsx(1 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor.tsx(1 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/file-tab.tsx(2 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/unsaved-changes-dialog.tsx(1 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx(6 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx(3 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsx(1 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree.tsx(10 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/types.ts(1 hunks)apps/web/client/src/components/store/editor/ide/index.ts(1 hunks)apps/web/client/src/components/store/editor/sandbox/index.ts(7 hunks)apps/web/client/src/services/sync-engine/sync-engine.ts(6 hunks)packages/models/src/code/index.ts(0 hunks)
💤 Files with no reviewable changes (2)
- packages/models/src/code/index.ts
- apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/code-controls.tsx
✅ Files skipped from review due to trivial changes (1)
- apps/web/client/src/components/store/editor/ide/index.ts
🧰 Additional context used
📓 Path-based instructions (6)
apps/web/client/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/**/*.{ts,tsx}: Use path aliases @/* and ~/* for imports that map to apps/web/client/src/*
Avoid hardcoded user-facing text; use next-intl messages/hooks insteadUse path aliases @/* and ~/* for imports mapping to src/*
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/types.tsapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor.tsxapps/web/client/src/services/sync-engine/sync-engine.tsapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-diff.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor-area.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsxapps/web/client/src/components/store/editor/sandbox/index.tsapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-block.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/file-tab.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/unsaved-changes-dialog.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Do not use the any type unless necessary
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/types.tsapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor.tsxapps/web/client/src/services/sync-engine/sync-engine.tsapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-diff.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor-area.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsxapps/web/client/src/components/store/editor/sandbox/index.tsapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-block.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/file-tab.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/unsaved-changes-dialog.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree.tsx
apps/web/client/src/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Default to Server Components; add 'use client' only when using events, state/effects, browser APIs, or client-only libs
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/types.tsapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-diff.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor-area.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-block.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/file-tab.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/unsaved-changes-dialog.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree.tsx
{apps,packages}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Avoid using the any type unless absolutely necessary
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/types.tsapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor.tsxapps/web/client/src/services/sync-engine/sync-engine.tsapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-diff.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor-area.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsxapps/web/client/src/components/store/editor/sandbox/index.tsapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-block.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/file-tab.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/unsaved-changes-dialog.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree.tsx
apps/web/client/src/app/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/app/**/*.tsx: Default to Server Components; add 'use client' when using events, state/effects, browser APIs, or client‑only libraries
Do not use process.env in client code; import env from @/env insteadAvoid hardcoded user-facing text; use next-intl messages/hooks
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-diff.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor-area.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-block.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/file-tab.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/unsaved-changes-dialog.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree.tsx
apps/web/client/src/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/**/*.tsx: Create MobX store instances with useState(() => new Store()) for stable references across renders
Keep the active MobX store in a useRef and perform async cleanup with setTimeout(() => storeRef.current?.clear(), 0) to avoid route-change races
Avoid useMemo for creating MobX store instances
Avoid putting the MobX store instance in effect dependency arrays if it causes loops; split concerns by domain
apps/web/client/src/**/*.tsx: Create MobX store instances with useState(() => new Store()) for stable identities across renders
Keep the active MobX store in a useRef and clean up asynchronously with setTimeout(() => storeRef.current?.clear(), 0)
Do not use useMemo to create MobX stores
Avoid placing MobX store instances in effect dependency arrays if it causes loops; split concerns instead
observer components must be client components; place a single client boundary at the feature entry; child observers need not repeat 'use client'
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-diff.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor-area.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-block.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/file-tab.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/unsaved-changes-dialog.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree.tsx
🧠 Learnings (3)
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
PR: onlook-dev/onlook#0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/app/**/*.tsx : Default to Server Components; add 'use client' when using events, state/effects, browser APIs, or client‑only libraries
Applied to files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
PR: onlook-dev/onlook#0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/**/*.{ts,tsx} : Use path aliases @/* and ~/* for imports that map to apps/web/client/src/*
Applied to files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsx
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
PR: onlook-dev/onlook#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/**/*.{ts,tsx} : Use path aliases @/* and ~/* for imports mapping to src/*
Applied to files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsx
🧬 Code graph analysis (6)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor.tsx (3)
apps/web/client/src/components/store/editor/ide/index.ts (1)
EditorFile(8-17)apps/web/client/src/components/store/editor/index.tsx (1)
useEditorEngine(10-14)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-mirror-config.ts (2)
getBasicSetup(254-281)getExtensions(309-326)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor-area.tsx (4)
apps/web/client/src/components/store/editor/ide/index.ts (1)
EditorFile(8-17)apps/web/client/src/components/store/editor/index.tsx (1)
useEditorEngine(10-14)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor.tsx (1)
CodeEditor(17-85)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/unsaved-changes-dialog.tsx (1)
UnsavedChangesDialog(9-39)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx (4)
apps/web/client/src/components/store/editor/index.tsx (1)
useEditorEngine(10-14)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/types.ts (1)
FileNode(1-6)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor-area.tsx (1)
CodeEditorArea(17-75)apps/web/client/src/components/store/editor/ide/index.ts (1)
updateFileContent(143-152)
apps/web/client/src/components/store/editor/sandbox/index.ts (3)
apps/web/client/src/components/store/editor/sandbox/session.ts (1)
SessionManager(8-217)packages/file-system/src/fs.ts (1)
FileSystem(13-562)apps/web/client/src/services/sync-engine/sync-engine.ts (1)
CodeProviderSync(27-631)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/unsaved-changes-dialog.tsx (1)
packages/ui/src/components/button.tsx (1)
Button(57-57)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree.tsx (1)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx (1)
FileTreeNode(23-174)
🔇 Additional comments (7)
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-block.tsx (1)
1-1: Import realignment looks good.The updated alias matches the new file-content location for the CodeMirror config and keeps the module resolution consistent across the refactor.
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-diff.tsx (1)
4-4: Import path realignment looks good.Line 4 now points to the relocated CodeMirror config under
file-content, matching the refactor.apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor.tsx (1)
1-85: FixEditorSelectionimport to prevent build break
EditorSelectionis defined in@codemirror/state, not@uiw/react-codemirror. The current import will fail TypeScript/webpack resolution, breaking the build. Point the import back to@codemirror/state.-import { EditorView } from '@codemirror/view'; -import CodeMirror from '@uiw/react-codemirror'; +import { EditorView } from '@codemirror/view'; +import { EditorSelection } from '@codemirror/state'; +import CodeMirror from '@uiw/react-codemirror'; - import { EditorSelection } from '@uiw/react-codemirror';Likely an incorrect or invalid review comment.
apps/web/client/src/components/store/editor/sandbox/index.ts (2)
267-275: Restore functionalreadFileimplementation
readFilenow always returnsnull, so every call site (e.g.,editorEngine.activeSandbox.readFilein the code editor) will fail to load file contents, effectively bricking the editor. We need to wire this up to the new filesystem (or restore the previous provider-backed logic) before merging.
290-322:writeFilemust persist editor savesReturning
falseshort-circuits all writes. Callers such asprocessFileForMappingand user-initiated saves silently fail, so no edits ever reach the sandbox or local FS. Please re-implement this to write through the new FileSystem (and trigger the sync) or reinstate the prior provider-backed flow.apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/file-tab.tsx (1)
13-20: Plain-function export keeps typings sharp.The move away from
React.FCremoves implicit children and aligns with our preferred style while keeping thedata-activedestructuring nicely typed.apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/types.ts (1)
1-6: Local FileNode mirrors the new tree usage well.With name/path/type spelled out here, the sidebar components get a clean, recursive structure to rely on—looks solid.
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx
Outdated
Show resolved
Hide resolved
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree.tsx
Outdated
Show resolved
Hide resolved
| async delete(path: string, recursive?: boolean): Promise<boolean> { | ||
| if (!this.session.provider) { | ||
| console.error('No provider found for delete file'); | ||
| return false; | ||
| } | ||
|
|
||
| try { | ||
| const normalizedPath = normalizePath(path); | ||
|
|
||
| // Check if file exists before attempting to delete | ||
| const exists = await this.fileExists(normalizedPath); | ||
| if (!exists) { | ||
| console.error(`File ${normalizedPath} does not exist`); | ||
| return false; | ||
| } | ||
|
|
||
| // Delete the file using the filesystem API | ||
| await this.session.provider.deleteFiles({ | ||
| args: { | ||
| path: normalizedPath, | ||
| recursive, | ||
| }, | ||
| }); | ||
|
|
||
| // Clean up the file sync cache | ||
| await this.fileSync.delete(normalizedPath); | ||
|
|
||
| // Publish file deletion event | ||
| this.fileEventBus.publish({ | ||
| type: 'remove', | ||
| paths: [normalizedPath], | ||
| timestamp: Date.now(), | ||
| }); | ||
|
|
||
| console.log(`Successfully deleted file: ${normalizedPath}`); | ||
| return true; | ||
| } catch (error) { | ||
| console.error(`Error deleting file ${path}:`, error); | ||
| return false; | ||
| } | ||
| return false; | ||
| // if (!this.session.provider) { | ||
| // console.error('No provider found for delete file'); | ||
| // return false; | ||
| // } | ||
|
|
||
| // try { | ||
| // const normalizedPath = normalizePath(path); | ||
|
|
||
| // // Check if file exists before attempting to delete | ||
| // const exists = await this.fileExists(normalizedPath); | ||
| // if (!exists) { | ||
| // console.error(`File ${normalizedPath} does not exist`); | ||
| // return false; | ||
| // } | ||
|
|
||
| // // Delete the file using the filesystem API | ||
| // await this.session.provider.deleteFiles({ | ||
| // args: { | ||
| // path: normalizedPath, | ||
| // recursive, | ||
| // }, | ||
| // }); | ||
|
|
||
| // // Clean up the file sync cache | ||
| // await this.fileSync.delete(normalizedPath); | ||
|
|
||
| // // Publish file deletion event | ||
| // this.fileEventBus.publish({ | ||
| // type: 'remove', | ||
| // paths: [normalizedPath], | ||
| // timestamp: Date.now(), | ||
| // }); | ||
|
|
||
| // console.log(`Successfully deleted file: ${normalizedPath}`); | ||
| // return true; | ||
| // } catch (error) { | ||
| // console.error(`Error deleting file ${path}:`, error); | ||
| // return false; | ||
| // } | ||
| } |
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.
Implement file deletion against the new FS/provider
delete now just returns false, which means UI flows like the file-tree “Delete” action never remove anything. Please hook this up to the FileSystem (and let the sync propagate upstream) or call the provider API so deletions actually happen.
🤖 Prompt for AI Agents
In apps/web/client/src/components/store/editor/sandbox/index.ts around lines 702
to 743, the delete method currently returns false and is not wired to the new
FS/provider; replace that stub with logic that: verify this.session.provider
exists and throw or return false if absent, normalize the input path, optionally
check file existence via this.fileExists(normalizedPath), call the provider
filesystem delete API (e.g., this.session.provider.deleteFiles or the FS client)
with the normalized path and recursive flag, await completion, remove any local
cache via await this.fileSync.delete(normalizedPath), publish a 'remove' event
on this.fileEventBus with paths and timestamp, and wrap the flow in try/catch to
log errors and return true on success or false on failure.
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: 4
🧹 Nitpick comments (5)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/modals/file-modal.tsx (1)
21-22: Use the project path alias instead of a relative import.Per our client-side guidelines we should prefer the
@/*(or~/*) alias for anything underapps/web/client/src. Please update these two imports to use the alias so they stay resilient to directory reshuffles.-import { - createFileInSandbox, - doesFileExist, - validateFileName, -} from '../shared/file-operations'; -import { getFileTemplate } from '../shared/file-templates'; +import { + createFileInSandbox, + doesFileExist, + validateFileName, +} from '@/app/project/[id]/_components/right-panel/code-tab/shared/file-operations'; +import { getFileTemplate } from '@/app/project/[id]/_components/right-panel/code-tab/shared/file-templates';apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx (1)
64-68: Drop debug logging before mergePlease remove the stray
console.logso we don’t leak noisy debug output into production bundles.- console.log('localFiles', localFiles); - // _____________________________________________________ -apps/web/client/src/app/test-local-fs/page.tsx (1)
21-21: Switch FileExplorer import to the @ aliasPer our client-side guidelines we should reference modules under
apps/web/client/srcvia the configured@/(or~/) alias instead of relative paths, so let’s update this import accordingly.-import { FileExplorer, type FileNode } from '../test-sync-engine/_components/file-explorer'; +import { FileExplorer, type FileNode } from '@/app/test-sync-engine/_components/file-explorer';apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/index.tsx (1)
51-74: Externalize the dropdown/tooltip copyThe new UI strings (
'Collapse sidebar','Expand sidebar','Close file','Close all') should flow throughnext-intlrather than being inlined so we stay compliant with the app directory i18n rule. Please wire these throughuseTranslations(or the existing messages helper for this surface) before merging.apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsx (1)
4-24: Use the project path alias for importsThe shared type lives under
apps/web/client/src, so please swap this relative import for the configured@/…alias to stay aligned with our client-side import guidelines.Apply this diff:
-import type { FileNode } from '../shared/types'; +import type { FileNode } from '@/app/project/[id]/_components/right-panel/code-tab/shared/types';Based on learnings
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx(1 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/file-tab.tsx(2 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/index.tsx(1 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx(5 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/modals/file-modal.tsx(1 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/modals/folder-modal.tsx(1 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/shared/types.ts(1 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx(1 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsx(2 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree.tsx(1 hunks)apps/web/client/src/app/test-local-fs/page.tsx(2 hunks)
✅ Files skipped from review due to trivial changes (1)
- apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/modals/folder-modal.tsx
👮 Files not reviewed due to content moderation or server errors (1)
- apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/shared/types.ts
🧰 Additional context used
📓 Path-based instructions (6)
apps/web/client/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/**/*.{ts,tsx}: Use path aliases @/* and ~/* for imports that map to apps/web/client/src/*
Avoid hardcoded user-facing text; use next-intl messages/hooks insteadUse path aliases @/* and ~/* for imports mapping to src/*
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/shared/types.tsapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/modals/file-modal.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsxapps/web/client/src/app/test-local-fs/page.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/file-tab.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Do not use the any type unless necessary
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/shared/types.tsapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/modals/file-modal.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsxapps/web/client/src/app/test-local-fs/page.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/file-tab.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx
apps/web/client/src/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Default to Server Components; add 'use client' only when using events, state/effects, browser APIs, or client-only libs
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/shared/types.tsapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/modals/file-modal.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsxapps/web/client/src/app/test-local-fs/page.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/file-tab.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx
{apps,packages}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Avoid using the any type unless absolutely necessary
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/shared/types.tsapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/modals/file-modal.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsxapps/web/client/src/app/test-local-fs/page.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/file-tab.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx
apps/web/client/src/app/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/app/**/*.tsx: Default to Server Components; add 'use client' when using events, state/effects, browser APIs, or client‑only libraries
Do not use process.env in client code; import env from @/env insteadAvoid hardcoded user-facing text; use next-intl messages/hooks
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/modals/file-modal.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsxapps/web/client/src/app/test-local-fs/page.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/file-tab.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx
apps/web/client/src/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/**/*.tsx: Create MobX store instances with useState(() => new Store()) for stable references across renders
Keep the active MobX store in a useRef and perform async cleanup with setTimeout(() => storeRef.current?.clear(), 0) to avoid route-change races
Avoid useMemo for creating MobX store instances
Avoid putting the MobX store instance in effect dependency arrays if it causes loops; split concerns by domain
apps/web/client/src/**/*.tsx: Create MobX store instances with useState(() => new Store()) for stable identities across renders
Keep the active MobX store in a useRef and clean up asynchronously with setTimeout(() => storeRef.current?.clear(), 0)
Do not use useMemo to create MobX stores
Avoid placing MobX store instances in effect dependency arrays if it causes loops; split concerns instead
observer components must be client components; place a single client boundary at the feature entry; child observers need not repeat 'use client'
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/modals/file-modal.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsxapps/web/client/src/app/test-local-fs/page.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/file-tab.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx
🧠 Learnings (10)
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
PR: onlook-dev/onlook#0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/**/*.{ts,tsx} : Use path aliases @/* and ~/* for imports that map to apps/web/client/src/*
Applied to files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsxapps/web/client/src/app/test-local-fs/page.tsx
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
PR: onlook-dev/onlook#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/**/*.{ts,tsx} : Use path aliases @/* and ~/* for imports mapping to src/*
Applied to files:
apps/web/client/src/app/test-local-fs/page.tsx
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
PR: onlook-dev/onlook#0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to **/*.{ts,tsx} : Do not use the any type unless necessary
Applied to files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree.tsx
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
PR: onlook-dev/onlook#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to {apps,packages}/**/*.{ts,tsx} : Avoid using the any type unless absolutely necessary
Applied to files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree.tsx
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
PR: onlook-dev/onlook#0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/app/**/*.tsx : Default to Server Components; add 'use client' when using events, state/effects, browser APIs, or client‑only libraries
Applied to files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
PR: onlook-dev/onlook#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/**/*.tsx : observer components must be client components; place a single client boundary at the feature entry; child observers need not repeat 'use client'
Applied to files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
PR: onlook-dev/onlook#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/app/**/*.{ts,tsx} : Default to Server Components; add 'use client' only when using events, state/effects, browser APIs, or client-only libs
Applied to files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
PR: onlook-dev/onlook#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/app/**/*.tsx : Avoid hardcoded user-facing text; use next-intl messages/hooks
Applied to files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
PR: onlook-dev/onlook#0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/**/*.{ts,tsx} : Avoid hardcoded user-facing text; use next-intl messages/hooks instead
Applied to files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
PR: onlook-dev/onlook#0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/trpc/react.tsx : Keep tRPC React client provider(s) behind a client boundary (ensure this provider file is a client component)
Applied to files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx
🧬 Code graph analysis (5)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/index.tsx (2)
apps/web/client/src/components/store/editor/ide/index.ts (1)
EditorFile(8-17)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/file-tab.tsx (1)
FileTab(13-74)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree.tsx (6)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/shared/types.ts (1)
FileNode(1-6)packages/ui/src/components/icons/index.tsx (1)
Icons(138-3667)packages/ui/src/components/tooltip.tsx (4)
Tooltip(72-72)TooltipTrigger(72-72)TooltipPortal(72-72)TooltipContent(72-72)packages/ui/src/components/button.tsx (1)
Button(57-57)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsx (1)
FileTreeRow(6-29)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx (1)
FileTreeNode(21-166)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx (4)
apps/web/client/src/components/store/editor/ide/index.ts (1)
EditorFile(8-17)apps/web/client/src/components/store/editor/index.tsx (1)
useEditorEngine(10-14)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor.tsx (1)
CodeEditor(17-85)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/unsaved-changes-dialog.tsx (1)
UnsavedChangesDialog(9-39)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx (6)
apps/web/client/src/components/store/editor/index.tsx (1)
useEditorEngine(10-14)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/shared/types.ts (1)
FileNode(1-6)apps/web/client/src/components/store/editor/ide/index.ts (6)
getElementCodeRange(254-277)isSandboxReady(44-49)EditorFile(8-17)closeFile(195-203)closeAllFiles(205-209)updateFileContent(143-152)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree.tsx (1)
FileTree(22-284)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/index.tsx (1)
FileTabs(27-93)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx (1)
CodeEditorArea(17-75)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx (3)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/shared/types.ts (1)
FileNode(1-6)packages/ui/src/components/icons/index.tsx (1)
Icons(138-3667)packages/ui/src/components/context-menu.tsx (3)
ContextMenuTrigger(226-226)ContextMenuContent(214-214)ContextMenuSeparator(221-221)
🪛 GitHub Actions: CI
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx
[error] 75-75: Variable 'menuItems' implicitly has type 'any[]' in some locations where its type cannot be determined.
[error] 148-148: Variable 'menuItems' implicitly has an 'any[]' type.
🔇 Additional comments (3)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx (1)
41-72: Fix extension matching so file icons resolve
split('.').pop()returns the extension without the leading dot, so none of thecase '.ts'style branches ever fire; every file falls through to the default icon. Restore the dot before switching.- const extension = node.data.path.split('.').pop()?.toLowerCase(); + const extension = (() => { + const lastDot = node.data.path.lastIndexOf('.'); + return lastDot >= 0 ? node.data.path.slice(lastDot).toLowerCase() : ''; + })();apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree.tsx (1)
22-31: Replaceanyon the forwarded tree refThe ref is a
TreeApi<FileNode>; keeping it typed avoidsanyleakage and lets callers use the API safely.-export const FileTree = memo( - forwardRef<any, FileTreeProps>(({ +export const FileTree = memo( + forwardRef<TreeApi<FileNode>, FileTreeProps>(({apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/file-tab.tsx (1)
13-74: Signature simplification looks goodThanks for inlining the prop typing and dropping
React.FC; the component reads cleaner and keeps the inferred return type intact.
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx
Outdated
Show resolved
Hide resolved
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
Show resolved
Hide resolved
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
Outdated
Show resolved
Hide resolved
.../web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx
Outdated
Show resolved
Hide resolved
| const getFileUrl = (file: BinaryEditorFile) => { | ||
| const mime = getMimeType(file.path.toLowerCase()); | ||
| // Convert Uint8Array to base64 string | ||
| const base64 = btoa(String.fromCharCode(...new Uint8Array(file.content))); |
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.
Spreading the Uint8Array into String.fromCharCode may hit argument limits for large files. Consider a more memory‐efficient conversion.
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: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
apps/web/client/src/components/store/editor/ide/index.ts (1)
17-18: Restore theEditorFiletype before using it.
EditorFileis no longer declared or imported in this module, yet we still typeopenedFiles(and other members) with it. TypeScript now fails to compile (Cannot find name 'EditorFile', see CI). Please reintroduce the interface (or import/extend the shared type) so the IDE store retains theid,filename,savedContent,language, andisBinaryfields it depends on.+export interface EditorFile { + id: string; + filename: string; + path: string; + content: string; + savedContent: string; + language: string; + isDirty: boolean; + isBinary: boolean; +}apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx (1)
121-126: AligneditorViewsRefkeys with the lookup.We store editor instances under
file.path(editorViewsRef.current.set(file.path, editor)), yet this lookup still useside.activeFile.id, so it always returnsundefined. Make both sides use the same key (path or id) to keep highlighting/search functioning.
🧹 Nitpick comments (1)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-search.tsx (1)
50-55: Set button type to avoid unintended form submission.Without
type="button", this clear control defaults tosubmit, which can break when the search lives inside a<form>. Explicitly set the type.{searchQuery && ( <button + type="button" className="absolute right-[1px] top-[1px] bottom-[1px] aspect-square hover:bg-background-onlook active:bg-transparent flex items-center justify-center rounded-r-[calc(theme(borderRadius.md)-1px)] group" onClick={clearSearch} >
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor.tsx(1 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx(1 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/index.tsx(1 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx(5 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/shared/types.ts(1 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx(1 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-search.tsx(1 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree.tsx(1 hunks)apps/web/client/src/components/store/editor/ide/index.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/shared/types.ts
- apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor.tsx
- apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree.tsx
- apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/index.tsx
🧰 Additional context used
📓 Path-based instructions (6)
apps/web/client/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/**/*.{ts,tsx}: Use path aliases @/* and ~/* for imports that map to apps/web/client/src/*
Avoid hardcoded user-facing text; use next-intl messages/hooks insteadUse path aliases @/* and ~/* for imports mapping to src/*
Files:
apps/web/client/src/components/store/editor/ide/index.tsapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-search.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Do not use the any type unless necessary
Files:
apps/web/client/src/components/store/editor/ide/index.tsapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-search.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
{apps,packages}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Avoid using the any type unless absolutely necessary
Files:
apps/web/client/src/components/store/editor/ide/index.tsapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-search.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
apps/web/client/src/app/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/app/**/*.tsx: Default to Server Components; add 'use client' when using events, state/effects, browser APIs, or client‑only libraries
Do not use process.env in client code; import env from @/env insteadAvoid hardcoded user-facing text; use next-intl messages/hooks
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-search.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
apps/web/client/src/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/**/*.tsx: Create MobX store instances with useState(() => new Store()) for stable references across renders
Keep the active MobX store in a useRef and perform async cleanup with setTimeout(() => storeRef.current?.clear(), 0) to avoid route-change races
Avoid useMemo for creating MobX store instances
Avoid putting the MobX store instance in effect dependency arrays if it causes loops; split concerns by domain
apps/web/client/src/**/*.tsx: Create MobX store instances with useState(() => new Store()) for stable identities across renders
Keep the active MobX store in a useRef and clean up asynchronously with setTimeout(() => storeRef.current?.clear(), 0)
Do not use useMemo to create MobX stores
Avoid placing MobX store instances in effect dependency arrays if it causes loops; split concerns instead
observer components must be client components; place a single client boundary at the feature entry; child observers need not repeat 'use client'
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-search.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
apps/web/client/src/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Default to Server Components; add 'use client' only when using events, state/effects, browser APIs, or client-only libs
Files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-search.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
🧠 Learnings (6)
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
PR: onlook-dev/onlook#0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/app/**/*.tsx : Default to Server Components; add 'use client' when using events, state/effects, browser APIs, or client‑only libraries
Applied to files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
PR: onlook-dev/onlook#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/app/**/*.{ts,tsx} : Default to Server Components; add 'use client' only when using events, state/effects, browser APIs, or client-only libs
Applied to files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
PR: onlook-dev/onlook#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/**/*.tsx : observer components must be client components; place a single client boundary at the feature entry; child observers need not repeat 'use client'
Applied to files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
PR: onlook-dev/onlook#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/app/**/*.tsx : Avoid hardcoded user-facing text; use next-intl messages/hooks
Applied to files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
PR: onlook-dev/onlook#0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/**/*.{ts,tsx} : Avoid hardcoded user-facing text; use next-intl messages/hooks instead
Applied to files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
PR: onlook-dev/onlook#0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/trpc/react.tsx : Keep tRPC React client provider(s) behind a client boundary (ensure this provider file is a client component)
Applied to files:
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
🧬 Code graph analysis (4)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx (2)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/shared/types.ts (1)
FileNode(1-6)packages/ui/src/components/context-menu.tsx (3)
ContextMenuTrigger(226-226)ContextMenuContent(214-214)ContextMenuSeparator(221-221)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-search.tsx (3)
packages/ui/src/components/icons/index.tsx (1)
Icons(138-3667)packages/ui/src/components/tooltip.tsx (4)
Tooltip(72-72)TooltipTrigger(72-72)TooltipPortal(72-72)TooltipContent(72-72)packages/ui/src/components/button.tsx (1)
Button(57-57)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx (3)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/shared/types.ts (1)
EditorFile(8-14)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor.tsx (1)
CodeEditor(18-93)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/unsaved-changes-dialog.tsx (1)
UnsavedChangesDialog(9-39)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx (6)
apps/web/client/src/components/store/editor/index.tsx (1)
useEditorEngine(10-14)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/shared/types.ts (4)
EditorFile(8-14)FileNode(1-6)BinaryEditorFile(24-28)TextEditorFile(16-21)apps/web/client/src/components/store/editor/ide/index.ts (3)
getElementCodeRange(244-267)isSandboxReady(34-39)getFilePathFromOid(228-242)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree.tsx (1)
FileTree(19-235)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/index.tsx (1)
FileTabs(27-93)apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx (1)
CodeEditorArea(17-62)
🪛 GitHub Actions: CI
apps/web/client/src/components/store/editor/ide/index.ts
[error] 17-18: Cannot find name 'EditorFile'.
[error] 18-18: Cannot find name 'EditorFile'.
[error] 57-95: Cannot find name 'EditorFile'.
[error] 98-98: Cannot find name 'EditorFile'.
[error] 221-221: Cannot find name 'EditorFile'.
🔇 Additional comments (3)
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx (1)
41-72: Align the extension switch with the parsed valueReiterating the earlier feedback:
split('.').pop()returnsjsx,tsx, etc. (without the dot), so none of thesecase '.tsx'branches ever match. Every file falls through to the default icon. Update the switch (or prepend the dot toextension) so the right icon renders.- const extension = node.data.path.split('.').pop()?.toLowerCase(); + const extension = node.data.path.split('.').pop()?.toLowerCase() ?? ''; @@ - switch (extension) { - case '.js': - case '.jsx': - case '.ts': - case '.tsx': + switch (extension) { + case 'js': + case 'jsx': + case 'ts': + case 'tsx': return <Icons.Code className="w-4 h-4 mr-2" />; - case '.css': - case '.scss': - case '.sass': + case 'css': + case 'scss': + case 'sass': return <Icons.Box className="w-4 h-4 mr-2" />; - case '.html': + case 'html': return <Icons.Frame className="w-4 h-4 mr-2" />; - case '.json': + case 'json': return <Icons.Code className="w-4 h-4 mr-2" />; - case '.md': - case '.mdx': + case 'md': + case 'mdx': return <Icons.Text className="w-4 h-4 mr-2" />; - case '.jpg': - case '.jpeg': - case '.png': - case '.gif': - case '.svg': + case 'jpg': + case 'jpeg': + case 'png': + case 'gif': + case 'svg': return <Icons.Image className="w-4 h-4 mr-2" />; default: return <Icons.File className="w-4 h-4 mr-2" />; }apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx (2)
1-14: Add'use client';at the top of this component.This module invokes hooks (
useEditorEngine,useState,useEffect, …), but without the client directive Next.js will treat it as a Server Component and crash. Add'use client';before the imports.+'use client'; + import { useEditorEngine } from '@/components/store/editor';
505-521: Respectide.isFilesVisiblewhen rendering the sidebar.
onToggleFilesVisiblestill flips the flag, but we always render<FileTree />, so the collapse button no longer does anything. Gate the render (or width) onide.isFilesVisibleso the toggle actually hides the panel.- <FileTree - onFileSelect={handleFileTreeSelect} - fileNodes={localFiles} - isLoading={localDirLoading} - selectedFilePath={selectedFile} - /> + {ide.isFilesVisible && ( + <FileTree + onFileSelect={handleFileTreeSelect} + fileNodes={localFiles} + isLoading={localDirLoading} + selectedFilePath={selectedFile} + /> + )}
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx
Show resolved
Hide resolved
| {activeFile?.isDirty && showUnsavedDialog && ( | ||
| <UnsavedChangesDialog | ||
| onSave={onSaveFile} | ||
| onDiscard={() => onDiscardChanges(activeFile.path)} | ||
| onCancel={() => { onCancelUnsaved(); }} |
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.
Pass the file id into onDiscardChanges.
onDiscardChanges ultimately calls ide.discardFileChanges, which looks up files by id. Forwarding activeFile.path means the lookup always fails and the discard flow silently does nothing. Please keep passing the file id (e.g. activeFile.id) once the type is restored.
🤖 Prompt for AI Agents
In
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx
around lines 53 to 57, the UnsavedChangesDialog is calling onDiscardChanges with
activeFile.path which fails because ide.discardFileChanges looks up files by id;
change the prop to pass activeFile.id (e.g. onDiscard={() =>
onDiscardChanges(activeFile.id)}) so the discard flow can find and remove the
file; ensure the value is only used once the activeFile type includes id.
| if (!selectedFile || !loadedContent) return; | ||
|
|
||
| const newLocalFile = createLocalEditorFile(selectedFile, loadedContent); | ||
|
|
||
| // Check if file is already open | ||
| const existingFileIndex = openedLocalFiles.findIndex(f => f.path === selectedFile); | ||
|
|
||
| if (existingFileIndex >= 0) { | ||
| // File already open, just set as active and update content | ||
| const existingFile = openedLocalFiles[existingFileIndex]; | ||
| if (existingFile) { | ||
| const updatedFile: EditorFile = { | ||
| path: existingFile.path, | ||
| isDirty: existingFile.isDirty, | ||
| type: existingFile.type, | ||
| originalContent: existingFile.originalContent, | ||
| content: newLocalFile.content | ||
| }; | ||
| const updatedFiles = [...openedLocalFiles]; | ||
| updatedFiles[existingFileIndex] = updatedFile; | ||
| setOpenedLocalFiles(updatedFiles); | ||
| setActiveLocalFile(updatedFile); | ||
| } | ||
| } else { | ||
| // Add new file to opened files | ||
| const updatedFiles = [...openedLocalFiles, newLocalFile]; | ||
| setOpenedLocalFiles(updatedFiles); | ||
| setActiveLocalFile(newLocalFile); | ||
| } | ||
| }, [selectedFile, loadedContent]); |
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.
Handle empty file contents correctly when opening.
The guard if (!selectedFile || !loadedContent) short-circuits when the file contents are an empty string, so blank files never load. Check explicitly for null/undefined instead.
- if (!selectedFile || !loadedContent) return;
+ if (!selectedFile || loadedContent === null || loadedContent === undefined) return;📝 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.
| if (!selectedFile || !loadedContent) return; | |
| const newLocalFile = createLocalEditorFile(selectedFile, loadedContent); | |
| // Check if file is already open | |
| const existingFileIndex = openedLocalFiles.findIndex(f => f.path === selectedFile); | |
| if (existingFileIndex >= 0) { | |
| // File already open, just set as active and update content | |
| const existingFile = openedLocalFiles[existingFileIndex]; | |
| if (existingFile) { | |
| const updatedFile: EditorFile = { | |
| path: existingFile.path, | |
| isDirty: existingFile.isDirty, | |
| type: existingFile.type, | |
| originalContent: existingFile.originalContent, | |
| content: newLocalFile.content | |
| }; | |
| const updatedFiles = [...openedLocalFiles]; | |
| updatedFiles[existingFileIndex] = updatedFile; | |
| setOpenedLocalFiles(updatedFiles); | |
| setActiveLocalFile(updatedFile); | |
| } | |
| } else { | |
| // Add new file to opened files | |
| const updatedFiles = [...openedLocalFiles, newLocalFile]; | |
| setOpenedLocalFiles(updatedFiles); | |
| setActiveLocalFile(newLocalFile); | |
| } | |
| }, [selectedFile, loadedContent]); | |
| if (!selectedFile || loadedContent === null || loadedContent === undefined) return; | |
| const newLocalFile = createLocalEditorFile(selectedFile, loadedContent); | |
| // Check if file is already open | |
| const existingFileIndex = openedLocalFiles.findIndex(f => f.path === selectedFile); | |
| if (existingFileIndex >= 0) { | |
| // File already open, just set as active and update content | |
| const existingFile = openedLocalFiles[existingFileIndex]; | |
| if (existingFile) { | |
| const updatedFile: EditorFile = { | |
| path: existingFile.path, | |
| isDirty: existingFile.isDirty, | |
| type: existingFile.type, | |
| originalContent: existingFile.originalContent, | |
| content: newLocalFile.content | |
| }; | |
| const updatedFiles = [...openedLocalFiles]; | |
| updatedFiles[existingFileIndex] = updatedFile; | |
| setOpenedLocalFiles(updatedFiles); | |
| setActiveLocalFile(updatedFile); | |
| } | |
| } else { | |
| // Add new file to opened files | |
| const updatedFiles = [...openedLocalFiles, newLocalFile]; | |
| setOpenedLocalFiles(updatedFiles); | |
| setActiveLocalFile(newLocalFile); | |
| } | |
| }, [selectedFile, loadedContent]); |
🤖 Prompt for AI Agents
In
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
around lines 81 to 110, the current guard `if (!selectedFile || !loadedContent)`
prevents loading files whose content is an empty string; change the check to
only bail on null/undefined (e.g., `selectedFile == null || loadedContent ==
null`) so empty-string file contents are allowed, leaving the rest of the
open/update logic unchanged.
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
Outdated
Show resolved
Hide resolved
| const fileToClose = openedLocalFiles.find(f => f.path === filePath); | ||
| if (fileToClose?.isDirty) { | ||
| setShowLocalUnsavedDialog(true); | ||
| return; | ||
| } | ||
|
|
||
| try { | ||
| return await ide.openFile(filePath, searchTerm, false); | ||
| } catch (error) { | ||
| console.error('Error loading file:', error); | ||
| return null; | ||
| const editorView = editorViewsRef.current.get(filePath); | ||
| if (editorView) { | ||
| editorView.destroy(); | ||
| editorViewsRef.current.delete(filePath); | ||
| } | ||
| }, [isSandboxReady]); | ||
|
|
||
| function handleFileSelect(file: EditorFile) { | ||
| ide.setHighlightRange(null); | ||
| ide.activeFile = file; | ||
| } | ||
| const updatedFiles = openedLocalFiles.filter(f => f.path !== filePath); | ||
| setOpenedLocalFiles(updatedFiles); | ||
|
|
||
| async function getFilePathFromOid(oid: string): Promise<string | null> { | ||
| if (!isSandboxReady) { | ||
| handleSandboxNotReady('get file path from OID'); | ||
| return null; | ||
| // Set new active file if we closed the active one | ||
| if (activeLocalFile?.path === filePath) { | ||
| const newActiveFile = updatedFiles.length > 0 ? updatedFiles[updatedFiles.length - 1] || null : null; | ||
| setActiveLocalFile(newActiveFile); |
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.
Track which dirty tab triggered the unsaved dialog.
When closing a dirty tab we only set showLocalUnsavedDialog and bail. We never record the target path/id, so the dialog either never appears (if the dirty tab isn’t active) or applies to the wrong file. Please cache the pending tab and drive the dialog from that state so confirmation targets the correct file.
🤖 Prompt for AI Agents
In
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
around lines 330-348, the code only sets showLocalUnsavedDialog when
encountering a dirty file but does not record which file triggered it, causing
the dialog to target the wrong file or not appear for non-active tabs; add a new
piece of state (e.g., pendingLocalClosePath or pendingLocalUnsavedFile) and set
it to the filePath (or file object) before returning, update the unsaved dialog
to read from that pending state to show the correct filename/details, and on
dialog confirm/abort handlers use that pending state to either proceed to
destroy/delete the correct editorView and remove the file from openedLocalFiles
(then clear pending state) or simply clear pending state without closing. Ensure
you clear pending state on dialog close and when performing the actual close
path so state stays consistent.
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
Show resolved
Hide resolved
.../web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx
Show resolved
Hide resolved
| import { Button } from '@onlook/ui/button'; | ||
| import { Icons } from '@onlook/ui/icons'; | ||
| import { Input } from '@onlook/ui/input'; | ||
| import { Tooltip, TooltipContent, TooltipPortal, TooltipTrigger } from '@onlook/ui/tooltip'; | ||
| import { forwardRef } from 'react'; |
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.
Add 'use client' directive before using event handlers.
Components under app/ default to server mode. Because this module attaches onChange, onClick, and similar handlers, it must opt into the client boundary, otherwise Next.js will throw during build/runtime. Insert the directive ahead of the imports.
+'use client';
+
import { Button } from '@onlook/ui/button';
import { Icons } from '@onlook/ui/icons';
import { Input } from '@onlook/ui/input';
import { Tooltip, TooltipContent, TooltipPortal, TooltipTrigger } from '@onlook/ui/tooltip';📝 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.
| import { Button } from '@onlook/ui/button'; | |
| import { Icons } from '@onlook/ui/icons'; | |
| import { Input } from '@onlook/ui/input'; | |
| import { Tooltip, TooltipContent, TooltipPortal, TooltipTrigger } from '@onlook/ui/tooltip'; | |
| import { forwardRef } from 'react'; | |
| 'use client'; | |
| import { Button } from '@onlook/ui/button'; | |
| import { Icons } from '@onlook/ui/icons'; | |
| import { Input } from '@onlook/ui/input'; | |
| import { Tooltip, TooltipContent, TooltipPortal, TooltipTrigger } from '@onlook/ui/tooltip'; | |
| import { forwardRef } from 'react'; |
🤖 Prompt for AI Agents
In
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-search.tsx
around lines 1 to 5, this component uses event handlers but lacks the Next.js
client directive; add "use client" as the very first line of the file (before
any imports) to opt into the client boundary so onChange/onClick handlers work
correctly during build/runtime.
| placeholder="Search files" | ||
| value={searchQuery} | ||
| disabled={isLoading} | ||
| onChange={(e) => onSearchChange(e.target.value)} | ||
| onKeyDown={onKeyDown} | ||
| /> | ||
| {searchQuery && ( | ||
| <button | ||
| className="absolute right-[1px] top-[1px] bottom-[1px] aspect-square hover:bg-background-onlook active:bg-transparent flex items-center justify-center rounded-r-[calc(theme(borderRadius.md)-1px)] group" | ||
| onClick={clearSearch} | ||
| > | ||
| <Icons.CrossS className="h-3 w-3 text-foreground-primary/50 group-hover:text-foreground-primary" /> | ||
| </button> | ||
| )} | ||
| </div> | ||
| <Tooltip> | ||
| <TooltipTrigger asChild> | ||
| <Button | ||
| variant={'default'} | ||
| size={'icon'} | ||
| className="p-2 w-fit h-8 text-foreground-tertiary hover:text-foreground-hover hover:border-border-onlook bg-background-none hover:bg-background-onlook" | ||
| disabled={isLoading} | ||
| onClick={handleRefresh} | ||
| > | ||
| {isLoading ? ( | ||
| <div className="animate-spin h-4 w-4 border-2 border-foreground-primary rounded-full border-t-transparent"></div> | ||
| ) : ( | ||
| <Icons.Reload /> | ||
| )} | ||
| </Button> | ||
| </TooltipTrigger> | ||
| <TooltipPortal> | ||
| <TooltipContent> | ||
| <p>{isLoading ? 'Loading files...' : 'Refresh files'}</p> | ||
| </TooltipContent> |
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.
🛠️ Refactor suggestion | 🟠 Major
Replace hardcoded UI strings with localized messages.
Per the client coding guidelines, user-facing copy should come from next-intl (or our localization layer). Please move the placeholder and tooltip strings to translations and read them with useTranslations, rather than hardcoding English literals in the component.
Based on coding guidelines
|
Generated with ❤️ by ellipsis.dev |
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: 0
♻️ Duplicate comments (6)
apps/web/client/src/services/sync-engine/sync-engine.ts (2)
55-56: Add conflict detection before pushing files to sandbox.Immediately after pulling and setting up watchers, the code pushes all local JSX/TSX files back to the sandbox. This creates a race condition where sandbox changes that occurred between the pull and this push could be overwritten.
Consider these improvements:
- Compare content hashes before pushing (only push if
localHash !== this.fileHashes.get(path))- Fetch the sandbox's current file state and compare against stored hashes to detect conflicts
- Add proper error handling instead of using
void(fire-and-forget)- void this.pushModifiedFilesToSandbox(); + try { + await this.pushModifiedFilesToSandbox(); + } catch (error) { + console.error('[Sync] Failed to push modified files:', error); + }
198-229: Add change detection to avoid overwriting unchanged files.This method pushes all local JSX/TSX files to the sandbox with
overwrite: true, regardless of whether they've been modified. This is problematic for several reasons:
- Data loss risk: Sandbox changes not yet synced locally will be overwritten
- Performance: Large projects unnecessarily upload hundreds of files on every startup
- Misleading name: Called
pushModifiedFiles...but actually pushes all JSX/TSX files- No verification: The comment mentions "with OIDs" but there's no check that files actually contain OIDs
Apply this diff to add proper change detection:
private async pushModifiedFilesToSandbox(): Promise<void> { console.log('[Sync] Pushing locally modified files back to sandbox...'); try { - // Get all local JSX/TSX files that might have been modified with OIDs const localFiles = await this.fs.listFiles('/'); const jsxFiles = localFiles.filter(path => /\.(jsx?|tsx?)$/i.test(path)); - await Promise.all( - jsxFiles.map(async (filePath) => { - try { - const content = await this.fs.readFile(filePath); - if (typeof content === 'string') { - // Push to sandbox - await this.provider.writeFile({ - args: { - path: filePath.startsWith('/') ? filePath.substring(1) : filePath, - content, - overwrite: true - } - }); - console.log(`[Sync] Pushed ${filePath} to sandbox`); - } - } catch (error) { - console.warn(`[Sync] Failed to push ${filePath} to sandbox:`, error); - } - }) - ); + for (const filePath of jsxFiles) { + try { + const content = await this.fs.readFile(filePath); + if (typeof content === 'string') { + // Check if content differs from sandbox + const localHash = await hashContent(content); + const sandboxHash = this.fileHashes.get(filePath); + + if (localHash === sandboxHash) { + console.log(`[Sync] Skipping ${filePath} - unchanged`); + continue; + } + + // Only push if content changed + await this.provider.writeFile({ + args: { + path: filePath.startsWith('/') ? filePath.substring(1) : filePath, + content, + overwrite: true + } + }); + // Update hash after successful write + this.fileHashes.set(filePath, localHash); + console.log(`[Sync] Pushed ${filePath} to sandbox`); + } + } catch (error) { + console.warn(`[Sync] Failed to push ${filePath} to sandbox:`, error); + } + } } catch (error) { console.error('[Sync] Error pushing files to sandbox:', error); } }apps/web/client/src/components/store/editor/sandbox/index.ts (4)
32-45: Add error handling for async sync engine initialization.The reaction calls the async
initializeSyncEnginewithout handling potential rejections, which can result in unhandled promise rejections and leave the sandbox manager in an inconsistent state.Apply this diff to add proper error handling:
async init() { this.providerReactionDisposer = reaction( () => this.session.provider, (provider) => { if (provider) { - this.initializeSyncEngine(provider); + void this.initializeSyncEngine(provider).catch((error) => { + console.error('[SandboxManager] Failed to initialize sync engine:', error); + }); } else if (this.sync) { // If the provider is null, stop the sync engine this.sync.stop(); this.sync = null; } }, ); }
58-71: Add error handling to prevent inconsistent state.If
sync.start(),ensurePreloadScriptExists(), orfs.rebuildIndex()fail, the method leavesthis.syncandthis.fsin an inconsistent state. Without error handling in the caller (the reaction ininit()), failures will silently corrupt the manager.Apply this diff to add comprehensive error handling:
async initializeSyncEngine(provider: Provider) { + try { if (this.sync) { this.sync?.stop(); this.sync = null; } this.sync = new CodeProviderSync(provider, this.fs, { exclude: EXCLUDED_SYNC_PATHS, }); await this.sync.start(); await this.ensurePreloadScriptExists(); await this.fs.rebuildIndex(); + } catch (error) { + console.error('[SandboxManager] Failed to initialize sync engine:', error); + // Clean up partial state + this.sync?.stop(); + this.sync = null; + throw error; // Re-throw so caller can handle + } }
115-168: File operation methods fail when FileSystem isn't initialized.All file operation methods throw "File system not initialized" errors when
this.fsis null, causing test failures as shown in the static analysis hints. There's a race condition where methods may be called beforeinitializeSyncEnginecompletes, or if initialization fails silently.Based on the static analysis hints showing test failures, consider implementing a ready-promise pattern:
export class SandboxManager { readonly session: SessionManager; private providerReactionDisposer?: () => void; private sync: CodeProviderSync | null = null; + private fsReady: Promise<void> = Promise.resolve(); preloadScriptInjected: boolean = false; preloadScriptLoading: boolean = false; routerConfig: RouterConfig | null = null; async init() { this.providerReactionDisposer = reaction( () => this.session.provider, (provider) => { if (provider) { + this.fsReady = this.initializeSyncEngine(provider); void this.initializeSyncEngine(provider).catch((error) => { console.error('[SandboxManager] Failed to initialize sync engine:', error); }); } else if (this.sync) { this.sync.stop(); this.sync = null; } }, ); } async readFile(path: string): Promise<string | Uint8Array> { + await this.fsReady; if (!this.fs) throw new Error('File system not initialized'); return this.fs.readFile(path); } // Apply similar pattern to other file methods...This ensures callers can safely call methods before initialization completes, and initialization errors propagate to tests.
196-203: Call FileSystem cleanup before nulling.The
clear()method should callthis.fs?.cleanup()before setting it tonullto ensure watchers are properly closed, debounced saves are flushed, and the metadata index is persisted.Apply this diff:
clear() { this.providerReactionDisposer?.(); this.providerReactionDisposer = undefined; this.sync?.stop(); this.sync = null; + void this.fs?.cleanup(); this.preloadScriptInjected = false; this.session.clear(); }Note: If
cleanup()returns a promise that should be awaited, consider makingclear()async or handling the promise appropriately.
🧹 Nitpick comments (1)
apps/web/client/src/app/project/[id]/_components/canvas/frame/index.tsx (1)
79-79: Minor: Layout direction change has no visual impact with single child.Removing
flex-colchanges the flex direction from vertical to horizontal, but since there's only one child element (the loading spinner), this has no current visual effect. If additional elements are added to this container in the future, the horizontal layout will apply.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/web/client/src/app/project/[id]/_components/canvas/frame/index.tsx(4 hunks)apps/web/client/src/components/store/editor/sandbox/index.ts(2 hunks)apps/web/client/src/services/sync-engine/sync-engine.ts(9 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
apps/web/client/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/**/*.{ts,tsx}: Use path aliases @/* and ~/* for imports that map to apps/web/client/src/*
Avoid hardcoded user-facing text; use next-intl messages/hooks insteadUse path aliases @/* and ~/* for imports mapping to src/*
Files:
apps/web/client/src/services/sync-engine/sync-engine.tsapps/web/client/src/components/store/editor/sandbox/index.tsapps/web/client/src/app/project/[id]/_components/canvas/frame/index.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Do not use the any type unless necessary
Files:
apps/web/client/src/services/sync-engine/sync-engine.tsapps/web/client/src/components/store/editor/sandbox/index.tsapps/web/client/src/app/project/[id]/_components/canvas/frame/index.tsx
{apps,packages}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Avoid using the any type unless absolutely necessary
Files:
apps/web/client/src/services/sync-engine/sync-engine.tsapps/web/client/src/components/store/editor/sandbox/index.tsapps/web/client/src/app/project/[id]/_components/canvas/frame/index.tsx
apps/web/client/src/app/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/app/**/*.tsx: Default to Server Components; add 'use client' when using events, state/effects, browser APIs, or client‑only libraries
Do not use process.env in client code; import env from @/env insteadAvoid hardcoded user-facing text; use next-intl messages/hooks
Files:
apps/web/client/src/app/project/[id]/_components/canvas/frame/index.tsx
apps/web/client/src/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/**/*.tsx: Create MobX store instances with useState(() => new Store()) for stable references across renders
Keep the active MobX store in a useRef and perform async cleanup with setTimeout(() => storeRef.current?.clear(), 0) to avoid route-change races
Avoid useMemo for creating MobX store instances
Avoid putting the MobX store instance in effect dependency arrays if it causes loops; split concerns by domain
apps/web/client/src/**/*.tsx: Create MobX store instances with useState(() => new Store()) for stable identities across renders
Keep the active MobX store in a useRef and clean up asynchronously with setTimeout(() => storeRef.current?.clear(), 0)
Do not use useMemo to create MobX stores
Avoid placing MobX store instances in effect dependency arrays if it causes loops; split concerns instead
observer components must be client components; place a single client boundary at the feature entry; child observers need not repeat 'use client'
Files:
apps/web/client/src/app/project/[id]/_components/canvas/frame/index.tsx
apps/web/client/src/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Default to Server Components; add 'use client' only when using events, state/effects, browser APIs, or client-only libs
Files:
apps/web/client/src/app/project/[id]/_components/canvas/frame/index.tsx
🧬 Code graph analysis (2)
apps/web/client/src/services/sync-engine/sync-engine.ts (2)
packages/file-system/src/code-fs.ts (1)
CodeFileSystem(27-282)apps/web/client/src/components/store/editor/sandbox/helpers.ts (1)
normalizePath(5-9)
apps/web/client/src/components/store/editor/sandbox/index.ts (8)
apps/web/client/src/components/store/editor/sandbox/session.ts (1)
SessionManager(8-225)apps/web/client/src/services/sync-engine/sync-engine.ts (1)
CodeProviderSync(27-596)packages/models/src/next/index.ts (1)
RouterConfig(6-9)packages/file-system/src/code-fs.ts (1)
CodeFileSystem(27-282)apps/web/client/src/components/store/editor/pages/helper.ts (1)
detectRouterConfig(436-487)packages/constants/src/files.ts (1)
EXCLUDED_SYNC_PATHS(29-36)apps/web/client/src/components/store/editor/sandbox/preload-script.ts (1)
copyPreloadScriptToPublic(8-29)packages/file-system/src/types.ts (1)
FileEntry(1-8)
🔇 Additional comments (7)
apps/web/client/src/services/sync-engine/sync-engine.ts (2)
10-10: LGTM! Type and export changes align with the refactoring.The transition from
FileSystemtoCodeFileSystemand the export ofhashContentare consistent with the PR's integration of the new file system architecture.Also applies to: 19-19, 37-37
143-150: LGTM! Sequential writes prevent race conditions.Switching from parallel
writeFilesto sequentialwriteFilecalls prevents race conditions during JSX processing and enables per-file error handling. This is essential given thatCodeFileSystem.writeFileperforms AST parsing and metadata indexing for JSX files.apps/web/client/src/components/store/editor/sandbox/index.ts (2)
22-30: LGTM! Constructor properly integrates the new dependencies.The constructor correctly accepts and initializes
CodeFileSystemand updates theSessionManagerinitialization to match the new signature.
73-101: LGTM! Preload script injection properly guarded and error-handled.The method correctly prevents duplicate injections using flags, validates preconditions, and includes comprehensive error handling with proper cleanup in the
finallyblock.apps/web/client/src/app/project/[id]/_components/canvas/frame/index.tsx (3)
74-74: LGTM—overlay condition properly gates on frame readiness.The updated condition
!isFrameReadycorrectly shows the loading overlay whenever the frame isn't fully ready, which now includes both the preload script injection and connection establishment. This is a logical enhancement over the previous connection-only check.
26-27: Approve enhanced frame readiness logic Verified thatSandboxManagerdefinespreloadScriptInjected: boolean, making thepreloadScriptReadycheck valid.
24-24: RemovedisIndexingfallback verified safe
No references toisIndexingremain in the codebase;preloadScriptInjectedis declared on the sandbox model (apps/web/client/src/components/store/editor/sandbox/index.ts).
|
Generated with ❤️ by ellipsis.dev |
|
Generated with ❤️ by ellipsis.dev |
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 (2)
apps/web/client/src/app/auth/auth-context.tsx (1)
59-60: Inconsistent error handling between login methods.
handleLogin(lines 44-46) rethrows errors after logging, buthandleDevLoginonly logs without rethrowing. This inconsistency means callers cannot catch dev login errors, potentially leading to silent failures in the UI.Consider applying the same error handling pattern:
} catch (error) { console.error('Error signing in with password:', error); + throw error; } finally {apps/web/client/src/app/_components/login-button.tsx (1)
1-1: Missing 'use client' directive.This file uses client-only features (onClick events, useTranslations hook, useAuthContext hook) but lacks the 'use client' directive at the top. This will cause runtime errors.
Add the directive at the top of the file:
+'use client'; + import { transKeys } from '@/i18n/keys';As per coding guidelines.
🧹 Nitpick comments (1)
apps/web/client/src/app/_components/login-button.tsx (1)
22-31: Reduce code duplication between login handlers.The GitHub and Google login handlers are nearly identical, differing only in the method name and error message. Consider extracting the common logic to reduce maintenance burden.
Example refactor:
const createLoginHandler = (method: SignInMethod.GITHUB | SignInMethod.GOOGLE, methodName: string) => { return async () => { try { await handleLogin(method, returnUrl ?? null); } catch (error) { console.error(`Error signing in with ${methodName}:`, error); toast.error(`Error signing in with ${methodName}`, { description: error instanceof Error ? error.message : 'Please try again.', }); } }; }; const handleGithubLoginClick = createLoginHandler(SignInMethod.GITHUB, 'GitHub'); const handleGoogleLoginClick = createLoginHandler(SignInMethod.GOOGLE, 'Google');Also applies to: 72-81
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/web/client/src/app/_components/login-button.tsx(5 hunks)apps/web/client/src/app/auth/auth-context.tsx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
apps/web/client/src/app/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/app/**/*.tsx: Default to Server Components; add 'use client' when using events, state/effects, browser APIs, or client‑only libraries
Do not use process.env in client code; import env from @/env insteadAvoid hardcoded user-facing text; use next-intl messages/hooks
Files:
apps/web/client/src/app/_components/login-button.tsxapps/web/client/src/app/auth/auth-context.tsx
apps/web/client/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/**/*.{ts,tsx}: Use path aliases @/* and ~/* for imports that map to apps/web/client/src/*
Avoid hardcoded user-facing text; use next-intl messages/hooks insteadUse path aliases @/* and ~/* for imports mapping to src/*
Files:
apps/web/client/src/app/_components/login-button.tsxapps/web/client/src/app/auth/auth-context.tsx
apps/web/client/src/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/**/*.tsx: Create MobX store instances with useState(() => new Store()) for stable references across renders
Keep the active MobX store in a useRef and perform async cleanup with setTimeout(() => storeRef.current?.clear(), 0) to avoid route-change races
Avoid useMemo for creating MobX store instances
Avoid putting the MobX store instance in effect dependency arrays if it causes loops; split concerns by domain
apps/web/client/src/**/*.tsx: Create MobX store instances with useState(() => new Store()) for stable identities across renders
Keep the active MobX store in a useRef and clean up asynchronously with setTimeout(() => storeRef.current?.clear(), 0)
Do not use useMemo to create MobX stores
Avoid placing MobX store instances in effect dependency arrays if it causes loops; split concerns instead
observer components must be client components; place a single client boundary at the feature entry; child observers need not repeat 'use client'
Files:
apps/web/client/src/app/_components/login-button.tsxapps/web/client/src/app/auth/auth-context.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Do not use the any type unless necessary
Files:
apps/web/client/src/app/_components/login-button.tsxapps/web/client/src/app/auth/auth-context.tsx
apps/web/client/src/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Default to Server Components; add 'use client' only when using events, state/effects, browser APIs, or client-only libs
Files:
apps/web/client/src/app/_components/login-button.tsxapps/web/client/src/app/auth/auth-context.tsx
{apps,packages}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Avoid using the any type unless absolutely necessary
Files:
apps/web/client/src/app/_components/login-button.tsxapps/web/client/src/app/auth/auth-context.tsx
🧬 Code graph analysis (1)
apps/web/client/src/app/_components/login-button.tsx (1)
packages/ui/src/components/sonner.tsx (1)
toast(19-19)
🔇 Additional comments (1)
apps/web/client/src/app/auth/auth-context.tsx (1)
45-46: LGTM: Improved error handling.Rethrowing the original error preserves the error type and stack trace, which is better than wrapping it in a generic Error. Moving toast notifications to the UI layer (login-button.tsx) improves separation of concerns.
|
Generated with ❤️ by ellipsis.dev |
|
Generated with ❤️ by ellipsis.dev |
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: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/web/client/src/app/_components/login-button.tsx (1)
1-7: Add the'use client'directive.This component uses hooks (
useTranslations,useAuthContext) and event handlers, so it must opt into client mode. Without'use client', Next.js will treat it as a Server Component, causing runtime build errors. Please add'use client';at the top of the file.+'use client'; + import { transKeys } from '@/i18n/keys';As per coding guidelines
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/web/client/src/app/_components/login-button.tsx(3 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
apps/web/client/src/app/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/app/**/*.tsx: Default to Server Components; add 'use client' when using events, state/effects, browser APIs, or client‑only libraries
Do not use process.env in client code; import env from @/env insteadAvoid hardcoded user-facing text; use next-intl messages/hooks
Files:
apps/web/client/src/app/_components/login-button.tsx
apps/web/client/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/**/*.{ts,tsx}: Use path aliases @/* and ~/* for imports that map to apps/web/client/src/*
Avoid hardcoded user-facing text; use next-intl messages/hooks insteadUse path aliases @/* and ~/* for imports mapping to src/*
Files:
apps/web/client/src/app/_components/login-button.tsx
apps/web/client/src/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/**/*.tsx: Create MobX store instances with useState(() => new Store()) for stable references across renders
Keep the active MobX store in a useRef and perform async cleanup with setTimeout(() => storeRef.current?.clear(), 0) to avoid route-change races
Avoid useMemo for creating MobX store instances
Avoid putting the MobX store instance in effect dependency arrays if it causes loops; split concerns by domain
apps/web/client/src/**/*.tsx: Create MobX store instances with useState(() => new Store()) for stable identities across renders
Keep the active MobX store in a useRef and clean up asynchronously with setTimeout(() => storeRef.current?.clear(), 0)
Do not use useMemo to create MobX stores
Avoid placing MobX store instances in effect dependency arrays if it causes loops; split concerns instead
observer components must be client components; place a single client boundary at the feature entry; child observers need not repeat 'use client'
Files:
apps/web/client/src/app/_components/login-button.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Do not use the any type unless necessary
Files:
apps/web/client/src/app/_components/login-button.tsx
apps/web/client/src/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Default to Server Components; add 'use client' only when using events, state/effects, browser APIs, or client-only libs
Files:
apps/web/client/src/app/_components/login-button.tsx
{apps,packages}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Avoid using the any type unless absolutely necessary
Files:
apps/web/client/src/app/_components/login-button.tsx
🧬 Code graph analysis (1)
apps/web/client/src/app/_components/login-button.tsx (3)
apps/web/client/src/i18n/keys.ts (1)
transKeys(5-5)apps/web/client/src/app/auth/auth-context.tsx (1)
useAuthContext(73-79)packages/ui/src/components/sonner.tsx (1)
toast(19-19)
| toast.error(`Error signing in with ${providerName}`, { | ||
| description: error instanceof Error ? error.message : 'Please try again.', | ||
| }); |
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.
Localize the toast copy.
The toast title/description are hardcoded English strings. Per our app guidelines, user-facing text must come from next-intl. Please move these messages into the translations bundle (e.g., transKeys.welcome.login.error) and fetch them via t(...), passing providerName as an interpolation if needed. This keeps the UI localizable.
As per coding guidelines
|
Generated with ❤️ by ellipsis.dev |
Description
Related Issues
Type of Change
Testing
Screenshots (if applicable)
Additional Notes
Important
Integrates a new file system and sync engine, refactoring file operations and tools for improved efficiency and reliability.
FileSystemclass for file operations, replacing sandbox-based methods.useFileanduseDirectoryhooks to useFileSystem.getFileSystem()inhelpers/files.tsfor consistent file system access.CodeProviderSyncfor file synchronization with code providers.SandboxManager.WriteFileTool,ReadFileTool, andSearchReplaceEditToolto useFileSystem.helpers/files.ts.modelsto reflect new file handling structures.This description was created by
for 14cebae. You can customize this summary. It will automatically update as commits are pushed.
Summary by CodeRabbit
New Features
Improvements
Refactor
Chores