mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-23 17:33:51 +02:00
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 <noreply@anthropic.com>
This commit is contained in:
1 parent
8e1f9cc431
commit
4ee2364f4a
1 file changed
+36
-10
@@ -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)}.
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => previewMutation.mutate(connection.id)}
|
||||
disabled={previewMutation.isPending || connection.tokenStatus !== "connected"}
|
||||
>
|
||||
{previewMutation.isPending ? <Loader2 className="h-4 w-4 animate-spin" /> : <RefreshCcw className="h-4 w-4" />}
|
||||
Preview push
|
||||
</Button>
|
||||
<div className="flex flex-col items-end gap-1">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => previewMutation.mutate(connection.id)}
|
||||
disabled={previewMutation.isPending || connection.tokenStatus !== "connected"}
|
||||
>
|
||||
{previewMutation.isPending ? <Loader2 className="h-4 w-4 animate-spin" /> : <RefreshCcw className="h-4 w-4" />}
|
||||
Preview push
|
||||
</Button>
|
||||
{previewMutation.isPending ? <PreviewProgressHint /> : null}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid gap-3 md:grid-cols-[1fr_auto]">
|
||||
@@ -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 <div className="text-xs text-muted-foreground">{message}</div>;
|
||||
}
|
||||
|
||||
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.";
|
||||
}
|
||||
Reference in new issue
Block a user