fix: resolve all ESLint errors (lint now exits 0)

- useAppKeyboard: move all logic inside useEffect, fixes refs-in-render
  and no-unused-expressions for view mode shortcut handler
- SettingsPanel: refactor to inner component to fix setState-in-effect;
  remove unused maskKey function
- NoteList: remove re-exports (consumers import from noteListHelpers directly);
  fix no-unused-expressions in toggleGroup; eslint-disable for Icon-in-render
- useNoteActions: eslint-disable tabsRef.current assignment (valid pattern)
- Test files: fix no-explicit-any in useKeyboardNavigation, useSettings,
  useVaultLoader, wikilinks tests; update NoteList.test import path
This commit is contained in:
lucaronin
2026-02-23 08:53:43 +01:00
parent f476897d5e
commit efd79e9a3d
9 changed files with 74 additions and 79 deletions

View File

@@ -1,6 +1,7 @@
import { render, screen, fireEvent } from '@testing-library/react'
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { NoteList, getSortComparator, filterEntries } from './NoteList'
import { NoteList } from './NoteList'
import { getSortComparator, filterEntries } from '../utils/noteListHelpers'
import type { VaultEntry, SidebarSelection } from '../types'
const allSelection: SidebarSelection = { kind: 'filter', filter: 'all' }

View File

@@ -11,14 +11,10 @@ import {
type SortOption, type SortDirection, type SortConfig, type RelationshipGroup,
getSortComparator,
buildRelationshipGroups, filterEntries,
sortByModified, relativeDate, getDisplayDate,
relativeDate, getDisplayDate,
loadSortPreferences, saveSortPreferences,
} from '../utils/noteListHelpers'
// Re-export for consumers
export { sortByModified, filterEntries, buildRelationshipGroups, getSortComparator }
export type { SortOption }
interface NoteListProps {
entries: VaultEntry[]
selection: SidebarSelection
@@ -41,6 +37,7 @@ function PinnedCard({ entry, typeEntryMap, onSelectNote, showDate }: {
const Icon = getTypeIcon(entry.isA, te?.icon)
return (
<div className="relative cursor-pointer border-b border-[var(--border)]" style={{ backgroundColor: bgColor, padding: '14px 16px' }} onClick={() => onSelectNote(entry)}>
{/* eslint-disable-next-line react-hooks/static-components */}
<Icon width={16} height={16} className="absolute right-3 top-3.5" style={{ color }} data-testid="type-icon" />
<div className="pr-6 text-[14px] font-bold" style={{ color }}>{entry.title}</div>
<div className="mt-1 text-[12px] leading-[1.5] opacity-80" style={{ color, display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', overflow: 'hidden' }}>{entry.snippet}</div>
@@ -219,7 +216,7 @@ function NoteListInner({ entries, selection, selectedNote, allContent, modifiedF
}, [])
const toggleGroup = useCallback((label: string) => {
setCollapsedGroups((prev) => { const next = new Set(prev); next.has(label) ? next.delete(label) : next.add(label); return next })
setCollapsedGroups((prev) => { const next = new Set(prev); if (next.has(label)) { next.delete(label) } else { next.add(label) }; return next })
}, [])
const typeEntryMap = useTypeEntryMap(entries)

View File

@@ -1,4 +1,4 @@
import { useState, useEffect, useRef } from 'react'
import { useState, useRef } from 'react'
import { X, Eye, EyeSlash } from '@phosphor-icons/react'
import type { Settings } from '../types'
@@ -9,10 +9,6 @@ interface SettingsPanelProps {
onClose: () => void
}
function maskKey(key: string): string {
if (key.length <= 8) return '•'.repeat(key.length)
return key.slice(0, 7) + '•'.repeat(Math.min(key.length - 11, 12)) + key.slice(-4)
}
interface KeyFieldProps {
label: string
@@ -70,21 +66,15 @@ function KeyField({ label, placeholder, value, onChange, onClear }: KeyFieldProp
}
export function SettingsPanel({ open, settings, onSave, onClose }: SettingsPanelProps) {
const [anthropicKey, setAnthropicKey] = useState('')
const [openaiKey, setOpenaiKey] = useState('')
const [googleKey, setGoogleKey] = useState('')
const [githubToken, setGithubToken] = useState('')
useEffect(() => {
if (open) {
setAnthropicKey(settings.anthropic_key ?? '')
setOpenaiKey(settings.openai_key ?? '')
setGoogleKey(settings.google_key ?? '')
setGithubToken(settings.github_token ?? '')
}
}, [open, settings])
if (!open) return null
return <SettingsPanelInner settings={settings} onSave={onSave} onClose={onClose} />
}
function SettingsPanelInner({ settings, onSave, onClose }: Omit<SettingsPanelProps, 'open'>) {
const [anthropicKey, setAnthropicKey] = useState(settings.anthropic_key ?? '')
const [openaiKey, setOpenaiKey] = useState(settings.openai_key ?? '')
const [googleKey, setGoogleKey] = useState(settings.google_key ?? '')
const [githubToken, setGithubToken] = useState(settings.github_token ?? '')
const handleSave = () => {
const trimmed: Settings = {
@@ -218,6 +208,3 @@ export function SettingsPanel({ open, settings, onSave, onClose }: SettingsPanel
</div>
)
}
// Export maskKey for use in other components
export { maskKey }