import { useState, useEffect } from 'react'; import { Box, Checkbox, Typography, List, ListItem, ListItemIcon, ListItemText, Collapse, CircularProgress, } from '@mui/material'; import FolderIcon from '@mui/icons-material/Folder'; import InsertDriveFileIcon from '@mui/icons-material/InsertDriveFile'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import ExpandLessIcon from '@mui/icons-material/ExpandLess'; interface FileNode { name: string; path: string; isDirectory: boolean; children: FileNode[]; } interface FilesSelectorProps { packName: string; onSelectionChange: (selectedFiles: string[]) => void; initialSelected?: string[]; // Добавляем этот параметр } export default function FilesSelector({ packName, onSelectionChange, initialSelected = [], // Значение по умолчанию }: FilesSelectorProps) { const [files, setFiles] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); // Используем initialSelected для начального состояния const [selectedFiles, setSelectedFiles] = useState(initialSelected); const [expandedFolders, setExpandedFolders] = useState>( new Set(), ); useEffect(() => { const fetchFiles = async () => { try { setLoading(true); const result = await window.electron.ipcRenderer.invoke( 'get-pack-files', packName, ); if (result.success) { setFiles(result.files); } else { setError(result.error); } } catch (err) { setError('Ошибка при загрузке файлов'); } finally { setLoading(false); } }; fetchFiles(); }, [packName]); // Обработка выбора файла/папки const handleToggle = ( path: string, isDirectory: boolean, children: FileNode[], ) => { let newSelected = [...selectedFiles]; if (isDirectory) { if (selectedFiles.includes(path)) { // Если папка выбрана, убираем ее и все вложенные файлы newSelected = newSelected.filter((p) => !p.startsWith(path)); } else { // Если папка не выбрана, добавляем ее и все вложенные файлы newSelected.push(path); const addChildPaths = (nodes: FileNode[]) => { for (const node of nodes) { newSelected.push(node.path); if (node.isDirectory) { addChildPaths(node.children); } } }; addChildPaths(children); } } else { // Для обычного файла просто переключаем состояние if (selectedFiles.includes(path)) { newSelected = newSelected.filter((p) => p !== path); } else { newSelected.push(path); } } setSelectedFiles(newSelected); onSelectionChange(newSelected); }; // Переключение раскрытия папки const toggleFolder = (path: string) => { const newExpanded = new Set(expandedFolders); if (expandedFolders.has(path)) { newExpanded.delete(path); } else { newExpanded.add(path); } setExpandedFolders(newExpanded); }; // Рекурсивный компонент для отображения файлов и папок const renderFileTree = (nodes: FileNode[]) => { // Сортировка: сначала папки, потом файлы const sortedNodes = [...nodes].sort((a, b) => { // Если у элементов разные типы (папка/файл) if (a.isDirectory !== b.isDirectory) { return a.isDirectory ? -1 : 1; // Папки идут первыми } // Если оба элемента одного типа, сортируем по алфавиту return a.name.localeCompare(b.name); }); return ( {sortedNodes.map((node) => (
handleToggle(node.path, node.isDirectory, node.children) } tabIndex={-1} sx={{ color: 'white' }} /> {node.isDirectory && ( toggleFolder(node.path)}> {expandedFolders.has(node.path) ? ( ) : ( )} )} {node.isDirectory ? ( ) : ( )} {node.isDirectory && node.children.length > 0 && ( {renderFileTree(node.children)} )}
))}
); }; if (loading) { return ; } if (error) { return {error}; } return ( {renderFileTree(files)} ); }