Files
fusion/packages/dashboard/app/hooks/useChangedFiles.ts
gsxdsm e9fddc44cb fix: use merge-base for diffStat in merger and show files changed on done task cards
The merger was using `git diff HEAD..branch --stat` which includes
artifacts from other tasks when branches fork from older main commits.
Switch to `git diff $(merge-base)..branch --stat` so commit messages
only describe the branch's own changes.

Also surface the "files changed" button on done task cards using
mergeDetails, opening the same ChangedFilesModal with commit-backed
diffs (matching the Changes tab in the task modal).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 08:33:53 -07:00

99 lines
2.9 KiB
TypeScript

import { useEffect, useState, useCallback } from "react";
import { fetchTaskFileDiffs, fetchCommitDiff, type TaskFileDiff } from "../api";
import { parsePatch } from "../components/CommitDiffTab";
const ACTIVE_COLUMNS = new Set(["in-progress", "in-review"]);
interface UseChangedFilesResult {
files: TaskFileDiff[];
loading: boolean;
error: string | null;
selectedFile: TaskFileDiff | null;
setSelectedFile: (file: TaskFileDiff) => void;
resetSelection: () => void;
}
export function useChangedFiles(
taskId: string,
worktree: string | undefined,
column: string,
projectId?: string,
commitSha?: string,
): UseChangedFilesResult {
const [files, setFiles] = useState<TaskFileDiff[]>([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [selectedFile, setSelectedFile] = useState<TaskFileDiff | null>(null);
const isDone = column === "done";
useEffect(() => {
// For active tasks: need worktree
// For done tasks: need commitSha
if (!taskId || (!isDone && (!worktree || !ACTIVE_COLUMNS.has(column))) || (isDone && !commitSha)) {
setFiles([]);
setLoading(false);
setError(null);
setSelectedFile(null);
return;
}
let cancelled = false;
async function load() {
setLoading(true);
setError(null);
try {
let result: TaskFileDiff[];
if (isDone && commitSha) {
// Done task: fetch from commit history
const data = await fetchCommitDiff(commitSha);
const parsed = parsePatch(data.patch || "");
result = parsed.map((f) => ({
path: f.path,
status: f.status === "unknown" ? "modified" as const : f.status,
diff: f.patch,
oldPath: undefined,
}));
} else {
// Active task: fetch from worktree
result = await fetchTaskFileDiffs(taskId, projectId);
}
if (cancelled) return;
setFiles(result);
setSelectedFile((current) => {
if (result.length === 0) return null;
if (current) {
const match = result.find(
(file) => file.path === current.path && file.oldPath === current.oldPath,
);
if (match) return match;
}
return null;
});
} catch (err) {
if (cancelled) return;
setFiles([]);
setSelectedFile(null);
setError(err instanceof Error ? err.message : "Failed to load changed files");
} finally {
if (!cancelled) {
setLoading(false);
}
}
}
void load();
return () => {
cancelled = true;
};
}, [taskId, worktree, column, projectId, commitSha, isDone]);
const resetSelection = useCallback(() => {
setSelectedFile(null);
}, []);
return { files, loading, error, selectedFile, setSelectedFile, resetSelection };
}