diff --git a/src/Charts/PrometheusChart.jsx b/src/Charts/PrometheusChart.jsx index c4f4bd0..ddfe219 100644 --- a/src/Charts/PrometheusChart.jsx +++ b/src/Charts/PrometheusChart.jsx @@ -14,7 +14,7 @@ const PrometheusChart = ({ metricName }) => { useEffect(() => { const fetchData = async () => { try { - const response = await axios.get(`http://192.168.2.39:3000/metrics?metric=zvks_apiforsnmp_ifOutUnicastPacket1`); + const response = await axios.get(`http://192.168.2.39:3000/metrics?metric=zvks_apiforsnmp_cpurawsystem`); const result = response.data; // Проверяем структуру данных diff --git a/src/Components/Layout/Dashboard.jsx b/src/Components/Layout/Dashboard.jsx index 8a409a7..fd733a7 100644 --- a/src/Components/Layout/Dashboard.jsx +++ b/src/Components/Layout/Dashboard.jsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from "react"; +import React, { useState, useEffect, useRef } from "react"; import SidebarMenu from "./SidebarMenu"; import TreeChart from "../TreeChart/TreeChart"; import "../../Style/Dashboard.css"; @@ -14,8 +14,11 @@ const Dashboard = () => { const [activeTab, setActiveTab] = useState("Главная"); const [tabContent, setTabContent] = useState({}); const [treeData, setTreeData] = useState(menuData); // Загружаем меню в state + const [sidebarWidth, setSidebarWidth] = useState(250); // Начальная ширина сайдбара + const [isResizing, setIsResizing] = useState(false); // Состояние перетаскивания + const sidebarRef = useRef(null); // Референс на сайдбар - // Обновление treeData каждые 10 секунд + // Обновление treeData каждые 30 секунд useEffect(() => { setTabContent(tabContentData); @@ -25,11 +28,48 @@ const Dashboard = () => { updateStatuses(updatedData); // Обновляем статусы return updatedData; }); - }, 10000); + }, 30000); return () => clearInterval(interval); }, []); + // Обработчик начала перетаскивания + const startResizing = (e) => { + e.preventDefault(); + setIsResizing(true); + }; + + // Обработчик движения мыши + const resize = (e) => { + if (isResizing) { + const newWidth = e.clientX; // Новая ширина сайдбара + if (newWidth > 100 && newWidth < 400) { // Ограничиваем минимальную и максимальную ширину + setSidebarWidth(newWidth); + } + } + }; + + // Обработчик окончания перетаскивания + const stopResizing = () => { + setIsResizing(false); + }; + + // Добавляем обработчики событий + useEffect(() => { + const handleMouseMove = (e) => resize(e); + const handleMouseUp = () => stopResizing(); + + if (isResizing) { + window.addEventListener("mousemove", handleMouseMove); + window.addEventListener("mouseup", handleMouseUp); + } + + return () => { + window.removeEventListener("mousemove", handleMouseMove); + window.removeEventListener("mouseup", handleMouseUp); + }; + }, [isResizing]); + const handleOpenTab = (id, title) => { if (!tabs.some((tab) => tab.id === id)) { setTabs([...tabs, { id, title }]); @@ -51,7 +91,8 @@ const Dashboard = () => {

Общий мониторинг

- {/* Теперь используем актуальные данные */} + {/* Используем актуальные данные */} +
); } else if (activeTab === "Визуализация") { @@ -64,8 +105,20 @@ const Dashboard = () => { return (
- {/* Передаём обновлённые данные */} -
+
+ + {/* Элемент для перетаскивания */} +
+
+ +
{ +const MenuItem = ({ item, onSelectItem, sidebarWidth }) => { const [isOpen, setIsOpen] = useState(false); const hasChildren = Array.isArray(item.items) && item.items.length > 0; - const backgroundColor = getStatusColor(item.status); + const statusColor = getStatusColor(item.status); const handleClick = () => { if (hasChildren) { @@ -16,15 +16,20 @@ const MenuItem = ({ item, onSelectItem }) => { }; return ( -
-
+
{/* Динамическая ширина */} +
+ {/* Круглый индикатор статуса */} +
{item.title} {hasChildren && {isOpen ? "▲" : "▼"}}
{isOpen && hasChildren && (
{item.items.map((child, index) => ( - + ))}
)} @@ -32,15 +37,21 @@ const MenuItem = ({ item, onSelectItem }) => { ); }; -function SidebarMenu({ data, onOpenTab }) { // Теперь получаем `data` из пропсов +function SidebarMenu({ data, onOpenTab, sidebarWidth }) { const handleSelectItem = (item) => { onOpenTab(item.id, item.title); }; return (
-

Меню

- +
{/* Динамическая ширина */} +

Меню

+ +
+
{/* Динамическая ширина */} +

Помощь

+

Настройка

+
); } diff --git a/src/Components/TreeChart/dataUtils.jsx b/src/Components/TreeChart/dataUtils.jsx index c506f21..85b5217 100644 --- a/src/Components/TreeChart/dataUtils.jsx +++ b/src/Components/TreeChart/dataUtils.jsx @@ -1,10 +1,10 @@ // Функция для генерации случайных статусов const getRandomStatus = () => { const statuses = [ - "green", "green", "green", "green", "green", "green", "green", // 7/10 chance - "yellow", // 1/10 chance - "orange", // 1/10 chance - "red", // 1/10 chance + ...Array(90).fill("green"), // 63/70 chance (примерно 90%) + ...Array(6).fill("yellow"), // 1/70 chance (примерно 1.43%) + ...Array(3).fill("orange"), // 1/70 chance (примерно 1.43%) + ...Array(1).fill("red"), // 1/70 chance (примерно 1.43%) ]; return statuses[Math.floor(Math.random() * statuses.length)]; }; diff --git a/src/Style/Dashboard.css b/src/Style/Dashboard.css index e39b9ad..d1f7b33 100644 --- a/src/Style/Dashboard.css +++ b/src/Style/Dashboard.css @@ -1,21 +1,56 @@ +/* Основной контейнер */ .dashboard-container { display: flex; height: 100vh; - width: 100vw; + width: 98vw; overflow: hidden; - /* Запрещаем появление скролла */ + margin-left: 20px; } +/* Сайдбар */ +.sidebar { + height: 100vh; + background-color: #3d74c7; + color: white; + position: fixed; + left: 0; + top: 0; + z-index: 999; + overflow: hidden; + transition: width 0.2s ease; + /* Плавное изменение ширины */ + display: flex; + flex-direction: column; +} + +/* Элемент для перетаскивания */ +.sidebar-resizer { + width: 5px; + /* Ширина элемента перетаскивания */ + height: 100%; + background-color: rgba(255, 255, 255, 0.1); + position: absolute; + right: 0; + top: 0; + cursor: ew-resize; + /* Курсор "изменить размер" */ + transition: background-color 0.2s ease; + z-index: 1000; + /* Убедимся, что элемент поверх других */ +} + +.sidebar-resizer:hover { + background-color: rgba(255, 255, 255, 0.3); + /* Эффект при наведении */ +} + +/* Основной контент */ .main-content { flex: 1; - min-width: 400px; - max-width: calc(100vw - 250px); padding: 20px; - box-sizing: border-box; - overflow-y: auto; - /* Добавляем вертикальную прокрутку */ - height: 100vh; - /* Ограничиваем высоту */ + margin-left: 50px; + transition: margin-left 0.2s ease; + /* Плавное изменение отступа */ } /* Контент */ @@ -26,19 +61,7 @@ box-shadow: 0 2px 5px rgba(29, 1, 1, 0.521); } -.default-content { - display: flex; - flex-direction: column; - gap: 50px; -} - -.tab-content { - background-color: #fff; - padding: 20px; - border-radius: 10px; - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); -} - +/* Заголовки */ h2 { color: #444; } diff --git a/src/Style/SidebarMenu.css b/src/Style/SidebarMenu.css index 749045c..9fcb8d6 100644 --- a/src/Style/SidebarMenu.css +++ b/src/Style/SidebarMenu.css @@ -1,71 +1,124 @@ /* Боковое меню */ .sidebar { - width: 270px; - background-color: #3d74c7; - padding: 20px; - box-sizing: border-box; - border-right: 1px solid white; height: 100vh; - /* Занимает всю высоту экрана */ - overflow-y: auto; - /* Прокрутка внутри меню, если контент не помещается */ - position: sticky; - /* Фиксируем меню */ + background-color: #3d74c7; + color: white; + position: fixed; + left: 0; top: 0; - /* Прилипаем к верху */ + z-index: 999; + overflow: hidden; + transition: width 0.2s ease; + /* Плавное изменение ширины */ + display: flex; + flex-direction: column; } +/* Контейнер для основного контента меню */ +.sidebar-content { + flex: 1; + overflow-y: auto; + /* Вертикальная прокрутка */ + overflow-x: hidden; + /* Убираем горизонтальную прокрутку */ + padding-bottom: 20px; + /* Отступ для "Помощи" и "Настроек" */ +} + +/* Заголовок меню */ .sidebar-title { margin-bottom: 20px; font-size: 18px; font-weight: bold; color: white; + padding: 10px; + /* Добавляем отступы */ } +/* Элементы меню */ .menu-item { margin-bottom: 10px; color: white; -} - -h2 { - color: white + width: 100%; + /* Ширина на всю ширину сайдбара */ } .menu-item-header { display: flex; - justify-content: space-between; align-items: center; + /* Выравниваем элементы по центру */ padding: 10px; - background-color: #3d74c7; border-radius: 5px; - border: 1px solid white; cursor: pointer; transition: background-color 0.3s ease; } .menu-item-header:hover { - background-color: #195fc9; + background-color: rgba(255, 255, 255, 0.1); + /* Легкий эффект при наведении */ } +/* Круглый индикатор статуса */ +.status-indicator { + width: 10px; + height: 10px; + border-radius: 50%; + /* Делаем круглым */ + margin-right: 10px; + /* Отступ от текста */ + flex-shrink: 0; + /* Запрещаем сжатие */ +} + +/* Анимация мигания для красного индикатора */ +@keyframes blink { + 0% { + opacity: 1; + } + + /* Полная видимость */ + 50% { + opacity: 0.3; + } + + /* Полупрозрачность */ + 100% { + opacity: 1; + } + + /* Полная видимость */ +} + +.status-indicator.blinking { + animation: blink 1s infinite; + /* Бесконечная анимация с интервалом 1 секунда */ +} + +/* Подменю */ .submenu { margin-left: 20px; margin-top: 10px; } -.tabs-container { - margin-top: 20px; -} - -.tab { +/* Футер сайдбара */ +.sidebar-footer { padding: 10px; background-color: #3d74c7; - border: 1px solid white; - border-radius: 5px; - margin-bottom: 5px; - cursor: pointer; - transition: background-color 0.3s ease; + text-align: center; + border-top: 1px solid rgba(255, 255, 255, 0.1); + /* Разделительная линия */ + flex-shrink: 0; + /* Запрещаем сжатие */ + width: 100%; + /* Ширина на всю ширину сайдбара */ } -.tab:hover { - background-color: #3d74c7; +.help, +.settings { + color: white; + margin: 5px 0; + /* Отступы между элементами */ + overflow-x: hidden; + /* Убираем горизонтальную прокрутку */ + text-align: left; } \ No newline at end of file diff --git a/src/Style/common.css b/src/Style/common.css index cbc0f84..d170447 100644 --- a/src/Style/common.css +++ b/src/Style/common.css @@ -1,43 +1,72 @@ /* src/Style/common.css */ -/* Вкладки */ + +/* Контейнер для вкладок */ .tabs { display: flex; gap: 5px; + /* Расстояние между вкладками */ padding: 5px; background-color: #3d74c7; + /* Цвет фона */ border-bottom: 2px solid #195fc9; + /* Линия под вкладками */ overflow-x: auto; + /* Прокрутка, если вкладок много */ border-radius: 5px; + /* Скругление углов */ white-space: nowrap; + /* Запрет переноса текста */ } +/* Стили для отдельной вкладки */ .tab { display: flex; align-items: center; background-color: #3d74c7; + /* Цвет фона вкладки */ color: white; - padding: 5px 10px; + /* Цвет текста */ + padding: 5px 15px; + /* Отступы внутри вкладки */ border-radius: 5px 5px 0 0; + /* Скругление углов */ cursor: pointer; - max-width: 250px; - min-width: 100px; + /* Курсор при наведении */ flex-shrink: 0; - position: relative; + /* Запрет сжатия */ + transition: background-color 0.3s ease; + /* Плавное изменение цвета */ } +/* Активная вкладка */ .tab.active { background-color: #195fc9; + /* Цвет фона активной вкладки */ } +/* Кнопка закрытия вкладки */ .close-tab { background: none; border: none; + color: white; + /* Цвет крестика */ cursor: pointer; font-size: 16px; + margin-left: 10px; + /* Отступ от текста */ padding: 0; + transition: color 0.3s ease; + /* Плавное изменение цвета */ } -.error { - color: red; - margin-bottom: 10px; +/* Эффект при наведении на кнопку закрытия */ +.close-tab:hover { + color: #ff6b6b; + /* Цвет крестика при наведении */ +} + +/* Эффект при наведении на вкладку */ +.tab:hover { + background-color: #195fc9; + /* Цвет фона при наведении */ } \ No newline at end of file