fix(dashboard): add score-based highlight intensity and memoize search nodeMap

Pass search score through to CustomNode for tiered ring highlighting
(bright/medium/dim based on score), and wrap SearchBar's nodeMap in
useMemo to avoid rebuilding it on every render.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lum1104
2026-03-14 19:15:46 +08:00
Unverified
parent 4f6214a5ce
commit c3bece91fc
3 changed files with 30 additions and 17 deletions
@@ -42,6 +42,7 @@ export interface CustomNodeData extends Record<string, unknown> {
summary: string;
complexity: string;
isHighlighted: boolean;
searchScore?: number;
isSelected: boolean;
}
@@ -58,7 +59,14 @@ export default function CustomNode({
if (data.isSelected) {
ringClass = "ring-2 ring-white";
} else if (data.isHighlighted) {
ringClass = "ring-2 ring-yellow-400";
const score = data.searchScore ?? 1;
if (score <= 0.1) {
ringClass = "ring-2 ring-yellow-300";
} else if (score <= 0.3) {
ringClass = "ring-2 ring-yellow-400";
} else {
ringClass = "ring-2 ring-yellow-500/60";
}
}
const truncatedName =
+17 -13
View File
@@ -26,19 +26,23 @@ export default function GraphView() {
const { initialNodes, initialEdges } = useMemo(() => {
if (!graph) return { initialNodes: [] as CustomFlowNode[], initialEdges: [] as Edge[] };
const flowNodes: CustomFlowNode[] = graph.nodes.map((node) => ({
id: node.id,
type: "custom" as const,
position: { x: 0, y: 0 },
data: {
label: node.name,
nodeType: node.type,
summary: node.summary,
complexity: node.complexity,
isHighlighted: searchResults.some((r) => r.nodeId === node.id),
isSelected: selectedNodeId === node.id,
},
}));
const flowNodes: CustomFlowNode[] = graph.nodes.map((node) => {
const matchResult = searchResults.find((r) => r.nodeId === node.id);
return {
id: node.id,
type: "custom" as const,
position: { x: 0, y: 0 },
data: {
label: node.name,
nodeType: node.type,
summary: node.summary,
complexity: node.complexity,
isHighlighted: !!matchResult,
searchScore: matchResult?.score,
isSelected: selectedNodeId === node.id,
},
};
});
const flowEdges: Edge[] = graph.edges.map((edge, i) => ({
id: `e-${i}`,
@@ -1,4 +1,4 @@
import { useCallback, useEffect, useRef, useState } from "react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useDashboardStore } from "../store";
const typeBadgeColors: Record<string, string> = {
@@ -21,8 +21,9 @@ export default function SearchBar() {
const inputRef = useRef<HTMLInputElement>(null);
// Build a lookup map for node details
const nodeMap = new Map(
(graph?.nodes ?? []).map((n) => [n.id, n]),
const nodeMap = useMemo(
() => new Map((graph?.nodes ?? []).map((n) => [n.id, n])),
[graph],
);
const topResults = searchResults.slice(0, 5);