From eaa467aa692fa47184dc87978453c1d04bfd0171 Mon Sep 17 00:00:00 2001 From: yuxz Date: Fri, 10 Oct 2025 15:46:04 +0800 Subject: [PATCH] feat: enhance kv info display in hypergraph viewer --- hyperdb/draw.py | 7 +- hyperdb/templates/hypergraph_viewer.html | 245 ++++++++++++++--------- 2 files changed, 146 insertions(+), 106 deletions(-) diff --git a/hyperdb/draw.py b/hyperdb/draw.py index 7d01fbf..18f9295 100644 --- a/hyperdb/draw.py +++ b/hyperdb/draw.py @@ -196,12 +196,7 @@ def _get_graph_data(self, vertex_id: str) -> Dict[str, Any]: vertices_data = {} for v_id in all_vertices: v_data = hg.v(v_id, {}) - vertices_data[v_id] = { - "entity_name": v_data.get("entity_name", v_id), - "entity_type": v_data.get("entity_type", ""), - "description": v_data.get("description", ""), - "additional_properties": v_data.get("additional_properties", ""), - } + vertices_data[v_id] = {**v_data} return {"vertices": vertices_data, "edges": edges_data} diff --git a/hyperdb/templates/hypergraph_viewer.html b/hyperdb/templates/hypergraph_viewer.html index b665c49..2c0e200 100644 --- a/hyperdb/templates/hypergraph_viewer.html +++ b/hyperdb/templates/hypergraph_viewer.html @@ -30,8 +30,9 @@ const { Graph } = window.G6; // API base path - // const API_BASE = window.location.origin; - const API_BASE = "http://localhost:8080"; + const API_BASE = window.location.origin; + // dev mode + // const API_BASE = "http://localhost:8080"; // Configuration constants const COLORS = [ @@ -308,6 +309,15 @@ } }, [selectedVertex]); + const excludedKeys = new Set([ + "id", + "label", + "style", + "data", + "weight", + "source_id", + ]); + // Convert data to G6 Graph format const graphDataFormatted = useMemo(() => { if (!graphData) return null; @@ -380,10 +390,9 @@ key: `bubble-sets-${key}`, type: "bubble-sets", members: nodes, - keywords: edge.keywords || "", - summary: edge.summary || "", weight: edge.weight || nodes.length, description: edge.description || edge.summary || "", + edge: edge, ...createBubbleStyle(COLORS[i % COLORS.length]), }); @@ -418,30 +427,15 @@ } // Add tooltip plugin - const excludedKeys = new Set([ - "id", - "entity_name", - "entity_type", - "style", - "data", - "description", - ]); plugins.push({ type: "tooltip", getContent: (e, items) => { return items .map((item) => { - let result = `

${item.id}

`; - if (item.entity_name) - result += `

Name: ${item.entity_name}

`; - if (item.entity_type) - result += `

Type: ${item.entity_type}

`; - if (item.description) { - result += `

Description: ${formatDescription( - item.description - )}

`; - } + let result = `

${ + item.entity_name || item.id + }

`; // Display all remaining properties Object.entries(item).forEach(([key, value]) => { if (!excludedKeys.has(key)) { @@ -520,7 +514,7 @@ if (e.targetType === "bubble-sets") { const target = e.target.options; const newHyperedge = { - ...target, + ...target.edge, members: Array.isArray(target.members) ? target.members : [], }; setHoverHyperedge((prev) => { @@ -869,48 +863,95 @@

Hyperedge
- {hoverHyperedge.description && ( -
-
Description:
-
- {hoverHyperedge.description} -
-
- )} - {hoverHyperedge.keywords && ( -
- Keywords: -
- {hoverHyperedge.keywords - .split(/,|,|、|。|/) - .map((keyword, i) => ( - - {keyword} + {Object.entries(hoverHyperedge).map( + ([key, value]) => { + // Skip empty values + if ( + !value || + (Array.isArray(value) && value.length === 0) || + excludedKeys.has(key) + ) { + return null; + } + + // Special handling for keywords + if ( + key === "keywords" && + typeof value === "string" + ) { + return ( +
+ + keywords: - ))} -
-
- )} - - {hoverHyperedge.members?.length > 0 && ( -
-
- Nodes ({hoverHyperedge.members.length}): -
-
- {hoverHyperedge.members.map((member, i) => ( - - {member} - - ))} -
-
+
+ {value + .split(/,|,|、|。|/) + .filter((k) => k.trim()) + .map((keyword, i) => ( + + {keyword.trim()} + + ))} +
+
+ ); + } + + // Special handling for members + if (Array.isArray(value)) { + return ( +
+
+ {key} ({value.length}): +
+
+ {value.map((member, i) => ( + + {member} + + ))} +
+
+ ); + } + + // Convert value to string for length check + const stringValue = + typeof value === "object" + ? JSON.stringify(value, null, 2) + : String(value).replace(//g, " | "); + + // If value is less than 10 characters, display as tag + if (stringValue.length < 20) { + return ( +
+ {key}: +
+ + {stringValue} + +
+
+ ); + } + + // Default handling for longer values + return ( +
+ {key}: +
+ {stringValue} +
+
+ ); + } )} )} @@ -919,42 +960,46 @@

Node
- {hoverNode.entity_name && ( -
- Name: - - {hoverNode.entity_name} - -
- )} - {hoverNode.entity_type && ( -
- Type: - - {hoverNode.entity_type} - -
- )} - {hoverNode.description && ( -
- Description: - - {formatDescription(hoverNode.description)} - -
- )} - {hoverNode.additional_properties && ( -
- - Additional Properties: - - - {formatDescription( - hoverNode.additional_properties - )} - -
- )} + {Object.entries(hoverNode).map(([key, value]) => { + // Skip empty values + if ( + !value || + (Array.isArray(value) && value.length === 0) || + excludedKeys.has(key) + ) { + return null; + } + + // Convert value to string for length check + const stringValue = + typeof value === "object" + ? JSON.stringify(value, null, 2) + : String(value).replace(//g, " | "); + + // If value is less than 10 characters, display as tag + if (stringValue.length < 20) { + return ( +
+ {key}: +
+ + {stringValue} + +
+
+ ); + } + + // Default handling for longer values + return ( +
+ {key}: +
+ {stringValue} +
+
+ ); + })} )}