Skip to content

Commit f548ea4

Browse files
committed
fix(webapp): admin-gate trace-export debug events, harden clipboard copy
1 parent a8288b2 commit f548ea4

2 files changed

Lines changed: 18 additions & 7 deletions

File tree

apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,11 +1134,21 @@ function TraceExportMenuItems({ runParam }: { runParam: string }) {
11341134

11351135
const copyForAI = async () => {
11361136
try {
1137-
const response = await fetch(`${downloadPath}?format=markdown`, { credentials: "include" });
1138-
if (!response.ok) {
1139-
throw new Error(`Request failed with ${response.status}`);
1140-
}
1141-
await navigator.clipboard.writeText(await response.text());
1137+
// Hand the clipboard a ClipboardItem backed by a promise so access is
1138+
// reserved synchronously during the click. The fetch can then take as long
1139+
// as a large trace needs without the browser revoking the transient user
1140+
// activation, which a fetch-then-writeText sequence trips (notably Safari
1141+
// and Firefox).
1142+
const text = fetch(`${downloadPath}?format=markdown`, { credentials: "include" }).then(
1143+
async (response) => {
1144+
if (!response.ok) {
1145+
throw new Error(`Request failed with ${response.status}`);
1146+
}
1147+
return new Blob([await response.text()], { type: "text/plain" });
1148+
}
1149+
);
1150+
1151+
await navigator.clipboard.write([new ClipboardItem({ "text/plain": text })]);
11421152
toast.custom((t) => (
11431153
<ToastUI variant="success" message="Copied trace as Markdown" t={t as string} />
11441154
));

apps/webapp/app/routes/resources.runs.$runParam.logs.download.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@ export async function loader({ params, request }: LoaderFunctionArgs) {
2020

2121
const url = new URL(request.url);
2222
// ?format=log|jsonl|markdown (default log). ?showDebug=true includes internal
23-
// engine debug events (off by default, matching the trace view's Debug toggle).
23+
// engine debug events; these stay admin-only (matching the admin-gated Debug
24+
// toggle in the trace view) and are off by default.
2425
const format = getTraceExportFormat(url.searchParams.get("format"));
25-
const showDebug = url.searchParams.get("showDebug") === "true";
26+
const showDebug = url.searchParams.get("showDebug") === "true" && user.admin;
2627
const filename = `${parsedParams.runParam}.${format.extension}`;
2728

2829
const run = await prisma.taskRun.findFirst({

0 commit comments

Comments
 (0)