diff --git a/src/components/dashboard/default/TabCard/ExpandedRow.tsx b/src/components/dashboard/default/TabCard/ExpandedRow.tsx index 24f11da..6e041dd 100644 --- a/src/components/dashboard/default/TabCard/ExpandedRow.tsx +++ b/src/components/dashboard/default/TabCard/ExpandedRow.tsx @@ -82,14 +82,38 @@ export const ExpandedRow = ({ record }: { record: MismatchesItem }) => { if (!ruleData) return []; return [ - { field: 'Title', value: ruleData.title }, - { field: 'Description', value: ruleData.description }, - { field: 'Status', value: ruleData.status }, - { field: 'Level', value: ruleData.level }, - { field: 'Tags', value: ruleData.tags.join(' => ') }, - { field: 'References', value: ruleData.references.join(' => ') }, - { field: 'Author', value: ruleData.author }, - { field: 'Date', value: ruleData.date }, + { + field: 'Title', + value: ruleData.title, + }, + { + field: 'Description', + value: ruleData.description, + }, + { + field: 'Status', + value: ruleData.status, + }, + { + field: 'Level', + value: ruleData.level, + }, + { + field: 'Tags', + value: ruleData.tags.join(' => '), + }, + { + field: 'References', + value: ruleData.references.join(' => '), + }, + { + field: 'Author', + value: ruleData.author, + }, + { + field: 'Date', + value: ruleData.date, + }, ]; }; @@ -97,15 +121,42 @@ export const ExpandedRow = ({ record }: { record: MismatchesItem }) => { if (!logData) return []; return [ - { field: 'Event ID', value: logData.EventId }, - { field: 'User', value: logData.Event?.User }, - { field: 'Image', value: logData.Event?.Image }, - { field: 'Company', value: logData.Event?.Company }, - { field: 'Command Line', value: logData.Event?.CommandLine }, - { field: 'Parent Image', value: logData.Event?.ParentImage }, - { field: 'Parent Command Line', value: logData.Event?.ParentCommandLine }, - { field: 'Original File Name', value: logData.Event?.OriginalFileName }, - { field: 'Integrity Level', value: logData.Event?.IntegrityLevel }, + { + field: 'Event ID', + value: logData.EventId, + }, + { + field: 'User', + value: logData.Event?.User, + }, + { + field: 'Image', + value: logData.Event?.Image, + }, + { + field: 'Company', + value: logData.Event?.Company, + }, + { + field: 'Command Line', + value: logData.Event?.CommandLine, + }, + { + field: 'Parent Image', + value: logData.Event?.ParentImage, + }, + { + field: 'Parent Command Line', + value: logData.Event?.ParentCommandLine, + }, + { + field: 'Original File Name', + value: logData.Event?.OriginalFileName, + }, + { + field: 'Integrity Level', + value: logData.Event?.IntegrityLevel, + }, { field: 'UTC Time', value: logData.Event?.UtcTime diff --git a/src/components/dashboard/default/TabCard/SecurityEventsTable.tsx b/src/components/dashboard/default/TabCard/SecurityEventsTable.tsx index c52155e..c296004 100644 --- a/src/components/dashboard/default/TabCard/SecurityEventsTable.tsx +++ b/src/components/dashboard/default/TabCard/SecurityEventsTable.tsx @@ -80,7 +80,7 @@ export const SecurityEventsTable = ({ pageSizeOptions: ['10', '20', '50', '100'], onChange: onPageChange, }} - locale={{ emptyText: loading ? 'Loading...' : 'No data found' }} + locale={{ emptyText: loading }} /> ); }; diff --git a/src/components/dashboard/projects/ProjectsTables/ProcessTreeView.css b/src/components/dashboard/projects/ProjectsTables/ProcessTreeView.css index 2a923a2..0882ffe 100644 --- a/src/components/dashboard/projects/ProjectsTables/ProcessTreeView.css +++ b/src/components/dashboard/projects/ProjectsTables/ProcessTreeView.css @@ -1,219 +1,310 @@ -.tree-container { +.curved-tree-container { background: #fff; - border-radius: 8px; overflow: auto; - max-height: 70vh; - /* padding: 16px; */ -} - -.tree-content { + max-height: 800vh; position: relative; - min-height: 100%; } -.tree-node-wrapper { +.curved-tree-content { position: relative; - margin-bottom: 12px; + min-height: 100%; + border-radius: 8px; + padding: 20px; } -/* Connection Lines */ -.tree-connections { +/* SVG Connections */ +.curved-tree-connections { position: absolute; top: 0; left: 0; - right: 0; - height: 40px; pointer-events: none; - z-index: 0; + z-index: 1; } -.tree-vertical-connector { - position: absolute; - top: -12px; - width: 2px; - height: 52px; - background-color: #d9d9d9; +.connection-path { + transition: all 0.3s ease; + filter: drop-shadow(0 2px 4px rgba(24, 144, 255, 0.2)); } -.tree-vertical-connector.hidden { - display: none; +.connection-path:hover { + stroke-width: 3; + opacity: 0.8; + filter: drop-shadow(0 4px 8px rgba(24, 144, 255, 0.3)); } -.tree-vertical-connector.visible { - display: block; +/* Curved Tree Nodes - Compact by default */ +.curved-tree-node { + position: absolute; + border: 2px solid #e2e8f0; + border-radius: 12px; + padding: 12px 16px; + width: 280px; + height: 60px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); + z-index: 2; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + cursor: pointer; + backdrop-filter: blur(10px); + background-clip: padding-box; + overflow: hidden; } -.tree-current-connector { - position: absolute; - top: -12px; - width: 2px; - background-color: #d9d9d9; +/* Hover state - expands to show details */ +.curved-tree-node:hover { + height: 160px; + transform: translateY(-10px) scale(1.02); + box-shadow: 0 12px 35px rgba(0, 0, 0, 0.15); + border-color: #1890ff; + z-index: 10; } -.tree-current-connector.has-siblings { - height: 52px; +.curved-tree-node:hover .connection-path { + stroke-width: 3; + opacity: 1; } -.tree-current-connector.last-child { - height: 28px; +/* Node Header - Always visible */ +.tree-node-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 8px; + padding-bottom: 8px; + border-bottom: 1px solid rgba(0, 0, 0, 0.06); } -.tree-horizontal-connector { - position: absolute; - top: 16px; - width: 20px; - height: 2px; - background-color: #d9d9d9; +.tree-node-header .ant-typography { + margin: 0; + font-size: 14px; + font-weight: 600; + color: #1a202c; + max-width: 180px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } -/* Node Styling */ -.tree-node-content { - position: relative; - border: 1px solid #d9d9d9; - border-radius: 6px; - padding: 12px; - min-width: 280px; - max-width: 500px; - background-color: #fff; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); - z-index: 1; - transition: all 0.2s ease; +/* Process Type Tags */ +.tree-node-header .ant-tag { + border-radius: 20px; + font-size: 10px; + font-weight: 500; + padding: 2px 8px; + margin: 0; + border: none; + text-transform: uppercase; + letter-spacing: 0.5px; } -.tree-node-content:hover { - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); - transform: translateY(-1px); +/* Hover Content - Hidden by default, shown on hover */ +.tree-node-hover-content { + opacity: 0; + transform: translateY(10px); + transition: all 0.3s ease; + pointer-events: none; } -.tree-node-content.root-node { - border-left: 4px solid #1890ff; - font-weight: 500; +.curved-tree-node:hover .tree-node-hover-content { + opacity: 1; + transform: translateY(0); + pointer-events: auto; } -.tree-node-header { +/* PIDs Display */ +.tree-node-pids { display: flex; - align-items: center; justify-content: space-between; margin-bottom: 8px; - padding-bottom: 6px; - border-bottom: 1px solid #f0f0f0; + font-size: 11px; + gap: 12px; } -.tree-node-pids { - display: flex; - justify-content: space-between; - margin-bottom: 6px; - font-size: 12px; - gap: 16px; +.tree-node-pids .ant-typography { + margin: 0; + font-size: 11px; + color: #64748b; + font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; + background: rgba(100, 116, 139, 0.1); + padding: 2px 6px; + border-radius: 4px; } +/* Path Display */ .tree-node-path { - margin-bottom: 6px; - font-size: 12px; + margin-bottom: 8px; + font-size: 10px; word-break: break-all; - color: #666; + line-height: 1.3; } +.tree-node-path .ant-typography { + margin: 0; + font-size: 10px; + color: #6b7280; + font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; +} + +/* Time Display */ .tree-node-time { - font-size: 11px; - color: #999; + font-size: 9px; +} + +.tree-node-time .ant-typography { + margin: 0; + font-size: 9px; + color: #9ca3af; font-style: italic; } -.tree-children-container { - position: relative; - margin-top: 8px; +/* Level-specific styling */ +.curved-tree-node[style*='#f0f9ff'] { + border-left: 4px solid #3b82f6; } -/* Enhanced Visual Elements */ -.tree-node-content::before { - content: ''; - position: absolute; - left: -8px; - top: 50%; - transform: translateY(-50%); - width: 6px; - height: 6px; - background-color: #1890ff; - border-radius: 50%; - border: 2px solid #fff; - box-shadow: 0 0 0 1px #d9d9d9; -} - -.tree-node-content.root-node::before { - background-color: #52c41a; - width: 8px; - height: 8px; +.curved-tree-node[style*='#f0fdf4'] { + border-left: 4px solid #10b981; } -/* Responsive adjustments */ -@media (max-width: 768px) { - .tree-node-content { - min-width: 250px; - max-width: calc(100vw - 60px); - } +.curved-tree-node[style*='#fff7ed'] { + border-left: 4px solid #f59e0b; +} - .tree-node-header { - flex-direction: column; - align-items: flex-start; - gap: 4px; - } +.curved-tree-node[style*='#faf5ff'] { + border-left: 4px solid #8b5cf6; +} - .tree-node-pids { - flex-direction: column; - gap: 2px; +.curved-tree-node[style*='#fff1f2'] { + border-left: 4px solid #ef4444; +} + +.curved-tree-node[style*='#eff6ff'] { + border-left: 4px solid #06b6d4; +} + +/* Animations */ +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); } } -/* Animation for tree loading */ -.tree-node-wrapper { - opacity: 0; - animation: fadeInUp 0.3s ease forwards; +.curved-tree-node { + animation: fadeInUp 0.6s ease-out; } -.tree-node-wrapper:nth-child(1) { +.curved-tree-node:nth-child(1) { animation-delay: 0.1s; } -.tree-node-wrapper:nth-child(2) { - animation-delay: 0.15s; -} -.tree-node-wrapper:nth-child(3) { +.curved-tree-node:nth-child(2) { animation-delay: 0.2s; } -.tree-node-wrapper:nth-child(4) { - animation-delay: 0.25s; -} -.tree-node-wrapper:nth-child(n + 5) { +.curved-tree-node:nth-child(3) { animation-delay: 0.3s; } +.curved-tree-node:nth-child(4) { + animation-delay: 0.4s; +} +.curved-tree-node:nth-child(5) { + animation-delay: 0.5s; +} +.curved-tree-node:nth-child(n + 6) { + animation-delay: 0.6s; +} -@keyframes fadeInUp { +/* Connection Path Animations */ +@keyframes drawPath { from { - opacity: 0; - transform: translateY(10px); + stroke-dasharray: 1000; + stroke-dashoffset: 1000; } to { - opacity: 1; - transform: translateY(0); + stroke-dasharray: 1000; + stroke-dashoffset: 0; } } -/* Scrollbar styling */ -.tree-container::-webkit-scrollbar { - width: 6px; - height: 6px; +.connection-path { + animation: drawPath 1s ease-out; + animation-delay: 0.5s; + animation-fill-mode: both; } -.tree-container::-webkit-scrollbar-track { - background: #f1f1f1; - border-radius: 3px; +/* Scrollbar Styling */ +.curved-tree-container::-webkit-scrollbar { + width: 8px; + height: 8px; } -.tree-container::-webkit-scrollbar-thumb { - background: #c1c1c1; - border-radius: 3px; +.curved-tree-container::-webkit-scrollbar-track { + background: #f1f5f9; + border-radius: 4px; } -.tree-container::-webkit-scrollbar-thumb:hover { - background: #a8a8a8; +.curved-tree-container::-webkit-scrollbar-thumb { + background: #cbd5e1; + border-radius: 4px; + transition: background 0.2s ease; +} + +.curved-tree-container::-webkit-scrollbar-thumb:hover { + background: #94a3b8; +} + +/* Responsive Design */ +@media (max-width: 1200px) { + .curved-tree-node { + width: 260px; + height: 55px; + } + + .curved-tree-node:hover { + height: 150px; + } + + .tree-node-header .ant-typography { + font-size: 13px; + max-width: 160px; + } +} + +@media (max-width: 768px) { + .curved-tree-container { + padding: 16px; + max-height: 70vh; + } + + .curved-tree-content { + padding: 16px; + } + + .curved-tree-node { + width: 240px; + height: 50px; + padding: 10px 12px; + } + + .curved-tree-node:hover { + height: 140px; + } + + .tree-node-header { + flex-direction: column; + align-items: flex-start; + gap: 4px; + } + + .tree-node-header .ant-typography { + font-size: 12px; + max-width: 200px; + } + + .tree-node-pids { + flex-direction: column; + gap: 4px; + } } diff --git a/src/components/dashboard/projects/ProjectsTables/TreeView.tsx b/src/components/dashboard/projects/ProjectsTables/TreeView.tsx index b7175de..b837429 100644 --- a/src/components/dashboard/projects/ProjectsTables/TreeView.tsx +++ b/src/components/dashboard/projects/ProjectsTables/TreeView.tsx @@ -1,17 +1,25 @@ -import { Tag, Tooltip, Typography } from 'antd'; +import { Tag, Tooltip, Typography, Button } from 'antd'; import { ProcessListData } from '../../../../types/process_list'; import './ProcessTreeView.css'; +import { useEffect, useState } from 'react'; const { Text } = Typography; type ProcessTreeNode = ProcessListData & { children: ProcessTreeNode[]; + x?: number; + y?: number; + level?: number; + showAllChildren?: boolean; + visibleChildren?: ProcessTreeNode[]; }; interface ProcessTreeBoxProps { processes: ProcessListData[]; } +const INITIAL_CHILDREN_LIMIT = 8; + const buildTree = (data: ProcessListData[]): ProcessTreeNode[] => { const treeMap: { [pid: number]: ProcessTreeNode } = {}; const rootNodes: ProcessTreeNode[] = []; @@ -20,6 +28,8 @@ const buildTree = (data: ProcessListData[]): ProcessTreeNode[] => { treeMap[item.pid] = { ...item, children: [], + showAllChildren: false, + visibleChildren: [], }; }); @@ -31,67 +41,159 @@ const buildTree = (data: ProcessListData[]): ProcessTreeNode[] => { } }); + // Initialize visible children for each node + const initializeVisibleChildren = (node: ProcessTreeNode) => { + node.visibleChildren = node.children.slice(0, INITIAL_CHILDREN_LIMIT); + node.children.forEach((child) => initializeVisibleChildren(child)); + }; + + rootNodes.forEach((node) => initializeVisibleChildren(node)); + return rootNodes; }; +const calculatePositions = ( + nodes: ProcessTreeNode[], + containerWidth: number, + containerHeight: number +) => { + const levels: ProcessTreeNode[][] = []; + + const assignLevels = (node: ProcessTreeNode, level: number) => { + if (!levels[level]) levels[level] = []; + node.level = level; + levels[level].push(node); + // Use visibleChildren instead of all children for positioning + node.visibleChildren?.forEach((child) => assignLevels(child, level + 1)); + }; + + nodes.forEach((node) => assignLevels(node, 0)); + + const nodeWidth = 280; + const levelWidth = containerWidth / Math.max(levels.length, 1); + const minLevelSpacing = 320; + + levels.forEach((levelNodes, levelIndex) => { + const levelHeight = containerHeight / Math.max(levelNodes.length + 1, 1); + const actualLevelWidth = Math.max(levelWidth, minLevelSpacing); + + levelNodes.forEach((node, nodeIndex) => { + node.x = levelIndex * actualLevelWidth + nodeWidth / 2; + node.y = (nodeIndex + 1) * levelHeight; + }); + }); + + return levels.flat(); +}; + const ProcessTypeTag = ({ type }: { type: string }) => { const isInstalled = type === 'installed'; return ( - + {isInstalled ? 'installed' : 'not installed'} ); }; -const TreeNode: React.FC<{ +const CurvedConnection: React.FC<{ + from: ProcessTreeNode; + to: ProcessTreeNode; +}> = ({ from, to }) => { + if (!from.x || !from.y || !to.x || !to.y) return null; + + const startX = from.x + 140; + const startY = from.y + 30; + const endX = to.x - 140; + const endY = to.y + 30; + + // Create curved path with better control points + const controlPointX1 = startX + (endX - startX) * 0.4; + const controlPointX2 = startX + (endX - startX) * 0.6; + const controlPointY1 = startY; + const controlPointY2 = endY; + + const pathData = `M ${startX} ${startY} C ${controlPointX1} ${controlPointY1}, ${controlPointX2} ${controlPointY2}, ${endX} ${endY}`; + + return ( + + ); +}; + +const ShowMoreButton: React.FC<{ node: ProcessTreeNode; - level?: number; - isLast?: boolean; - parentIsLast?: boolean[]; -}> = ({ node, level = 0, isLast = true, parentIsLast = [] }) => { - const hasChildren = node.children.length > 0; - const isRoot = level === 0; + onShowMore: (node: ProcessTreeNode) => void; +}> = ({ node, onShowMore }) => { + const hiddenCount = + node.children.length - (node.visibleChildren?.length || 0); + + if (hiddenCount <= 0) return null; return ( -
- {!isRoot && ( -
- {parentIsLast.map((isParentLast, index) => ( -
- ))} + + ); +}; -
- -
-
- )} +const ProcessNode: React.FC<{ + node: ProcessTreeNode; + onShowMore: (node: ProcessTreeNode) => void; +}> = ({ node, onShowMore }) => { + if (!node.x || !node.y) return null; -
-
- {node.title || node.exe} - -
+ const getBackgroundColor = (level: number) => { + const colors = [ + '#f0f9ff', + '#f0fdf4', + '#fff7ed', + '#faf5ff', + '#fff1f2', + '#eff6ff', + ]; + return colors[Math.min(level || 0, colors.length - 1)]; + }; + return ( +
+ {/* Always visible content */} +
+ {node.title || node.exe} + +
+ + {/* Hover content - only shown on hover */} +
PID: {node.pid} PPID: {node.ppid} @@ -102,8 +204,8 @@ const TreeNode: React.FC<{ Path:{' '} - {node.exe.length > 35 - ? `${node.exe.substring(0, 35)}...` + {node.exe.length > 40 + ? `${node.exe.substring(0, 40)}...` : node.exe} @@ -115,55 +217,209 @@ const TreeNode: React.FC<{ Created: {new Date(node.create_time).toLocaleString()}
-
- {/* Children */} - {hasChildren && ( -
- {node.children.map((child, index) => { - const isChildLast = index === node.children.length - 1; - const newParentIsLast = [...parentIsLast, isLast]; - - return ( - - ); - })} -
- )} + {node.children.length > 0 && ( +
+ +
+ )} +
); }; -const getBackgroundColor = (level: number) => { - const colors = [ - '#e6f7ff', // level 0 - root - '#f6ffed', // level 1 - '#fff7e6', // level 2 - '#f9f0ff', // level 3 - '#fff0f6', // level 4 - '#f0f5ff', // level 5 - ]; - return colors[Math.min(level, colors.length - 1)]; -}; - export const ProcessTreeBox = ({ processes }: ProcessTreeBoxProps) => { - const treeData = buildTree(processes); + const [treeData, setTreeData] = useState([]); + const [scale, setScale] = useState(1); + const [position, setPosition] = useState({ x: 0, y: 0 }); + + // Initialize tree data + useEffect(() => { + setTreeData(buildTree(processes)); + }, [processes]); + + const handleShowMore = (node: ProcessTreeNode) => { + const updateNode = (nodes: ProcessTreeNode[]): ProcessTreeNode[] => { + return nodes.map((n) => { + if (n.pid === node.pid) { + return { + ...n, + showAllChildren: true, + visibleChildren: n.children, + }; + } + return { + ...n, + visibleChildren: n.visibleChildren + ? updateNode(n.visibleChildren) + : [], + }; + }); + }; + + setTreeData((prevData) => updateNode(prevData)); + }; + + // Calculate container dimensions based on visible tree structure + const calculateTreeDimensions = (nodes: ProcessTreeNode[]) => { + let maxLevels = 0; + let maxNodesPerLevel = 0; + + const countLevels = (node: ProcessTreeNode, level: number) => { + maxLevels = Math.max(maxLevels, level); + node.visibleChildren?.forEach((child) => countLevels(child, level + 1)); + }; + + nodes.forEach((node) => countLevels(node, 0)); + maxLevels += 1; + + // Count nodes at each level + const levelCounts = Array(maxLevels).fill(0); + const countAtLevel = (node: ProcessTreeNode, level: number) => { + levelCounts[level]++; + node.visibleChildren?.forEach((child) => countAtLevel(child, level + 1)); + }; + + nodes.forEach((node) => countAtLevel(node, 0)); + maxNodesPerLevel = Math.max(...levelCounts); + + return { maxLevels, maxNodesPerLevel }; + }; + + const { maxLevels, maxNodesPerLevel } = calculateTreeDimensions(treeData); + const containerWidth = Math.max(maxLevels * 800, 1000); + const containerHeight = Math.max(maxNodesPerLevel * 100 + 100, 600); + + const allNodes = calculatePositions( + treeData, + containerWidth, + containerHeight + ); + + // Create connections using only visible children + const connections: Array<{ from: ProcessTreeNode; to: ProcessTreeNode }> = []; + + const addConnections = (node: ProcessTreeNode) => { + node.visibleChildren?.forEach((child) => { + connections.push({ from: node, to: child }); + addConnections(child); + }); + }; + + treeData.forEach(addConnections); + + // Handle zoom events + useEffect(() => { + const handleZoom = (e: CustomEvent) => { + const content = document.querySelector( + '.curved-tree-content' + ) as HTMLElement; + if (!content) return; + + switch (e.detail) { + case 'in': + setScale((prev) => Math.min(prev * 1.2, 3)); + break; + case 'out': + setScale((prev) => Math.max(prev / 1.2, 0.5)); + break; + } + }; + + const content = document.querySelector('.curved-tree-content'); + content?.addEventListener('zoom', handleZoom as EventListener); + + return () => { + content?.removeEventListener('zoom', handleZoom as EventListener); + }; + }, [containerWidth, containerHeight]); + + // Handle panning + useEffect(() => { + const content = document.querySelector( + '.curved-tree-content' + ) as HTMLElement; + if (!content) return; + + let isDragging = false; + let startX = 0; + let startY = 0; + let startPosition = { x: 0, y: 0 }; + + const handleMouseDown = (e: MouseEvent) => { + if (e.button !== 0) return; + isDragging = true; + startX = e.clientX; + startY = e.clientY; + startPosition = { ...position }; + content.style.cursor = 'grabbing'; + }; + + const handleMouseMove = (e: MouseEvent) => { + if (!isDragging) return; + const dx = e.clientX - startX; + const dy = e.clientY - startY; + setPosition({ + x: startPosition.x + dx, + y: startPosition.y + dy, + }); + }; + + const handleMouseUp = () => { + isDragging = false; + content.style.cursor = 'grab'; + }; + + content.addEventListener('mousedown', handleMouseDown); + window.addEventListener('mousemove', handleMouseMove); + window.addEventListener('mouseup', handleMouseUp); + + return () => { + content.removeEventListener('mousedown', handleMouseDown); + window.removeEventListener('mousemove', handleMouseMove); + window.removeEventListener('mouseup', handleMouseUp); + }; + }, [position]); return ( -
-
- {treeData.map((node, index) => ( - +
+
+ {/* SVG for curved connections */} + + + + + + + + + + + {connections.map((conn, index) => ( + + ))} + + + {/* Process nodes */} + {allNodes.map((node) => ( + ))}
diff --git a/src/pages/About.tsx b/src/pages/About.tsx index 2e606e9..02946ee 100644 --- a/src/pages/About.tsx +++ b/src/pages/About.tsx @@ -1,15 +1,11 @@ -import { Alert, Card, Flex } from 'antd'; -// import { PageHeader } from '../components'; -// import { -// BranchesOutlined, -// HomeOutlined, -// PieChartOutlined, -// } from '@ant-design/icons'; +import { Alert, Card, Flex, Button } from 'antd'; import { ReactNode, useEffect, useState } from 'react'; import { fetchProcessList } from '../service/process_list'; import { ProcessListData } from '../types/process_list'; import { useParams } from 'react-router-dom'; import { ProcessTreeBox } from '../components/dashboard/projects/ProjectsTables/TreeView'; +import { ZoomInOutlined, ZoomOutOutlined } from '@ant-design/icons'; +import ButtonGroup from 'antd/es/button/button-group'; export const AboutPage = () => { const [processes, setProcesses] = useState([]); @@ -41,34 +37,6 @@ export const AboutPage = () => { return (
- {/* } - title="Process Tree" - breadcrumbs={[ - { - title: ( - <> - - home - - ), - path: '/', - }, - { - title: ( - <> - - dashboards - - ), - path: '/dashboards', - }, - { - title: 'tree', - }, - ]} - /> */} - {error ? ( { title="Process Tree View" style={{ borderRadius: 8, backgroundColor: '#ffff' }} loading={loading} + extra={ + +
);