Skip to content

Commit 0b2abee

Browse files
authored
Merge pull request RooCodeInc#1516 from RooVetGit/cte/layout-fixes
App tab layout fixes
2 parents 85775ce + 9fdc546 commit 0b2abee

File tree

21 files changed

+200
-178
lines changed

21 files changed

+200
-178
lines changed

.changeset/lemon-bulldogs-unite.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"roo-cline": patch
3+
---
4+
5+
App tab layout fixes

.env.sample

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
# PostHog API Keys for telemetry
2-
POSTHOG_API_KEY=key-goes-here
1+
POSTHOG_API_KEY=key-goes-here

webview-ui/src/App.tsx

Lines changed: 17 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,31 +17,34 @@ import { HumanRelayDialog } from "./components/human-relay/HumanRelayDialog"
1717

1818
type Tab = "settings" | "history" | "mcp" | "prompts" | "chat"
1919

20+
type HumanRelayDialogState = {
21+
isOpen: boolean
22+
requestId: string
23+
promptText: string
24+
}
25+
2026
const tabsByMessageAction: Partial<Record<NonNullable<ExtensionMessage["action"]>, Tab>> = {
2127
chatButtonClicked: "chat",
2228
settingsButtonClicked: "settings",
2329
promptsButtonClicked: "prompts",
2430
mcpButtonClicked: "mcp",
2531
historyButtonClicked: "history",
2632
}
33+
2734
const App = () => {
2835
const { didHydrateState, showWelcome, shouldShowAnnouncement, telemetrySetting, telemetryKey, machineId } =
2936
useExtensionState()
37+
3038
const [showAnnouncement, setShowAnnouncement] = useState(false)
3139
const [tab, setTab] = useState<Tab>("chat")
32-
const settingsRef = useRef<SettingsViewRef>(null)
33-
34-
// Human Relay Dialog Status
35-
const [humanRelayDialogState, setHumanRelayDialogState] = useState<{
36-
isOpen: boolean
37-
requestId: string
38-
promptText: string
39-
}>({
40+
const [humanRelayDialogState, setHumanRelayDialogState] = useState<HumanRelayDialogState>({
4041
isOpen: false,
4142
requestId: "",
4243
promptText: "",
4344
})
4445

46+
const settingsRef = useRef<SettingsViewRef>(null)
47+
4548
const switchTab = useCallback((newTab: Tab) => {
4649
if (settingsRef.current?.checkUnsaveChanges) {
4750
settingsRef.current.checkUnsaveChanges(() => setTab(newTab))
@@ -74,23 +77,6 @@ const App = () => {
7477
[switchTab],
7578
)
7679

77-
// Processing Human Relay Dialog Submission
78-
const handleHumanRelaySubmit = (requestId: string, text: string) => {
79-
vscode.postMessage({
80-
type: "humanRelayResponse",
81-
requestId,
82-
text,
83-
})
84-
}
85-
86-
// Handle Human Relay dialog box cancel
87-
const handleHumanRelayCancel = (requestId: string) => {
88-
vscode.postMessage({
89-
type: "humanRelayCancel",
90-
requestId,
91-
})
92-
}
93-
9480
useEvent("message", onMessage)
9581

9682
useEffect(() => {
@@ -106,7 +92,7 @@ const App = () => {
10692
}
10793
}, [telemetrySetting, telemetryKey, machineId, didHydrateState])
10894

109-
// Tell Extension that we are ready to receive messages
95+
// Tell the extension that we are ready to receive messages.
11096
useEffect(() => {
11197
vscode.postMessage({ type: "webviewDidLaunch" })
11298
}, [])
@@ -121,24 +107,23 @@ const App = () => {
121107
<WelcomeView />
122108
) : (
123109
<>
124-
{tab === "settings" && <SettingsView ref={settingsRef} onDone={() => setTab("chat")} />}
125-
{tab === "history" && <HistoryView onDone={() => switchTab("chat")} />}
126-
{tab === "mcp" && <McpView onDone={() => switchTab("chat")} />}
127110
{tab === "prompts" && <PromptsView onDone={() => switchTab("chat")} />}
111+
{tab === "mcp" && <McpView onDone={() => switchTab("chat")} />}
112+
{tab === "history" && <HistoryView onDone={() => switchTab("chat")} />}
113+
{tab === "settings" && <SettingsView ref={settingsRef} onDone={() => setTab("chat")} />}
128114
<ChatView
129115
isHidden={tab !== "chat"}
130116
showAnnouncement={showAnnouncement}
131117
hideAnnouncement={() => setShowAnnouncement(false)}
132118
showHistoryView={() => switchTab("history")}
133119
/>
134-
{/* Human Relay Dialog */}
135120
<HumanRelayDialog
136121
isOpen={humanRelayDialogState.isOpen}
137122
requestId={humanRelayDialogState.requestId}
138123
promptText={humanRelayDialogState.promptText}
139124
onClose={() => setHumanRelayDialogState((prev) => ({ ...prev, isOpen: false }))}
140-
onSubmit={handleHumanRelaySubmit}
141-
onCancel={handleHumanRelayCancel}
125+
onSubmit={(requestId, text) => vscode.postMessage({ type: "humanRelayResponse", requestId, text })}
126+
onCancel={(requestId) => vscode.postMessage({ type: "humanRelayCancel", requestId })}
142127
/>
143128
</>
144129
)

webview-ui/src/components/chat/Announcement.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ const Announcement = ({ version, hideAnnouncement }: AnnouncementProps) => {
3333
</p>
3434

3535
<h3 style={{ margin: "12px 0 8px" }}>What's New</h3>
36-
<p style={{ margin: "5px 0px" }}>
36+
<div style={{ margin: "5px 0px" }}>
3737
<ul style={{ margin: "4px 0 6px 20px", padding: 0 }}>
3838
<li>• Faster asynchronous checkpoints</li>
3939
<li>• Support for .rooignore files</li>
@@ -44,7 +44,7 @@ const Announcement = ({ version, hideAnnouncement }: AnnouncementProps) => {
4444
<li>• Updated DeepSeek provider</li>
4545
<li>• New "Human Relay" provider</li>
4646
</ul>
47-
</p>
47+
</div>
4848

4949
<p style={{ margin: "10px 0px 0px" }}>
5050
Get more details and discuss in{" "}

webview-ui/src/components/chat/ChatTextArea.tsx

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,25 @@
11
import React, { forwardRef, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"
22
import DynamicTextArea from "react-textarea-autosize"
3+
34
import { mentionRegex, mentionRegexGlobal } from "../../../../src/shared/context-mentions"
4-
import { useExtensionState } from "../../context/ExtensionStateContext"
5+
import { WebviewMessage } from "../../../../src/shared/WebviewMessage"
6+
import { Mode, getAllModes } from "../../../../src/shared/modes"
7+
8+
import { vscode } from "@/utils/vscode"
59
import {
610
ContextMenuOptionType,
711
getContextMenuOptions,
812
insertMention,
913
removeMention,
1014
shouldShowContextMenu,
11-
} from "../../utils/context-mentions"
12-
import { MAX_IMAGES_PER_MESSAGE } from "./ChatView"
13-
import ContextMenu from "./ContextMenu"
15+
} from "@/utils/context-mentions"
16+
import { SelectDropdown, DropdownOptionType } from "@/components/ui"
17+
18+
import { useExtensionState } from "../../context/ExtensionStateContext"
1419
import Thumbnails from "../common/Thumbnails"
15-
import { vscode } from "../../utils/vscode"
16-
import { WebviewMessage } from "../../../../src/shared/WebviewMessage"
17-
import { Mode, getAllModes } from "../../../../src/shared/modes"
1820
import { convertToMentionPath } from "../../utils/path-mentions"
19-
import { SelectDropdown, DropdownOptionType } from "../ui"
21+
import { MAX_IMAGES_PER_MESSAGE } from "./ChatView"
22+
import ContextMenu from "./ContextMenu"
2023

2124
interface ChatTextAreaProps {
2225
inputValue: string

webview-ui/src/components/chat/ChatView.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1275,7 +1275,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
12751275
modeShortcutText={modeShortcutText}
12761276
/>
12771277

1278-
<div id="chat-view-portal" />
1278+
<div id="roo-portal" />
12791279
</div>
12801280
)
12811281
}

webview-ui/src/components/chat/checkpoints/CheckpointMenu.tsx

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import { useState, useEffect, useCallback } from "react"
1+
import { useState, useCallback } from "react"
22
import { CheckIcon, Cross2Icon } from "@radix-ui/react-icons"
33

44
import { Button, Popover, PopoverContent, PopoverTrigger } from "@/components/ui"
5+
import { useRooPortal } from "@/components/ui/hooks"
56

67
import { vscode } from "../../../utils/vscode"
78
import { Checkpoint } from "./schema"
@@ -14,9 +15,9 @@ type CheckpointMenuProps = {
1415
}
1516

1617
export const CheckpointMenu = ({ ts, commitHash, currentHash, checkpoint }: CheckpointMenuProps) => {
17-
const [portalContainer, setPortalContainer] = useState<HTMLElement>()
1818
const [isOpen, setIsOpen] = useState(false)
1919
const [isConfirming, setIsConfirming] = useState(false)
20+
const portalContainer = useRooPortal("roo-portal")
2021

2122
const isCurrent = currentHash === commitHash
2223
const isFirst = checkpoint.isFirst
@@ -42,15 +43,6 @@ export const CheckpointMenu = ({ ts, commitHash, currentHash, checkpoint }: Chec
4243
setIsOpen(false)
4344
}, [ts, commitHash])
4445

45-
useEffect(() => {
46-
// The dropdown menu uses a portal from @shadcn/ui which by default renders
47-
// at the document root. This causes the menu to remain visible even when
48-
// the parent ChatView component is hidden (during settings/history view).
49-
// By moving the portal inside ChatView, the menu will properly hide when
50-
// its parent is hidden.
51-
setPortalContainer(document.getElementById("chat-view-portal") || undefined)
52-
}, [])
53-
5446
return (
5547
<div className="flex flex-row gap-1">
5648
{isDiffAvailable && (
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { cn } from "@/lib/utils"
2+
import { HTMLAttributes } from "react"
3+
4+
type AlertProps = HTMLAttributes<HTMLDivElement>
5+
6+
export const Alert = ({ className, children, ...props }: AlertProps) => (
7+
<div
8+
className={cn(
9+
"text-vscode-inputValidation-infoForeground bg-vscode-inputValidation-infoBackground border border-vscode-inputValidation-infoBorder rounded-xs p-2",
10+
className,
11+
)}
12+
{...props}>
13+
{children}
14+
</div>
15+
)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { HTMLAttributes } from "react"
2+
3+
import { cn } from "@/lib/utils"
4+
5+
type TabProps = HTMLAttributes<HTMLDivElement>
6+
7+
export const Tab = ({ className, children, ...props }: TabProps) => (
8+
<div className={cn("fixed inset-0 flex flex-col overflow-hidden", className)} {...props}>
9+
{children}
10+
</div>
11+
)
12+
13+
export const TabHeader = ({ className, children, ...props }: TabProps) => (
14+
<div className={cn("px-5 py-2.5 border-b border-vscode-panel-border", className)} {...props}>
15+
{children}
16+
</div>
17+
)
18+
19+
export const TabContent = ({ className, children, ...props }: TabProps) => (
20+
<div className={cn("flex-1 overflow-auto p-5", className)} {...props}>
21+
{children}
22+
</div>
23+
)

webview-ui/src/components/history/HistoryView.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { formatLargeNumber, formatDate } from "@/utils/format"
99
import { cn } from "@/lib/utils"
1010
import { Button } from "@/components/ui"
1111

12+
import { Tab, TabContent, TabHeader } from "../common/Tab"
1213
import { useTaskSearch } from "./useTaskSearch"
1314
import { ExportButton } from "./ExportButton"
1415
import { CopyButton } from "./CopyButton"
@@ -25,8 +26,8 @@ const HistoryView = ({ onDone }: HistoryViewProps) => {
2526
const [deleteTaskId, setDeleteTaskId] = useState<string | null>(null)
2627

2728
return (
28-
<div className="fixed inset-0 flex flex-col">
29-
<div className="flex flex-col gap-2 px-5 py-2.5 border-b border-vscode-panel-border">
29+
<Tab>
30+
<TabHeader className="flex flex-col gap-2">
3031
<div className="flex justify-between items-center">
3132
<h3 className="text-vscode-foreground m-0">History</h3>
3233
<VSCodeButton onClick={onDone}>Done</VSCodeButton>
@@ -81,8 +82,9 @@ const HistoryView = ({ onDone }: HistoryViewProps) => {
8182
</VSCodeRadio>
8283
</VSCodeRadioGroup>
8384
</div>
84-
</div>
85-
<div style={{ flexGrow: 1, overflowY: "auto", margin: 0 }}>
85+
</TabHeader>
86+
87+
<TabContent className="p-0">
8688
<Virtuoso
8789
style={{
8890
flexGrow: 1,
@@ -312,11 +314,12 @@ const HistoryView = ({ onDone }: HistoryViewProps) => {
312314
</div>
313315
)}
314316
/>
315-
</div>
317+
</TabContent>
318+
316319
{deleteTaskId && (
317320
<DeleteTaskDialog taskId={deleteTaskId} onOpenChange={(open) => !open && setDeleteTaskId(null)} open />
318321
)}
319-
</div>
322+
</Tab>
320323
)
321324
}
322325

0 commit comments

Comments
 (0)