mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-01-10 07:38:04 -05:00
dx(frontend): make preview deploys work + minor improvements (#11329)
## Changes 🏗️ Make sure we can login on preview deployments generated by Vercel to test Front-end changes. As of now, the Cloudflare CAPTCHA verification fails, we don't need to have it active there. ### Minor improvements <img width="1599" height="755" alt="Screenshot 2025-11-06 at 16 18 10" src="https://github.com/user-attachments/assets/0a3fb1f3-2d4d-49fe-885f-10f141dc0ce4" /> Prevent the following build error: ``` 15:58:01.507 at j (.next/server/app/(no-navbar)/onboarding/reset/page.js:1:5125) 15:58:01.507 at <unknown> (.next/server/chunks/5826.js:2:14221) 15:58:01.507 at b.handleCallbackErrors (.next/server/chunks/5826.js:43:43068) 15:58:01.507 at <unknown> (.next/server/chunks/5826.js:2:14194) { 15:58:01.507 description: "Route /onboarding/reset couldn't be rendered statically because it used `cookies`. See more info here: https://nextjs.org/docs/messages/dynamic-server-error", 15:58:01.507 digest: 'DYNAMIC_SERVER_USAGE' 15:58:01.507 } ``` by making the reset onboarding route a client one. I made a new component, `<LoadingSpinner />`, and that page will show it while onboarding it's being reset. ## Checklist 📋 ### For code changes: - [x] I have clearly listed my changes in the PR description - [x] I have made a test plan - [x] I have tested my changes according to the test plan: - [x] You can login/signup on the app and use it in the preview URL generated by Vercel
This commit is contained in:
@@ -1,7 +0,0 @@
|
||||
import { postV1ResetOnboardingProgress } from "@/app/api/__generated__/endpoints/onboarding/onboarding";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export default async function OnboardingResetPage() {
|
||||
await postV1ResetOnboardingProgress();
|
||||
redirect("/onboarding/1-welcome");
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
"use client";
|
||||
import { postV1ResetOnboardingProgress } from "@/app/api/__generated__/endpoints/onboarding/onboarding";
|
||||
import { LoadingSpinner } from "@/components/atoms/LoadingSpinner/LoadingSpinner";
|
||||
import { useToast } from "@/components/molecules/Toast/use-toast";
|
||||
import { redirect } from "next/navigation";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export default function OnboardingResetPage() {
|
||||
const { toast } = useToast();
|
||||
|
||||
useEffect(() => {
|
||||
postV1ResetOnboardingProgress()
|
||||
.then(() => {
|
||||
toast({
|
||||
title: "Onboarding reset successfully",
|
||||
description: "You can now start the onboarding process again",
|
||||
variant: "success",
|
||||
});
|
||||
|
||||
redirect("/onboarding/1-welcome");
|
||||
})
|
||||
.catch(() => {
|
||||
toast({
|
||||
title: "Failed to reset onboarding",
|
||||
description: "Please try again later",
|
||||
variant: "destructive",
|
||||
});
|
||||
});
|
||||
}, []);
|
||||
|
||||
return <LoadingSpinner cover />;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import BackendAPI from "@/lib/autogpt-server-api";
|
||||
import { getServerSupabase } from "@/lib/supabase/server/getServerSupabase";
|
||||
import { verifyTurnstileToken } from "@/lib/turnstile";
|
||||
import { environment } from "@/services/environment";
|
||||
import { loginFormSchema } from "@/types/auth";
|
||||
import * as Sentry from "@sentry/nextjs";
|
||||
import { NextResponse } from "next/server";
|
||||
@@ -26,7 +27,7 @@ export async function POST(request: Request) {
|
||||
|
||||
// Verify Turnstile token if provided
|
||||
const captchaOk = await verifyTurnstileToken(turnstileToken ?? "", "login");
|
||||
if (!captchaOk) {
|
||||
if (!captchaOk && !environment.isVercelPreview()) {
|
||||
return NextResponse.json(
|
||||
{ error: "CAPTCHA verification failed. Please try again." },
|
||||
{ status: 400 },
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import * as Sentry from "@sentry/nextjs";
|
||||
import { getServerSupabase } from "@/lib/supabase/server/getServerSupabase";
|
||||
import { verifyTurnstileToken } from "@/lib/turnstile";
|
||||
import { environment } from "@/services/environment";
|
||||
import { signupFormSchema } from "@/types/auth";
|
||||
import * as Sentry from "@sentry/nextjs";
|
||||
import { NextResponse } from "next/server";
|
||||
import { shouldShowOnboarding } from "../../helpers";
|
||||
import { isWaitlistError, logWaitlistError } from "../utils";
|
||||
|
||||
@@ -31,7 +32,7 @@ export async function POST(request: Request) {
|
||||
"signup",
|
||||
);
|
||||
|
||||
if (!captchaOk) {
|
||||
if (!captchaOk && !environment.isVercelPreview()) {
|
||||
return NextResponse.json(
|
||||
{ error: "CAPTCHA verification failed. Please try again." },
|
||||
{ status: 400 },
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
import type { Meta, StoryObj } from "@storybook/nextjs";
|
||||
import { LoadingSpinner } from "./LoadingSpinner";
|
||||
|
||||
const meta: Meta<typeof LoadingSpinner> = {
|
||||
title: "Atoms/LoadingSpinner",
|
||||
component: LoadingSpinner,
|
||||
tags: ["autodocs"],
|
||||
parameters: {
|
||||
layout: "centered",
|
||||
docs: {
|
||||
description: {
|
||||
component:
|
||||
"Animated loading indicator using the Phosphor CircleNotch icon. Provide a `size` prop or custom classes to fit different contexts.",
|
||||
},
|
||||
},
|
||||
},
|
||||
argTypes: {
|
||||
size: {
|
||||
control: "select",
|
||||
options: ["small", "medium", "large"],
|
||||
description: "Spinner size preset",
|
||||
},
|
||||
className: {
|
||||
control: "text",
|
||||
description: "Additional CSS classes to customize color or layout",
|
||||
},
|
||||
},
|
||||
args: {
|
||||
size: "medium",
|
||||
className: "text-indigo-500",
|
||||
role: "status",
|
||||
"aria-label": "loading",
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Default: Story = {};
|
||||
|
||||
export const Small: Story = {
|
||||
args: {
|
||||
size: "small",
|
||||
},
|
||||
};
|
||||
|
||||
export const Large: Story = {
|
||||
args: {
|
||||
size: "large",
|
||||
},
|
||||
};
|
||||
|
||||
export const CustomColor: Story = {
|
||||
args: {
|
||||
className: "text-emerald-500",
|
||||
},
|
||||
};
|
||||
|
||||
export const Cover: Story = {
|
||||
args: {
|
||||
cover: true,
|
||||
},
|
||||
};
|
||||
|
||||
export const AllSizes: Story = {
|
||||
render: renderAllSizes,
|
||||
};
|
||||
|
||||
function renderAllSizes() {
|
||||
return (
|
||||
<div className="flex items-center gap-8 text-indigo-500">
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<LoadingSpinner size="small" aria-label="loading-small" />
|
||||
<span className="text-xs capitalize text-zinc-500">Small</span>
|
||||
</div>
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<LoadingSpinner size="medium" aria-label="loading-medium" />
|
||||
<span className="text-xs capitalize text-zinc-500">Medium</span>
|
||||
</div>
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<LoadingSpinner size="large" aria-label="loading-large" />
|
||||
<span className="text-xs capitalize text-zinc-500">Large</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { cn } from "@/lib/utils";
|
||||
import { CircleNotchIcon } from "@phosphor-icons/react/dist/ssr";
|
||||
import React from "react";
|
||||
|
||||
const sizeClassNameMap = {
|
||||
small: "h-4 w-4",
|
||||
medium: "h-6 w-6",
|
||||
large: "h-10 w-10",
|
||||
} as const;
|
||||
|
||||
type SpinnerSize = keyof typeof sizeClassNameMap;
|
||||
|
||||
type LoadingSpinnerProps = {
|
||||
size?: SpinnerSize;
|
||||
className?: string;
|
||||
cover?: boolean;
|
||||
} & React.ComponentPropsWithoutRef<typeof CircleNotchIcon>;
|
||||
|
||||
export function LoadingSpinner(props: LoadingSpinnerProps) {
|
||||
const { size = "medium", className, cover = false, ...restProps } = props;
|
||||
|
||||
const spinner = (
|
||||
<CircleNotchIcon
|
||||
className={cn(
|
||||
"animate-spin text-inherit",
|
||||
sizeClassNameMap[size],
|
||||
className,
|
||||
)}
|
||||
weight="bold"
|
||||
{...restProps}
|
||||
/>
|
||||
);
|
||||
|
||||
if (cover) {
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center">
|
||||
{spinner}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return spinner;
|
||||
}
|
||||
@@ -84,6 +84,10 @@ function isClientSide() {
|
||||
return typeof window !== "undefined";
|
||||
}
|
||||
|
||||
function isVercelPreview() {
|
||||
return process.env.VERCEL_ENV === "preview";
|
||||
}
|
||||
|
||||
function isCAPTCHAEnabled() {
|
||||
return process.env.NEXT_PUBLIC_TURNSTILE === "enabled";
|
||||
}
|
||||
@@ -110,6 +114,7 @@ export const environment = {
|
||||
isDev,
|
||||
isCloud,
|
||||
isLocal,
|
||||
isVercelPreview,
|
||||
isCAPTCHAEnabled,
|
||||
areFeatureFlagsEnabled,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user