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
2 changes: 1 addition & 1 deletion webview-ui/src/components/chat/ChatView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1225,8 +1225,8 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
{telemetrySetting === "unset" && <TelemetryBanner />}
{showAnnouncement && <Announcement version={version} hideAnnouncement={hideAnnouncement} />}

<RooHero />
{taskHistory.length > 0 && <HistoryPreview showHistoryView={showHistoryView} />}
<RooHero />
</div>
)}

Expand Down
161 changes: 95 additions & 66 deletions webview-ui/src/components/history/HistoryPreview.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { memo } from "react"
import { memo, useState, useEffect } from "react"

import { vscode } from "@/utils/vscode"
import { formatLargeNumber, formatDate } from "@/utils/format"
Expand All @@ -16,20 +16,50 @@ type HistoryPreviewProps = {
const HistoryPreview = ({ showHistoryView }: HistoryPreviewProps) => {
const { tasks, showAllWorkspaces } = useTaskSearch()
const { t } = useAppTranslation()
// Use a consistent key for localStorage
const STORAGE_KEY = "historyPreview.minimized"

// Initialize state from localStorage with fallback
const [minimized, setMinimized] = useState(() => {
try {
const savedState = localStorage.getItem(STORAGE_KEY)
return savedState === "true"
} catch (e) {
console.error("Failed to access localStorage:", e)
return false
}
})

// Persist state changes to localStorage and notify VSCode
useEffect(() => {
try {
localStorage.setItem(STORAGE_KEY, minimized.toString())

// Notify VSCode about state change to persist across sessions
vscode.postMessage({
type: "historyPreviewState",
minimized,
})
} catch (e) {
console.error("Failed to save history preview state:", e)
}
}, [minimized])

const toggleMinimized = () => {
setMinimized(!minimized)
}

return (
<>
<div className="flex flex-col gap-3 shrink-0 mx-5">
{!!tasks.length && (
<div className="flex items-center justify-between text-vscode-descriptionForeground">
<div className="flex items-center gap-1">
<span className="codicon codicon-comment-discussion scale-90 mr-1" />
<span className="font-medium text-xs uppercase">{t("history:recentTasks")}</span>
</div>
<Button variant="ghost" size="sm" onClick={() => showHistoryView()} className="uppercase">
{t("history:viewAll")}
</Button>
</div>
<div className="flex flex-col gap-3 shrink-0 mx-4">
{tasks.length > 0 && (
<Button
variant="secondary"
size="default"
onClick={toggleMinimized}
className="w-full text-center py-4 bg-vscode-editor-background text-vscode-foreground text-xs uppercase tracking-wider border border-vscode-toolbar-hoverBackground/30 hover:border-vscode-toolbar-hoverBackground/60">
{minimized ? "Show recent tasks" : "Hide recent tasks"}
</Button>
)}
{tasks.length === 0 && (
<>
Expand All @@ -54,63 +84,62 @@ const HistoryPreview = ({ showHistoryView }: HistoryPreviewProps) => {
</Button>
</>
)}
{tasks.slice(0, 3).map((item) => (
<div
key={item.id}
className="bg-vscode-toolbar-hoverBackground/50 hover:bg-vscode-toolbar-hoverBackground/75 rounded-xs relative overflow-hidden opacity-90 hover:opacity-100 cursor-pointer"
onClick={() => vscode.postMessage({ type: "showTaskWithId", text: item.id })}>
<div className="flex flex-col gap-2 p-3 pt-1">
<div className="flex justify-between items-center">
<span className="text-xs font-medium text-vscode-descriptionForeground uppercase">
{formatDate(item.ts)}
</span>
<CopyButton itemTask={item.task} />
</div>
<div
className="text-vscode-descriptionForeground overflow-hidden whitespace-pre-wrap"
style={{
display: "-webkit-box",
WebkitLineClamp: 3,
WebkitBoxOrient: "vertical",
wordBreak: "break-word",
overflowWrap: "anywhere",
}}>
{item.task}
</div>
<div className="text-xs text-vscode-descriptionForeground">
<span>
{t("history:tokens", {
in: formatLargeNumber(item.tokensIn || 0),
out: formatLargeNumber(item.tokensOut || 0),
})}
</span>
{!!item.cacheWrites && (
<>
{" • "}
<span>
{t("history:cache", {
writes: formatLargeNumber(item.cacheWrites || 0),
reads: formatLargeNumber(item.cacheReads || 0),
})}
</span>
</>
)}
{!!item.totalCost && (
<>
{" • "}
<span>{t("history:apiCost", { cost: item.totalCost?.toFixed(4) })}</span>
</>
{!minimized &&
tasks.slice(0, 3).map((item) => (
<div
key={item.id}
className="bg-vscode-editor-background rounded relative overflow-hidden cursor-pointer border border-vscode-toolbar-hoverBackground/30 hover:border-vscode-toolbar-hoverBackground/60"
onClick={() => vscode.postMessage({ type: "showTaskWithId", text: item.id })}>
<div className="flex flex-col gap-2 p-3 pt-1">
<div className="flex justify-between items-center">
<span className="text-xs font-medium text-vscode-descriptionForeground uppercase">
{formatDate(item.ts)}
</span>
<CopyButton itemTask={item.task} />
</div>
<div
className="text-vscode-foreground overflow-hidden whitespace-pre-wrap"
style={{
display: "-webkit-box",
WebkitLineClamp: 2,
WebkitBoxOrient: "vertical",
wordBreak: "break-word",
overflowWrap: "anywhere",
}}>
{item.task}
</div>
<div className="text-xs text-vscode-descriptionForeground">
<span>
Tokens: ↑{formatLargeNumber(item.tokensIn || 0)} ↓
{formatLargeNumber(item.tokensOut || 0)}
</span>
{!!item.totalCost && (
<>
{" • "}
<span>API Cost: ${item.totalCost?.toFixed(4)}</span>
</>
)}
</div>
{showAllWorkspaces && item.workspace && (
<div className="flex flex-row gap-1 text-vscode-descriptionForeground text-xs mt-1">
<span className="codicon codicon-folder scale-80" />
<span>{item.workspace}</span>
</div>
)}
</div>
{showAllWorkspaces && item.workspace && (
<div className="flex flex-row gap-1 text-vscode-descriptionForeground text-xs mt-1">
<span className="codicon codicon-folder scale-80" />
<span>{item.workspace}</span>
</div>
)}
</div>
</div>
))}
))}

{/* View All History button */}
{!minimized && tasks.length > 0 && (
<Button
variant="secondary"
size="default"
onClick={() => showHistoryView()}
className="w-full text-center py-4 bg-vscode-editor-background text-vscode-foreground text-xs uppercase tracking-wider border border-vscode-toolbar-hoverBackground/30 hover:border-vscode-toolbar-hoverBackground/60">
View all history
</Button>
)}
</div>
</>
)
Expand Down
36 changes: 33 additions & 3 deletions webview-ui/src/components/welcome/RooHero.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { useState } from "react"
import { useAppTranslation } from "../../i18n/TranslationContext"
import { VSCodeLink } from "@vscode/webview-ui-toolkit/react"

const WelcomeView = () => {
const { t } = useAppTranslation()
// Import translation but don't use it yet
useAppTranslation()

const [imagesBaseUri] = useState(() => {
const w = window as any
return w.IMAGES_BASE_URI || ""
})

return (
<div style={{ padding: "10px 20px", flexShrink: 0 }} className="flex flex-col items-center mt-8 gap-2">
<div className="flex flex-col items-center justify-center h-full px-5 py-2.5">
<div
style={{
backgroundColor: "var(--vscode-foreground)",
Expand All @@ -24,7 +26,35 @@ const WelcomeView = () => {
className="mx-auto">
<img src={imagesBaseUri + "/roo-logo.svg"} alt="Roo logo" className="h-8 opacity-0" />
</div>
<h2 className="">{t("chat:greeting")}</h2>

<h2 className="text-3xl font-semibold leading-none text-vscode-editor-foreground mb-2 whitespace-nowrap font-vscode">
Roo Code
</h2>

<p className="text-vscode-editor-foreground leading-tight mb-6 font-vscode text-center">
Generate, refactor, and debug code with AI assistance.
<br />
Check out our <VSCodeLink href="https://docs.roocode.com/">documentation</VSCodeLink> to learn more.
</p>

<div className="flex flex-col items-start space-y-2 text-vscode-editor-foreground font-vscode max-w-[250px]">
<div className="flex items-center gap-2">
<span className="codicon codicon-list-tree"></span>
<span>
<VSCodeLink href="https://docs.roocode.com/features/boomerang-tasks">
Boomerang Tasks
</VSCodeLink>
: Orchestrate complex workflows with subtasks
</span>
</div>
<div className="flex items-center gap-2">
<span className="codicon codicon-pinned"></span>
<span>
<VSCodeLink href="https://docs.roocode.com/basic-usage/using-modes">Sticky Models</VSCodeLink>:
Each mode remembers your last used model
</span>
</div>
</div>
</div>
)
}
Expand Down
2 changes: 1 addition & 1 deletion webview-ui/src/components/welcome/WelcomeView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const WelcomeView = () => {

return (
<Tab>
<TabContent className="flex flex-col gap-5">
<TabContent className="flex flex-col gap-5 h-full">
<RooHero />

<div className="outline rounded p-4">
Expand Down
Loading