diff --git a/desktop/src/features/messages/lib/parseDiff.ts b/desktop/src/features/messages/lib/parseDiff.ts index a44dc62ec7..c797dc8904 100644 --- a/desktop/src/features/messages/lib/parseDiff.ts +++ b/desktop/src/features/messages/lib/parseDiff.ts @@ -33,15 +33,59 @@ export function parseUnifiedDiff(content: string): ParsedDiffResult { } } +export const DIFF_TYPE_LABELS: Record = { + add: "New file", + copy: "Copied", + delete: "Deleted", + modify: "Modified", + rename: "Renamed", +}; + export function getDiffFileLabel( file: FileData, fallbackFilePath?: string, ): string { - if (file.oldPath && file.newPath && file.oldPath !== file.newPath) { - return `${file.oldPath} -> ${file.newPath}`; + const oldPath = file.oldPath === "/dev/null" ? undefined : file.oldPath; + const newPath = file.newPath === "/dev/null" ? undefined : file.newPath; + + if (oldPath && newPath && oldPath !== newPath) { + return `${oldPath} -> ${newPath}`; + } + + return newPath || oldPath || fallbackFilePath || "diff"; +} + +export function shouldShowDiffFileHeader( + label: string, + fileCount: number, + fallbackFilePath?: string, +): boolean { + return fileCount > 1 || !fallbackFilePath || label !== fallbackFilePath; +} + +/** + * Badge for the diff card's title bar. Set only when the diff is a single + * file whose per-file header is collapsed (its label just repeats the card + * title) and whose change type is notable — so "New file"/"Deleted" isn't + * lost with the header. + */ +export function getDiffTitleBadge( + content: string, + fallbackFilePath?: string, +): string | undefined { + const { files } = parseUnifiedDiff(content); + if (files.length !== 1) { + return undefined; + } + + const file = files[0]; + const label = getDiffFileLabel(file, fallbackFilePath); + if (shouldShowDiffFileHeader(label, files.length, fallbackFilePath)) { + return undefined; } - return file.newPath || file.oldPath || fallbackFilePath || "diff"; + const diffType = normalizeDiffType(file.type); + return diffType === "modify" ? undefined : DIFF_TYPE_LABELS[diffType]; } export function countDiffFileChanges(file: FileData) { diff --git a/desktop/src/features/messages/ui/DiffMessage.tsx b/desktop/src/features/messages/ui/DiffMessage.tsx index 9013ae5d69..71a3460ce8 100644 --- a/desktop/src/features/messages/ui/DiffMessage.tsx +++ b/desktop/src/features/messages/ui/DiffMessage.tsx @@ -1,6 +1,7 @@ import * as React from "react"; import { FileDiff, Maximize2 } from "lucide-react"; +import { getDiffTitleBadge } from "@/features/messages/lib/parseDiff"; import { isSafeUrl } from "@/shared/lib/url"; import { Button } from "@/shared/ui/button"; import { useSmoothCorners } from "@/shared/ui/smoothCorners"; @@ -39,6 +40,11 @@ export default function DiffMessage({ const safeRepoUrl = isSafeUrl(repoUrl) ? repoUrl : undefined; + const titleBadge = React.useMemo( + () => getDiffTitleBadge(content, filePath), + [content, filePath], + ); + const commitUrl = safeRepoUrl && commitSha ? `${safeRepoUrl}/commit/${commitSha}` : undefined; @@ -51,54 +57,61 @@ export default function DiffMessage({ >
- + {filePath ?? "diff"} - {shortSha && ( - - {commitUrl ? ( + {titleBadge && ( + + {titleBadge} + + )} +
+ {shortSha && ( + + {commitUrl ? ( + + {shortSha} + + ) : ( + shortSha + )} + + )} + {safeRepoUrl && !commitUrl && ( + - {shortSha} + {getHostname(safeRepoUrl)} - ) : ( - shortSha - )} - - )} - {safeRepoUrl && !commitUrl && ( - - - {getHostname(safeRepoUrl)} - - - )} - {onExpand && ( - - - - - Expand diff - - )} + + )} + {onExpand && ( + + + + + Expand diff + + )} +
{description && ( diff --git a/desktop/src/features/messages/ui/DiffMessageExpanded.tsx b/desktop/src/features/messages/ui/DiffMessageExpanded.tsx index 15ce1703e4..5c533bb4e5 100644 --- a/desktop/src/features/messages/ui/DiffMessageExpanded.tsx +++ b/desktop/src/features/messages/ui/DiffMessageExpanded.tsx @@ -1,6 +1,7 @@ import { Rows3, SplitSquareVertical } from "lucide-react"; -import { useState } from "react"; +import { useMemo, useState } from "react"; +import { getDiffTitleBadge } from "@/features/messages/lib/parseDiff"; import { DiffViewer } from "@/features/messages/ui/DiffViewer"; import { Button } from "@/shared/ui/button"; import { @@ -23,6 +24,11 @@ export default function DiffMessageExpanded({ }: DiffMessageExpandedProps) { const [viewType, setViewType] = useState<"split" | "unified">("unified"); + const titleBadge = useMemo( + () => getDiffTitleBadge(content, filePath), + [content, filePath], + ); + return ( { @@ -33,10 +39,15 @@ export default function DiffMessageExpanded({
- + {filePath ?? "Diff Viewer"} -
+ {titleBadge && ( + + {titleBadge} + + )} +