mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-23 12:31:54 +00:00
chore(ui): improve changes
This commit is contained in:
@@ -2,6 +2,14 @@
|
||||
|
||||
All notable changes to the **Prowler UI** are documented in this file.
|
||||
|
||||
## [1.25.0] (Prowler UNRELEASED)
|
||||
|
||||
### 🚀 Added
|
||||
|
||||
- Sign-in and sign-up redesigned with an animated background and a live release highlights panel from GitHub, with adaptive summaries for patch releases [(#10774)](https://github.com/prowler-cloud/prowler/pull/10774)
|
||||
|
||||
---
|
||||
|
||||
## [1.24.1] (Prowler v5.24.1)
|
||||
|
||||
### 🔒 Security
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./releases";
|
||||
export * from "./types";
|
||||
@@ -0,0 +1,125 @@
|
||||
"use server";
|
||||
|
||||
import { unstable_cache } from "next/cache";
|
||||
import { z } from "zod";
|
||||
|
||||
import type { LatestRelease, ReleaseComponent } from "./types";
|
||||
import { RELEASE_COMPONENTS } from "./types";
|
||||
|
||||
const REPO = "prowler-cloud/prowler";
|
||||
const REPO_URL = `https://github.com/${REPO}`;
|
||||
const RELEASES_ENDPOINT = `https://api.github.com/repos/${REPO}/releases?per_page=10`;
|
||||
const MAX_HIGHLIGHTS = 3;
|
||||
const REVALIDATE_SECONDS = 3600;
|
||||
|
||||
const META_HEADINGS = [
|
||||
/^what'?s changed$/i,
|
||||
/^new contributors$/i,
|
||||
/^full changelog$/i,
|
||||
];
|
||||
|
||||
const releaseSchema = z.object({
|
||||
tag_name: z.string(),
|
||||
html_url: z.url(),
|
||||
body: z.string().nullable(),
|
||||
draft: z.boolean(),
|
||||
prerelease: z.boolean(),
|
||||
});
|
||||
|
||||
const releaseListSchema = z.array(releaseSchema);
|
||||
|
||||
const stripLeadingSymbols = (s: string) =>
|
||||
s.replace(/^[^A-Za-z0-9]+/, "").trim();
|
||||
|
||||
const startsWithNonAscii = (s: string) => {
|
||||
const first = s.trim().charCodeAt(0);
|
||||
return Number.isFinite(first) && first > 127;
|
||||
};
|
||||
|
||||
const stripFencedAndDetails = (body: string) =>
|
||||
body
|
||||
.replace(/```[\s\S]*?```/g, "")
|
||||
.replace(/<details[\s\S]*?<\/details>/gi, "");
|
||||
|
||||
const parseBody = (
|
||||
body: string,
|
||||
): { curated: string[]; components: ReleaseComponent[] } => {
|
||||
const clean = stripFencedAndDetails(body);
|
||||
const headings = Array.from(clean.matchAll(/^##\s+(.+?)\s*$/gm)).map((m) =>
|
||||
m[1].trim(),
|
||||
);
|
||||
|
||||
const curated = headings
|
||||
.filter(startsWithNonAscii)
|
||||
.filter((h) => !META_HEADINGS.some((re) => re.test(stripLeadingSymbols(h))))
|
||||
.slice(0, MAX_HIGHLIGHTS);
|
||||
|
||||
const components: ReleaseComponent[] = RELEASE_COMPONENTS.filter((comp) =>
|
||||
headings.some((h) => h.toUpperCase() === comp),
|
||||
);
|
||||
|
||||
return { curated, components };
|
||||
};
|
||||
|
||||
const buildHeaders = (): HeadersInit => {
|
||||
const headers: Record<string, string> = {
|
||||
Accept: "application/vnd.github+json",
|
||||
"X-GitHub-Api-Version": "2022-11-28",
|
||||
};
|
||||
if (process.env.GITHUB_TOKEN) {
|
||||
headers.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`;
|
||||
}
|
||||
return headers;
|
||||
};
|
||||
|
||||
const fetchLatestReleaseWithHighlights = async (): Promise<LatestRelease> => {
|
||||
const res = await fetch(RELEASES_ENDPOINT, {
|
||||
headers: buildHeaders(),
|
||||
next: { revalidate: REVALIDATE_SECONDS },
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`GitHub releases API responded with ${res.status}`);
|
||||
}
|
||||
|
||||
const json = await res.json();
|
||||
const releases = releaseListSchema.parse(json);
|
||||
|
||||
for (const release of releases) {
|
||||
if (release.draft || release.prerelease || !release.body) continue;
|
||||
const { curated, components } = parseBody(release.body);
|
||||
|
||||
const base = {
|
||||
version: release.tag_name.replace(/^v/, ""),
|
||||
url: release.html_url,
|
||||
repoUrl: REPO_URL,
|
||||
};
|
||||
|
||||
if (curated.length > 0) {
|
||||
return { ...base, kind: "curated", highlights: curated };
|
||||
}
|
||||
if (components.length > 0) {
|
||||
return { ...base, kind: "patch", components };
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error("No releases with parseable highlights or components");
|
||||
};
|
||||
|
||||
const getCachedLatestRelease = unstable_cache(
|
||||
fetchLatestReleaseWithHighlights,
|
||||
["github-latest-release", REPO],
|
||||
{
|
||||
revalidate: REVALIDATE_SECONDS,
|
||||
tags: ["releases"],
|
||||
},
|
||||
);
|
||||
|
||||
export async function getLatestRelease(): Promise<LatestRelease | null> {
|
||||
try {
|
||||
return await getCachedLatestRelease();
|
||||
} catch (err) {
|
||||
console.error("[releases] failed to resolve latest release:", err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
export const RELEASE_COMPONENTS = ["UI", "API", "SDK"] as const;
|
||||
|
||||
export type ReleaseComponent = (typeof RELEASE_COMPONENTS)[number];
|
||||
|
||||
interface LatestReleaseBase {
|
||||
version: string;
|
||||
url: string;
|
||||
repoUrl: string;
|
||||
}
|
||||
|
||||
export interface CuratedRelease extends LatestReleaseBase {
|
||||
kind: "curated";
|
||||
highlights: string[];
|
||||
}
|
||||
|
||||
export interface PatchRelease extends LatestReleaseBase {
|
||||
kind: "patch";
|
||||
components: ReleaseComponent[];
|
||||
}
|
||||
|
||||
export type LatestRelease = CuratedRelease | PatchRelease;
|
||||
@@ -1,4 +1,8 @@
|
||||
import { Suspense } from "react";
|
||||
|
||||
import { AuthForm } from "@/components/auth/oss";
|
||||
import { AuthReleaseHighlightsServer } from "@/components/auth/oss/auth-release-highlights-server";
|
||||
import { AuthReleaseHighlightsSkeleton } from "@/components/auth/oss/auth-release-highlights-skeleton";
|
||||
import {
|
||||
getAuthUrl,
|
||||
isGithubOAuthEnabled,
|
||||
@@ -15,6 +19,14 @@ const SignIn = () => {
|
||||
githubAuthUrl={GITHUB_AUTH_URL}
|
||||
isGoogleOAuthEnabled={isGoogleOAuthEnabled}
|
||||
isGithubOAuthEnabled={isGithubOAuthEnabled}
|
||||
releaseHighlights={
|
||||
<Suspense
|
||||
key="auth-release-highlights"
|
||||
fallback={<AuthReleaseHighlightsSkeleton />}
|
||||
>
|
||||
<AuthReleaseHighlightsServer />
|
||||
</Suspense>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import { Suspense } from "react";
|
||||
|
||||
import { AuthForm } from "@/components/auth/oss";
|
||||
import { getAuthUrl, isGithubOAuthEnabled } from "@/lib/helper";
|
||||
import { isGoogleOAuthEnabled } from "@/lib/helper";
|
||||
import { AuthReleaseHighlightsServer } from "@/components/auth/oss/auth-release-highlights-server";
|
||||
import { AuthReleaseHighlightsSkeleton } from "@/components/auth/oss/auth-release-highlights-skeleton";
|
||||
import {
|
||||
getAuthUrl,
|
||||
isGithubOAuthEnabled,
|
||||
isGoogleOAuthEnabled,
|
||||
} from "@/lib/helper";
|
||||
import { SearchParamsProps } from "@/types";
|
||||
|
||||
const SignUp = async ({
|
||||
@@ -25,6 +32,14 @@ const SignUp = async ({
|
||||
githubAuthUrl={GITHUB_AUTH_URL}
|
||||
isGoogleOAuthEnabled={isGoogleOAuthEnabled}
|
||||
isGithubOAuthEnabled={isGithubOAuthEnabled}
|
||||
releaseHighlights={
|
||||
<Suspense
|
||||
key="auth-release-highlights"
|
||||
fallback={<AuthReleaseHighlightsSkeleton />}
|
||||
>
|
||||
<AuthReleaseHighlightsServer />
|
||||
</Suspense>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -10,9 +10,9 @@ const PARTICLE_SPEED = 0.35;
|
||||
const CONNECTION_DISTANCE = 140;
|
||||
const CONNECTION_DISTANCE_SQ = CONNECTION_DISTANCE * CONNECTION_DISTANCE;
|
||||
const LINE_WIDTH = 0.8;
|
||||
const MOUSE_RADIUS = 160;
|
||||
const MOUSE_RADIUS = 100;
|
||||
const MOUSE_RADIUS_SQ = MOUSE_RADIUS * MOUSE_RADIUS;
|
||||
const MOUSE_FORCE = 2.2;
|
||||
const MOUSE_FORCE = 1.4;
|
||||
const PARTICLE_ALPHA = 0.75;
|
||||
const CONNECTION_MAX_ALPHA = 0.35;
|
||||
const ALPHA_TIER_COUNT = 3;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { ReactNode } from "react";
|
||||
|
||||
import { SignInForm } from "@/components/auth/oss/sign-in-form";
|
||||
import { SignUpForm } from "@/components/auth/oss/sign-up-form";
|
||||
|
||||
@@ -8,6 +10,7 @@ export const AuthForm = ({
|
||||
githubAuthUrl,
|
||||
isGoogleOAuthEnabled,
|
||||
isGithubOAuthEnabled,
|
||||
releaseHighlights,
|
||||
}: {
|
||||
type: string;
|
||||
invitationToken?: string | null;
|
||||
@@ -15,6 +18,7 @@ export const AuthForm = ({
|
||||
githubAuthUrl?: string;
|
||||
isGoogleOAuthEnabled?: boolean;
|
||||
isGithubOAuthEnabled?: boolean;
|
||||
releaseHighlights?: ReactNode;
|
||||
}) => {
|
||||
if (type === "sign-in") {
|
||||
return (
|
||||
@@ -23,6 +27,7 @@ export const AuthForm = ({
|
||||
githubAuthUrl={githubAuthUrl}
|
||||
isGoogleOAuthEnabled={isGoogleOAuthEnabled}
|
||||
isGithubOAuthEnabled={isGithubOAuthEnabled}
|
||||
releaseHighlights={releaseHighlights}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -34,6 +39,7 @@ export const AuthForm = ({
|
||||
githubAuthUrl={githubAuthUrl}
|
||||
isGoogleOAuthEnabled={isGoogleOAuthEnabled}
|
||||
isGithubOAuthEnabled={isGithubOAuthEnabled}
|
||||
releaseHighlights={releaseHighlights}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -2,24 +2,28 @@ import { ReactNode } from "react";
|
||||
|
||||
import { AnimatedDotsBackground } from "@/components/auth/oss/animated-dots-background";
|
||||
import { AuthCard } from "@/components/auth/oss/auth-card";
|
||||
import { AuthReleaseHighlights } from "@/components/auth/oss/auth-release-highlights";
|
||||
import { ProwlerExtended } from "@/components/icons";
|
||||
import { ThemeSwitch } from "@/components/ThemeSwitch";
|
||||
|
||||
interface AuthLayoutProps {
|
||||
title: string;
|
||||
children: ReactNode;
|
||||
releaseHighlights?: ReactNode;
|
||||
}
|
||||
|
||||
export const AuthLayout = ({ title, children }: AuthLayoutProps) => (
|
||||
export const AuthLayout = ({
|
||||
title,
|
||||
children,
|
||||
releaseHighlights,
|
||||
}: AuthLayoutProps) => (
|
||||
<main className="relative min-h-screen w-full overflow-hidden">
|
||||
<AnimatedDotsBackground />
|
||||
|
||||
<div className="relative z-10 mx-auto flex min-h-screen w-full max-w-6xl items-center justify-center px-6 py-10 sm:px-10">
|
||||
<div className="flex w-full items-center justify-center gap-10 lg:justify-between xl:gap-16">
|
||||
<div className="flex w-full items-center justify-center gap-10 lg:justify-center xl:gap-16">
|
||||
<div className="flex w-full max-w-sm flex-col">
|
||||
<div className="mb-6 flex w-full justify-center">
|
||||
<ProwlerExtended width={300} className="h-auto w-55 max-w-full" />
|
||||
<ProwlerExtended width={300} className="h-auto w-56 max-w-full" />
|
||||
</div>
|
||||
|
||||
<AuthCard className="gap-4 px-7 py-9">
|
||||
@@ -32,7 +36,7 @@ export const AuthLayout = ({ title, children }: AuthLayoutProps) => (
|
||||
</AuthCard>
|
||||
</div>
|
||||
|
||||
<AuthReleaseHighlights />
|
||||
{releaseHighlights}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { getLatestRelease } from "@/actions/releases/releases";
|
||||
import { AuthReleaseHighlights } from "@/components/auth/oss/auth-release-highlights";
|
||||
|
||||
export const AuthReleaseHighlightsServer = async () => {
|
||||
const release = await getLatestRelease();
|
||||
if (!release) return null;
|
||||
return <AuthReleaseHighlights release={release} />;
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
export const AuthReleaseHighlightsSkeleton = () => (
|
||||
<aside aria-hidden="true" className="hidden w-full max-w-md lg:block">
|
||||
<div className="relative min-h-[380px] animate-pulse overflow-hidden rounded-3xl border border-black/8 bg-white/60 shadow-2xl ring-1 shadow-slate-300/35 ring-white/55 backdrop-blur-2xl dark:border-white/10 dark:bg-black/60 dark:shadow-black/45 dark:ring-white/6" />
|
||||
</aside>
|
||||
);
|
||||
@@ -1,26 +1,35 @@
|
||||
import { Icon } from "@iconify/react";
|
||||
|
||||
import type { LatestRelease, ReleaseComponent } from "@/actions/releases/types";
|
||||
import { ProwlerShort } from "@/components/icons";
|
||||
import { Button } from "@/components/shadcn";
|
||||
|
||||
const RELEASE = {
|
||||
version: "5.24.0",
|
||||
url: "https://github.com/prowler-cloud/prowler/releases/tag/5.24.0",
|
||||
repoUrl: "https://github.com/prowler-cloud/prowler",
|
||||
} as const;
|
||||
interface AuthReleaseHighlightsProps {
|
||||
release: LatestRelease;
|
||||
}
|
||||
|
||||
const HIGHLIGHTS: readonly string[] = [
|
||||
"Redesigned resources side drawer",
|
||||
"New AWS Bedrock & IAM hardening checks",
|
||||
"New Microsoft 365 Conditional Access coverage",
|
||||
];
|
||||
const formatPatchMessage = (components: ReleaseComponent[]): string => {
|
||||
const [a, b, c] = components;
|
||||
if (!a) return "";
|
||||
if (!b) return `This version contains multiple fixes on the ${a} component.`;
|
||||
if (!c) {
|
||||
return `This version contains multiple fixes across ${a} and ${b} components.`;
|
||||
}
|
||||
return `This version contains multiple fixes across ${a}, ${b} and ${c} components.`;
|
||||
};
|
||||
|
||||
export const AuthReleaseHighlights = () => (
|
||||
export const AuthReleaseHighlights = ({
|
||||
release,
|
||||
}: AuthReleaseHighlightsProps) => (
|
||||
<aside
|
||||
aria-label={`Prowler v${RELEASE.version} highlights`}
|
||||
aria-label={
|
||||
release.kind === "curated"
|
||||
? `Prowler v${release.version} release highlights`
|
||||
: `Prowler v${release.version} patch summary`
|
||||
}
|
||||
className="hidden w-full max-w-md lg:block"
|
||||
>
|
||||
<div className="relative overflow-hidden rounded-3xl border border-black/8 bg-gradient-to-br from-white/78 via-white/70 to-white/58 p-8 shadow-2xl ring-1 shadow-slate-300/35 ring-white/55 backdrop-blur-2xl dark:border-white/10 dark:from-black/70 dark:via-black/62 dark:to-black/52 dark:shadow-black/45 dark:ring-white/6">
|
||||
<div className="relative min-h-[380px] overflow-hidden rounded-3xl border border-black/8 bg-gradient-to-br from-white/78 via-white/70 to-white/58 p-8 shadow-2xl ring-1 shadow-slate-300/35 ring-white/55 backdrop-blur-2xl dark:border-white/10 dark:from-black/82 dark:via-black/74 dark:to-black/68 dark:shadow-black/45 dark:ring-white/6">
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="pointer-events-none absolute inset-0 bg-gradient-to-br from-white/55 via-white/10 to-transparent dark:from-white/8 dark:via-transparent"
|
||||
@@ -39,37 +48,48 @@ export const AuthReleaseHighlights = () => (
|
||||
aria-hidden="true"
|
||||
className="flex h-10 w-10 items-center justify-center rounded-xl border border-black/8 bg-emerald-400/18 shadow-lg shadow-emerald-400/15 dark:border-white/10 dark:bg-emerald-400/15 dark:shadow-emerald-950/30"
|
||||
>
|
||||
<ProwlerShort width={18} className="text-emerald-400" />
|
||||
<ProwlerShort
|
||||
width={18}
|
||||
className="text-emerald-700 dark:text-emerald-300"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className="text-xs font-semibold tracking-wide text-emerald-700 uppercase dark:text-emerald-300">
|
||||
Prowler v{RELEASE.version}
|
||||
<p className="text-xs font-semibold tracking-wide text-emerald-700 uppercase dark:text-emerald-200">
|
||||
Prowler v{release.version}
|
||||
</p>
|
||||
<h2 className="mt-1 text-2xl leading-tight font-semibold text-slate-950 dark:text-white dark:drop-shadow-sm">
|
||||
Fresh off the branch
|
||||
</h2>
|
||||
<p className="mt-2 max-w-sm text-sm text-slate-600 dark:text-white/72">
|
||||
A quick look at what we just shipped in v{RELEASE.version}.
|
||||
<p className="mt-2 max-w-sm text-sm text-slate-600 dark:text-white/85">
|
||||
A quick look at what we just shipped in v{release.version}.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<ul className="flex flex-col gap-3">
|
||||
{HIGHLIGHTS.map((label) => (
|
||||
<li
|
||||
key={label}
|
||||
className="flex items-start gap-3 text-slate-700 dark:text-white/90"
|
||||
>
|
||||
<Icon
|
||||
aria-hidden="true"
|
||||
icon="mdi:check-circle"
|
||||
width={20}
|
||||
className="mt-0.5 shrink-0 text-emerald-600 drop-shadow-sm dark:text-emerald-300"
|
||||
/>
|
||||
<span className="text-sm leading-6">{label}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
{release.kind === "curated" && (
|
||||
<ul className="flex flex-col gap-3">
|
||||
{release.highlights.map((label) => (
|
||||
<li
|
||||
key={label}
|
||||
className="flex items-start gap-3 text-slate-700 dark:text-white/90"
|
||||
>
|
||||
<Icon
|
||||
aria-hidden="true"
|
||||
icon="mdi:check-circle"
|
||||
width={20}
|
||||
className="mt-0.5 shrink-0 text-emerald-600 drop-shadow-sm dark:text-emerald-300"
|
||||
/>
|
||||
<span className="text-sm leading-6">{label}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
|
||||
{release.kind === "patch" && (
|
||||
<p className="text-sm leading-6 text-slate-700 dark:text-white/90">
|
||||
{formatPatchMessage(release.components)}
|
||||
</p>
|
||||
)}
|
||||
|
||||
<div className="flex flex-wrap items-center gap-4">
|
||||
<Button
|
||||
@@ -78,19 +98,19 @@ export const AuthReleaseHighlights = () => (
|
||||
size="sm"
|
||||
className="border-black/8 bg-white/45 text-slate-900 hover:bg-white/70 dark:border-white/12 dark:bg-white/6 dark:text-white dark:hover:bg-white/10"
|
||||
>
|
||||
<a href={RELEASE.repoUrl} target="_blank" rel="noopener noreferrer">
|
||||
<a href={release.repoUrl} target="_blank" rel="noopener noreferrer">
|
||||
<Icon aria-hidden="true" icon="mdi:github" width={16} />
|
||||
GitHub
|
||||
</a>
|
||||
</Button>
|
||||
<a
|
||||
href={RELEASE.url}
|
||||
href={release.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="inline-flex items-center gap-1 text-sm font-medium text-emerald-700 transition-colors hover:text-emerald-800 dark:text-emerald-300 dark:hover:text-emerald-200"
|
||||
className="inline-flex items-center gap-1 rounded-sm text-sm font-medium text-emerald-700 transition-colors hover:text-emerald-800 focus-visible:ring-2 focus-visible:ring-emerald-400/60 focus-visible:outline-none dark:text-emerald-200 dark:hover:text-emerald-100"
|
||||
>
|
||||
See full release notes
|
||||
<Icon aria-hidden="true" icon="mdi:arrow-top-right" width={14} />
|
||||
<Icon aria-hidden="true" icon="mdi:arrow-top-right" width={16} />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Icon } from "@iconify/react";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import { useEffect } from "react";
|
||||
import { ReactNode, useEffect } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
|
||||
import { authenticate } from "@/actions/auth";
|
||||
@@ -23,11 +23,13 @@ export const SignInForm = ({
|
||||
githubAuthUrl,
|
||||
isGoogleOAuthEnabled,
|
||||
isGithubOAuthEnabled,
|
||||
releaseHighlights,
|
||||
}: {
|
||||
googleAuthUrl?: string;
|
||||
githubAuthUrl?: string;
|
||||
isGoogleOAuthEnabled?: boolean;
|
||||
isGithubOAuthEnabled?: boolean;
|
||||
releaseHighlights?: ReactNode;
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
@@ -143,7 +145,7 @@ export const SignInForm = ({
|
||||
const title = isSamlMode ? "Sign in with SAML SSO" : "Sign in";
|
||||
|
||||
return (
|
||||
<AuthLayout title={title}>
|
||||
<AuthLayout title={title} releaseHighlights={releaseHighlights}>
|
||||
<Form {...form}>
|
||||
<form
|
||||
noValidate
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { Checkbox } from "@heroui/checkbox";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { ReactNode } from "react";
|
||||
import { useForm, useWatch } from "react-hook-form";
|
||||
|
||||
import { createNewUser } from "@/actions/auth";
|
||||
@@ -37,12 +38,14 @@ export const SignUpForm = ({
|
||||
githubAuthUrl,
|
||||
isGoogleOAuthEnabled,
|
||||
isGithubOAuthEnabled,
|
||||
releaseHighlights,
|
||||
}: {
|
||||
invitationToken?: string | null;
|
||||
googleAuthUrl?: string;
|
||||
githubAuthUrl?: string;
|
||||
isGoogleOAuthEnabled?: boolean;
|
||||
isGithubOAuthEnabled?: boolean;
|
||||
releaseHighlights?: ReactNode;
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
const { toast } = useToast();
|
||||
@@ -126,7 +129,7 @@ export const SignUpForm = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<AuthLayout title="Sign up">
|
||||
<AuthLayout title="Sign up" releaseHighlights={releaseHighlights}>
|
||||
<Form {...form}>
|
||||
<form
|
||||
noValidate
|
||||
|
||||
Reference in New Issue
Block a user