From be3b439621ff6cca3f55bb959b69da1c0bdf26e5 Mon Sep 17 00:00:00 2001 From: saravanakumardb1 Date: Tue, 10 Mar 2026 12:50:32 -0700 Subject: [PATCH] feat(web): back artifact viewing with blob sas --- web/src/components/ArtifactPanel.tsx | 38 ++++++++++++++++++++++++++-- web/src/lib/blob-client.ts | 18 +++++++++++++ web/src/lib/notes-client.ts | 6 +++++ web/src/lib/types.ts | 3 +++ 4 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 web/src/lib/blob-client.ts diff --git a/web/src/components/ArtifactPanel.tsx b/web/src/components/ArtifactPanel.tsx index 3294658..d6ec891 100644 --- a/web/src/components/ArtifactPanel.tsx +++ b/web/src/components/ArtifactPanel.tsx @@ -1,11 +1,31 @@ +"use client"; + +import { useState } from "react"; +import { getArtifactReadUrl } from "@/lib/blob-client"; import type { ArtifactSummary } from "@/lib/types"; export function ArtifactPanel({ artifacts }: { artifacts: ArtifactSummary[] }) { + const [openingId, setOpeningId] = useState(null); + + async function handleOpenArtifact(artifact: ArtifactSummary) { + if (!artifact.blobPath) { + return; + } + + try { + setOpeningId(artifact.id); + const url = await getArtifactReadUrl(artifact.blobPath); + window.open(url, "_blank", "noopener,noreferrer"); + } finally { + setOpeningId(null); + } + } + return (
Artifacts
- upload deferred + blob-backed view
{artifacts.map((artifact) => (
@@ -13,7 +33,21 @@ export function ArtifactPanel({ artifacts }: { artifacts: ArtifactSummary[] }) { {artifact.name} {artifact.type}
- {artifact.status} +
+ {artifact.status} + {artifact.blobPath ? ( + + ) : null} +
))}
diff --git a/web/src/lib/blob-client.ts b/web/src/lib/blob-client.ts new file mode 100644 index 0000000..8b5d1bf --- /dev/null +++ b/web/src/lib/blob-client.ts @@ -0,0 +1,18 @@ +"use client"; + +import { platformClient } from "@/lib/platform"; + +type BlobSasResponse = { + sasUrl: string; +}; + +export async function getArtifactReadUrl(blobPath: string): Promise { + const response = await platformClient.post("/blob/sas", { + container: "attachments", + blobName: blobPath, + permissions: "r", + expiresInMinutes: 15, + }); + + return response.sasUrl; +} diff --git a/web/src/lib/notes-client.ts b/web/src/lib/notes-client.ts index fa27656..6b033f7 100644 --- a/web/src/lib/notes-client.ts +++ b/web/src/lib/notes-client.ts @@ -47,6 +47,9 @@ type NoteArtifactDoc = { artifactType: "file" | "summary" | "extraction" | "citation" | "export"; title: string; description?: string; + blobPath?: string; + contentType?: string; + sizeBytes?: number; }; type NoteAgentActionDoc = { @@ -145,6 +148,9 @@ function toArtifactSummary(artifact: NoteArtifactDoc): ArtifactSummary { name: artifact.title, type: artifact.artifactType, status: artifact.description ? "ready" : "processing", + blobPath: artifact.blobPath, + contentType: artifact.contentType, + sizeBytes: artifact.sizeBytes, }; } diff --git a/web/src/lib/types.ts b/web/src/lib/types.ts index 741f40a..3a0bb6a 100644 --- a/web/src/lib/types.ts +++ b/web/src/lib/types.ts @@ -45,6 +45,9 @@ export interface ArtifactSummary { name: string; type: string; status: "ready" | "processing" | "deferred"; + blobPath?: string; + contentType?: string; + sizeBytes?: number; } export interface NoteSummary {