automatic generation of tabs for the sidebar menu

pull/40/head
DmitriyA 2025-05-27 21:40:59 -04:00
parent 069cea21b0
commit efd8532ac3
5 changed files with 36 additions and 58 deletions

View File

@ -9,7 +9,7 @@ import TabContent from "../hooks/TabContent";
import menuData from "../TreeChart/menuData.json"; import menuData from "../TreeChart/menuData.json";
import SidebarMenuWrapper from "./SidebarMenuWrapper"; import SidebarMenuWrapper from "./SidebarMenuWrapper";
// Создаем стилизованные компоненты // Стилизованные компоненты
const DashboardContainer = styled(Box)(({ theme }) => ({ const DashboardContainer = styled(Box)(({ theme }) => ({
display: 'flex', display: 'flex',
height: '100vh', height: '100vh',
@ -82,49 +82,36 @@ const Dashboard = ({ isDarkMode, setIsDarkMode }) => {
const handleMenuSelect = (item) => { const handleMenuSelect = (item) => {
const tabId = `tab_${item.id}`; const tabId = `tab_${item.id}`;
const tabTitle = item.title || 'Новая вкладка'; const tabTitle = item.title || 'Новая вкладка';
const tabContent = <div style={{ padding: 20 }}>Контент для <strong>{item.title}</strong></div>;
const generateTabContentForItem = (item) => {
return (
<Box p={2}>
<Typography variant="h6">{item.title}</Typography>
{item.description && (
<Typography color="textSecondary">{item.description}</Typography>
)}
{item.metric && (
<Box mt={2}>
<Typography variant="subtitle1">Метрика: {item.metric}</Typography>
{/* Здесь можно добавить визуализацию метрики */}
</Box>
)}
</Box>
);
};
// Проверяем, существует ли уже такая вкладка
const existingTab = tabs.find(tab => tab.id === tabId); const existingTab = tabs.find(tab => tab.id === tabId);
if (!existingTab) { if (!existingTab) {
const newTab = { handleOpenTab(tabId, tabTitle, tabContent); // Передаем аргументы отдельно
id: tabId,
title: tabTitle,
content: generateTabContentForItem(item),
type: 'menuItem',
itemData: item // Сохраняем данные элемента для возможного обновления
};
handleOpenTab(newTab);
} else { } else {
setActiveTab(tabId); setActiveTab(tabId);
} }
}; };
// Вспомогательная функция для получения всех дочерних элементов
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;
};
return ( return (
<DashboardContainer> <DashboardContainer>
{/* Сайдбар - теперь используется SidebarMenuWrapper */} {/* Сайдбар */}
<SidebarMenuWrapper <SidebarMenuWrapper
isDarkMode={isDarkMode} isDarkMode={isDarkMode}
setIsDarkMode={setIsDarkMode} setIsDarkMode={setIsDarkMode}
onSelectItem={handleMenuSelect} onMenuSelect={handleMenuSelect}
/> />
{/* Основной контент */} {/* Основной контент */}
@ -160,6 +147,7 @@ const Dashboard = ({ isDarkMode, setIsDarkMode }) => {
treeData1={treeData1} treeData1={treeData1}
tabContent={tabContent} tabContent={tabContent}
handleOpenTab={handleOpenTab} handleOpenTab={handleOpenTab}
tabs={tabs}
/> />
</Content> </Content>
</MainContent> </MainContent>

View File

@ -122,7 +122,7 @@ const SidebarMenu = ({
collapsed={collapsed} collapsed={collapsed}
level={0} level={0}
onEdit={onEditItem} onEdit={onEditItem}
onSelect={onSelectItem} onSelectItem={onSelectItem}
/> />
)} )}
</List> </List>

View File

@ -12,8 +12,7 @@ import {
MenuItem as MuiMenuItem MenuItem as MuiMenuItem
} from "@mui/material"; } from "@mui/material";
import { ExpandLess, ExpandMore, Folder, FolderOpen, Edit } from "@mui/icons-material"; import { ExpandLess, ExpandMore, Folder, FolderOpen, Edit } from "@mui/icons-material";
import { getStatusColor } from "../../TreeChart/dataUtils"; import StatusIndicator from "./StatusIndicator";
import StatusIndicator from "./StatusIndicator"
const StyledListItem = styled(ListItem)(({ theme, level }) => ({ const StyledListItem = styled(ListItem)(({ theme, level }) => ({
cursor: "pointer", cursor: "pointer",
@ -55,25 +54,17 @@ const MenuItem = ({ item, onSelectItem, level = 0, collapsed, onEdit }) => {
setIsOpen(!isOpen); setIsOpen(!isOpen);
}; };
const handleItemClick = (e) => { const handleClick = () => {
e.stopPropagation(); if (onSelectItem) {
// Если есть обработчик выбора и элемент можно выбрать
if (onSelectItem && (!item.items || item.items.length === 0)) {
onSelectItem(item); onSelectItem(item);
} }
// Если есть подэлементы - переключаем раскрытие
if (item.items && item.items.length > 0) {
setIsOpen(!isOpen);
}
}; };
return ( return (
<> <>
<StyledListItem <StyledListItem
component="div" component="div"
onClick={handleItemClick} onClick={hasChildren ? handleToggle : handleClick}
onContextMenu={handleContextMenu} onContextMenu={handleContextMenu}
level={level} level={level}
sx={{ sx={{
@ -113,7 +104,6 @@ const MenuItem = ({ item, onSelectItem, level = 0, collapsed, onEdit }) => {
)} )}
</StyledListItem> </StyledListItem>
{/* Контекстное меню */}
<Menu <Menu
open={contextMenu !== null} open={contextMenu !== null}
onClose={handleCloseContextMenu} onClose={handleCloseContextMenu}
@ -134,7 +124,7 @@ const MenuItem = ({ item, onSelectItem, level = 0, collapsed, onEdit }) => {
<List component="div" disablePadding> <List component="div" disablePadding>
{item.items.map((child, index) => ( {item.items.map((child, index) => (
<MenuItem <MenuItem
key={index} key={child.id ?? index}
item={child} item={child}
onSelectItem={onSelectItem} onSelectItem={onSelectItem}
onEdit={onEdit} onEdit={onEdit}
@ -149,4 +139,4 @@ const MenuItem = ({ item, onSelectItem, level = 0, collapsed, onEdit }) => {
); );
}; };
export default MenuItem; export default MenuItem;

View File

@ -4,11 +4,11 @@ import FlowChart from "../TreeChart/FlowChart";
import { getStatusColor } from "../TreeChart/dataUtils"; import { getStatusColor } from "../TreeChart/dataUtils";
const TabContent = ({ activeTab, statusHistories, treeData1, tabContent, handleOpenTab }) => { const TabContent = ({ activeTab, tabs, statusHistories, treeData1, tabContent, handleOpenTab }) => {
// Функция для подсчета количества элементов каждого статуса // Функция для подсчета количества элементов каждого статуса
const countStatuses = (data) => { const countStatuses = (data) => {
const counts = { green: 0, yellow: 0, orange: 0, red: 0 }; const counts = { green: 0, yellow: 0, orange: 0, red: 0 };
const countRecursive = (node) => { const countRecursive = (node) => {
if (node.status) { if (node.status) {
counts[node.status]++; counts[node.status]++;
@ -17,7 +17,7 @@ const TabContent = ({ activeTab, statusHistories, treeData1, tabContent, handleO
node.items.forEach(child => countRecursive(child)); node.items.forEach(child => countRecursive(child));
} }
}; };
countRecursive(data); countRecursive(data);
return counts; return counts;
}; };
@ -38,11 +38,11 @@ const TabContent = ({ activeTab, statusHistories, treeData1, tabContent, handleO
<SystemStatusChart data={statusHistories.history2} /> <SystemStatusChart data={statusHistories.history2} />
</div> </div>
</div> </div>
{/* Контейнер для индикаторов статусов */} {/* Контейнер для индикаторов статусов */}
<div style={{ <div style={{
display: 'flex', display: 'flex',
justifyContent: 'flex-end', justifyContent: 'flex-end',
marginTop: '20px', marginTop: '20px',
gap: '10px' gap: '10px'
}}> }}>
@ -63,7 +63,7 @@ const TabContent = ({ activeTab, statusHistories, treeData1, tabContent, handleO
</div> </div>
))} ))}
</div> </div>
<label>Статус компонентов системы</label> <label>Статус компонентов системы</label>
<TreeTable data={treeData1} /> <TreeTable data={treeData1} />
</div> </div>
@ -71,7 +71,7 @@ const TabContent = ({ activeTab, statusHistories, treeData1, tabContent, handleO
} else if (activeTab === "Визуализация") { } else if (activeTab === "Визуализация") {
return <FlowChart data={treeData1} onNodeClick={(id, title) => handleOpenTab(id, title)} />; return <FlowChart data={treeData1} onNodeClick={(id, title) => handleOpenTab(id, title)} />;
} else { } else {
const tabData = tabContent[activeTab]; const tabData = tabs.find(t => t.id === activeTab);
return tabData ? tabData.content : <p>Нет данных</p>; return tabData ? tabData.content : <p>Нет данных</p>;
} }
}; };

View File

@ -11,11 +11,11 @@ const useTabs = (initialTab) => {
if (existingTabIndex >= 0) { if (existingTabIndex >= 0) {
return prevTabs.map((tab, index) => ({ return prevTabs.map((tab, index) => ({
...tab, ...tab,
content: content || tab.content, title: title || tab.title,
content: content || tab.content,
active: index === existingTabIndex active: index === existingTabIndex
})); }));
} }
// Добавляем новую вкладку // Добавляем новую вкладку
return [ return [
...prevTabs.map(tab => ({ ...tab, active: false })), ...prevTabs.map(tab => ({ ...tab, active: false })),