add learn more link

This commit is contained in:
miloschwartz
2026-03-29 11:34:07 -07:00
parent d1b2105c80
commit bff2ba7cc2
7 changed files with 420 additions and 383 deletions

View File

@@ -45,6 +45,7 @@ import { useTranslations } from "next-intl";
import { AxiosResponse } from "axios"; import { AxiosResponse } from "axios";
import { ListRolesResponse } from "@server/routers/role"; import { ListRolesResponse } from "@server/routers/role";
import AutoProvisionConfigWidget from "@app/components/AutoProvisionConfigWidget"; import AutoProvisionConfigWidget from "@app/components/AutoProvisionConfigWidget";
import IdpAutoProvisionUsersDescription from "@app/components/IdpAutoProvisionUsersDescription";
import { PaidFeaturesAlert } from "@app/components/PaidFeaturesAlert"; import { PaidFeaturesAlert } from "@app/components/PaidFeaturesAlert";
import { tierMatrix } from "@server/lib/billing/tierMatrix"; import { tierMatrix } from "@server/lib/billing/tierMatrix";
import { import {
@@ -493,7 +494,7 @@ export default function GeneralPage() {
{t("idpAutoProvisionUsers")} {t("idpAutoProvisionUsers")}
</SettingsSectionTitle> </SettingsSectionTitle>
<SettingsSectionDescription> <SettingsSectionDescription>
{t("idpAutoProvisionUsersDescription")} <IdpAutoProvisionUsersDescription />
</SettingsSectionDescription> </SettingsSectionDescription>
</SettingsSectionHeader> </SettingsSectionHeader>
<SettingsSectionBody> <SettingsSectionBody>

View File

@@ -1,6 +1,7 @@
"use client"; "use client";
import AutoProvisionConfigWidget from "@app/components/AutoProvisionConfigWidget"; import AutoProvisionConfigWidget from "@app/components/AutoProvisionConfigWidget";
import IdpAutoProvisionUsersDescription from "@app/components/IdpAutoProvisionUsersDescription";
import { PaidFeaturesAlert } from "@app/components/PaidFeaturesAlert"; import { PaidFeaturesAlert } from "@app/components/PaidFeaturesAlert";
import { import {
SettingsContainer, SettingsContainer,
@@ -296,7 +297,7 @@ export default function Page() {
{t("idpAutoProvisionUsers")} {t("idpAutoProvisionUsers")}
</SettingsSectionTitle> </SettingsSectionTitle>
<SettingsSectionDescription> <SettingsSectionDescription>
{t("idpAutoProvisionUsersDescription")} <IdpAutoProvisionUsersDescription />
</SettingsSectionDescription> </SettingsSectionDescription>
</SettingsSectionHeader> </SettingsSectionHeader>
<SettingsSectionBody> <SettingsSectionBody>

View File

@@ -31,6 +31,7 @@ import { formatAxiosError } from "@app/lib/api";
import { createApiClient } from "@app/lib/api"; import { createApiClient } from "@app/lib/api";
import { useEnvContext } from "@app/hooks/useEnvContext"; import { useEnvContext } from "@app/hooks/useEnvContext";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import IdpAutoProvisionUsersDescription from "@app/components/IdpAutoProvisionUsersDescription";
import { SwitchInput } from "@app/components/SwitchInput"; import { SwitchInput } from "@app/components/SwitchInput";
import { import {
InfoSection, InfoSection,
@@ -349,7 +350,7 @@ export default function GeneralPage() {
{t("idpAutoProvisionUsers")} {t("idpAutoProvisionUsers")}
</SettingsSectionTitle> </SettingsSectionTitle>
<SettingsSectionDescription> <SettingsSectionDescription>
{t("idpAutoProvisionUsersDescription")} <IdpAutoProvisionUsersDescription />
</SettingsSectionDescription> </SettingsSectionDescription>
</SettingsSectionHeader> </SettingsSectionHeader>
<SettingsSectionBody> <SettingsSectionBody>
@@ -375,9 +376,6 @@ export default function GeneralPage() {
/> />
</div> </div>
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<span className="text-sm text-muted-foreground">
{t("idpAutoProvisionUsersDescription")}
</span>
{form.watch("autoProvision") && ( {form.watch("autoProvision") && (
<FormDescription> <FormDescription>
{t.rich( {t.rich(

View File

@@ -22,6 +22,7 @@ import {
FormMessage FormMessage
} from "@app/components/ui/form"; } from "@app/components/ui/form";
import HeaderTitle from "@app/components/SettingsSectionTitle"; import HeaderTitle from "@app/components/SettingsSectionTitle";
import IdpAutoProvisionUsersDescription from "@app/components/IdpAutoProvisionUsersDescription";
import { SwitchInput } from "@app/components/SwitchInput"; import { SwitchInput } from "@app/components/SwitchInput";
import { Alert, AlertDescription, AlertTitle } from "@app/components/ui/alert"; import { Alert, AlertDescription, AlertTitle } from "@app/components/ui/alert";
import { Button } from "@app/components/ui/button"; import { Button } from "@app/components/ui/button";
@@ -94,8 +95,7 @@ export default function Page() {
const watchedType = form.watch("type"); const watchedType = form.watch("type");
const templatesLocked = const templatesLocked =
!templatesPaid && !templatesPaid && (watchedType === "google" || watchedType === "azure");
(watchedType === "google" || watchedType === "azure");
async function onSubmit(data: CreateIdpFormValues) { async function onSubmit(data: CreateIdpFormValues) {
if ( if (
@@ -223,7 +223,9 @@ export default function Page() {
<div className="flex items-start mb-0"> <div className="flex items-start mb-0">
<SwitchInput <SwitchInput
id="auto-provision-toggle" id="auto-provision-toggle"
label={t("idpAutoProvisionUsers")} label={t(
"idpAutoProvisionUsers"
)}
defaultChecked={form.getValues( defaultChecked={form.getValues(
"autoProvision" "autoProvision"
)} )}
@@ -235,11 +237,6 @@ export default function Page() {
}} }}
/> />
</div> </div>
<span className="text-sm text-muted-foreground">
{t(
"idpAutoProvisionUsersDescription"
)}
</span>
</form> </form>
</Form> </Form>
</SettingsSectionForm> </SettingsSectionForm>
@@ -267,7 +264,9 @@ export default function Page() {
<form <form
className="space-y-4" className="space-y-4"
id="create-idp-form" id="create-idp-form"
onSubmit={form.handleSubmit(onSubmit)} onSubmit={form.handleSubmit(
onSubmit
)}
> >
<FormField <FormField
control={form.control} control={form.control}
@@ -296,7 +295,9 @@ export default function Page() {
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel> <FormLabel>
{t("idpClientSecret")} {t(
"idpClientSecret"
)}
</FormLabel> </FormLabel>
<FormControl> <FormControl>
<Input <Input
@@ -336,7 +337,9 @@ export default function Page() {
<form <form
className="space-y-4" className="space-y-4"
id="create-idp-form" id="create-idp-form"
onSubmit={form.handleSubmit(onSubmit)} onSubmit={form.handleSubmit(
onSubmit
)}
> >
<FormField <FormField
control={form.control} control={form.control}
@@ -344,7 +347,9 @@ export default function Page() {
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel> <FormLabel>
{t("idpTenantIdLabel")} {t(
"idpTenantIdLabel"
)}
</FormLabel> </FormLabel>
<FormControl> <FormControl>
<Input {...field} /> <Input {...field} />
@@ -386,7 +391,9 @@ export default function Page() {
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel> <FormLabel>
{t("idpClientSecret")} {t(
"idpClientSecret"
)}
</FormLabel> </FormLabel>
<FormControl> <FormControl>
<Input <Input
@@ -426,7 +433,9 @@ export default function Page() {
<form <form
className="space-y-4" className="space-y-4"
id="create-idp-form" id="create-idp-form"
onSubmit={form.handleSubmit(onSubmit)} onSubmit={form.handleSubmit(
onSubmit
)}
> >
<FormField <FormField
control={form.control} control={form.control}
@@ -455,7 +464,9 @@ export default function Page() {
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel> <FormLabel>
{t("idpClientSecret")} {t(
"idpClientSecret"
)}
</FormLabel> </FormLabel>
<FormControl> <FormControl>
<Input <Input
@@ -539,7 +550,9 @@ export default function Page() {
<form <form
className="space-y-4" className="space-y-4"
id="create-idp-form" id="create-idp-form"
onSubmit={form.handleSubmit(onSubmit)} onSubmit={form.handleSubmit(
onSubmit
)}
> >
<FormField <FormField
control={form.control} control={form.control}
@@ -547,7 +560,9 @@ export default function Page() {
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel> <FormLabel>
{t("idpJmespathLabel")} {t(
"idpJmespathLabel"
)}
</FormLabel> </FormLabel>
<FormControl> <FormControl>
<Input {...field} /> <Input {...field} />

View File

@@ -1,14 +1,12 @@
"use client"; "use client";
import IdpAutoProvisionUsersDescription from "@app/components/IdpAutoProvisionUsersDescription";
import { FormDescription } from "@app/components/ui/form"; import { FormDescription } from "@app/components/ui/form";
import { SwitchInput } from "@app/components/SwitchInput"; import { SwitchInput } from "@app/components/SwitchInput";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
import { usePaidStatus } from "@app/hooks/usePaidStatus"; import { usePaidStatus } from "@app/hooks/usePaidStatus";
import { tierMatrix } from "@server/lib/billing/tierMatrix"; import { tierMatrix } from "@server/lib/billing/tierMatrix";
import { import { MappingBuilderRule, RoleMappingMode } from "@app/lib/idpRoleMapping";
MappingBuilderRule,
RoleMappingMode
} from "@app/lib/idpRoleMapping";
import RoleMappingConfigFields from "@app/components/RoleMappingConfigFields"; import RoleMappingConfigFields from "@app/components/RoleMappingConfigFields";
type Role = { type Role = {
@@ -60,9 +58,6 @@ export default function AutoProvisionConfigWidget({
onCheckedChange={onAutoProvisionChange} onCheckedChange={onAutoProvisionChange}
disabled={!isPaidUser(tierMatrix.autoProvisioning)} disabled={!isPaidUser(tierMatrix.autoProvisioning)}
/> />
<FormDescription className="text-sm text-muted-foreground">
{t("idpAutoProvisionUsersDescription")}
</FormDescription>
</div> </div>
{autoProvision && ( {autoProvision && (

View File

@@ -0,0 +1,29 @@
"use client";
import { useTranslations } from "next-intl";
const AUTO_PROVISION_DOCS_URL =
"https://docs.pangolin.net/manage/identity-providers/auto-provisioning";
type IdpAutoProvisionUsersDescriptionProps = {
className?: string;
};
export default function IdpAutoProvisionUsersDescription({
className
}: IdpAutoProvisionUsersDescriptionProps) {
const t = useTranslations();
return (
<span className={className}>
{t("idpAutoProvisionUsersDescription")}{" "}
<a
href={AUTO_PROVISION_DOCS_URL}
target="_blank"
rel="noopener noreferrer"
className="text-primary hover:underline"
>
{t("learnMore")}
</a>
</span>
);
}

View File

@@ -27,6 +27,7 @@ import { Checkbox } from "@app/components/ui/checkbox";
import { Alert, AlertDescription, AlertTitle } from "@app/components/ui/alert"; import { Alert, AlertDescription, AlertTitle } from "@app/components/ui/alert";
import { InfoIcon, ExternalLink } from "lucide-react"; import { InfoIcon, ExternalLink } from "lucide-react";
import { StrategySelect } from "@app/components/StrategySelect"; import { StrategySelect } from "@app/components/StrategySelect";
import IdpAutoProvisionUsersDescription from "@app/components/IdpAutoProvisionUsersDescription";
import { SwitchInput } from "@app/components/SwitchInput"; import { SwitchInput } from "@app/components/SwitchInput";
import { Badge } from "@app/components/ui/badge"; import { Badge } from "@app/components/ui/badge";
import { useTranslations } from "next-intl"; import { useTranslations } from "next-intl";
@@ -163,9 +164,6 @@ export function IdpCreateWizard({
disabled={loading} disabled={loading}
/> />
</div> </div>
<span className="text-sm text-muted-foreground">
{t("idpAutoProvisionUsersDescription")}
</span>
</form> </form>
</Form> </Form>
</SettingsSectionForm> </SettingsSectionForm>