Skip to content
Closed
Show file tree
Hide file tree
Changes from 5 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
4 changes: 4 additions & 0 deletions src/core/webview/ClineProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,8 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
() => {
if (this.view?.visible) {
this.postMessageToWebview({ type: "action", action: "didBecomeVisible" })
} else {
this.postMessageToWebview({ type: "action", action: "didBecomeInvisible" })
}
},
null,
Expand All @@ -408,6 +410,8 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
() => {
if (this.view?.visible) {
this.postMessageToWebview({ type: "action", action: "didBecomeVisible" })
} else {
this.postMessageToWebview({ type: "action", action: "didBecomeInvisible" })
}
},
null,
Expand Down
1 change: 1 addition & 0 deletions src/shared/ExtensionMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export interface ExtensionMessage {
| "historyButtonClicked"
| "promptsButtonClicked"
| "didBecomeVisible"
| "didBecomeInvisible"
invoke?: "newChat" | "sendMessage" | "primaryButtonClick" | "secondaryButtonClick" | "setChatBoxMessage"
state?: ExtensionState
images?: string[]
Expand Down
43 changes: 14 additions & 29 deletions webview-ui/src/components/chat/ChatView.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { VSCodeButton, VSCodeLink } from "@vscode/webview-ui-toolkit/react"
import debounce from "debounce"
import { useCallback, useEffect, useMemo, useRef, useState } from "react"
import { useDeepCompareEffect, useEvent, useMount } from "react-use"
import { useDeepCompareEffect, useEvent } from "react-use"
import { Virtuoso, type VirtuosoHandle } from "react-virtuoso"
import styled from "styled-components"
import {
Expand Down Expand Up @@ -32,6 +32,7 @@ import { getAllModes } from "../../../../src/shared/modes"
import TelemetryBanner from "../common/TelemetryBanner"
import { useAppTranslation } from "@/i18n/TranslationContext"
import removeMd from "remove-markdown"
import { useFocusPreservation } from "./hooks/useFocusPreservation"

interface ChatViewProps {
isHidden: boolean
Expand Down Expand Up @@ -95,6 +96,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
const [showScrollToBottom, setShowScrollToBottom] = useState(false)
const [isAtBottom, setIsAtBottom] = useState(false)
const lastTtsRef = useRef<string>("")
const [viewHidden, setViewHidden] = useState<boolean>(false)

const [wasStreaming, setWasStreaming] = useState<boolean>(false)
const [showCheckpointWarning, setShowCheckpointWarning] = useState<boolean>(false)
Expand Down Expand Up @@ -140,13 +142,9 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
case "followup":
setTextAreaDisabled(isPartial)
setClineAsk("followup")
// setting enable buttons to `false` would trigger a focus grab when
// the text area is enabled which is undesirable.
// We have no buttons for this tool, so no problem having them "enabled"
// to workaround this issue. See #1358.
setEnableButtons(true)
setPrimaryButtonText(undefined)
setSecondaryButtonText(undefined)
setEnableButtons(isPartial)
// setPrimaryButtonText(undefined)
// setSecondaryButtonText(undefined)
break
case "tool":
if (!isAutoApproved(lastMessage)) {
Expand Down Expand Up @@ -495,9 +493,10 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
case "action":
switch (message.action!) {
case "didBecomeVisible":
if (!isHidden && !textAreaDisabled && !enableButtons) {
textAreaRef.current?.focus()
}
setViewHidden(false)
break
case "didBecomeInvisible":
setViewHidden(true)
break
}
break
Expand Down Expand Up @@ -531,9 +530,6 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
// textAreaRef.current is not explicitly required here since react gaurantees that ref will be stable across re-renders, and we're not using its value but its reference.
},
[
isHidden,
textAreaDisabled,
enableButtons,
handleChatReset,
handleSendMessage,
handleSetChatBoxMessage,
Expand All @@ -544,21 +540,10 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie

useEvent("message", handleMessage)

useMount(() => {
// NOTE: the vscode window needs to be focused for this to work
textAreaRef.current?.focus()
})

useEffect(() => {
const timer = setTimeout(() => {
if (!isHidden && !textAreaDisabled && !enableButtons) {
textAreaRef.current?.focus()
}
}, 50)
return () => {
clearTimeout(timer)
}
}, [isHidden, textAreaDisabled, enableButtons])
// preserve focus on text area when...
// - isHidden: switching to another Roo tab
// - viewHidden: switchint to another VSCode extension, or hiding this one.
useFocusPreservation(textAreaRef.current, isHidden || viewHidden)

const visibleMessages = useMemo(() => {
return modifiedMessages.filter((message) => {
Expand Down
Loading
Loading