feat: Update conversation summary and pull request components styling (#607)

* Apply patch [skip ci]

* Apply patch [skip ci]

* Apply patch [skip ci]

* Apply patch [skip ci]

* Empty commit to trigger CI

* cr

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Co-authored-by: bracesproul <braceasproul@gmail.com>
This commit is contained in:
open-swe[bot] 2025-07-30 19:21:35 +00:00 • committed by GitHub
parent 3105a318d2
commit e92de3f300
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 170 additions and 118 deletions

View file

@ -1,7 +1,9 @@
import { FileText, ChevronDown, ChevronRight } from "lucide-react"; import { FileText, ChevronDown, Check } from "lucide-react";
import { useState } from "react"; import { useState } from "react";
import { MarkdownText } from "../thread/markdown-text"; import { MarkdownText } from "../thread/markdown-text";
import { ToolIconWithTooltip } from "./tool-icon-tooltip"; import { cn } from "@/lib/utils";
import { Button } from "../ui/button";
import { Badge } from "../ui/badge";
/** /**
* ConversationHistorySummary component for rendering conversation history summaries * ConversationHistorySummary component for rendering conversation history summaries
@ -11,32 +13,59 @@ export function ConversationHistorySummary({ summary }: { summary: string }) {
const [expanded, setExpanded] = useState(true); const [expanded, setExpanded] = useState(true);
return ( return (
<div className="border-border overflow-hidden rounded-md border"> <div
<div className="border-b border-blue-300 bg-blue-100/50 p-2 dark:border-blue-800 dark:bg-blue-900/50"> className={cn(
<div className="flex items-center justify-between"> "group via-background to-background dark:via-background dark:to-background rounded-xl border bg-gradient-to-br from-blue-50/50 transition-shadow dark:from-blue-950/20",
<div className="flex items-center gap-2"> "shadow-sm hover:shadow-md",
<ToolIconWithTooltip )}
toolNamePretty="Conversation Summary" >
icon={<FileText className="h-4 w-4" />} {/* Header */}
/> <div
<span className="text-xs font-medium">Conversation Summary</span> className={cn(
</div> "relative flex items-center bg-gradient-to-r from-blue-50 to-blue-50/50 p-4 backdrop-blur-sm dark:from-blue-950/30 dark:to-blue-950/10",
<button "rounded-xl",
onClick={() => setExpanded(!expanded)} )}
className="flex items-center gap-1 text-xs font-normal text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300" >
> <div className="flex h-8 w-8 items-center justify-center rounded-full bg-blue-500 shadow-md dark:bg-blue-600">
{expanded ? ( <FileText className="h-4 w-4 text-white" />
<ChevronDown className="h-3 w-3" />
) : (
<ChevronRight className="h-3 w-3" />
)}
{expanded ? "Collapse" : "Expand"}
</button>
</div> </div>
<div className="ml-3 flex-1">
<div className="flex items-center gap-2">
<h3 className="text-foreground text-sm font-semibold">
Conversation Summary
</h3>
<Badge
variant="secondary"
className="border-blue-200 bg-blue-100 text-blue-700 dark:border-blue-800 dark:bg-blue-950 dark:text-blue-300"
>
<Check className="h-3 w-3" />
Complete
</Badge>
</div>
<p className="text-muted-foreground mt-1 text-xs">
Summary of the conversation history
</p>
</div>
<Button
variant="ghost"
size="sm"
onClick={() => setExpanded(!expanded)}
className="h-8 px-2"
>
<ChevronDown
className={cn(
"h-4 w-4 transition-transform duration-200",
!expanded && "-rotate-90",
)}
/>
</Button>
</div> </div>
{/* Content */}
{expanded && ( {expanded && (
<div className="p-3"> <div className="p-4">
<div className="text-sm"> <div className="text-sm">
<MarkdownText>{summary}</MarkdownText> <MarkdownText>{summary}</MarkdownText>
</div> </div>

View file

@ -4,19 +4,15 @@ import { useState } from "react";
import { import {
GitPullRequest, GitPullRequest,
Loader2, Loader2,
CheckCircle,
ChevronDown, ChevronDown,
ChevronUp,
ExternalLink, ExternalLink,
GitPullRequestDraft, GitPullRequestDraft,
Clock,
Check,
} from "lucide-react"; } from "lucide-react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { import { Button } from "../ui/button";
Tooltip, import { Badge } from "../ui/badge";
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "../ui/tooltip";
type PullRequestOpenedProps = { type PullRequestOpenedProps = {
status: "loading" | "generating" | "done"; status: "loading" | "generating" | "done";
@ -41,31 +37,69 @@ export function PullRequestOpened({
}: PullRequestOpenedProps) { }: PullRequestOpenedProps) {
const [expanded, setExpanded] = useState(false); const [expanded, setExpanded] = useState(false);
const getStatusIcon = () => { const getStatusBadge = () => {
switch (status) { switch (status) {
case "loading": case "loading":
return ( return (
<div className="h-3.5 w-3.5 rounded-full border border-gray-300 dark:border-gray-600" /> <Badge
variant="secondary"
className="border-purple-200 bg-purple-100 text-purple-700 dark:border-purple-800 dark:bg-purple-950 dark:text-purple-300"
>
<Clock className="h-3 w-3" />
Preparing
</Badge>
); );
case "generating": case "generating":
return ( return (
<Loader2 className="h-3.5 w-3.5 animate-spin text-gray-500 dark:text-gray-400" /> <Badge
variant="secondary"
className="border-purple-200 bg-purple-100 text-purple-700 dark:border-purple-800 dark:bg-purple-950 dark:text-purple-300"
>
<Loader2 className="h-3 w-3 animate-spin" />
Opening
</Badge>
); );
case "done": case "done":
return <CheckCircle className="h-3.5 w-3.5 text-green-500" />; if (isDraft) {
return (
<Badge
variant="secondary"
className="border-slate-200 bg-slate-100 text-slate-700 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-300"
>
<GitPullRequestDraft className="h-3 w-3" />
Draft
</Badge>
);
}
return (
<Badge
variant="secondary"
className="border-emerald-200 bg-emerald-100 text-emerald-700 dark:border-emerald-800 dark:bg-emerald-950 dark:text-emerald-300"
>
<Check className="h-3 w-3" />
Opened
</Badge>
);
} }
}; };
const getStatusText = () => { const getStatusText = () => {
if (status === "done" && prNumber && !isDraft) {
return `Pull request #${prNumber}`;
}
return isDraft
? `Draft pull request${prNumber ? ` #${prNumber}` : ""}`
: `Pull request${prNumber ? ` #${prNumber}` : ""}`;
};
const getSubtitleText = () => {
switch (status) { switch (status) {
case "loading": case "loading":
return "Preparing pull request..."; return "Preparing to open pull request...";
case "generating": case "generating":
return "Opening pull request..."; return "Opening pull request on GitHub...";
case "done": case "done":
return prNumber return branch ? `${branch} → ${targetBranch}` : "Successfully opened";
? `Pull request #${prNumber} opened`
: "Pull request opened";
} }
}; };
@ -73,98 +107,87 @@ export function PullRequestOpened({
return status === "done" && description; return status === "done" && description;
}; };
const iconClassName = "mr-2 h-3.5 w-3.5";
const getIconWithTooltip = () => {
return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger>
{isDraft && (
<GitPullRequestDraft
className={cn(
iconClassName,
"text-gray-500 dark:text-gray-400",
)}
/>
)}
{!isDraft && (
<GitPullRequest
className={cn(
iconClassName,
"text-green-500 dark:text-green-400",
)}
/>
)}
</TooltipTrigger>
<TooltipContent>
{isDraft ? "Opened draft pull request" : "Opened pull request"}
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
};
return ( return (
<div className="overflow-hidden rounded-md border border-gray-200 dark:border-gray-700"> <div
<div className="flex items-center border-b border-gray-200 bg-gray-50 p-2 dark:border-gray-700 dark:bg-gray-800"> className={cn(
{getIconWithTooltip()} "group via-background to-background dark:via-background dark:to-background rounded-xl border bg-gradient-to-br from-purple-50/50 transition-shadow dark:from-purple-950/20",
<div className="flex-1"> "shadow-sm hover:shadow-md",
{title && status === "done" && ( )}
<div className="mb-0.5 text-xs font-normal text-gray-800 dark:text-gray-200"> >
{title} {/* Header */}
</div> <div
)} className={cn(
{branch && status === "done" && ( "relative flex items-center bg-gradient-to-r from-purple-50 to-purple-50/50 p-4 backdrop-blur-sm dark:from-purple-950/30 dark:to-purple-950/10",
<div className="text-xs font-normal text-gray-500 dark:text-gray-400"> "rounded-xl",
{branch} → {targetBranch} )}
</div> >
)} <div className="flex h-8 w-8 items-center justify-center rounded-full bg-purple-500 shadow-md dark:bg-purple-600">
{!title && ( {isDraft ? (
<span className="text-xs font-normal text-gray-800 dark:text-gray-200"> <GitPullRequestDraft className="h-4 w-4 text-white" />
{getStatusText()} ) : (
</span> <GitPullRequest className="h-4 w-4 text-white" />
)} )}
</div> </div>
<div className="ml-3 flex-1">
<div className="flex items-center gap-2">
<h3 className="text-foreground text-sm font-semibold">
{title || getStatusText()}
</h3>
{getStatusBadge()}
</div>
<p className="text-muted-foreground mt-1 text-xs">
{getSubtitleText()}
</p>
</div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<span className="text-xs font-normal text-gray-500 dark:text-gray-400">
{getStatusText()}
</span>
{getStatusIcon()}
{url && status === "done" && ( {url && status === "done" && (
<a <Button
href={url} variant="ghost"
target="_blank" size="sm"
rel="noopener noreferrer" className="h-8 px-2"
className="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300" asChild
title="Open pull request"
> >
<ExternalLink className="h-3.5 w-3.5" /> <a
</a> href={url}
target="_blank"
rel="noopener noreferrer"
title="Open pull request on GitHub"
>
<ExternalLink className="h-4 w-4" />
</a>
</Button>
)} )}
{shouldShowToggle() && ( {shouldShowToggle() && (
<button <Button
variant="ghost"
size="sm"
onClick={() => setExpanded(!expanded)} onClick={() => setExpanded(!expanded)}
className="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300" className="h-8 px-2"
> >
{expanded ? ( <ChevronDown
<ChevronUp className="h-3.5 w-3.5" /> className={cn(
) : ( "h-4 w-4 transition-transform duration-200",
<ChevronDown className="h-3.5 w-3.5" /> !expanded && "-rotate-90",
)} )}
</button> />
</Button>
)} )}
</div> </div>
</div> </div>
{/* Content */}
{expanded && description && status === "done" && ( {expanded && description && status === "done" && (
<div className="border-t border-gray-200 bg-white p-2 dark:border-gray-700 dark:bg-gray-900"> <div className="border-t p-4">
<h3 className="mb-1 text-xs font-normal text-gray-500 dark:text-gray-400"> <div className="bg-muted/30 rounded-lg p-3">
Description <h4 className="text-muted-foreground mb-2 text-xs font-medium">
</h3> Description
<pre className="text-xs font-normal whitespace-pre-wrap text-gray-800 dark:text-gray-200"> </h4>
{description} <pre className="text-foreground text-sm whitespace-pre-wrap">
</pre> {description}
</pre>
</div>
</div> </div>
)} )}
</div> </div>