From aaa48782294f900b5802961b80218eeb824da612 Mon Sep 17 00:00:00 2001 From: Denis Shatskiy Date: Thu, 10 Jul 2025 09:45:18 +0700 Subject: [PATCH] feat: Integrate react-router-dom for routing and enhance App component with new navigation structure --- frontend/index.html | 3 + frontend/package-lock.json | 44 +++++++- frontend/package.json | 2 +- frontend/src/App.jsx | 188 +++++++++++++-------------------- frontend/src/ServerManager.jsx | 51 ++++++--- 5 files changed, 152 insertions(+), 136 deletions(-) diff --git a/frontend/index.html b/frontend/index.html index 08537b6..7fbd771 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -16,6 +16,9 @@
+ diff --git a/frontend/package-lock.json b/frontend/package-lock.json index ff62c5a..455cbcb 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -14,7 +14,8 @@ "bootstrap": "^5.3.7", "react": "^19.1.0", "react-bootstrap": "^2.10.10", - "react-dom": "^19.1.0" + "react-dom": "^19.1.0", + "react-router-dom": "^6.30.1" }, "devDependencies": { "@eslint/js": "^9.29.0", @@ -563,6 +564,15 @@ "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, + "node_modules/@remix-run/router": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.0.tgz", + "integrity": "sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@restart/hooks": { "version": "0.4.16", "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.16.tgz", @@ -2067,6 +2077,38 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "6.30.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.1.tgz", + "integrity": "sha512-X1m21aEmxGXqENEPG3T6u0Th7g0aS4ZmoNynhbs+Cn+q+QGTLt+d5IQ2bHAXKzKcxGJjxACpVbnYQSCRcfxHlQ==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.30.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.1.tgz", + "integrity": "sha512-llKsgOkZdbPU1Eg3zK8lCn+sjD9wMRZZPuzmdWWX5SUs8OFkN5HnFVC0u5KMeMaC9aoancFI/KoLuKPqN+hxHw==", + "license": "MIT", + "dependencies": { + "@remix-run/router": "1.23.0", + "react-router": "6.30.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", diff --git a/frontend/package.json b/frontend/package.json index 2c3d0c9..1966f03 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -17,7 +17,7 @@ "react": "^19.1.0", "react-bootstrap": "^2.10.10", "react-dom": "^19.1.0", - "react-router-dom": "^6.23.1" + "react-router-dom": "^6.30.1" }, "devDependencies": { "@eslint/js": "^9.29.0", diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 7d77bdb..85dfcd0 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -1,9 +1,9 @@ import { useState, useEffect } from 'react'; import { Container } from 'react-bootstrap'; -import { - IconBrandTabler, - IconWorld, - IconNetwork, +import { + IconBrandTabler, + IconWorld, + IconNetwork, IconSettings, IconHome, IconFileText, @@ -22,140 +22,94 @@ import DataManager from './DataManager'; import ServerManager from './ServerManager'; import './App.css'; import axios from 'axios'; +import { + BrowserRouter as Router, + Routes, + Route, + Link, + useLocation, + Navigate +} from 'react-router-dom'; function App() { - const [activeTab, setActiveTab] = useState('dashboard'); + return ( + + + + ); +} + +function MainLayout() { + const location = useLocation(); const [notifications] = useState([ { id: 1, title: 'Новый домен добавлен', message: 'example.com был добавлен в список', time: '2 мин назад' }, { id: 2, title: 'Изменения сохранены', message: 'Список AS обновлен в S3', time: '5 мин назад' } ]); const navItems = [ - { id: 'dashboard', title: 'Dashboard', icon: IconHome }, - { id: 'domains', title: 'Домены', icon: IconWorld }, - { id: 'asns', title: 'AS', icon: IconNetwork }, - { id: 'servers', title: 'Серверы', icon: IconServer }, - { id: 'files', title: 'Файлы', icon: IconFileText }, - { id: 'cloud', title: 'Облако', icon: IconCloud }, - { id: 'security', title: 'Безопасность', icon: IconShield }, - { id: 'activity', title: 'Активность', icon: IconActivity }, - { id: 'settings', title: 'Настройки', icon: IconSettings } + { id: 'domains', title: 'Домены', icon: IconWorld, path: '/domains' }, + { id: 'asns', title: 'AS', icon: IconNetwork, path: '/asns' }, + { id: 'servers', title: 'Серверы', icon: IconServer, path: '/servers' }, + { id: 'files', title: 'Файлы', icon: IconFileText, path: '/files' }, + { id: 'cloud', title: 'Облако', icon: IconCloud, path: '/cloud' }, + { id: 'security', title: 'Безопасность', icon: IconShield, path: '/security' }, + { id: 'activity', title: 'Активность', icon: IconActivity, path: '/activity' }, + { id: 'settings', title: 'Настройки', icon: IconSettings, path: '/settings' } ]; - const renderContent = () => { - switch (activeTab) { - case 'dashboard': - return ; - case 'domains': - return ( - - ); - case 'asns': - return ( - - ); - case 'servers': - return ; - default: - return ; - } - }; + // Определяем активную вкладку по адресу + const activeTab = navItems.find(item => location.pathname.startsWith(item.path))?.id || 'domains'; return (
{/* Верхнее меню Tabler Admin */}
- + S3 Lists Manager - - +
-
-
- {renderContent()} +
+
+
+ +
+
+ + + } /> + + } /> + } /> + } /> + {/* Можно добавить другие разделы по необходимости */} + +
-
+
); } diff --git a/frontend/src/ServerManager.jsx b/frontend/src/ServerManager.jsx index f5dc8ee..820c89a 100644 --- a/frontend/src/ServerManager.jsx +++ b/frontend/src/ServerManager.jsx @@ -526,17 +526,35 @@ function ServerManager() { // Модальное окно для редактирования сервера с backdrop и анимацией function EditServerModal({ show, server, onChange, onSave, onClose }) { - if (!show || !server) return null; + const modalRef = useRef(null); + + useEffect(() => { + if (window.Tabler && window.Tabler.Modal && modalRef.current) { + const modalInstance = window.Tabler.Modal.getOrCreateInstance(modalRef.current); + if (show) { + modalInstance.show(); + } else { + modalInstance.hide(); + } + // Закрытие по событию Tabler + const handler = () => onClose && onClose(); + modalRef.current.addEventListener('hide.bs.modal', handler); + return () => { + modalRef.current.removeEventListener('hide.bs.modal', handler); + }; + } + }, [show, onClose]); + return ( - <> -
-
-
-
-
Редактировать сервер
- -
-
+
+
+
+
+
Редактировать сервер
+ +
+
+ {server && (
{ e.preventDefault(); onSave(); }}>
@@ -559,16 +577,15 @@ function EditServerModal({ show, server, onChange, onSave, onClose }) { onChange({ ...server, tunnel: e.target.value })} />
-
-
- - -
+ )} +
+
+ +
-
- +
); }