Skip to content

Commit f057f43

Browse files
fix(archive): preserve archived task metadata (#3755)
1 parent 88375a2 commit f057f43

19 files changed

Lines changed: 844 additions & 126 deletions

packages/core/src/archive/archiveListView.test.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
deriveUniqueRepos,
77
filterAndSortArchivedTasks,
88
getRepoName,
9+
mergeArchivedWithTasks,
910
withRepoNames,
1011
} from "./archiveListView";
1112

@@ -58,6 +59,63 @@ describe("deriveUniqueRepos", () => {
5859
});
5960
});
6061

62+
describe("mergeArchivedWithTasks", () => {
63+
it("resolves details fetched directly for an archived task", () => {
64+
const archived = makeArchived("older-task", "2024-01-02T00:00:00.000Z");
65+
const task = makeTask("older-task", { title: "Recover me" });
66+
67+
expect(mergeArchivedWithTasks([archived], [task])).toEqual([
68+
{ archived, task },
69+
]);
70+
});
71+
72+
it.each([
73+
{
74+
name: "creation date",
75+
patch: { taskCreatedAt: undefined },
76+
expected: {
77+
title: "Recovered title",
78+
created_at: null,
79+
repository: "posthog/code",
80+
},
81+
},
82+
{
83+
name: "title",
84+
patch: { title: undefined },
85+
expected: {
86+
title: "Unknown task (older-ta)",
87+
created_at: "2024-01-01T00:00:00.000Z",
88+
repository: "posthog/code",
89+
},
90+
},
91+
{
92+
name: "repository",
93+
patch: { repository: undefined },
94+
expected: {
95+
title: "Recovered title",
96+
created_at: "2024-01-01T00:00:00.000Z",
97+
repository: null,
98+
},
99+
},
100+
])(
101+
"preserves other archived metadata when $name is missing",
102+
({ patch, expected }) => {
103+
const archived = {
104+
...makeArchived("older-task", "2024-01-02T00:00:00.000Z"),
105+
title: "Recovered title",
106+
taskCreatedAt: "2024-01-01T00:00:00.000Z",
107+
repository: "posthog/code",
108+
...patch,
109+
};
110+
111+
expect(mergeArchivedWithTasks([archived], [])[0].task).toEqual({
112+
id: "older-task",
113+
...expected,
114+
});
115+
},
116+
);
117+
});
118+
61119
describe("filterAndSortArchivedTasks", () => {
62120
const items: ArchivedTaskWithDetails[] = [
63121
{
@@ -79,6 +137,15 @@ describe("filterAndSortArchivedTasks", () => {
79137
expect(result.map((i) => i.archived.taskId)).toEqual(["b"]);
80138
});
81139

140+
it("filters by task id when the original title is unavailable", () => {
141+
const result = filterAndSortArchivedTasks(withRepoNames(items), {
142+
searchQuery: "b",
143+
repoFilter: null,
144+
sort: { column: "archived", direction: "desc" },
145+
});
146+
expect(result.map((i) => i.archived.taskId)).toEqual(["b"]);
147+
});
148+
82149
it("filters by repo name", () => {
83150
const result = filterAndSortArchivedTasks(withRepoNames(items), {
84151
searchQuery: "",
@@ -88,6 +155,15 @@ describe("filterAndSortArchivedTasks", () => {
88155
expect(result.map((i) => i.archived.taskId)).toEqual(["a"]);
89156
});
90157

158+
it("does not include repository names in the title and task ID search", () => {
159+
const result = filterAndSortArchivedTasks(withRepoNames(items), {
160+
searchQuery: "two",
161+
repoFilter: null,
162+
sort: { column: "archived", direction: "desc" },
163+
});
164+
expect(result).toEqual([]);
165+
});
166+
91167
it("sorts by archivedAt descending", () => {
92168
const result = filterAndSortArchivedTasks(withRepoNames(items), {
93169
searchQuery: "",

packages/core/src/archive/archiveListView.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@ import type { ArchivedTask } from "@posthog/shared";
22
import { formatRelativeTimeLong } from "@posthog/shared";
33
import type { Task } from "@posthog/shared/domain-types";
44

5+
export interface ArchivedTaskDetails
6+
extends Pick<Task, "id" | "title" | "repository"> {
7+
created_at: Task["created_at"] | null;
8+
}
9+
510
export interface ArchivedTaskWithDetails {
611
archived: ArchivedTask;
7-
task: Task | null;
12+
task: ArchivedTaskDetails | null;
813
}
914

1015
export interface ArchivedTaskWithRepo extends ArchivedTaskWithDetails {
@@ -27,16 +32,27 @@ export interface ArchiveFilterSortInput {
2732

2833
export function mergeArchivedWithTasks(
2934
archivedTasks: ArchivedTask[],
30-
tasks: Task[],
35+
tasks: ArchivedTaskDetails[],
3136
): ArchivedTaskWithDetails[] {
3237
const taskMap = new Map(tasks.map((task) => [task.id, task]));
3338
return archivedTasks.map((archived) => ({
3439
archived,
35-
task: taskMap.get(archived.taskId) ?? null,
40+
task:
41+
taskMap.get(archived.taskId) ??
42+
(archived.title || archived.taskCreatedAt || archived.repository
43+
? {
44+
id: archived.taskId,
45+
title:
46+
archived.title ??
47+
`Unknown task (${archived.branchName ?? archived.worktreeName ?? archived.taskId.slice(0, 8)})`,
48+
created_at: archived.taskCreatedAt ?? null,
49+
repository: archived.repository ?? null,
50+
}
51+
: null),
3652
}));
3753
}
3854

39-
export function formatRelativeDate(isoDate: string | undefined): string {
55+
export function formatRelativeDate(isoDate: string | null | undefined): string {
4056
if (!isoDate) return "—";
4157
return formatRelativeTimeLong(isoDate);
4258
}
@@ -81,7 +97,9 @@ export function filterAndSortArchivedTasks(
8197
const query = searchQuery.trim().toLowerCase();
8298
if (query) {
8399
result = result.filter((item) =>
84-
(item.task?.title?.toLowerCase() ?? "").includes(query),
100+
[item.task?.title, item.archived.taskId].some((value) =>
101+
value?.toLowerCase().includes(query),
102+
),
85103
);
86104
}
87105

packages/host-router/src/routers/archive.router.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export const archiveRouter = router({
3232
list: publicProcedure
3333
.output(listArchivedTasksOutput)
3434
.query(({ ctx }) =>
35-
ctx.container.get<ArchiveService>(ARCHIVE_SERVICE).getArchivedTasks(),
35+
ctx.container.get<ArchiveService>(ARCHIVE_SERVICE).listArchivedTasks(),
3636
),
3737

3838
archivedTaskIds: publicProcedure

packages/shared/src/archive-domain.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ export const archivedTaskSchema = z.object({
1212
worktreeName: z.string().nullable(),
1313
branchName: z.string().nullable(),
1414
checkpointId: z.string().nullable(),
15+
title: z.string().nullable().optional(),
16+
taskCreatedAt: z.string().nullable().optional(),
17+
repository: z.string().nullable().optional(),
18+
recoveryPending: z.boolean().optional(),
1519
});
1620

1721
export type ArchivedTask = z.infer<typeof archivedTaskSchema>;

0 commit comments

Comments
 (0)