Skip to content

Commit 65d220d

Browse files
authored
fix(tasks): refresh active cloud run on task open (#3758)
1 parent 48346e1 commit 65d220d

3 files changed

Lines changed: 72 additions & 8 deletions

File tree

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import type { Task } from "@posthog/shared/domain-types";
2+
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
3+
import { renderHook, waitFor } from "@testing-library/react";
4+
import type { PropsWithChildren } from "react";
5+
import { beforeEach, describe, expect, it, vi } from "vitest";
6+
import { useRefreshedTask } from "./useRefreshedTask";
7+
8+
const mocks = vi.hoisted(() => ({ getTask: vi.fn() }));
9+
10+
vi.mock("@posthog/ui/features/auth/authClientImperative", () => ({
11+
getAuthenticatedClient: vi.fn(async () => ({ getTask: mocks.getTask })),
12+
}));
13+
14+
function task(runId: string, status: "failed" | "in_progress"): Task {
15+
return {
16+
id: "task-123",
17+
title: "Cloud task",
18+
description: "Keep working",
19+
repository: null,
20+
latest_run: {
21+
id: runId,
22+
task: "task-123",
23+
environment: "cloud",
24+
status,
25+
state: {},
26+
},
27+
} as Task;
28+
}
29+
30+
describe("useRefreshedTask", () => {
31+
beforeEach(() => {
32+
mocks.getTask.mockReset();
33+
});
34+
35+
it("replaces a cached failed run with the authoritative resumed run", async () => {
36+
const failedParent = task("run-parent", "failed");
37+
const resumedChild = task("run-child", "in_progress");
38+
mocks.getTask.mockResolvedValue(resumedChild);
39+
const queryClient = new QueryClient({
40+
defaultOptions: { queries: { retry: false } },
41+
});
42+
const wrapper = ({ children }: PropsWithChildren) => (
43+
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
44+
);
45+
46+
const { result } = renderHook(
47+
() => useRefreshedTask("task-123", failedParent),
48+
{ wrapper },
49+
);
50+
51+
expect(result.current.latest_run?.id).toBe("run-parent");
52+
await waitFor(() => {
53+
expect(result.current.latest_run?.id).toBe("run-child");
54+
});
55+
expect(mocks.getTask).toHaveBeenCalledWith("task-123");
56+
});
57+
});
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import type { Task } from "@posthog/shared/domain-types";
2+
import { useQuery } from "@tanstack/react-query";
3+
import { taskDetailQuery } from "../../tasks/queries";
4+
5+
export function useRefreshedTask(taskId: string, initialTask: Task): Task {
6+
const { data } = useQuery({
7+
...taskDetailQuery(taskId),
8+
initialData: initialTask,
9+
refetchOnMount: "always",
10+
});
11+
12+
return data;
13+
}

packages/ui/src/features/task-detail/hooks/useTaskData.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@ import { getTaskRepository } from "@posthog/shared";
77
import type { Task } from "@posthog/shared/domain-types";
88
import { useWorkspaceTRPC } from "@posthog/workspace-client/trpc";
99
import { useQuery } from "@tanstack/react-query";
10-
import { useMemo } from "react";
1110
import { cloneStore } from "../../clone/cloneStore";
12-
import { useTasks } from "../../tasks/useTasks";
1311
import { useWorkspace } from "../../workspace/useWorkspace";
12+
import { useRefreshedTask } from "./useRefreshedTask";
1413

1514
interface UseTaskDataParams {
1615
taskId: string;
@@ -19,12 +18,7 @@ interface UseTaskDataParams {
1918

2019
export function useTaskData({ taskId, initialTask }: UseTaskDataParams) {
2120
const trpcReact = useWorkspaceTRPC();
22-
const { data: tasks = [] } = useTasks();
23-
24-
const task = useMemo(
25-
() => tasks.find((t) => t.id === taskId) || initialTask,
26-
[tasks, taskId, initialTask],
27-
);
21+
const task = useRefreshedTask(taskId, initialTask);
2822

2923
const workspace = useWorkspace(taskId);
3024
const repoPath = workspace?.folderPath ?? null;

0 commit comments

Comments
 (0)