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:
committed by
GitHub
parent
354c6c05ac
commit
e3e6c93da0
@@ -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
|
||||||
)}`,
|
)}`,
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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: {
|
||||||
|
|||||||
@@ -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: {
|
||||||
|
|||||||
Reference in New Issue
Block a user