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)) {
|
||||
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) => {
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -45,7 +45,7 @@ export default function FilesPage() {
|
||||
navigateByPath,
|
||||
refresh,
|
||||
createDirectory,
|
||||
uploadFile,
|
||||
uploadFile: _uploadFile,
|
||||
uploadFiles,
|
||||
uploadFolder,
|
||||
deleteResource,
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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' },
|
||||
|
||||
@@ -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/);
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -64,7 +64,7 @@ export function EmailList({
|
||||
const { client } = useAuthStore();
|
||||
const {
|
||||
selectedEmailIds,
|
||||
selectAllEmails,
|
||||
selectAllEmails: _selectAllEmails,
|
||||
clearSelection,
|
||||
batchMarkAsRead,
|
||||
batchDelete,
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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,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';
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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,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
@@ -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,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.
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,4 +1,3 @@
|
||||
import * as asn1js from 'asn1js';
|
||||
import * as pkijs from 'pkijs';
|
||||
import { parseCertificateDer } from './certificate-utils';
|
||||
|
||||
|
||||
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user