From 4ee2364f4afe5bc7b39d4b0f8a23bb1b9d087879 Mon Sep 17 00:00:00 2001 From: Dotta Date: Mon, 18 May 2026 20:46:24 -0500 Subject: [PATCH] Show friendly preview error + in-flight hint for PAP-scale push (PAP-9798) When the cloud rejects a preview as payload_too_large or bad_request, the wizard previously surfaced the raw error code. Show a code-aware banner directing the user to continue with Push (which uploads in chunks) and add an elapsed-time hint near the spinner, since preview takes ~60s on PAP-scale companies. Co-Authored-By: Claude Opus 4.7 --- ui/src/pages/CloudUpstream.tsx | 46 ++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/ui/src/pages/CloudUpstream.tsx b/ui/src/pages/CloudUpstream.tsx index 278005500e0..0e7dee0aa72 100644 --- a/ui/src/pages/CloudUpstream.tsx +++ b/ui/src/pages/CloudUpstream.tsx @@ -157,7 +157,7 @@ export function CloudUpstream() { setPreview(nextPreview); setActionError(null); }, - onError: (error) => setActionError(error instanceof Error ? error.message : "Failed to preview push."), + onError: (error) => setActionError(previewErrorMessage(error)), }); const runMutation = useMutation({ @@ -267,15 +267,18 @@ export function CloudUpstream() { Schema {connection.target.schemaMajor}. Max chunk {formatBytes(connection.target.maxChunkBytes)}. - +
+ + {previewMutation.isPending ? : null} +
) : (
@@ -404,6 +407,21 @@ export function CloudUpstream() { ); } +function PreviewProgressHint() { + const [elapsed, setElapsed] = useState(0); + useEffect(() => { + const startedAt = Date.now(); + const interval = window.setInterval(() => setElapsed(Math.round((Date.now() - startedAt) / 1000)), 1000); + return () => window.clearInterval(interval); + }, []); + const message = elapsed < 15 + ? "Building manifest..." + : elapsed < 45 + ? `Building manifest... ${elapsed}s. Large companies can take up to a minute.` + : `Still building manifest... ${elapsed}s. PAP-scale companies routinely take ~60s.`; + return
{message}
; +} + function Stepper({ activeStep }: { activeStep: CloudUpstreamStep }) { const activeIndex = STEPS.findIndex((step) => step.key === activeStep); return ( @@ -601,3 +619,11 @@ function formatBytes(value: number) { if (value >= 1024) return `${Math.round(value / 1024)} KiB`; return `${value} B`; } + +function previewErrorMessage(error: unknown): string { + const code = error instanceof Error ? error.message : null; + if (code === "payload_too_large" || code === "bad_request") { + return "Local company is too large to preview as a single request. Click Push to continue (the Push step uploads in chunks), or see the docs for chunked-preview options."; + } + return code ?? "Failed to preview push."; +}