From f541f0a208dcdbfe009179a5f0f38d476dc4e13f Mon Sep 17 00:00:00 2001 From: forhappy Date: Mon, 27 Jul 2026 15:07:08 -0700 Subject: [PATCH] feat(graph): hint node navigation actions --- .../compass-viewer/src/graph/CompassGraph.tsx | 11 +++- .../src/graph/NodeHoverCard.test.tsx | 59 +++++++++++++++++++ .../src/graph/NodeHoverCard.tsx | 26 +++++--- packages/compass-viewer/src/theme.css | 19 +++++- 4 files changed, 106 insertions(+), 9 deletions(-) create mode 100644 packages/compass-viewer/src/graph/NodeHoverCard.test.tsx diff --git a/packages/compass-viewer/src/graph/CompassGraph.tsx b/packages/compass-viewer/src/graph/CompassGraph.tsx index f8483ea..f975c33 100644 --- a/packages/compass-viewer/src/graph/CompassGraph.tsx +++ b/packages/compass-viewer/src/graph/CompassGraph.tsx @@ -130,6 +130,9 @@ function CompassGraphView({ hostRef.current = host; const selected = model.nodes.find((node) => node.id === state.focusedNodeId); const hovered = hover ? model.nodes.find((node) => node.id === hover.nodeId) : undefined; + const hoveredActivation = hovered + ? graphNodeActivation(model, hovered, detailCommunityId) + : undefined; const comparisonMode = model.nodes.some((node) => node.change !== undefined) || model.edges.some((edge) => edge.change !== undefined); const changeCounts = useMemo(() => { @@ -301,7 +304,13 @@ function CompassGraphView({ )} - {hover && hovered && } + {hover && hovered && hoveredActivation && ( + + )} {!inspectorLayout.collapsed && ( { + it("hints that an aggregated community opens its subgraph", () => { + const markup = renderToStaticMarkup( + + ); + + expect(markup).toContain("Double-click"); + expect(markup).toContain("to open community subgraph"); + }); + + it("hints that a concrete node opens its source code", () => { + const markup = renderToStaticMarkup( + + ); + + expect(markup).toContain("Double-click"); + expect(markup).toContain("to open source code"); + }); + + it("does not show an action hint for non-navigable nodes", () => { + const markup = renderToStaticMarkup( + + ); + + expect(markup).not.toContain("Double-click"); + expect(markup).not.toContain("compass-hover-hint"); + }); +}); diff --git a/packages/compass-viewer/src/graph/NodeHoverCard.tsx b/packages/compass-viewer/src/graph/NodeHoverCard.tsx index 19cb2f7..c695a0a 100644 --- a/packages/compass-viewer/src/graph/NodeHoverCard.tsx +++ b/packages/compass-viewer/src/graph/NodeHoverCard.tsx @@ -1,5 +1,7 @@ +import { FileCode2Icon, NetworkIcon } from "lucide-react"; import type { CSSProperties } from "react"; import type { GraphNode } from "../contracts/graph"; +import type { GraphNodeActivation } from "./nodeActivation"; export type GraphHover = { nodeId: string; @@ -16,10 +18,12 @@ function sourceRange(node: GraphNode): string | undefined { export function NodeHoverCard({ node, - hover + hover, + activation }: { node: GraphNode; hover: GraphHover; + activation: GraphNodeActivation; }) { const style = { "--compass-hover-x": `${hover.x + 18}px`, @@ -40,12 +44,7 @@ export function NodeHoverCard({ )} {node.memberCount !== undefined ? ( - <> -

{node.memberCount.toLocaleString()} symbols

- {node.change && node.change !== "unchanged" && ( -

Select to inspect exact changes

- )} - +

{node.memberCount.toLocaleString()} symbols

) : ( <> {node.language &&

Language: {node.language}

} @@ -54,6 +53,19 @@ export function NodeHoverCard({ {node.signature && {node.signature}} )} + {activation.type !== "none" && ( +

+ {activation.type === "community" + ?

+ )} ); } diff --git a/packages/compass-viewer/src/theme.css b/packages/compass-viewer/src/theme.css index 246f31d..883cd92 100644 --- a/packages/compass-viewer/src/theme.css +++ b/packages/compass-viewer/src/theme.css @@ -1479,8 +1479,25 @@ button:not(:disabled), } .compass-hover-hint { + display: flex !important; + align-items: center; + gap: 7px; + margin-top: 2px; + padding-top: 9px; + border-top: 1px solid var(--compass-line); color: var(--vscode-textLink-foreground, var(--compass-focus)); - font-weight: 600; + font-size: 11px; +} + +.compass-hover-hint svg { + width: 14px; + height: 14px; + flex: 0 0 auto; +} + +.compass-hover-hint strong { + color: var(--vscode-editorHoverWidget-foreground, var(--foreground)); + font-weight: 650; } .compass-section-heading,