fix: improve dev login error handling and suppress hydration warning#3069
fix: improve dev login error handling and suppress hydration warning#3069paritoshk wants to merge 3 commits intoonlook-dev:mainfrom
Conversation
…to-expand) Implements three high-impact UX improvements identified from user journey analysis: ## 1. Save State Indicator (onlook-dev#1 Priority - CRITICAL) **Problem**: Users had no visibility into whether changes were saved **Solution**: Real-time visual feedback in top bar - Created SaveStateManager to track save states (saved/saving/unsaved) - Integrated into EditorEngine lifecycle - CodeManager notifies on write start/complete/error - Visual indicator shows: spinning "Saving...", checkmark "Saved", orange dot "Unsaved" - Tooltip displays time since last save **Files**: - apps/web/client/src/components/store/editor/save-state/index.ts (NEW) - apps/web/client/src/app/project/[id]/_components/top-bar/save-indicator.tsx (NEW) - apps/web/client/src/components/store/editor/engine.ts - apps/web/client/src/components/store/editor/code/index.ts - apps/web/client/src/app/project/[id]/_components/top-bar/index.tsx **Impact**: Builds user trust, eliminates confusion about save status --- ## 2. Example Prompts (onlook-dev#5 - Conversion Boost) **Problem**: Empty chat provided no guidance for new users **Solution**: Mode-specific clickable example prompts - 3 examples per mode (CREATE/EDIT/ASK/FIX) - Auto-send message on click - Examples: "Add hero section", "Change button color", "Explain component", "Fix layout" **Files**: - apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsx (NEW) - apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsx - apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-tab-content/index.tsx **Impact**: Reduces time-to-first-message, lowers cognitive load --- ## 3. Auto-Expand Last Tool Call (onlook-dev#4 - Transparency) **Problem**: Users manually clicked every tool to see AI actions **Solution**: Latest tool call auto-expands - Identifies last tool in message parts - Passes defaultOpen flag to CollapsibleCodeBlock - Previous tools remain collapsed - Works with all code editing tools **Files**: - apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsx - apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/tool-call-display.tsx - apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/collapsible-code-block.tsx **Impact**: Improves transparency, reduces clicks --- ## Testing All changes type-checked successfully with `bun run typecheck` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
- Add try-catch wrapper in DevLoginButton with toast error notification - Re-throw errors in AuthContext for proper error propagation - Add suppressHydrationWarning to body tag to fix Next.js warnings - Fix indentation in LoginButton component
|
@paritoshk is attempting to deploy a commit to the Onlook Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughThis PR introduces a save-state management system for tracking code write operations, adds UI components for chat example prompts and save status indicators, improves error handling in authentication, and includes comprehensive architecture documentation. Multiple chat components are enhanced with prop propagation and tool call display improvements. Changes
Sequence DiagramsequenceDiagram
participant User
participant CodeManager
participant SaveStateManager
participant EditorStore
participant SaveIndicator
User->>CodeManager: write code
CodeManager->>SaveStateManager: startSaving()
SaveStateManager->>SaveStateManager: state = 'saving'
SaveStateManager->>EditorStore: notify observers (saveState)
EditorStore->>SaveIndicator: update
SaveIndicator->>SaveIndicator: render spinner + "Saving..."
CodeManager->>CodeManager: apply code changes
CodeManager->>SaveStateManager: debouncedCompleteSave(300ms)
par Debounce Wait
SaveIndicator->>SaveIndicator: maintain saving state display
end
SaveStateManager->>SaveStateManager: (after 300ms) completeSave()
SaveStateManager->>SaveStateManager: state = 'saved'<br/>lastSaveTime = now()
SaveStateManager->>EditorStore: notify observers (saveState)
EditorStore->>SaveIndicator: update
SaveIndicator->>SaveIndicator: render check + "Saved"
SaveIndicator->>SaveIndicator: tooltip: "Last saved 1 second ago"
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (4)
apps/web/client/src/app/_components/login-button.tsx (1)
87-89: Consider using next-intl for user-facing text.The hardcoded strings
'Dev login failed','Please try again.', and'DEV MODE: Sign in as demo user'should ideally usenext-intlmessages for consistency with the rest of the codebase. TheLoginButtoncomponent correctly usest(transKeys.welcome.login[translationKey])for its text.Based on coding guidelines, hardcoded user-facing text should be avoided in favor of
next-intlmessages/hooks.Also applies to: 102-102
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsx (2)
95-108: Consider using next-intl for user-facing text.The hardcoded strings in
getModeTitle()and the UI text (lines 113-118) should usenext-intlmessages/hooks for internationalization consistency. This includes:
- Mode titles: "Create something new", "Edit your design", etc.
- Helper text: "Start a conversation or try one of these examples"
Based on coding guidelines, hardcoded user-facing text should be avoided.
Also applies to: 113-118
15-84: Consider extracting prompts to translation keys.The
EXAMPLE_PROMPTSconstant contains hardcoded user-facing text for button labels and prompt content. For full i18n support, consider moving these strings to translation files.That said, if these prompts are intentionally English-only for AI interaction purposes, this may be acceptable. Verify with the team whether these prompts should be localized.
apps/web/client/src/components/store/editor/save-state/index.ts (1)
8-8: Use browser-compatible timeout type.
NodeJS.Timeoutis specific to Node.js and may not be the correct type in browser contexts. Use the return type ofsetTimeoutfor better cross-environment compatibility.Apply this diff:
- private saveTimeout: NodeJS.Timeout | null = null; + private saveTimeout: ReturnType<typeof setTimeout> | null = null;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (16)
.gitignore(1 hunks)ARCHITECTURE.md(1 hunks)apps/web/client/src/app/_components/login-button.tsx(2 hunks)apps/web/client/src/app/auth/auth-context.tsx(1 hunks)apps/web/client/src/app/layout.tsx(1 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsx(1 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsx(2 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsx(3 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/tool-call-display.tsx(5 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-tab-content/index.tsx(1 hunks)apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/collapsible-code-block.tsx(1 hunks)apps/web/client/src/app/project/[id]/_components/top-bar/index.tsx(2 hunks)apps/web/client/src/app/project/[id]/_components/top-bar/save-indicator.tsx(1 hunks)apps/web/client/src/components/store/editor/code/index.ts(2 hunks)apps/web/client/src/components/store/editor/engine.ts(3 hunks)apps/web/client/src/components/store/editor/save-state/index.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
apps/web/client/src/app/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/app/**/*.tsx: Default to Server Components; add 'use client' when using events, state/effects, browser APIs, or client‑only libraries
Do not use process.env in client code; import env from @/env insteadAvoid hardcoded user-facing text; use next-intl messages/hooks
Files:
apps/web/client/src/app/project/[id]/_components/top-bar/save-indicator.tsxapps/web/client/src/app/auth/auth-context.tsxapps/web/client/src/app/layout.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-tab-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/tool-call-display.tsxapps/web/client/src/app/_components/login-button.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/collapsible-code-block.tsxapps/web/client/src/app/project/[id]/_components/top-bar/index.tsx
apps/web/client/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
apps/web/client/src/**/*.{ts,tsx}: Use path aliases @/* and ~/* for imports that map to apps/web/client/src/*
Avoid hardcoded user-facing text; use next-intl messages/hooks insteadUse path aliases @/* and ~/* for imports mapping to src/*
Files:
apps/web/client/src/app/project/[id]/_components/top-bar/save-indicator.tsxapps/web/client/src/app/auth/auth-context.tsxapps/web/client/src/app/layout.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsxapps/web/client/src/components/store/editor/code/index.tsapps/web/client/src/components/store/editor/save-state/index.tsapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-tab-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/tool-call-display.tsxapps/web/client/src/app/_components/login-button.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsxapps/web/client/src/components/store/editor/engine.tsapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/collapsible-code-block.tsxapps/web/client/src/app/project/[id]/_components/top-bar/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/top-bar/save-indicator.tsxapps/web/client/src/app/auth/auth-context.tsxapps/web/client/src/app/layout.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-tab-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/tool-call-display.tsxapps/web/client/src/app/_components/login-button.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/collapsible-code-block.tsxapps/web/client/src/app/project/[id]/_components/top-bar/index.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/top-bar/save-indicator.tsxapps/web/client/src/app/auth/auth-context.tsxapps/web/client/src/app/layout.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsxapps/web/client/src/components/store/editor/code/index.tsapps/web/client/src/components/store/editor/save-state/index.tsapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-tab-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/tool-call-display.tsxapps/web/client/src/app/_components/login-button.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsxapps/web/client/src/components/store/editor/engine.tsapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/collapsible-code-block.tsxapps/web/client/src/app/project/[id]/_components/top-bar/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/top-bar/save-indicator.tsxapps/web/client/src/app/auth/auth-context.tsxapps/web/client/src/app/layout.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-tab-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/tool-call-display.tsxapps/web/client/src/app/_components/login-button.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/collapsible-code-block.tsxapps/web/client/src/app/project/[id]/_components/top-bar/index.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/top-bar/save-indicator.tsxapps/web/client/src/app/auth/auth-context.tsxapps/web/client/src/app/layout.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsxapps/web/client/src/components/store/editor/code/index.tsapps/web/client/src/components/store/editor/save-state/index.tsapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-tab-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/tool-call-display.tsxapps/web/client/src/app/_components/login-button.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsxapps/web/client/src/components/store/editor/engine.tsapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/collapsible-code-block.tsxapps/web/client/src/app/project/[id]/_components/top-bar/index.tsx
apps/web/client/src/app/layout.tsx
📄 CodeRabbit inference engine (AGENTS.md)
Preserve dark theme defaults via ThemeProvider usage in the root layout
Preserve dark theme defaults via ThemeProvider in the root layout
Files:
apps/web/client/src/app/layout.tsx
apps/web/client/src/app/{page,layout,route}.tsx
📄 CodeRabbit inference engine (CLAUDE.md)
Follow App Router file conventions (page.tsx, layout.tsx, route.ts) within src/app
Files:
apps/web/client/src/app/layout.tsx
🧠 Learnings (12)
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 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/top-bar/save-indicator.tsx
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/app/layout.tsx : Preserve dark theme defaults via ThemeProvider in the root layout
Applied to files:
apps/web/client/src/app/layout.tsx
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/app/layout.tsx : Preserve dark theme defaults via ThemeProvider usage in the root layout
Applied to files:
apps/web/client/src/app/layout.tsx
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 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/layout.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-tab-content/index.tsxapps/web/client/src/app/_components/login-button.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsx
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 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/layout.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-tab-content/index.tsxapps/web/client/src/app/_components/login-button.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsxapps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsx
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/**/*.tsx : Create MobX store instances with useState(() => new Store()) for stable identities across renders
Applied to files:
apps/web/client/src/components/store/editor/save-state/index.tsapps/web/client/src/components/store/editor/engine.ts
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/**/*.tsx : Create MobX store instances with useState(() => new Store()) for stable references across renders
Applied to files:
apps/web/client/src/components/store/editor/save-state/index.tsapps/web/client/src/components/store/editor/engine.ts
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-16T19:22:52.461Z
Learning: Applies to apps/web/client/src/**/*.tsx : Keep the active MobX store in a useRef and clean up asynchronously with setTimeout(() => storeRef.current?.clear(), 0)
Applied to files:
apps/web/client/src/components/store/editor/save-state/index.ts
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/**/*.tsx : Keep the active MobX store in a useRef and perform async cleanup with setTimeout(() => storeRef.current?.clear(), 0) to avoid route-change races
Applied to files:
apps/web/client/src/components/store/editor/save-state/index.ts
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-14T01:44:21.209Z
Learning: Applies to apps/web/client/src/**/*.tsx : Avoid putting the MobX store instance in effect dependency arrays if it causes loops; split concerns by domain
Applied to files:
apps/web/client/src/components/store/editor/save-state/index.ts
📚 Learning: 2025-09-14T01:44:21.209Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 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/_components/login-button.tsxARCHITECTURE.md
📚 Learning: 2025-09-16T19:22:52.461Z
Learnt from: CR
Repo: onlook-dev/onlook PR: 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/_components/login-button.tsx
🧬 Code graph analysis (10)
apps/web/client/src/app/project/[id]/_components/top-bar/save-indicator.tsx (3)
apps/web/client/src/components/store/editor/index.tsx (1)
useEditorEngine(10-14)apps/web/client/src/components/store/editor/save-state/index.ts (1)
SaveState(4-4)packages/ui/src/components/tooltip.tsx (3)
Tooltip(72-72)TooltipTrigger(72-72)TooltipContent(72-72)
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsx (2)
packages/ui/src/components/icons/index.tsx (1)
Icons(138-3667)apps/web/client/src/components/store/editor/index.tsx (1)
useEditorEngine(10-14)
apps/web/client/src/components/store/editor/code/index.ts (1)
packages/ui/src/components/sonner.tsx (1)
toast(19-19)
apps/web/client/src/components/store/editor/save-state/index.ts (1)
apps/web/client/src/components/store/editor/engine.ts (1)
EditorEngine(34-138)
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-tab-content/index.tsx (1)
apps/web/client/src/components/store/editor/chat/index.ts (1)
sendMessage(43-49)
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsx (1)
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/tool-call-display.tsx (1)
ToolCallDisplay(236-236)
apps/web/client/src/components/store/editor/engine.ts (1)
apps/web/client/src/components/store/editor/save-state/index.ts (1)
SaveStateManager(6-85)
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsx (3)
packages/models/src/chat/message/message.ts (1)
ChatMessage(19-19)apps/web/client/src/app/project/[id]/_hooks/use-chat/index.tsx (1)
EditMessage(19-23)apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsx (1)
ExamplePrompts(90-137)
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/collapsible-code-block.tsx (1)
apps/web/client/src/components/store/editor/index.tsx (1)
useEditorEngine(10-14)
apps/web/client/src/app/project/[id]/_components/top-bar/index.tsx (1)
apps/web/client/src/app/project/[id]/_components/top-bar/save-indicator.tsx (1)
SaveIndicator(9-62)
🪛 LanguageTool
ARCHITECTURE.md
[uncategorized] ~569-~569: The official name of this software platform is spelled with a capital “H”.
Context: ...` ### Feature Packages #### @onlook/github - Purpose: GitHub integration - *...
(GITHUB)
🔇 Additional comments (18)
.gitignore (1)
48-50: Ignore entry for.claude/looks goodConsistent with other temporary/tool directories and safe to keep out of version control.
apps/web/client/src/app/layout.tsx (1)
74-74: LGTM!Adding
suppressHydrationWarningto the<body>tag is appropriate for Next.js applications using ThemeProvider, as client-side theme modifications can cause legitimate hydration mismatches. This correctly addresses the console warnings mentioned in the PR objectives.apps/web/client/src/app/auth/auth-context.tsx (1)
59-65: LGTM!Re-throwing the error after logging makes
handleDevLoginconsistent withhandleLogin(lines 44-46), allowing callers to implement their own error handling (e.g., displaying toast notifications). Thefinallyblock correctly ensuressigningInMethodis reset regardless of success or failure.apps/web/client/src/components/store/editor/engine.ts (1)
32-32: LGTM!The
SaveStateManagerintegration follows the established pattern used by other managers inEditorEngine. The import, property declaration, and cleanup inclear()are all consistent with how other managers (e.g.,ChatManager,ActionManager) are handled.Also applies to: 75-75, 119-119
apps/web/client/src/app/_components/login-button.tsx (1)
82-91: Error handling implementation looks good.The try/catch wrapper with toast notification properly addresses the PR objective of providing user feedback on dev login failures. The pattern is consistent with
LoginButton'shandleLoginClick.ARCHITECTURE.md (2)
569-575: Minor: Capitalize "GitHub" consistently.Per the static analysis hint, "GitHub" should be capitalized with a capital "H" for consistency with official branding.
-#### **@onlook/github** +#### **@onlook/GitHub**Actually, the package name
@onlook/githubis correct as package names are typically lowercase. The issue is in the descriptive text if any. Looking at the content, the package name format is fine. This can be ignored.
113-113: No changes required. The ARCHITECTURE.md documentation correctly references Next.js 16, which matches the actual version specified in package.json (16.0.7).Likely an incorrect or invalid review comment.
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/code-display/collapsible-code-block.tsx (1)
18-18: LGTM!The
defaultOpenprop is cleanly implemented with a sensible default offalse, maintaining backward compatibility. UsinguseState(defaultOpen)correctly sets the initial state while allowing the component to be uncontrolled after mount.Also applies to: 26-29
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/example-prompts.tsx (1)
90-137: Component structure looks good.The component correctly:
- Uses
'use client'directive (required for hooks, events, and MobX observer)- Wraps with
observerfor MobX reactivity onchatMode- Properly accesses editor state via
useEditorEngine()- Has a clean fallback with
|| EXAMPLE_PROMPTS[ChatType.EDIT]apps/web/client/src/app/project/[id]/_components/top-bar/index.tsx (1)
22-22: LGTM! SaveIndicator integration looks good.The SaveIndicator component is properly imported and rendered in the appropriate location within the TopBar's right-aligned section.
Also applies to: 54-54
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-tab-content/index.tsx (1)
31-31: LGTM! Prop propagation is correct.The
onSendMessageprop is properly passed through to theChatMessagescomponent, enabling message sending from child components like example prompts.apps/web/client/src/components/store/editor/code/index.ts (1)
27-27: LGTM! Save state lifecycle integration is correct.The save state transitions are properly integrated:
startSaving()at the beginning of the write operationdebouncedCompleteSave()after successful writesmarkUnsaved()on error pathsThis provides clear user feedback about the save status throughout the operation.
Also applies to: 40-40, 47-47
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/tool-call-display.tsx (2)
16-17: LGTM! Optional prop with safe default.The
isLatestprop is properly defined with a default value offalse, ensuring backward compatibility and clear intent.Also applies to: 23-23
96-96: LGTM! Consistent propagation across tool types.The
defaultOpen={isLatest}prop is consistently passed to all relevantCollapsibleCodeBlockinstances, ensuring uniform behavior across different tool call types.Also applies to: 122-122, 148-148, 174-174
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/index.tsx (1)
19-19: LGTM! ExamplePrompts integration enhances empty state UX.The
onSendMessageprop is properly added to the component interface and correctly wired to theExamplePromptscomponent, improving the user experience when there are no chat messages.Also applies to: 25-25, 33-33, 70-70
apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/message-content/index.tsx (1)
20-21: LGTM! Last tool call tracking logic is correct.The implementation properly identifies the last tool call using a backward scan and passes this information to
ToolCallDisplayfor conditional auto-expansion. The logic is separate from the existing incomplete tool tracking, maintaining clear separation of concerns.Also applies to: 35-42, 55-55, 63-63
apps/web/client/src/components/store/editor/save-state/index.ts (2)
18-24: Consider edge case: rapid successive saves.The
startSaving()method clears any pending timeout, which is correct. However, if multiple save operations are initiated in rapid succession, each call tostartSaving()will cancel the previous debounce timer. This might keep the UI in a "saving" state longer than expected if saves keep happening.This is likely the intended behavior, but verify that this aligns with the desired UX for rapid successive writes.
37-42: Verify the markUnsaved guard logic.The guard
if (this.saveState !== 'saving')prevents marking as unsaved during an active save. However, if an error occurs during save (e.g., in CodeManager.write), the state would be 'saving', and this guard would prevent marking it as 'unsaved'.Looking at the CodeManager.write implementation, it calls
markUnsaved()in the error path after the save has failed. At that point, is the state still 'saving'? If so, this guard might prevent proper error state indication.Verify the call sequence:
- Does
startSaving()get called before the try block?- When an error occurs, is the state still 'saving' when
markUnsaved()is called?- Should the error path first reset the state before marking unsaved?
Consider this safer pattern:
markUnsaved() { if (this.saveTimeout) { clearTimeout(this.saveTimeout); this.saveTimeout = null; } this.saveState = 'unsaved'; }
| return ( | ||
| <div className="flex items-center gap-1.5 text-xs text-foreground-secondary"> | ||
| <Icons.Reload className="h-3 w-3 animate-spin" /> | ||
| <span>Saving...</span> |
There was a problem hiding this comment.
Replace hardcoded text with next-intl messages.
The component contains hardcoded user-facing text ("Saving...", "Saved", "Unsaved changes") that should be internationalized using next-intl messages and hooks.
As per coding guidelines: "Avoid hardcoded user-facing text; use next-intl messages/hooks instead"
Apply this pattern to internationalize the strings:
+import { useTranslations } from 'next-intl';
+import { transKeys } from '@/i18n/keys';
+
export const SaveIndicator = observer(() => {
const editorEngine = useEditorEngine();
+ const t = useTranslations();
const saveState: SaveState = editorEngine.saveState.saveState;
const getIndicatorContent = () => {
switch (saveState) {
case 'saving':
return (
<div className="flex items-center gap-1.5 text-xs text-foreground-secondary">
<Icons.Reload className="h-3 w-3 animate-spin" />
- <span>Saving...</span>
+ <span>{t(transKeys.editor.saveState.saving)}</span>
</div>
);
case 'saved':
return (
<div className="flex items-center gap-1.5 text-xs text-foreground-tertiary">
<Icons.Check className="h-3 w-3" />
- <span>Saved</span>
+ <span>{t(transKeys.editor.saveState.saved)}</span>
</div>
);
case 'unsaved':
return (
<div className="flex items-center gap-1.5 text-xs text-orange-500">
<Icons.Circle className="h-3 w-3 fill-current" />
- <span>Unsaved changes</span>
+ <span>{t(transKeys.editor.saveState.unsaved)}</span>
</div>
);
}
};Based on coding guidelines.
Also applies to: 26-26, 33-33
🤖 Prompt for AI Agents
In apps/web/client/src/app/project/[id]/_components/top-bar/save-indicator.tsx
around lines 19, 26 and 33, the user-facing strings ("Saving...", "Saved",
"Unsaved changes") are hardcoded and must be internationalized: import and use
next-intl's useTranslations (or the project's i18n hook), add message keys
(e.g., project.saveIndicator.saving, .saved, .unsaved) to the appropriate locale
JSON, and replace the literal strings with calls to
t('project.saveIndicator.saving') / t('project.saveIndicator.saved') /
t('project.saveIndicator.unsaved') so the component renders localized text;
ensure the import and t() usage match the component's typing and render logic.
| const getTooltipContent = () => { | ||
| switch (saveState) { | ||
| case 'saving': | ||
| return 'Saving your changes...'; |
There was a problem hiding this comment.
Replace hardcoded tooltip text with next-intl messages.
The tooltip text is also hardcoded and should be internationalized. Note that the "Last saved" message includes dynamic content that needs proper formatting.
Apply this pattern:
const getTooltipContent = () => {
switch (saveState) {
case 'saving':
- return 'Saving your changes...';
+ return t(transKeys.editor.saveState.savingTooltip);
case 'saved':
- return `Last saved ${editorEngine.saveState.formattedTimeSinceLastSave}`;
+ return t(transKeys.editor.saveState.savedTooltip, {
+ time: editorEngine.saveState.formattedTimeSinceLastSave
+ });
case 'unsaved':
- return 'You have unsaved changes';
+ return t(transKeys.editor.saveState.unsavedTooltip);
}
};Based on coding guidelines.
Also applies to: 44-44, 46-46
🤖 Prompt for AI Agents
In apps/web/client/src/app/project/[id]/_components/top-bar/save-indicator.tsx
around lines 42, 44 and 46, replace the three hardcoded tooltip strings with
next-intl message lookups and use the intl/date formatting helper for the
dynamic "Last saved" string; add message keys (e.g. saveIndicator.saving,
saveIndicator.savedLast, saveIndicator.saved) to the locale JSON, import/use the
next-intl hook (useTranslations or intl) in this component, use the translation
for the static tooltips and for the "Last saved" message call the translation
with a formatted date/time argument (use the provided date formatter from
next-intl or formatDate) so the dynamic timestamp is localized correctly.
| get formattedTimeSinceLastSave(): string { | ||
| const seconds = this.timeSinceLastSave; | ||
| if (seconds < 60) { | ||
| return seconds === 1 ? '1 second ago' : `${seconds} seconds ago`; | ||
| } | ||
| const minutes = Math.floor(seconds / 60); | ||
| return minutes === 1 ? '1 minute ago' : `${minutes} minutes ago`; | ||
| } |
There was a problem hiding this comment.
Internationalize time formatting strings.
The formattedTimeSinceLastSave getter contains hardcoded English text ("1 second ago", "seconds ago", etc.) that should be internationalized. This getter is used in the SaveIndicator tooltip, making it user-facing content.
As per coding guidelines: "Avoid hardcoded user-facing text; use next-intl messages/hooks instead"
Consider one of these approaches:
- Move formatting to the UI component where next-intl is available:
// In SaveStateManager, just expose the raw value
get timeSinceLastSave(): number {
return Math.floor((Date.now() - this.lastSaveTime) / 1000);
}Then format in the SaveIndicator component using next-intl's date/time formatting utilities or custom translation keys.
- Pass a formatter function to the SaveStateManager constructor if formatting must happen in the store layer.
Based on coding guidelines.
🤖 Prompt for AI Agents
In apps/web/client/src/components/store/editor/save-state/index.ts around lines
69 to 76, the getter currently returns hardcoded English strings for elapsed
time which must be internationalized; change the getter to return a raw numeric
value (seconds or minutes) or accept a formatter function injected via the store
constructor, then move string formatting into the UI layer (SaveIndicator) where
next-intl is available (or call the provided formatter) so messages use
next-intl translation utilities instead of hardcoded text.
Problem: Dev login failures show no user feedback and Next.js hydration warnings appear in console.
Solution:
Testing:
User Experience: Silent failure replaced with clear error toast notifications
Important
Improves dev login error handling with toast notifications, suppresses Next.js hydration warnings, and adds a save state indicator for the editor.
DevLoginButtonfor error toast notifications on login failure.AuthProviderfor better error propagation.suppressHydrationWarningto<body>inlayout.tsxto fix Next.js warnings.SaveIndicatorcomponent intop-bar/index.tsxto show save status.SaveStateManagerinsave-state/index.tsto manage save states.LoginButtoncomponent.This description was created by
for f8690b0. You can customize this summary. It will automatically update as commits are pushed.
Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.