Skip to content

Commit ce22a16

Browse files
authored
Merge pull request #8 from yuxizhe/main
feat: enhance kv info display in hypergraph viewer
2 parents 74ed9cf + eaa467a commit ce22a16

File tree

2 files changed

+146
-106
lines changed

2 files changed

+146
-106
lines changed

hyperdb/draw.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -197,12 +197,7 @@ def _get_graph_data(self, vertex_id: str) -> Dict[str, Any]:
197197
vertices_data = {}
198198
for v_id in all_vertices:
199199
v_data = hg.v(v_id, {})
200-
vertices_data[v_id] = {
201-
"entity_name": v_data.get("entity_name", v_id),
202-
"entity_type": v_data.get("entity_type", ""),
203-
"description": v_data.get("description", ""),
204-
"additional_properties": v_data.get("additional_properties", ""),
205-
}
200+
vertices_data[v_id] = {**v_data}
206201

207202
return {"vertices": vertices_data, "edges": edges_data}
208203

hyperdb/templates/hypergraph_viewer.html

Lines changed: 145 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@
3030
const { Graph } = window.G6;
3131

3232
// API base path
33-
// const API_BASE = window.location.origin;
34-
const API_BASE = "http://localhost:8080";
33+
const API_BASE = window.location.origin;
34+
// dev mode
35+
// const API_BASE = "http://localhost:8080";
3536

3637
// Configuration constants
3738
const COLORS = [
@@ -308,6 +309,15 @@
308309
}
309310
}, [selectedVertex]);
310311

312+
const excludedKeys = new Set([
313+
"id",
314+
"label",
315+
"style",
316+
"data",
317+
"weight",
318+
"source_id",
319+
]);
320+
311321
// Convert data to G6 Graph format
312322
const graphDataFormatted = useMemo(() => {
313323
if (!graphData) return null;
@@ -380,10 +390,9 @@
380390
key: `bubble-sets-${key}`,
381391
type: "bubble-sets",
382392
members: nodes,
383-
keywords: edge.keywords || "",
384-
summary: edge.summary || "",
385393
weight: edge.weight || nodes.length,
386394
description: edge.description || edge.summary || "",
395+
edge: edge,
387396
...createBubbleStyle(COLORS[i % COLORS.length]),
388397
});
389398

@@ -418,30 +427,15 @@
418427
}
419428

420429
// Add tooltip plugin
421-
const excludedKeys = new Set([
422-
"id",
423-
"entity_name",
424-
"entity_type",
425-
"style",
426-
"data",
427-
"description",
428-
]);
429430

430431
plugins.push({
431432
type: "tooltip",
432433
getContent: (e, items) => {
433434
return items
434435
.map((item) => {
435-
let result = `<h4>${item.id}</h4>`;
436-
if (item.entity_name)
437-
result += `<p><strong>Name:</strong> ${item.entity_name}</p>`;
438-
if (item.entity_type)
439-
result += `<p><strong>Type:</strong> ${item.entity_type}</p>`;
440-
if (item.description) {
441-
result += `<p><strong>Description:</strong> ${formatDescription(
442-
item.description
443-
)}</p>`;
444-
}
436+
let result = `<h3><strong>${
437+
item.entity_name || item.id
438+
}</strong></h3>`;
445439
// Display all remaining properties
446440
Object.entries(item).forEach(([key, value]) => {
447441
if (!excludedKeys.has(key)) {
@@ -520,7 +514,7 @@
520514
if (e.targetType === "bubble-sets") {
521515
const target = e.target.options;
522516
const newHyperedge = {
523-
...target,
517+
...target.edge,
524518
members: Array.isArray(target.members) ? target.members : [],
525519
};
526520
setHoverHyperedge((prev) => {
@@ -869,48 +863,95 @@ <h3 className="text-xl font-semibold text-gray-800 m-0">
869863
<div className="text-base font-semibold text-gray-900">
870864
Hyperedge
871865
</div>
872-
{hoverHyperedge.description && (
873-
<div>
874-
<div className="font-medium">Description:</div>
875-
<div className="mt-1 text-gray-600 bg-gray-50 p-2 rounded">
876-
{hoverHyperedge.description}
877-
</div>
878-
</div>
879-
)}
880-
{hoverHyperedge.keywords && (
881-
<div>
882-
<span className="font-medium">Keywords:</span>
883-
<div className="flex flex-wrap gap-2 mt-2">
884-
{hoverHyperedge.keywords
885-
.split(/,||||<SEP>/)
886-
.map((keyword, i) => (
887-
<span
888-
key={i}
889-
className="inline-block p-1 bg-primary-50 rounded"
890-
>
891-
{keyword}
866+
{Object.entries(hoverHyperedge).map(
867+
([key, value]) => {
868+
// Skip empty values
869+
if (
870+
!value ||
871+
(Array.isArray(value) && value.length === 0) ||
872+
excludedKeys.has(key)
873+
) {
874+
return null;
875+
}
876+
877+
// Special handling for keywords
878+
if (
879+
key === "keywords" &&
880+
typeof value === "string"
881+
) {
882+
return (
883+
<div key={key}>
884+
<span className="font-medium">
885+
keywords:
892886
</span>
893-
))}
894-
</div>
895-
</div>
896-
)}
897-
898-
{hoverHyperedge.members?.length > 0 && (
899-
<div>
900-
<div className="font-medium">
901-
Nodes ({hoverHyperedge.members.length}):
902-
</div>
903-
<div className="flex flex-wrap gap-2 mt-2">
904-
{hoverHyperedge.members.map((member, i) => (
905-
<span
906-
key={i}
907-
className="p-1 bg-primary-50 rounded"
908-
>
909-
{member}
910-
</span>
911-
))}
912-
</div>
913-
</div>
887+
<div className="flex flex-wrap gap-2 mt-2">
888+
{value
889+
.split(/,||||<SEP>/)
890+
.filter((k) => k.trim())
891+
.map((keyword, i) => (
892+
<span
893+
key={i}
894+
className="inline-block p-1 bg-primary-50 rounded text-xs"
895+
>
896+
{keyword.trim()}
897+
</span>
898+
))}
899+
</div>
900+
</div>
901+
);
902+
}
903+
904+
// Special handling for members
905+
if (Array.isArray(value)) {
906+
return (
907+
<div key={key}>
908+
<div className="font-medium">
909+
{key} ({value.length}):
910+
</div>
911+
<div className="flex flex-wrap gap-2 mt-2">
912+
{value.map((member, i) => (
913+
<span
914+
key={i}
915+
className="p-1 bg-primary-50 rounded text-xs"
916+
>
917+
{member}
918+
</span>
919+
))}
920+
</div>
921+
</div>
922+
);
923+
}
924+
925+
// Convert value to string for length check
926+
const stringValue =
927+
typeof value === "object"
928+
? JSON.stringify(value, null, 2)
929+
: String(value).replace(/<SEP>/g, " | ");
930+
931+
// If value is less than 10 characters, display as tag
932+
if (stringValue.length < 20) {
933+
return (
934+
<div key={key}>
935+
<span className="font-medium">{key}:</span>
936+
<div className="mt-1">
937+
<span className="inline-block px-2 py-1 bg-gray-100 rounded text-xs">
938+
{stringValue}
939+
</span>
940+
</div>
941+
</div>
942+
);
943+
}
944+
945+
// Default handling for longer values
946+
return (
947+
<div key={key}>
948+
<span className="font-medium">{key}:</span>
949+
<div className="mt-1 text-gray-600 bg-gray-100 p-2 rounded text-xs">
950+
{stringValue}
951+
</div>
952+
</div>
953+
);
954+
}
914955
)}
915956
</div>
916957
)}
@@ -919,42 +960,46 @@ <h3 className="text-xl font-semibold text-gray-800 m-0">
919960
<div className="text-base font-semibold text-gray-900">
920961
Node
921962
</div>
922-
{hoverNode.entity_name && (
923-
<div>
924-
<span className="font-medium">Name:</span>
925-
<span className="ml-2">
926-
{hoverNode.entity_name}
927-
</span>
928-
</div>
929-
)}
930-
{hoverNode.entity_type && (
931-
<div>
932-
<span className="font-medium">Type:</span>
933-
<span className="ml-2 inline-block px-2 py-0.5 bg-gray-100 rounded">
934-
{hoverNode.entity_type}
935-
</span>
936-
</div>
937-
)}
938-
{hoverNode.description && (
939-
<div>
940-
<span className="font-medium">Description:</span>
941-
<span className="ml-2">
942-
{formatDescription(hoverNode.description)}
943-
</span>
944-
</div>
945-
)}
946-
{hoverNode.additional_properties && (
947-
<div>
948-
<span className="font-medium">
949-
Additional Properties:
950-
</span>
951-
<span className="ml-2">
952-
{formatDescription(
953-
hoverNode.additional_properties
954-
)}
955-
</span>
956-
</div>
957-
)}
963+
{Object.entries(hoverNode).map(([key, value]) => {
964+
// Skip empty values
965+
if (
966+
!value ||
967+
(Array.isArray(value) && value.length === 0) ||
968+
excludedKeys.has(key)
969+
) {
970+
return null;
971+
}
972+
973+
// Convert value to string for length check
974+
const stringValue =
975+
typeof value === "object"
976+
? JSON.stringify(value, null, 2)
977+
: String(value).replace(/<SEP>/g, " | ");
978+
979+
// If value is less than 10 characters, display as tag
980+
if (stringValue.length < 20) {
981+
return (
982+
<div key={key}>
983+
<span className="font-medium">{key}:</span>
984+
<div className="mt-1">
985+
<span className="inline-block px-2 py-1 bg-gray-100 rounded text-xs">
986+
{stringValue}
987+
</span>
988+
</div>
989+
</div>
990+
);
991+
}
992+
993+
// Default handling for longer values
994+
return (
995+
<div key={key}>
996+
<span className="font-medium">{key}:</span>
997+
<div className="mt-1 text-gray-600 bg-gray-100 p-2 rounded text-xs">
998+
{stringValue}
999+
</div>
1000+
</div>
1001+
);
1002+
})}
9581003
</div>
9591004
)}
9601005
</div>

0 commit comments

Comments
 (0)