import { useState, useEffect, useCallback, 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'; import type { PathEntry } from '@/core/path-entry'; interface ProfileMeta { name: string; created: string; modified: string; } interface ProfileData { name: string; sys: PathEntry[]; user: PathEntry[]; created: string; modified: string; } interface Props { open: boolean; onClose: () => void; } export function ProfileDialog({ open, onClose }: Props) { const { t } = useTranslation(); const [profiles, setProfiles] = useState([]); const [newName, setNewName] = useState(''); const [selected, setSelected] = useState(null); const [selectedData, setSelectedData] = useState(null); const [saving, setSaving] = useState(false); const [renameOpen, setRenameOpen] = useState(false); const [renameValue, setRenameValue] = useState(''); const refreshProfiles = useCallback(async () => { const list = await invoke('list_profiles'); setProfiles(list); }, []); const prevOpen = useRef(false); useEffect(() => { if (open && !prevOpen.current) refreshProfiles(); prevOpen.current = open; }, [open, refreshProfiles]); const handleSave = async () => { if (!newName.trim()) return; setSaving(true); const { sysPaths, userPaths } = useAppStore.getState(); await invoke('save_profile', { name: newName.trim(), sys: sysPaths, user: userPaths }); setNewName(''); setSaving(false); refreshProfiles(); }; const handleLoad = async (name: string) => { const data = await invoke('load_profile', { name }); setSelected(name); setSelectedData(data); }; const handleApply = async () => { if (!selected || !selectedData) return; if (!window.confirm(t('profile.applyConfirm', { name: selected }))) return; useAppStore.getState().replaceBothPaths( selectedData.sys.map(e => e.path), selectedData.user.map(e => e.path), ); // 同步 disabled 状态 await invoke('save_disabled_state', { system: selectedData.sys.filter(e => !e.enabled).map(e => e.path), user: selectedData.user.filter(e => !e.enabled).map(e => e.path), }); const result = await useAppStore.getState().savePaths(); if (result.kind === 'success') { onClose(); } else if (result.kind === 'warning') { const { ask } = await import('@tauri-apps/plugin-dialog'); const confirmed = await ask(t('status.saveWarningLongPaths'), { title: t('dialog.backupTitle'), kind: 'warning' }); if (confirmed) { const forceResult = await useAppStore.getState().savePaths(true); if (forceResult.kind === 'success') { onClose(); } } } }; const handleDelete = async (name: string) => { if (!window.confirm(`删除配置文件 "${name}"?`)) return; await invoke('delete_profile', { name }); if (selected === name) { setSelected(null); setSelectedData(null); } refreshProfiles(); }; const handleRename = async () => { if (!selected || !renameValue.trim()) return; await invoke('rename_profile', { oldName: selected, newName: renameValue.trim() }); setRenameOpen(false); setSelected(renameValue.trim()); refreshProfiles(); }; return (

{t('profile.title')}

setNewName(e.target.value)} placeholder={t('profile.namePlaceholder')} className="px-2 py-1 text-sm rounded border outline-none w-44" style={{ backgroundColor: 'var(--app-list-bg)', color: 'var(--app-fg)', borderColor: 'var(--app-border)' }} />
{/* 左侧:列表 */}
{profiles.length === 0 ? (
{t('profile.noProfiles')}
) : ( profiles.map(p => (
handleLoad(p.name)} className="px-2 py-1.5 text-sm rounded cursor-pointer mb-0.5" style={{ backgroundColor: selected === p.name ? 'rgba(59,130,246,0.15)' : 'transparent', color: selected === p.name ? '#3b82f6' : 'var(--app-fg)', }} > {p.name}
)) )}
{/* 右侧:详情 */}
{!selectedData ? (
{profiles.length === 0 ? t('profile.noProfiles') : t('profile.selectProfile')}
) : (
{selectedData.name} {selectedData.modified}
{renameOpen && (
setRenameValue(e.target.value)} className="px-2 py-1 text-xs rounded border outline-none" style={{ backgroundColor: 'var(--app-list-bg)', color: 'var(--app-fg)', borderColor: 'var(--app-border)' }} />
)}
)}
); } function PathSection({ title, paths }: { title: string; paths: PathEntry[] }) { const { t } = useTranslation(); return (
{title}
{paths.length === 0 ? (
{t('profile.empty')}
) : (
{paths.map((e) => (
{e.enabled ? '●' : '○'} {e.path}
))}
)}
); }