mirror of
https://github.com/fosrl/pangolin.git
synced 2026-06-10 17:43:15 +00:00
fix form responsiveness
This commit is contained in:
@@ -17,7 +17,8 @@ import {
|
||||
SettingsSectionTitle,
|
||||
SettingsSectionDescription,
|
||||
SettingsSectionBody,
|
||||
SettingsSectionFooter
|
||||
SettingsSectionFooter,
|
||||
SettingsSectionForm
|
||||
} from "@app/components/Settings";
|
||||
import {
|
||||
InfoSection,
|
||||
@@ -1326,44 +1327,46 @@ export default function BillingPage() {
|
||||
</SettingsSectionDescription>
|
||||
</SettingsSectionHeader>
|
||||
<SettingsSectionBody>
|
||||
<SettingsFormGrid>
|
||||
<SettingsFormCell span="half">
|
||||
<div className="flex flex-col md:flex-row items-start md:items-center justify-between gap-4 border rounded-lg p-4">
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground mb-1">
|
||||
{t("billingCurrentKeys") ||
|
||||
"Current Keys"}
|
||||
</div>
|
||||
<div className="flex items-baseline gap-2">
|
||||
<span className="text-3xl font-semibold">
|
||||
{getLicenseKeyCount()}
|
||||
</span>
|
||||
<span className="text-lg">
|
||||
{getLicenseKeyCount() === 1
|
||||
? "key"
|
||||
: "keys"}
|
||||
</span>
|
||||
<SettingsSectionForm variant="half">
|
||||
<SettingsFormGrid>
|
||||
<SettingsFormCell span="full">
|
||||
<div className="flex flex-col md:flex-row items-start md:items-center justify-between gap-4 border rounded-lg p-4">
|
||||
<div>
|
||||
<div className="text-sm text-muted-foreground mb-1">
|
||||
{t("billingCurrentKeys") ||
|
||||
"Current Keys"}
|
||||
</div>
|
||||
<div className="flex items-baseline gap-2">
|
||||
<span className="text-3xl font-semibold">
|
||||
{getLicenseKeyCount()}
|
||||
</span>
|
||||
<span className="text-lg">
|
||||
{getLicenseKeyCount() === 1
|
||||
? "key"
|
||||
: "keys"}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={handleModifySubscription}
|
||||
disabled={isLoading}
|
||||
loading={isLoading}
|
||||
>
|
||||
<CreditCard className="mr-2 h-4 w-4" />
|
||||
{t("billingModifyCurrentPlan") ||
|
||||
"Modify Current Plan"}
|
||||
</Button>
|
||||
<p className="text-sm text-muted-foreground mt-2">
|
||||
{t(
|
||||
"billingManageLicenseSubscriptionDescription"
|
||||
) ||
|
||||
"Manage your subscription for paid self-hosted license keys and download invoices."}
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={handleModifySubscription}
|
||||
disabled={isLoading}
|
||||
loading={isLoading}
|
||||
>
|
||||
<CreditCard className="mr-2 h-4 w-4" />
|
||||
{t("billingModifyCurrentPlan") ||
|
||||
"Modify Current Plan"}
|
||||
</Button>
|
||||
<p className="text-sm text-muted-foreground mt-2">
|
||||
{t(
|
||||
"billingManageLicenseSubscriptionDescription"
|
||||
) ||
|
||||
"Manage your subscription for paid self-hosted license keys and download invoices."}
|
||||
</p>
|
||||
</div>
|
||||
</SettingsFormCell>
|
||||
</SettingsFormGrid>
|
||||
</SettingsFormCell>
|
||||
</SettingsFormGrid>
|
||||
</SettingsSectionForm>
|
||||
</SettingsSectionBody>
|
||||
</SettingsSection>
|
||||
)}
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
SettingsSection,
|
||||
SettingsSectionBody,
|
||||
SettingsSectionDescription,
|
||||
SettingsSectionForm,
|
||||
SettingsSectionHeader,
|
||||
SettingsSectionTitle
|
||||
} from "@app/components/Settings";
|
||||
@@ -252,96 +253,102 @@ export default function Page() {
|
||||
</SettingsSectionTitle>
|
||||
</SettingsSectionHeader>
|
||||
<SettingsSectionBody>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault(); // block default enter refresh
|
||||
}
|
||||
}}
|
||||
id="create-client-form"
|
||||
>
|
||||
<SettingsFormGrid>
|
||||
<SettingsFormCell span="quarter">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
{t("name")}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
autoComplete="off"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
<FormDescription>
|
||||
{t(
|
||||
"clientNameDescription"
|
||||
)}
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</SettingsFormCell>
|
||||
<SettingsFormCell span="full">
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() =>
|
||||
setShowAdvancedSettings(
|
||||
!showAdvancedSettings
|
||||
)
|
||||
}
|
||||
className="flex items-center gap-2 -ml-3"
|
||||
>
|
||||
{showAdvancedSettings ? (
|
||||
<ChevronUp className="h-4 w-4" />
|
||||
) : (
|
||||
<ChevronDown className="h-4 w-4" />
|
||||
)}
|
||||
{t("advancedSettings")}
|
||||
</Button>
|
||||
</SettingsFormCell>
|
||||
{showAdvancedSettings && (
|
||||
<SettingsFormCell span="quarter">
|
||||
<SettingsSectionForm variant="half">
|
||||
<Form {...form}>
|
||||
<form
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault(); // block default enter refresh
|
||||
}
|
||||
}}
|
||||
id="create-client-form"
|
||||
>
|
||||
<SettingsFormGrid>
|
||||
<SettingsFormCell span="half">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="subnet"
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
{t(
|
||||
"clientAddress"
|
||||
)}
|
||||
{t("name")}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
autoComplete="off"
|
||||
placeholder={t(
|
||||
"subnetPlaceholder"
|
||||
)}
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
<FormDescription>
|
||||
{t(
|
||||
"addressDescription"
|
||||
"clientNameDescription"
|
||||
)}
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</SettingsFormCell>
|
||||
)}
|
||||
</SettingsFormGrid>
|
||||
</form>
|
||||
</Form>
|
||||
<SettingsFormCell span="full">
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() =>
|
||||
setShowAdvancedSettings(
|
||||
!showAdvancedSettings
|
||||
)
|
||||
}
|
||||
className="flex items-center gap-2 -ml-3"
|
||||
>
|
||||
{showAdvancedSettings ? (
|
||||
<ChevronUp className="h-4 w-4" />
|
||||
) : (
|
||||
<ChevronDown className="h-4 w-4" />
|
||||
)}
|
||||
{t("advancedSettings")}
|
||||
</Button>
|
||||
</SettingsFormCell>
|
||||
{showAdvancedSettings && (
|
||||
<SettingsFormCell span="half">
|
||||
<FormField
|
||||
control={
|
||||
form.control
|
||||
}
|
||||
name="subnet"
|
||||
render={({
|
||||
field
|
||||
}) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
{t(
|
||||
"clientAddress"
|
||||
)}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
autoComplete="off"
|
||||
placeholder={t(
|
||||
"subnetPlaceholder"
|
||||
)}
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
<FormDescription>
|
||||
{t(
|
||||
"addressDescription"
|
||||
)}
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</SettingsFormCell>
|
||||
)}
|
||||
</SettingsFormGrid>
|
||||
</form>
|
||||
</Form>
|
||||
</SettingsSectionForm>
|
||||
</SettingsSectionBody>
|
||||
</SettingsSection>
|
||||
|
||||
|
||||
@@ -243,7 +243,7 @@ function ProxyResourceProtocolForm({
|
||||
{proxySettingsForm.watch("proxyProtocol") && (
|
||||
<>
|
||||
<SettingsFormCell span="full">
|
||||
<Alert className="[&>svg]:self-start">
|
||||
<Alert className="[&>svg]:self-start" variant="neutral">
|
||||
<AlertTriangle className="h-4 w-4" />
|
||||
<AlertDescription>
|
||||
<strong>
|
||||
|
||||
@@ -1454,7 +1454,8 @@ export default function Page() {
|
||||
</SettingsSectionDescription>
|
||||
</SettingsSectionHeader>
|
||||
<SettingsSectionBody>
|
||||
<SettingsFormGrid>
|
||||
<SettingsSectionForm variant="half">
|
||||
<SettingsFormGrid>
|
||||
<SettingsFormCell span="full">
|
||||
<SettingsSubsectionHeader>
|
||||
<SettingsSubsectionTitle>
|
||||
@@ -1496,6 +1497,7 @@ export default function Page() {
|
||||
/>
|
||||
</SettingsFormCell>
|
||||
</SettingsFormGrid>
|
||||
</SettingsSectionForm>
|
||||
</SettingsSectionBody>
|
||||
</SettingsSection>
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
SettingsSection,
|
||||
SettingsSectionBody,
|
||||
SettingsSectionDescription,
|
||||
SettingsSectionForm,
|
||||
SettingsSectionHeader,
|
||||
SettingsSectionTitle
|
||||
} from "@app/components/Settings";
|
||||
@@ -507,121 +508,122 @@ export default function Page() {
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
<Form {...form}>
|
||||
<form
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault(); // block default enter refresh
|
||||
}
|
||||
}}
|
||||
id="create-site-form"
|
||||
>
|
||||
<SettingsFormGrid>
|
||||
<SettingsFormCell span="quarter">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
{t("name")}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
autoComplete="off"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
<FormDescription>
|
||||
{t(
|
||||
"siteNameDescription"
|
||||
)}
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</SettingsFormCell>
|
||||
{form.watch("method") ===
|
||||
"newt" && (
|
||||
<>
|
||||
<SettingsFormCell span="full">
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() =>
|
||||
setShowAdvancedSettings(
|
||||
!showAdvancedSettings
|
||||
)
|
||||
}
|
||||
className="mt-2 flex items-center gap-2 -ml-3"
|
||||
>
|
||||
{showAdvancedSettings ? (
|
||||
<ChevronUp className="h-4 w-4" />
|
||||
) : (
|
||||
<ChevronDown className="h-4 w-4" />
|
||||
)}
|
||||
{t(
|
||||
"advancedSettings"
|
||||
)}
|
||||
</Button>
|
||||
</SettingsFormCell>
|
||||
{showAdvancedSettings && (
|
||||
<SettingsFormCell span="quarter">
|
||||
<FormField
|
||||
control={
|
||||
form.control
|
||||
<SettingsSectionForm variant="half">
|
||||
<Form {...form}>
|
||||
<form
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault(); // block default enter refresh
|
||||
}
|
||||
}}
|
||||
id="create-site-form"
|
||||
>
|
||||
<SettingsFormGrid>
|
||||
<SettingsFormCell span="half">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
{t("name")}w
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
autoComplete="off"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
<FormDescription>
|
||||
{t(
|
||||
"siteNameDescription"
|
||||
)}
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</SettingsFormCell>
|
||||
{form.watch("method") ===
|
||||
"newt" && (
|
||||
<>
|
||||
<SettingsFormCell span="full">
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() =>
|
||||
setShowAdvancedSettings(
|
||||
!showAdvancedSettings
|
||||
)
|
||||
}
|
||||
name="clientAddress"
|
||||
render={({
|
||||
field
|
||||
}) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
{t(
|
||||
"siteAddress"
|
||||
)}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
autoComplete="off"
|
||||
value={
|
||||
clientAddress
|
||||
}
|
||||
onChange={(
|
||||
e
|
||||
) => {
|
||||
setClientAddress(
|
||||
e
|
||||
.target
|
||||
.value
|
||||
);
|
||||
field.onChange(
|
||||
e
|
||||
.target
|
||||
.value
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
<FormDescription>
|
||||
{t(
|
||||
"siteAddressDescription"
|
||||
)}
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
className="mt-2 flex items-center gap-2 -ml-3"
|
||||
>
|
||||
{showAdvancedSettings ? (
|
||||
<ChevronUp className="h-4 w-4" />
|
||||
) : (
|
||||
<ChevronDown className="h-4 w-4" />
|
||||
)}
|
||||
/>
|
||||
{t(
|
||||
"advancedSettings"
|
||||
)}
|
||||
</Button>
|
||||
</SettingsFormCell>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</SettingsFormGrid>
|
||||
</form>
|
||||
</Form>
|
||||
{showAdvancedSettings && (
|
||||
<SettingsFormCell span="quarter">
|
||||
<FormField
|
||||
control={
|
||||
form.control
|
||||
}
|
||||
name="clientAddress"
|
||||
render={({
|
||||
field
|
||||
}) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
{t(
|
||||
"siteAddress"
|
||||
)}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
autoComplete="off"
|
||||
value={
|
||||
clientAddress
|
||||
}
|
||||
onChange={(
|
||||
e
|
||||
) => {
|
||||
setClientAddress(
|
||||
e
|
||||
.target
|
||||
.value
|
||||
);
|
||||
field.onChange(
|
||||
e
|
||||
.target
|
||||
.value
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
<FormDescription>
|
||||
{t(
|
||||
"siteAddressDescription"
|
||||
)}
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</SettingsFormCell>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</SettingsFormGrid>
|
||||
</form>
|
||||
</Form>
|
||||
</SettingsSectionForm>
|
||||
</SettingsSectionBody>
|
||||
</SettingsSection>
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
SettingsSection,
|
||||
SettingsSectionBody,
|
||||
SettingsSectionDescription,
|
||||
SettingsSectionForm,
|
||||
SettingsSectionHeader,
|
||||
SettingsSectionTitle
|
||||
} from "@app/components/Settings";
|
||||
@@ -200,25 +201,27 @@ export function CreatePolicyForm({}: CreatePolicyFormProps) {
|
||||
</SettingsSectionDescription>
|
||||
</SettingsSectionHeader>
|
||||
<SettingsSectionBody>
|
||||
<SettingsFormGrid>
|
||||
<SettingsFormCell span="quarter">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
{t("name")}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</SettingsFormCell>
|
||||
</SettingsFormGrid>
|
||||
<SettingsSectionForm variant="half">
|
||||
<SettingsFormGrid>
|
||||
<SettingsFormCell span="half">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
{t("name")}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</SettingsFormCell>
|
||||
</SettingsFormGrid>
|
||||
</SettingsSectionForm>
|
||||
</SettingsSectionBody>
|
||||
</SettingsSection>
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
SettingsSectionBody,
|
||||
SettingsSectionDescription,
|
||||
SettingsSectionFooter,
|
||||
SettingsSectionForm,
|
||||
SettingsSectionHeader,
|
||||
SettingsSectionTitle
|
||||
} from "@app/components/Settings";
|
||||
@@ -148,10 +149,10 @@ function PolicyAccessRulesSectionLayout({
|
||||
</SettingsSectionDescription>
|
||||
</SettingsSectionHeader>
|
||||
<SettingsSectionBody>
|
||||
{resourceOverlayMode && (
|
||||
<SharedPolicyResourceNotice section="rules" />
|
||||
)}
|
||||
<div className="space-y-4">
|
||||
{resourceOverlayMode && (
|
||||
<SharedPolicyResourceNotice section="rules" />
|
||||
)}
|
||||
<PolicyAccessRulesIntro
|
||||
rulesEnabled={rulesEnabled}
|
||||
onRulesEnabledChange={onRulesEnabledChange}
|
||||
|
||||
120
src/components/resource-policy/PolicyAuthOtherMethodsSection.tsx
Normal file
120
src/components/resource-policy/PolicyAuthOtherMethodsSection.tsx
Normal file
@@ -0,0 +1,120 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
SettingsFormCell,
|
||||
SettingsFormGrid,
|
||||
SettingsSubsectionDescription,
|
||||
SettingsSubsectionHeader,
|
||||
SettingsSubsectionTitle
|
||||
} from "@app/components/Settings";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { PolicyAuthMethodRow } from "./PolicyAuthMethodRow";
|
||||
import type { PolicyAuthMethodId } from "./policy-auth-method-id";
|
||||
import {
|
||||
getEmailWhitelistSummary,
|
||||
getHeaderAuthSummary,
|
||||
getPasscodeSummary,
|
||||
getPincodeSummary
|
||||
} from "./policy-auth-summaries";
|
||||
|
||||
export type PolicyAuthOtherMethodsSectionProps = {
|
||||
pinActive: boolean;
|
||||
passcodeActive: boolean;
|
||||
emailWhitelistEnabled: boolean;
|
||||
headerAuthActive: boolean;
|
||||
headerAuthUser: string;
|
||||
emailCount: number;
|
||||
emailEnabled: boolean;
|
||||
disabled?: boolean;
|
||||
onConfigure: (method: PolicyAuthMethodId) => void;
|
||||
onTogglePincode: (active: boolean) => void;
|
||||
onTogglePasscode: (active: boolean) => void;
|
||||
onToggleEmail: (active: boolean) => void;
|
||||
onToggleHeaderAuth: (active: boolean) => void;
|
||||
};
|
||||
|
||||
export function PolicyAuthOtherMethodsSection({
|
||||
pinActive,
|
||||
passcodeActive,
|
||||
emailWhitelistEnabled,
|
||||
headerAuthActive,
|
||||
headerAuthUser,
|
||||
emailCount,
|
||||
emailEnabled,
|
||||
disabled,
|
||||
onConfigure,
|
||||
onTogglePincode,
|
||||
onTogglePasscode,
|
||||
onToggleEmail,
|
||||
onToggleHeaderAuth
|
||||
}: PolicyAuthOtherMethodsSectionProps) {
|
||||
const t = useTranslations();
|
||||
|
||||
return (
|
||||
<SettingsFormGrid>
|
||||
<SettingsFormCell span="full">
|
||||
<SettingsSubsectionHeader>
|
||||
<SettingsSubsectionTitle>
|
||||
{t("policyAuthOtherMethodsTitle")}
|
||||
</SettingsSubsectionTitle>
|
||||
<SettingsSubsectionDescription>
|
||||
{t("policyAuthOtherMethodsDescription")}
|
||||
</SettingsSubsectionDescription>
|
||||
</SettingsSubsectionHeader>
|
||||
</SettingsFormCell>
|
||||
<SettingsFormCell span="full">
|
||||
<div className="flex flex-col gap-3">
|
||||
<PolicyAuthMethodRow
|
||||
id="pincode"
|
||||
title={t("policyAuthPincodeTitle")}
|
||||
description={t("policyAuthPincodeDescription")}
|
||||
summary={getPincodeSummary({ t })}
|
||||
active={pinActive}
|
||||
onConfigure={() => onConfigure("pincode")}
|
||||
onToggle={onTogglePincode}
|
||||
disabled={disabled}
|
||||
/>
|
||||
|
||||
<PolicyAuthMethodRow
|
||||
id="passcode"
|
||||
title={t("policyAuthPasscodeTitle")}
|
||||
description={t("policyAuthPasscodeDescription")}
|
||||
summary={getPasscodeSummary({ t })}
|
||||
active={passcodeActive}
|
||||
onConfigure={() => onConfigure("passcode")}
|
||||
onToggle={onTogglePasscode}
|
||||
disabled={disabled}
|
||||
/>
|
||||
|
||||
<PolicyAuthMethodRow
|
||||
id="email"
|
||||
title={t("policyAuthEmailTitle")}
|
||||
description={t("policyAuthEmailDescription")}
|
||||
summary={getEmailWhitelistSummary({
|
||||
t,
|
||||
count: emailCount
|
||||
})}
|
||||
active={emailWhitelistEnabled}
|
||||
onConfigure={() => onConfigure("email")}
|
||||
onToggle={onToggleEmail}
|
||||
disabled={disabled || !emailEnabled}
|
||||
/>
|
||||
|
||||
<PolicyAuthMethodRow
|
||||
id="header-auth"
|
||||
title={t("policyAuthHeaderAuthTitle")}
|
||||
description={t("policyAuthHeaderAuthDescription")}
|
||||
summary={getHeaderAuthSummary({
|
||||
t,
|
||||
headerName: headerAuthUser
|
||||
})}
|
||||
active={headerAuthActive}
|
||||
onConfigure={() => onConfigure("headerAuth")}
|
||||
onToggle={onToggleHeaderAuth}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</div>
|
||||
</SettingsFormCell>
|
||||
</SettingsFormGrid>
|
||||
);
|
||||
}
|
||||
@@ -1,10 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
SettingsFormCell,
|
||||
SettingsFormGrid,
|
||||
SettingsSectionForm
|
||||
} from "@app/components/Settings";
|
||||
import { SettingsFormCell, SettingsFormGrid } from "@app/components/Settings";
|
||||
import { SwitchInput } from "@app/components/SwitchInput";
|
||||
import { Button } from "@app/components/ui/button";
|
||||
import {
|
||||
@@ -58,106 +54,100 @@ export function PolicyAuthSsoSection({
|
||||
const idpSelectDisabled = idpDisabled ?? disabled;
|
||||
|
||||
return (
|
||||
<SettingsSectionForm variant="half">
|
||||
<SettingsFormGrid>
|
||||
<SettingsFormCell span="full">
|
||||
<SwitchInput
|
||||
id="policy-auth-sso"
|
||||
label={t("policyAuthSsoTitle")}
|
||||
description={t("policyAuthSsoDescription")}
|
||||
checked={sso}
|
||||
disabled={disabled}
|
||||
onCheckedChange={onSsoChange}
|
||||
/>
|
||||
</SettingsFormCell>
|
||||
<SettingsFormGrid>
|
||||
<SettingsFormCell span="full">
|
||||
<SwitchInput
|
||||
id="policy-auth-sso"
|
||||
label={t("policyAuthSsoTitle")}
|
||||
description={t("policyAuthSsoDescription")}
|
||||
checked={sso}
|
||||
disabled={disabled}
|
||||
onCheckedChange={onSsoChange}
|
||||
/>
|
||||
</SettingsFormCell>
|
||||
|
||||
{sso && (
|
||||
<>
|
||||
<SettingsFormCell span="full">
|
||||
<FormItem>
|
||||
<FormLabel>{t("roles")}</FormLabel>
|
||||
{rolesEditor}
|
||||
</FormItem>
|
||||
</SettingsFormCell>
|
||||
<SettingsFormCell span="full">
|
||||
<FormItem>
|
||||
<FormLabel>{t("users")}</FormLabel>
|
||||
{usersEditor}
|
||||
</FormItem>
|
||||
</SettingsFormCell>
|
||||
{allIdps.length > 0 && (
|
||||
<SettingsFormCell span="half">
|
||||
{skipToIdpId == null && !showIdpSelect ? (
|
||||
<Button
|
||||
type="button"
|
||||
variant="text"
|
||||
size="sm"
|
||||
className="h-auto px-0"
|
||||
{sso && (
|
||||
<>
|
||||
<SettingsFormCell span="full">
|
||||
<FormItem>
|
||||
<FormLabel>{t("roles")}</FormLabel>
|
||||
{rolesEditor}
|
||||
</FormItem>
|
||||
</SettingsFormCell>
|
||||
<SettingsFormCell span="full">
|
||||
<FormItem>
|
||||
<FormLabel>{t("users")}</FormLabel>
|
||||
{usersEditor}
|
||||
</FormItem>
|
||||
</SettingsFormCell>
|
||||
{allIdps.length > 0 && (
|
||||
<SettingsFormCell span="half">
|
||||
{skipToIdpId == null && !showIdpSelect ? (
|
||||
<Button
|
||||
type="button"
|
||||
variant="text"
|
||||
size="sm"
|
||||
className="h-auto px-0"
|
||||
disabled={idpSelectDisabled}
|
||||
onClick={() => setShowIdpSelect(true)}
|
||||
>
|
||||
{t("policyAuthAddDefaultIdentityProvider")}
|
||||
</Button>
|
||||
) : (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
{t("defaultIdentityProvider")}
|
||||
</FormLabel>
|
||||
<Select
|
||||
disabled={idpSelectDisabled}
|
||||
onClick={() => setShowIdpSelect(true)}
|
||||
>
|
||||
{t(
|
||||
"policyAuthAddDefaultIdentityProvider"
|
||||
)}
|
||||
</Button>
|
||||
) : (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
{t("defaultIdentityProvider")}
|
||||
</FormLabel>
|
||||
<Select
|
||||
disabled={idpSelectDisabled}
|
||||
onValueChange={(value) => {
|
||||
if (value === "none") {
|
||||
onSkipToIdpChange(null);
|
||||
setShowIdpSelect(false);
|
||||
return;
|
||||
}
|
||||
onSkipToIdpChange(
|
||||
parseInt(value)
|
||||
);
|
||||
}}
|
||||
value={
|
||||
skipToIdpId
|
||||
? skipToIdpId.toString()
|
||||
: "none"
|
||||
onValueChange={(value) => {
|
||||
if (value === "none") {
|
||||
onSkipToIdpChange(null);
|
||||
setShowIdpSelect(false);
|
||||
return;
|
||||
}
|
||||
>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue
|
||||
placeholder={t(
|
||||
"selectIdpPlaceholder"
|
||||
)}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
<SelectItem value="none">
|
||||
{t("none")}
|
||||
onSkipToIdpChange(parseInt(value));
|
||||
}}
|
||||
value={
|
||||
skipToIdpId
|
||||
? skipToIdpId.toString()
|
||||
: "none"
|
||||
}
|
||||
>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue
|
||||
placeholder={t(
|
||||
"selectIdpPlaceholder"
|
||||
)}
|
||||
/>
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
<SelectItem value="none">
|
||||
{t("none")}
|
||||
</SelectItem>
|
||||
{allIdps.map((idp) => (
|
||||
<SelectItem
|
||||
key={idp.id}
|
||||
value={idp.id.toString()}
|
||||
>
|
||||
{idp.text}
|
||||
</SelectItem>
|
||||
{allIdps.map((idp) => (
|
||||
<SelectItem
|
||||
key={idp.id}
|
||||
value={idp.id.toString()}
|
||||
>
|
||||
{idp.text}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormDescription>
|
||||
{t(
|
||||
"defaultIdentityProviderDescription"
|
||||
)}
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
)}
|
||||
</SettingsFormCell>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</SettingsFormGrid>
|
||||
</SettingsSectionForm>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormDescription>
|
||||
{t(
|
||||
"defaultIdentityProviderDescription"
|
||||
)}
|
||||
</FormDescription>
|
||||
</FormItem>
|
||||
)}
|
||||
</SettingsFormCell>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</SettingsFormGrid>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
SettingsFormCell,
|
||||
SettingsFormGrid,
|
||||
SettingsSection,
|
||||
SettingsSectionBody,
|
||||
SettingsSectionDescription,
|
||||
SettingsSectionForm,
|
||||
SettingsSectionHeader,
|
||||
SettingsSubsectionDescription,
|
||||
SettingsSubsectionHeader,
|
||||
SettingsSubsectionTitle,
|
||||
SettingsSectionTitle
|
||||
} from "@app/components/Settings";
|
||||
import { RolesSelector } from "@app/components/roles-selector";
|
||||
@@ -25,15 +21,9 @@ import {
|
||||
PasscodeCredenza,
|
||||
PincodeCredenza
|
||||
} from "./PolicyAuthMethodCredenzas";
|
||||
import { PolicyAuthMethodRow } from "./PolicyAuthMethodRow";
|
||||
import { PolicyAuthOtherMethodsSection } from "./PolicyAuthOtherMethodsSection";
|
||||
import { PolicyAuthSsoSection } from "./PolicyAuthSsoSection";
|
||||
import type { PolicyAuthMethodId } from "./policy-auth-method-id";
|
||||
import {
|
||||
getEmailWhitelistSummary,
|
||||
getHeaderAuthSummary,
|
||||
getPasscodeSummary,
|
||||
getPincodeSummary
|
||||
} from "./policy-auth-summaries";
|
||||
|
||||
export type PolicyAuthStackSectionCreateProps = {
|
||||
form: UseFormReturn<PolicyFormValues, any, any>;
|
||||
@@ -105,144 +95,90 @@ export function PolicyAuthStackSectionCreate({
|
||||
</SettingsSectionDescription>
|
||||
</SettingsSectionHeader>
|
||||
<SettingsSectionBody>
|
||||
<SettingsFormGrid>
|
||||
<SettingsFormCell span="half">
|
||||
<PolicyAuthSsoSection
|
||||
sso={Boolean(sso)}
|
||||
onSsoChange={(active) =>
|
||||
parentForm.setValue("sso", active)
|
||||
}
|
||||
skipToIdpId={skipToIdpId}
|
||||
onSkipToIdpChange={(id) =>
|
||||
parentForm.setValue("skipToIdpId", id)
|
||||
}
|
||||
allIdps={allIdps}
|
||||
rolesEditor={
|
||||
<FormField<PolicyFormValues, "roles">
|
||||
control={parentForm.control}
|
||||
name="roles"
|
||||
render={({ field }) => (
|
||||
<RolesSelector
|
||||
orgId={orgId}
|
||||
selectedRoles={field.value}
|
||||
onSelectRoles={(selected) =>
|
||||
parentForm.setValue(
|
||||
"roles",
|
||||
selected
|
||||
)
|
||||
}
|
||||
restrictAdminRole
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
}
|
||||
usersEditor={
|
||||
<FormField<PolicyFormValues, "users">
|
||||
control={parentForm.control}
|
||||
name="users"
|
||||
render={({ field }) => (
|
||||
<UsersSelector
|
||||
orgId={orgId}
|
||||
selectedUsers={field.value}
|
||||
onSelectUsers={(selected) =>
|
||||
parentForm.setValue(
|
||||
"users",
|
||||
selected
|
||||
)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</SettingsFormCell>
|
||||
</SettingsFormGrid>
|
||||
|
||||
<SettingsFormGrid>
|
||||
<SettingsFormCell span="full">
|
||||
<SettingsSubsectionHeader>
|
||||
<SettingsSubsectionTitle>
|
||||
{t("policyAuthOtherMethodsTitle")}
|
||||
</SettingsSubsectionTitle>
|
||||
<SettingsSubsectionDescription>
|
||||
{t("policyAuthOtherMethodsDescription")}
|
||||
</SettingsSubsectionDescription>
|
||||
</SettingsSubsectionHeader>
|
||||
</SettingsFormCell>
|
||||
<SettingsFormCell span="half">
|
||||
<div className="flex flex-col gap-3">
|
||||
<PolicyAuthMethodRow
|
||||
id="pincode"
|
||||
title={t("policyAuthPincodeTitle")}
|
||||
description={t("policyAuthPincodeDescription")}
|
||||
summary={getPincodeSummary({ t })}
|
||||
active={pinActive}
|
||||
onConfigure={() => setEditingMethod("pincode")}
|
||||
onToggle={(active) =>
|
||||
handleToggle("pincode", active, () =>
|
||||
parentForm.setValue("pincode", null)
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||
<PolicyAuthMethodRow
|
||||
id="passcode"
|
||||
title={t("policyAuthPasscodeTitle")}
|
||||
description={t("policyAuthPasscodeDescription")}
|
||||
summary={getPasscodeSummary({ t })}
|
||||
active={passcodeActive}
|
||||
onConfigure={() => setEditingMethod("passcode")}
|
||||
onToggle={(active) =>
|
||||
handleToggle("passcode", active, () =>
|
||||
parentForm.setValue("password", null)
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||
<PolicyAuthMethodRow
|
||||
id="email"
|
||||
title={t("policyAuthEmailTitle")}
|
||||
description={t("policyAuthEmailDescription")}
|
||||
summary={getEmailWhitelistSummary({
|
||||
t,
|
||||
count: emails.length
|
||||
})}
|
||||
active={Boolean(emailWhitelistEnabled)}
|
||||
onConfigure={() => setEditingMethod("email")}
|
||||
onToggle={(active) =>
|
||||
handleToggle("email", active, () =>
|
||||
parentForm.setValue(
|
||||
"emailWhitelistEnabled",
|
||||
false
|
||||
)
|
||||
)
|
||||
}
|
||||
disabled={!emailEnabled}
|
||||
/>
|
||||
|
||||
<PolicyAuthMethodRow
|
||||
id="header-auth"
|
||||
title={t("policyAuthHeaderAuthTitle")}
|
||||
description={t(
|
||||
"policyAuthHeaderAuthDescription"
|
||||
<SettingsSectionForm variant="half">
|
||||
<PolicyAuthSsoSection
|
||||
sso={Boolean(sso)}
|
||||
onSsoChange={(active) =>
|
||||
parentForm.setValue("sso", active)
|
||||
}
|
||||
skipToIdpId={skipToIdpId}
|
||||
onSkipToIdpChange={(id) =>
|
||||
parentForm.setValue("skipToIdpId", id)
|
||||
}
|
||||
allIdps={allIdps}
|
||||
rolesEditor={
|
||||
<FormField<PolicyFormValues, "roles">
|
||||
control={parentForm.control}
|
||||
name="roles"
|
||||
render={({ field }) => (
|
||||
<RolesSelector
|
||||
orgId={orgId}
|
||||
selectedRoles={field.value}
|
||||
onSelectRoles={(selected) =>
|
||||
parentForm.setValue(
|
||||
"roles",
|
||||
selected
|
||||
)
|
||||
}
|
||||
restrictAdminRole
|
||||
/>
|
||||
)}
|
||||
summary={getHeaderAuthSummary({
|
||||
t,
|
||||
headerName: headerAuth?.user ?? ""
|
||||
})}
|
||||
active={headerAuthActive}
|
||||
onConfigure={() =>
|
||||
setEditingMethod("headerAuth")
|
||||
}
|
||||
onToggle={(active) =>
|
||||
handleToggle("headerAuth", active, () =>
|
||||
parentForm.setValue("headerAuth", null)
|
||||
)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</SettingsFormCell>
|
||||
</SettingsFormGrid>
|
||||
}
|
||||
usersEditor={
|
||||
<FormField<PolicyFormValues, "users">
|
||||
control={parentForm.control}
|
||||
name="users"
|
||||
render={({ field }) => (
|
||||
<UsersSelector
|
||||
orgId={orgId}
|
||||
selectedUsers={field.value}
|
||||
onSelectUsers={(selected) =>
|
||||
parentForm.setValue(
|
||||
"users",
|
||||
selected
|
||||
)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
|
||||
<PolicyAuthOtherMethodsSection
|
||||
pinActive={pinActive}
|
||||
passcodeActive={passcodeActive}
|
||||
emailWhitelistEnabled={Boolean(emailWhitelistEnabled)}
|
||||
headerAuthActive={headerAuthActive}
|
||||
headerAuthUser={headerAuth?.user ?? ""}
|
||||
emailCount={emails.length}
|
||||
emailEnabled={emailEnabled}
|
||||
onConfigure={setEditingMethod}
|
||||
onTogglePincode={(active) =>
|
||||
handleToggle("pincode", active, () =>
|
||||
parentForm.setValue("pincode", null)
|
||||
)
|
||||
}
|
||||
onTogglePasscode={(active) =>
|
||||
handleToggle("passcode", active, () =>
|
||||
parentForm.setValue("password", null)
|
||||
)
|
||||
}
|
||||
onToggleEmail={(active) =>
|
||||
handleToggle("email", active, () =>
|
||||
parentForm.setValue(
|
||||
"emailWhitelistEnabled",
|
||||
false
|
||||
)
|
||||
)
|
||||
}
|
||||
onToggleHeaderAuth={(active) =>
|
||||
handleToggle("headerAuth", active, () =>
|
||||
parentForm.setValue("headerAuth", null)
|
||||
)
|
||||
}
|
||||
/>
|
||||
</SettingsSectionForm>
|
||||
|
||||
<PincodeCredenza
|
||||
open={editingMethod === "pincode"}
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
SettingsFormCell,
|
||||
SettingsFormGrid,
|
||||
SettingsSection,
|
||||
SettingsSectionBody,
|
||||
SettingsSectionDescription,
|
||||
SettingsSectionForm,
|
||||
SettingsSectionFooter,
|
||||
SettingsSectionHeader,
|
||||
SettingsSubsectionDescription,
|
||||
SettingsSubsectionHeader,
|
||||
SettingsSubsectionTitle,
|
||||
SettingsSectionTitle
|
||||
} from "@app/components/Settings";
|
||||
import {
|
||||
@@ -50,15 +46,9 @@ import {
|
||||
PasscodeCredenza,
|
||||
PincodeCredenza
|
||||
} from "./PolicyAuthMethodCredenzas";
|
||||
import { PolicyAuthMethodRow } from "./PolicyAuthMethodRow";
|
||||
import { PolicyAuthOtherMethodsSection } from "./PolicyAuthOtherMethodsSection";
|
||||
import { PolicyAuthSsoSection } from "./PolicyAuthSsoSection";
|
||||
import type { PolicyAuthMethodId } from "./policy-auth-method-id";
|
||||
import {
|
||||
getEmailWhitelistSummary,
|
||||
getHeaderAuthSummary,
|
||||
getPasscodeSummary,
|
||||
getPincodeSummary
|
||||
} from "./policy-auth-summaries";
|
||||
import { SharedPolicyResourceNotice } from "./SharedPolicyResourceNotice";
|
||||
import z from "zod";
|
||||
|
||||
@@ -528,255 +518,133 @@ export function PolicyAuthStackSectionEdit({
|
||||
</SettingsSectionDescription>
|
||||
</SettingsSectionHeader>
|
||||
<SettingsSectionBody>
|
||||
<div className="space-y-4">
|
||||
{isResourceOverlay && (
|
||||
<SharedPolicyResourceNotice section="authentication" />
|
||||
)}
|
||||
<SettingsFormGrid>
|
||||
<SettingsFormCell span="half">
|
||||
<PolicyAuthSsoSection
|
||||
sso={Boolean(sso)}
|
||||
onSsoChange={(active) =>
|
||||
form.setValue("sso", active)
|
||||
}
|
||||
skipToIdpId={skipToIdpId}
|
||||
onSkipToIdpChange={(id) =>
|
||||
form.setValue("skipToIdpId", id)
|
||||
}
|
||||
allIdps={allIdps}
|
||||
disabled={authReadonly}
|
||||
idpDisabled={authReadonly}
|
||||
rolesEditor={
|
||||
isResourceOverlay ? (
|
||||
{isResourceOverlay && (
|
||||
<SharedPolicyResourceNotice section="authentication" />
|
||||
)}
|
||||
<SettingsSectionForm variant="half">
|
||||
<PolicyAuthSsoSection
|
||||
sso={Boolean(sso)}
|
||||
onSsoChange={(active) =>
|
||||
form.setValue("sso", active)
|
||||
}
|
||||
skipToIdpId={skipToIdpId}
|
||||
onSkipToIdpChange={(id) =>
|
||||
form.setValue("skipToIdpId", id)
|
||||
}
|
||||
allIdps={allIdps}
|
||||
disabled={authReadonly}
|
||||
idpDisabled={authReadonly}
|
||||
rolesEditor={
|
||||
isResourceOverlay ? (
|
||||
<RolesSelector
|
||||
orgId={orgId}
|
||||
selectedRoles={overlayRoles}
|
||||
onSelectRoles={(selected) =>
|
||||
setCombinedRoles(
|
||||
selected.map((role) => ({
|
||||
...role,
|
||||
isAdmin: Boolean(
|
||||
role.isAdmin
|
||||
)
|
||||
}))
|
||||
)
|
||||
}
|
||||
disabled={isLoading}
|
||||
restrictAdminRole
|
||||
lockedIds={policyRoleLockedIds}
|
||||
/>
|
||||
) : (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="roles"
|
||||
render={({ field }) => (
|
||||
<RolesSelector
|
||||
orgId={orgId}
|
||||
selectedRoles={overlayRoles}
|
||||
selectedRoles={field.value}
|
||||
onSelectRoles={(selected) =>
|
||||
setCombinedRoles(
|
||||
selected.map(
|
||||
(role) => ({
|
||||
...role,
|
||||
isAdmin:
|
||||
Boolean(
|
||||
role.isAdmin
|
||||
)
|
||||
})
|
||||
)
|
||||
form.setValue(
|
||||
"roles",
|
||||
selected
|
||||
)
|
||||
}
|
||||
disabled={isLoading}
|
||||
disabled={readonly}
|
||||
restrictAdminRole
|
||||
lockedIds={
|
||||
policyRoleLockedIds
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="roles"
|
||||
render={({ field }) => (
|
||||
<RolesSelector
|
||||
orgId={orgId}
|
||||
selectedRoles={
|
||||
field.value
|
||||
}
|
||||
onSelectRoles={(
|
||||
selected
|
||||
) =>
|
||||
form.setValue(
|
||||
"roles",
|
||||
selected
|
||||
)
|
||||
}
|
||||
disabled={readonly}
|
||||
restrictAdminRole
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
usersEditor={
|
||||
isResourceOverlay ? (
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
usersEditor={
|
||||
isResourceOverlay ? (
|
||||
<UsersSelector
|
||||
orgId={orgId}
|
||||
selectedUsers={overlayUsers}
|
||||
onSelectUsers={setCombinedUsers}
|
||||
disabled={isLoading}
|
||||
lockedIds={policyUserLockedIds}
|
||||
/>
|
||||
) : (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="users"
|
||||
render={({ field }) => (
|
||||
<UsersSelector
|
||||
orgId={orgId}
|
||||
selectedUsers={overlayUsers}
|
||||
onSelectUsers={
|
||||
setCombinedUsers
|
||||
}
|
||||
disabled={isLoading}
|
||||
lockedIds={
|
||||
policyUserLockedIds
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="users"
|
||||
render={({ field }) => (
|
||||
<UsersSelector
|
||||
orgId={orgId}
|
||||
selectedUsers={
|
||||
field.value
|
||||
}
|
||||
onSelectUsers={(
|
||||
selected
|
||||
) =>
|
||||
form.setValue(
|
||||
"users",
|
||||
selected
|
||||
)
|
||||
}
|
||||
disabled={readonly}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
</SettingsFormCell>
|
||||
</SettingsFormGrid>
|
||||
|
||||
<SettingsFormGrid>
|
||||
<SettingsFormCell span="full">
|
||||
<SettingsSubsectionHeader>
|
||||
<SettingsSubsectionTitle>
|
||||
{t("policyAuthOtherMethodsTitle")}
|
||||
</SettingsSubsectionTitle>
|
||||
<SettingsSubsectionDescription>
|
||||
{t(
|
||||
"policyAuthOtherMethodsDescription"
|
||||
)}
|
||||
</SettingsSubsectionDescription>
|
||||
</SettingsSubsectionHeader>
|
||||
</SettingsFormCell>
|
||||
<SettingsFormCell span="half">
|
||||
<div className="flex flex-col gap-3">
|
||||
<PolicyAuthMethodRow
|
||||
id="pincode"
|
||||
title={t("policyAuthPincodeTitle")}
|
||||
description={t(
|
||||
"policyAuthPincodeDescription"
|
||||
)}
|
||||
summary={getPincodeSummary({ t })}
|
||||
active={pinActive}
|
||||
onConfigure={() =>
|
||||
openMethodEditor("pincode")
|
||||
}
|
||||
onToggle={(active) =>
|
||||
handleToggle(
|
||||
"pincode",
|
||||
active,
|
||||
() => {
|
||||
setPinActive(false);
|
||||
selectedUsers={field.value}
|
||||
onSelectUsers={(selected) =>
|
||||
form.setValue(
|
||||
"pincode",
|
||||
null
|
||||
);
|
||||
}
|
||||
)
|
||||
}
|
||||
disabled={authReadonly}
|
||||
/>
|
||||
|
||||
<PolicyAuthMethodRow
|
||||
id="passcode"
|
||||
title={t("policyAuthPasscodeTitle")}
|
||||
description={t(
|
||||
"policyAuthPasscodeDescription"
|
||||
)}
|
||||
summary={getPasscodeSummary({ t })}
|
||||
active={passcodeActive}
|
||||
onConfigure={() =>
|
||||
openMethodEditor("passcode")
|
||||
}
|
||||
onToggle={(active) =>
|
||||
handleToggle(
|
||||
"passcode",
|
||||
active,
|
||||
() => {
|
||||
setPasscodeActive(
|
||||
false
|
||||
);
|
||||
form.setValue(
|
||||
"password",
|
||||
null
|
||||
);
|
||||
}
|
||||
)
|
||||
}
|
||||
disabled={authReadonly}
|
||||
/>
|
||||
|
||||
<PolicyAuthMethodRow
|
||||
id="email"
|
||||
title={t("policyAuthEmailTitle")}
|
||||
description={t(
|
||||
"policyAuthEmailDescription"
|
||||
)}
|
||||
summary={getEmailWhitelistSummary({
|
||||
t,
|
||||
count: emails.length
|
||||
})}
|
||||
active={Boolean(
|
||||
emailWhitelistEnabled
|
||||
)}
|
||||
onConfigure={() =>
|
||||
openMethodEditor("email")
|
||||
}
|
||||
onToggle={(active) =>
|
||||
handleToggle(
|
||||
"email",
|
||||
active,
|
||||
() =>
|
||||
form.setValue(
|
||||
"emailWhitelistEnabled",
|
||||
false
|
||||
"users",
|
||||
selected
|
||||
)
|
||||
)
|
||||
}
|
||||
disabled={
|
||||
authReadonly || !emailEnabled
|
||||
}
|
||||
/>
|
||||
|
||||
<PolicyAuthMethodRow
|
||||
id="header-auth"
|
||||
title={t(
|
||||
"policyAuthHeaderAuthTitle"
|
||||
)}
|
||||
description={t(
|
||||
"policyAuthHeaderAuthDescription"
|
||||
)}
|
||||
summary={getHeaderAuthSummary({
|
||||
t,
|
||||
headerName:
|
||||
headerAuth?.user ?? ""
|
||||
})}
|
||||
active={headerAuthActive}
|
||||
onConfigure={() =>
|
||||
openMethodEditor("headerAuth")
|
||||
}
|
||||
onToggle={(active) =>
|
||||
handleToggle(
|
||||
"headerAuth",
|
||||
active,
|
||||
() => {
|
||||
setHeaderAuthActive(
|
||||
false
|
||||
);
|
||||
form.setValue(
|
||||
"headerAuth",
|
||||
null
|
||||
);
|
||||
}
|
||||
)
|
||||
}
|
||||
disabled={authReadonly}
|
||||
disabled={readonly}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</SettingsFormCell>
|
||||
</SettingsFormGrid>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||
<PolicyAuthOtherMethodsSection
|
||||
pinActive={pinActive}
|
||||
passcodeActive={passcodeActive}
|
||||
emailWhitelistEnabled={Boolean(
|
||||
emailWhitelistEnabled
|
||||
)}
|
||||
headerAuthActive={headerAuthActive}
|
||||
headerAuthUser={headerAuth?.user ?? ""}
|
||||
emailCount={emails.length}
|
||||
emailEnabled={emailEnabled}
|
||||
disabled={authReadonly}
|
||||
onConfigure={openMethodEditor}
|
||||
onTogglePincode={(active) =>
|
||||
handleToggle("pincode", active, () => {
|
||||
setPinActive(false);
|
||||
form.setValue("pincode", null);
|
||||
})
|
||||
}
|
||||
onTogglePasscode={(active) =>
|
||||
handleToggle("passcode", active, () => {
|
||||
setPasscodeActive(false);
|
||||
form.setValue("password", null);
|
||||
})
|
||||
}
|
||||
onToggleEmail={(active) =>
|
||||
handleToggle("email", active, () =>
|
||||
form.setValue(
|
||||
"emailWhitelistEnabled",
|
||||
false
|
||||
)
|
||||
)
|
||||
}
|
||||
onToggleHeaderAuth={(active) =>
|
||||
handleToggle("headerAuth", active, () => {
|
||||
setHeaderAuthActive(false);
|
||||
form.setValue("headerAuth", null);
|
||||
})
|
||||
}
|
||||
/>
|
||||
</SettingsSectionForm>
|
||||
|
||||
<PincodeCredenza
|
||||
open={editingMethod === "pincode"}
|
||||
|
||||
Reference in New Issue
Block a user