mirror of
https://github.com/fosrl/pangolin.git
synced 2026-10-20 19:49:05 +02:00
Merge branch 'dev' of github.com:fosrl/pangolin into dev
This commit is contained in:
@@ -36,7 +36,9 @@ import {
|
|||||||
SettingsSectionDescription,
|
SettingsSectionDescription,
|
||||||
SettingsSectionBody,
|
SettingsSectionBody,
|
||||||
SettingsSectionForm,
|
SettingsSectionForm,
|
||||||
SettingsSectionFooter
|
SettingsSectionFooter,
|
||||||
|
SettingsFormGrid,
|
||||||
|
SettingsFormCell
|
||||||
} from "@app/components/Settings";
|
} from "@app/components/Settings";
|
||||||
import { useUserContext } from "@app/hooks/useUserContext";
|
import { useUserContext } from "@app/hooks/useUserContext";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
@@ -242,7 +244,7 @@ function GeneralSectionForm({ org }: SectionFormProps) {
|
|||||||
</SettingsSectionDescription>
|
</SettingsSectionDescription>
|
||||||
</SettingsSectionHeader>
|
</SettingsSectionHeader>
|
||||||
<SettingsSectionBody>
|
<SettingsSectionBody>
|
||||||
<SettingsSectionForm>
|
<SettingsSectionForm variant="half">
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
onSubmit={(e) => {
|
onSubmit={(e) => {
|
||||||
@@ -251,71 +253,86 @@ function GeneralSectionForm({ org }: SectionFormProps) {
|
|||||||
formAction();
|
formAction();
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
className="grid gap-4"
|
|
||||||
id="org-general-settings-form"
|
id="org-general-settings-form"
|
||||||
>
|
>
|
||||||
<FormField
|
<SettingsFormGrid>
|
||||||
control={form.control}
|
<SettingsFormCell span="half">
|
||||||
name="name"
|
<FormField
|
||||||
render={({ field }) => (
|
control={form.control}
|
||||||
<FormItem>
|
name="name"
|
||||||
<FormLabel>{t("name")}</FormLabel>
|
render={({ field }) => (
|
||||||
<FormControl>
|
<FormItem>
|
||||||
<Input {...field} />
|
<FormLabel>
|
||||||
</FormControl>
|
{t("name")}
|
||||||
<FormMessage />
|
</FormLabel>
|
||||||
<FormDescription>
|
<FormControl>
|
||||||
{t("orgDisplayName")}
|
<Input {...field} />
|
||||||
</FormDescription>
|
</FormControl>
|
||||||
</FormItem>
|
<FormMessage />
|
||||||
)}
|
<FormDescription>
|
||||||
/>
|
{t("orgDisplayName")}
|
||||||
|
</FormDescription>
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</SettingsFormCell>
|
||||||
|
|
||||||
<PaidFeaturesAlert
|
<SettingsFormCell span="full">
|
||||||
tiers={tierMatrix.newtAutoUpdate}
|
<PaidFeaturesAlert
|
||||||
/>
|
tiers={tierMatrix.newtAutoUpdate}
|
||||||
{!env.flags.disableEnterpriseFeatures && (
|
/>
|
||||||
<FormField
|
</SettingsFormCell>
|
||||||
control={form.control}
|
{!env.flags.disableEnterpriseFeatures && (
|
||||||
name="settingsEnableGlobalNewtAutoUpdate"
|
<SettingsFormCell span="full">
|
||||||
render={({ field }) => (
|
<FormField
|
||||||
<FormItem>
|
control={form.control}
|
||||||
<FormControl>
|
name="settingsEnableGlobalNewtAutoUpdate"
|
||||||
<SwitchInput
|
render={({ field }) => (
|
||||||
id="settings-enable-global-newt-auto-update"
|
<FormItem>
|
||||||
label={t("newtAutoUpdate")}
|
<FormControl>
|
||||||
checked={field.value}
|
<SwitchInput
|
||||||
onCheckedChange={
|
id="settings-enable-global-newt-auto-update"
|
||||||
field.onChange
|
label={t(
|
||||||
}
|
"newtAutoUpdate"
|
||||||
disabled={
|
)}
|
||||||
!hasAutoUpdateFeature
|
checked={
|
||||||
}
|
field.value
|
||||||
/>
|
}
|
||||||
</FormControl>
|
onCheckedChange={
|
||||||
<FormDescription>
|
field.onChange
|
||||||
{t("newtAutoUpdateDescription")}{" "}
|
}
|
||||||
<a
|
disabled={
|
||||||
href="https://docs.pangolin.net/manage/sites/auto-update"
|
!hasAutoUpdateFeature
|
||||||
target="_blank"
|
}
|
||||||
rel="noopener noreferrer"
|
/>
|
||||||
className="text-primary hover:underline inline-flex items-center gap-1"
|
</FormControl>
|
||||||
>
|
<FormDescription>
|
||||||
{t("learnMore")}
|
{t(
|
||||||
<ExternalLink className="size-3.5 shrink-0" />
|
"newtAutoUpdateDescription"
|
||||||
</a>
|
)}{" "}
|
||||||
</FormDescription>
|
<a
|
||||||
<FormMessage />
|
href="https://docs.pangolin.net/manage/sites/auto-update"
|
||||||
</FormItem>
|
target="_blank"
|
||||||
)}
|
rel="noopener noreferrer"
|
||||||
/>
|
className="text-primary hover:underline inline-flex items-center gap-1"
|
||||||
)}
|
>
|
||||||
|
{t("learnMore")}
|
||||||
|
<ExternalLink className="size-3.5 shrink-0" />
|
||||||
|
</a>
|
||||||
|
</FormDescription>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</SettingsFormCell>
|
||||||
|
)}
|
||||||
|
</SettingsFormGrid>
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
</SettingsSectionForm>
|
</SettingsSectionForm>
|
||||||
</SettingsSectionBody>
|
</SettingsSectionBody>
|
||||||
|
|
||||||
<div className="flex justify-end gap-2 mt-4">
|
<SettingsSectionFooter>
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
form="org-general-settings-form"
|
form="org-general-settings-form"
|
||||||
@@ -324,7 +341,7 @@ function GeneralSectionForm({ org }: SectionFormProps) {
|
|||||||
>
|
>
|
||||||
{t("saveSettings")}
|
{t("saveSettings")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</SettingsSectionFooter>
|
||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -15,12 +15,18 @@ import { useActionState } from "react";
|
|||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import z from "zod";
|
import z from "zod";
|
||||||
import {
|
import {
|
||||||
|
SettingsFormCell,
|
||||||
|
SettingsFormGrid,
|
||||||
SettingsSection,
|
SettingsSection,
|
||||||
SettingsSectionBody,
|
SettingsSectionBody,
|
||||||
SettingsSectionDescription,
|
SettingsSectionDescription,
|
||||||
|
SettingsSectionFooter,
|
||||||
SettingsSectionForm,
|
SettingsSectionForm,
|
||||||
SettingsSectionHeader,
|
SettingsSectionHeader,
|
||||||
SettingsSectionTitle
|
SettingsSectionTitle,
|
||||||
|
SettingsSubsectionDescription,
|
||||||
|
SettingsSubsectionHeader,
|
||||||
|
SettingsSubsectionTitle
|
||||||
} from "./Settings";
|
} from "./Settings";
|
||||||
|
|
||||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||||
@@ -176,89 +182,228 @@ export default function AuthPageBrandingForm({
|
|||||||
</SettingsSectionHeader>
|
</SettingsSectionHeader>
|
||||||
|
|
||||||
<SettingsSectionBody>
|
<SettingsSectionBody>
|
||||||
<SettingsSectionForm>
|
<SettingsSectionForm variant="half">
|
||||||
<PaidFeaturesAlert
|
|
||||||
tiers={tierMatrix.loginPageBranding}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
action={updateFormAction}
|
action={updateFormAction}
|
||||||
id="auth-page-branding-form"
|
id="auth-page-branding-form"
|
||||||
className="flex flex-col space-y-4 items-stretch"
|
|
||||||
>
|
>
|
||||||
<FormField
|
<SettingsFormGrid>
|
||||||
control={form.control}
|
<SettingsFormCell span="full">
|
||||||
name="primaryColor"
|
<PaidFeaturesAlert
|
||||||
render={({ field }) => (
|
tiers={tierMatrix.loginPageBranding}
|
||||||
<FormItem className="">
|
/>
|
||||||
<FormLabel>
|
</SettingsFormCell>
|
||||||
{t("brandingPrimaryColor")}
|
|
||||||
</FormLabel>
|
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<SettingsFormCell span="half">
|
||||||
<label
|
|
||||||
className="size-8 rounded-sm"
|
|
||||||
aria-hidden="true"
|
|
||||||
style={{
|
|
||||||
backgroundColor:
|
|
||||||
field.value
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="color"
|
|
||||||
{...field}
|
|
||||||
className="sr-only"
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<FormControl>
|
|
||||||
<Input {...field} />
|
|
||||||
</FormControl>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className="grid md:grid-cols-5 gap-3 items-start">
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="logoUrl"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem className="md:col-span-3">
|
|
||||||
<FormLabel>
|
|
||||||
{build === "enterprise"
|
|
||||||
? t(
|
|
||||||
"brandingLogoURLOrPath"
|
|
||||||
)
|
|
||||||
: t("brandingLogoURL")}
|
|
||||||
</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<Input {...field} />
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
<FormDescription>
|
|
||||||
{build === "enterprise"
|
|
||||||
? t(
|
|
||||||
"brandingLogoPathDescription"
|
|
||||||
)
|
|
||||||
: t(
|
|
||||||
"brandingLogoURLDescription"
|
|
||||||
)}
|
|
||||||
</FormDescription>
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<div className="md:col-span-2 flex gap-3 items-start">
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="logoWidth"
|
name="primaryColor"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className="grow">
|
<FormItem>
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
{t("brandingLogoWidth")}
|
{t(
|
||||||
|
"brandingPrimaryColor"
|
||||||
|
)}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<label
|
||||||
|
className="size-8 rounded-sm"
|
||||||
|
aria-hidden="true"
|
||||||
|
style={{
|
||||||
|
backgroundColor:
|
||||||
|
field.value
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="color"
|
||||||
|
{...field}
|
||||||
|
className="sr-only"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<FormControl>
|
||||||
|
<Input {...field} />
|
||||||
|
</FormControl>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</SettingsFormCell>
|
||||||
|
|
||||||
|
<SettingsFormCell
|
||||||
|
span="half"
|
||||||
|
className="md:col-start-1"
|
||||||
|
>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="logoUrl"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>
|
||||||
|
{build === "enterprise"
|
||||||
|
? t(
|
||||||
|
"brandingLogoURLOrPath"
|
||||||
|
)
|
||||||
|
: t(
|
||||||
|
"brandingLogoURL"
|
||||||
|
)}
|
||||||
|
</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
<FormDescription>
|
||||||
|
{build === "enterprise"
|
||||||
|
? t(
|
||||||
|
"brandingLogoPathDescription"
|
||||||
|
)
|
||||||
|
: t(
|
||||||
|
"brandingLogoURLDescription"
|
||||||
|
)}
|
||||||
|
</FormDescription>
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</SettingsFormCell>
|
||||||
|
|
||||||
|
<SettingsFormCell span="half">
|
||||||
|
<div className="flex gap-3 items-start">
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="logoWidth"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem className="grow">
|
||||||
|
<FormLabel>
|
||||||
|
{t(
|
||||||
|
"brandingLogoWidth"
|
||||||
|
)}
|
||||||
|
</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<span className="relative top-8">
|
||||||
|
<XIcon className="text-muted-foreground size-4" />
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="logoHeight"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem className="grow">
|
||||||
|
<FormLabel>
|
||||||
|
{t(
|
||||||
|
"brandingLogoHeight"
|
||||||
|
)}
|
||||||
|
</FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Input {...field} />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</SettingsFormCell>
|
||||||
|
|
||||||
|
{build === "saas" ||
|
||||||
|
env.env.app.identityProviderMode ===
|
||||||
|
"org" ? (
|
||||||
|
<>
|
||||||
|
<SettingsFormCell span="full">
|
||||||
|
<SettingsSubsectionHeader>
|
||||||
|
<SettingsSubsectionTitle>
|
||||||
|
{t(
|
||||||
|
"organizationLoginPageTitle"
|
||||||
|
)}
|
||||||
|
</SettingsSubsectionTitle>
|
||||||
|
<SettingsSubsectionDescription>
|
||||||
|
{t(
|
||||||
|
"organizationLoginPageDescription"
|
||||||
|
)}
|
||||||
|
</SettingsSubsectionDescription>
|
||||||
|
</SettingsSubsectionHeader>
|
||||||
|
</SettingsFormCell>
|
||||||
|
|
||||||
|
<SettingsFormCell span="half">
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="orgTitle"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>
|
||||||
|
{t(
|
||||||
|
"brandingOrgTitle"
|
||||||
|
)}
|
||||||
|
</FormLabel>
|
||||||
|
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</SettingsFormCell>
|
||||||
|
<SettingsFormCell span="half">
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="orgSubtitle"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>
|
||||||
|
{t(
|
||||||
|
"brandingOrgSubtitle"
|
||||||
|
)}
|
||||||
|
</FormLabel>
|
||||||
|
|
||||||
|
<FormControl>
|
||||||
|
<Input
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</SettingsFormCell>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
|
|
||||||
|
<SettingsFormCell span="full">
|
||||||
|
<SettingsSubsectionHeader>
|
||||||
|
<SettingsSubsectionTitle>
|
||||||
|
{t("resourceLoginPageTitle")}
|
||||||
|
</SettingsSubsectionTitle>
|
||||||
|
<SettingsSubsectionDescription>
|
||||||
|
{t(
|
||||||
|
"resourceLoginPageDescription"
|
||||||
|
)}
|
||||||
|
</SettingsSubsectionDescription>
|
||||||
|
</SettingsSubsectionHeader>
|
||||||
|
</SettingsFormCell>
|
||||||
|
|
||||||
|
<SettingsFormCell span="half">
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="resourceTitle"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>
|
||||||
|
{t(
|
||||||
|
"brandingResourceTitle"
|
||||||
|
)}
|
||||||
|
</FormLabel>
|
||||||
|
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input {...field} />
|
<Input {...field} />
|
||||||
</FormControl>
|
</FormControl>
|
||||||
@@ -266,19 +411,16 @@ export default function AuthPageBrandingForm({
|
|||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
</SettingsFormCell>
|
||||||
<span className="relative top-8">
|
<SettingsFormCell span="half">
|
||||||
<XIcon className="text-muted-foreground size-4" />
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="logoHeight"
|
name="resourceSubtitle"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className="grow">
|
<FormItem>
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
{t(
|
{t(
|
||||||
"brandingLogoHeight"
|
"brandingResourceSubtitle"
|
||||||
)}
|
)}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
@@ -288,116 +430,14 @@ export default function AuthPageBrandingForm({
|
|||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</SettingsFormCell>
|
||||||
</div>
|
</SettingsFormGrid>
|
||||||
|
|
||||||
{build === "saas" ||
|
|
||||||
env.env.app.identityProviderMode === "org" ? (
|
|
||||||
<>
|
|
||||||
<div className="mt-3 mb-6">
|
|
||||||
<SettingsSectionTitle>
|
|
||||||
{t(
|
|
||||||
"organizationLoginPageTitle"
|
|
||||||
)}
|
|
||||||
</SettingsSectionTitle>
|
|
||||||
<SettingsSectionDescription>
|
|
||||||
{t(
|
|
||||||
"organizationLoginPageDescription"
|
|
||||||
)}
|
|
||||||
</SettingsSectionDescription>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col gap-5">
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="orgTitle"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem className="md:col-span-3">
|
|
||||||
<FormLabel>
|
|
||||||
{t(
|
|
||||||
"brandingOrgTitle"
|
|
||||||
)}
|
|
||||||
</FormLabel>
|
|
||||||
|
|
||||||
<FormControl>
|
|
||||||
<Input {...field} />
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="orgSubtitle"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem className="md:col-span-3">
|
|
||||||
<FormLabel>
|
|
||||||
{t(
|
|
||||||
"brandingOrgSubtitle"
|
|
||||||
)}
|
|
||||||
</FormLabel>
|
|
||||||
|
|
||||||
<FormControl>
|
|
||||||
<Input {...field} />
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
<div className="mt-3 mb-6">
|
|
||||||
<SettingsSectionTitle>
|
|
||||||
{t("resourceLoginPageTitle")}
|
|
||||||
</SettingsSectionTitle>
|
|
||||||
<SettingsSectionDescription>
|
|
||||||
{t("resourceLoginPageDescription")}
|
|
||||||
</SettingsSectionDescription>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col gap-5">
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="resourceTitle"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem className="md:col-span-3">
|
|
||||||
<FormLabel>
|
|
||||||
{t("brandingResourceTitle")}
|
|
||||||
</FormLabel>
|
|
||||||
|
|
||||||
<FormControl>
|
|
||||||
<Input {...field} />
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<FormField
|
|
||||||
control={form.control}
|
|
||||||
name="resourceSubtitle"
|
|
||||||
render={({ field }) => (
|
|
||||||
<FormItem className="md:col-span-3">
|
|
||||||
<FormLabel>
|
|
||||||
{t(
|
|
||||||
"brandingResourceSubtitle"
|
|
||||||
)}
|
|
||||||
</FormLabel>
|
|
||||||
<FormControl>
|
|
||||||
<Input {...field} />
|
|
||||||
</FormControl>
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
</SettingsSectionForm>
|
</SettingsSectionForm>
|
||||||
</SettingsSectionBody>
|
</SettingsSectionBody>
|
||||||
|
|
||||||
<div className="flex justify-end gap-2 mt-6 items-center">
|
<SettingsSectionFooter>
|
||||||
{branding && (
|
{branding && (
|
||||||
<form action={deleteFormAction}>
|
<form action={deleteFormAction}>
|
||||||
<Button
|
<Button
|
||||||
@@ -427,7 +467,7 @@ export default function AuthPageBrandingForm({
|
|||||||
>
|
>
|
||||||
{t("saveAuthPageBranding")}
|
{t("saveAuthPageBranding")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</SettingsSectionFooter>
|
||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
+150
-125
@@ -20,7 +20,10 @@ import {
|
|||||||
SettingsSectionTitle,
|
SettingsSectionTitle,
|
||||||
SettingsSectionDescription,
|
SettingsSectionDescription,
|
||||||
SettingsSectionBody,
|
SettingsSectionBody,
|
||||||
SettingsSectionForm
|
SettingsSectionForm,
|
||||||
|
SettingsSectionFooter,
|
||||||
|
SettingsFormGrid,
|
||||||
|
SettingsFormCell
|
||||||
} from "@app/components/Settings";
|
} from "@app/components/Settings";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { GetLoginPageResponse } from "@server/routers/loginPage/types";
|
import { GetLoginPageResponse } from "@server/routers/loginPage/types";
|
||||||
@@ -284,145 +287,167 @@ function AuthPageSettings({
|
|||||||
</SettingsSectionDescription>
|
</SettingsSectionDescription>
|
||||||
</SettingsSectionHeader>
|
</SettingsSectionHeader>
|
||||||
<SettingsSectionBody>
|
<SettingsSectionBody>
|
||||||
<SettingsSectionForm>
|
<SettingsSectionForm variant="half">
|
||||||
<PaidFeaturesAlert tiers={tierMatrix.loginPageDomain} />
|
|
||||||
|
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
action={formAction}
|
action={formAction}
|
||||||
className="space-y-4"
|
|
||||||
id="auth-page-settings-form"
|
id="auth-page-settings-form"
|
||||||
>
|
>
|
||||||
<div className="space-y-3">
|
<SettingsFormGrid>
|
||||||
<Label>{t("authPageDomain")}</Label>
|
<SettingsFormCell span="full">
|
||||||
<div className="border p-2 rounded-md flex items-center justify-between">
|
<PaidFeaturesAlert
|
||||||
<span className="text-sm text-muted-foreground flex items-center gap-2">
|
tiers={tierMatrix.loginPageDomain}
|
||||||
<Globe size="14" />
|
/>
|
||||||
{loginPage &&
|
</SettingsFormCell>
|
||||||
!loginPage.domainId ? (
|
<SettingsFormCell span="full">
|
||||||
<InfoPopup
|
<div className="space-y-3">
|
||||||
info={t(
|
<Label>{t("authPageDomain")}</Label>
|
||||||
"domainNotFoundDescription"
|
<div className="border p-2 rounded-md flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
|
||||||
|
<span className="text-sm text-muted-foreground flex items-center gap-2">
|
||||||
|
<Globe size="14" />
|
||||||
|
{loginPage &&
|
||||||
|
!loginPage.domainId ? (
|
||||||
|
<InfoPopup
|
||||||
|
info={t(
|
||||||
|
"domainNotFoundDescription"
|
||||||
|
)}
|
||||||
|
text={t(
|
||||||
|
"domainNotFound"
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
) : loginPage?.fullDomain ? (
|
||||||
|
<a
|
||||||
|
href={`${window.location.protocol}//${loginPage.fullDomain}`}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="hover:underline"
|
||||||
|
>
|
||||||
|
{`${window.location.protocol}//${loginPage.fullDomain}`}
|
||||||
|
</a>
|
||||||
|
) : form.watch(
|
||||||
|
"authPageDomainId"
|
||||||
|
) ? (
|
||||||
|
// Show selected domain from form state when no loginPage exists yet
|
||||||
|
(() => {
|
||||||
|
const selectedDomainId =
|
||||||
|
form.watch(
|
||||||
|
"authPageDomainId"
|
||||||
|
);
|
||||||
|
const selectedSubdomain =
|
||||||
|
form.watch(
|
||||||
|
"authPageSubdomain"
|
||||||
|
);
|
||||||
|
const domain =
|
||||||
|
baseDomains.find(
|
||||||
|
(d) =>
|
||||||
|
d.domainId ===
|
||||||
|
selectedDomainId
|
||||||
|
);
|
||||||
|
if (domain) {
|
||||||
|
const sanitizedSubdomain =
|
||||||
|
selectedSubdomain
|
||||||
|
? finalizeSubdomainSanitize(
|
||||||
|
selectedSubdomain
|
||||||
|
)
|
||||||
|
: "";
|
||||||
|
const fullDomain =
|
||||||
|
sanitizedSubdomain
|
||||||
|
? `${sanitizedSubdomain}.${domain.baseDomain}`
|
||||||
|
: domain.baseDomain;
|
||||||
|
return fullDomain;
|
||||||
|
}
|
||||||
|
return t(
|
||||||
|
"noDomainSet"
|
||||||
|
);
|
||||||
|
})()
|
||||||
|
) : (
|
||||||
|
t("noDomainSet")
|
||||||
)}
|
)}
|
||||||
text={t("domainNotFound")}
|
</span>
|
||||||
/>
|
<div className="flex items-center gap-2">
|
||||||
) : loginPage?.fullDomain ? (
|
<Button
|
||||||
<a
|
variant="secondary"
|
||||||
href={`${window.location.protocol}//${loginPage.fullDomain}`}
|
type="button"
|
||||||
target="_blank"
|
size="sm"
|
||||||
rel="noopener noreferrer"
|
onClick={() =>
|
||||||
className="hover:underline"
|
setEditDomainOpen(
|
||||||
>
|
true
|
||||||
{`${window.location.protocol}//${loginPage.fullDomain}`}
|
)
|
||||||
</a>
|
}
|
||||||
) : form.watch(
|
disabled={
|
||||||
"authPageDomainId"
|
!isPaidUser(
|
||||||
) ? (
|
tierMatrix.loginPageDomain
|
||||||
// Show selected domain from form state when no loginPage exists yet
|
)
|
||||||
(() => {
|
}
|
||||||
const selectedDomainId =
|
>
|
||||||
form.watch(
|
{form.watch(
|
||||||
"authPageDomainId"
|
"authPageDomainId"
|
||||||
);
|
|
||||||
const selectedSubdomain =
|
|
||||||
form.watch(
|
|
||||||
"authPageSubdomain"
|
|
||||||
);
|
|
||||||
const domain =
|
|
||||||
baseDomains.find(
|
|
||||||
(d) =>
|
|
||||||
d.domainId ===
|
|
||||||
selectedDomainId
|
|
||||||
);
|
|
||||||
if (domain) {
|
|
||||||
const sanitizedSubdomain =
|
|
||||||
selectedSubdomain
|
|
||||||
? finalizeSubdomainSanitize(
|
|
||||||
selectedSubdomain
|
|
||||||
)
|
|
||||||
: "";
|
|
||||||
const fullDomain =
|
|
||||||
sanitizedSubdomain
|
|
||||||
? `${sanitizedSubdomain}.${domain.baseDomain}`
|
|
||||||
: domain.baseDomain;
|
|
||||||
return fullDomain;
|
|
||||||
}
|
|
||||||
return t("noDomainSet");
|
|
||||||
})()
|
|
||||||
) : (
|
|
||||||
t("noDomainSet")
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<Button
|
|
||||||
variant="secondary"
|
|
||||||
type="button"
|
|
||||||
size="sm"
|
|
||||||
onClick={() =>
|
|
||||||
setEditDomainOpen(true)
|
|
||||||
}
|
|
||||||
disabled={
|
|
||||||
!isPaidUser(
|
|
||||||
tierMatrix.loginPageDomain
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{form.watch("authPageDomainId")
|
|
||||||
? t("changeDomain")
|
|
||||||
: t("selectDomain")}
|
|
||||||
</Button>
|
|
||||||
{form.watch("authPageDomainId") && (
|
|
||||||
<Button
|
|
||||||
variant="destructive"
|
|
||||||
type="button"
|
|
||||||
size="sm"
|
|
||||||
onClick={
|
|
||||||
clearAuthPageDomain
|
|
||||||
}
|
|
||||||
disabled={
|
|
||||||
!isPaidUser(
|
|
||||||
tierMatrix.loginPageDomain
|
|
||||||
)
|
)
|
||||||
}
|
? t("changeDomain")
|
||||||
>
|
: t("selectDomain")}
|
||||||
<Trash2 size="14" />
|
</Button>
|
||||||
</Button>
|
{form.watch(
|
||||||
)}
|
"authPageDomainId"
|
||||||
</div>
|
) && (
|
||||||
</div>
|
<Button
|
||||||
|
variant="destructive"
|
||||||
|
type="button"
|
||||||
|
size="sm"
|
||||||
|
onClick={
|
||||||
|
clearAuthPageDomain
|
||||||
|
}
|
||||||
|
disabled={
|
||||||
|
!isPaidUser(
|
||||||
|
tierMatrix.loginPageDomain
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Trash2 size="14" />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{!form.watch("authPageDomainId") && (
|
{!form.watch(
|
||||||
<div className="text-sm text-muted-foreground">
|
"authPageDomainId"
|
||||||
{t(
|
) && (
|
||||||
"addDomainToEnableCustomAuthPages"
|
<div className="text-sm text-muted-foreground">
|
||||||
|
{t(
|
||||||
|
"addDomainToEnableCustomAuthPages"
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{(build === "enterprise" ||
|
{(build === "enterprise" ||
|
||||||
!isPaidUser(
|
!isPaidUser(
|
||||||
tierMatrix.loginPageDomain
|
tierMatrix.loginPageDomain
|
||||||
)) &&
|
)) &&
|
||||||
loginPage?.domainId &&
|
loginPage?.domainId &&
|
||||||
loginPage?.fullDomain &&
|
loginPage?.fullDomain &&
|
||||||
!hasUnsavedChanges && (
|
!hasUnsavedChanges && (
|
||||||
<CertificateStatus
|
<CertificateStatus
|
||||||
orgId={org?.org.orgId || ""}
|
orgId={
|
||||||
domainId={loginPage.domainId}
|
org?.org.orgId || ""
|
||||||
fullDomain={
|
}
|
||||||
loginPage.fullDomain
|
domainId={
|
||||||
}
|
loginPage.domainId
|
||||||
showLabel={true}
|
}
|
||||||
polling={true}
|
fullDomain={
|
||||||
/>
|
loginPage.fullDomain
|
||||||
)}
|
}
|
||||||
</div>
|
showLabel={true}
|
||||||
|
polling={true}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</SettingsFormCell>
|
||||||
|
</SettingsFormGrid>
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
</SettingsSectionForm>
|
</SettingsSectionForm>
|
||||||
</SettingsSectionBody>
|
</SettingsSectionBody>
|
||||||
|
|
||||||
<div className="flex justify-end mt-6">
|
<SettingsSectionFooter>
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
form="auth-page-settings-form"
|
form="auth-page-settings-form"
|
||||||
@@ -435,7 +460,7 @@ function AuthPageSettings({
|
|||||||
>
|
>
|
||||||
{t("saveAuthPageDomain")}
|
{t("saveAuthPageDomain")}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</SettingsSectionFooter>
|
||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
|
|
||||||
{/* Domain Picker Modal */}
|
{/* Domain Picker Modal */}
|
||||||
|
|||||||
Reference in New Issue
Block a user