diff --git a/apps/code/src/renderer/features/git-interaction/components/CreatePrDialog.tsx b/apps/code/src/renderer/features/git-interaction/components/CreatePrDialog.tsx index d044f8432..ffc50c117 100644 --- a/apps/code/src/renderer/features/git-interaction/components/CreatePrDialog.tsx +++ b/apps/code/src/renderer/features/git-interaction/components/CreatePrDialog.tsx @@ -4,6 +4,7 @@ import { } from "@features/git-interaction/components/GitInteractionDialogs"; import { useGitInteractionStore } from "@features/git-interaction/state/gitInteractionStore"; import type { CreatePrStep } from "@features/git-interaction/types"; +import type { DiffStats } from "@features/git-interaction/utils/diffStats"; import { CheckCircle, Circle, @@ -113,7 +114,7 @@ export interface CreatePrDialogProps { open: boolean; onOpenChange: (open: boolean) => void; currentBranch: string | null; - diffStats: { filesChanged: number; linesAdded: number; linesRemoved: number }; + diffStats: DiffStats; isSubmitting: boolean; onSubmit: () => void; onGenerateCommitMessage: () => void; diff --git a/apps/code/src/renderer/features/git-interaction/components/GitInteractionDialogs.tsx b/apps/code/src/renderer/features/git-interaction/components/GitInteractionDialogs.tsx index 9240d0501..4dfe7610a 100644 --- a/apps/code/src/renderer/features/git-interaction/components/GitInteractionDialogs.tsx +++ b/apps/code/src/renderer/features/git-interaction/components/GitInteractionDialogs.tsx @@ -1,4 +1,5 @@ import { Tooltip } from "@components/ui/Tooltip"; +import type { DiffStats } from "@features/git-interaction/utils/diffStats"; import { CheckCircle, CloudArrowUp, @@ -243,7 +244,7 @@ interface GitCommitDialogProps { open: boolean; onOpenChange: (open: boolean) => void; branchName: string | null; - diffStats: { filesChanged: number; linesAdded: number; linesRemoved: number }; + diffStats: DiffStats; commitMessage: string; onCommitMessageChange: (value: string) => void; nextStep: "commit" | "commit-push"; diff --git a/apps/code/src/renderer/features/git-interaction/hooks/useGitInteraction.ts b/apps/code/src/renderer/features/git-interaction/hooks/useGitInteraction.ts index fcea68d05..22afba10f 100644 --- a/apps/code/src/renderer/features/git-interaction/hooks/useGitInteraction.ts +++ b/apps/code/src/renderer/features/git-interaction/hooks/useGitInteraction.ts @@ -13,6 +13,7 @@ import { createBranch, getBranchNameInputState, } from "@features/git-interaction/utils/branchCreation"; +import type { DiffStats } from "@features/git-interaction/utils/diffStats"; import { invalidateGitBranchQueries } from "@features/git-interaction/utils/gitCacheKeys"; import { updateGitCacheFromSnapshot } from "@features/git-interaction/utils/updateGitCache"; import { trpc, trpcClient } from "@renderer/trpc"; @@ -38,7 +39,7 @@ interface GitInteractionState { defaultBranch: string | null; prBaseBranch: string | null; prHeadBranch: string | null; - diffStats: { filesChanged: number; linesAdded: number; linesRemoved: number }; + diffStats: DiffStats; prUrl: string | null; pushDisabledReason: string | null; isLoading: boolean; diff --git a/apps/code/src/renderer/features/git-interaction/hooks/useGitQueries.ts b/apps/code/src/renderer/features/git-interaction/hooks/useGitQueries.ts index e0ad14dea..caf61d6e4 100644 --- a/apps/code/src/renderer/features/git-interaction/hooks/useGitQueries.ts +++ b/apps/code/src/renderer/features/git-interaction/hooks/useGitQueries.ts @@ -2,6 +2,7 @@ import { useTRPC } from "@renderer/trpc"; import { useQuery } from "@tanstack/react-query"; const EMPTY_DIFF_STATS = { filesChanged: 0, linesAdded: 0, linesRemoved: 0 }; +const EMPTY_CHANGED_FILES: never[] = []; const GIT_QUERY_DEFAULTS = { staleTime: 30_000, @@ -20,7 +21,10 @@ export function useGitQueries(repoPath?: string) { const repoEnabled = enabled && isRepo; - const { data: changedFiles = [], isLoading: changesLoading } = useQuery( + const { + data: changedFiles = EMPTY_CHANGED_FILES, + isLoading: changesLoading, + } = useQuery( trpc.git.getChangedFilesHead.queryOptions( { directoryPath: repoPath as string }, { diff --git a/apps/code/src/renderer/features/git-interaction/utils/diffStats.ts b/apps/code/src/renderer/features/git-interaction/utils/diffStats.ts new file mode 100644 index 000000000..d8d549715 --- /dev/null +++ b/apps/code/src/renderer/features/git-interaction/utils/diffStats.ts @@ -0,0 +1,17 @@ +import type { ChangedFile } from "@shared/types"; + +export interface DiffStats { + filesChanged: number; + linesAdded: number; + linesRemoved: number; +} + +export function computeDiffStats(files: ChangedFile[]): DiffStats { + let linesAdded = 0; + let linesRemoved = 0; + for (const file of files) { + linesAdded += file.linesAdded ?? 0; + linesRemoved += file.linesRemoved ?? 0; + } + return { filesChanged: files.length, linesAdded, linesRemoved }; +} diff --git a/apps/code/src/renderer/features/git-interaction/utils/gitStatusUtils.ts b/apps/code/src/renderer/features/git-interaction/utils/gitStatusUtils.ts new file mode 100644 index 000000000..b536c00bf --- /dev/null +++ b/apps/code/src/renderer/features/git-interaction/utils/gitStatusUtils.ts @@ -0,0 +1,23 @@ +import type { GitFileStatus } from "@shared/types"; + +export type StatusColor = "green" | "orange" | "red" | "blue" | "gray"; +export interface StatusIndicator { + label: string; + fullLabel: string; + color: StatusColor; +} +export function getStatusIndicator(status: GitFileStatus): StatusIndicator { + switch (status) { + case "added": + case "untracked": + return { label: "A", fullLabel: "Added", color: "green" }; + case "deleted": + return { label: "D", fullLabel: "Deleted", color: "red" }; + case "modified": + return { label: "M", fullLabel: "Modified", color: "orange" }; + case "renamed": + return { label: "R", fullLabel: "Renamed", color: "blue" }; + default: + return { label: "?", fullLabel: "Unknown", color: "gray" }; + } +} diff --git a/apps/code/src/renderer/features/message-editor/components/DiffStatsIndicator.tsx b/apps/code/src/renderer/features/message-editor/components/DiffStatsIndicator.tsx index 230f5822d..580eb6864 100644 --- a/apps/code/src/renderer/features/message-editor/components/DiffStatsIndicator.tsx +++ b/apps/code/src/renderer/features/message-editor/components/DiffStatsIndicator.tsx @@ -1,14 +1,11 @@ +import type { DiffStats } from "@features/git-interaction/utils/diffStats"; import { Flex, Text } from "@radix-ui/themes"; import { useTRPC } from "@renderer/trpc"; import { useQuery } from "@tanstack/react-query"; interface DiffStatsIndicatorProps { repoPath: string | null | undefined; - overrideStats?: { - filesChanged: number; - linesAdded: number; - linesRemoved: number; - } | null; + overrideStats?: DiffStats | null; } export function DiffStatsIndicator({ diff --git a/apps/code/src/renderer/features/task-detail/components/TaskLogsPanel.tsx b/apps/code/src/renderer/features/task-detail/components/TaskLogsPanel.tsx index a6af0726b..90ab786bf 100644 --- a/apps/code/src/renderer/features/task-detail/components/TaskLogsPanel.tsx +++ b/apps/code/src/renderer/features/task-detail/components/TaskLogsPanel.tsx @@ -5,6 +5,7 @@ import { useCloudBranchChangedFiles, useCloudPrChangedFiles, } from "@features/git-interaction/hooks/useGitQueries"; +import { computeDiffStats } from "@features/git-interaction/utils/diffStats"; import { useDraftStore } from "@features/message-editor/stores/draftStore"; import { ProvisioningView } from "@features/provisioning/components/ProvisioningView"; import { useProvisioningStore } from "@features/provisioning/stores/provisioningStore"; @@ -100,11 +101,7 @@ export function TaskLogsPanel({ taskId, task }: TaskLogsPanelProps) { if (!isCloud) return null; const files = prUrl ? prFiles : branchFiles; if (!files || files.length === 0) return null; - return { - filesChanged: files.length, - linesAdded: files.reduce((sum, f) => sum + (f.linesAdded ?? 0), 0), - linesRemoved: files.reduce((sum, f) => sum + (f.linesRemoved ?? 0), 0), - }; + return computeDiffStats(files); }, [isCloud, prUrl, prFiles, branchFiles]); useEffect(() => { diff --git a/apps/code/src/renderer/utils/path.ts b/apps/code/src/renderer/utils/path.ts index 02ec568d5..a2e019886 100644 --- a/apps/code/src/renderer/utils/path.ts +++ b/apps/code/src/renderer/utils/path.ts @@ -35,3 +35,8 @@ export function compactHomePath(text: string): string { .replace(/\/Users\/[^/\s]+/g, "~") .replace(/\/home\/[^/\s]+/g, "~"); } + +export function getFileExtension(filePath: string): string { + const parts = filePath.split("."); + return parts.length > 1 ? parts[parts.length - 1] : ""; +}