fix: stop passing stale task_id from the frontend (#86)

* use selected_attempt.task_id rather than task_id

(cherry picked from commit ff31951daa8b52394607ab2aa5fa04ffdc8d32e1)

* use selected.task_id when calling get_task_attempt_diff

* format

* add diffLoading to dependencies in callback

* adding diffLoading to dependencies caused an infinite loop; implemented Claude Code suggested alternative
This commit is contained in:
Gabriel Gordon-Hall
2025-07-08 09:26:08 +01:00
committed by GitHub
parent 354c6c05ac
commit e3e6c93da0
3 changed files with 41 additions and 23 deletions

View File

@@ -119,19 +119,28 @@ export function TaskDetailsPanel({
handleSendFollowUp, handleSendFollowUp,
} = useTaskDetails(task, projectId, isOpen); } = useTaskDetails(task, projectId, isOpen);
// Use ref to track loading state to prevent dependency cycles
const diffLoadingRef = useRef(false);
// Fetch diff when attempt changes // Fetch diff when attempt changes
const fetchDiff = useCallback(async () => { const fetchDiff = useCallback(async () => {
if (!projectId || !task?.id || !selectedAttempt?.id) { if (!projectId || !selectedAttempt?.id || !selectedAttempt?.task_id) {
setDiff(null); setDiff(null);
setDiffLoading(false); setDiffLoading(false);
return; return;
} }
// Prevent multiple concurrent requests
if (diffLoadingRef.current) {
return;
}
try { try {
diffLoadingRef.current = true;
setDiffLoading(true); setDiffLoading(true);
setDiffError(null); setDiffError(null);
const response = await makeRequest( const response = await makeRequest(
`/api/projects/${projectId}/tasks/${task.id}/attempts/${selectedAttempt.id}/diff` `/api/projects/${projectId}/tasks/${selectedAttempt.task_id}/attempts/${selectedAttempt.id}/diff`
); );
if (response.ok) { if (response.ok) {
@@ -147,9 +156,10 @@ export function TaskDetailsPanel({
} catch (err) { } catch (err) {
setDiffError('Failed to load diff'); setDiffError('Failed to load diff');
} finally { } finally {
diffLoadingRef.current = false;
setDiffLoading(false); setDiffLoading(false);
} }
}, [projectId, task?.id, selectedAttempt?.id]); }, [projectId, selectedAttempt?.id, selectedAttempt?.task_id]);
useEffect(() => { useEffect(() => {
if (isOpen) { if (isOpen) {
@@ -463,7 +473,7 @@ export function TaskDetailsPanel({
try { try {
setDeletingFiles((prev) => new Set(prev).add(fileToDelete)); setDeletingFiles((prev) => new Set(prev).add(fileToDelete));
const response = await makeRequest( const response = await makeRequest(
`/api/projects/${projectId}/tasks/${task.id}/attempts/${selectedAttempt.id}/delete-file?file_path=${encodeURIComponent( `/api/projects/${projectId}/tasks/${selectedAttempt.task_id}/attempts/${selectedAttempt.id}/delete-file?file_path=${encodeURIComponent(
fileToDelete fileToDelete
)}`, )}`,
{ {

View File

@@ -141,12 +141,12 @@ export function TaskDetailsToolbar({
// Branch status fetching // Branch status fetching
const fetchBranchStatus = useCallback(async () => { const fetchBranchStatus = useCallback(async () => {
if (!projectId || !task.id || !selectedAttempt?.id) return; if (!projectId || !selectedAttempt?.id || !selectedAttempt?.task_id) return;
try { try {
setBranchStatusLoading(true); setBranchStatusLoading(true);
const response = await makeRequest( const response = await makeRequest(
`/api/projects/${projectId}/tasks/${task.id}/attempts/${selectedAttempt.id}/branch-status` `/api/projects/${projectId}/tasks/${selectedAttempt.task_id}/attempts/${selectedAttempt.id}/branch-status`
); );
if (response.ok) { if (response.ok) {
@@ -164,7 +164,7 @@ export function TaskDetailsToolbar({
} finally { } finally {
setBranchStatusLoading(false); setBranchStatusLoading(false);
} }
}, [projectId, task.id, selectedAttempt?.id]); }, [projectId, selectedAttempt?.id, selectedAttempt?.task_id]);
// Fetch branch status when selected attempt changes // Fetch branch status when selected attempt changes
useEffect(() => { useEffect(() => {
@@ -175,19 +175,19 @@ export function TaskDetailsToolbar({
// Git operations // Git operations
const handleMergeClick = async () => { const handleMergeClick = async () => {
if (!projectId || !task.id || !selectedAttempt?.id) return; if (!projectId || !selectedAttempt?.id || !selectedAttempt?.task_id) return;
// Directly perform merge without checking branch status // Directly perform merge without checking branch status
await performMerge(); await performMerge();
}; };
const performMerge = async () => { const performMerge = async () => {
if (!projectId || !task.id || !selectedAttempt?.id) return; if (!projectId || !selectedAttempt?.id || !selectedAttempt?.task_id) return;
try { try {
setMerging(true); setMerging(true);
const response = await makeRequest( const response = await makeRequest(
`/api/projects/${projectId}/tasks/${task.id}/attempts/${selectedAttempt.id}/merge`, `/api/projects/${projectId}/tasks/${selectedAttempt.task_id}/attempts/${selectedAttempt.id}/merge`,
{ {
method: 'POST', method: 'POST',
} }
@@ -212,12 +212,12 @@ export function TaskDetailsToolbar({
}; };
const handleRebaseClick = async () => { const handleRebaseClick = async () => {
if (!projectId || !task.id || !selectedAttempt?.id) return; if (!projectId || !selectedAttempt?.id || !selectedAttempt?.task_id) return;
try { try {
setRebasing(true); setRebasing(true);
const response = await makeRequest( const response = await makeRequest(
`/api/projects/${projectId}/tasks/${task.id}/attempts/${selectedAttempt.id}/rebase`, `/api/projects/${projectId}/tasks/${selectedAttempt.task_id}/attempts/${selectedAttempt.id}/rebase`,
{ {
method: 'POST', method: 'POST',
} }
@@ -242,7 +242,7 @@ export function TaskDetailsToolbar({
}; };
const handleCreatePRClick = async () => { const handleCreatePRClick = async () => {
if (!projectId || !task.id || !selectedAttempt?.id) return; if (!projectId || !selectedAttempt?.id || !selectedAttempt?.task_id) return;
// If PR already exists, open it // If PR already exists, open it
if (selectedAttempt.pr_url) { if (selectedAttempt.pr_url) {
@@ -258,12 +258,12 @@ export function TaskDetailsToolbar({
}; };
const handleConfirmCreatePR = async () => { const handleConfirmCreatePR = async () => {
if (!projectId || !task.id || !selectedAttempt?.id) return; if (!projectId || !selectedAttempt?.id || !selectedAttempt?.task_id) return;
try { try {
setCreatingPR(true); setCreatingPR(true);
const response = await makeRequest( const response = await makeRequest(
`/api/projects/${projectId}/tasks/${task.id}/attempts/${selectedAttempt.id}/create-pr`, `/api/projects/${projectId}/tasks/${selectedAttempt.task_id}/attempts/${selectedAttempt.id}/create-pr`,
{ {
method: 'POST', method: 'POST',
headers: { headers: {

View File

@@ -128,13 +128,17 @@ export function useTaskDetails(
async (attemptId: string) => { async (attemptId: string) => {
if (!task) return; if (!task) return;
// Find the attempt to get the task_id
const attempt = taskAttempts.find((a) => a.id === attemptId);
const taskId = attempt?.task_id || task.id;
try { try {
const [activitiesResponse, processesResponse] = await Promise.all([ const [activitiesResponse, processesResponse] = await Promise.all([
makeRequest( makeRequest(
`/api/projects/${projectId}/tasks/${task.id}/attempts/${attemptId}/activities` `/api/projects/${projectId}/tasks/${taskId}/attempts/${attemptId}/activities`
), ),
makeRequest( makeRequest(
`/api/projects/${projectId}/tasks/${task.id}/attempts/${attemptId}/execution-processes` `/api/projects/${projectId}/tasks/${taskId}/attempts/${attemptId}/execution-processes`
), ),
]); ]);
@@ -222,9 +226,13 @@ export function useTaskDetails(
async (attemptId: string) => { async (attemptId: string) => {
if (!task) return; if (!task) return;
// Find the attempt to get the task_id
const attempt = taskAttempts.find((a) => a.id === attemptId);
const taskId = attempt?.task_id || task.id;
try { try {
const response = await makeRequest( const response = await makeRequest(
`/api/projects/${projectId}/tasks/${task.id}/attempts/${attemptId}` `/api/projects/${projectId}/tasks/${taskId}/attempts/${attemptId}`
); );
if (response.ok) { if (response.ok) {
@@ -414,7 +422,7 @@ export function useTaskDetails(
try { try {
setIsStopping(true); setIsStopping(true);
const response = await makeRequest( const response = await makeRequest(
`/api/projects/${projectId}/tasks/${task.id}/attempts/${selectedAttempt.id}/stop`, `/api/projects/${projectId}/tasks/${selectedAttempt.task_id}/attempts/${selectedAttempt.id}/stop`,
{ {
method: 'POST', method: 'POST',
headers: { headers: {
@@ -443,7 +451,7 @@ export function useTaskDetails(
try { try {
const response = await makeRequest( const response = await makeRequest(
`/api/projects/${projectId}/tasks/${task.id}/attempts/${selectedAttempt.id}/start-dev-server`, `/api/projects/${projectId}/tasks/${selectedAttempt.task_id}/attempts/${selectedAttempt.id}/start-dev-server`,
{ {
method: 'POST', method: 'POST',
headers: { headers: {
@@ -477,7 +485,7 @@ export function useTaskDetails(
try { try {
const response = await makeRequest( const response = await makeRequest(
`/api/projects/${projectId}/tasks/${task.id}/attempts/${selectedAttempt.id}/execution-processes/${runningDevServer.id}/stop`, `/api/projects/${projectId}/tasks/${selectedAttempt.task_id}/attempts/${selectedAttempt.id}/execution-processes/${runningDevServer.id}/stop`,
{ {
method: 'POST', method: 'POST',
headers: { headers: {
@@ -503,7 +511,7 @@ export function useTaskDetails(
try { try {
const response = await makeRequest( const response = await makeRequest(
`/api/projects/${projectId}/tasks/${task.id}/attempts/${selectedAttempt.id}/open-editor`, `/api/projects/${projectId}/tasks/${selectedAttempt.task_id}/attempts/${selectedAttempt.id}/open-editor`,
{ {
method: 'POST', method: 'POST',
headers: { headers: {
@@ -529,7 +537,7 @@ export function useTaskDetails(
setIsSendingFollowUp(true); setIsSendingFollowUp(true);
setFollowUpError(null); setFollowUpError(null);
const response = await makeRequest( const response = await makeRequest(
`/api/projects/${projectId}/tasks/${task.id}/attempts/${selectedAttempt.id}/follow-up`, `/api/projects/${projectId}/tasks/${selectedAttempt.task_id}/attempts/${selectedAttempt.id}/follow-up`,
{ {
method: 'POST', method: 'POST',
headers: { headers: {