diff --git a/ui/src/components/WorkFolderBrowser.test.tsx b/ui/src/components/WorkFolderBrowser.test.tsx index b3cd2f264c..d872086dee 100644 --- a/ui/src/components/WorkFolderBrowser.test.tsx +++ b/ui/src/components/WorkFolderBrowser.test.tsx @@ -53,4 +53,17 @@ describe("work folder save feedback", () => { expect(html).toContain("View failed run"); expect(html).toContain("Last agent save"); }); + it("keeps every failed sandbox accessible alongside saved shared files", () => { + const html = render([checkpoint, ...["newer", "earlier"].map((runId) => ({ + ...checkpoint, runId, agentId: "other-agent", state: "failed" as const, + error: `Retained ${runId} working copy`, + }))], null, true); + expect(html).toContain("2 sandbox runs could not save their files."); + for (const runId of ["newer", "earlier"]) { + expect(html).toContain(`href="/STG/agents/other-agent/runs/${runId}"`); + expect(html).toContain(`Retained ${runId} working copy`); + } + expect(html).toContain("Last agent save"); + }); + }); diff --git a/ui/src/components/WorkFolderBrowser.tsx b/ui/src/components/WorkFolderBrowser.tsx index 9ba569258a..2675a58bd3 100644 --- a/ui/src/components/WorkFolderBrowser.tsx +++ b/ui/src/components/WorkFolderBrowser.tsx @@ -70,7 +70,7 @@ export function WorkFolderBrowser({ owner, exampleFiles, readOnly = false, fillH setAnnouncement(action.type === "refresh" ? "Refresh requested for the next safe run boundary." : "Files saved."); }, onSettled: () => queryClient.invalidateQueries({ queryKey: key }) }); const statuses = syncQuery.data ?? []; - const failed = statuses.find((status) => status.state === "failed"); + const failures = statuses.filter((status) => status.state === "failed"); const saving = mutation.isPending || statuses.some((status) => status.state === "saving"); const lastSaved = statuses.map((status) => status.lastSavedAt) .filter((value): value is string => Boolean(value)).sort().at(-1); @@ -89,7 +89,7 @@ export function WorkFolderBrowser({ owner, exampleFiles, readOnly = false, fillH {!trash && canManageTrash && checkedPaths.length > 0 && } {!readOnly && } - {saving ? "Saving…" : mutation.isError ? "Save failed" : failed ? "Run save failed" : "Saved"} + {saving ? "Saving…" : mutation.isError ? "Save failed" : failures.length > 0 ? "Run save failed" : "Saved"} {lastSaved && Last agent save {new Date(lastSaved).toLocaleTimeString()}} {lastOperation && (!lastSaved || lastOperation > lastSaved) && Files updated {new Date(lastOperation).toLocaleTimeString()}} @@ -98,10 +98,15 @@ export function WorkFolderBrowser({ owner, exampleFiles, readOnly = false, fillH } {[filesQuery.error, syncQuery.error, mutation.error].filter(Boolean).map((error, index) =>
{(error as Error).message}
)} - {failed &&- A sandbox run could not save its files. The files below are saved copies. {failed.error}{" "} - {failed.agentId && View failed run} -
} + {failures.length > 0 &&{failures.length === 1 ? "A sandbox run could not save its files." : `${failures.length} sandbox runs could not save their files.`} The files below are saved copies.
+{announcement}
{trash ?Deleted cached files are retained here. Restore them to return them to Files.
{files.length === 0 ?Trash is empty.
: files.map((file) =>