From 6fd5d1aed258f540993079e60e8e5ae4ae3bada8 Mon Sep 17 00:00:00 2001 From: DmitriyA Date: Wed, 23 Apr 2025 08:48:09 -0400 Subject: [PATCH] fixed a bug with tabs --- src/Components/Layout/SidebarMenu.jsx | 14 ++++-- src/Components/TreeChart/tabContent.jsx | 45 +++++------------ src/Components/hooks/useTabs.jsx | 64 ++++++++++++++++++++----- 3 files changed, 74 insertions(+), 49 deletions(-) diff --git a/src/Components/Layout/SidebarMenu.jsx b/src/Components/Layout/SidebarMenu.jsx index 98e7962..af22fb1 100644 --- a/src/Components/Layout/SidebarMenu.jsx +++ b/src/Components/Layout/SidebarMenu.jsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from "react"; +import React, { useState, useEffect, useRef } from "react"; import { Drawer, List, @@ -35,11 +35,10 @@ const SidebarResizer = styled('div')(({ theme }) => ({ const SidebarMenu = ({ data, onOpenTab, sidebarWidth, startResizing, collapsed, setCollapsed }) => { const [hovered, setHovered] = useState(false); const [menuData, setMenuData] = useState(data); + const contentCache = useRef({}); - // Обновляем статусы при изменении данных useEffect(() => { if (data) { - // Создаем глубокую копию данных, чтобы не мутировать исходные const dataCopy = JSON.parse(JSON.stringify(data)); statusManager1.updateStatuses(dataCopy); setMenuData(dataCopy); @@ -51,9 +50,16 @@ const SidebarMenu = ({ data, onOpenTab, sidebarWidth, startResizing, collapsed, }; const handleSelectItem = (id, title, children) => { - onOpenTab(id, title, children); + onOpenTab(id, title); + + contentCache.current = tabContent({ items: children }, contentCache.current); + if (contentCache.current[id]) { + onOpenTab(id, title, contentCache.current[id].content); + } }; + + const drawerWidth = collapsed ? 64 : sidebarWidth; return ( diff --git a/src/Components/TreeChart/tabContent.jsx b/src/Components/TreeChart/tabContent.jsx index a7845f8..15596a8 100755 --- a/src/Components/TreeChart/tabContent.jsx +++ b/src/Components/TreeChart/tabContent.jsx @@ -5,26 +5,23 @@ import Box from '@mui/material/Box'; const PrometheusChart = lazy(() => import('../../Charts/PrometheusChart')); import LazyChartBatchRenderer from "../hooks/LazyChartBatchRender"; -// Функция для генерации названия метрики на основе id const getMetricName = (id) => { return `zvks_apiforsnmp_measure_${id}`; }; -// Функция для рекурсивного сбора всех id потомков const getAllChildIds = (node) => { let ids = []; if (node.id) { - ids.push(node.id); // Добавляем id текущего узла + ids.push(node.id); } if (node.items && node.items.length > 0) { node.items.forEach((child) => { - ids = ids.concat(getAllChildIds(child)); // Рекурсивно собираем id потомков + ids = ids.concat(getAllChildIds(child)); }); } return ids; }; -// Компонент Skeleton для графика const ChartSkeleton = () => ( {/* Заголовок */} @@ -32,7 +29,6 @@ const ChartSkeleton = () => ( ); -// Компонент Skeleton для родительского контейнера const ContainerSkeleton = () => ( {/* Заголовок */} @@ -46,69 +42,52 @@ const ContainerSkeleton = () => ( ); -const tabContent = (data) => { - const tabContent = {}; +const tabContent = (data, existingContent = {}) => { + const tabContent = { ...existingContent }; - // Функция для рекурсивного обхода и сбора данных - // Функция для рекурсивного обхода и сбора данных const generateContent = (nodes) => { nodes.forEach((node) => { - // Если у узла есть вложенные элементы, рекурсивно обрабатываем их + if (tabContent[node.id]) return; + if (node.items && node.items.length > 0) { - // Создаем контент для родителя - const childrenContent = generateContent(node.items); + generateContent(node.items); const content = ( -
+

{node.title}

}> - tabContent[child.id].content)} /> + tabContent[child.id]?.content) || } + /> -

Контент для {node.title}.

- {/*childrenContent*/}
); - // Сохраняем контент для текущего id tabContent[node.id] = { title: node.title, content: content, }; } else { - // Если у узла нет вложенных элементов, это самый нижний уровень const metricName = getMetricName(node.id); const content = (
-

{node.title}

{/* Используем title узла */} +

{node.title}

}>
); - // Сохраняем контент для текущего id tabContent[node.id] = { title: node.title, content: content, }; } }); - - // Возвращаем контент для всех потомков - return ( -
- {nodes.map((node) => ( -
{tabContent[node.id].content}
- ))} -
- ); }; - // Начинаем обработку с корневого уровня if (data.items && data.items.length > 0) { generateContent(data.items); - } else { - console.warn("Данные отсутствуют или массив items пуст"); } return tabContent; diff --git a/src/Components/hooks/useTabs.jsx b/src/Components/hooks/useTabs.jsx index 188cdf5..2df5f13 100644 --- a/src/Components/hooks/useTabs.jsx +++ b/src/Components/hooks/useTabs.jsx @@ -4,23 +4,63 @@ const useTabs = (initialTab) => { const [tabs, setTabs] = useState([]); const [activeTab, setActiveTab] = useState(initialTab); - const handleOpenTab = useCallback((id, title) => { - setTabs((prevTabs) => - prevTabs.some((tab) => tab.id === id) - ? prevTabs - : [...prevTabs, { id, title }] - ); + const handleOpenTab = useCallback((id, title, content) => { + setTabs((prevTabs) => { + const existingTabIndex = prevTabs.findIndex(tab => tab.id === id); + + if (existingTabIndex >= 0) { + return prevTabs.map((tab, index) => ({ + ...tab, + content: content || tab.content, + active: index === existingTabIndex + })); + } + + // Добавляем новую вкладку + return [ + ...prevTabs.map(tab => ({ ...tab, active: false })), + { + id, + title, + content: content ||
Loading...
, + active: true + } + ]; + }); setActiveTab(id); }, []); const handleCloseTab = useCallback((id) => { - setTabs((prevTabs) => prevTabs.filter((tab) => tab.id !== id)); - if (activeTab === id) { - setActiveTab(tabs.length > 1 ? tabs[tabs.length - 2].id : initialTab); - } - }, [activeTab, tabs, initialTab]); + setTabs((prevTabs) => { + const newTabs = prevTabs.filter((tab) => tab.id !== id); - return { tabs, activeTab, handleOpenTab, handleCloseTab, setActiveTab }; + if (activeTab === id) { + setActiveTab(newTabs.length > 0 + ? newTabs[newTabs.length - 1].id + : initialTab + ); + } + + return newTabs; + }); + }, [activeTab, initialTab]); + + const updateTabContent = useCallback((id, content) => { + setTabs(prevTabs => + prevTabs.map(tab => + tab.id === id ? { ...tab, content } : tab + ) + ); + }, []); + + return { + tabs, + activeTab, + handleOpenTab, + handleCloseTab, + setActiveTab, + updateTabContent + }; }; export default useTabs; \ No newline at end of file