"use client"; import { SettingsContainer, SettingsSection, SettingsSectionBody, SettingsSectionDescription, SettingsSectionForm, SettingsSectionGrid, SettingsSectionHeader, SettingsSectionTitle } from "@app/components/Settings"; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from "@app/components/ui/form"; import HeaderTitle from "@app/components/SettingsSectionTitle"; import { z } from "zod"; import { createElement, useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { Input } from "@app/components/ui/input"; import { Button } from "@app/components/ui/button"; import { createApiClient, formatAxiosError } from "@app/lib/api"; import { useEnvContext } from "@app/hooks/useEnvContext"; import { toast } from "@app/hooks/useToast"; import { useRouter } from "next/navigation"; import { Checkbox } from "@app/components/ui/checkbox"; import { Alert, AlertDescription, AlertTitle } from "@app/components/ui/alert"; import { InfoIcon, ExternalLink } from "lucide-react"; import { StrategySelect } from "@app/components/StrategySelect"; import { SwitchInput } from "@app/components/SwitchInput"; import { Badge } from "@app/components/ui/badge"; import { useLicenseStatusContext } from "@app/hooks/useLicenseStatusContext"; import { useTranslations } from "next-intl"; export default function Page() { const { env } = useEnvContext(); const api = createApiClient({ env }); const router = useRouter(); const [createLoading, setCreateLoading] = useState(false); const { isUnlocked } = useLicenseStatusContext(); const t = useTranslations(); const createIdpFormSchema = z.object({ name: z.string().min(2, { message: t("nameMin", { len: 2 }) }), type: z.enum(["oidc"]), clientId: z.string().min(1, { message: t("idpClientIdRequired") }), clientSecret: z .string() .min(1, { message: t("idpClientSecretRequired") }), authUrl: z.url({ message: t("idpErrorAuthUrlInvalid") }), tokenUrl: z.url({ message: t("idpErrorTokenUrlInvalid") }), identifierPath: z.string().min(1, { message: t("idpPathRequired") }), emailPath: z.string().optional(), namePath: z.string().optional(), scopes: z.string().min(1, { message: t("idpScopeRequired") }), autoProvision: z.boolean().default(false) }); type CreateIdpFormValues = z.infer; interface ProviderTypeOption { id: "oidc"; title: string; description: string; } const providerTypes: ReadonlyArray = [ { id: "oidc", title: "OAuth2/OIDC", description: t("idpOidcDescription") } ]; const form = useForm({ resolver: zodResolver(createIdpFormSchema), defaultValues: { name: "", type: "oidc", clientId: "", clientSecret: "", authUrl: "", tokenUrl: "", identifierPath: "sub", namePath: "name", emailPath: "email", scopes: "openid profile email", autoProvision: false } }); async function onSubmit(data: CreateIdpFormValues) { setCreateLoading(true); try { const payload = { name: data.name, clientId: data.clientId, clientSecret: data.clientSecret, authUrl: data.authUrl, tokenUrl: data.tokenUrl, identifierPath: data.identifierPath, emailPath: data.emailPath, namePath: data.namePath, autoProvision: data.autoProvision, scopes: data.scopes }; const res = await api.put("/idp/oidc", payload); if (res.status === 201) { toast({ title: t("success"), description: t("idpCreatedDescription") }); router.push(`/admin/idp/${res.data.data.idpId}`); } } catch (e) { toast({ title: t("error"), description: formatAxiosError(e), variant: "destructive" }); } finally { setCreateLoading(false); } } return ( <>
{t("idpTitle")} {t("idpCreateSettingsDescription")}
( {t("name")} {t("idpDisplayName")} )} />
{ form.setValue( "autoProvision", checked ); }} />
{t("idpAutoProvisionUsersDescription")}
{t("idpType")} {t("idpTypeDescription")} { form.setValue("type", value as "oidc"); }} cols={3} /> {form.watch("type") === "oidc" && ( {t("idpOidcConfigure")} {t("idpOidcConfigureDescription")}
( {t("idpClientId")} {t( "idpClientIdDescription" )} )} /> ( {t("idpClientSecret")} {t( "idpClientSecretDescription" )} )} /> ( {t("idpAuthUrl")} {t( "idpAuthUrlDescription" )} )} /> ( {t("idpTokenUrl")} {t( "idpTokenUrlDescription" )} )} /> {t("idpOidcConfigureAlert")} {t("idpOidcConfigureAlertDescription")}
{t("idpToken")} {t("idpTokenDescription")}
{t("idpJmespathAbout")} {t( "idpJmespathAboutDescription" )}{" "} {t( "idpJmespathAboutDescriptionLink" )}{" "} ( {t("idpJmespathLabel")} {t( "idpJmespathLabelDescription" )} )} /> ( {t( "idpJmespathEmailPathOptional" )} {t( "idpJmespathEmailPathOptionalDescription" )} )} /> ( {t( "idpJmespathNamePathOptional" )} {t( "idpJmespathNamePathOptionalDescription" )} )} /> ( {t( "idpOidcConfigureScopes" )} {t( "idpOidcConfigureScopesDescription" )} )} />
)}
); }