import { useState, useEffect, useMemo, useRef } from 'react'; import { invoke } from '@tauri-apps/api/core'; import { useTranslation } from 'react-i18next'; import { Modal } from '@/components/ui/Modal'; import { useAppStore } from '@/store/app-store'; interface ConflictLocation { dir: string; priority: number; } interface ConflictEntry { name: string; locations: ConflictLocation[]; } interface ToolGroup { dir: string; exists: boolean; exes: string[]; } type TabType = 'conflicts' | 'tools'; interface Props { open: boolean; onClose: () => void; } export function AnalyzeDialog({ open, onClose }: Props) { const { t } = useTranslation(); const [tab, setTab] = useState('conflicts'); const [loading, setLoading] = useState(false); const [conflicts, setConflicts] = useState([]); const [toolGroups, setToolGroups] = useState([]); const [searchQuery, setSearchQuery] = useState(''); const prevOpen = useRef(false); useEffect(() => { if (!open) { prevOpen.current = false; return; } if (prevOpen.current) return; prevOpen.current = true; setLoading(true); const paths = getEnabledPaths(); Promise.all([ invoke('scan_conflicts', { paths }), invoke('scan_tools', { paths, query: '' }), ]) .then(([c, t]) => { setConflicts(c); setToolGroups(t); }) .catch(console.error) .finally(() => setLoading(false)); }, [open]); // 搜索的工具清单 const filteredTools = useMemo(() => { if (!searchQuery.trim()) return toolGroups; const q = searchQuery.toLowerCase(); return toolGroups .map((g) => ({ ...g, exes: g.exes.filter((e) => e.toLowerCase().includes(q)) })) .filter((g) => g.exes.length > 0); }, [toolGroups, searchQuery]); return (
{/* 标题栏 */}

{t('analyze.title')}

{(['conflicts', 'tools'] as TabType[]).map((tb) => ( ))}
{/* 内容 */}
{loading ? (
{t('analyze.scanning')}
) : tab === 'conflicts' ? ( ) : ( )}
); } function ConflictsTab({ conflicts }: { conflicts: ConflictEntry[] }) { const { t } = useTranslation(); if (conflicts.length === 0) { return ; } return (

{t('analyze.conflictCount', { count: conflicts.length })}

{conflicts.map((c) => ( ))}
EXE {t('analyze.priority')}
{c.name} {c.locations.map((loc, i) => (
{i === 0 ? '✓' : '✗'} {loc.dir} {i > 0 && ( ({t('analyze.shadowed')}) )}
))}
); } function ToolsTab({ groups, query, onQueryChange, }: { groups: ToolGroup[]; query: string; onQueryChange: (q: string) => void; }) { const { t } = useTranslation(); return (
onQueryChange(e.target.value)} placeholder={t('analyze.searchPlaceholder')} className="w-full px-3 py-1.5 text-sm rounded mb-3 border outline-none" style={{ backgroundColor: 'var(--app-list-bg)', color: 'var(--app-fg)', borderColor: 'var(--app-border)', }} /> {groups.length === 0 ? ( ) : ( groups.map((g) => (
{g.dir} {!g.exists && t('analyze.notExists')}
{g.exes.map((exe) => ( {exe} ))}
)) )}
); } function EmptyHint({ text }: { text: string }) { return (
{text}
); } function getEnabledPaths(): string[] { const { sysPaths, userPaths } = useAppStore.getState(); return [...sysPaths.filter((e) => e.enabled), ...userPaths.filter((e) => e.enabled)].map( (e) => e.path, ); }