Skip to content
This repository was archived by the owner on Aug 6, 2026. It is now read-only.

Commit 2a1cd89

Browse files
authored
test(channels): pin artifact rows to per-file-type icons
The rows already use the same FileIcon the chat's file list does, so markdown resolves to the markdown icon and HTML to the HTML one. Lock that in — the row it replaced hardcoded a single clipboard glyph, and nothing else would catch a regression back to a generic icon. Generated-By: PostHog Code Task-Id: 8d187d00-0633-4706-8443-f79130b65f9f
1 parent 2215cbb commit 2a1cd89

2 files changed

Lines changed: 38 additions & 36 deletions

File tree

packages/ui/src/features/canvas/components/TaskArtifactsList.test.tsx

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,14 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
44

55
const mocks = vi.hoisted(() => ({
66
runs: [] as TaskRun[],
7-
presignTaskRunArtifact: vi.fn(),
7+
openArtifactTab: vi.fn(),
88
}));
99

1010
vi.mock("@posthog/ui/features/canvas/hooks/useTaskRuns", () => ({
1111
useTaskRuns: () => ({ runs: mocks.runs, isLoading: false }),
1212
}));
13-
vi.mock("@posthog/ui/features/auth/authClient", () => ({
14-
useOptionalAuthenticatedClient: () => ({
15-
presignTaskRunArtifact: mocks.presignTaskRunArtifact,
16-
}),
13+
vi.mock("@posthog/ui/features/panels/panelLayoutStore", () => ({
14+
usePanelLayoutStore: () => mocks.openArtifactTab,
1715
}));
1816
vi.mock("@posthog/ui/features/git-interaction/usePrArtifact", () => ({
1917
usePrArtifact: (url: string) => ({
@@ -66,8 +64,7 @@ function outputFile(
6664
describe("TaskArtifactsList", () => {
6765
beforeEach(() => {
6866
mocks.runs = [run("run-1", { prNumber: 1 }), run("run-2", { prNumber: 2 })];
69-
mocks.presignTaskRunArtifact.mockReset();
70-
mocks.presignTaskRunArtifact.mockResolvedValue("https://signed.example/x");
67+
mocks.openArtifactTab.mockReset();
7168
useReviewNavigationStore.setState({
7269
reviewModes: {},
7370
selectedPrUrls: {},
@@ -97,7 +94,22 @@ describe("TaskArtifactsList", () => {
9794
expect(screen.getByText("File · 17 KB")).toBeTruthy();
9895
});
9996

100-
it("presigns the artifact of the run that produced it", () => {
97+
// The row should read like the chat's file list: markdown looks like
98+
// markdown, HTML looks like HTML.
99+
it.each([
100+
{ name: "notes.md", icon: "markdown" },
101+
{ name: "demo.html", icon: "html" },
102+
])("gives $name an icon for its file type", ({ name, icon }) => {
103+
mocks.runs = [run("run-1", { artifacts: [outputFile({ id: "a", name })] })];
104+
105+
const { container } = render(
106+
<TaskArtifactsList task={task} timeline={[]} />,
107+
);
108+
109+
expect(container.querySelector("img")?.getAttribute("src")).toContain(icon);
110+
});
111+
112+
it("opens the artifact of the run that produced it beside the chat", () => {
101113
mocks.runs = [
102114
run("run-1", { artifacts: [outputFile({ id: "a", name: "old.md" })] }),
103115
run("run-2", {
@@ -114,11 +126,11 @@ describe("TaskArtifactsList", () => {
114126
render(<TaskArtifactsList task={task} timeline={[]} />);
115127
fireEvent.click(screen.getByText("new.md"));
116128

117-
expect(mocks.presignTaskRunArtifact).toHaveBeenCalledWith(
118-
"task-1",
119-
"run-2",
120-
"runs/2/new.md",
121-
);
129+
expect(mocks.openArtifactTab).toHaveBeenCalledWith("task-1", {
130+
runId: "run-2",
131+
artifactId: "b",
132+
name: "new.md",
133+
});
122134
});
123135

124136
// Agents revise a deliverable and upload it again under the same name.

packages/ui/src/features/canvas/components/TaskArtifactsList.tsx

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,14 @@ import type {
2121
TaskRun,
2222
TaskThreadMessage,
2323
} from "@posthog/shared/domain-types";
24-
import { useOptionalAuthenticatedClient } from "@posthog/ui/features/auth/authClient";
2524
import { iconForTemplate } from "@posthog/ui/features/canvas/components/canvasTemplateIcon";
2625
import { useTaskRuns } from "@posthog/ui/features/canvas/hooks/useTaskRuns";
2726
import { useReviewNavigationStore } from "@posthog/ui/features/code-review/reviewNavigationStore";
2827
import { usePrArtifact } from "@posthog/ui/features/git-interaction/usePrArtifact";
28+
import { usePanelLayoutStore } from "@posthog/ui/features/panels/panelLayoutStore";
2929
import { usePrComments } from "@posthog/ui/features/pr-review/usePrComments";
3030
import { usePrReviewThreads } from "@posthog/ui/features/pr-review/usePrReviewThreads";
3131
import { FileIcon } from "@posthog/ui/primitives/FileIcon";
32-
import { toast } from "@posthog/ui/primitives/toast";
3332
import { openExternalUrl } from "@posthog/ui/shell/openExternal";
3433
import { formatFileSize } from "@posthog/ui/utils/formatFileSize";
3534
import { parseHttpsUrl, parseShareLink } from "@posthog/ui/utils/posthogLinks";
@@ -43,8 +42,8 @@ type ArtifactRow =
4342
| {
4443
kind: "file";
4544
key: string;
45+
artifactId: string | null;
4646
name: string;
47-
storagePath: string | null;
4847
runId: string | null;
4948
size: number | undefined;
5049
}
@@ -110,8 +109,8 @@ function buildRows(
110109
rows.push({
111110
kind: "file",
112111
key: `file:${file.id ?? file.storage_path ?? name}`,
112+
artifactId: file.id ?? null,
113113
name,
114-
storagePath: file.storage_path ?? null,
115114
runId,
116115
size: file.size,
117116
});
@@ -238,41 +237,32 @@ function CanvasRow({ name, url }: { name: string; url: string | null }) {
238237
function FileRow({
239238
taskId,
240239
runId,
240+
artifactId,
241241
name,
242-
storagePath,
243242
size,
244243
}: {
245244
taskId: string;
246245
runId: string | null;
246+
artifactId: string | null;
247247
name: string;
248-
storagePath: string | null;
249248
size: number | undefined;
250249
}) {
251-
const client = useOptionalAuthenticatedClient();
252-
const canOpen = !!client && !!runId && !!storagePath;
250+
const openArtifactTab = usePanelLayoutStore((state) => state.openArtifactTab);
251+
const canOpen = !!runId && !!artifactId;
253252
const onOpen = canOpen
254253
? () => {
255-
client
256-
.presignTaskRunArtifact(
257-
taskId,
258-
runId as string,
259-
storagePath as string,
260-
)
261-
.then((url) => openExternalUrl(url))
262-
.catch((error: unknown) => {
263-
toast.error("Couldn't open file", {
264-
description:
265-
error instanceof Error ? error.message : String(error),
266-
});
267-
});
254+
openArtifactTab(taskId, {
255+
runId: runId as string,
256+
artifactId: artifactId as string,
257+
name,
258+
});
268259
}
269260
: undefined;
270261
return (
271262
<ArtifactListRow
272263
icon={<FileIcon filename={name} size={14} />}
273264
title={name}
274265
detail={["File", formatFileSize(size)].filter(Boolean).join(" · ")}
275-
external={canOpen}
276266
onOpen={onOpen}
277267
/>
278268
);
@@ -320,8 +310,8 @@ export function TaskArtifactsList({
320310
key={row.key}
321311
taskId={task.id}
322312
runId={row.runId}
313+
artifactId={row.artifactId}
323314
name={row.name}
324-
storagePath={row.storagePath}
325315
size={row.size}
326316
/>
327317
) : (

0 commit comments

Comments
 (0)