Add title and logs; fix row expansion in browser group

This commit is contained in:
Saoud Rizwan
2024-10-27 14:17:50 -04:00
parent 978c6996af
commit 3ba1eaf908
3 changed files with 114 additions and 28 deletions

View File

@@ -5,13 +5,13 @@ import { BrowserActionResult, ClineMessage, ClineSayBrowserAction } from "../../
import { vscode } from "../../utils/vscode" import { vscode } from "../../utils/vscode"
import CodeAccordian from "../common/CodeAccordian" import CodeAccordian from "../common/CodeAccordian"
import CodeBlock, { CODE_BLOCK_BG_COLOR } from "../common/CodeBlock" import CodeBlock, { CODE_BLOCK_BG_COLOR } from "../common/CodeBlock"
import { ChatRowContent } from "./ChatRow" import { ChatRowContent, ProgressIndicator } from "./ChatRow"
import { VSCodeButton } from "@vscode/webview-ui-toolkit/react" import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
interface BrowserSessionRowProps { interface BrowserSessionRowProps {
messages: ClineMessage[] messages: ClineMessage[]
isExpanded: boolean isExpanded: (messageTs: number) => boolean
onToggleExpand: () => void onToggleExpand: (messageTs: number) => void
lastModifiedMessage?: ClineMessage lastModifiedMessage?: ClineMessage
isLast: boolean isLast: boolean
onHeightChange: (isTaller: boolean) => void onHeightChange: (isTaller: boolean) => void
@@ -20,12 +20,20 @@ interface BrowserSessionRowProps {
/* /*
- console logs will be aggregate up to that current page - console logs will be aggregate up to that current page
- while isbrowsing, disable next prev buttons and latest action if click use that as position instead of display state
*/ */
const BrowserSessionRow = memo((props: BrowserSessionRowProps) => { const BrowserSessionRow = memo((props: BrowserSessionRowProps) => {
const { messages, isLast, onHeightChange } = props const { messages, isLast, onHeightChange, lastModifiedMessage, isExpanded } = props
const prevHeightRef = useRef(0) const prevHeightRef = useRef(0)
const maxActionHeightRef = useRef(0) // Track max height of action section const [maxActionHeight, setMaxActionHeight] = useState(0)
const [consoleLogsExpanded, setConsoleLogsExpanded] = useState(false)
const isBrowsing = useMemo(() => {
return (
isLast && lastModifiedMessage?.ask !== "resume_task" && lastModifiedMessage?.ask !== "resume_completed_task"
)
}, [isLast, lastModifiedMessage])
// Organize messages into pages with current state and next action // Organize messages into pages with current state and next action
const pages = useMemo(() => { const pages = useMemo(() => {
@@ -33,6 +41,8 @@ const BrowserSessionRow = memo((props: BrowserSessionRowProps) => {
currentState: { currentState: {
url?: string url?: string
screenshot?: string screenshot?: string
mousePosition?: string
consoleLogs?: string
messages: ClineMessage[] // messages up to and including the result messages: ClineMessage[] // messages up to and including the result
} }
nextAction?: { nextAction?: {
@@ -57,6 +67,8 @@ const BrowserSessionRow = memo((props: BrowserSessionRowProps) => {
currentState: { currentState: {
url: resultData.currentUrl, url: resultData.currentUrl,
screenshot: resultData.screenshot, screenshot: resultData.screenshot,
mousePosition: resultData.currentMousePosition,
consoleLogs: resultData.logs,
messages: [...currentStateMessages], messages: [...currentStateMessages],
}, },
nextAction: nextAction:
@@ -120,11 +132,13 @@ const BrowserSessionRow = memo((props: BrowserSessionRowProps) => {
if (page.currentState.url || page.currentState.screenshot) { if (page.currentState.url || page.currentState.screenshot) {
return { return {
url: page.currentState.url, url: page.currentState.url,
mousePosition: page.currentState.mousePosition,
consoleLogs: page.currentState.consoleLogs,
screenshot: page.currentState.screenshot, screenshot: page.currentState.screenshot,
} }
} }
} }
return { url: undefined, screenshot: undefined } return { url: undefined, mousePosition: undefined, consoleLogs: undefined, screenshot: undefined }
}, [pages]) }, [pages])
const currentPage = pages[currentPageIndex] const currentPage = pages[currentPageIndex]
@@ -134,17 +148,26 @@ const BrowserSessionRow = memo((props: BrowserSessionRowProps) => {
const displayState = isLastPage const displayState = isLastPage
? { ? {
url: currentPage?.currentState.url || latestState.url || initialUrl, url: currentPage?.currentState.url || latestState.url || initialUrl,
mousePosition: currentPage?.currentState.mousePosition || latestState.mousePosition || "400,300",
consoleLogs: currentPage?.currentState.consoleLogs,
screenshot: currentPage?.currentState.screenshot || latestState.screenshot, screenshot: currentPage?.currentState.screenshot || latestState.screenshot,
} }
: { : {
url: currentPage?.currentState.url || initialUrl, url: currentPage?.currentState.url || initialUrl,
mousePosition: currentPage?.currentState.mousePosition || "400,300",
consoleLogs: currentPage?.currentState.consoleLogs,
screenshot: currentPage?.currentState.screenshot, screenshot: currentPage?.currentState.screenshot,
} }
const [actionContent, { height: actionHeight }] = useSize( const [actionContent, { height: actionHeight }] = useSize(
<div> <div>
{currentPage?.nextAction?.messages.map((message) => ( {currentPage?.nextAction?.messages.map((message) => (
<BrowserSessionRowContent key={message.ts} {...props} message={message} /> <BrowserSessionRowContent
key={message.ts}
{...props}
message={message}
setMaxActionHeight={setMaxActionHeight}
/>
))} ))}
</div> </div>
) )
@@ -153,13 +176,31 @@ const BrowserSessionRow = memo((props: BrowserSessionRowProps) => {
if (actionHeight === 0 || actionHeight === Infinity) { if (actionHeight === 0 || actionHeight === Infinity) {
return return
} }
if (actionHeight > maxActionHeightRef.current) { if (actionHeight > maxActionHeight) {
maxActionHeightRef.current = actionHeight setMaxActionHeight(actionHeight)
} }
}, [actionHeight]) }, [actionHeight, maxActionHeight])
useEffect(() => {
if (!displayState.consoleLogs || displayState.consoleLogs.trim() === "") {
setConsoleLogsExpanded(false)
}
}, [displayState.consoleLogs])
const [browserSessionRow, { height }] = useSize( const [browserSessionRow, { height }] = useSize(
<div style={{ padding: "10px 6px 10px 15px" }}> <div style={{ padding: "10px 6px 10px 15px" }}>
<div style={{ display: "flex", alignItems: "center", gap: "10px", marginBottom: "10px" }}>
{isBrowsing ? (
<ProgressIndicator />
) : (
<span
className={`codicon codicon-inspect`}
style={{ color: "var(--vscode-foreground)", marginBottom: "-1.5px" }}></span>
)}
<span style={{ fontWeight: "bold" }}>
<>Cline wants to use the browser:</>
</span>
</div>
<div <div
style={{ style={{
borderRadius: 3, borderRadius: 3,
@@ -172,6 +213,7 @@ const BrowserSessionRow = memo((props: BrowserSessionRowProps) => {
style={{ style={{
margin: "5px auto", margin: "5px auto",
width: "calc(100% - 10px)", width: "calc(100% - 10px)",
boxSizing: "border-box", // includes padding in width calculation
backgroundColor: "var(--vscode-input-background)", backgroundColor: "var(--vscode-input-background)",
border: "1px solid var(--vscode-input-border)", border: "1px solid var(--vscode-input-border)",
borderRadius: "4px", borderRadius: "4px",
@@ -228,11 +270,42 @@ const BrowserSessionRow = memo((props: BrowserSessionRowProps) => {
/> />
</div> </div>
)} )}
{displayState.mousePosition && (
<BrowserCursor
style={{
position: "absolute",
top: `${(parseInt(displayState.mousePosition.split(",")[1]) / 600) * 100}%`,
left: `${(parseInt(displayState.mousePosition.split(",")[0]) / 800) * 100}%`,
}}
/>
)}
</div>
<div style={{ width: "100%" }}>
<div
onClick={() => {
setConsoleLogsExpanded(!consoleLogsExpanded)
}}
style={{
display: "flex",
alignItems: "center",
gap: "4px",
width: "100%",
justifyContent: "flex-start",
cursor: "pointer",
padding: `9px 8px ${consoleLogsExpanded ? 0 : 8}px 8px`,
}}>
<span className={`codicon codicon-chevron-${consoleLogsExpanded ? "down" : "right"}`}></span>
<span style={{ fontSize: "0.8em" }}>Console Logs</span>
</div>
{consoleLogsExpanded && (
<CodeBlock source={`${"```"}shell\n${displayState.consoleLogs || "(No new logs)"}\n${"```"}`} />
)}
</div> </div>
</div> </div>
{/* Action content with min height */} {/* Action content with min height */}
<div style={{ minHeight: maxActionHeightRef.current }}>{actionContent}</div> <div style={{ minHeight: maxActionHeight }}>{actionContent}</div>
{/* Pagination moved to bottom */} {/* Pagination moved to bottom */}
{pages.length > 1 && ( {pages.length > 1 && (
@@ -250,12 +323,12 @@ const BrowserSessionRow = memo((props: BrowserSessionRowProps) => {
</div> </div>
<div style={{ display: "flex", gap: "4px" }}> <div style={{ display: "flex", gap: "4px" }}>
<VSCodeButton <VSCodeButton
disabled={currentPageIndex === 0} disabled={currentPageIndex === 0 || isBrowsing}
onClick={() => setCurrentPageIndex((i) => i - 1)}> onClick={() => setCurrentPageIndex((i) => i - 1)}>
Previous Previous
</VSCodeButton> </VSCodeButton>
<VSCodeButton <VSCodeButton
disabled={currentPageIndex === pages.length - 1} disabled={currentPageIndex === pages.length - 1 || isBrowsing}
onClick={() => setCurrentPageIndex((i) => i + 1)}> onClick={() => setCurrentPageIndex((i) => i + 1)}>
Next Next
</VSCodeButton> </VSCodeButton>
@@ -281,6 +354,7 @@ const BrowserSessionRow = memo((props: BrowserSessionRowProps) => {
interface BrowserSessionRowContentProps extends Omit<BrowserSessionRowProps, "messages"> { interface BrowserSessionRowContentProps extends Omit<BrowserSessionRowProps, "messages"> {
message: ClineMessage message: ClineMessage
setMaxActionHeight: (height: number) => void
} }
const BrowserSessionRowContent = ({ const BrowserSessionRowContent = ({
@@ -289,6 +363,7 @@ const BrowserSessionRowContent = ({
onToggleExpand, onToggleExpand,
lastModifiedMessage, lastModifiedMessage,
isLast, isLast,
setMaxActionHeight,
}: BrowserSessionRowContentProps) => { }: BrowserSessionRowContentProps) => {
const headerStyle: React.CSSProperties = { const headerStyle: React.CSSProperties = {
display: "flex", display: "flex",
@@ -307,13 +382,20 @@ const BrowserSessionRowContent = ({
case "api_req_started": case "api_req_started":
case "text": case "text":
return ( return (
<ChatRowContent <div style={{ padding: "15px 0 5px 0" }}>
message={message} <ChatRowContent
isExpanded={isExpanded} message={message}
onToggleExpand={onToggleExpand} isExpanded={isExpanded(message.ts)}
lastModifiedMessage={lastModifiedMessage} onToggleExpand={() => {
isLast={isLast} if (message.say === "api_req_started") {
/> setMaxActionHeight(0)
}
onToggleExpand(message.ts)
}}
lastModifiedMessage={lastModifiedMessage}
isLast={isLast}
/>
</div>
) )
case "browser_action": case "browser_action":
@@ -355,8 +437,8 @@ const BrowserSessionRowContent = ({
code={logs} code={logs}
language="shell" language="shell"
isConsoleLogs={true} isConsoleLogs={true}
isExpanded={isExpanded} isExpanded={isExpanded(message.ts)}
onToggleExpand={onToggleExpand} onToggleExpand={() => onToggleExpand(message.ts)}
/> />
)} )}
</div> </div>

View File

@@ -754,7 +754,7 @@ export const ChatRowContent = ({
} }
} }
const ProgressIndicator = () => ( export const ProgressIndicator = () => (
<div <div
style={{ style={{
width: "16px", width: "16px",

View File

@@ -627,16 +627,20 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
(index: number, messageOrGroup: ClineMessage | ClineMessage[]) => { (index: number, messageOrGroup: ClineMessage | ClineMessage[]) => {
// browser session group // browser session group
if (Array.isArray(messageOrGroup)) { if (Array.isArray(messageOrGroup)) {
const firstMessage = messageOrGroup[0]
return ( return (
<BrowserSessionRow <BrowserSessionRow
key={firstMessage.ts}
messages={messageOrGroup} messages={messageOrGroup}
isExpanded={expandedRows[firstMessage.ts] || false}
onToggleExpand={() => toggleRowExpansion(firstMessage.ts)}
lastModifiedMessage={modifiedMessages.at(-1)}
isLast={index === groupedMessages.length - 1} isLast={index === groupedMessages.length - 1}
lastModifiedMessage={modifiedMessages.at(-1)}
onHeightChange={handleRowHeightChange} onHeightChange={handleRowHeightChange}
// Pass handlers for each message in the group
isExpanded={(messageTs: number) => expandedRows[messageTs] ?? false}
onToggleExpand={(messageTs: number) => {
setExpandedRows((prev) => ({
...prev,
[messageTs]: !prev[messageTs],
}))
}}
/> />
) )
} }