Skip to content

Conversation

@Kitenite
Copy link
Contributor

@Kitenite Kitenite commented Sep 26, 2025

Description

Related Issues

Type of Change

  • Bug fix
  • New feature
  • Documentation update
  • Release
  • Refactor
  • Other (please describe):

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.

  • File System Integration:
    • Introduces FileSystem class for file operations, replacing sandbox-based methods.
    • Updates useFile and useDirectory hooks to use FileSystem.
    • Implements getFileSystem() in helpers/files.ts for consistent file system access.
  • Sync Engine:
    • Integrates CodeProviderSync for file synchronization with code providers.
    • Removes legacy file sync and event bus logic from SandboxManager.
  • Tool Updates:
    • Refactors tools like WriteFileTool, ReadFileTool, and SearchReplaceEditTool to use FileSystem.
    • Simplifies file path resolution and command execution in helpers/files.ts.
  • Miscellaneous:
    • Cleans up unused imports and redundant code across several files.
    • Updates models to reflect new file handling structures.

This description was created by Ellipsis for 14cebae. You can customize this summary. It will automatically update as commits are pushed.


Summary by CodeRabbit

  • New Features

    • Major CODE tab revamp: per-file tabs, searchable file tree, multi-file editor area, binary previews, element highlighting, and unsaved-changes dialog.
  • Improvements

    • Better editor navigation and branch-aware file handling; more reliable session reconnect and sync behavior.
    • Left-panel Images redesigned: folders, breadcrumbs, searchable grid, upload/search bar, and improved upload UX.
  • Refactor

    • Moved to a filesystem-first, branch-aware backend and streamlined editor APIs.
  • Chores

    • Removed legacy test pages, deprecated image/folder providers and several obsolete utilities.

@vercel
Copy link

vercel bot commented Sep 26, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
web Ready Ready Preview Comment Oct 6, 2025 0:59am
1 Skipped Deployment
Project Deployment Preview Comments Updated (UTC)
docs Skipped Skipped Oct 6, 2025 0:59am

@coderabbitai
Copy link

coderabbitai bot commented Sep 26, 2025

Note

Other AI code review bot(s) detected

CodeRabbit 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.

Walkthrough

Replaces 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

Cohort / File(s) Summary
Core FS & hooks
packages/file-system/src/code-fs.ts, packages/file-system/src/fs.ts, packages/file-system/src/hooks/*, packages/file-system/src/index.ts, apps/web/client/tsconfig.json
Add CodeFileSystem with JSX metadata/indexing; migrate path handling to Node path; add fileExists; rename/refactor hooks to accept projectId, branchId (use-fs, use-dir, use-file); re-export code-fs; include code-fs in tsconfig.
Sync engine & sandbox
apps/web/client/src/services/sync-engine/sync-engine.ts, apps/web/client/src/components/store/editor/sandbox/*, apps/web/client/src/components/store/editor/sandbox/preload-script.ts
Export hashContent; sequentialize writes; add pushModifiedFilesToSandbox; replace legacy indexing/watch with CodeProviderSync/FS-driven pipeline; add preload script helpers; introduce sandbox restart/provider lifecycle changes.
Right-panel code UX
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/**
Full refactor to filesystem-driven per-file editor: new EditorFile types and utils; CodeEditor, CodeEditorArea, FileTabs/FileTab, UnsavedChangesDialog, isDirty util; CodeTab now forwarded-ref exposing save/create/refresh/unsaved APIs; per-file open/save/discard flows and dialogs.
Sidebar / file tree
apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/*
New FileTree, FileTreeSearch, FileTreeNode, FileTreeRow, FileIcon: hierarchical tree with search/filter, keyboard nav, rename/delete, selection/scroll sync and updated styling.
Branching, models & history
apps/web/client/src/components/store/editor/*, packages/models/src/*, packages/constants/src/*, packages/penpal/src/*
Propagate branchId across actions/elements/history; BranchManager exposes per-branch CodeFileSystem and async lifecycle; EditorEngine adds api and fileSystem getter; EditorTabValue.DEVCODE; penpal/preload APIs extended for branchId; constants updated.
AI tools & helpers
packages/ai/src/tools/*, packages/ai/src/tools/shared/helpers/files.ts, packages/ai/src/agents/tool-lookup.ts
Tools switched to branch-aware filesystem via getFileSystem(branchId, editorEngine); replaced sandbox reads/writes with CodeFileSystem usage; added centralized tool arrays (allTools, rootTools, userTools).
Image tab refactor
apps/web/client/src/app/project/[id]/_components/left-panel/image-tab/**
Remove many provider/context/hooks/modals; add FS-driven useImageOperations, useNavigation, BreadcrumbNavigation, FolderList, ImageGrid, ImageItem, SearchUploadBar; simplify upload/read flows and UI composition.
Fonts / Tailwind / layout
apps/web/client/src/components/store/editor/font/*, apps/web/client/src/components/store/editor/theme/*
Replace class-based managers with exported helper functions for font/layout/Tailwind operations; ThemeManager.getConfigPath() becomes async; remove reactive file watchers; move formatting into parser/prettier utilities.
Parser & formatting
packages/parser/src/prettier/*, apps/web/client/src/components/store/editor/sandbox/helpers.ts
Add Prettier-based formatContent in parser package; remove old sandbox format helper; CodeFileSystem integrates formatting on writes.
Preload & frame integration
apps/web/preload/script/api/*, apps/web/client/src/.../canvas/*
Add preload child/parent setBranchId/getBranchId; helpers to copy/inject preload script into layouts; frame readiness gated on preload readiness; canvas/tab semantics updated to CODE.
Right-panel integration & controls
apps/web/client/src/app/project/[id]/_components/right-panel/index.tsx, .../header-controls.tsx, code-tab/*
DEV tab renamed to CODE; mount CodeTab with ref to surface unsaved state; CodeControls become prop-driven; File/Folder/Upload modals controlled externally and delegate create ops via callbacks.
Removed legacy subsystems & tests
apps/.../components/store/editor/sandbox/*, image-tab providers/modals/hooks, template-nodes, preload manager, file-event-bus, file-sync, many test/demo pages & tests
Delete old managers (FileEventBus, FileSyncManager, PreloadScriptManager, TemplateNodeManager), numerous image-tab components/hooks/modals, test/demo pages and a large set of tests; simplify codebase toward branch FS model.
Utilities & small additions
packages/utility/src/path.ts, packages/utility/src/string.ts, assorted imports/tests
Add pathsEqual, pathMatchesAny, findMatchingPath; add sanitizeFilename; update imports/tests to new code-fs and hooks APIs.

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
Loading
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
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~150 minutes

Possibly related PRs

Poem

I’m a rabbit in branches, nibbling bytes and logs,
I hop through files and swap old sandboxes for progs.
Tabs now say CODE, indexes hum and write,
Highlights blink softly, editors wake at night.
Tiny hops, big changes — carrots for the devs! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request description retains the template placeholders without providing actual details under the required sections such as Description, Related Issues, Type of Change, Testing, and Additional Notes, making it incomplete and unhelpful for reviewers. Please populate each section of the repository’s description template by replacing placeholder comments with a clear summary of your changes under Description, linking related issues, selecting the appropriate type-of-change checkbox, and describing testing steps, screenshots, and any additional context.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly conveys the primary change by indicating the integration of the sync engine, which aligns with the pull request’s main objective to integrate a new file system and sync engine across the codebase.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/integrate-sync-eng

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5012335 and 6148c01.

📒 Files selected for processing (3)
  • apps/web/client/src/app/_components/auth-modal.tsx (2 hunks)
  • apps/web/client/src/app/_components/login-button.tsx (3 hunks)
  • apps/web/client/src/app/login/page.tsx (2 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 instead

Avoid hardcoded user-facing text; use next-intl messages/hooks

Files:

  • apps/web/client/src/app/_components/login-button.tsx
  • apps/web/client/src/app/login/page.tsx
  • apps/web/client/src/app/_components/auth-modal.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 instead

Use path aliases @/* and ~/* for imports mapping to src/*

Files:

  • apps/web/client/src/app/_components/login-button.tsx
  • apps/web/client/src/app/login/page.tsx
  • apps/web/client/src/app/_components/auth-modal.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
  • apps/web/client/src/app/login/page.tsx
  • apps/web/client/src/app/_components/auth-modal.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/login/page.tsx
  • apps/web/client/src/app/_components/auth-modal.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/web/client/src/app/login/page.tsx
  • apps/web/client/src/app/_components/auth-modal.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
  • apps/web/client/src/app/login/page.tsx
  • apps/web/client/src/app/_components/auth-modal.tsx
🧠 Learnings (2)
📚 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/_components/login-button.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/_components/login-button.tsx
🧬 Code graph analysis (3)
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)
apps/web/client/src/app/login/page.tsx (2)
apps/web/client/src/app/_components/login-button.tsx (1)
  • LoginButton (19-68)
packages/ui/src/components/icons/index.tsx (1)
  • Icons (138-3667)
apps/web/client/src/app/_components/auth-modal.tsx (2)
apps/web/client/src/app/_components/login-button.tsx (1)
  • LoginButton (19-68)
packages/ui/src/components/icons/index.tsx (1)
  • Icons (138-3667)

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

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@supabase
Copy link

supabase bot commented Sep 26, 2025

This pull request has been ignored for the connected project wowaemfasoptxrdjhilu because there are no changes detected in apps/backend/supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bab9d85 and 5bdf732.

📒 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 instead

Use path aliases @/* and ~/* for imports mapping to src/*

Files:

  • apps/web/client/src/services/sync-engine/index.ts
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
  • apps/web/client/src/app/project/[id]/_hooks/use-start-project.tsx
  • apps/web/client/src/app/test-sync-engine/page.tsx
  • apps/web/client/src/components/store/editor/sandbox/index.ts
  • apps/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.ts
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
  • apps/web/client/src/app/project/[id]/_hooks/use-start-project.tsx
  • apps/web/client/src/app/test-sync-engine/page.tsx
  • apps/web/client/src/components/store/editor/sandbox/index.ts
  • apps/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.ts
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
  • apps/web/client/src/app/project/[id]/_hooks/use-start-project.tsx
  • apps/web/client/src/app/test-sync-engine/page.tsx
  • apps/web/client/src/components/store/editor/sandbox/index.ts
  • apps/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 instead

Avoid hardcoded user-facing text; use next-intl messages/hooks

Files:

  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
  • apps/web/client/src/app/project/[id]/_hooks/use-start-project.tsx
  • apps/web/client/src/app/test-sync-engine/page.tsx
  • apps/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.tsx
  • apps/web/client/src/app/project/[id]/_hooks/use-start-project.tsx
  • apps/web/client/src/app/test-sync-engine/page.tsx
  • apps/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.tsx
  • apps/web/client/src/app/project/[id]/_hooks/use-start-project.tsx
  • apps/web/client/src/app/test-sync-engine/page.tsx
  • apps/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.ts
  • apps/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.ts
  • apps/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 good

Using 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 cleanly

The 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 layout

Thanks for updating the hook import to the hyphenated path; this keeps the test page tracking the sync-engine re-export structure.

@vercel vercel bot temporarily deployed to Preview – docs September 26, 2025 16:41 Inactive

// File system
const rootDir = `/${editorEngine.projectId}/${editorEngine.branches.activeBranch.id}`;
// const { fs, isInitializing: fsInitializing, error: fsError } = useFS(rootDir);
Copy link
Contributor

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.

Suggested change
// 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();
Copy link
Contributor

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.

Suggested change
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:');
Copy link
Contributor

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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 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

extension is now just js, 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

FileNode no longer exposes isDirectory, so this check always treats directories as files. Selecting a folder now tries to open it and will error. Switch the predicate to the new type === 'directory' shape before invoking loadFile.

-        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 sync

The new syncDirectoryContents traversal no longer calls shouldSync on nested entries. If a sandbox change arrives for an allowed parent (e.g. src/), we now blindly recreate excluded descendants such as src/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 copy

This 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 strings

Strings 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 strings

Labels 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 imports

Per the client coding guidelines we should use the @/* / ~/* aliases for imports under apps/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

📥 Commits

Reviewing files that changed from the base of the PR and between 5bdf732 and c9cc777.

📒 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 instead

Use path aliases @/* and ~/* for imports mapping to src/*

Files:

  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/types.ts
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor.tsx
  • apps/web/client/src/services/sync-engine/sync-engine.ts
  • apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-diff.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor-area.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
  • apps/web/client/src/components/store/editor/sandbox/index.ts
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-block.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/file-tab.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/unsaved-changes-dialog.tsx
  • apps/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.ts
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor.tsx
  • apps/web/client/src/services/sync-engine/sync-engine.ts
  • apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-diff.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor-area.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
  • apps/web/client/src/components/store/editor/sandbox/index.ts
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-block.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/file-tab.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/unsaved-changes-dialog.tsx
  • apps/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.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/chat-tab/code-display/code-diff.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor-area.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-block.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/file-tab.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/unsaved-changes-dialog.tsx
  • apps/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.ts
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor.tsx
  • apps/web/client/src/services/sync-engine/sync-engine.ts
  • apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-diff.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor-area.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
  • apps/web/client/src/components/store/editor/sandbox/index.ts
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-block.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/file-tab.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/unsaved-changes-dialog.tsx
  • apps/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 instead

Avoid 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.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-diff.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor-area.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-block.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/file-tab.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/unsaved-changes-dialog.tsx
  • apps/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.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-diff.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/code-editor-area.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/code-block.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/file-tab.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/unsaved-changes-dialog.tsx
  • apps/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: Fix EditorSelection import to prevent build break

EditorSelection is 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 functional readFile implementation

readFile now always returns null, so every call site (e.g., editorEngine.activeSandbox.readFile in 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: writeFile must persist editor saves

Returning false short-circuits all writes. Callers such as processFileForMapping and 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.FC removes implicit children and aligns with our preferred style while keeping the data-active destructuring 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.

Comment on lines 702 to 743
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;
// }
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 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 under apps/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 merge

Please remove the stray console.log so 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 @ alias

Per our client-side guidelines we should reference modules under apps/web/client/src via 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 copy

The new UI strings ('Collapse sidebar', 'Expand sidebar', 'Close file', 'Close all') should flow through next-intl rather than being inlined so we stay compliant with the app directory i18n rule. Please wire these through useTranslations (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 imports

The 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

📥 Commits

Reviewing files that changed from the base of the PR and between c9cc777 and fdd56dc.

📒 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 instead

Use path aliases @/* and ~/* for imports mapping to src/*

Files:

  • 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/modals/file-modal.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/index.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsx
  • apps/web/client/src/app/test-local-fs/page.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/file-tab.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
  • apps/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.ts
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/modals/file-modal.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/index.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsx
  • apps/web/client/src/app/test-local-fs/page.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/file-tab.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
  • apps/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.ts
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/modals/file-modal.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/index.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsx
  • apps/web/client/src/app/test-local-fs/page.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/file-tab.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
  • apps/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.ts
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/modals/file-modal.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/index.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsx
  • apps/web/client/src/app/test-local-fs/page.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/file-tab.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
  • apps/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 instead

Avoid 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.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/index.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsx
  • apps/web/client/src/app/test-local-fs/page.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/file-tab.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
  • apps/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.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-tabs/index.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-row.tsx
  • apps/web/client/src/app/test-local-fs/page.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/file-tab.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/index.tsx
  • apps/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.tsx
  • apps/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 the case '.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: Replace any on the forwarded tree ref

The ref is a TreeApi<FileNode>; keeping it typed avoids any leakage 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 good

Thanks for inlining the prop typing and dropping React.FC; the component reads cleaner and keeps the inferred return type intact.

const getFileUrl = (file: BinaryEditorFile) => {
const mime = getMimeType(file.path.toLowerCase());
// Convert Uint8Array to base64 string
const base64 = btoa(String.fromCharCode(...new Uint8Array(file.content)));
Copy link
Contributor

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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 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 the EditorFile type before using it.

EditorFile is no longer declared or imported in this module, yet we still type openedFiles (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 the id, filename, savedContent, language, and isBinary fields 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: Align editorViewsRef keys with the lookup.

We store editor instances under file.path (editorViewsRef.current.set(file.path, editor)), yet this lookup still uses ide.activeFile.id, so it always returns undefined. 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 to submit, 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

📥 Commits

Reviewing files that changed from the base of the PR and between fdd56dc and 22c3783.

📒 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 instead

Use path aliases @/* and ~/* for imports mapping to src/*

Files:

  • apps/web/client/src/components/store/editor/ide/index.ts
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-search.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx
  • apps/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.ts
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-search.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx
  • apps/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.ts
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-node.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-search.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx
  • apps/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 instead

Avoid 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.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-search.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx
  • apps/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.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-search.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx
  • apps/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.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/sidebar/file-tree-search.tsx
  • apps/web/client/src/app/project/[id]/_components/right-panel/code-tab/file-content/index.tsx
  • apps/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.tsx
  • apps/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.tsx
  • apps/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.tsx
  • apps/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.tsx
  • 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} : 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
  • 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/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
  • apps/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 value

Reiterating the earlier feedback: split('.').pop() returns jsx, tsx, etc. (without the dot), so none of these case '.tsx' branches ever match. Every file falls through to the default icon. Update the switch (or prepend the dot to extension) 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: Respect ide.isFilesVisible when rendering the sidebar.

onToggleFilesVisible still flips the flag, but we always render <FileTree />, so the collapse button no longer does anything. Gate the render (or width) on ide.isFilesVisible so 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}
+                    />
+                )}

Comment on lines 53 to 57
{activeFile?.isDirty && showUnsavedDialog && (
<UnsavedChangesDialog
onSave={onSaveFile}
onDiscard={() => onDiscardChanges(activeFile.path)}
onCancel={() => { onCancelUnsaved(); }}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

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.

Comment on lines 81 to 110
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]);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

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.

Suggested change
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.

Comment on lines 330 to 348
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);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

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.

Comment on lines 1 to 5
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';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

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.

Suggested change
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.

Comment on lines 43 to 77
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>
Copy link

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

@vercel vercel bot temporarily deployed to Preview – docs October 5, 2025 20:42 Inactive
@ellipsis-dev
Copy link
Contributor

ellipsis-dev bot commented Oct 5, 2025

⚠️ This PR is too big for Ellipsis, but support for larger PRs is coming soon. If you want us to prioritize this feature, let us know at [email protected]


Generated with ❤️ by ellipsis.dev

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ 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:

  1. Compare content hashes before pushing (only push if localHash !== this.fileHashes.get(path))
  2. Fetch the sandbox's current file state and compare against stored hashes to detect conflicts
  3. 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:

  1. Data loss risk: Sandbox changes not yet synced locally will be overwritten
  2. Performance: Large projects unnecessarily upload hundreds of files on every startup
  3. Misleading name: Called pushModifiedFiles... but actually pushes all JSX/TSX files
  4. 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 initializeSyncEngine without 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(), or fs.rebuildIndex() fail, the method leaves this.sync and this.fs in an inconsistent state. Without error handling in the caller (the reaction in init()), 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.fs is null, causing test failures as shown in the static analysis hints. There's a race condition where methods may be called before initializeSyncEngine completes, 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 call this.fs?.cleanup() before setting it to null to 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 making clear() 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-col changes 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

📥 Commits

Reviewing files that changed from the base of the PR and between e38d38f and 355299f.

📒 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 instead

Use path aliases @/* and ~/* for imports mapping to src/*

Files:

  • apps/web/client/src/services/sync-engine/sync-engine.ts
  • apps/web/client/src/components/store/editor/sandbox/index.ts
  • apps/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.ts
  • apps/web/client/src/components/store/editor/sandbox/index.ts
  • apps/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.ts
  • apps/web/client/src/components/store/editor/sandbox/index.ts
  • apps/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 instead

Avoid 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 FileSystem to CodeFileSystem and the export of hashContent are 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 writeFiles to sequential writeFile calls prevents race conditions during JSX processing and enables per-file error handling. This is essential given that CodeFileSystem.writeFile performs 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 CodeFileSystem and updates the SessionManager initialization 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 finally block.

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 !isFrameReady correctly 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 that SandboxManager defines preloadScriptInjected: boolean, making the preloadScriptReady check valid.


24-24: Removed isIndexing fallback verified safe
No references to isIndexing remain in the codebase; preloadScriptInjected is declared on the sandbox model (apps/web/client/src/components/store/editor/sandbox/index.ts).

@ellipsis-dev
Copy link
Contributor

ellipsis-dev bot commented Oct 5, 2025

⚠️ This PR is too big for Ellipsis, but support for larger PRs is coming soon. If you want us to prioritize this feature, let us know at [email protected]


Generated with ❤️ by ellipsis.dev

@ellipsis-dev
Copy link
Contributor

ellipsis-dev bot commented Oct 5, 2025

⚠️ This PR is too big for Ellipsis, but support for larger PRs is coming soon. If you want us to prioritize this feature, let us know at [email protected]


Generated with ❤️ by ellipsis.dev

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 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, but handleDevLogin only 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

📥 Commits

Reviewing files that changed from the base of the PR and between 355299f and 29a3ba8.

📒 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 instead

Avoid hardcoded user-facing text; use next-intl messages/hooks

Files:

  • apps/web/client/src/app/_components/login-button.tsx
  • apps/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 instead

Use path aliases @/* and ~/* for imports mapping to src/*

Files:

  • apps/web/client/src/app/_components/login-button.tsx
  • apps/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.tsx
  • apps/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.tsx
  • apps/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.tsx
  • apps/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.tsx
  • apps/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.

@ellipsis-dev
Copy link
Contributor

ellipsis-dev bot commented Oct 6, 2025

⚠️ This PR is too big for Ellipsis, but support for larger PRs is coming soon. If you want us to prioritize this feature, let us know at [email protected]


Generated with ❤️ by ellipsis.dev

@ellipsis-dev
Copy link
Contributor

ellipsis-dev bot commented Oct 6, 2025

⚠️ This PR is too big for Ellipsis, but support for larger PRs is coming soon. If you want us to prioritize this feature, let us know at [email protected]


Generated with ❤️ by ellipsis.dev

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

📥 Commits

Reviewing files that changed from the base of the PR and between c2a0f36 and 5012335.

📒 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 instead

Avoid 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 instead

Use 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)

Comment on lines +37 to +39
toast.error(`Error signing in with ${providerName}`, {
description: error instanceof Error ? error.message : 'Please try again.',
});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

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

@vercel vercel bot temporarily deployed to Preview – docs October 6, 2025 00:56 Inactive
@ellipsis-dev
Copy link
Contributor

ellipsis-dev bot commented Oct 6, 2025

⚠️ This PR is too big for Ellipsis, but support for larger PRs is coming soon. If you want us to prioritize this feature, let us know at [email protected]


Generated with ❤️ by ellipsis.dev

@Kitenite Kitenite merged commit 0b234ca into main Oct 6, 2025
8 checks passed
@Kitenite Kitenite deleted the feat/integrate-sync-eng branch October 6, 2025 01:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants