/
nollieundergrob
/
PythonPackageStorage
Обзор
Документация
Войти
/
nollieundergrob
/
PythonPackageStorage
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
frontend/src/pages/LibraryDetail.jsx
250 строк
8 KB
nollieundergrob
asd
25 мар 2025, 10:19
25 мар 2025, 10:19
86abb1a
Код
Авторство
О чём код?
import { useEffect, useState } from 'react'; import { useParams } from 'react-router-dom'; import Loading from '../components/Loadin_Spinner'; function LibraryDetail() { const { type, id } = useParams(); const [library, setLibrary] = useState(null); const [loading, setLoading] = useState(true); const [selectedVersion, setSelectedVersion] = useState(''); const [installCommand, setInstallCommand] = useState(''); const [showAllVersions, setShowAllVersions] = useState(false); const [isFetchingCommand, setIsFetchingCommand] = useState(false); useEffect(() => { const loadLibrary = async () => { try { const response = await fetch(process.env.REACT_APP_BACKEND_URL+`/dev/${type}/${id}`); if (!response.ok) throw new Error('Ошибка загрузки данных'); const libraryData = await response.json(); setLibrary(libraryData); const latestStableVersion = filterStableVersions(libraryData.version)[0]; setSelectedVersion(latestStableVersion || ''); if (latestStableVersion) { setIsFetchingCommand(true); try { const initialCommand = await fetchInstallCommand( type, libraryData.library.name, latestStableVersion ); setInstallCommand(initialCommand); } catch (error) { console.error('Ошибка при получении команды установки:', error.message); setInstallCommand('Ошибка загрузки команды'); } finally { setIsFetchingCommand(false); } } else { setInstallCommand('Нет доступных версий для установки'); } } catch (error) { console.error('Ошибка загрузки данных:', error.message); } finally { setLoading(false); } }; loadLibrary(); }, [type, id]); const compareVersions = (a, b) => { const partsA = a.split('.').map(Number); const partsB = b.split('.').map(Number); for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) { const numA = partsA[i] || 0; const numB = partsB[i] || 0; if (numA > numB) return -1; // Более новые версии идут первыми if (numA < numB) return 1; // Более старые версии идут позже } return 0; }; const filterStableVersions = (versions) => { const stableVersionRegex = /^\d+(\.\d+)*$/; return versions .filter((v) => stableVersionRegex.test(v)) .sort(compareVersions); // Сортировка стабильных версий }; const fetchInstallCommand = async (type, name, version) => { try { const response = await fetch( "https://10.14.37.165/api"+`/simple/dev/${type}/${name}/${version}` ); if (!response.ok) throw new Error(`Ошибка ${response.status}`); const data = await response.json(); return data.command; } catch (error) { console.error('Ошибка при получении команды установки:', error.message); return 'Ошибка загрузки команды'; } }; const handleVersionChange = async (e) => { const selected = e.target.value; setSelectedVersion(selected); setIsFetchingCommand(true); try { const newCommand = await fetchInstallCommand(type, library.library.name, selected); setInstallCommand(newCommand); } catch (error) { console.error('Ошибка при получении команды установки:', error.message); setInstallCommand('Ошибка загрузки команды'); } finally { setIsFetchingCommand(false); } }; const toggleShowAllVersions = () => { setShowAllVersions((prev) => !prev); }; if (loading) { return <Loading />; } if (!library) { return <div className="error-container">Библиотека не найдена</div>; } const { library: libInfo, version } = library; const allVersionsSorted = [...version].sort(compareVersions); // Сортировка всех версий const filteredVersions = showAllVersions ? allVersionsSorted : filterStableVersions(version); return ( <div className="container"> <h1>{libInfo.name}</h1> <div className="description"> <p>{libInfo.description || 'Описание недоступно'}</p> </div> <div className="install_panel" style={{ '--order': 1 }}> <div className="header_row"> <p className="accept">Выберите версию:</p> <div className="versionRow"> <select value={selectedVersion} onChange={handleVersionChange} className="version-select" > {filteredVersions.map((v, index) => ( <option key={index} value={v}> {v === filteredVersions[0] ? `${v} (latest)` : v} {/* Помечаем первую версию как latest */} </option> ))} </select> <div className={`checkbox_container ${showAllVersions ? 'active' : ''}`}> <input type="checkbox" checked={showAllVersions} onChange={toggleShowAllVersions} /> <p>Показать все версии</p> </div> </div> </div> </div> <div className="install_panel" style={{ '--order': 2 }}> <div className="header_row"> <p className="accept"> Команда для установки {libInfo.name} ({selectedVersion}) </p> <div className="copy_row"> <p>Скопировать в буфер обмена</p> <button className="copy-btn" onClick={() => copyToClipboard(installCommand)} disabled={isFetchingCommand || installCommand === 'Ошибка загрузки команды'} > Copy </button> </div> </div> {isFetchingCommand ? ( <p>Загрузка команды...</p> ) : ( <pre className="copy-text">{installCommand}</pre> )} </div> <a href={ type === 'pypi' ? `https://pypi.org/project/${libInfo.name}` : `https://www.npmjs.com/package/${libInfo.name}` } className="link" > {type === 'pypi' ? 'Link to PyPI' : 'Link to NPM'} </a> <a href="/" className="link"> Back to Search </a> </div> ); } // Функция для копирования текста в буфер обмена function copyToClipboard(text) { try { if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(text) .then(() => { showNotification("Copied to clipboard!", "success"); }) .catch(err => { console.error("Failed to copy text: ", err); showNotification("Failed to copy text.", "error"); }); } else { const tempInput = document.createElement('textarea'); tempInput.value = text; tempInput.style.position = 'absolute'; tempInput.style.left = '-9999px'; document.body.appendChild(tempInput); tempInput.select(); try { document.execCommand('copy'); showNotification("Copied to clipboard!", "success"); } catch (err) { console.error("Fallback: Failed to copy text: ", err); showNotification("Fallback: Failed to copy text.", "error"); } document.body.removeChild(tempInput); } } catch (err) { console.error("Error in copyToClipboard: ", err); showNotification("Unexpected error occurred.", "error"); } } // Функция для показа уведомлений function showNotification(message, type) { const notification = document.createElement("div"); notification.className = `notification ${type}`; notification.textContent = message; document.body.appendChild(notification); // Плавное появление setTimeout(() => { notification.classList.add("show"); }, 300); // Удаление уведомления через 2 секунды setTimeout(() => { notification.classList.remove("show"); setTimeout(() => { notification.remove(); }, 500); // Длительность исчезновения }, 2000); } export default LibraryDetail;