mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-10-10 19:59:04 +02:00
feat: add configurable login notification modes (#1813)
This commit is contained in:
@@ -31,7 +31,7 @@ export type AllAppConfig = AppConfig & {
|
||||
smtpPassword: string;
|
||||
smtpTls: 'none' | 'starttls' | 'tls';
|
||||
smtpSkipCertVerify: boolean;
|
||||
emailLoginNotificationEnabled: boolean;
|
||||
emailLoginNotificationMode: 'disabled' | 'always' | 'ipAndUserAgent' | 'browserRecognition';
|
||||
emailApiKeyExpirationEnabled: boolean;
|
||||
// LDAP
|
||||
ldapUrl: string;
|
||||
|
||||
+55
-9
@@ -30,6 +30,22 @@
|
||||
tls: 'TLS'
|
||||
};
|
||||
|
||||
const notificationOptions = $derived({
|
||||
disabled: { label: m.never(), description: m.login_notification_disabled_description() },
|
||||
always: {
|
||||
label: m.login_notification_always(),
|
||||
description: m.login_notification_always_description()
|
||||
},
|
||||
ipAndUserAgent: {
|
||||
label: m.login_notification_ip_and_user_agent(),
|
||||
description: m.login_notification_ip_and_user_agent_description()
|
||||
},
|
||||
browserRecognition: {
|
||||
label: m.login_notification_browser_recognition(),
|
||||
description: m.login_notification_browser_recognition_description()
|
||||
}
|
||||
});
|
||||
|
||||
let isSendingTestEmail = $state(false);
|
||||
|
||||
const formSchema = z
|
||||
@@ -49,7 +65,12 @@
|
||||
emailOneTimeAccessAsUnauthenticatedEnabled: z.boolean(),
|
||||
emailVerificationEnabled: z.boolean(),
|
||||
emailOneTimeAccessAsAdminEnabled: z.boolean(),
|
||||
emailLoginNotificationEnabled: z.boolean(),
|
||||
emailLoginNotificationMode: z.enum([
|
||||
'disabled',
|
||||
'always',
|
||||
'ipAndUserAgent',
|
||||
'browserRecognition'
|
||||
]),
|
||||
emailApiKeyExpirationEnabled: z.boolean()
|
||||
})
|
||||
.superRefine((data, ctx) => {
|
||||
@@ -63,7 +84,6 @@
|
||||
'emailOneTimeAccessAsUnauthenticatedEnabled',
|
||||
'emailVerificationEnabled',
|
||||
'emailOneTimeAccessAsAdminEnabled',
|
||||
'emailLoginNotificationEnabled',
|
||||
'emailApiKeyExpirationEnabled'
|
||||
];
|
||||
|
||||
@@ -84,7 +104,8 @@
|
||||
const anyProvided = requiredSmtpFields.some((f) => !!data[f]);
|
||||
requireFieldsWhen(anyProvided, m.smtp_field_required_when_other_provided());
|
||||
|
||||
const emailEnabled = emailFields.some((f) => data[f]);
|
||||
const emailEnabled =
|
||||
data.emailLoginNotificationMode !== 'disabled' || emailFields.some((f) => data[f]);
|
||||
requireFieldsWhen(emailEnabled, m.smtp_field_required_when_email_enabled());
|
||||
});
|
||||
|
||||
@@ -194,12 +215,37 @@
|
||||
</div>
|
||||
<h4 class="mt-10 text-lg font-semibold">{m.enabled_emails()}</h4>
|
||||
<div class="mt-4 flex flex-col gap-5">
|
||||
<SwitchWithLabel
|
||||
id="email-login-notification"
|
||||
label={m.email_login_notification()}
|
||||
description={m.send_an_email_to_the_user_when_they_log_in_from_a_new_device()}
|
||||
bind:checked={$inputs.emailLoginNotificationEnabled.value}
|
||||
/>
|
||||
<Field.Field>
|
||||
<div>
|
||||
<Field.Label for="email-login-notification">{m.email_login_notification()}</Field.Label>
|
||||
<Field.Description>{m.email_login_notification_description()}</Field.Description>
|
||||
</div>
|
||||
<Select.Root
|
||||
type="single"
|
||||
disabled={$appConfigStore.uiConfigDisabled}
|
||||
value={$inputs.emailLoginNotificationMode.value}
|
||||
allowDeselect={false}
|
||||
onValueChange={(value) =>
|
||||
($inputs.emailLoginNotificationMode.value =
|
||||
value as AllAppConfig['emailLoginNotificationMode'])}
|
||||
>
|
||||
<Select.Trigger id="email-login-notification" class="w-full">
|
||||
{notificationOptions[$inputs.emailLoginNotificationMode.value].label}
|
||||
</Select.Trigger>
|
||||
<Select.Content class="w-[calc(var(--bits-select-anchor-width)+--spacing(3))]">
|
||||
<Select.Group>
|
||||
{#each Object.entries(notificationOptions) as [value, option] (value)}
|
||||
<Select.Item {value} label={option.label}>
|
||||
<div class="flex flex-col items-start gap-1 whitespace-normal">
|
||||
<span class="font-medium">{option.label}</span>
|
||||
<span class="text-muted-foreground text-xs">{option.description}</span>
|
||||
</div>
|
||||
</Select.Item>
|
||||
{/each}
|
||||
</Select.Group>
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</Field.Field>
|
||||
<SwitchWithLabel
|
||||
id="email-verification"
|
||||
label={m.email_verification()}
|
||||
|
||||
Reference in New Issue
Block a user