Deleted the trash files, added a button to minimize the side menu, and adjusted the styles
test-org/trust-module-frontend/pipeline/pr-rc This commit looks good
Details
test-org/trust-module-frontend/pipeline/pr-rc This commit looks good
Details
parent
bd96278895
commit
6a4640ba93
|
|
@ -78,7 +78,7 @@ const LineChartComponent = ({ chartData, metricName, colors, description, onRang
|
|||
<p style={{ fontWeight: 'bold', marginBottom: '5px' }}>{`Время: ${label}`}</p>
|
||||
{payload.map((item, index) => (
|
||||
<p key={index} style={{ color: item.color }}>
|
||||
{`${item.name}: ${item.value}`}
|
||||
{`${item.value}`}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
import React from 'react';
|
||||
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
|
||||
|
||||
const SystemStatusChart = ({ data }) => {
|
||||
const trimmedData = data.slice(-20);
|
||||
|
||||
return (
|
||||
<ResponsiveContainer width="100%" height={300}>
|
||||
<LineChart
|
||||
data={trimmedData}
|
||||
margin={{
|
||||
top: 5, right: 30, left: 20, bottom: 5,
|
||||
}}
|
||||
>
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<XAxis dataKey="time" />
|
||||
<YAxis domain={[0, 100]} />
|
||||
<Tooltip />
|
||||
<Legend />
|
||||
<Line
|
||||
type="monotone"
|
||||
dataKey="status"
|
||||
stroke="#8884d8"
|
||||
activeDot={{ r: 8 }}
|
||||
name=""
|
||||
/>
|
||||
</LineChart>
|
||||
</ResponsiveContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default SystemStatusChart;
|
||||
|
|
@ -92,7 +92,7 @@ const PrometheusChart = ({ metricName }) => {
|
|||
else if (range <= 86400) step = 120;
|
||||
else step = 300;
|
||||
|
||||
const response = await axios.get(`${import.meta.env.VITE_BACK_URL}/api/metrics`, {
|
||||
const response = await axios.get(`${import.meta.env.VITE_BACK_URL}/metrics`, {
|
||||
params: {
|
||||
metric: metricName,
|
||||
start,
|
||||
|
|
@ -170,8 +170,7 @@ const PrometheusChart = ({ metricName }) => {
|
|||
setSelectedRange({ ...range }); // Создаем новый объект, чтобы React увидел изменение
|
||||
setUseCustomRange(false);
|
||||
|
||||
// Принудительно обновляем данные
|
||||
fetchData();
|
||||
|
||||
};
|
||||
|
||||
const handleCustomRangeChange = () => {
|
||||
|
|
|
|||
|
|
@ -1,84 +0,0 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import "../Style/SystemStatusTable.css";
|
||||
import axios from "axios";
|
||||
|
||||
const SystemStatusTable = () => {
|
||||
const [systemData, setSystemData] = useState([]);
|
||||
const [expandedRow, setExpandedRow] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
|
||||
// Загрузка данных с бэкенда
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
const response = await axios.get("/trust.json"); // Укажите ваш endpoint
|
||||
setSystemData(response.data);
|
||||
setLoading(false);
|
||||
} catch (err) {
|
||||
setError(err.message);
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
// Обработчик для кнопки "Подробнее"
|
||||
const handleDetailsClick = (id) => {
|
||||
setExpandedRow(expandedRow === id ? null : id);
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return <p>Загрузка данных...</p>;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <p>Ошибка: {error}</p>;
|
||||
}
|
||||
|
||||
return (
|
||||
<table>
|
||||
<caption>
|
||||
<h2>Состояние системы</h2>
|
||||
</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Метрика</th>
|
||||
<th>Значение</th>
|
||||
<th>Статус</th>
|
||||
<th>Детали</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{systemData.map((item) => (
|
||||
<React.Fragment key={item.id}>
|
||||
<tr>
|
||||
<td>{item.name}</td>
|
||||
<td>{item.value}%</td>
|
||||
<td>
|
||||
<span className={`status ${item.status}`}>{item.status}</span>
|
||||
</td>
|
||||
<td>
|
||||
<button onClick={() => handleDetailsClick(item.id)}>
|
||||
{expandedRow === item.id ? "Скрыть" : "Подробнее"}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
{expandedRow === item.id && (
|
||||
<tr>
|
||||
<td colSpan="4">
|
||||
<div className="details">
|
||||
<p>{item.details}</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
};
|
||||
|
||||
export default SystemStatusTable;
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import "../Style/SystemStatusTable.css";
|
||||
import axios from "axios";
|
||||
|
||||
const SystemStatusTableSoftware = () => {
|
||||
const [systemData, setSystemData] = useState([]);
|
||||
const [expandedRow, setExpandedRow] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState(null);
|
||||
|
||||
// Загрузка данных с бэкенда
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
const response = await axios.get("/TrustSoftware.json"); // Укажите ваш endpoint
|
||||
setSystemData(response.data);
|
||||
setLoading(false);
|
||||
} catch (err) {
|
||||
setError(err.message);
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
// Обработчик для кнопки "Подробнее"
|
||||
const handleDetailsClick = (id) => {
|
||||
setExpandedRow(expandedRow === id ? null : id);
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return <p>Загрузка данных...</p>;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <p>Ошибка: {error}</p>;
|
||||
}
|
||||
|
||||
return (
|
||||
<table>
|
||||
<caption>
|
||||
<h2>Состояние ПО</h2>
|
||||
</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Метрика</th>
|
||||
<th>Значение</th>
|
||||
<th>Статус</th>
|
||||
<th>Детали</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{systemData.map((item) => (
|
||||
<React.Fragment key={item.id}>
|
||||
<tr>
|
||||
<td>{item.name}</td>
|
||||
<td>{item.value}%</td>
|
||||
<td>
|
||||
<span className={`status ${item.status}`}>{item.status}</span>
|
||||
</td>
|
||||
<td>
|
||||
<button onClick={() => handleDetailsClick(item.id)}>
|
||||
{expandedRow === item.id ? "Скрыть" : "Подробнее"}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
{expandedRow === item.id && (
|
||||
<tr>
|
||||
<td colSpan="4">
|
||||
<div className="details">
|
||||
<p>{item.details}</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
};
|
||||
|
||||
export default SystemStatusTableSoftware;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { Box, styled } from "@mui/material";
|
||||
import SidebarMenu from "./SidebarMenu";
|
||||
import "../../Style/Dashboard.css";
|
||||
import { statusManager1, statusManager2 } from "../TreeChart/dataUtils";
|
||||
import generateTabContent from "../TreeChart/tabContent";
|
||||
import CustomTabs from "../UI/MUItabs";
|
||||
|
|
@ -9,6 +9,53 @@ import useSidebarResize from "../hooks/useSidebarResize";
|
|||
import TabContent from "../hooks/TabContent";
|
||||
import menuData from "../TreeChart/menuData.json";
|
||||
|
||||
// Создаем стилизованные компоненты
|
||||
const DashboardContainer = styled(Box)(({ theme }) => ({
|
||||
display: 'flex',
|
||||
height: '100vh',
|
||||
width: '100vw',
|
||||
overflow: 'hidden',
|
||||
backgroundColor: theme.palette.background.default,
|
||||
color: theme.palette.text.primary,
|
||||
}));
|
||||
|
||||
const SidebarWrapper = styled(Box)(({ theme }) => ({
|
||||
position: 'relative',
|
||||
backgroundColor: theme.palette.custom.sidebar,
|
||||
color: theme.palette.custom.sidebarText,
|
||||
}));
|
||||
|
||||
const SidebarResizer = styled(Box)(({ theme }) => ({
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
width: '4px',
|
||||
cursor: 'col-resize',
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
},
|
||||
}));
|
||||
|
||||
const MainContent = styled(Box)(({ theme }) => ({
|
||||
flexGrow: 1,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
padding: theme.spacing(2.5), // 20px
|
||||
overflow: 'auto',
|
||||
backgroundColor: theme.palette.background.default,
|
||||
}));
|
||||
|
||||
const Content = styled(Box)(({ theme }) => ({
|
||||
backgroundColor: theme.palette.custom.modalBackground,
|
||||
padding: theme.spacing(2.5),
|
||||
borderRadius: '10px',
|
||||
boxShadow: theme.shadows[2],
|
||||
maxWidth: '100%',
|
||||
overflow: 'auto',
|
||||
color: theme.palette.custom.modalText,
|
||||
}));
|
||||
|
||||
const Dashboard = () => {
|
||||
const { tabs, activeTab, handleOpenTab, handleCloseTab, setActiveTab } = useTabs("Главная");
|
||||
const { sidebarWidth, startResizing } = useSidebarResize(250);
|
||||
|
|
@ -20,13 +67,11 @@ const Dashboard = () => {
|
|||
history2: [],
|
||||
});
|
||||
|
||||
// Генерация контента для вкладок
|
||||
useEffect(() => {
|
||||
const generatedTabContent = generateTabContent(menuData);
|
||||
setTabContent(generatedTabContent);
|
||||
}, []);
|
||||
|
||||
// Обновление статусов каждые 30 секунд
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
const updatedData1 = JSON.parse(JSON.stringify(treeData1));
|
||||
|
|
@ -56,15 +101,20 @@ const Dashboard = () => {
|
|||
}, [treeData1, treeData2]);
|
||||
|
||||
return (
|
||||
<div className="dashboard-container">
|
||||
<DashboardContainer>
|
||||
{/* Сайдбар */}
|
||||
<div className="sidebar" style={{ width: sidebarWidth }}>
|
||||
<SidebarMenu data={treeData1} onOpenTab={handleOpenTab} sidebarWidth={sidebarWidth} startResizing={startResizing} />
|
||||
<div className="sidebar-resizer" onMouseDown={startResizing} />
|
||||
</div>
|
||||
<SidebarWrapper sx={{ width: sidebarWidth }}>
|
||||
<SidebarMenu
|
||||
data={treeData1}
|
||||
onOpenTab={handleOpenTab}
|
||||
sidebarWidth={sidebarWidth}
|
||||
startResizing={startResizing}
|
||||
/>
|
||||
<SidebarResizer onMouseDown={startResizing} />
|
||||
</SidebarWrapper>
|
||||
|
||||
{/* Основной контент */}
|
||||
<div className="main-content">
|
||||
<MainContent>
|
||||
{/* Вкладки */}
|
||||
<CustomTabs
|
||||
tabs={tabs}
|
||||
|
|
@ -74,7 +124,7 @@ const Dashboard = () => {
|
|||
/>
|
||||
|
||||
{/* Контент вкладки */}
|
||||
<div className="content">
|
||||
<Content>
|
||||
<TabContent
|
||||
activeTab={activeTab}
|
||||
statusHistories={statusHistories}
|
||||
|
|
@ -82,9 +132,9 @@ const Dashboard = () => {
|
|||
tabContent={tabContent}
|
||||
handleOpenTab={handleOpenTab}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Content>
|
||||
</MainContent>
|
||||
</DashboardContainer>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,49 +1,151 @@
|
|||
import React from "react";
|
||||
import { Drawer, List } from "@mui/material";
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
Drawer,
|
||||
List,
|
||||
Typography,
|
||||
styled,
|
||||
IconButton,
|
||||
Tooltip,
|
||||
Box
|
||||
} from "@mui/material";
|
||||
import {
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
Menu as MenuIcon
|
||||
} from "@mui/icons-material";
|
||||
import MenuItem from "./SidebarMenuComponents/MenuItem";
|
||||
import SidebarFooter from "./SidebarMenuComponents/SidebarFooter";
|
||||
|
||||
const SidebarResizer = styled('div')(({ theme }) => ({
|
||||
width: "5px",
|
||||
cursor: "ew-resize",
|
||||
backgroundColor: 'transparent',
|
||||
height: "100%",
|
||||
position: "absolute",
|
||||
right: 0,
|
||||
top: 0,
|
||||
transition: 'background-color 0.2s',
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
},
|
||||
zIndex: 2
|
||||
}));
|
||||
|
||||
const SidebarMenu = ({ data, onOpenTab, sidebarWidth, startResizing }) => {
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
const [hovered, setHovered] = useState(false);
|
||||
|
||||
const handleToggleCollapse = () => {
|
||||
setCollapsed(!collapsed);
|
||||
};
|
||||
|
||||
const handleSelectItem = (id, title, children) => {
|
||||
onOpenTab(id, title, children);
|
||||
};
|
||||
|
||||
const drawerWidth = collapsed ? 64 : sidebarWidth;
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
variant="permanent"
|
||||
<Box
|
||||
onMouseEnter={() => setHovered(true)}
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
sx={{
|
||||
width: sidebarWidth,
|
||||
flexShrink: 0,
|
||||
"& .MuiDrawer-paper": {
|
||||
width: sidebarWidth,
|
||||
boxSizing: "border-box",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
},
|
||||
position: 'relative',
|
||||
width: drawerWidth,
|
||||
transition: 'width 0.3s ease',
|
||||
}}
|
||||
>
|
||||
<List>
|
||||
<h2 style={{ padding: "16px", fontWeight: "bold", }}>Меню</h2>
|
||||
<MenuItem item={data} onSelectItem={handleSelectItem} />
|
||||
</List>
|
||||
|
||||
{/* Ресайзер */}
|
||||
<div
|
||||
onMouseDown={startResizing}
|
||||
style={{
|
||||
width: "5px",
|
||||
cursor: "ew-resize",
|
||||
backgroundColor: "#ccc",
|
||||
height: "100%",
|
||||
position: "absolute",
|
||||
right: 0,
|
||||
top: 0,
|
||||
<Drawer
|
||||
variant="permanent"
|
||||
sx={{
|
||||
width: drawerWidth,
|
||||
flexShrink: 0,
|
||||
'& .MuiDrawer-paper': {
|
||||
width: drawerWidth,
|
||||
boxSizing: "border-box",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
backgroundColor: 'custom.sidebar',
|
||||
color: 'custom.sidebarText',
|
||||
transition: 'width 0.3s ease',
|
||||
overflowX: 'hidden',
|
||||
borderRight: 'none'
|
||||
},
|
||||
}}
|
||||
/>
|
||||
>
|
||||
{/* Кнопка сворачивания/разворачивания */}
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end',
|
||||
p: 1,
|
||||
borderBottom: '1px solid',
|
||||
borderColor: 'divider',
|
||||
backgroundColor: 'custom.sidebar'
|
||||
}}>
|
||||
<Tooltip title={collapsed ? "Развернуть меню" : "Свернуть меню"}>
|
||||
<IconButton
|
||||
onClick={handleToggleCollapse}
|
||||
size="small"
|
||||
sx={{
|
||||
color: 'custom.sidebarText',
|
||||
'&:hover': {
|
||||
backgroundColor: 'custom.sidebarHover',
|
||||
}
|
||||
}}
|
||||
>
|
||||
{collapsed ? (
|
||||
hovered ? <ChevronRight /> : <MenuIcon />
|
||||
) : (
|
||||
<ChevronLeft />
|
||||
)}
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
|
||||
<SidebarFooter sidebarWidth={sidebarWidth} />
|
||||
</Drawer>
|
||||
{/* Содержимое меню */}
|
||||
<Box sx={{
|
||||
flexGrow: 1,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
overflow: 'hidden'
|
||||
}}>
|
||||
<List sx={{
|
||||
overflowY: 'auto',
|
||||
overflowX: 'hidden',
|
||||
flex: '1 1 auto'
|
||||
}}>
|
||||
{!collapsed && (
|
||||
<Typography
|
||||
variant="h6"
|
||||
sx={{
|
||||
p: 2,
|
||||
fontWeight: 'bold',
|
||||
textAlign: 'center'
|
||||
}}
|
||||
>
|
||||
Меню
|
||||
</Typography>
|
||||
)}
|
||||
<MenuItem
|
||||
item={data}
|
||||
onSelectItem={handleSelectItem}
|
||||
collapsed={collapsed}
|
||||
/>
|
||||
</List>
|
||||
|
||||
{/* Футер */}
|
||||
{!collapsed && (
|
||||
<SidebarFooter />
|
||||
)}
|
||||
</Box>
|
||||
|
||||
{/* Ресайзер */}
|
||||
{!collapsed && (
|
||||
<SidebarResizer onMouseDown={startResizing} />
|
||||
)}
|
||||
</Drawer>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default SidebarMenu;
|
||||
export default SidebarMenu;
|
||||
|
|
@ -1,95 +1,90 @@
|
|||
import React from "react";
|
||||
import { ListItem, ListItemIcon, ListItemText, Collapse, List } from "@mui/material";
|
||||
import {
|
||||
ListItem,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Collapse,
|
||||
List,
|
||||
styled
|
||||
} from "@mui/material";
|
||||
import { ExpandLess, ExpandMore, Folder, FolderOpen } from "@mui/icons-material";
|
||||
|
||||
// Функция для сбора всех потомков
|
||||
const getAllChildren = (node) => {
|
||||
let children = [];
|
||||
if (node.items && node.items.length > 0) {
|
||||
node.items.forEach((child) => {
|
||||
children.push(child); // Добавляем текущий элемент
|
||||
children = children.concat(getAllChildren(child)); // Рекурсивно добавляем потомков
|
||||
});
|
||||
}
|
||||
return children;
|
||||
};
|
||||
const StyledListItem = styled(ListItem)(({ theme, level }) => ({
|
||||
cursor: "pointer",
|
||||
paddingLeft: theme.spacing(2 + level * 2),
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.action.hover,
|
||||
},
|
||||
'&.Mui-selected': {
|
||||
backgroundColor: theme.palette.custom.sidebarHover,
|
||||
},
|
||||
}));
|
||||
|
||||
const MenuItem = ({ item, onSelectItem, level = 0 }) => { // Добавлен параметр level для отслеживания уровня вложенности
|
||||
const IconWrapper = styled('div')(({ theme }) => ({
|
||||
cursor: "pointer",
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
padding: theme.spacing(0.5),
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.action.selected,
|
||||
},
|
||||
}));
|
||||
|
||||
const MenuItem = ({ item, onSelectItem, level = 0, collapsed }) => {
|
||||
const [isOpen, setIsOpen] = React.useState(false);
|
||||
const hasChildren = Array.isArray(item.items) && item.items.length > 0;
|
||||
|
||||
const handleToggle = () => {
|
||||
|
||||
const handleToggle = (e) => {
|
||||
e.stopPropagation();
|
||||
setIsOpen(!isOpen);
|
||||
};
|
||||
|
||||
const handleOpenTab = (e) => {
|
||||
e.stopPropagation(); // Останавливаем всплытие события
|
||||
const allChildren = getAllChildren(item); // Собираем всех потомков
|
||||
onSelectItem(item.id, item.title, allChildren); // Передаем данные в родительский компонент
|
||||
e.stopPropagation();
|
||||
const allChildren = getAllChildren(item);
|
||||
onSelectItem(item.id, item.title, allChildren);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ListItem
|
||||
component="div"
|
||||
<StyledListItem
|
||||
component="div"
|
||||
onClick={hasChildren ? handleToggle : handleOpenTab}
|
||||
level={level}
|
||||
sx={{
|
||||
cursor: "pointer", // Курсор pointer везде
|
||||
pl: 2 + level * 2, // Сдвиг в зависимости от уровня вложенности
|
||||
"&:hover": {
|
||||
backgroundColor: "#f5f5f5", // Подсветка при наведении на весь элемент
|
||||
|
||||
},
|
||||
pl: collapsed ? 2 : 2 + level * 2, // Адаптируем отступы
|
||||
justifyContent: collapsed ? 'center' : 'flex-start',
|
||||
}}
|
||||
>
|
||||
<ListItemIcon>
|
||||
{hasChildren ? (
|
||||
<div
|
||||
onClick={handleOpenTab}
|
||||
style={{
|
||||
cursor: "pointer",
|
||||
borderRadius: "4px", // Скругление углов
|
||||
padding: "4px", // Отступы для увеличения области hover
|
||||
"&:hover": {
|
||||
backgroundColor: "#e0e0e0", // Подсветка при наведении на иконку
|
||||
// transform: 2,
|
||||
|
||||
},
|
||||
}}
|
||||
>
|
||||
{isOpen ? <FolderOpen /> : <Folder />}
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
onClick={handleOpenTab}
|
||||
style={{
|
||||
cursor: "pointer",
|
||||
borderRadius: "4px", // Скругление углов
|
||||
padding: "4px", // Отступы для увеличения области hover
|
||||
"&:hover": {
|
||||
backgroundColor: "#e0e0e0", // Подсветка при наведении на иконку
|
||||
},
|
||||
}}
|
||||
>
|
||||
{/* Здесь можно добавить другую иконку или оставить пустым */}
|
||||
</div>
|
||||
)}
|
||||
<ListItemIcon sx={{ minWidth: collapsed ? 'auto' : 56 }}>
|
||||
<IconWrapper onClick={handleOpenTab}>
|
||||
{hasChildren ? (isOpen ? <FolderOpen /> : <Folder />) : <Folder />}
|
||||
</IconWrapper>
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
primary={item.title}
|
||||
sx={{ cursor: "pointer" }} // Курсор pointer для текста
|
||||
/>
|
||||
{hasChildren && (isOpen ? <ExpandLess /> : <ExpandMore />)}
|
||||
</ListItem>
|
||||
{hasChildren && (
|
||||
|
||||
{!collapsed && ( // Показываем текст только в развернутом состоянии
|
||||
<>
|
||||
<ListItemText
|
||||
primary={item.title}
|
||||
primaryTypographyProps={{
|
||||
color: 'custom.sidebarText'
|
||||
}}
|
||||
/>
|
||||
{hasChildren && (isOpen ? <ExpandLess /> : <ExpandMore />)}
|
||||
</>
|
||||
)}
|
||||
</StyledListItem>
|
||||
|
||||
{hasChildren && !collapsed && ( // Показываем детей только в развернутом состоянии
|
||||
<Collapse in={isOpen} timeout="auto" unmountOnExit>
|
||||
<List component="div" disablePadding>
|
||||
{item.items.map((child, index) => (
|
||||
<MenuItem
|
||||
key={index}
|
||||
item={child}
|
||||
onSelectItem={onSelectItem}
|
||||
level={level + 1} // Увеличиваем уровень вложенности
|
||||
<MenuItem
|
||||
key={index}
|
||||
item={child}
|
||||
onSelectItem={onSelectItem}
|
||||
level={level + 1}
|
||||
collapsed={collapsed}
|
||||
/>
|
||||
))}
|
||||
</List>
|
||||
|
|
@ -99,4 +94,16 @@ const MenuItem = ({ item, onSelectItem, level = 0 }) => { // Добавлен п
|
|||
);
|
||||
};
|
||||
|
||||
// Вспомогательная функция (остается без изменений)
|
||||
const getAllChildren = (node) => {
|
||||
let children = [];
|
||||
if (node.items && node.items.length > 0) {
|
||||
node.items.forEach((child) => {
|
||||
children.push(child);
|
||||
children = children.concat(getAllChildren(child));
|
||||
});
|
||||
}
|
||||
return children;
|
||||
};
|
||||
|
||||
export default MenuItem;
|
||||
|
|
@ -1,16 +1,47 @@
|
|||
import React from "react";
|
||||
import { List, ListItem, ListItemText } from "@mui/material";
|
||||
import {
|
||||
List,
|
||||
ListItem,
|
||||
ListItemText,
|
||||
styled
|
||||
} from "@mui/material";
|
||||
|
||||
const SidebarFooter = ({ sidebarWidth }) => {
|
||||
const FooterList = styled(List)(({ theme }) => ({
|
||||
backgroundColor: theme.palette.custom.sidebar,
|
||||
padding: theme.spacing(1, 0),
|
||||
borderTop: `1px solid ${theme.palette.divider}`,
|
||||
marginTop: 'auto'
|
||||
}));
|
||||
|
||||
const FooterListItem = styled(ListItem)(({ theme }) => ({
|
||||
'&:hover': {
|
||||
backgroundColor: theme.palette.custom.sidebarHover,
|
||||
},
|
||||
padding: theme.spacing(1, 2),
|
||||
}));
|
||||
|
||||
const SidebarFooter = () => {
|
||||
return (
|
||||
<List sx={{ marginTop: "auto", backgroundColor: "#ffffff", padding: "10px 0" }}>
|
||||
<ListItem button={true}>
|
||||
<ListItemText primary="Помощь" sx={{ color: "#000000" }} />
|
||||
</ListItem>
|
||||
<ListItem button={true}>
|
||||
<ListItemText primary="Настройка" sx={{ color: "#000000" }} />
|
||||
</ListItem>
|
||||
</List>
|
||||
<FooterList>
|
||||
<FooterListItem button>
|
||||
<ListItemText
|
||||
primary="Помощь"
|
||||
primaryTypographyProps={{
|
||||
color: 'custom.sidebarText',
|
||||
variant: 'body2'
|
||||
}}
|
||||
/>
|
||||
</FooterListItem>
|
||||
<FooterListItem button>
|
||||
<ListItemText
|
||||
primary="Настройка"
|
||||
primaryTypographyProps={{
|
||||
color: 'custom.sidebarText',
|
||||
variant: 'body2'
|
||||
}}
|
||||
/>
|
||||
</FooterListItem>
|
||||
</FooterList>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,714 +0,0 @@
|
|||
{
|
||||
"title": "Сервис ЗВКС",
|
||||
"id": "1",
|
||||
"items": [
|
||||
{
|
||||
"title": "Функциональные задачи",
|
||||
"id": "functional_tasks",
|
||||
"items": [
|
||||
{
|
||||
"id": "system_control",
|
||||
"title": "Контроль системы"
|
||||
},
|
||||
{
|
||||
"id": "system_management",
|
||||
"title": "Система управления"
|
||||
},
|
||||
{
|
||||
"id": "conference",
|
||||
"title": "Проведение ВКС"
|
||||
},
|
||||
{
|
||||
"id": "backup",
|
||||
"title": "Резервное копирование"
|
||||
},
|
||||
{
|
||||
"id": "relay_info",
|
||||
"title": "Ретрансляция информации"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "18",
|
||||
"title": "Graviton S2082I (device$18)",
|
||||
"items": [
|
||||
{
|
||||
"id": "4",
|
||||
"title": "OS Linux (module$4) АО",
|
||||
"items": [
|
||||
{
|
||||
"id": "190",
|
||||
"title": "Загрузка процессора за 1 минуту"
|
||||
},
|
||||
{
|
||||
"id": "191",
|
||||
"title": "Загрузка процессора за 5 минут"
|
||||
},
|
||||
{
|
||||
"id": "192",
|
||||
"title": "Загрузка процессора за 15 минут"
|
||||
},
|
||||
{
|
||||
"id": "197",
|
||||
"title": "Общий объем SWAP-файла"
|
||||
},
|
||||
{
|
||||
"id": "198",
|
||||
"title": "Используемый объем SWAP-файла"
|
||||
},
|
||||
{
|
||||
"id": "199",
|
||||
"title": "Общий объем физической оперативной памяти"
|
||||
},
|
||||
{
|
||||
"id": "200",
|
||||
"title": "Доступный объем физической оперативной памяти"
|
||||
},
|
||||
{
|
||||
"id": "201",
|
||||
"title": "Свободный объем физической и виртуальной оперативной памяти"
|
||||
},
|
||||
{
|
||||
"id": "202",
|
||||
"title": "Буферизованный объем оперативной памяти"
|
||||
},
|
||||
{
|
||||
"id": "203",
|
||||
"title": "Кэшированый объем оперативной памяти"
|
||||
},
|
||||
{
|
||||
"id": "274",
|
||||
"title": "Используемый объем SWAP-файла"
|
||||
},
|
||||
{
|
||||
"id": "275",
|
||||
"title": "Время затраченное процессором на процессы с пониженным приоритетом"
|
||||
},
|
||||
{
|
||||
"id": "276",
|
||||
"title": "Время затраченное процессором на процессы ядра ОС"
|
||||
},
|
||||
{
|
||||
"id": "277",
|
||||
"title": "Время простоя процессора"
|
||||
},
|
||||
{
|
||||
"id": "278",
|
||||
"title": "Общая емкость жестких дисков"
|
||||
},
|
||||
{
|
||||
"id": "279",
|
||||
"title": "Доступная емкость жестких дисков"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "5",
|
||||
"title": "Vinteo (module$5) ПО",
|
||||
"items": [
|
||||
{
|
||||
"id": "31",
|
||||
"title": "Общее количество участников"
|
||||
},
|
||||
{
|
||||
"id": "32",
|
||||
"title": "Ожидание соединения"
|
||||
},
|
||||
{
|
||||
"id": "33",
|
||||
"title": "Зарегистрированные абоненты"
|
||||
},
|
||||
{
|
||||
"id": "34",
|
||||
"title": "Количество пользоватей HLS"
|
||||
},
|
||||
{
|
||||
"id": "35",
|
||||
"title": "Общее количество P2P комнат"
|
||||
},
|
||||
{
|
||||
"id": "36",
|
||||
"title": "Общее количество конференций"
|
||||
},
|
||||
{
|
||||
"id": "37",
|
||||
"title": "Общее количество активных конференций"
|
||||
},
|
||||
{
|
||||
"id": "38",
|
||||
"title": "Статус записи"
|
||||
},
|
||||
{
|
||||
"id": "39",
|
||||
"title": "Общее количество сохранённых записей"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "280",
|
||||
"title": "Сетевой адаптер №1 (port$261) Eth_1",
|
||||
"items": [
|
||||
{
|
||||
"id": "207",
|
||||
"title": "Скорость порта Eth_1"
|
||||
},
|
||||
{
|
||||
"id": "209",
|
||||
"title": "Административное состояние порта Eth_1"
|
||||
},
|
||||
{
|
||||
"id": "210",
|
||||
"title": "Оперативное состояние порта Eth_1"
|
||||
},
|
||||
{
|
||||
"id": "211",
|
||||
"title": "Общее количество отправленных октетов Eth_1"
|
||||
},
|
||||
{
|
||||
"id": "212",
|
||||
"title": "Количество входящих Multicast пакетов Eth_1"
|
||||
},
|
||||
{
|
||||
"id": "213",
|
||||
"title": "Количество иcходящих Multiicast пакетов Eth_1"
|
||||
},
|
||||
{
|
||||
"id": "214",
|
||||
"title": "Количество входящих Broadcast пакетов Eth_1"
|
||||
},
|
||||
{
|
||||
"id": "215",
|
||||
"title": "Количество иcходящих Broadcast пакетов Eth_1"
|
||||
},
|
||||
{
|
||||
"id": "216",
|
||||
"title": "Количество входящих Unicast пакетов Eth_1"
|
||||
},
|
||||
{
|
||||
"id": "217",
|
||||
"title": "Количество иcходящих Unicast пакетов Eth_1"
|
||||
},
|
||||
{
|
||||
"id": "218",
|
||||
"title": "Количество входящих пакетов помеченные как отброшенные Eth_1"
|
||||
},
|
||||
{
|
||||
"id": "219",
|
||||
"title": "Количество иcходящих пакетов помеченные как отброшенные Eth_1"
|
||||
},
|
||||
{
|
||||
"id": "220",
|
||||
"title": "Количество входящих пакетов с ошибкой Eth_1"
|
||||
},
|
||||
{
|
||||
"id": "221",
|
||||
"title": "Количество исходящих пакетов с ошибкой Eth_1"
|
||||
},
|
||||
{
|
||||
"id": "222",
|
||||
"title": "Количество входящих пакетов с неизвестным или неподдерживаемым протоколом Eth_1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "281",
|
||||
"title": "Сетевой адаптер №2 (port$262) Eth_2",
|
||||
"items": [
|
||||
{
|
||||
"id": "224",
|
||||
"title": "Скорость порта Eth_2"
|
||||
},
|
||||
{
|
||||
"id": "226",
|
||||
"title": "Административное состояние порта Eth_2"
|
||||
},
|
||||
{
|
||||
"id": "227",
|
||||
"title": "Оперативное состояние порта Eth_2"
|
||||
},
|
||||
{
|
||||
"id": "228",
|
||||
"title": "Общее количество отправленных октетов Eth_2"
|
||||
},
|
||||
{
|
||||
"id": "229",
|
||||
"title": "Количество входящих Multicast пакетов Eth_2"
|
||||
},
|
||||
{
|
||||
"id": "230",
|
||||
"title": "Количество иcходящих Multiicast пакетов Eth_2"
|
||||
},
|
||||
{
|
||||
"id": "231",
|
||||
"title": "Количество входящих Broadcast пакетов Eth_2"
|
||||
},
|
||||
{
|
||||
"id": "232",
|
||||
"title": "Количество иcходящих Broadcast пакетов Eth_2"
|
||||
},
|
||||
{
|
||||
"id": "233",
|
||||
"title": "Количество входящих Unicast пакетов Eth_2"
|
||||
},
|
||||
{
|
||||
"id": "234",
|
||||
"title": "Количество иcходящих Unicast пакетов Eth_2"
|
||||
},
|
||||
{
|
||||
"id": "235",
|
||||
"title": "Количество входящих пакетов помеченные как отброшенные Eth_2"
|
||||
},
|
||||
{
|
||||
"id": "236",
|
||||
"title": "Количество иcходящих пакетов помеченные как отброшенные Eth_2"
|
||||
},
|
||||
{
|
||||
"id": "237",
|
||||
"title": "Количество входящих пакетов с ошибкой Eth_2"
|
||||
},
|
||||
{
|
||||
"id": "238",
|
||||
"title": "Количество исходящих пакетов с ошибкой Eth_2"
|
||||
},
|
||||
{
|
||||
"id": "239",
|
||||
"title": "Количество входящих пакетов с неизвестным или неподдерживаемым протоколом Eth_2"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "282",
|
||||
"title": "Сетевой адаптер №3 (port$263) Eth_3",
|
||||
"items": [
|
||||
{
|
||||
"id": "241",
|
||||
"title": "Скорость порта Eth_3"
|
||||
},
|
||||
{
|
||||
"id": "243",
|
||||
"title": "Административное состояние порта Eth_3"
|
||||
},
|
||||
{
|
||||
"id": "244",
|
||||
"title": "Оперативное состояние порта Eth_3"
|
||||
},
|
||||
{
|
||||
"id": "245",
|
||||
"title": "Общее количество отправленных октетов Eth_3"
|
||||
},
|
||||
{
|
||||
"id": "246",
|
||||
"title": "Количество входящих Multicast пакетов Eth_3"
|
||||
},
|
||||
{
|
||||
"id": "247",
|
||||
"title": "Количество иcходящих Multiicast пакетов Eth_3"
|
||||
},
|
||||
{
|
||||
"id": "248",
|
||||
"title": "Количество входящих Broadcast пакетов Eth_3"
|
||||
},
|
||||
{
|
||||
"id": "249",
|
||||
"title": "Количество иcходящих Broadcast пакетов Eth_3"
|
||||
},
|
||||
{
|
||||
"id": "250",
|
||||
"title": "Количество входящих Unicast пакетов Eth_3"
|
||||
},
|
||||
{
|
||||
"id": "251",
|
||||
"title": "Количество иcходящих Unicast пакетов Eth_3"
|
||||
},
|
||||
{
|
||||
"id": "252",
|
||||
"title": "Количество входящих пакетов помеченные как отброшенные Eth_3"
|
||||
},
|
||||
{
|
||||
"id": "253",
|
||||
"title": "Количество иcходящих пакетов помеченные как отброшенные Eth_3"
|
||||
},
|
||||
{
|
||||
"id": "254",
|
||||
"title": "Количество входящих пакетов с ошибкой Eth_3"
|
||||
},
|
||||
{
|
||||
"id": "255",
|
||||
"title": "Количество исходящих пакетов с ошибкой Eth_3"
|
||||
},
|
||||
{
|
||||
"id": "256",
|
||||
"title": "Количество входящих пакетов с неизвестным или неподдерживаемым протоколом Eth_3"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "283",
|
||||
"title": "Сетевой адаптер №4 (port$264) Eth_4",
|
||||
"items": [
|
||||
{
|
||||
"id": "258",
|
||||
"title": "Скорость порта Eth_4"
|
||||
},
|
||||
{
|
||||
"id": "260",
|
||||
"title": "Административное состояние порта Eth_4"
|
||||
},
|
||||
{
|
||||
"id": "261",
|
||||
"title": "Оперативное состояние порта Eth_4"
|
||||
},
|
||||
{
|
||||
"id": "262",
|
||||
"title": "Общее количество отправленных октетов Eth_4"
|
||||
},
|
||||
{
|
||||
"id": "263",
|
||||
"title": "Количество входящих Multicast пакетов Eth_4"
|
||||
},
|
||||
{
|
||||
"id": "264",
|
||||
"title": "Количество иcходящих Multiicast пакетов Eth_4"
|
||||
},
|
||||
{
|
||||
"id": "265",
|
||||
"title": "Количество входящих Broadcast пакетов Eth_4"
|
||||
},
|
||||
{
|
||||
"id": "266",
|
||||
"title": "Количество иcходящих Broadcast пакетов Eth_4"
|
||||
},
|
||||
{
|
||||
"id": "267",
|
||||
"title": "Количество входящих Unicast пакетов Eth_4"
|
||||
},
|
||||
{
|
||||
"id": "268",
|
||||
"title": "Количество иcходящих Unicast пакетов Eth_4"
|
||||
},
|
||||
{
|
||||
"id": "269",
|
||||
"title": "Количество входящих пакетов помеченные как отброшенные Eth_4"
|
||||
},
|
||||
{
|
||||
"id": "270",
|
||||
"title": "Количество иcходящих пакетов помеченные как отброшенные Eth_4"
|
||||
},
|
||||
{
|
||||
"id": "271",
|
||||
"title": "Количество входящих пакетов с ошибкой Eth_4"
|
||||
},
|
||||
{
|
||||
"id": "272",
|
||||
"title": "Количество исходящих пакетов с ошибкой Eth_4"
|
||||
},
|
||||
{
|
||||
"id": "273",
|
||||
"title": "Количество входящих пакетов с неизвестным или неподдерживаемым протоколом Eth_4"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Медиа сервер",
|
||||
"id": "media_server_1",
|
||||
"items": [
|
||||
{
|
||||
"title": "Аппаратное обеспечение",
|
||||
"id": "system_software_1",
|
||||
"items": [
|
||||
{
|
||||
"id": "media_system_software_1_2",
|
||||
"title": "Центральный процессор"
|
||||
},
|
||||
{
|
||||
"id": "media_system_software_2_2",
|
||||
"title": "Оперативная память"
|
||||
},
|
||||
{
|
||||
"id": "media_system_software_3_2",
|
||||
"title": "Жесткий диск"
|
||||
},
|
||||
{
|
||||
"id": "media_system_software_4_2",
|
||||
"title": "Сетевые адаптеры"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Программное обеспечение",
|
||||
"id": "software_1",
|
||||
"items": [
|
||||
{
|
||||
"id": "media_software_1_2",
|
||||
"title": "ПО"
|
||||
},
|
||||
{
|
||||
"id": "media_software_2_2",
|
||||
"title": "ПО"
|
||||
},
|
||||
{
|
||||
"id": "media_software_3_2",
|
||||
"title": "ПО"
|
||||
},
|
||||
{
|
||||
"id": "media_software_4_2",
|
||||
"title": "ПО"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Медиа сервер",
|
||||
"id": "media_server_2",
|
||||
"items": [
|
||||
{
|
||||
"title": "Аппаратное обеспечение",
|
||||
"id": "system_software_2",
|
||||
"items": [
|
||||
{
|
||||
"id": "media_system_software_1_3",
|
||||
"title": "Центральный процессор"
|
||||
},
|
||||
{
|
||||
"id": "media_system_software_2_3",
|
||||
"title": "Оперативная память"
|
||||
},
|
||||
{
|
||||
"id": "media_system_software_3_3",
|
||||
"title": "Жесткий диск"
|
||||
},
|
||||
{
|
||||
"id": "media_system_software_4_3",
|
||||
"title": "Сетевые адаптеры"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Программное обеспечение",
|
||||
"id": "software_2",
|
||||
"items": [
|
||||
{
|
||||
"id": "media_software_1_3",
|
||||
"title": "ПО"
|
||||
},
|
||||
{
|
||||
"id": "media_software_2_3",
|
||||
"title": "ПО"
|
||||
},
|
||||
{
|
||||
"id": "media_software_3_3",
|
||||
"title": "ПО"
|
||||
},
|
||||
{
|
||||
"id": "media_software_4_3",
|
||||
"title": "ПО"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Медиа сервер",
|
||||
"id": "media_server_3",
|
||||
"items": [
|
||||
{
|
||||
"title": "Аппаратное обеспечение",
|
||||
"id": "system_software_3",
|
||||
"items": [
|
||||
{
|
||||
"id": "media_system_software_1_4",
|
||||
"title": "Центральный процессор"
|
||||
},
|
||||
{
|
||||
"id": "media_system_software_2_4",
|
||||
"title": "Оперативная память"
|
||||
},
|
||||
{
|
||||
"id": "media_system_software_3_4",
|
||||
"title": "Жесткий диск"
|
||||
},
|
||||
{
|
||||
"id": "media_system_software_4_4",
|
||||
"title": "Сетевые адаптеры"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Программное обеспечение",
|
||||
"id": "software_3",
|
||||
"items": [
|
||||
{
|
||||
"id": "media_software_1_4",
|
||||
"title": "ПО"
|
||||
},
|
||||
{
|
||||
"id": "media_software_2_4",
|
||||
"title": "ПО"
|
||||
},
|
||||
{
|
||||
"id": "media_software_3_4",
|
||||
"title": "ПО"
|
||||
},
|
||||
{
|
||||
"id": "media_software_4_4",
|
||||
"title": "ПО"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Медиа сервер",
|
||||
"id": "media_server_4",
|
||||
"items": [
|
||||
{
|
||||
"title": "Аппаратное обеспечение",
|
||||
"id": "system_software_4",
|
||||
"items": [
|
||||
{
|
||||
"id": "media_system_software_1_5",
|
||||
"title": "Центральный процессор"
|
||||
},
|
||||
{
|
||||
"id": "media_system_software_2_5",
|
||||
"title": "Оперативная память"
|
||||
},
|
||||
{
|
||||
"id": "media_system_software_3_5",
|
||||
"title": "Жесткий диск"
|
||||
},
|
||||
{
|
||||
"id": "media_system_software_4_5",
|
||||
"title": "Сетевые адаптеры"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Программное обеспечение",
|
||||
"id": "software_4",
|
||||
"items": [
|
||||
{
|
||||
"id": "media_software_1_5",
|
||||
"title": "ПО"
|
||||
},
|
||||
{
|
||||
"id": "media_software_2_5",
|
||||
"title": "ПО"
|
||||
},
|
||||
{
|
||||
"id": "media_software_3_5",
|
||||
"title": "ПО"
|
||||
},
|
||||
{
|
||||
"id": "media_software_4_5",
|
||||
"title": "ПО"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Сервер систем",
|
||||
"id": "system_server_1",
|
||||
"items": [
|
||||
{
|
||||
"title": "Аппаратное обеспечение",
|
||||
"id": "system_software_5",
|
||||
"items": [
|
||||
{
|
||||
"id": "copy_system_software_1",
|
||||
"title": "Центральный процессор"
|
||||
},
|
||||
{
|
||||
"id": "copy_system_software_2",
|
||||
"title": "Оперативная память"
|
||||
},
|
||||
{
|
||||
"id": "copy_system_software_3",
|
||||
"title": "Жесткий диск"
|
||||
},
|
||||
{
|
||||
"id": "copy_system_software_4",
|
||||
"title": "Сетевые адаптеры"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Программное обеспечение",
|
||||
"id": "software_5",
|
||||
"items": [
|
||||
{
|
||||
"id": "copy_software_1",
|
||||
"title": "ПО"
|
||||
},
|
||||
{
|
||||
"id": "copy_software_2",
|
||||
"title": "ПО"
|
||||
},
|
||||
{
|
||||
"id": "copy_software_3",
|
||||
"title": "ПО"
|
||||
},
|
||||
{
|
||||
"id": "copy_software_4",
|
||||
"title": "ПО"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Сервер систем",
|
||||
"id": "system_server_2",
|
||||
"items": [
|
||||
{
|
||||
"title": "Аппаратное обеспечение",
|
||||
"id": "system_software_6",
|
||||
"items": [
|
||||
{
|
||||
"id": "control_system_software_1",
|
||||
"title": "Центральный процессор"
|
||||
},
|
||||
{
|
||||
"id": "control_system_software_2",
|
||||
"title": "Оперативная память"
|
||||
},
|
||||
{
|
||||
"id": "control_system_software_3",
|
||||
"title": "Жесткий диск"
|
||||
},
|
||||
{
|
||||
"id": "control_system_software_4",
|
||||
"title": "Сетевые адаптеры"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Программное обеспечение",
|
||||
"id": "software_6",
|
||||
"items": [
|
||||
{
|
||||
"id": "control_software_1",
|
||||
"title": "ПО"
|
||||
},
|
||||
{
|
||||
"id": "control_software_2",
|
||||
"title": "ПО"
|
||||
},
|
||||
{
|
||||
"id": "control_software_3",
|
||||
"title": "ПО"
|
||||
},
|
||||
{
|
||||
"id": "control_software_4",
|
||||
"title": "ПО"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
import React from "react";
|
||||
import criticalIcon from "../../assets/images/critical.png"; // Красный треугольник
|
||||
import warningIcon from "../../assets/images/warning.png"; // Желтый треугольник
|
||||
import "../../Style/ErrorIndicator.css"; // Подключаем стили
|
||||
|
||||
const ErrorIndicator = ({ criticalCount, warningCount }) => {
|
||||
return (
|
||||
<div className="error-indicator">
|
||||
{/* Красный индикатор (критические ошибки) */}
|
||||
<div className="error-item critical">
|
||||
<img src={criticalIcon} alt="Критическая ошибка" />
|
||||
<span>{criticalCount}</span>
|
||||
</div>
|
||||
|
||||
{/* Желтый индикатор (предупреждения) */}
|
||||
<div className="error-item warning">
|
||||
<img src={warningIcon} alt="Предупреждение" />
|
||||
<span>{warningCount}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ErrorIndicator;
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
import React, { useState } from "react";
|
||||
import "../Style/Expandable.css"
|
||||
|
||||
const ExpandableInfo = ({ details }) => {
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
|
||||
const toggleExpand = () => {
|
||||
setIsExpanded(!isExpanded);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="expandable-info">
|
||||
<button onClick={toggleExpand} className="expand-button">
|
||||
{isExpanded ? "Скрыть" : "Подробнее"}
|
||||
</button>
|
||||
{isExpanded && (
|
||||
<div className="details-menu">
|
||||
{details.map((detail, index) => (
|
||||
<div key={index} className="detail-item">
|
||||
<span className="label">{detail.label}:</span>
|
||||
<span className="value">{detail.value}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ExpandableInfo;
|
||||
|
|
@ -17,7 +17,7 @@ const LoginModal = ({ onLogin, onClose }) => {
|
|||
|
||||
try {
|
||||
// Отправляем данные на бэкенд
|
||||
const response = await fetch(`${import.meta.env.VITE_BACK_URL}/api/auth/login`, {
|
||||
const response = await fetch(`${import.meta.env.VITE_BACK_URL}/auth/login`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
|
|
|||
|
|
@ -1,10 +1,22 @@
|
|||
import React from "react";
|
||||
import { Tabs, Tab, Box } from "@mui/material";
|
||||
import { Tabs, Tab, Box, styled } from "@mui/material";
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
|
||||
const StyledTab = styled(Tab)(({ theme }) => ({
|
||||
minHeight: 48,
|
||||
'&.Mui-selected': {
|
||||
color: theme.palette.primary.main,
|
||||
fontWeight: theme.typography.fontWeightMedium,
|
||||
},
|
||||
'&:focus-visible': {
|
||||
outline: `2px solid ${theme.palette.primary.main}`,
|
||||
outlineOffset: '-2px',
|
||||
},
|
||||
}));
|
||||
|
||||
const CustomTabs = ({ tabs, activeTab, onTabClick, onCloseTab }) => {
|
||||
const handleMouseDown = (e, id) => {
|
||||
if (e.button === 1) {
|
||||
if (e.button === 1) { // Middle mouse button
|
||||
e.preventDefault();
|
||||
onCloseTab(id);
|
||||
}
|
||||
|
|
@ -15,7 +27,13 @@ const CustomTabs = ({ tabs, activeTab, onTabClick, onCloseTab }) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<Box sx={{ borderBottom: 1, borderColor: "divider" }}>
|
||||
<Box sx={{
|
||||
borderBottom: 1,
|
||||
borderColor: 'divider',
|
||||
'& .MuiTabs-indicator': {
|
||||
backgroundColor: 'primary.main',
|
||||
}
|
||||
}}>
|
||||
<Tabs
|
||||
value={activeTab}
|
||||
onChange={handleChange}
|
||||
|
|
@ -23,28 +41,34 @@ const CustomTabs = ({ tabs, activeTab, onTabClick, onCloseTab }) => {
|
|||
scrollButtons="auto"
|
||||
aria-label="tabs"
|
||||
>
|
||||
{/* Всегда отображаемые вкладки */}
|
||||
<Tab
|
||||
{/* Статические вкладки */}
|
||||
<StyledTab
|
||||
label="Главная"
|
||||
value="Главная"
|
||||
onMouseDown={(e) => handleMouseDown(e, "Главная")}
|
||||
/>
|
||||
<Tab
|
||||
<StyledTab
|
||||
label="Визуализация"
|
||||
value="Визуализация"
|
||||
onMouseDown={(e) => handleMouseDown(e, "Визуализация")}
|
||||
/>
|
||||
|
||||
{/* Динамически добавляемые вкладки */}
|
||||
{/* Динамические вкладки */}
|
||||
{tabs.map((tab) => (
|
||||
<Tab
|
||||
<StyledTab
|
||||
key={tab.id}
|
||||
label={
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<span>{tab.title}</span>
|
||||
<CloseIcon
|
||||
fontSize="small"
|
||||
sx={{ ml: 1, cursor: "pointer" }}
|
||||
sx={{
|
||||
ml: 1,
|
||||
cursor: "pointer",
|
||||
'&:hover': {
|
||||
color: 'error.main'
|
||||
}
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onCloseTab(tab.id);
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
import React from "react";
|
||||
import "../../Style/common.css"; // Общие стили для табов
|
||||
|
||||
const Tabs = ({ tabs, activeTab, onTabClick, onCloseTab }) => {
|
||||
const handleMouseDown = (e, id) => {
|
||||
// Проверяем, была ли нажата средняя кнопка мыши (button === 1)
|
||||
if (e.button === 1) {
|
||||
e.preventDefault(); // Предотвращаем стандартное поведение (например, прокрутку)
|
||||
onCloseTab(id); // Закрываем вкладку
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<div className="tabs">
|
||||
{/* Всегда отображаемые вкладки */}
|
||||
<div
|
||||
className={`tab ${activeTab === "Главная" ? "active" : ""}`}
|
||||
onClick={() => onTabClick("Главная")}
|
||||
onMouseDown={(e) => handleMouseDown(e, "Главная")} // Добавляем обработчик для СКМ
|
||||
>
|
||||
<span>Главная</span>
|
||||
</div>
|
||||
<div
|
||||
className={`tab ${activeTab === "Визуализация" ? "active" : ""}`}
|
||||
onClick={() => onTabClick("Визуализация")}
|
||||
onMouseDown={(e) => handleMouseDown(e, "Визуализация")} // Добавляем обработчик для СКМ
|
||||
>
|
||||
<span>Визуализация</span>
|
||||
</div>
|
||||
|
||||
{/* Динамически добавляемые вкладки */}
|
||||
{tabs.map((tab) => (
|
||||
<div
|
||||
key={tab.id}
|
||||
className={`tab ${activeTab === tab.id ? "active" : ""}`}
|
||||
onClick={() => onTabClick(tab.id)}
|
||||
onMouseDown={(e) => handleMouseDown(e, tab.id)} // Добавляем обработчик для СКМ
|
||||
>
|
||||
<span>{tab.title}</span>
|
||||
<button
|
||||
className="close-tab"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onCloseTab(tab.id);
|
||||
}}
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Tabs;
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
/* Основной контейнер */
|
||||
.dashboard-container {
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
overflow: hidden;
|
||||
background-color: var(--background-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
/* Сайдбар */
|
||||
.sidebar {
|
||||
flex-shrink: 0;
|
||||
height: 100vh;
|
||||
overflow-y: auto;
|
||||
background-color: var(--sidebar-color);
|
||||
color: var(--sidebar-text-color);
|
||||
transition: width 0.2s ease;
|
||||
}
|
||||
|
||||
/* Основной контент */
|
||||
.main-content {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 20px;
|
||||
overflow: auto;
|
||||
background-color: var(--background-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
|
||||
/* Контент */
|
||||
.content {
|
||||
background-color: var(--modal-background);
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.521);
|
||||
max-width: 100%;
|
||||
overflow: auto;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
/* Заголовки */
|
||||
h2 {
|
||||
color: var(--text-color);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
p {
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
.error-indicator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.error-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.error-item img {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.error-item span {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.critical span {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.warning span {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
.indicator-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
justify-content: center;
|
||||
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
.expandable-info {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.expand-button {
|
||||
background-color: #444;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 8px 16px;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.expand-button:hover {
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
.details-menu {
|
||||
margin-top: 10px;
|
||||
padding: 10px;
|
||||
border: 1px solid #333;
|
||||
border-radius: 4px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.detail-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-weight: bold;
|
||||
color: #333
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #333;
|
||||
}
|
||||
|
|
@ -1,143 +0,0 @@
|
|||
/* Сайдбар */
|
||||
.sidebar {
|
||||
height: 100vh;
|
||||
background-color: var(--sidebar-color);
|
||||
color: var(--sidebar-text-color);
|
||||
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;
|
||||
padding-right: 10px;
|
||||
/* Отступ справа для скроллбара */
|
||||
}
|
||||
|
||||
/* Заголовок меню */
|
||||
.sidebar-title {
|
||||
margin-bottom: 20px;
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
color: var(--sidebar-text-color);
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
/* font-size: 2vh; */
|
||||
}
|
||||
|
||||
/* Элементы меню */
|
||||
.menu-item {
|
||||
margin-bottom: 10px;
|
||||
color: var(--sidebar-text-color);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Элемент для перетаскивания */
|
||||
.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);
|
||||
}
|
||||
|
||||
/* Стили для заголовка элемента меню */
|
||||
.menu-item-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
/* Распределяем пространство между элементами */
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s ease;
|
||||
width: 100%;
|
||||
/* Занимаем всю доступную ширину */
|
||||
box-sizing: border-box;
|
||||
/* Учитываем padding в ширине */
|
||||
}
|
||||
|
||||
/* Стили для текста элемента меню */
|
||||
.menu-item-header span {
|
||||
flex: 1;
|
||||
/* Текст занимает все доступное пространство */
|
||||
margin-right: 14px;
|
||||
/* Отступ справа для текста */
|
||||
overflow: hidden;
|
||||
/* Скрываем текст, который не помещается */
|
||||
text-overflow: ellipsis;
|
||||
/* Добавляем многоточие, если текст не помещается */
|
||||
}
|
||||
|
||||
/* Стили для иконок */
|
||||
.menu-item-header .open-parent-icon,
|
||||
.menu-item-header .toggle-icon {
|
||||
flex-shrink: 0;
|
||||
/* Запрещаем сжатие иконок */
|
||||
margin-left: 1px;
|
||||
/* Отступ между иконками */
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.menu-item-header:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
/* Круглый индикатор статуса */
|
||||
.status-indicator {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
margin-right: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Подменю */
|
||||
.submenu {
|
||||
margin-left: 20px;
|
||||
/* Отступ слева для вложенных элементов */
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* Стили для элементов нижнего уровня вложенности */
|
||||
|
||||
/* Дополнительные отступы для элементов без иконок */
|
||||
.menu-item:not(.has-children) .menu-item-header {
|
||||
padding-right: 25px;
|
||||
/* Добавляем отступ справа для элементов без иконок */
|
||||
}
|
||||
|
||||
/* Футер сайдбара */
|
||||
.sidebar-footer {
|
||||
padding: 10px;
|
||||
background-color: var(--sidebar-color);
|
||||
text-align: center;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.1);
|
||||
flex-shrink: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.help,
|
||||
.settings {
|
||||
color: var(--sidebar-text-color);
|
||||
margin: 5px 0;
|
||||
overflow-x: hidden;
|
||||
text-align: left;
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
.tree-table-container {
|
||||
width: 100%;
|
||||
overflow-x: hidden;
|
||||
/* Убираем горизонтальный скролл */
|
||||
}
|
||||
|
||||
.tree-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
text-align: center;
|
||||
table-layout: fixed;
|
||||
/* Фиксированная ширина колонок */
|
||||
background-color: var(--table-cell-background);
|
||||
color: var(--table-text-color);
|
||||
}
|
||||
|
||||
.tree-table-header {
|
||||
padding: 10px;
|
||||
border: 1px solid black;
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
/* Текст не переносится */
|
||||
overflow: hidden;
|
||||
/* Скрываем текст, который не помещается */
|
||||
text-overflow: ellipsis;
|
||||
/* Добавляем многоточие */
|
||||
background-color: var(--table-header-background);
|
||||
}
|
||||
|
||||
.tree-table-cell {
|
||||
padding: 8px;
|
||||
border: 1px solid black;
|
||||
white-space: nowrap;
|
||||
/* Текст не переносится */
|
||||
overflow: hidden;
|
||||
/* Скрываем текст, который не помещается */
|
||||
text-overflow: ellipsis;
|
||||
/* Добавляем многоточие */
|
||||
}
|
||||
|
||||
.cell-content,
|
||||
.header-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.cell-text {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.status-indicator-bar {
|
||||
width: 6px;
|
||||
height: 20px;
|
||||
border-radius: 3px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
/* Контейнер для вкладок */
|
||||
.tabs {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
padding: 5px;
|
||||
background-color: var(--sidebar-color);
|
||||
border-bottom: 2px solid var(--accent-color);
|
||||
overflow-x: auto;
|
||||
border-radius: 5px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Стили для отдельной вкладки */
|
||||
.tab {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: var(--sidebar-color);
|
||||
color: var(--sidebar-text-color);
|
||||
/* Используем переменную для цвета текста */
|
||||
padding: 5px 15px;
|
||||
border-radius: 5px 5px 0 0;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
/* Активная вкладка */
|
||||
.tab.active {
|
||||
background-color: var(--accent-color);
|
||||
}
|
||||
|
||||
/* Кнопка закрытия вкладки */
|
||||
.close-tab {
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--sidebar-text-color);
|
||||
/* Используем переменную для цвета текста */
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
margin-left: 10px;
|
||||
padding: 0;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
/* Эффект при наведении на кнопку закрытия */
|
||||
.close-tab:hover {
|
||||
color: #ff6b6b;
|
||||
}
|
||||
|
||||
/* Эффект при наведении на вкладку */
|
||||
.tab:hover {
|
||||
background-color: var(--accent-hover-color);
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
/* Темная тема, если пользователь предпочитает ее */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--background-color: #1E1E1E;
|
||||
--text-color: #E0E0E0;
|
||||
--header-color: #FFFFFF;
|
||||
/* Основной цвет текста (светлый) */
|
||||
--sidebar-color: #2d2d2d;
|
||||
/* Темный цвет сайдбара */
|
||||
--sidebar-text-color: #E0E0E0;
|
||||
/* Светлый текст в сайдбаре */
|
||||
--modal-background: #2d2d2d;
|
||||
--modal--btn-background: #333333;
|
||||
--modal-text: #FFFFFF;
|
||||
--table-border: #c70a0a;
|
||||
--table-header-background: #2d2d2d;
|
||||
--table-cell-background: #333333;
|
||||
--table-text-color: #E0E0E0;
|
||||
/* Светлый текст в таблице */
|
||||
--TreeChart-text-color: #ffffff;
|
||||
--scrollbar-track-color: #333;
|
||||
/* hover for buttons */
|
||||
--hover-button: #333d4d;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
/* Светлая тема по умолчанию */
|
||||
:root {
|
||||
--background-color: #FFFFFF;
|
||||
--text-color: #000000;
|
||||
--header-color: #333333;
|
||||
/* Основной цвет текста (черный) */
|
||||
--sidebar-color: #3d74c7;
|
||||
/* Синий цвет сайдбара */
|
||||
--sidebar-text-color: #FFFFFF;
|
||||
/* Белый текст в сайдбаре и вкладках */
|
||||
--modal-background: #FFFFFF;
|
||||
--modal--btn-background: #0f55bec2;
|
||||
--modal-text: #333333;
|
||||
--table-border: #ddd;
|
||||
--table-header-background: #f9f9f9;
|
||||
--table-cell-background: #FFFFFF;
|
||||
--table-text-color: #000000;
|
||||
/* Черный текст в таблице */
|
||||
|
||||
/* hover for buttons */
|
||||
--hover-button: #2d62b1;
|
||||
--hover-text-color: #FFFFFF
|
||||
}
|
||||
|
|
@ -1,73 +1,191 @@
|
|||
import { createTheme } from "@mui/material/styles";
|
||||
|
||||
/**
|
||||
* Общие настройки темы, применяемые для обеих тем (светлой и темной)
|
||||
*/
|
||||
const commonThemeSettings = {
|
||||
// Настройки формы элементов
|
||||
shape: {
|
||||
borderRadius: 8, // Базовый радиус скругления углов для всех компонентов
|
||||
},
|
||||
|
||||
// Переопределения стилей конкретных MUI компонентов
|
||||
components: {
|
||||
// Стили для компонента Drawer (боковое меню)
|
||||
MuiDrawer: {
|
||||
styleOverrides: {
|
||||
paper: {
|
||||
borderRight: 'none', // Убираем правую границу у бокового меню
|
||||
}
|
||||
},
|
||||
MuiTab: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
textTransform: 'none', // Убираем uppercase
|
||||
minWidth: 'unset', // Убираем минимальную ширину
|
||||
padding: '6px 16px',
|
||||
'&:hover': {
|
||||
color: 'primary.main',
|
||||
opacity: 1,
|
||||
},
|
||||
'&.Mui-selected': {
|
||||
color: 'primary.main',
|
||||
},
|
||||
'&.Mui-focusVisible': {
|
||||
backgroundColor: 'action.selected',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiTabs: {
|
||||
styleOverrides: {
|
||||
indicator: {
|
||||
height: 3, // Толщина индикатора
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// Стили для кнопок-элементов списка
|
||||
MuiListItemButton: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
// Стиль для выбранного элемента
|
||||
'&.Mui-selected': {
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.16)',
|
||||
},
|
||||
// Стиль при наведении на выбранный элемент
|
||||
'&.Mui-selected:hover': {
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.24)',
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Светлая тема приложения
|
||||
*/
|
||||
export const lightTheme = createTheme({
|
||||
...commonThemeSettings, // Распаковываем общие настройки
|
||||
|
||||
// Цветовая палитра для светлой темы
|
||||
palette: {
|
||||
mode: "light",
|
||||
mode: "light", // Режим светлой темы
|
||||
|
||||
// Фоновые цвета
|
||||
background: {
|
||||
default: "#FFFFFF",
|
||||
paper: "#FFFFFF",
|
||||
default: "#6CACE4", // Основной фон приложения
|
||||
paper: "#FFFFFF", // Фон "бумажных" поверхностей (карточек, панелей)
|
||||
},
|
||||
|
||||
// Текстовые цвета
|
||||
text: {
|
||||
primary: "#000000",
|
||||
primary: "#000000", // Основной цвет текста
|
||||
secondary: "#333333", // Вторичный цвет текста
|
||||
},
|
||||
|
||||
// Основные цвета UI
|
||||
primary: {
|
||||
main: "#3d74c7",
|
||||
main: "#3d74c7", // Основной брендовый цвет
|
||||
contrastText: "#FFFFFF", // Цвет текста на кнопках primary цвета
|
||||
},
|
||||
|
||||
// Дополнительные цвета UI
|
||||
secondary: {
|
||||
main: "#0f55bec2",
|
||||
main: "#0f55bec2", // Вторичный брендовый цвет
|
||||
},
|
||||
|
||||
divider: "#e0e0e0", // Цвет разделителей
|
||||
|
||||
// Кастомные цвета для специфических элементов
|
||||
custom: {
|
||||
background: "#025EA1",
|
||||
text: "#000000",
|
||||
sidebar: "#025EA1",
|
||||
sidebarText: "#FFFFFF",
|
||||
modalBackground: "#FFFFFF",
|
||||
modalBtnBackground: "#0f55bec2",
|
||||
modalText: "#333333",
|
||||
tableBorder: "#ddd",
|
||||
tableHeaderBackground: "#f9f9f9",
|
||||
tableCellBackground: "#FFFFFF",
|
||||
tableText: "#000000",
|
||||
treeChartText: "#000000",
|
||||
scrollbarTrack: "#f1f1f1",
|
||||
hoverButton: "#2d62b1",
|
||||
hoverText: "#FFFFFF",
|
||||
background: "#D4EFFC", // Кастомный фоновый цвет
|
||||
text: "#000000", // Кастомный цвет текста
|
||||
sidebar: "#025EA1", // Фон боковой панели
|
||||
sidebarText: "#FFFFFF", // Текст в боковой панели
|
||||
sidebarHover: "rgba(255, 255, 255, 0.08)", // Цвет при наведении в боковой панели
|
||||
modalBackground: "#FFFFFF", // Фон модальных окон
|
||||
modalBtnBackground: "#0f55bec2", // Фон кнопок в модальных окнах
|
||||
modalText: "#333333", // Текст в модальных окнах
|
||||
tableBorder: "#ddd", // Границы таблиц
|
||||
tableHeaderBackground: "#f9f9f9", // Фон заголовков таблиц
|
||||
tableCellBackground: "#FFFFFF", // Фон ячеек таблиц
|
||||
tableText: "#000000", // Текст в таблицах
|
||||
treeChartText: "#000000", // Текст в древовидных диаграммах
|
||||
scrollbarTrack: "#f1f1f1", // Цвет трека скроллбара
|
||||
hoverButton: "#2d62b1", // Цвет кнопок при наведении
|
||||
hoverText: "#FFFFFF", // Цвет текста при наведении
|
||||
},
|
||||
|
||||
// Цвета для различных состояний
|
||||
action: {
|
||||
hover: "rgba(0, 0, 0, 0.04)", // Цвет при наведении на интерактивные элементы
|
||||
selected: "rgba(0, 0, 0, 0.08)", // Цвет выбранных элементов
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Темная тема приложения
|
||||
*/
|
||||
export const darkTheme = createTheme({
|
||||
...commonThemeSettings, // Распаковываем общие настройки
|
||||
|
||||
// Цветовая палитра для темной темы
|
||||
palette: {
|
||||
mode: "dark",
|
||||
mode: "dark", // Режим темной темы
|
||||
|
||||
// Фоновые цвета
|
||||
background: {
|
||||
default: "#1E1E1E",
|
||||
paper: "#2d2d2d",
|
||||
default: "#1E1E1E", // Основной фон приложения
|
||||
paper: "#2d2d2d", // Фон "бумажных" поверхностей
|
||||
},
|
||||
|
||||
// Текстовые цвета
|
||||
text: {
|
||||
primary: "#E0E0E0",
|
||||
primary: "#E0E0E0", // Основной цвет текста
|
||||
secondary: "#B0B0B0", // Вторичный цвет текста
|
||||
},
|
||||
|
||||
// Основные цвета UI
|
||||
primary: {
|
||||
main: "#2d2d2d",
|
||||
main: "#3d74c7", // Основной брендовый цвет (может совпадать со светлой темой)
|
||||
contrastText: "#FFFFFF", // Цвет текста на кнопках primary цвета
|
||||
},
|
||||
|
||||
// Дополнительные цвета UI
|
||||
secondary: {
|
||||
main: "#333333",
|
||||
main: "#0f55bec2", // Вторичный брендовый цвет
|
||||
},
|
||||
|
||||
divider: "#444444", // Цвет разделителей
|
||||
|
||||
// Кастомные цвета для специфических элементов
|
||||
custom: {
|
||||
background: "#1E1E1E",
|
||||
text: "#E0E0E0",
|
||||
sidebar: "#2d2d2d",
|
||||
sidebarText: "#E0E0E0",
|
||||
modalBackground: "#2d2d2d",
|
||||
modalBtnBackground: "#333333",
|
||||
modalText: "#FFFFFF",
|
||||
tableBorder: "#444444",
|
||||
tableHeaderBackground: "#2d2d2d",
|
||||
tableCellBackground: "#333333",
|
||||
tableText: "#E0E0E0",
|
||||
treeChartText: "#FFFFFF",
|
||||
scrollbarTrack: "#333",
|
||||
hoverButton: "#333d4d",
|
||||
hoverText: "#E0E0E0",
|
||||
background: "#1E1E1E", // Кастомный фоновый цвет
|
||||
text: "#E0E0E0", // Кастомный цвет текста
|
||||
sidebar: "#2d2d2d", // Фон боковой панели
|
||||
sidebarText: "#E0E0E0", // Текст в боковой панели
|
||||
sidebarHover: "rgba(255, 255, 255, 0.16)", // Цвет при наведении в боковой панели
|
||||
modalBackground: "#2d2d2d", // Фон модальных окон
|
||||
modalBtnBackground: "#333333", // Фон кнопок в модальных окнах
|
||||
modalText: "#FFFFFF", // Текст в модальных окнах
|
||||
tableBorder: "#444444", // Границы таблиц
|
||||
tableHeaderBackground: "#2d2d2d", // Фон заголовков таблиц
|
||||
tableCellBackground: "#333333", // Фон ячеек таблиц
|
||||
tableText: "#E0E0E0", // Текст в таблицах
|
||||
treeChartText: "#FFFFFF", // Текст в древовидных диаграммах
|
||||
scrollbarTrack: "#333", // Цвет трека скроллбара
|
||||
hoverButton: "#333d4d", // Цвет кнопок при наведении
|
||||
hoverText: "#E0E0E0", // Цвет текста при наведении
|
||||
},
|
||||
|
||||
// Цвета для различных состояний
|
||||
action: {
|
||||
hover: "rgba(255, 255, 255, 0.08)", // Цвет при наведении на интерактивные элементы
|
||||
selected: "rgba(255, 255, 255, 0.16)", // Цвет выбранных элементов
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
|
|
@ -83,7 +83,7 @@ button:focus-visible {
|
|||
|
||||
/* Фон скроллбара */
|
||||
::-webkit-scrollbar-track {
|
||||
background: var(--scrollbar-track-color, #f1f1f1);
|
||||
background: var(--scrollbar-track-color, #025EA1);
|
||||
/* Цвет фона */
|
||||
border-radius: 10px;
|
||||
/* Скругление углов */
|
||||
|
|
@ -91,7 +91,7 @@ button:focus-visible {
|
|||
|
||||
/* Ползунок */
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #3d74c7;
|
||||
background: #D4EFFC;
|
||||
/* Основной цвет */
|
||||
border-radius: 10px;
|
||||
/* Скругляем края */
|
||||
|
|
|
|||
Loading…
Reference in New Issue