mirror of
https://github.com/fosrl/pangolin.git
synced 2026-10-17 09:19:35 +00:00
Merge branch 'dev' of github.com:fosrl/pangolin into dev
This commit is contained in:
4 files changed
+1317
-1165
No files matched your search
@@ -36,7 +36,9 @@ import {
|
||||
SettingsSectionDescription,
|
||||
SettingsSectionBody,
|
||||
SettingsSectionForm,
|
||||
SettingsSectionFooter
|
||||
SettingsSectionFooter,
|
||||
SettingsFormGrid,
|
||||
SettingsFormCell
|
||||
} from "@app/components/Settings";
|
||||
import { useUserContext } from "@app/hooks/useUserContext";
|
||||
import { useTranslations } from "next-intl";
|
||||
@@ -242,7 +244,7 @@ function GeneralSectionForm({ org }: SectionFormProps) {
|
||||
</SettingsSectionDescription>
|
||||
</SettingsSectionHeader>
|
||||
<SettingsSectionBody>
|
||||
<SettingsSectionForm>
|
||||
<SettingsSectionForm variant="half">
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
@@ -251,71 +253,86 @@ function GeneralSectionForm({ org }: SectionFormProps) {
|
||||
formAction();
|
||||
});
|
||||
}}
|
||||
className="grid gap-4"
|
||||
id="org-general-settings-form"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t("name")}</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
<FormDescription>
|
||||
{t("orgDisplayName")}
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<SettingsFormGrid>
|
||||
<SettingsFormCell span="half">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
{t("name")}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
<FormDescription>
|
||||
{t("orgDisplayName")}
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</SettingsFormCell>
|
||||
|
||||
<PaidFeaturesAlert
|
||||
tiers={tierMatrix.newtAutoUpdate}
|
||||
/>
|
||||
{!env.flags.disableEnterpriseFeatures && (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="settingsEnableGlobalNewtAutoUpdate"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<SwitchInput
|
||||
id="settings-enable-global-newt-auto-update"
|
||||
label={t("newtAutoUpdate")}
|
||||
checked={field.value}
|
||||
onCheckedChange={
|
||||
field.onChange
|
||||
}
|
||||
disabled={
|
||||
!hasAutoUpdateFeature
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
{t("newtAutoUpdateDescription")}{" "}
|
||||
<a
|
||||
href="https://docs.pangolin.net/manage/sites/auto-update"
|
||||
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 span="full">
|
||||
<PaidFeaturesAlert
|
||||
tiers={tierMatrix.newtAutoUpdate}
|
||||
/>
|
||||
</SettingsFormCell>
|
||||
{!env.flags.disableEnterpriseFeatures && (
|
||||
<SettingsFormCell span="full">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="settingsEnableGlobalNewtAutoUpdate"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<SwitchInput
|
||||
id="settings-enable-global-newt-auto-update"
|
||||
label={t(
|
||||
"newtAutoUpdate"
|
||||
)}
|
||||
checked={
|
||||
field.value
|
||||
}
|
||||
onCheckedChange={
|
||||
field.onChange
|
||||
}
|
||||
disabled={
|
||||
!hasAutoUpdateFeature
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
{t(
|
||||
"newtAutoUpdateDescription"
|
||||
)}{" "}
|
||||
<a
|
||||
href="https://docs.pangolin.net/manage/sites/auto-update"
|
||||
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>
|
||||
</SettingsSectionForm>
|
||||
</SettingsSectionBody>
|
||||
|
||||
<div className="flex justify-end gap-2 mt-4">
|
||||
<SettingsSectionFooter>
|
||||
<Button
|
||||
type="submit"
|
||||
form="org-general-settings-form"
|
||||
@@ -324,7 +341,7 @@ function GeneralSectionForm({ org }: SectionFormProps) {
|
||||
>
|
||||
{t("saveSettings")}
|
||||
</Button>
|
||||
</div>
|
||||
</SettingsSectionFooter>
|
||||
</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 z from "zod";
|
||||
import {
|
||||
SettingsFormCell,
|
||||
SettingsFormGrid,
|
||||
SettingsSection,
|
||||
SettingsSectionBody,
|
||||
SettingsSectionDescription,
|
||||
SettingsSectionFooter,
|
||||
SettingsSectionForm,
|
||||
SettingsSectionHeader,
|
||||
SettingsSectionTitle
|
||||
SettingsSectionTitle,
|
||||
SettingsSubsectionDescription,
|
||||
SettingsSubsectionHeader,
|
||||
SettingsSubsectionTitle
|
||||
} from "./Settings";
|
||||
|
||||
import { useEnvContext } from "@app/hooks/useEnvContext";
|
||||
@@ -176,89 +182,228 @@ export default function AuthPageBrandingForm({
|
||||
</SettingsSectionHeader>
|
||||
|
||||
<SettingsSectionBody>
|
||||
<SettingsSectionForm>
|
||||
<PaidFeaturesAlert
|
||||
tiers={tierMatrix.loginPageBranding}
|
||||
/>
|
||||
|
||||
<SettingsSectionForm variant="half">
|
||||
<Form {...form}>
|
||||
<form
|
||||
action={updateFormAction}
|
||||
id="auth-page-branding-form"
|
||||
className="flex flex-col space-y-4 items-stretch"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="primaryColor"
|
||||
render={({ field }) => (
|
||||
<FormItem className="">
|
||||
<FormLabel>
|
||||
{t("brandingPrimaryColor")}
|
||||
</FormLabel>
|
||||
<SettingsFormGrid>
|
||||
<SettingsFormCell span="full">
|
||||
<PaidFeaturesAlert
|
||||
tiers={tierMatrix.loginPageBranding}
|
||||
/>
|
||||
</SettingsFormCell>
|
||||
|
||||
<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>
|
||||
)}
|
||||
/>
|
||||
|
||||
<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">
|
||||
<SettingsFormCell span="half">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="logoWidth"
|
||||
name="primaryColor"
|
||||
render={({ field }) => (
|
||||
<FormItem className="grow">
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
{t("brandingLogoWidth")}
|
||||
{t(
|
||||
"brandingPrimaryColor"
|
||||
)}
|
||||
</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>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
@@ -266,19 +411,16 @@ export default function AuthPageBrandingForm({
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<span className="relative top-8">
|
||||
<XIcon className="text-muted-foreground size-4" />
|
||||
</span>
|
||||
|
||||
</SettingsFormCell>
|
||||
<SettingsFormCell span="half">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="logoHeight"
|
||||
name="resourceSubtitle"
|
||||
render={({ field }) => (
|
||||
<FormItem className="grow">
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
{t(
|
||||
"brandingLogoHeight"
|
||||
"brandingResourceSubtitle"
|
||||
)}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
@@ -288,116 +430,14 @@ export default function AuthPageBrandingForm({
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{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>
|
||||
</SettingsFormCell>
|
||||
</SettingsFormGrid>
|
||||
</form>
|
||||
</Form>
|
||||
</SettingsSectionForm>
|
||||
</SettingsSectionBody>
|
||||
|
||||
<div className="flex justify-end gap-2 mt-6 items-center">
|
||||
<SettingsSectionFooter>
|
||||
{branding && (
|
||||
<form action={deleteFormAction}>
|
||||
<Button
|
||||
@@ -427,7 +467,7 @@ export default function AuthPageBrandingForm({
|
||||
>
|
||||
{t("saveAuthPageBranding")}
|
||||
</Button>
|
||||
</div>
|
||||
</SettingsSectionFooter>
|
||||
</SettingsSection>
|
||||
</>
|
||||
);
|
||||
|
||||
+150
-125
@@ -20,7 +20,10 @@ import {
|
||||
SettingsSectionTitle,
|
||||
SettingsSectionDescription,
|
||||
SettingsSectionBody,
|
||||
SettingsSectionForm
|
||||
SettingsSectionForm,
|
||||
SettingsSectionFooter,
|
||||
SettingsFormGrid,
|
||||
SettingsFormCell
|
||||
} from "@app/components/Settings";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { GetLoginPageResponse } from "@server/routers/loginPage/types";
|
||||
@@ -284,145 +287,167 @@ function AuthPageSettings({
|
||||
</SettingsSectionDescription>
|
||||
</SettingsSectionHeader>
|
||||
<SettingsSectionBody>
|
||||
<SettingsSectionForm>
|
||||
<PaidFeaturesAlert tiers={tierMatrix.loginPageDomain} />
|
||||
|
||||
<SettingsSectionForm variant="half">
|
||||
<Form {...form}>
|
||||
<form
|
||||
action={formAction}
|
||||
className="space-y-4"
|
||||
id="auth-page-settings-form"
|
||||
>
|
||||
<div className="space-y-3">
|
||||
<Label>{t("authPageDomain")}</Label>
|
||||
<div className="border p-2 rounded-md flex items-center justify-between">
|
||||
<span className="text-sm text-muted-foreground flex items-center gap-2">
|
||||
<Globe size="14" />
|
||||
{loginPage &&
|
||||
!loginPage.domainId ? (
|
||||
<InfoPopup
|
||||
info={t(
|
||||
"domainNotFoundDescription"
|
||||
<SettingsFormGrid>
|
||||
<SettingsFormCell span="full">
|
||||
<PaidFeaturesAlert
|
||||
tiers={tierMatrix.loginPageDomain}
|
||||
/>
|
||||
</SettingsFormCell>
|
||||
<SettingsFormCell span="full">
|
||||
<div className="space-y-3">
|
||||
<Label>{t("authPageDomain")}</Label>
|
||||
<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")}
|
||||
/>
|
||||
) : 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(
|
||||
</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"
|
||||
);
|
||||
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
|
||||
)
|
||||
}
|
||||
>
|
||||
<Trash2 size="14" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
? t("changeDomain")
|
||||
: t("selectDomain")}
|
||||
</Button>
|
||||
{form.watch(
|
||||
"authPageDomainId"
|
||||
) && (
|
||||
<Button
|
||||
variant="destructive"
|
||||
type="button"
|
||||
size="sm"
|
||||
onClick={
|
||||
clearAuthPageDomain
|
||||
}
|
||||
disabled={
|
||||
!isPaidUser(
|
||||
tierMatrix.loginPageDomain
|
||||
)
|
||||
}
|
||||
>
|
||||
<Trash2 size="14" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!form.watch("authPageDomainId") && (
|
||||
<div className="text-sm text-muted-foreground">
|
||||
{t(
|
||||
"addDomainToEnableCustomAuthPages"
|
||||
{!form.watch(
|
||||
"authPageDomainId"
|
||||
) && (
|
||||
<div className="text-sm text-muted-foreground">
|
||||
{t(
|
||||
"addDomainToEnableCustomAuthPages"
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{(build === "enterprise" ||
|
||||
!isPaidUser(
|
||||
tierMatrix.loginPageDomain
|
||||
)) &&
|
||||
loginPage?.domainId &&
|
||||
loginPage?.fullDomain &&
|
||||
!hasUnsavedChanges && (
|
||||
<CertificateStatus
|
||||
orgId={org?.org.orgId || ""}
|
||||
domainId={loginPage.domainId}
|
||||
fullDomain={
|
||||
loginPage.fullDomain
|
||||
}
|
||||
showLabel={true}
|
||||
polling={true}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{(build === "enterprise" ||
|
||||
!isPaidUser(
|
||||
tierMatrix.loginPageDomain
|
||||
)) &&
|
||||
loginPage?.domainId &&
|
||||
loginPage?.fullDomain &&
|
||||
!hasUnsavedChanges && (
|
||||
<CertificateStatus
|
||||
orgId={
|
||||
org?.org.orgId || ""
|
||||
}
|
||||
domainId={
|
||||
loginPage.domainId
|
||||
}
|
||||
fullDomain={
|
||||
loginPage.fullDomain
|
||||
}
|
||||
showLabel={true}
|
||||
polling={true}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</SettingsFormCell>
|
||||
</SettingsFormGrid>
|
||||
</form>
|
||||
</Form>
|
||||
</SettingsSectionForm>
|
||||
</SettingsSectionBody>
|
||||
|
||||
<div className="flex justify-end mt-6">
|
||||
<SettingsSectionFooter>
|
||||
<Button
|
||||
type="submit"
|
||||
form="auth-page-settings-form"
|
||||
@@ -435,7 +460,7 @@ function AuthPageSettings({
|
||||
>
|
||||
{t("saveAuthPageDomain")}
|
||||
</Button>
|
||||
</div>
|
||||
</SettingsSectionFooter>
|
||||
</SettingsSection>
|
||||
|
||||
{/* Domain Picker Modal */}
|
||||
|
||||
Reference in new issue
Block a user