mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-27 11:20:42 +01:00
fix: keep cache listing errors separate from save status
This commit is contained in:
1 parent
ebe1fc8b65
commit
f50fa19eed
2 files changed
+19
-4
No files matched your search
@@ -10,13 +10,16 @@ vi.mock("@/context/CompanyContext", () => ({ useCompany: () => ({ selectedCompan
|
||||
|
||||
const owner = { companyId: "company", scope: "task" as const, ownerId: "task" };
|
||||
const key = ["work-folders", owner.companyId, owner.scope, owner.ownerId];
|
||||
function render(statuses: WorkFolderSyncStatus[], lastOperationAt: string | null, readOnly = false, queryState?: "loading" | "error") {
|
||||
function render(statuses: WorkFolderSyncStatus[], lastOperationAt: string | null, readOnly = false, queryState?: "loading" | "error", filesState?: "loading" | "error") {
|
||||
const client = new QueryClient({ defaultOptions: { queries: { retry: false, staleTime: Infinity } } });
|
||||
client.setQueryData([...key, "files", false], { files: [], lastOperationAt });
|
||||
client.setQueryData([...key, "sync"], statuses);
|
||||
if (queryState === "loading") client.removeQueries({ queryKey: [...key, "sync"] });
|
||||
if (queryState === "error") client.getQueryCache().find({ queryKey: [...key, "sync"] })!
|
||||
.setState({ status: "error", error: new Error("Save service unavailable") });
|
||||
if (filesState === "loading") client.removeQueries({ queryKey: [...key, "files", false] });
|
||||
if (filesState === "error") client.getQueryCache().find({ queryKey: [...key, "files", false] })!
|
||||
.setState({ status: "error", error: new Error("File listing unavailable") });
|
||||
return renderToStaticMarkup(<MemoryRouter initialEntries={["/STG/issues/task"]}><QueryClientProvider client={client}><TooltipProvider><WorkFolderBrowser owner={owner} readOnly={readOnly} /></TooltipProvider></QueryClientProvider></MemoryRouter>);
|
||||
}
|
||||
const checkpoint: WorkFolderSyncStatus = { runId: "run", state: "saved", active: false,
|
||||
@@ -36,6 +39,18 @@ describe("work folder save feedback", () => {
|
||||
expect(unavailable).toContain("Last agent save");
|
||||
expect(unavailable).toContain("Save service unavailable");
|
||||
});
|
||||
it.each(["loading", "error"] as const)("preserves known save status while file listing is %s", (filesState) => {
|
||||
for (const [state, expected] of [["saved", "Saved"], ["saving", "Saving…"], ["failed", "Run save failed"]] as const) {
|
||||
const html = render([{ ...checkpoint, state }], null, true, undefined, filesState);
|
||||
expect(html).toContain(`role="status">${expected}`);
|
||||
expect(html).toContain("Last agent save");
|
||||
if (filesState === "error") {
|
||||
expect(html).toContain("File listing unavailable");
|
||||
expect(html).toContain("File list unavailable");
|
||||
expect(html).not.toContain("No files yet");
|
||||
}
|
||||
}
|
||||
});
|
||||
it("keeps inspection free of controls that mutate the cache or refresh the sandbox", () => {
|
||||
const html = render([checkpoint], null, true);
|
||||
for (const action of ["Upload", "Create folder", "Refresh sandbox", "Delete", "Restore", "Purge"]) expect(html).not.toContain(action);
|
||||
|
||||
@@ -77,8 +77,8 @@ export function WorkFolderBrowser({ owner, exampleFiles, readOnly = false, fillH
|
||||
const lastOperation = filesQuery.data?.lastOperationAt;
|
||||
const saveLabel = mutation.isPending ? "Saving…"
|
||||
: mutation.isError ? "Save failed"
|
||||
: syncQuery.isError || filesQuery.isError ? "Save status unavailable"
|
||||
: !exampleFiles && (syncQuery.isPending || filesQuery.isPending) ? "Loading save status…"
|
||||
: syncQuery.isError ? "Save status unavailable"
|
||||
: !exampleFiles && syncQuery.isPending ? "Loading save status…"
|
||||
: saving ? "Saving…"
|
||||
: failures.length > 0 ? "Run save failed"
|
||||
: !lastSaved && statuses.some((status) => status.active) ? "Waiting for first save"
|
||||
@@ -138,7 +138,7 @@ export function WorkFolderBrowser({ owner, exampleFiles, readOnly = false, fillH
|
||||
return next;
|
||||
});
|
||||
}}
|
||||
onSelectFile={setSelectedPath} loading={!exampleFiles && filesQuery.isLoading} empty={{ title: "No files yet", description: readOnly ? "No cached files have been saved for this scope." : "Upload files here, or create them during a sandbox run." }} ariaLabel={`${owner.scope} files`} /></div>
|
||||
onSelectFile={setSelectedPath} loading={!exampleFiles && filesQuery.isLoading} empty={filesQuery.isError ? { title: "File list unavailable", description: "The saved contents could not be listed." } : { title: "No files yet", description: readOnly ? "No cached files have been saved for this scope." : "Upload files here, or create them during a sandbox run." }} ariaLabel={`${owner.scope} files`} /></div>
|
||||
<div className="flex min-h-0 flex-col gap-2 md:col-span-2">
|
||||
{selected && <div className="flex items-center gap-2"><span className="min-w-0 flex-1 truncate text-sm">{selected.path}</span>
|
||||
{selected.kind === "file" && !exampleFiles && <Button asChild size="sm" variant="outline"><a href={workFoldersApi.downloadUrl(owner, selected.path)} download><Download aria-hidden />Download</a></Button>}
|
||||
|
||||
Reference in new issue
Block a user