feat: add email filters with JMAP Sieve Scripts (RFC 9661)

Server-side email filtering with visual rule builder and raw Sieve editor.
Conditions (From/To/Subject/Size/Body), actions (Move/Forward/Star/Discard),
auto-save with rollback, drag-and-drop reorder, opaque script reset,
accessibility focus traps, toast validation, and 8-language i18n support.
This commit is contained in:
Matthieu MALVACHE
2026-02-16 23:09:18 +01:00
committed by Matthieu MALVACHE
parent ff65693e26
commit 73612313c0
24 changed files with 3511 additions and 203 deletions
+5 -1
View File
@@ -11,11 +11,12 @@ import { AccountSettings } from '@/components/settings/account-settings';
import { IdentitySettings } from '@/components/settings/identity-settings';
import { VacationSettings } from '@/components/settings/vacation-settings';
import { CalendarSettings } from '@/components/settings/calendar-settings';
import { FilterSettings } from '@/components/settings/filter-settings';
import { AdvancedSettings } from '@/components/settings/advanced-settings';
import { useAuthStore } from '@/stores/auth-store';
import { cn } from '@/lib/utils';
type Tab = 'appearance' | 'email' | 'account' | 'identities' | 'vacation' | 'calendar' | 'advanced';
type Tab = 'appearance' | 'email' | 'account' | 'identities' | 'vacation' | 'calendar' | 'filters' | 'advanced';
export default function SettingsPage() {
const router = useRouter();
@@ -25,6 +26,7 @@ export default function SettingsPage() {
const supportsVacation = client?.supportsVacationResponse() ?? false;
const supportsCalendar = client?.supportsCalendars() ?? false;
const supportsSieve = client?.supportsSieve() ?? false;
const tabs: { id: Tab; label: string }[] = [
{ id: 'appearance', label: t('tabs.appearance') },
@@ -33,6 +35,7 @@ export default function SettingsPage() {
{ id: 'identities', label: t('tabs.identities') },
...(supportsVacation ? [{ id: 'vacation' as Tab, label: t('tabs.vacation') }] : []),
...(supportsCalendar ? [{ id: 'calendar' as Tab, label: t('tabs.calendar') }] : []),
...(supportsSieve ? [{ id: 'filters' as Tab, label: t('tabs.filters') }] : []),
{ id: 'advanced', label: t('tabs.advanced') },
];
@@ -93,6 +96,7 @@ export default function SettingsPage() {
{activeTab === 'identities' && <IdentitySettings />}
{activeTab === 'vacation' && <VacationSettings />}
{activeTab === 'calendar' && <CalendarSettings />}
{activeTab === 'filters' && <FilterSettings />}
{activeTab === 'advanced' && <AdvancedSettings />}
</div>
</div>