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:
Linus Rath
2026-03-26 18:35:56 +01:00
parent 733e99f094
commit 7a191cf78b
40 changed files with 62 additions and 68 deletions
+2 -2
View File
@@ -186,7 +186,7 @@ export default function CalendarPage() {
if (client && enableCalendarTasks && (normalizedViewMode === "tasks" || showTasksOnCalendar)) {
taskStore.fetchTasks(client);
}
}, [client, enableCalendarTasks, normalizedViewMode, showTasksOnCalendar]);
}, [client, enableCalendarTasks, normalizedViewMode, showTasksOnCalendar, taskStore]);
useEffect(() => {
if (client && calendars.length > 0 && dateRange) {
@@ -704,7 +704,7 @@ export default function CalendarPage() {
};
window.addEventListener("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(() =>
events.filter((e) => {
+2 -2
View File
@@ -122,7 +122,7 @@ export default function ContactsPage() {
const individuals = useMemo(() => contacts.filter(c => c.kind !== 'group'), [contacts]);
const selectedContact = contacts.find((c) => c.id === selectedContactId) || 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
const allKeywords = useMemo(() => {
@@ -307,7 +307,7 @@ export default function ContactsPage() {
}
};
const handleSelectGroup = (id: string) => {
const _handleSelectGroup = (id: string) => {
setSelectedGroupId(id);
setActiveCategory({ groupId: id });
setView("group-detail");
+1 -1
View File
@@ -45,7 +45,7 @@ export default function FilesPage() {
navigateByPath,
refresh,
createDirectory,
uploadFile,
uploadFile: _uploadFile,
uploadFiles,
uploadFolder,
deleteResource,
+1 -1
View File
@@ -11,7 +11,7 @@ import { useThemeStore } from "@/stores/theme-store";
import { useShallow } from "zustand/react/shallow";
import { useConfig } from "@/hooks/use-config";
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 { generateCodeVerifier, generateCodeChallenge, generateState } from "@/lib/oauth/pkce";
import { OAUTH_SCOPES } from "@/lib/oauth/tokens";
+1 -1
View File
@@ -3,7 +3,7 @@
import { useEffect, useState, useRef } from 'react';
import { Upload, Trash2, Power, Loader2, Palette, Save, Shield } from 'lucide-react';
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 = [
{ id: 'builtin-nord', name: 'Nord' },
+1 -1
View File
@@ -89,7 +89,7 @@ function localDateTime(dayOffset: number, hour: number, minute: number): string
}
/** Parse a JMAP duration like "PT1H30M", "P1D", "PT45M" into milliseconds. */
function parseDurationMs(dur: string): number {
function _parseDurationMs(dur: string): number {
let ms = 0;
const dayMatch = dur.match(/(\d+)D/);
const hourMatch = dur.match(/(\d+)H/);
+1 -1
View File
@@ -3,7 +3,7 @@
import { useMemo, useRef, useEffect, useCallback } from "react";
import { useTranslations, useFormatter } from "next-intl";
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 { parseDuration, getEventColor } from "./event-card";
import { getEventDayBounds, getPrimaryCalendarId } from "@/lib/calendar-utils";
@@ -2,7 +2,7 @@
import { useState, useRef, useEffect, useMemo } from "react";
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 type { Calendar } from "@/lib/jmap/types";
import { CalendarColorPicker } from "@/components/settings/calendar-management-settings";
+1 -1
View File
@@ -3,7 +3,7 @@
import { useMemo, useCallback, useState } from "react";
import { useTranslations } from "next-intl";
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 type { CalendarTask, Calendar } from "@/lib/jmap/types";
import type { TaskViewFilter } from "@/stores/task-store";
+2 -2
View File
@@ -6,7 +6,7 @@ import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { X, Trash2, CalendarDays, Bell, Flag } from "lucide-react";
import { format, parseISO } from "date-fns";
import { cn } from "@/lib/utils";
import type { CalendarTask, Calendar, CalendarEventAlert } from "@/lib/jmap/types";
interface TaskModalProps {
@@ -43,7 +43,7 @@ export function TaskModal({
onSave,
onDelete,
onClose,
isMobile,
isMobile: _isMobile,
}: TaskModalProps) {
const t = useTranslations("calendar");
const isEdit = !!task;
@@ -66,7 +66,7 @@ describe('ContactForm', () => {
const onSave = vi.fn().mockResolvedValue(undefined);
render(<ContactForm onSave={onSave} onCancel={vi.fn()} />);
const inputs = screen.getAllByRole('textbox');
const _inputs = screen.getAllByRole('textbox');
const givenNameInput = screen.getByPlaceholderText('given_name');
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 { ContactList } from '../contact-list';
import type { ContactCard } from '@/lib/jmap/types';
@@ -22,7 +22,7 @@ const bob = makeContact({
emails: { e0: { address: 'bob@example.com' } },
});
const group = makeContact({
const _group = makeContact({
id: '3',
kind: 'group',
name: { components: [{ kind: 'given', value: 'Team' }], isOrdered: true },
+1 -1
View File
@@ -2,7 +2,7 @@
import { useState, useEffect } from "react";
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 { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
+1 -1
View File
@@ -132,7 +132,7 @@ export function EmailContextMenu({
onEditDraft,
}: EmailContextMenuProps) {
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 isUnread = !email.keywords?.$seen;
const isStarred = email.keywords?.$flagged;
+1 -1
View File
@@ -6,7 +6,7 @@ import { formatDate } from "@/lib/utils";
import { Email } from "@/lib/jmap/types";
import { cn } from "@/lib/utils";
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 { useSettingsStore, KEYWORD_PALETTE } from "@/stores/settings-store";
import { useAuthStore } from "@/stores/auth-store";
+1 -1
View File
@@ -64,7 +64,7 @@ export function EmailList({
const { client } = useAuthStore();
const {
selectedEmailIds,
selectAllEmails,
selectAllEmails: _selectAllEmails,
clearSelection,
batchMarkAsRead,
batchDelete,
+4 -3
View File
@@ -204,7 +204,7 @@ const getCurrentColor = (keywords: Record<string, boolean> | undefined) => {
};
// Helper function to format recipients with contextual display
const formatRecipients = (
const _formatRecipients = (
recipients: Array<{ name?: string; email: string }> | undefined,
currentUserEmail: string | undefined,
t: (key: string, params?: Record<string, string | number>) => string
@@ -1751,6 +1751,7 @@ export function EmailViewer({
smimeStore.autoImportSignerCerts,
smimeStore.keyRecords,
smimeStore.unlockedDecryptionKeys,
smimeStore,
]);
// TNEF (winmail.dat) detection and processing
@@ -1928,7 +1929,7 @@ export function EmailViewer({
if (decryptedCidAttachments.length > 0) {
const urls: Record<string, string> = {};
decryptedCidAttachments.forEach((att, index) => {
decryptedCidAttachments.forEach((att) => {
const bytes = getAttachmentContentBytes(att);
if (!bytes) return;
const cidValue = att.contentId!.replace(/^<|>$/g, '');
@@ -1985,7 +1986,7 @@ export function EmailViewer({
cancelled = true;
objectUrls.forEach(url => URL.revokeObjectURL(url));
};
}, [client, email?.id, smimeDecryptedAttachments]);
}, [client, email?.id, smimeDecryptedAttachments, email?.attachments]);
const effectiveAttachments = useMemo<EffectiveAttachment[]>(() => {
if (smimeDecryptedAttachments.length > 0) {
@@ -305,7 +305,7 @@ function EmailCard({
cancelled = true;
objectUrls.forEach(url => URL.revokeObjectURL(url));
};
}, [client, email?.id]);
}, [client, email?.id, email?.attachments]);
// Sanitize and prepare email HTML content
const emailContent = useMemo(() => {
+2 -2
View File
@@ -453,13 +453,13 @@ export function FileBrowser({
})),
];
const handleNavigateUp = () => {
const handleNavigateUp = useCallback(() => {
if (currentPath === '/') return;
const segments = currentPath.split('/').filter(Boolean);
segments.pop();
const parentPath = segments.length === 0 ? '/' : '/' + segments.join('/');
onNavigate(parentPath, null);
};
}, [currentPath, onNavigate]);
const handleResourceClick = (resource: FileResource, e: React.MouseEvent) => {
if (resource.isDirectory) {
+1 -1
View File
@@ -2,7 +2,7 @@
import { useCallback, useState } from "react";
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 { getDroppedFilesAndFolders } from "@/lib/webdav/drop-utils";
+1 -1
View File
@@ -208,7 +208,7 @@ function FolderTreeItem({
}) {
const isExpanded = expandedIds.has(node.id);
const isSelected = currentPath === node.path;
const isLoading = loadingIds.has(node.id);
const _isLoading = loadingIds.has(node.id);
const children = childrenCache.get(node.id);
const hasChildren = children !== undefined && children.length > 0;
const indentPx = depth * 16;
@@ -45,7 +45,7 @@ export function IdentityManagerModal({ isOpen, onClose }: IdentityManagerModalPr
const client = useAuthStore((state) => state.client);
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 syncIdentities = useSyncIdentities();
+1 -1
View File
@@ -1,6 +1,6 @@
'use client';
import { useState, useMemo, useRef, useEffect, useCallback } from 'react';
import { useState, useMemo, useRef, useCallback } from 'react';
import { useTranslations } from 'next-intl';
import { icons as lucideIcons, type LucideIcon } from 'lucide-react';
import { Search, X } from 'lucide-react';
+1 -1
View File
@@ -2,7 +2,7 @@
import { useState, useRef, useEffect, useCallback } from "react";
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 { icons as lucideIcons, type LucideIcon } from "lucide-react";
import { useConfig } from "@/hooks/use-config";
+1 -1
View File
@@ -2,7 +2,7 @@
import { useState, useCallback } from 'react';
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 { cn } from '@/lib/utils';
import { Button } from '@/components/ui/button';
+1 -1
View File
@@ -429,7 +429,7 @@ export function Sidebar({
className,
}: SidebarProps) {
const { sidebarCollapsed: isCollapsed, toggleSidebarCollapsed } = useUIStore();
const { primaryIdentity } = useAuthStore();
const { primaryIdentity: _primaryIdentity } = useAuthStore();
const [expandedFolders, setExpandedFolders] = useState<Set<string>>(new Set());
const [tagsExpanded, setTagsExpanded] = useState(() => {
try {
@@ -6,7 +6,7 @@ import { useCalendarStore } from '@/stores/calendar-store';
import { useAuthStore } from '@/stores/auth-store';
import { toast } from '@/stores/toast-store';
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 { ICalImportModal } from '@/components/calendar/ical-import-modal';
import { ICalSubscriptionModal } from '@/components/calendar/ical-subscription-modal';
+1 -1
View File
@@ -4,7 +4,7 @@ import { useState, useCallback } from 'react';
import { useTranslations } from 'next-intl';
import { useConfig } from '@/hooks/use-config';
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 { useAuthStore } from '@/stores/auth-store';
import { useEmailStore } from '@/stores/email-store';
@@ -18,7 +18,7 @@ export function SmimeCertificateModal({
isOpen,
onClose,
record,
type,
type: _type,
}: SmimeCertificateModalProps) {
const t = useTranslations("smime");
const id = useId();
+1 -1
View File
@@ -108,7 +108,7 @@ export function useCalendarAlerts() {
}, [
calendarNotificationsEnabled, calendarNotificationSound, notificationSoundChoice,
isAuthenticated, events, calendars, acknowledgedAlerts,
acknowledgeAlert, addToast, t, locale,
acknowledgeAlert, addToast, t, locale, enableCalendarTasks, storeTasks,
]);
const proactiveFetch = useCallback(async () => {
-2
View File
@@ -2,8 +2,6 @@ import type { Email } from '@/lib/jmap/types';
import { demoDate } from '../demo-utils';
export function createDemoEmails(): Email[] {
const now = new Date();
return [
// ── Inbox ───────────────────────────────────────────────────
{
+1 -3
View File
@@ -568,7 +568,6 @@ export class JMAPClient implements IJMAPClient {
let position = 0;
const batchSize = 100;
// eslint-disable-next-line no-constant-condition
while (true) {
const { emails, hasMore } = await this.getEmails(mailboxId, undefined, batchSize, position);
allEmails.push(...emails);
@@ -788,7 +787,6 @@ export class JMAPClient implements IJMAPClient {
let position = 0;
const batchSize = 100;
// eslint-disable-next-line no-constant-condition
while (true) {
const response = await this.request([
["Email/query", {
@@ -3836,7 +3834,7 @@ export class JMAPClient implements IJMAPClient {
blob: Blob,
identityId: string,
sentMailboxId: string,
draftMailboxId?: string,
_draftMailboxId?: string,
): Promise<void> {
// Upload the raw message
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 {
pemToDer,
derToPem,
+1 -1
View File
@@ -1,4 +1,4 @@
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { describe, it, expect } from 'vitest';
import 'fake-indexeddb/auto';
// Each test file gets a fresh global indexedDB via fake-indexeddb/auto.
+2 -2
View File
@@ -21,7 +21,7 @@ vi.mock('@/lib/smime/certificate-utils', () => ({
}));
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 type { SmimeKeyRecord, SmimePublicCert } from '@/lib/smime/types';
@@ -128,7 +128,7 @@ describe('smime-store', () => {
it('imports and adds key record', async () => {
vi.mocked(importPkcs12).mockResolvedValue({
keyRecord: mockKeyRecord,
certInfo: {} as any,
certInfo: {} as unknown as import('@/lib/smime/types').CertificateInfo,
});
const result = await useSmimeStore.getState().importPKCS12(
-2
View File
@@ -1,7 +1,6 @@
import * as asn1js from 'asn1js';
import * as pkijs from 'pkijs';
import {
parseCertificateDer,
extractCertificateInfo,
classifyCapabilities,
} from './certificate-utils';
@@ -36,7 +35,6 @@ export async function importPkcs12(
// Verify MAC if present
if (pfx.macData) {
const macOk = await pfx.parsedValue?.integrityMode === undefined || true;
// PKIjs handles MAC verification internally during parseInternalValues
}
-1
View File
@@ -1,4 +1,3 @@
import * as asn1js from 'asn1js';
import * as pkijs from 'pkijs';
import { parseCertificateDer } from './certificate-utils';
+4 -5
View File
@@ -1,6 +1,5 @@
import * as asn1js from 'asn1js';
import * as pkijs from 'pkijs';
import { Convert } from 'pvtsutils';
import { parseCertificateDer } from './certificate-utils';
/**
@@ -44,13 +43,13 @@ export async function smimeSign(
const algorithm = privateKey.algorithm;
const hashAlgorithm = 'SHA-256';
let signAlg: string;
let _signAlg: string;
if (algorithm.name === 'RSASSA-PKCS1-v1_5' || algorithm.name === 'RSA-PSS') {
signAlg = algorithm.name;
_signAlg = algorithm.name;
} else if (algorithm.name === 'ECDSA') {
signAlg = 'ECDSA';
_signAlg = 'ECDSA';
} else {
signAlg = 'RSASSA-PKCS1-v1_5';
_signAlg = 'RSASSA-PKCS1-v1_5';
}
// Sign
+1 -1
View File
@@ -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
function anniversaryDateToVcardString(date: AnniversaryDate): string {
+14 -13
View File
@@ -1,6 +1,7 @@
import { describe, it, expect, beforeEach } from 'vitest';
import { useFilterStore } from '../filter-store';
import type { FilterRule } from '@/lib/jmap/sieve-types';
import type { IJMAPClient } from '@/lib/jmap/client-interface';
const makeRule = (overrides: Partial<FilterRule> = {}): FilterRule => ({
id: 'rule-1',
@@ -156,7 +157,7 @@ describe('filter-store', () => {
getSieveScripts: async () => [{ id: 's1', name: 'main', blobId: 'b1', isActive: true }],
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().rules).toEqual([]);
});
@@ -170,7 +171,7 @@ describe('filter-store', () => {
getSieveScripts: async () => [{ id: 's1', name: 'main', blobId: 'b1', isActive: true }],
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().rules).toEqual(rules);
});
@@ -181,7 +182,7 @@ describe('filter-store', () => {
getSieveScripts: 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().activeScriptId).toBeNull();
});
@@ -191,7 +192,7 @@ describe('filter-store', () => {
getSieveCapabilities: () => null,
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().isLoading).toBe(false);
});
@@ -209,7 +210,7 @@ describe('filter-store', () => {
rules: [makeRule()],
isOpaque: false,
});
await useFilterStore.getState().saveFilters(mockClient as any);
await useFilterStore.getState().saveFilters(mockClient as unknown as IJMAPClient);
expect(calls).toHaveLength(1);
expect(calls[0].method).toBe('updateSieveScript');
expect(calls[0].args[0]).toBe('existing-id');
@@ -230,7 +231,7 @@ describe('filter-store', () => {
rules: [makeRule()],
isOpaque: false,
});
await useFilterStore.getState().saveFilters(mockClient as any);
await useFilterStore.getState().saveFilters(mockClient as unknown as IJMAPClient);
expect(calls).toHaveLength(1);
expect(calls[0].method).toBe('createSieveScript');
expect(calls[0].args[2]).toBe(true); // activate flag
@@ -248,7 +249,7 @@ describe('filter-store', () => {
isOpaque: true,
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"]');
});
@@ -257,7 +258,7 @@ describe('filter-store', () => {
updateSieveScript: async () => { throw new Error('Server error'); },
};
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().isSaving).toBe(false);
});
@@ -269,7 +270,7 @@ describe('filter-store', () => {
};
const rules = [makeRule({ name: 'My Filter' })];
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('My Filter');
expect(savedContent).toContain('fileinto "Archive"');
@@ -280,7 +281,7 @@ describe('filter-store', () => {
updateSieveScript: async () => {},
};
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');
});
});
@@ -311,7 +312,7 @@ describe('filter-store', () => {
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().rules[0].name).toBe('Active');
});
@@ -322,7 +323,7 @@ describe('filter-store', () => {
getSieveCapabilities: () => caps,
getSieveScripts: async () => [],
};
await useFilterStore.getState().fetchFilters(mockClient as any);
await useFilterStore.getState().fetchFilters(mockClient as unknown as IJMAPClient);
expect(useFilterStore.getState().sieveCapabilities).toEqual(caps);
});
@@ -335,7 +336,7 @@ describe('filter-store', () => {
getSieveScripts: async () => [{ id: 's1', name: 'main', blobId: 'b1', isActive: true }],
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);
});
});