Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion webview-ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { AccountView } from "./components/account/AccountView"
import { useAddNonInteractiveClickListener } from "./components/ui/hooks/useNonInteractiveClick"
import { TooltipProvider } from "./components/ui/tooltip"
import { STANDARD_TOOLTIP_DELAY } from "./components/ui/standard-tooltip"
import { LoadingScreen } from "./components/common/LoadingScreen"

type Tab = "settings" | "history" | "mcp" | "modes" | "chat" | "marketplace" | "account"

Expand Down Expand Up @@ -81,6 +82,7 @@ const App = () => {

const [showAnnouncement, setShowAnnouncement] = useState(false)
const [tab, setTab] = useState<Tab>("chat")
const [showTimeout, setShowTimeout] = useState(false)

const [humanRelayDialogState, setHumanRelayDialogState] = useState<HumanRelayDialogState>({
isOpen: false,
Expand Down Expand Up @@ -207,6 +209,27 @@ const App = () => {
console.debug("App initialized with source map support")
}, [])

// Add timeout handling for extension state
useEffect(() => {
if (!didHydrateState) {
// Show timeout message after 5 seconds
const timeoutTimer = setTimeout(() => {
setShowTimeout(true)
}, 5000)

// Retry sending webviewDidLaunch after 3 seconds
const retryTimer = setTimeout(() => {
console.debug("Retrying webviewDidLaunch message...")
vscode.postMessage({ type: "webviewDidLaunch" })
}, 3000)

return () => {
clearTimeout(timeoutTimer)
clearTimeout(retryTimer)
}
}
}, [didHydrateState])

// Focus the WebView when non-interactive content is clicked (only in editor/tab mode)
useAddNonInteractiveClickListener(
useCallback(() => {
Expand All @@ -224,7 +247,7 @@ const App = () => {
}, [tab])

if (!didHydrateState) {
return null
return <LoadingScreen showTimeout={showTimeout} />
}

// Do not conditionally load ChatView, it's expensive and there's state we
Expand Down
24 changes: 24 additions & 0 deletions webview-ui/src/components/common/LoadingScreen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from "react"
import { VSCodeProgressRing } from "@vscode/webview-ui-toolkit/react"

interface LoadingScreenProps {
message?: string
showTimeout?: boolean
}

export const LoadingScreen: React.FC<LoadingScreenProps> = ({
message = "Loading Roo Code...",
Copy link
Contributor

Choose a reason for hiding this comment

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

User-facing text ('Loading Roo Code...' and 'Taking longer than expected...') is hardcoded. Consider using translation functions to support internationalization as per our guidelines.

This comment was generated because it violated a code review rule: irule_C0ez7Rji6ANcGkkX.

showTimeout = false,
}) => {
return (
<div className="fixed inset-0 flex flex-col items-center justify-center bg-vscode-editor-background">
<div className="flex flex-col items-center gap-4">
<VSCodeProgressRing />
<p className="text-vscode-foreground text-sm">{message}</p>
{showTimeout && (
<p className="text-vscode-descriptionForeground text-xs mt-2">Taking longer than expected...</p>
)}
</div>
</div>
)
}
13 changes: 12 additions & 1 deletion webview-ui/src/context/ExtensionStateContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -360,8 +360,19 @@ export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode
}, [handleMessage])

useEffect(() => {
// Send initial launch message
vscode.postMessage({ type: "webviewDidLaunch" })
}, [])

// If we don't get a response within 2 seconds, try again
const retryTimer = setTimeout(() => {
if (!didHydrateState) {
console.warn("No state received from extension, retrying webviewDidLaunch...")
vscode.postMessage({ type: "webviewDidLaunch" })
}
}, 2000)

return () => clearTimeout(retryTimer)
}, [didHydrateState])

const contextValue: ExtensionStateContextType = {
...state,
Expand Down