mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-05 08:10:14 +00:00
Initial restructuring of onboarding content
This commit is contained in:
parent
8dbd8c4b1b
commit
25364a4f53
6 changed files with 146 additions and 82 deletions
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
|
|
@ -10,7 +10,7 @@
|
|||
"type": "extensionHost",
|
||||
"request": "launch",
|
||||
"runtimeExecutable": "${execPath}",
|
||||
"args": ["--extensionDevelopmentPath=${workspaceFolder}/src"],
|
||||
"args": ["--extensionDevelopmentPath=${workspaceFolder}/src", "--profile-temp"],
|
||||
"sourceMaps": true,
|
||||
"outFiles": ["${workspaceFolder}/src/dist/**/*.js"],
|
||||
"preLaunchTask": "${defaultBuildTask}",
|
||||
|
|
|
|||
|
|
@ -1776,7 +1776,6 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
|
|||
<div
|
||||
data-testid="chat-view"
|
||||
className={isHidden ? "hidden" : "fixed top-0 left-0 right-0 bottom-0 flex flex-col overflow-hidden"}>
|
||||
{telemetrySetting === "unset" && <TelemetryBanner />}
|
||||
{(showAnnouncement || showAnnouncementModal) && (
|
||||
<Announcement
|
||||
hideAnnouncement={() => {
|
||||
|
|
@ -1832,14 +1831,16 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
|
|||
</div>
|
||||
)}
|
||||
<div
|
||||
className={` w-full flex flex-col gap-4 m-auto ${isExpanded && tasks.length > 0 ? "mt-0" : ""} px-3.5 min-[370px]:px-10 pt-5 transition-all duration-300`}>
|
||||
className={` w-full flex flex-col gap-4 items-start m-auto ${isExpanded && tasks.length > 0 ? "mt-0" : ""} px-3.5 min-[370px]:px-10 pt-5 transition-all duration-300`}>
|
||||
{/* Version indicator in top-right corner - only on welcome screen */}
|
||||
<VersionIndicator
|
||||
onClick={() => setShowAnnouncementModal(true)}
|
||||
className="absolute top-2 right-3 z-10"
|
||||
/>
|
||||
|
||||
<RooHero />
|
||||
<div className="ml-6">
|
||||
<RooHero />
|
||||
</div>
|
||||
|
||||
<div className="mb-2.5">
|
||||
{cloudIsAuthenticated || taskHistory.length < 4 ? (
|
||||
|
|
@ -1989,6 +1990,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
|
|||
}
|
||||
}}
|
||||
/>
|
||||
{telemetrySetting === "unset" && <TelemetryBanner />}
|
||||
<ChatTextArea
|
||||
ref={textAreaRef}
|
||||
inputValue={inputValue}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { memo, useState } from "react"
|
||||
import { Trans } from "react-i18next"
|
||||
import { VSCodeLink } from "@vscode/webview-ui-toolkit/react"
|
||||
import { ChartColumnIncreasing } from "lucide-react"
|
||||
|
||||
import type { TelemetrySetting } from "@roo-code/types"
|
||||
|
||||
|
|
@ -29,7 +30,7 @@ const TelemetryBanner = () => {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="relative px-4 py-2.5 pr-10 bg-vscode-banner-background border-b border-vscode-panel-border text-sm leading-normal text-vscode-foreground">
|
||||
<div className="relative p-4 mb-4 flex gap-2 bg-vscode-button-secondaryBackground/50 border-b border-vscode-panel-border text-sm text-vscode-foreground">
|
||||
{/* Close button (X) */}
|
||||
<button
|
||||
onClick={handleClose}
|
||||
|
|
@ -38,14 +39,17 @@ const TelemetryBanner = () => {
|
|||
×
|
||||
</button>
|
||||
|
||||
<div className="mb-0.5 font-bold">{t("welcome:telemetry.helpImprove")}</div>
|
||||
<div>
|
||||
<Trans
|
||||
i18nKey="welcome:telemetry.helpImproveMessage"
|
||||
components={{
|
||||
settingsLink: <VSCodeLink href="#" onClick={handleOpenSettings} />,
|
||||
}}
|
||||
/>
|
||||
<ChartColumnIncreasing className="inline size-4 mt-0.5 shrink-0" />
|
||||
<div className="pr-6 cursor-default">
|
||||
<div className="mb-0.5 font-bold">{t("welcome:telemetry.helpImprove")}</div>
|
||||
<div>
|
||||
<Trans
|
||||
i18nKey="welcome:telemetry.helpImproveMessage"
|
||||
components={{
|
||||
settingsLink: <VSCodeLink href="#" onClick={handleOpenSettings} />,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,55 +1,67 @@
|
|||
import { VSCodeLink } from "@vscode/webview-ui-toolkit/react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { Trans } from "react-i18next"
|
||||
|
||||
import { buildDocLink } from "@src/utils/docLinks"
|
||||
import { Keyboard, ReplaceAll, LucideIcon, CheckCheck, Users2 } from "lucide-react"
|
||||
import { Button } from "../ui"
|
||||
|
||||
const tips = [
|
||||
interface TipItem {
|
||||
icon: LucideIcon
|
||||
title: string
|
||||
description: string
|
||||
}
|
||||
|
||||
const tipItems: TipItem[] = [
|
||||
{
|
||||
icon: "codicon-account",
|
||||
href: buildDocLink("basic-usage/using-modes", "tips"),
|
||||
titleKey: "rooTips.customizableModes.title",
|
||||
descriptionKey: "rooTips.customizableModes.description",
|
||||
icon: Users2,
|
||||
title: "Powerful role-specific modes",
|
||||
description:
|
||||
"Personas like Architect, Code and Ask which stay on task and deliver results. Create your own or get more in the marketplace.",
|
||||
},
|
||||
{
|
||||
icon: "codicon-list-tree",
|
||||
href: buildDocLink("features/boomerang-tasks", "tips"),
|
||||
titleKey: "rooTips.boomerangTasks.title",
|
||||
descriptionKey: "rooTips.boomerangTasks.description",
|
||||
icon: CheckCheck,
|
||||
title: "Granular auto-approval",
|
||||
description: "Make Roo as autonomous as you want as you build confidence. Or go YOLO.",
|
||||
},
|
||||
{
|
||||
icon: Keyboard,
|
||||
title: "Highly customizable",
|
||||
description:
|
||||
"Fine-tune settings for Roo to work for you, like inference context, model properties, slash commands and more.",
|
||||
},
|
||||
{
|
||||
icon: ReplaceAll,
|
||||
title: "Model-agnostic",
|
||||
description: "Bring your own key, no markup or lock-in.",
|
||||
},
|
||||
]
|
||||
|
||||
const RooTips = () => {
|
||||
const { t } = useTranslation("chat")
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p className="text-vscode-editor-foreground leading-tight font-vscode-font-family text-center text-balance max-w-[380px] mx-auto my-0">
|
||||
<Trans
|
||||
i18nKey="chat:about"
|
||||
components={{
|
||||
DocsLink: (
|
||||
<a href={buildDocLink("", "welcome")} target="_blank" rel="noopener noreferrer">
|
||||
the docs
|
||||
</a>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<div className="text-left text-base font-light pl-7 pr-2">
|
||||
<h1 className="text-vscode-editor-foreground text-xl">Welcome to Roo Code!</h1>
|
||||
|
||||
<p className="font-bold">Get a whole dev team in your editor:</p>
|
||||
<ul className="space-y-3 -ml-7">
|
||||
{tipItems.map((item, index) => {
|
||||
const Icon = item.icon
|
||||
return (
|
||||
<li key={index} className="flex items-start gap-3">
|
||||
<Icon className="size-3.5 mt-0.75 shrink-0" />
|
||||
<div>
|
||||
<strong className="block font-semibold mr-1">{item.title}</strong>
|
||||
<span className="text-vscode-descriptionForeground">{item.description}</span>
|
||||
</div>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
<p className="text-vscode-descriptionForeground">
|
||||
Learn more in the <VSCodeLink href={buildDocLink("", "onboarding-home")}>docs</VSCodeLink>
|
||||
</p>
|
||||
<div className="flex flex-col items-center justify-center px-5 py-2.5 gap-4">
|
||||
{tips.map((tip) => (
|
||||
<div
|
||||
key={tip.titleKey}
|
||||
className="flex items-center gap-2 text-vscode-editor-foreground font-vscode max-w-[250px]">
|
||||
<span className={`codicon ${tip.icon}`}></span>
|
||||
<span>
|
||||
<VSCodeLink className="forced-color-adjust-none" href={tip.href}>
|
||||
{t(tip.titleKey)}
|
||||
</VSCodeLink>
|
||||
: {t(tip.descriptionKey)}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
|
||||
<div className="mt-12 border-t border-vscode-panel-border">
|
||||
<p>To get started:</p>
|
||||
<Button>Configure API Provider</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,46 +1,92 @@
|
|||
import React from "react"
|
||||
import { render, screen } from "@/utils/test-utils"
|
||||
|
||||
import { render, screen } from "@testing-library/react"
|
||||
import { describe, it, expect, vi } from "vitest"
|
||||
import RooTips from "../RooTips"
|
||||
|
||||
// Mock react-i18next
|
||||
vi.mock("react-i18next", () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => key, // Simple mock that returns the key
|
||||
t: (key: string) => key,
|
||||
}),
|
||||
Trans: ({
|
||||
children,
|
||||
components,
|
||||
}: {
|
||||
children?: React.ReactNode
|
||||
components?: Record<string, React.ReactElement>
|
||||
}) => {
|
||||
// Simple mock that renders children or the first component if no children
|
||||
return children || (components && Object.values(components)[0]) || null
|
||||
},
|
||||
Trans: ({ children }: { children: React.ReactNode }) => children,
|
||||
}))
|
||||
|
||||
vi.mock("@vscode/webview-ui-toolkit/react", () => ({
|
||||
VSCodeLink: ({ href, children }: { href: string; children: React.ReactNode }) => <a href={href}>{children}</a>,
|
||||
// Mock lucide-react icons
|
||||
vi.mock("lucide-react", () => ({
|
||||
ReplaceAll: ({ className }: { className?: string }) => <div data-testid="replace-all-icon" className={className} />,
|
||||
ChefHat: ({ className }: { className?: string }) => <div data-testid="chef-hat-icon" className={className} />,
|
||||
Keyboard: ({ className }: { className?: string }) => <div data-testid="keyboard-icon" className={className} />,
|
||||
Wifi: ({ className }: { className?: string }) => <div data-testid="wifi-icon" className={className} />,
|
||||
Github: () => null,
|
||||
Router: () => null,
|
||||
}))
|
||||
|
||||
describe("RooTips Component", () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers()
|
||||
describe("RooTips", () => {
|
||||
it("renders the welcome heading", () => {
|
||||
render(<RooTips />)
|
||||
expect(screen.getByText("Welcome to Roo Code!")).toBeInTheDocument()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
vi.runOnlyPendingTimers()
|
||||
vi.useRealTimers()
|
||||
it("renders the subtitle", () => {
|
||||
render(<RooTips />)
|
||||
expect(screen.getByText("Roo is a powerful AI Coding assistant for serious work:")).toBeInTheDocument()
|
||||
})
|
||||
|
||||
describe("when cycle is false (default)", () => {
|
||||
beforeEach(() => {
|
||||
render(<RooTips />)
|
||||
it("renders all tip items", () => {
|
||||
render(<RooTips />)
|
||||
|
||||
// Check titles
|
||||
expect(screen.getByText("Model-agnostic")).toBeInTheDocument()
|
||||
expect(screen.getByText("Extensible Role-specific Modes")).toBeInTheDocument()
|
||||
expect(screen.getByText("Highly customizable")).toBeInTheDocument()
|
||||
expect(screen.getByText("Produce from anywhere")).toBeInTheDocument()
|
||||
|
||||
// Check descriptions
|
||||
expect(screen.getByText("Bring your own key, no markup or lock-in")).toBeInTheDocument()
|
||||
expect(
|
||||
screen.getByText("Focus the LLM of activities like planning, coding, merging conflicts and more"),
|
||||
).toBeInTheDocument()
|
||||
expect(screen.getByText("Tweak the details that matter to make it work for you")).toBeInTheDocument()
|
||||
expect(
|
||||
screen.getByText("Follow and control Roo from any device with Roo Code Cloud (optional)"),
|
||||
).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("renders all icons", () => {
|
||||
render(<RooTips />)
|
||||
|
||||
expect(screen.getByTestId("replace-all-icon")).toBeInTheDocument()
|
||||
expect(screen.getByTestId("chef-hat-icon")).toBeInTheDocument()
|
||||
expect(screen.getByTestId("keyboard-icon")).toBeInTheDocument()
|
||||
expect(screen.getByTestId("wifi-icon")).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("renders the docs link text", () => {
|
||||
render(<RooTips />)
|
||||
expect(screen.getByText("Learn more in the Docs")).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("applies correct CSS classes to list items", () => {
|
||||
const { container } = render(<RooTips />)
|
||||
const listItems = container.querySelectorAll("li")
|
||||
|
||||
expect(listItems).toHaveLength(4)
|
||||
listItems.forEach((item) => {
|
||||
expect(item).toHaveClass("flex", "items-start", "gap-2")
|
||||
})
|
||||
})
|
||||
|
||||
test("renders only the top two tips", () => {
|
||||
// Ensure only two tips are present plus the docs link in the Trans component (3 total links)
|
||||
expect(screen.getAllByRole("link")).toHaveLength(3)
|
||||
it("applies correct CSS classes to icons", () => {
|
||||
render(<RooTips />)
|
||||
|
||||
const icons = [
|
||||
screen.getByTestId("replace-all-icon"),
|
||||
screen.getByTestId("chef-hat-icon"),
|
||||
screen.getByTestId("keyboard-icon"),
|
||||
screen.getByTestId("wifi-icon"),
|
||||
]
|
||||
|
||||
icons.forEach((icon) => {
|
||||
expect(icon).toHaveClass("size-4", "mt-1", "shrink-0")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@
|
|||
"startRouter": "We recommend using an LLM Router:",
|
||||
"startCustom": "Or you can bring your provider API key:",
|
||||
"telemetry": {
|
||||
"helpImprove": "Help Improve Roo Code",
|
||||
"helpImproveMessage": "Roo Code collects error and usage data to help us fix bugs and improve the extension. This telemetry does not collect code, prompts or personal information. You can turn this off in <settingsLink>settings</settingsLink>."
|
||||
"helpImprove": "Anonymous usage analytics",
|
||||
"helpImproveMessage": "We collect usage and error data to help us fix bugs and improve the product. We don't collect any code, prompts or personal information. Opt out in <settingsLink>settings</settingsLink>."
|
||||
},
|
||||
"importSettings": "Import Settings"
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue