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 { 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
@ -11,32 +13,59 @@ export function ConversationHistorySummary({ summary }: { summary: string }) {
const [expanded, setExpanded] = useState(true);
return (
<div className="border-border overflow-hidden rounded-md border">
<div className="border-b border-blue-300 bg-blue-100/50 p-2 dark:border-blue-800 dark:bg-blue-900/50">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<ToolIconWithTooltip
toolNamePretty="Conversation Summary"
icon={<FileText className="h-4 w-4" />}
/>
<span className="text-xs font-medium">Conversation Summary</span>
</div>
<button
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"
>
{expanded ? (
<ChevronDown className="h-3 w-3" />
) : (
<ChevronRight className="h-3 w-3" />
)}
{expanded ? "Collapse" : "Expand"}
</button>
<div
className={cn(
"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",
"shadow-sm hover:shadow-md",
)}
>
{/* Header */}
<div
className={cn(
"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",
"rounded-xl",
)}
>
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-blue-500 shadow-md dark:bg-blue-600">
<FileText className="h-4 w-4 text-white" />
</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>
{/* Content */}
{expanded && (
<div className="p-3">
<div className="p-4">
<div className="text-sm">
<MarkdownText>{summary}</MarkdownText>
</div>

View file

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