fix: resolve all 69 ESLint warnings across 40 files
- Remove unused imports (Mail, CalendarIcon, Plus, Circle, cn, Link, MessageCircle, User, Tag, FolderUp, useEffect, LogOut, GripVertical, Check, X, HoverActionsMode, HoverActionsCorner, asn1js, Convert, etc.) - Prefix unused variables/params with underscore to satisfy no-unused-vars - Add missing React hook dependencies (exhaustive-deps) - Wrap handleNavigateUp in useCallback and selectedGroupMembers in useMemo - Remove unused eslint-disable directives in jmap/client.ts - Replace as any with typed casts in filter-store and smime-store tests - Remove dead code (macOk assignment, unused now variable)
This commit is contained in:
@@ -186,7 +186,7 @@ export default function CalendarPage() {
|
|||||||
if (client && enableCalendarTasks && (normalizedViewMode === "tasks" || showTasksOnCalendar)) {
|
if (client && enableCalendarTasks && (normalizedViewMode === "tasks" || showTasksOnCalendar)) {
|
||||||
taskStore.fetchTasks(client);
|
taskStore.fetchTasks(client);
|
||||||
}
|
}
|
||||||
}, [client, enableCalendarTasks, normalizedViewMode, showTasksOnCalendar]);
|
}, [client, enableCalendarTasks, normalizedViewMode, showTasksOnCalendar, taskStore]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (client && calendars.length > 0 && dateRange) {
|
if (client && calendars.length > 0 && dateRange) {
|
||||||
@@ -704,7 +704,7 @@ export default function CalendarPage() {
|
|||||||
};
|
};
|
||||||
window.addEventListener("keydown", handleKey);
|
window.addEventListener("keydown", handleKey);
|
||||||
return () => window.removeEventListener("keydown", handleKey);
|
return () => window.removeEventListener("keydown", handleKey);
|
||||||
}, [navigatePrev, navigateNext, goToToday, setViewMode, openCreateModal, showEventModal, detailEvent]);
|
}, [navigatePrev, navigateNext, goToToday, setViewMode, openCreateModal, showEventModal, detailEvent, enableCalendarTasks]);
|
||||||
|
|
||||||
const visibleEvents = useMemo(() =>
|
const visibleEvents = useMemo(() =>
|
||||||
events.filter((e) => {
|
events.filter((e) => {
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ export default function ContactsPage() {
|
|||||||
const individuals = useMemo(() => contacts.filter(c => c.kind !== 'group'), [contacts]);
|
const individuals = useMemo(() => contacts.filter(c => c.kind !== 'group'), [contacts]);
|
||||||
const selectedContact = contacts.find((c) => c.id === selectedContactId) || null;
|
const selectedContact = contacts.find((c) => c.id === selectedContactId) || null;
|
||||||
const selectedGroup = selectedGroupId ? contacts.find(c => c.id === selectedGroupId) || null : null;
|
const selectedGroup = selectedGroupId ? contacts.find(c => c.id === selectedGroupId) || null : null;
|
||||||
const selectedGroupMembers = selectedGroupId ? getGroupMembers(selectedGroupId) : [];
|
const selectedGroupMembers = useMemo(() => selectedGroupId ? getGroupMembers(selectedGroupId) : [], [selectedGroupId, getGroupMembers]);
|
||||||
|
|
||||||
// Collect all unique keywords across contacts
|
// Collect all unique keywords across contacts
|
||||||
const allKeywords = useMemo(() => {
|
const allKeywords = useMemo(() => {
|
||||||
@@ -307,7 +307,7 @@ export default function ContactsPage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSelectGroup = (id: string) => {
|
const _handleSelectGroup = (id: string) => {
|
||||||
setSelectedGroupId(id);
|
setSelectedGroupId(id);
|
||||||
setActiveCategory({ groupId: id });
|
setActiveCategory({ groupId: id });
|
||||||
setView("group-detail");
|
setView("group-detail");
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export default function FilesPage() {
|
|||||||
navigateByPath,
|
navigateByPath,
|
||||||
refresh,
|
refresh,
|
||||||
createDirectory,
|
createDirectory,
|
||||||
uploadFile,
|
uploadFile: _uploadFile,
|
||||||
uploadFiles,
|
uploadFiles,
|
||||||
uploadFolder,
|
uploadFolder,
|
||||||
deleteResource,
|
deleteResource,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { useThemeStore } from "@/stores/theme-store";
|
|||||||
import { useShallow } from "zustand/react/shallow";
|
import { useShallow } from "zustand/react/shallow";
|
||||||
import { useConfig } from "@/hooks/use-config";
|
import { useConfig } from "@/hooks/use-config";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { Mail, AlertCircle, Loader2, X, Info, Eye, EyeOff, LogIn, Sun, Moon, Monitor, Check, Shield, Play } from "lucide-react";
|
import { AlertCircle, Loader2, X, Info, Eye, EyeOff, LogIn, Sun, Moon, Monitor, Check, Shield, Play } from "lucide-react";
|
||||||
import { discoverOAuth, type OAuthMetadata } from "@/lib/oauth/discovery";
|
import { discoverOAuth, type OAuthMetadata } from "@/lib/oauth/discovery";
|
||||||
import { generateCodeVerifier, generateCodeChallenge, generateState } from "@/lib/oauth/pkce";
|
import { generateCodeVerifier, generateCodeChallenge, generateState } from "@/lib/oauth/pkce";
|
||||||
import { OAUTH_SCOPES } from "@/lib/oauth/tokens";
|
import { OAUTH_SCOPES } from "@/lib/oauth/tokens";
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import { useEffect, useState, useRef } from 'react';
|
import { useEffect, useState, useRef } from 'react';
|
||||||
import { Upload, Trash2, Power, Loader2, Palette, Save, Shield } from 'lucide-react';
|
import { Upload, Trash2, Power, Loader2, Palette, Save, Shield } from 'lucide-react';
|
||||||
import type { SettingsPolicy } from '@/lib/admin/types';
|
import type { SettingsPolicy } from '@/lib/admin/types';
|
||||||
import { DEFAULT_POLICY, DEFAULT_THEME_POLICY, DEFAULT_FEATURE_GATES } from '@/lib/admin/types';
|
import { DEFAULT_POLICY, DEFAULT_THEME_POLICY } from '@/lib/admin/types';
|
||||||
|
|
||||||
const BUILTIN_THEME_OPTIONS = [
|
const BUILTIN_THEME_OPTIONS = [
|
||||||
{ id: 'builtin-nord', name: 'Nord' },
|
{ id: 'builtin-nord', name: 'Nord' },
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ function localDateTime(dayOffset: number, hour: number, minute: number): string
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Parse a JMAP duration like "PT1H30M", "P1D", "PT45M" into milliseconds. */
|
/** Parse a JMAP duration like "PT1H30M", "P1D", "PT45M" into milliseconds. */
|
||||||
function parseDurationMs(dur: string): number {
|
function _parseDurationMs(dur: string): number {
|
||||||
let ms = 0;
|
let ms = 0;
|
||||||
const dayMatch = dur.match(/(\d+)D/);
|
const dayMatch = dur.match(/(\d+)D/);
|
||||||
const hourMatch = dur.match(/(\d+)H/);
|
const hourMatch = dur.match(/(\d+)H/);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import { useMemo, useRef, useEffect, useCallback } from "react";
|
import { useMemo, useRef, useEffect, useCallback } from "react";
|
||||||
import { useTranslations, useFormatter } from "next-intl";
|
import { useTranslations, useFormatter } from "next-intl";
|
||||||
import { format, parseISO, isToday, isTomorrow, startOfDay } from "date-fns";
|
import { format, parseISO, isToday, isTomorrow, startOfDay } from "date-fns";
|
||||||
import { Calendar as CalendarIcon, MapPin, Users } from "lucide-react";
|
import { MapPin, Users } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { parseDuration, getEventColor } from "./event-card";
|
import { parseDuration, getEventColor } from "./event-card";
|
||||||
import { getEventDayBounds, getPrimaryCalendarId } from "@/lib/calendar-utils";
|
import { getEventDayBounds, getPrimaryCalendarId } from "@/lib/calendar-utils";
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { useState, useRef, useEffect, useMemo } from "react";
|
import { useState, useRef, useEffect, useMemo } from "react";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { Globe, ListTodo, Plus, RefreshCw, Share2, Trash2 } from "lucide-react";
|
import { Globe, ListTodo, RefreshCw, Share2, Trash2 } from "lucide-react";
|
||||||
import { cn, formatDateTime } from "@/lib/utils";
|
import { cn, formatDateTime } from "@/lib/utils";
|
||||||
import type { Calendar } from "@/lib/jmap/types";
|
import type { Calendar } from "@/lib/jmap/types";
|
||||||
import { CalendarColorPicker } from "@/components/settings/calendar-management-settings";
|
import { CalendarColorPicker } from "@/components/settings/calendar-management-settings";
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import { useMemo, useCallback, useState } from "react";
|
import { useMemo, useCallback, useState } from "react";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { format, parseISO, isPast, isToday, isTomorrow } from "date-fns";
|
import { format, parseISO, isPast, isToday, isTomorrow } from "date-fns";
|
||||||
import { Check, Circle, Flag, CalendarDays, ListTodo, Plus } from "lucide-react";
|
import { Check, Flag, CalendarDays, ListTodo, Plus } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import type { CalendarTask, Calendar } from "@/lib/jmap/types";
|
import type { CalendarTask, Calendar } from "@/lib/jmap/types";
|
||||||
import type { TaskViewFilter } from "@/stores/task-store";
|
import type { TaskViewFilter } from "@/stores/task-store";
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { Button } from "@/components/ui/button";
|
|||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { X, Trash2, CalendarDays, Bell, Flag } from "lucide-react";
|
import { X, Trash2, CalendarDays, Bell, Flag } from "lucide-react";
|
||||||
import { format, parseISO } from "date-fns";
|
import { format, parseISO } from "date-fns";
|
||||||
import { cn } from "@/lib/utils";
|
|
||||||
import type { CalendarTask, Calendar, CalendarEventAlert } from "@/lib/jmap/types";
|
import type { CalendarTask, Calendar, CalendarEventAlert } from "@/lib/jmap/types";
|
||||||
|
|
||||||
interface TaskModalProps {
|
interface TaskModalProps {
|
||||||
@@ -43,7 +43,7 @@ export function TaskModal({
|
|||||||
onSave,
|
onSave,
|
||||||
onDelete,
|
onDelete,
|
||||||
onClose,
|
onClose,
|
||||||
isMobile,
|
isMobile: _isMobile,
|
||||||
}: TaskModalProps) {
|
}: TaskModalProps) {
|
||||||
const t = useTranslations("calendar");
|
const t = useTranslations("calendar");
|
||||||
const isEdit = !!task;
|
const isEdit = !!task;
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ describe('ContactForm', () => {
|
|||||||
const onSave = vi.fn().mockResolvedValue(undefined);
|
const onSave = vi.fn().mockResolvedValue(undefined);
|
||||||
render(<ContactForm onSave={onSave} onCancel={vi.fn()} />);
|
render(<ContactForm onSave={onSave} onCancel={vi.fn()} />);
|
||||||
|
|
||||||
const inputs = screen.getAllByRole('textbox');
|
const _inputs = screen.getAllByRole('textbox');
|
||||||
const givenNameInput = screen.getByPlaceholderText('given_name');
|
const givenNameInput = screen.getByPlaceholderText('given_name');
|
||||||
fireEvent.change(givenNameInput, { target: { value: 'Jane' } });
|
fireEvent.change(givenNameInput, { target: { value: 'Jane' } });
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { render, screen, fireEvent } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import { describe, it, expect, vi } from 'vitest';
|
import { describe, it, expect, vi } from 'vitest';
|
||||||
import { ContactList } from '../contact-list';
|
import { ContactList } from '../contact-list';
|
||||||
import type { ContactCard } from '@/lib/jmap/types';
|
import type { ContactCard } from '@/lib/jmap/types';
|
||||||
@@ -22,7 +22,7 @@ const bob = makeContact({
|
|||||||
emails: { e0: { address: 'bob@example.com' } },
|
emails: { e0: { address: 'bob@example.com' } },
|
||||||
});
|
});
|
||||||
|
|
||||||
const group = makeContact({
|
const _group = makeContact({
|
||||||
id: '3',
|
id: '3',
|
||||||
kind: 'group',
|
kind: 'group',
|
||||||
name: { components: [{ kind: 'given', value: 'Team' }], isOrdered: true },
|
name: { components: [{ kind: 'given', value: 'Team' }], isOrdered: true },
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { Mail, Phone, Building, MapPin, StickyNote, Pencil, Trash2, BookUser, Copy, Send, Globe, Cake, Tag, KeyRound, Link, Users, Briefcase, Heart, Languages, MessageCircle, User, Calendar, UserCircle, ShieldCheck, ShieldAlert, Download } from "lucide-react";
|
import { Mail, Phone, Building, MapPin, StickyNote, Pencil, Trash2, BookUser, Copy, Send, Globe, Cake, Tag, KeyRound, Users, Briefcase, Heart, Languages, Calendar, UserCircle, ShieldCheck, ShieldAlert, Download } from "lucide-react";
|
||||||
import { Avatar } from "@/components/ui/avatar";
|
import { Avatar } from "@/components/ui/avatar";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ export function EmailContextMenu({
|
|||||||
onEditDraft,
|
onEditDraft,
|
||||||
}: EmailContextMenuProps) {
|
}: EmailContextMenuProps) {
|
||||||
const t = useTranslations("context_menu");
|
const t = useTranslations("context_menu");
|
||||||
const tColor = useTranslations("email_viewer.color_tag");
|
const _tColor = useTranslations("email_viewer.color_tag");
|
||||||
const emailKeywords = useSettingsStore((state) => state.emailKeywords);
|
const emailKeywords = useSettingsStore((state) => state.emailKeywords);
|
||||||
const isUnread = !email.keywords?.$seen;
|
const isUnread = !email.keywords?.$seen;
|
||||||
const isStarred = email.keywords?.$flagged;
|
const isStarred = email.keywords?.$flagged;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { formatDate } from "@/lib/utils";
|
|||||||
import { Email } from "@/lib/jmap/types";
|
import { Email } from "@/lib/jmap/types";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { Avatar } from "@/components/ui/avatar";
|
import { Avatar } from "@/components/ui/avatar";
|
||||||
import { Paperclip, Star, Circle, CheckSquare, Square, Tag, Reply, Forward } from "lucide-react";
|
import { Paperclip, Star, Circle, CheckSquare, Square, Reply, Forward } from "lucide-react";
|
||||||
import { useEmailStore } from "@/stores/email-store";
|
import { useEmailStore } from "@/stores/email-store";
|
||||||
import { useSettingsStore, KEYWORD_PALETTE } from "@/stores/settings-store";
|
import { useSettingsStore, KEYWORD_PALETTE } from "@/stores/settings-store";
|
||||||
import { useAuthStore } from "@/stores/auth-store";
|
import { useAuthStore } from "@/stores/auth-store";
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ export function EmailList({
|
|||||||
const { client } = useAuthStore();
|
const { client } = useAuthStore();
|
||||||
const {
|
const {
|
||||||
selectedEmailIds,
|
selectedEmailIds,
|
||||||
selectAllEmails,
|
selectAllEmails: _selectAllEmails,
|
||||||
clearSelection,
|
clearSelection,
|
||||||
batchMarkAsRead,
|
batchMarkAsRead,
|
||||||
batchDelete,
|
batchDelete,
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ const getCurrentColor = (keywords: Record<string, boolean> | undefined) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Helper function to format recipients with contextual display
|
// Helper function to format recipients with contextual display
|
||||||
const formatRecipients = (
|
const _formatRecipients = (
|
||||||
recipients: Array<{ name?: string; email: string }> | undefined,
|
recipients: Array<{ name?: string; email: string }> | undefined,
|
||||||
currentUserEmail: string | undefined,
|
currentUserEmail: string | undefined,
|
||||||
t: (key: string, params?: Record<string, string | number>) => string
|
t: (key: string, params?: Record<string, string | number>) => string
|
||||||
@@ -1751,6 +1751,7 @@ export function EmailViewer({
|
|||||||
smimeStore.autoImportSignerCerts,
|
smimeStore.autoImportSignerCerts,
|
||||||
smimeStore.keyRecords,
|
smimeStore.keyRecords,
|
||||||
smimeStore.unlockedDecryptionKeys,
|
smimeStore.unlockedDecryptionKeys,
|
||||||
|
smimeStore,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// TNEF (winmail.dat) detection and processing
|
// TNEF (winmail.dat) detection and processing
|
||||||
@@ -1928,7 +1929,7 @@ export function EmailViewer({
|
|||||||
if (decryptedCidAttachments.length > 0) {
|
if (decryptedCidAttachments.length > 0) {
|
||||||
const urls: Record<string, string> = {};
|
const urls: Record<string, string> = {};
|
||||||
|
|
||||||
decryptedCidAttachments.forEach((att, index) => {
|
decryptedCidAttachments.forEach((att) => {
|
||||||
const bytes = getAttachmentContentBytes(att);
|
const bytes = getAttachmentContentBytes(att);
|
||||||
if (!bytes) return;
|
if (!bytes) return;
|
||||||
const cidValue = att.contentId!.replace(/^<|>$/g, '');
|
const cidValue = att.contentId!.replace(/^<|>$/g, '');
|
||||||
@@ -1985,7 +1986,7 @@ export function EmailViewer({
|
|||||||
cancelled = true;
|
cancelled = true;
|
||||||
objectUrls.forEach(url => URL.revokeObjectURL(url));
|
objectUrls.forEach(url => URL.revokeObjectURL(url));
|
||||||
};
|
};
|
||||||
}, [client, email?.id, smimeDecryptedAttachments]);
|
}, [client, email?.id, smimeDecryptedAttachments, email?.attachments]);
|
||||||
|
|
||||||
const effectiveAttachments = useMemo<EffectiveAttachment[]>(() => {
|
const effectiveAttachments = useMemo<EffectiveAttachment[]>(() => {
|
||||||
if (smimeDecryptedAttachments.length > 0) {
|
if (smimeDecryptedAttachments.length > 0) {
|
||||||
|
|||||||
@@ -305,7 +305,7 @@ function EmailCard({
|
|||||||
cancelled = true;
|
cancelled = true;
|
||||||
objectUrls.forEach(url => URL.revokeObjectURL(url));
|
objectUrls.forEach(url => URL.revokeObjectURL(url));
|
||||||
};
|
};
|
||||||
}, [client, email?.id]);
|
}, [client, email?.id, email?.attachments]);
|
||||||
|
|
||||||
// Sanitize and prepare email HTML content
|
// Sanitize and prepare email HTML content
|
||||||
const emailContent = useMemo(() => {
|
const emailContent = useMemo(() => {
|
||||||
|
|||||||
@@ -453,13 +453,13 @@ export function FileBrowser({
|
|||||||
})),
|
})),
|
||||||
];
|
];
|
||||||
|
|
||||||
const handleNavigateUp = () => {
|
const handleNavigateUp = useCallback(() => {
|
||||||
if (currentPath === '/') return;
|
if (currentPath === '/') return;
|
||||||
const segments = currentPath.split('/').filter(Boolean);
|
const segments = currentPath.split('/').filter(Boolean);
|
||||||
segments.pop();
|
segments.pop();
|
||||||
const parentPath = segments.length === 0 ? '/' : '/' + segments.join('/');
|
const parentPath = segments.length === 0 ? '/' : '/' + segments.join('/');
|
||||||
onNavigate(parentPath, null);
|
onNavigate(parentPath, null);
|
||||||
};
|
}, [currentPath, onNavigate]);
|
||||||
|
|
||||||
const handleResourceClick = (resource: FileResource, e: React.MouseEvent) => {
|
const handleResourceClick = (resource: FileResource, e: React.MouseEvent) => {
|
||||||
if (resource.isDirectory) {
|
if (resource.isDirectory) {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { useCallback, useState } from "react";
|
import { useCallback, useState } from "react";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import { Upload, FolderPlus, FilePlus, FolderUp } from "lucide-react";
|
import { Upload, FolderPlus, FilePlus } from "lucide-react";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { getDroppedFilesAndFolders } from "@/lib/webdav/drop-utils";
|
import { getDroppedFilesAndFolders } from "@/lib/webdav/drop-utils";
|
||||||
|
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ function FolderTreeItem({
|
|||||||
}) {
|
}) {
|
||||||
const isExpanded = expandedIds.has(node.id);
|
const isExpanded = expandedIds.has(node.id);
|
||||||
const isSelected = currentPath === node.path;
|
const isSelected = currentPath === node.path;
|
||||||
const isLoading = loadingIds.has(node.id);
|
const _isLoading = loadingIds.has(node.id);
|
||||||
const children = childrenCache.get(node.id);
|
const children = childrenCache.get(node.id);
|
||||||
const hasChildren = children !== undefined && children.length > 0;
|
const hasChildren = children !== undefined && children.length > 0;
|
||||||
const indentPx = depth * 16;
|
const indentPx = depth * 16;
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export function IdentityManagerModal({ isOpen, onClose }: IdentityManagerModalPr
|
|||||||
|
|
||||||
const client = useAuthStore((state) => state.client);
|
const client = useAuthStore((state) => state.client);
|
||||||
const identities = useIdentityStore((state) => state.identities);
|
const identities = useIdentityStore((state) => state.identities);
|
||||||
const preferredPrimaryId = useIdentityStore((state) => state.preferredPrimaryId);
|
const _preferredPrimaryId = useIdentityStore((state) => state.preferredPrimaryId);
|
||||||
const setPreferredPrimary = useIdentityStore((state) => state.setPreferredPrimary);
|
const setPreferredPrimary = useIdentityStore((state) => state.setPreferredPrimary);
|
||||||
const syncIdentities = useSyncIdentities();
|
const syncIdentities = useSyncIdentities();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useState, useMemo, useRef, useEffect, useCallback } from 'react';
|
import { useState, useMemo, useRef, useCallback } from 'react';
|
||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
import { icons as lucideIcons, type LucideIcon } from 'lucide-react';
|
import { icons as lucideIcons, type LucideIcon } from 'lucide-react';
|
||||||
import { Search, X } from 'lucide-react';
|
import { Search, X } from 'lucide-react';
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { useState, useRef, useEffect, useCallback } from "react";
|
import { useState, useRef, useEffect, useCallback } from "react";
|
||||||
import { createPortal } from "react-dom";
|
import { createPortal } from "react-dom";
|
||||||
import { Mail, Calendar, BookUser, HardDrive, Settings, LogOut, Keyboard, Plus } from "lucide-react";
|
import { Mail, Calendar, BookUser, HardDrive, Settings, Keyboard, Plus } from "lucide-react";
|
||||||
import { AccountSwitcher } from "./account-switcher";
|
import { AccountSwitcher } from "./account-switcher";
|
||||||
import { icons as lucideIcons, type LucideIcon } from "lucide-react";
|
import { icons as lucideIcons, type LucideIcon } from "lucide-react";
|
||||||
import { useConfig } from "@/hooks/use-config";
|
import { useConfig } from "@/hooks/use-config";
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { useState, useCallback } from 'react';
|
import { useState, useCallback } from 'react';
|
||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
import { X, Plus, Pencil, Trash2, GripVertical, ExternalLink, PanelRight } from 'lucide-react';
|
import { X, Plus, Pencil, Trash2, ExternalLink, PanelRight } from 'lucide-react';
|
||||||
import { icons as lucideIcons, type LucideIcon } from 'lucide-react';
|
import { icons as lucideIcons, type LucideIcon } from 'lucide-react';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
|
|||||||
@@ -429,7 +429,7 @@ export function Sidebar({
|
|||||||
className,
|
className,
|
||||||
}: SidebarProps) {
|
}: SidebarProps) {
|
||||||
const { sidebarCollapsed: isCollapsed, toggleSidebarCollapsed } = useUIStore();
|
const { sidebarCollapsed: isCollapsed, toggleSidebarCollapsed } = useUIStore();
|
||||||
const { primaryIdentity } = useAuthStore();
|
const { primaryIdentity: _primaryIdentity } = useAuthStore();
|
||||||
const [expandedFolders, setExpandedFolders] = useState<Set<string>>(new Set());
|
const [expandedFolders, setExpandedFolders] = useState<Set<string>>(new Set());
|
||||||
const [tagsExpanded, setTagsExpanded] = useState(() => {
|
const [tagsExpanded, setTagsExpanded] = useState(() => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { useCalendarStore } from '@/stores/calendar-store';
|
|||||||
import { useAuthStore } from '@/stores/auth-store';
|
import { useAuthStore } from '@/stores/auth-store';
|
||||||
import { toast } from '@/stores/toast-store';
|
import { toast } from '@/stores/toast-store';
|
||||||
import { SettingsSection } from './settings-section';
|
import { SettingsSection } from './settings-section';
|
||||||
import { Plus, Pencil, Trash2, Check, X, Calendar as CalendarIcon, Copy, Link, Upload, Globe, RefreshCw, Eraser } from 'lucide-react';
|
import { Plus, Pencil, Trash2, Calendar as CalendarIcon, Copy, Link, Upload, Globe, RefreshCw, Eraser } from 'lucide-react';
|
||||||
import { cn, formatDateTime } from '@/lib/utils';
|
import { cn, formatDateTime } from '@/lib/utils';
|
||||||
import { ICalImportModal } from '@/components/calendar/ical-import-modal';
|
import { ICalImportModal } from '@/components/calendar/ical-import-modal';
|
||||||
import { ICalSubscriptionModal } from '@/components/calendar/ical-subscription-modal';
|
import { ICalSubscriptionModal } from '@/components/calendar/ical-subscription-modal';
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { useState, useCallback } from 'react';
|
|||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
import { useConfig } from '@/hooks/use-config';
|
import { useConfig } from '@/hooks/use-config';
|
||||||
import { useSettingsStore } from '@/stores/settings-store';
|
import { useSettingsStore } from '@/stores/settings-store';
|
||||||
import type { ArchiveMode, HoverAction, HoverActionsMode, HoverActionsCorner } from '@/stores/settings-store';
|
import type { ArchiveMode, HoverAction } from '@/stores/settings-store';
|
||||||
import { ALL_HOVER_ACTIONS } from '@/stores/settings-store';
|
import { ALL_HOVER_ACTIONS } from '@/stores/settings-store';
|
||||||
import { useAuthStore } from '@/stores/auth-store';
|
import { useAuthStore } from '@/stores/auth-store';
|
||||||
import { useEmailStore } from '@/stores/email-store';
|
import { useEmailStore } from '@/stores/email-store';
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export function SmimeCertificateModal({
|
|||||||
isOpen,
|
isOpen,
|
||||||
onClose,
|
onClose,
|
||||||
record,
|
record,
|
||||||
type,
|
type: _type,
|
||||||
}: SmimeCertificateModalProps) {
|
}: SmimeCertificateModalProps) {
|
||||||
const t = useTranslations("smime");
|
const t = useTranslations("smime");
|
||||||
const id = useId();
|
const id = useId();
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ export function useCalendarAlerts() {
|
|||||||
}, [
|
}, [
|
||||||
calendarNotificationsEnabled, calendarNotificationSound, notificationSoundChoice,
|
calendarNotificationsEnabled, calendarNotificationSound, notificationSoundChoice,
|
||||||
isAuthenticated, events, calendars, acknowledgedAlerts,
|
isAuthenticated, events, calendars, acknowledgedAlerts,
|
||||||
acknowledgeAlert, addToast, t, locale,
|
acknowledgeAlert, addToast, t, locale, enableCalendarTasks, storeTasks,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const proactiveFetch = useCallback(async () => {
|
const proactiveFetch = useCallback(async () => {
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ import type { Email } from '@/lib/jmap/types';
|
|||||||
import { demoDate } from '../demo-utils';
|
import { demoDate } from '../demo-utils';
|
||||||
|
|
||||||
export function createDemoEmails(): Email[] {
|
export function createDemoEmails(): Email[] {
|
||||||
const now = new Date();
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
// ── Inbox ───────────────────────────────────────────────────
|
// ── Inbox ───────────────────────────────────────────────────
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-3
@@ -568,7 +568,6 @@ export class JMAPClient implements IJMAPClient {
|
|||||||
let position = 0;
|
let position = 0;
|
||||||
const batchSize = 100;
|
const batchSize = 100;
|
||||||
|
|
||||||
// eslint-disable-next-line no-constant-condition
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const { emails, hasMore } = await this.getEmails(mailboxId, undefined, batchSize, position);
|
const { emails, hasMore } = await this.getEmails(mailboxId, undefined, batchSize, position);
|
||||||
allEmails.push(...emails);
|
allEmails.push(...emails);
|
||||||
@@ -788,7 +787,6 @@ export class JMAPClient implements IJMAPClient {
|
|||||||
let position = 0;
|
let position = 0;
|
||||||
const batchSize = 100;
|
const batchSize = 100;
|
||||||
|
|
||||||
// eslint-disable-next-line no-constant-condition
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const response = await this.request([
|
const response = await this.request([
|
||||||
["Email/query", {
|
["Email/query", {
|
||||||
@@ -3836,7 +3834,7 @@ export class JMAPClient implements IJMAPClient {
|
|||||||
blob: Blob,
|
blob: Blob,
|
||||||
identityId: string,
|
identityId: string,
|
||||||
sentMailboxId: string,
|
sentMailboxId: string,
|
||||||
draftMailboxId?: string,
|
_draftMailboxId?: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
// Upload the raw message
|
// Upload the raw message
|
||||||
const file = new File([blob], 'message.eml', { type: 'message/rfc822' });
|
const file = new File([blob], 'message.eml', { type: 'message/rfc822' });
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { describe, it, expect, vi, beforeAll } from 'vitest';
|
import { describe, it, expect, beforeAll } from 'vitest';
|
||||||
import {
|
import {
|
||||||
pemToDer,
|
pemToDer,
|
||||||
derToPem,
|
derToPem,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
import { describe, it, expect } from 'vitest';
|
||||||
import 'fake-indexeddb/auto';
|
import 'fake-indexeddb/auto';
|
||||||
|
|
||||||
// Each test file gets a fresh global indexedDB via fake-indexeddb/auto.
|
// Each test file gets a fresh global indexedDB via fake-indexeddb/auto.
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ vi.mock('@/lib/smime/certificate-utils', () => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
import { useSmimeStore } from '@/stores/smime-store';
|
import { useSmimeStore } from '@/stores/smime-store';
|
||||||
import { listKeyRecords, listPublicCerts, saveKeyRecord, deleteKeyRecord, savePublicCert, deletePublicCert } from '@/lib/smime/key-storage';
|
import { listKeyRecords, listPublicCerts, saveKeyRecord, deleteKeyRecord, deletePublicCert } from '@/lib/smime/key-storage';
|
||||||
import { importPkcs12, unlockPrivateKey } from '@/lib/smime/pkcs12-import';
|
import { importPkcs12, unlockPrivateKey } from '@/lib/smime/pkcs12-import';
|
||||||
import type { SmimeKeyRecord, SmimePublicCert } from '@/lib/smime/types';
|
import type { SmimeKeyRecord, SmimePublicCert } from '@/lib/smime/types';
|
||||||
|
|
||||||
@@ -128,7 +128,7 @@ describe('smime-store', () => {
|
|||||||
it('imports and adds key record', async () => {
|
it('imports and adds key record', async () => {
|
||||||
vi.mocked(importPkcs12).mockResolvedValue({
|
vi.mocked(importPkcs12).mockResolvedValue({
|
||||||
keyRecord: mockKeyRecord,
|
keyRecord: mockKeyRecord,
|
||||||
certInfo: {} as any,
|
certInfo: {} as unknown as import('@/lib/smime/types').CertificateInfo,
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await useSmimeStore.getState().importPKCS12(
|
const result = await useSmimeStore.getState().importPKCS12(
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import * as asn1js from 'asn1js';
|
import * as asn1js from 'asn1js';
|
||||||
import * as pkijs from 'pkijs';
|
import * as pkijs from 'pkijs';
|
||||||
import {
|
import {
|
||||||
parseCertificateDer,
|
|
||||||
extractCertificateInfo,
|
extractCertificateInfo,
|
||||||
classifyCapabilities,
|
classifyCapabilities,
|
||||||
} from './certificate-utils';
|
} from './certificate-utils';
|
||||||
@@ -36,7 +35,6 @@ export async function importPkcs12(
|
|||||||
|
|
||||||
// Verify MAC if present
|
// Verify MAC if present
|
||||||
if (pfx.macData) {
|
if (pfx.macData) {
|
||||||
const macOk = await pfx.parsedValue?.integrityMode === undefined || true;
|
|
||||||
// PKIjs handles MAC verification internally during parseInternalValues
|
// PKIjs handles MAC verification internally during parseInternalValues
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import * as asn1js from 'asn1js';
|
|
||||||
import * as pkijs from 'pkijs';
|
import * as pkijs from 'pkijs';
|
||||||
import { parseCertificateDer } from './certificate-utils';
|
import { parseCertificateDer } from './certificate-utils';
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import * as asn1js from 'asn1js';
|
import * as asn1js from 'asn1js';
|
||||||
import * as pkijs from 'pkijs';
|
import * as pkijs from 'pkijs';
|
||||||
import { Convert } from 'pvtsutils';
|
|
||||||
import { parseCertificateDer } from './certificate-utils';
|
import { parseCertificateDer } from './certificate-utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -44,13 +43,13 @@ export async function smimeSign(
|
|||||||
const algorithm = privateKey.algorithm;
|
const algorithm = privateKey.algorithm;
|
||||||
const hashAlgorithm = 'SHA-256';
|
const hashAlgorithm = 'SHA-256';
|
||||||
|
|
||||||
let signAlg: string;
|
let _signAlg: string;
|
||||||
if (algorithm.name === 'RSASSA-PKCS1-v1_5' || algorithm.name === 'RSA-PSS') {
|
if (algorithm.name === 'RSASSA-PKCS1-v1_5' || algorithm.name === 'RSA-PSS') {
|
||||||
signAlg = algorithm.name;
|
_signAlg = algorithm.name;
|
||||||
} else if (algorithm.name === 'ECDSA') {
|
} else if (algorithm.name === 'ECDSA') {
|
||||||
signAlg = 'ECDSA';
|
_signAlg = 'ECDSA';
|
||||||
} else {
|
} else {
|
||||||
signAlg = 'RSASSA-PKCS1-v1_5';
|
_signAlg = 'RSASSA-PKCS1-v1_5';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sign
|
// Sign
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import type { ContactCard, NameComponent, ContactMedia, ContactOnlineService, AnniversaryDate, PartialDate } from "@/lib/jmap/types";
|
import type { ContactCard, NameComponent, ContactOnlineService, AnniversaryDate, PartialDate } from "@/lib/jmap/types";
|
||||||
|
|
||||||
// Convert RFC 9553 AnniversaryDate (PartialDate|Timestamp|string) to vCard date string
|
// Convert RFC 9553 AnniversaryDate (PartialDate|Timestamp|string) to vCard date string
|
||||||
function anniversaryDateToVcardString(date: AnniversaryDate): string {
|
function anniversaryDateToVcardString(date: AnniversaryDate): string {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { describe, it, expect, beforeEach } from 'vitest';
|
import { describe, it, expect, beforeEach } from 'vitest';
|
||||||
import { useFilterStore } from '../filter-store';
|
import { useFilterStore } from '../filter-store';
|
||||||
import type { FilterRule } from '@/lib/jmap/sieve-types';
|
import type { FilterRule } from '@/lib/jmap/sieve-types';
|
||||||
|
import type { IJMAPClient } from '@/lib/jmap/client-interface';
|
||||||
|
|
||||||
const makeRule = (overrides: Partial<FilterRule> = {}): FilterRule => ({
|
const makeRule = (overrides: Partial<FilterRule> = {}): FilterRule => ({
|
||||||
id: 'rule-1',
|
id: 'rule-1',
|
||||||
@@ -156,7 +157,7 @@ describe('filter-store', () => {
|
|||||||
getSieveScripts: async () => [{ id: 's1', name: 'main', blobId: 'b1', isActive: true }],
|
getSieveScripts: async () => [{ id: 's1', name: 'main', blobId: 'b1', isActive: true }],
|
||||||
getSieveScriptContent: async () => 'require ["fileinto"];\nif header :contains "From" "x" { fileinto "Y"; }',
|
getSieveScriptContent: async () => 'require ["fileinto"];\nif header :contains "From" "x" { fileinto "Y"; }',
|
||||||
};
|
};
|
||||||
await useFilterStore.getState().fetchFilters(mockClient as any);
|
await useFilterStore.getState().fetchFilters(mockClient as unknown as IJMAPClient);
|
||||||
expect(useFilterStore.getState().isOpaque).toBe(true);
|
expect(useFilterStore.getState().isOpaque).toBe(true);
|
||||||
expect(useFilterStore.getState().rules).toEqual([]);
|
expect(useFilterStore.getState().rules).toEqual([]);
|
||||||
});
|
});
|
||||||
@@ -170,7 +171,7 @@ describe('filter-store', () => {
|
|||||||
getSieveScripts: async () => [{ id: 's1', name: 'main', blobId: 'b1', isActive: true }],
|
getSieveScripts: async () => [{ id: 's1', name: 'main', blobId: 'b1', isActive: true }],
|
||||||
getSieveScriptContent: async () => script,
|
getSieveScriptContent: async () => script,
|
||||||
};
|
};
|
||||||
await useFilterStore.getState().fetchFilters(mockClient as any);
|
await useFilterStore.getState().fetchFilters(mockClient as unknown as IJMAPClient);
|
||||||
expect(useFilterStore.getState().isOpaque).toBe(false);
|
expect(useFilterStore.getState().isOpaque).toBe(false);
|
||||||
expect(useFilterStore.getState().rules).toEqual(rules);
|
expect(useFilterStore.getState().rules).toEqual(rules);
|
||||||
});
|
});
|
||||||
@@ -181,7 +182,7 @@ describe('filter-store', () => {
|
|||||||
getSieveScripts: async () => [],
|
getSieveScripts: async () => [],
|
||||||
getSieveScriptContent: async () => '',
|
getSieveScriptContent: async () => '',
|
||||||
};
|
};
|
||||||
await useFilterStore.getState().fetchFilters(mockClient as any);
|
await useFilterStore.getState().fetchFilters(mockClient as unknown as IJMAPClient);
|
||||||
expect(useFilterStore.getState().rules).toEqual([]);
|
expect(useFilterStore.getState().rules).toEqual([]);
|
||||||
expect(useFilterStore.getState().activeScriptId).toBeNull();
|
expect(useFilterStore.getState().activeScriptId).toBeNull();
|
||||||
});
|
});
|
||||||
@@ -191,7 +192,7 @@ describe('filter-store', () => {
|
|||||||
getSieveCapabilities: () => null,
|
getSieveCapabilities: () => null,
|
||||||
getSieveScripts: async () => { throw new Error('Network error'); },
|
getSieveScripts: async () => { throw new Error('Network error'); },
|
||||||
};
|
};
|
||||||
await useFilterStore.getState().fetchFilters(mockClient as any);
|
await useFilterStore.getState().fetchFilters(mockClient as unknown as IJMAPClient);
|
||||||
expect(useFilterStore.getState().error).toBe('Network error');
|
expect(useFilterStore.getState().error).toBe('Network error');
|
||||||
expect(useFilterStore.getState().isLoading).toBe(false);
|
expect(useFilterStore.getState().isLoading).toBe(false);
|
||||||
});
|
});
|
||||||
@@ -209,7 +210,7 @@ describe('filter-store', () => {
|
|||||||
rules: [makeRule()],
|
rules: [makeRule()],
|
||||||
isOpaque: false,
|
isOpaque: false,
|
||||||
});
|
});
|
||||||
await useFilterStore.getState().saveFilters(mockClient as any);
|
await useFilterStore.getState().saveFilters(mockClient as unknown as IJMAPClient);
|
||||||
expect(calls).toHaveLength(1);
|
expect(calls).toHaveLength(1);
|
||||||
expect(calls[0].method).toBe('updateSieveScript');
|
expect(calls[0].method).toBe('updateSieveScript');
|
||||||
expect(calls[0].args[0]).toBe('existing-id');
|
expect(calls[0].args[0]).toBe('existing-id');
|
||||||
@@ -230,7 +231,7 @@ describe('filter-store', () => {
|
|||||||
rules: [makeRule()],
|
rules: [makeRule()],
|
||||||
isOpaque: false,
|
isOpaque: false,
|
||||||
});
|
});
|
||||||
await useFilterStore.getState().saveFilters(mockClient as any);
|
await useFilterStore.getState().saveFilters(mockClient as unknown as IJMAPClient);
|
||||||
expect(calls).toHaveLength(1);
|
expect(calls).toHaveLength(1);
|
||||||
expect(calls[0].method).toBe('createSieveScript');
|
expect(calls[0].method).toBe('createSieveScript');
|
||||||
expect(calls[0].args[2]).toBe(true); // activate flag
|
expect(calls[0].args[2]).toBe(true); // activate flag
|
||||||
@@ -248,7 +249,7 @@ describe('filter-store', () => {
|
|||||||
isOpaque: true,
|
isOpaque: true,
|
||||||
rawScript: 'require ["fileinto"];\nif header :contains "From" "x" { fileinto "Y"; }',
|
rawScript: 'require ["fileinto"];\nif header :contains "From" "x" { fileinto "Y"; }',
|
||||||
});
|
});
|
||||||
await useFilterStore.getState().saveFilters(mockClient as any);
|
await useFilterStore.getState().saveFilters(mockClient as unknown as IJMAPClient);
|
||||||
expect(savedContent).toContain('require ["fileinto"]');
|
expect(savedContent).toContain('require ["fileinto"]');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -257,7 +258,7 @@ describe('filter-store', () => {
|
|||||||
updateSieveScript: async () => { throw new Error('Server error'); },
|
updateSieveScript: async () => { throw new Error('Server error'); },
|
||||||
};
|
};
|
||||||
useFilterStore.setState({ activeScriptId: 'existing-id', rules: [makeRule()] });
|
useFilterStore.setState({ activeScriptId: 'existing-id', rules: [makeRule()] });
|
||||||
await expect(useFilterStore.getState().saveFilters(mockClient as any)).rejects.toThrow('Server error');
|
await expect(useFilterStore.getState().saveFilters(mockClient as unknown as IJMAPClient)).rejects.toThrow('Server error');
|
||||||
expect(useFilterStore.getState().error).toBe('Server error');
|
expect(useFilterStore.getState().error).toBe('Server error');
|
||||||
expect(useFilterStore.getState().isSaving).toBe(false);
|
expect(useFilterStore.getState().isSaving).toBe(false);
|
||||||
});
|
});
|
||||||
@@ -269,7 +270,7 @@ describe('filter-store', () => {
|
|||||||
};
|
};
|
||||||
const rules = [makeRule({ name: 'My Filter' })];
|
const rules = [makeRule({ name: 'My Filter' })];
|
||||||
useFilterStore.setState({ activeScriptId: 'existing-id', rules, isOpaque: false });
|
useFilterStore.setState({ activeScriptId: 'existing-id', rules, isOpaque: false });
|
||||||
await useFilterStore.getState().saveFilters(mockClient as any);
|
await useFilterStore.getState().saveFilters(mockClient as unknown as IJMAPClient);
|
||||||
expect(savedContent).toContain('@metadata:begin');
|
expect(savedContent).toContain('@metadata:begin');
|
||||||
expect(savedContent).toContain('My Filter');
|
expect(savedContent).toContain('My Filter');
|
||||||
expect(savedContent).toContain('fileinto "Archive"');
|
expect(savedContent).toContain('fileinto "Archive"');
|
||||||
@@ -280,7 +281,7 @@ describe('filter-store', () => {
|
|||||||
updateSieveScript: async () => {},
|
updateSieveScript: async () => {},
|
||||||
};
|
};
|
||||||
useFilterStore.setState({ activeScriptId: 'existing-id', rules: [makeRule()], isOpaque: false, rawScript: '' });
|
useFilterStore.setState({ activeScriptId: 'existing-id', rules: [makeRule()], isOpaque: false, rawScript: '' });
|
||||||
await useFilterStore.getState().saveFilters(mockClient as any);
|
await useFilterStore.getState().saveFilters(mockClient as unknown as IJMAPClient);
|
||||||
expect(useFilterStore.getState().rawScript).toContain('@metadata:begin');
|
expect(useFilterStore.getState().rawScript).toContain('@metadata:begin');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -311,7 +312,7 @@ describe('filter-store', () => {
|
|||||||
return generateScript(inactiveRules);
|
return generateScript(inactiveRules);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
await useFilterStore.getState().fetchFilters(mockClient as any);
|
await useFilterStore.getState().fetchFilters(mockClient as unknown as IJMAPClient);
|
||||||
expect(useFilterStore.getState().activeScriptId).toBe('s2');
|
expect(useFilterStore.getState().activeScriptId).toBe('s2');
|
||||||
expect(useFilterStore.getState().rules[0].name).toBe('Active');
|
expect(useFilterStore.getState().rules[0].name).toBe('Active');
|
||||||
});
|
});
|
||||||
@@ -322,7 +323,7 @@ describe('filter-store', () => {
|
|||||||
getSieveCapabilities: () => caps,
|
getSieveCapabilities: () => caps,
|
||||||
getSieveScripts: async () => [],
|
getSieveScripts: async () => [],
|
||||||
};
|
};
|
||||||
await useFilterStore.getState().fetchFilters(mockClient as any);
|
await useFilterStore.getState().fetchFilters(mockClient as unknown as IJMAPClient);
|
||||||
expect(useFilterStore.getState().sieveCapabilities).toEqual(caps);
|
expect(useFilterStore.getState().sieveCapabilities).toEqual(caps);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -335,7 +336,7 @@ describe('filter-store', () => {
|
|||||||
getSieveScripts: async () => [{ id: 's1', name: 'main', blobId: 'b1', isActive: true }],
|
getSieveScripts: async () => [{ id: 's1', name: 'main', blobId: 'b1', isActive: true }],
|
||||||
getSieveScriptContent: async () => script,
|
getSieveScriptContent: async () => script,
|
||||||
};
|
};
|
||||||
await useFilterStore.getState().fetchFilters(mockClient as any);
|
await useFilterStore.getState().fetchFilters(mockClient as unknown as IJMAPClient);
|
||||||
expect(useFilterStore.getState().rawScript).toBe(script);
|
expect(useFilterStore.getState().rawScript).toBe(script);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user