Skip to content
Merged
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
46 changes: 41 additions & 5 deletions frontend/src/components/message/PatchPart.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { useState } from 'react'
import type { components } from '@/api/opencode-types'
import { getRelativePath } from './FileToolRender'
import { ChevronDown, ChevronUp } from 'lucide-react'

type PatchPartType = components['schemas']['PatchPart']

Expand All @@ -8,18 +10,32 @@ interface PatchPartProps {
onFileClick?: (filePath: string) => void
}

const INITIAL_FILES_SHOWN = 3

export function PatchPart({ part, onFileClick }: PatchPartProps) {
const [expanded, setExpanded] = useState(false)

const hasMoreFiles = part.files.length > INITIAL_FILES_SHOWN
const displayedFiles = expanded ? part.files : part.files.slice(0, INITIAL_FILES_SHOWN)
const hiddenCount = part.files.length - INITIAL_FILES_SHOWN

return (
<div className="border border-border rounded-lg overflow-hidden my-2">
<div className="px-3 py-1.5 bg-card flex items-center justify-between text-sm">
<button
onClick={() => setExpanded(!expanded)}
className="w-full px-3 py-1.5 bg-card hover:bg-card-hover text-left flex items-center justify-between text-sm gap-2"
>
<span className="font-medium">
File Changes ({part.files.length} file{part.files.length !== 1 ? 's' : ''})
</span>
<span className="text-muted-foreground text-xs font-mono">{part.hash.slice(0, 8)}</span>
</div>

<div className="flex items-center gap-2 flex-shrink-0">
<span className="text-muted-foreground text-xs font-mono">{part.hash.slice(0, 8)}</span>
{expanded ? <ChevronUp className="w-4 h-4 text-muted-foreground" /> : <ChevronDown className="w-4 h-4 text-muted-foreground" />}
</div>
</button>

<div className="bg-card px-3 py-2 space-y-1">
{part.files.map((file, index) => (
{displayedFiles.map((file, index) => (
<div
key={index}
className="text-xs font-mono text-blue-600 dark:text-blue-400 hover:underline cursor-pointer"
Expand All @@ -28,6 +44,26 @@ export function PatchPart({ part, onFileClick }: PatchPartProps) {
{getRelativePath(file)}
</div>
))}

{!expanded && hasMoreFiles && (
<button
onClick={() => setExpanded(true)}
className="text-xs text-muted-foreground hover:text-foreground flex items-center gap-1 mt-1"
>
<ChevronDown className="w-3 h-3" />
+{hiddenCount} more file{hiddenCount !== 1 ? 's' : ''}
</button>
)}

{expanded && hasMoreFiles && (
<button
onClick={() => setExpanded(false)}
className="text-xs text-muted-foreground hover:text-foreground flex items-center gap-1 mt-1"
>
<ChevronUp className="w-3 h-3" />
Show less
</button>
)}
</div>
</div>
)
Expand Down