diff --git a/desktop/src/features/messages/lib/parseDiff.ts b/desktop/src/features/messages/lib/parseDiff.ts index b65c1e63c..c797dc890 100644 --- a/desktop/src/features/messages/lib/parseDiff.ts +++ b/desktop/src/features/messages/lib/parseDiff.ts @@ -33,6 +33,14 @@ 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, @@ -47,6 +55,39 @@ export function getDiffFileLabel( 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; + } + + const diffType = normalizeDiffType(file.type); + return diffType === "modify" ? undefined : DIFF_TYPE_LABELS[diffType]; +} + export function countDiffFileChanges(file: FileData) { let additions = 0; let deletions = 0; diff --git a/desktop/src/features/messages/ui/DiffMessage.tsx b/desktop/src/features/messages/ui/DiffMessage.tsx index 9013ae5d6..444f2d1fa 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; @@ -54,6 +60,11 @@ export default function DiffMessage({ {filePath ?? "diff"} + {titleBadge && ( + + {titleBadge} + + )} {shortSha && ( {commitUrl ? ( diff --git a/desktop/src/features/messages/ui/DiffMessageExpanded.tsx b/desktop/src/features/messages/ui/DiffMessageExpanded.tsx index 15ce1703e..eb30447f7 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 ( { @@ -36,6 +42,11 @@ export default function DiffMessageExpanded({ {filePath ?? "Diff Viewer"} + {titleBadge && ( + + {titleBadge} + + )}