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

Commit c8452c4

Browse files
authored
fix(channels): preview artifacts from the activity pane
Generated-By: PostHog Code Task-Id: 1b29f8c0-d916-449a-bf69-50dbf5f32bf1
1 parent eb46283 commit c8452c4

3 files changed

Lines changed: 23 additions & 40 deletions

File tree

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

Lines changed: 10 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: {},
@@ -112,7 +109,7 @@ describe("TaskArtifactsList", () => {
112109
expect(container.querySelector("img")?.getAttribute("src")).toContain(icon);
113110
});
114111

115-
it("presigns the artifact of the run that produced it", () => {
112+
it("opens the artifact of the run that produced it beside the chat", () => {
116113
mocks.runs = [
117114
run("run-1", { artifacts: [outputFile({ id: "a", name: "old.md" })] }),
118115
run("run-2", {
@@ -129,11 +126,11 @@ describe("TaskArtifactsList", () => {
129126
render(<TaskArtifactsList task={task} timeline={[]} />);
130127
fireEvent.click(screen.getByText("new.md"));
131128

132-
expect(mocks.presignTaskRunArtifact).toHaveBeenCalledWith(
133-
"task-1",
134-
"run-2",
135-
"runs/2/new.md",
136-
);
129+
expect(mocks.openArtifactTab).toHaveBeenCalledWith("task-1", {
130+
runId: "run-2",
131+
artifactId: "b",
132+
name: "new.md",
133+
});
137134
});
138135

139136
// 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
) : (

packages/ui/src/features/sidebar/components/SidebarNavSection.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import {
33
ANALYTICS_EVENTS,
44
type SidebarNavItem,
55
} from "@posthog/shared/analytics-events";
6-
import { useChannelsLayout } from "@posthog/ui/features/canvas/hooks/useChannelsLayout";
76
import { useCommandCenterActiveCount } from "@posthog/ui/features/command-center/useCommandCenterActiveCount";
87
import { useFeatureFlag } from "@posthog/ui/features/feature-flags/useFeatureFlag";
98
import { useInboxAllReports } from "@posthog/ui/features/inbox/hooks/useInboxAllReports";
@@ -77,7 +76,6 @@ export function SidebarNavSection({
7776
// The new channels layout subsumes the alpha: while its flag is on, the
7877
// "Enable channels" toggle is meaningless, so its row is hidden.
7978
const channelsLayout = useChannelsLayout();
80-
8179
// When this section renders inside the Channels space, the destinations that
8280
// have a /website mirror stay in that space; everything else (and the whole
8381
// section in the Code space) uses the canonical routes. Inbox and New task
@@ -146,8 +144,6 @@ export function SidebarNavSection({
146144
const navItemAvailable: Record<CustomizableNavItemId, boolean> = {
147145
inbox: true,
148146
"command-center": true,
149-
// Hidden while the new layout is on — the opt-in toggle would be a no-op.
150-
contexts: bluebirdEnabled && !channelsLayout,
151147
// Activity (the mentions feed) is a channels surface, so it only appears
152148
// once channels are enabled.
153149
activity: channelsEnabled,

0 commit comments

Comments
 (0)