elksmmx 1 месяц назад
Родитель
Сommit
103f60e56f

+ 36 - 29
knowhub/frontend/src/components/common/SideDrawer.tsx

@@ -26,15 +26,15 @@ export function SideDrawer({ isOpen, onClose, title, children, width = 'w-[650px
   if (!mounted) return null;
   if (!mounted) return null;
 
 
   return createPortal(
   return createPortal(
-    <div 
-      className={cn(
-        "fixed top-0 left-0 h-full bg-white shadow-2xl z-[220] transform transition-all duration-300 ease-in-out overflow-hidden flex flex-col border-r border-slate-200",
-        expanded ? width : "w-[60px]",
-        isOpen ? "translate-x-0" : "-translate-x-full"
-      )}
-    >
-      <div className={cn("border-b border-slate-100 bg-white sticky top-0 z-10", expanded ? "px-4 py-4" : "px-2 py-4")}>
-        {expanded ? (
+    <>
+      <div
+        className={cn(
+          "fixed top-0 left-0 h-full bg-white shadow-2xl z-[220] transform transition-all duration-300 ease-in-out overflow-hidden flex flex-col border-r border-slate-200",
+          expanded ? width : "w-0",
+          isOpen && expanded ? "translate-x-0" : "-translate-x-full"
+        )}
+      >
+        <div className="border-b border-slate-100 bg-white sticky top-0 z-10 px-4 py-4">
           <div className="flex justify-between items-center gap-2">
           <div className="flex justify-between items-center gap-2">
             <button
             <button
               onClick={() => setExpanded(false)}
               onClick={() => setExpanded(false)}
@@ -44,7 +44,7 @@ export function SideDrawer({ isOpen, onClose, title, children, width = 'w-[650px
               <PanelLeftClose size={18} />
               <PanelLeftClose size={18} />
             </button>
             </button>
             <div className="text-lg font-bold text-slate-900 min-w-0 flex-1 truncate">{title}</div>
             <div className="text-lg font-bold text-slate-900 min-w-0 flex-1 truncate">{title}</div>
-            <button 
+            <button
               onClick={onClose}
               onClick={onClose}
               className="p-2 hover:bg-slate-100 rounded-lg text-slate-400 hover:text-slate-600 transition-colors"
               className="p-2 hover:bg-slate-100 rounded-lg text-slate-400 hover:text-slate-600 transition-colors"
               title="关闭"
               title="关闭"
@@ -52,28 +52,35 @@ export function SideDrawer({ isOpen, onClose, title, children, width = 'w-[650px
               <X size={18} />
               <X size={18} />
             </button>
             </button>
           </div>
           </div>
-        ) : (
-          <button
-            onClick={() => setExpanded(true)}
-            className="w-full flex flex-col items-center gap-3 text-slate-500 hover:text-slate-700 transition-colors"
-            title={typeof title === 'string' ? title : '展开详情'}
-          >
-            <ChevronRight size={18} />
-            <span
-              className="text-[11px] font-bold tracking-widest text-slate-500"
-              style={{ writingMode: 'vertical-rl', textOrientation: 'mixed' }}
-            >
-              {typeof title === 'string' ? title : '详情'}
-            </span>
-          </button>
-        )}
-      </div>
-      {expanded && (
+        </div>
         <div className="flex-1 overflow-y-auto p-6 bg-slate-50">
         <div className="flex-1 overflow-y-auto p-6 bg-slate-50">
           {children}
           {children}
         </div>
         </div>
-      )}
-    </div>,
+      </div>
+
+      <button
+        onClick={() => {
+          if (!isOpen) {
+            setExpanded(true);
+          } else {
+            setExpanded((prev) => !prev);
+          }
+        }}
+        className={cn(
+          "fixed left-0 top-24 z-[230] flex items-center gap-1 rounded-r-xl border border-l-0 border-slate-200 bg-white/95 px-2 py-3 shadow-lg backdrop-blur transition-all duration-300 hover:bg-white text-slate-500 hover:text-slate-700",
+          isOpen && expanded ? "-translate-x-full opacity-0 pointer-events-none" : "translate-x-0 opacity-100"
+        )}
+        title={isOpen ? "展开详情页" : "打开详情页"}
+      >
+        <ChevronRight size={16} />
+        <span
+          className="text-[10px] font-bold tracking-widest"
+          style={{ writingMode: 'vertical-rl', textOrientation: 'mixed' }}
+        >
+          详情页
+        </span>
+      </button>
+    </>,
     document.body
     document.body
   );
   );
 }
 }

+ 7 - 7
knowhub/frontend/src/components/dashboard/CategoryTree.tsx

@@ -10,7 +10,7 @@ interface NodeProps {
   level: number;
   level: number;
   highlightLeafNames: Set<string> | null; // null = no filter active
   highlightLeafNames: Set<string> | null; // null = no filter active
   subtreeHighlightNodeIds: Set<string> | null;
   subtreeHighlightNodeIds: Set<string> | null;
-  sourceNodeNames: Set<string> | null;
+  sourceNodeIds: Set<string> | null;
   nodeMetricsMap: Record<string, { reqCount: number; procCount: number; capCount: number; toolCount: number; nodeCount: number }>;
   nodeMetricsMap: Record<string, { reqCount: number; procCount: number; capCount: number; toolCount: number; nodeCount: number }>;
   dimensionColor: string; // hex color for the node's dimension
   dimensionColor: string; // hex color for the node's dimension
   focusedTreeNodeId?: string | number | null;
   focusedTreeNodeId?: string | number | null;
@@ -24,7 +24,7 @@ function nodeHasHighlightedLeaf(node: any, highlightLeafNames: Set<string> | nul
   return node.children.some((child: any) => nodeHasHighlightedLeaf(child, highlightLeafNames));
   return node.children.some((child: any) => nodeHasHighlightedLeaf(child, highlightLeafNames));
 }
 }
 
 
-function HorizontalTreeNode({ node, onSelect, selectedId, level, highlightLeafNames, subtreeHighlightNodeIds, sourceNodeNames, nodeMetricsMap, dimensionColor, focusedTreeNodeId = null }: NodeProps) {
+function HorizontalTreeNode({ node, onSelect, selectedId, level, highlightLeafNames, subtreeHighlightNodeIds, sourceNodeIds, nodeMetricsMap, dimensionColor, focusedTreeNodeId = null }: NodeProps) {
   const [expanded, setExpanded] = useState(true);
   const [expanded, setExpanded] = useState(true);
   const [hoveredMetric, setHoveredMetric] = useState<null | { key: string; count: number; colorClass: string; x: number; y: number }>(null);
   const [hoveredMetric, setHoveredMetric] = useState<null | { key: string; count: number; colorClass: string; x: number; y: number }>(null);
   const hasChildren = node.children && node.children.length > 0;
   const hasChildren = node.children && node.children.length > 0;
@@ -36,7 +36,7 @@ function HorizontalTreeNode({ node, onSelect, selectedId, level, highlightLeafNa
   const inHighlight = nodeHasHighlightedLeaf(node, highlightLeafNames);
   const inHighlight = nodeHasHighlightedLeaf(node, highlightLeafNames);
   const isLeafHighlighted = highlightLeafNames && highlightLeafNames.has(node.name);
   const isLeafHighlighted = highlightLeafNames && highlightLeafNames.has(node.name);
   const isInSubtreeHighlight = subtreeHighlightNodeIds?.has(String(node.id)) ?? false;
   const isInSubtreeHighlight = subtreeHighlightNodeIds?.has(String(node.id)) ?? false;
-  const isSourceNode = sourceNodeNames?.has(node.name) ?? false;
+  const isSourceNode = sourceNodeIds?.has(String(node.id)) ?? false;
   const isSelected =
   const isSelected =
     selectedId !== null &&
     selectedId !== null &&
     selectedId !== undefined &&
     selectedId !== undefined &&
@@ -141,7 +141,7 @@ function HorizontalTreeNode({ node, onSelect, selectedId, level, highlightLeafNa
                 level={level + 1}
                 level={level + 1}
                 highlightLeafNames={highlightLeafNames}
                 highlightLeafNames={highlightLeafNames}
                 subtreeHighlightNodeIds={subtreeHighlightNodeIds}
                 subtreeHighlightNodeIds={subtreeHighlightNodeIds}
-                sourceNodeNames={sourceNodeNames}
+                sourceNodeIds={sourceNodeIds}
                 nodeMetricsMap={nodeMetricsMap}
                 nodeMetricsMap={nodeMetricsMap}
                 dimensionColor={dimensionColor}
                 dimensionColor={dimensionColor}
                 focusedTreeNodeId={focusedTreeNodeId}
                 focusedTreeNodeId={focusedTreeNodeId}
@@ -169,7 +169,7 @@ export function CategoryTree({
   selectedId,
   selectedId,
   highlightLeafNames = null,
   highlightLeafNames = null,
   subtreeHighlightNodeIds = null,
   subtreeHighlightNodeIds = null,
-  sourceNodeNames = null,
+  sourceNodeIds = null,
   nodeMetricsMap = {},
   nodeMetricsMap = {},
   filterLabel,
   filterLabel,
   onClearFilter,
   onClearFilter,
@@ -187,7 +187,7 @@ export function CategoryTree({
   selectedId: any;
   selectedId: any;
   highlightLeafNames?: Set<string> | null;
   highlightLeafNames?: Set<string> | null;
   subtreeHighlightNodeIds?: Set<string> | null;
   subtreeHighlightNodeIds?: Set<string> | null;
-  sourceNodeNames?: Set<string> | null;
+  sourceNodeIds?: Set<string> | null;
   nodeMetricsMap?: Record<string, { reqCount: number; procCount: number; capCount: number; toolCount: number; nodeCount: number }>;
   nodeMetricsMap?: Record<string, { reqCount: number; procCount: number; capCount: number; toolCount: number; nodeCount: number }>;
   filterLabel?: string | null;
   filterLabel?: string | null;
   onClearFilter?: () => void;
   onClearFilter?: () => void;
@@ -313,7 +313,7 @@ export function CategoryTree({
                         level={1}
                         level={1}
                         highlightLeafNames={highlightLeafNames}
                         highlightLeafNames={highlightLeafNames}
                         subtreeHighlightNodeIds={subtreeHighlightNodeIds}
                         subtreeHighlightNodeIds={subtreeHighlightNodeIds}
-                        sourceNodeNames={sourceNodeNames}
+                        sourceNodeIds={sourceNodeIds}
                         nodeMetricsMap={nodeMetricsMap}
                         nodeMetricsMap={nodeMetricsMap}
                         dimensionColor={color.hex}
                         dimensionColor={color.hex}
                         focusedTreeNodeId={focusedTreeNodeId}
                         focusedTreeNodeId={focusedTreeNodeId}

Разница между файлами не показана из-за своего большого размера
+ 372 - 340
knowhub/frontend/src/pages/Dashboard.tsx


Некоторые файлы не были показаны из-за большого количества измененных файлов