diff --git a/apps/docs/content/guides/auth/passwords.mdx b/apps/docs/content/guides/auth/passwords.mdx index 892c127e233..25ffbaea936 100644 --- a/apps/docs/content/guides/auth/passwords.mdx +++ b/apps/docs/content/guides/auth/passwords.mdx @@ -142,7 +142,7 @@ The PKCE flow allows for server-side authentication. Unlike the implicit flow, w ##### Step 1: Update signup confirmation email -Update your signup email template to send the token hash. See [Email Templates](/docs/guides/auth/auth-email-templates) for how to configure your email templates. +Update your signup email template to send the token hash. For detailed instructions on how to configure your email templates, including the use of variables like `{{ .SiteURL }}`, `{{ .TokenHash }}`, and `{{ .RedirectTo }}`, please refer to our [Email Templates](/docs/guides/auth/auth-email-templates) guide. Your signup email template should contain the following HTML: @@ -151,7 +151,8 @@ Your signup email template should contain the following HTML:
Follow this link to confirm your user:
@@ -170,18 +171,16 @@ Create a new file at `app/auth/confirm/route.ts` and populate with the following ```ts app/auth/confirm/route.ts import { type EmailOtpType } from '@supabase/supabase-js' -import { cookies } from 'next/headers' -import { NextRequest, NextResponse } from 'next/server' -// The client you created from the Server-Side Auth instructions +import { type NextRequest } from 'next/server' + import { createClient } from '@/utils/supabase/server' +import { redirect } from 'next/navigation' export async function GET(request: NextRequest) { const { searchParams } = new URL(request.url) const token_hash = searchParams.get('token_hash') const type = searchParams.get('type') as EmailOtpType | null const next = searchParams.get('next') ?? '/' - const redirectTo = request.nextUrl.clone() - redirectTo.pathname = next if (token_hash && type) { const supabase = await createClient() @@ -191,13 +190,13 @@ export async function GET(request: NextRequest) { token_hash, }) if (!error) { - return NextResponse.redirect(redirectTo) + // redirect user to specified redirect URL or root of app + redirect(next) } } - // return the user to an error page with some instructions - redirectTo.pathname = '/auth/auth-code-error' - return NextResponse.redirect(redirectTo) + // redirect the user to an error page with some instructions + redirect('/auth/auth-code-error') } ``` @@ -381,11 +380,18 @@ app.get("/auth/confirm", async function (req, res) { To sign up the user, call [signUp()](/docs/reference/javascript/auth-signup) with their email address and password: +You can optionally specify a URL to redirect to after the user clicks the confirmation link. This URL must be configured as a [Redirect URL](/docs/guides/auth/redirect-urls), which you can do in the [dashboard](/dashboard/project/_/auth/url-configuration) for hosted projects, or in the [configuration file](/docs/guides/cli/config#auth.additional_redirect_urls) for self-hosted projects. + +If you don't specify a redirect URL, the user is automatically redirected to your site URL. This defaults to `localhost:3000`, but you can also configure this. + ```js async function signUpNewUser() { const { data, error } = await supabase.auth.signUp({ email: 'example@email.com', password: 'example-password', + options: { + emailRedirectTo: 'https://example.com/welcome', + }, }) } ``` diff --git a/apps/studio/components/interfaces/DiskManagement/DiskManagementForm.tsx b/apps/studio/components/interfaces/DiskManagement/DiskManagementForm.tsx index b9f2d95490f..ab1c663830f 100644 --- a/apps/studio/components/interfaces/DiskManagement/DiskManagementForm.tsx +++ b/apps/studio/components/interfaces/DiskManagement/DiskManagementForm.tsx @@ -4,6 +4,7 @@ import { useQueryClient } from '@tanstack/react-query' import { AnimatePresence, motion } from 'framer-motion' import { ChevronRight } from 'lucide-react' import Link from 'next/link' +import { useRouter } from 'next/router' import { useEffect, useState } from 'react' import { useForm } from 'react-hook-form' import { toast } from 'sonner' @@ -24,8 +25,10 @@ import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-que import { useProjectAddonUpdateMutation } from 'data/subscriptions/project-addon-update-mutation' import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query' import { AddonVariantId } from 'data/subscriptions/types' +import { useResourceWarningsQuery } from 'data/usage/resource-warnings-query' import { useCheckPermissions, usePermissionsLoaded } from 'hooks/misc/useCheckPermissions' import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' +import { useFlag } from 'hooks/ui/useFlag' import { GB, PROJECT_STATUS } from 'lib/constants' import { Button, @@ -56,7 +59,6 @@ import { } from './ui/DiskManagement.constants' import { NoticeBar } from './ui/NoticeBar' import { SpendCapDisabledSection } from './ui/SpendCapDisabledSection' -import { useResourceWarningsQuery } from 'data/usage/resource-warnings-query' export function DiskManagementForm() { const { @@ -67,6 +69,8 @@ export function DiskManagementForm() { const org = useSelectedOrganization() const { ref: projectRef } = useParams() const queryClient = useQueryClient() + const router = useRouter() + const diskAndComputeForm = useFlag('diskAndComputeForm') const { data: resourceWarnings } = useResourceWarningsQuery() const projectResourceWarnings = (resourceWarnings ?? [])?.find( @@ -186,14 +190,6 @@ export function DiskManagementForm() { isFlyArchitecture const disableComputeInputs = isPlanUpgradeRequired - - useEffect(() => { - // Initialize field values properly when data has been loaded, preserving any user changes - if (isSuccess) { - form.reset(defaultValues, {}) - } - }, [isSuccess]) - const isDirty = !!Object.keys(form.formState.dirtyFields).length const isProjectResizing = project?.status === PROJECT_STATUS.RESIZING const isProjectRequestingDiskChanges = isRequestingChanges && !isProjectResizing @@ -262,6 +258,20 @@ export function DiskManagementForm() { } } + useEffect(() => { + // Initialize field values properly when data has been loaded, preserving any user changes + if (isSuccess) { + form.reset(defaultValues, {}) + } + }, [isSuccess]) + + // Redirect logic incase disk and compute feature is not live yet + useEffect(() => { + if (diskAndComputeForm !== undefined && !diskAndComputeForm && projectRef) { + router.push(`/project/${projectRef}/settings/addons?panel=computeInstance`) + } + }, [diskAndComputeForm, projectRef, router]) + return (