@petrarca/sonnet-graph 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +20 -7
- package/dist/index.js +501 -247
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -436,7 +436,8 @@ var useGraphFilter = createGraphFilterStore();
|
|
|
436
436
|
|
|
437
437
|
// src/stores/GraphExploration.ts
|
|
438
438
|
import { create as create4 } from "zustand";
|
|
439
|
-
import { devLog as devLog3 } from "@petrarca/sonnet-core";
|
|
439
|
+
import { devLog as devLog3, errorLog } from "@petrarca/sonnet-core";
|
|
440
|
+
import { toast } from "sonner";
|
|
440
441
|
function collectReachable(startId, direction, allEdges, includeStart) {
|
|
441
442
|
const nodes = /* @__PURE__ */ new Set();
|
|
442
443
|
const edges = /* @__PURE__ */ new Set();
|
|
@@ -542,6 +543,23 @@ function ensureNodeLabelInFilters(enrichedNodes, nodeId, graphFilterStore) {
|
|
|
542
543
|
graphFilterStore.getState().setNodeLabelFilters([...currentFilters, nodeLabel]);
|
|
543
544
|
}
|
|
544
545
|
}
|
|
546
|
+
function mergeExpandedLabelsIntoFilters(stores, enrichedNodes, nodeId) {
|
|
547
|
+
const graphFilterState = stores.graphFilter.getState();
|
|
548
|
+
const currentFilters = graphFilterState.nodeLabelFilters;
|
|
549
|
+
if (currentFilters.length === 0 || enrichedNodes.length === 0) return;
|
|
550
|
+
const newLabels = new Set(enrichedNodes.map((n) => n.label_));
|
|
551
|
+
const labelsToAdd = Array.from(newLabels).filter(
|
|
552
|
+
(label) => !currentFilters.includes(label)
|
|
553
|
+
);
|
|
554
|
+
if (labelsToAdd.length > 0) {
|
|
555
|
+
devLog3("[GraphExploration] Adding expanded node labels to active filters", {
|
|
556
|
+
nodeId,
|
|
557
|
+
labelsToAdd,
|
|
558
|
+
currentFilters
|
|
559
|
+
});
|
|
560
|
+
stores.graphFilter.getState().setNodeLabelFilters([...currentFilters, ...labelsToAdd]);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
545
563
|
function createGraphExplorationStore(deps) {
|
|
546
564
|
const stores = deps;
|
|
547
565
|
return create4()((set, get) => ({
|
|
@@ -841,10 +859,10 @@ function createGraphExplorationStore(deps) {
|
|
|
841
859
|
isNodeExpanded: (nodeId) => {
|
|
842
860
|
return get().expandedNodeIds.has(nodeId);
|
|
843
861
|
},
|
|
844
|
-
expandNode: async (nodeId) => {
|
|
845
|
-
devLog3("[GraphExploration] expandNode", { nodeId });
|
|
862
|
+
expandNode: async (nodeId, options) => {
|
|
863
|
+
devLog3("[GraphExploration] expandNode", { nodeId, options });
|
|
846
864
|
try {
|
|
847
|
-
const result = await stores.expandNode(Number(nodeId));
|
|
865
|
+
const result = await stores.expandNode(Number(nodeId), options);
|
|
848
866
|
devLog3("[GraphExploration] Expansion API result", {
|
|
849
867
|
nodeId,
|
|
850
868
|
newNodes: result.nodes.length,
|
|
@@ -866,25 +884,7 @@ function createGraphExplorationStore(deps) {
|
|
|
866
884
|
);
|
|
867
885
|
const enrichedEdges = enrichEdges(result.edges);
|
|
868
886
|
stores.graphData.getState().mergeExpandedData(enrichedNodes, enrichedEdges);
|
|
869
|
-
|
|
870
|
-
const currentFilters = graphFilterState.nodeLabelFilters;
|
|
871
|
-
if (currentFilters.length > 0 && enrichedNodes.length > 0) {
|
|
872
|
-
const newLabels = new Set(enrichedNodes.map((n) => n.label_));
|
|
873
|
-
const labelsToAdd = Array.from(newLabels).filter(
|
|
874
|
-
(label) => !currentFilters.includes(label)
|
|
875
|
-
);
|
|
876
|
-
if (labelsToAdd.length > 0) {
|
|
877
|
-
devLog3(
|
|
878
|
-
"[GraphExploration] Adding expanded node labels to active filters",
|
|
879
|
-
{
|
|
880
|
-
nodeId,
|
|
881
|
-
labelsToAdd,
|
|
882
|
-
currentFilters
|
|
883
|
-
}
|
|
884
|
-
);
|
|
885
|
-
stores.graphFilter.getState().setNodeLabelFilters([...currentFilters, ...labelsToAdd]);
|
|
886
|
-
}
|
|
887
|
-
}
|
|
887
|
+
mergeExpandedLabelsIntoFilters(stores, enrichedNodes, nodeId);
|
|
888
888
|
get().markNodeExpanded(nodeId);
|
|
889
889
|
const currentState = get();
|
|
890
890
|
if (currentState.isFocusMode) {
|
|
@@ -900,13 +900,19 @@ function createGraphExplorationStore(deps) {
|
|
|
900
900
|
});
|
|
901
901
|
set({ focusedNodeIds: newFocusedIds });
|
|
902
902
|
}
|
|
903
|
+
if (result.has_more) {
|
|
904
|
+
toast.info(
|
|
905
|
+
`Showing first ${enrichedNodes.length} neighbors \u2014 more exist. Refine filters or increase the limit.`
|
|
906
|
+
);
|
|
907
|
+
}
|
|
903
908
|
devLog3("[GraphExploration] Expansion complete", {
|
|
904
909
|
nodeId,
|
|
905
910
|
addedNodes: enrichedNodes.length,
|
|
906
|
-
addedEdges: enrichedEdges.length
|
|
911
|
+
addedEdges: enrichedEdges.length,
|
|
912
|
+
hasMore: result.has_more
|
|
907
913
|
});
|
|
908
914
|
} catch (error) {
|
|
909
|
-
|
|
915
|
+
errorLog("[GraphExploration] Expansion failed", { nodeId, error });
|
|
910
916
|
throw error;
|
|
911
917
|
}
|
|
912
918
|
},
|
|
@@ -1439,10 +1445,10 @@ function GraphRendererProvider({
|
|
|
1439
1445
|
|
|
1440
1446
|
// src/components/rea/ReaGraph.tsx
|
|
1441
1447
|
import {
|
|
1442
|
-
useEffect as
|
|
1443
|
-
useRef,
|
|
1444
|
-
useState as
|
|
1445
|
-
useCallback as
|
|
1448
|
+
useEffect as useEffect3,
|
|
1449
|
+
useRef as useRef2,
|
|
1450
|
+
useState as useState5,
|
|
1451
|
+
useCallback as useCallback3
|
|
1446
1452
|
} from "react";
|
|
1447
1453
|
import { devLog as devLog8 } from "@petrarca/sonnet-core";
|
|
1448
1454
|
import {
|
|
@@ -1662,16 +1668,194 @@ function NodeHoverInfo({ node }) {
|
|
|
1662
1668
|
var NodeHoverInfo_default = NodeHoverInfo;
|
|
1663
1669
|
|
|
1664
1670
|
// src/components/rea/ReaContextMenu.tsx
|
|
1665
|
-
import
|
|
1671
|
+
import React3, { useState as useState4 } from "react";
|
|
1666
1672
|
import { devLog as devLog7 } from "@petrarca/sonnet-core";
|
|
1673
|
+
|
|
1674
|
+
// src/components/rea/ExpandOptionsPanel.tsx
|
|
1675
|
+
import { useCallback as useCallback2, useEffect as useEffect2, useRef, useState as useState3 } from "react";
|
|
1676
|
+
import { Checkbox, Input, Label } from "@petrarca/sonnet-ui";
|
|
1667
1677
|
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1678
|
+
function ExpandOptionsPanel({
|
|
1679
|
+
nodeLabel,
|
|
1680
|
+
onExpand,
|
|
1681
|
+
onBack,
|
|
1682
|
+
getEdgeTypes
|
|
1683
|
+
}) {
|
|
1684
|
+
const [direction, setDirection] = useState3("both");
|
|
1685
|
+
const [limit, setLimit] = useState3(100);
|
|
1686
|
+
const [edgeTypes, setEdgeTypes] = useState3([]);
|
|
1687
|
+
const [selectedTypes, setSelectedTypes] = useState3([]);
|
|
1688
|
+
const [loading, setLoading] = useState3(!!getEdgeTypes);
|
|
1689
|
+
const [offset, setOffset] = useState3({ x: 0, y: 0 });
|
|
1690
|
+
const dragRef = useRef(null);
|
|
1691
|
+
const onPointerDown = useCallback2(
|
|
1692
|
+
(e) => {
|
|
1693
|
+
if (e.target.closest("button")) return;
|
|
1694
|
+
e.preventDefault();
|
|
1695
|
+
e.target.setPointerCapture(e.pointerId);
|
|
1696
|
+
dragRef.current = {
|
|
1697
|
+
startX: e.clientX,
|
|
1698
|
+
startY: e.clientY,
|
|
1699
|
+
origX: offset.x,
|
|
1700
|
+
origY: offset.y
|
|
1701
|
+
};
|
|
1702
|
+
},
|
|
1703
|
+
[offset]
|
|
1704
|
+
);
|
|
1705
|
+
const onPointerMove = useCallback2((e) => {
|
|
1706
|
+
if (!dragRef.current) return;
|
|
1707
|
+
const dx = e.clientX - dragRef.current.startX;
|
|
1708
|
+
const dy = e.clientY - dragRef.current.startY;
|
|
1709
|
+
setOffset({ x: dragRef.current.origX + dx, y: dragRef.current.origY + dy });
|
|
1710
|
+
}, []);
|
|
1711
|
+
const onPointerUp = useCallback2(() => {
|
|
1712
|
+
dragRef.current = null;
|
|
1713
|
+
}, []);
|
|
1714
|
+
useEffect2(() => {
|
|
1715
|
+
if (!getEdgeTypes) return;
|
|
1716
|
+
setLoading(true);
|
|
1717
|
+
getEdgeTypes().then((types) => {
|
|
1718
|
+
setEdgeTypes(types);
|
|
1719
|
+
setSelectedTypes(types);
|
|
1720
|
+
}).finally(() => setLoading(false));
|
|
1721
|
+
}, [getEdgeTypes]);
|
|
1722
|
+
const handleToggleType = (type) => {
|
|
1723
|
+
setSelectedTypes(
|
|
1724
|
+
(prev) => prev.includes(type) ? prev.filter((t) => t !== type) : [...prev, type]
|
|
1725
|
+
);
|
|
1726
|
+
};
|
|
1727
|
+
const handleExpand = () => {
|
|
1728
|
+
const options = {};
|
|
1729
|
+
if (direction !== "both") options.direction = direction;
|
|
1730
|
+
const clampedLimit = Math.max(1, Math.min(1e4, limit));
|
|
1731
|
+
if (clampedLimit !== 100) options.limit = clampedLimit;
|
|
1732
|
+
if (selectedTypes.length > 0 && selectedTypes.length < edgeTypes.length) {
|
|
1733
|
+
options.relTypes = selectedTypes;
|
|
1734
|
+
}
|
|
1735
|
+
onExpand(options);
|
|
1736
|
+
};
|
|
1737
|
+
const allSelected = selectedTypes.length === edgeTypes.length;
|
|
1738
|
+
const noneSelected = edgeTypes.length > 0 && selectedTypes.length === 0;
|
|
1739
|
+
return /* @__PURE__ */ jsxs4(
|
|
1740
|
+
"div",
|
|
1741
|
+
{
|
|
1742
|
+
className: "bg-background border border-border rounded-md shadow-md p-2.5 min-w-48 space-y-2",
|
|
1743
|
+
style: { transform: `translate(${offset.x}px, ${offset.y}px)` },
|
|
1744
|
+
children: [
|
|
1745
|
+
/* @__PURE__ */ jsxs4(
|
|
1746
|
+
"div",
|
|
1747
|
+
{
|
|
1748
|
+
className: "flex items-center justify-between gap-2 cursor-grab active:cursor-grabbing select-none",
|
|
1749
|
+
onPointerDown,
|
|
1750
|
+
onPointerMove,
|
|
1751
|
+
onPointerUp,
|
|
1752
|
+
children: [
|
|
1753
|
+
/* @__PURE__ */ jsx5(
|
|
1754
|
+
"button",
|
|
1755
|
+
{
|
|
1756
|
+
className: "text-[11px] text-muted-foreground hover:text-foreground cursor-pointer",
|
|
1757
|
+
onClick: onBack,
|
|
1758
|
+
children: "Back"
|
|
1759
|
+
}
|
|
1760
|
+
),
|
|
1761
|
+
/* @__PURE__ */ jsx5("span", { className: "text-[11px] font-medium text-foreground truncate max-w-32", children: nodeLabel })
|
|
1762
|
+
]
|
|
1763
|
+
}
|
|
1764
|
+
),
|
|
1765
|
+
/* @__PURE__ */ jsxs4("div", { className: "space-y-1", children: [
|
|
1766
|
+
/* @__PURE__ */ jsx5(Label, { className: "text-[11px] text-muted-foreground", children: "Direction" }),
|
|
1767
|
+
/* @__PURE__ */ jsx5("div", { className: "flex gap-0.5", children: ["both", "out", "in"].map((dir) => /* @__PURE__ */ jsx5(
|
|
1768
|
+
"button",
|
|
1769
|
+
{
|
|
1770
|
+
className: `flex-1 px-2 py-1 text-[11px] capitalize rounded border cursor-pointer ${direction === dir ? "bg-primary/10 text-primary border-primary/40 font-medium" : "bg-background text-muted-foreground border-border hover:bg-muted"}`,
|
|
1771
|
+
onClick: () => setDirection(dir),
|
|
1772
|
+
children: dir
|
|
1773
|
+
},
|
|
1774
|
+
dir
|
|
1775
|
+
)) })
|
|
1776
|
+
] }),
|
|
1777
|
+
!loading && edgeTypes.length > 1 && /* @__PURE__ */ jsxs4("div", { className: "space-y-1", children: [
|
|
1778
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex items-center justify-between", children: [
|
|
1779
|
+
/* @__PURE__ */ jsx5(Label, { className: "text-[11px] text-muted-foreground", children: "Rel Types" }),
|
|
1780
|
+
/* @__PURE__ */ jsx5(
|
|
1781
|
+
"button",
|
|
1782
|
+
{
|
|
1783
|
+
className: "text-[10px] text-muted-foreground hover:text-foreground cursor-pointer",
|
|
1784
|
+
onClick: () => setSelectedTypes(allSelected ? [] : [...edgeTypes]),
|
|
1785
|
+
children: allSelected ? "None" : "All"
|
|
1786
|
+
}
|
|
1787
|
+
)
|
|
1788
|
+
] }),
|
|
1789
|
+
/* @__PURE__ */ jsx5("div", { className: "space-y-0.5 max-h-32 overflow-y-auto", children: edgeTypes.map((type) => /* @__PURE__ */ jsxs4(
|
|
1790
|
+
"label",
|
|
1791
|
+
{
|
|
1792
|
+
className: "flex items-center gap-1.5 text-[11px] cursor-pointer",
|
|
1793
|
+
children: [
|
|
1794
|
+
/* @__PURE__ */ jsx5(
|
|
1795
|
+
Checkbox,
|
|
1796
|
+
{
|
|
1797
|
+
checked: selectedTypes.includes(type),
|
|
1798
|
+
onCheckedChange: () => handleToggleType(type),
|
|
1799
|
+
className: "h-3 w-3"
|
|
1800
|
+
}
|
|
1801
|
+
),
|
|
1802
|
+
/* @__PURE__ */ jsx5("span", { className: "truncate", children: type })
|
|
1803
|
+
]
|
|
1804
|
+
},
|
|
1805
|
+
type
|
|
1806
|
+
)) })
|
|
1807
|
+
] }),
|
|
1808
|
+
/* @__PURE__ */ jsxs4("div", { className: "space-y-1", children: [
|
|
1809
|
+
/* @__PURE__ */ jsx5(Label, { className: "text-[11px] text-muted-foreground", children: "Limit" }),
|
|
1810
|
+
/* @__PURE__ */ jsx5(
|
|
1811
|
+
Input,
|
|
1812
|
+
{
|
|
1813
|
+
type: "number",
|
|
1814
|
+
min: 1,
|
|
1815
|
+
max: 1e4,
|
|
1816
|
+
value: limit,
|
|
1817
|
+
onChange: (e) => {
|
|
1818
|
+
const v = Number(e.target.value);
|
|
1819
|
+
if (!Number.isNaN(v)) setLimit(Math.max(1, Math.min(1e4, v)));
|
|
1820
|
+
},
|
|
1821
|
+
className: "h-6 text-[11px]"
|
|
1822
|
+
}
|
|
1823
|
+
)
|
|
1824
|
+
] }),
|
|
1825
|
+
/* @__PURE__ */ jsx5(
|
|
1826
|
+
"button",
|
|
1827
|
+
{
|
|
1828
|
+
className: "w-full py-1.5 text-[11px] font-medium rounded bg-primary text-primary-foreground hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed cursor-pointer",
|
|
1829
|
+
onClick: handleExpand,
|
|
1830
|
+
disabled: loading || noneSelected,
|
|
1831
|
+
title: noneSelected ? "Select at least one relationship type" : void 0,
|
|
1832
|
+
children: "Expand"
|
|
1833
|
+
}
|
|
1834
|
+
)
|
|
1835
|
+
]
|
|
1836
|
+
}
|
|
1837
|
+
);
|
|
1838
|
+
}
|
|
1839
|
+
var ExpandOptionsPanel_default = ExpandOptionsPanel;
|
|
1840
|
+
|
|
1841
|
+
// src/components/rea/ReaContextMenu.tsx
|
|
1842
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1668
1843
|
function ReaContextMenu({
|
|
1669
1844
|
data,
|
|
1670
1845
|
onClose,
|
|
1671
1846
|
elementType,
|
|
1672
1847
|
useGraphExploration,
|
|
1673
|
-
onCopyNode
|
|
1848
|
+
onCopyNode,
|
|
1849
|
+
getNodeEdgeTypes
|
|
1674
1850
|
}) {
|
|
1851
|
+
const [showExpandPanel, setShowExpandPanel] = useState4(false);
|
|
1852
|
+
React3.useEffect(() => {
|
|
1853
|
+
const handleKey = (e) => {
|
|
1854
|
+
if (e.key === "Escape") onClose();
|
|
1855
|
+
};
|
|
1856
|
+
document.addEventListener("keydown", handleKey);
|
|
1857
|
+
return () => document.removeEventListener("keydown", handleKey);
|
|
1858
|
+
}, [onClose]);
|
|
1675
1859
|
const handleFocus = () => {
|
|
1676
1860
|
if (elementType === "node") {
|
|
1677
1861
|
const nodeId = data.id;
|
|
@@ -1724,11 +1908,11 @@ function ReaContextMenu({
|
|
|
1724
1908
|
}
|
|
1725
1909
|
onClose();
|
|
1726
1910
|
};
|
|
1727
|
-
const
|
|
1911
|
+
const handleExpandWithOptions = (options) => {
|
|
1728
1912
|
if (elementType === "node") {
|
|
1729
1913
|
const nodeId = data.id;
|
|
1730
|
-
devLog7("[ReaContextMenu] Expand node:", nodeId);
|
|
1731
|
-
useGraphExploration.getState().expandNode(nodeId);
|
|
1914
|
+
devLog7("[ReaContextMenu] Expand node with options:", nodeId, options);
|
|
1915
|
+
useGraphExploration.getState().expandNode(nodeId, options);
|
|
1732
1916
|
}
|
|
1733
1917
|
onClose();
|
|
1734
1918
|
};
|
|
@@ -1763,7 +1947,7 @@ function ReaContextMenu({
|
|
|
1763
1947
|
{ label: "Hide Node", action: handleHideNode },
|
|
1764
1948
|
{ label: "Hide Incoming", action: handleHideIncoming },
|
|
1765
1949
|
{ label: "Hide Outgoing", action: handleHideOutgoing },
|
|
1766
|
-
{ label: "Expand", action:
|
|
1950
|
+
{ label: "Expand...", action: () => setShowExpandPanel(true) }
|
|
1767
1951
|
];
|
|
1768
1952
|
const edgeMenuItems = [
|
|
1769
1953
|
{ label: "Focus", action: handleFocus },
|
|
@@ -1773,23 +1957,46 @@ function ReaContextMenu({
|
|
|
1773
1957
|
{ label: "Hide Reverse Path", action: handleHideReversePath }
|
|
1774
1958
|
];
|
|
1775
1959
|
const menuItems = elementType === "node" ? nodeMenuItems : edgeMenuItems;
|
|
1776
|
-
|
|
1777
|
-
|
|
1960
|
+
if (showExpandPanel && elementType === "node") {
|
|
1961
|
+
const nodeLabel = data.label || data.id;
|
|
1962
|
+
return /* @__PURE__ */ jsx6(
|
|
1963
|
+
ExpandOptionsPanel_default,
|
|
1964
|
+
{
|
|
1965
|
+
nodeLabel: String(nodeLabel),
|
|
1966
|
+
onExpand: handleExpandWithOptions,
|
|
1967
|
+
onBack: () => setShowExpandPanel(false),
|
|
1968
|
+
getEdgeTypes: getNodeEdgeTypes ? () => getNodeEdgeTypes(Number(data.id)) : void 0
|
|
1969
|
+
}
|
|
1970
|
+
);
|
|
1971
|
+
}
|
|
1972
|
+
return /* @__PURE__ */ jsxs5("div", { className: "bg-background border border-border rounded-md shadow-lg py-1 min-w-48", children: [
|
|
1973
|
+
menuItems.map((item, index) => /* @__PURE__ */ jsxs5(React3.Fragment, { children: [
|
|
1974
|
+
/* @__PURE__ */ jsx6(
|
|
1975
|
+
"button",
|
|
1976
|
+
{
|
|
1977
|
+
className: "w-full text-left px-3 py-2 text-sm hover:bg-muted/50 cursor-pointer",
|
|
1978
|
+
onClick: item.action,
|
|
1979
|
+
children: item.label
|
|
1980
|
+
}
|
|
1981
|
+
),
|
|
1982
|
+
index === 1 && /* @__PURE__ */ jsx6("div", { className: "border-t border-border my-1" })
|
|
1983
|
+
] }, item.label)),
|
|
1984
|
+
/* @__PURE__ */ jsx6("div", { className: "border-t border-border my-1" }),
|
|
1985
|
+
/* @__PURE__ */ jsx6(
|
|
1778
1986
|
"button",
|
|
1779
1987
|
{
|
|
1780
|
-
className: "w-full text-left px-3 py-
|
|
1781
|
-
onClick:
|
|
1782
|
-
children:
|
|
1988
|
+
className: "w-full text-left px-3 py-1.5 text-xs text-muted-foreground hover:bg-muted/50 cursor-pointer",
|
|
1989
|
+
onClick: onClose,
|
|
1990
|
+
children: "Cancel"
|
|
1783
1991
|
}
|
|
1784
|
-
)
|
|
1785
|
-
|
|
1786
|
-
] }, item.label)) });
|
|
1992
|
+
)
|
|
1993
|
+
] });
|
|
1787
1994
|
}
|
|
1788
1995
|
var ReaContextMenu_default = ReaContextMenu;
|
|
1789
1996
|
|
|
1790
1997
|
// src/components/rea/ReaGraph.tsx
|
|
1791
|
-
import { toast } from "sonner";
|
|
1792
|
-
import { jsx as
|
|
1998
|
+
import { toast as toast2 } from "sonner";
|
|
1999
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1793
2000
|
function findElementInGraphData(elementId, elementType, nodes, edges) {
|
|
1794
2001
|
if (elementType === "node") {
|
|
1795
2002
|
const node = nodes.find((n) => n.id === elementId);
|
|
@@ -1851,22 +2058,26 @@ function processFocusAction(focusAction, canvasRef, nodes, edges, setSelectedNod
|
|
|
1851
2058
|
}
|
|
1852
2059
|
return true;
|
|
1853
2060
|
}
|
|
1854
|
-
function ReaGraph({
|
|
1855
|
-
|
|
2061
|
+
function ReaGraph({
|
|
2062
|
+
onCopyNode,
|
|
2063
|
+
extraToolbarContent,
|
|
2064
|
+
getNodeEdgeTypes
|
|
2065
|
+
}) {
|
|
2066
|
+
const isMountedRef = useRef2(false);
|
|
1856
2067
|
const { nodes, edges } = useReagraphData();
|
|
1857
2068
|
const { normalized } = useLiveGraphData();
|
|
1858
|
-
|
|
2069
|
+
useEffect3(() => {
|
|
1859
2070
|
devLog8("[ReGraph] counts", { nodes: nodes.length, edges: edges.length });
|
|
1860
2071
|
if (nodes.length > 0) devLog8("[ReGraph] sample node", nodes[0]);
|
|
1861
2072
|
if (edges.length > 0) devLog8("[ReGraph] sample edge", edges[0]);
|
|
1862
2073
|
}, [nodes, edges]);
|
|
1863
|
-
const canvas =
|
|
1864
|
-
const [hoveredNode, setHoveredNode] =
|
|
2074
|
+
const canvas = useRef2(null);
|
|
2075
|
+
const [hoveredNode, setHoveredNode] = useState5(
|
|
1865
2076
|
void 0
|
|
1866
2077
|
);
|
|
1867
|
-
const [layout, setLayout] =
|
|
1868
|
-
const [fullscreen, setFullscreen] =
|
|
1869
|
-
const [pathSelectionType, setPathSelectionType] =
|
|
2078
|
+
const [layout, setLayout] = useState5("forceDirected2d");
|
|
2079
|
+
const [fullscreen, setFullscreen] = useState5(false);
|
|
2080
|
+
const [pathSelectionType, setPathSelectionType] = useState5("direct");
|
|
1870
2081
|
const useGraphSelection = useWorkspaceSelection();
|
|
1871
2082
|
const useGraphFilter2 = useWorkspaceGraphFilter();
|
|
1872
2083
|
const useGraphExploration = useWorkspaceGraphExploration();
|
|
@@ -1892,7 +2103,7 @@ function ReaGraph({ onCopyNode, extraToolbarContent }) {
|
|
|
1892
2103
|
pathSelectionType,
|
|
1893
2104
|
type: "multi"
|
|
1894
2105
|
});
|
|
1895
|
-
|
|
2106
|
+
useEffect3(() => {
|
|
1896
2107
|
const unsubscribe = GraphFocus_default.subscribe((state) => {
|
|
1897
2108
|
const focusAction = state.focusAction;
|
|
1898
2109
|
if (!focusAction || !canvas.current) return;
|
|
@@ -1916,12 +2127,12 @@ function ReaGraph({ onCopyNode, extraToolbarContent }) {
|
|
|
1916
2127
|
});
|
|
1917
2128
|
return unsubscribe;
|
|
1918
2129
|
}, [nodes, edges, setSelectedNodeIds, setSelectedEdge]);
|
|
1919
|
-
|
|
2130
|
+
useEffect3(() => {
|
|
1920
2131
|
if (!canvas.current) return;
|
|
1921
2132
|
clearSelections();
|
|
1922
2133
|
clearSelectionStore();
|
|
1923
2134
|
}, [lastDataChangeTime, clearSelections, clearSelectionStore]);
|
|
1924
|
-
const fitToScreen =
|
|
2135
|
+
const fitToScreen = useCallback3(
|
|
1925
2136
|
(reason) => {
|
|
1926
2137
|
if (!isMountedRef.current) return;
|
|
1927
2138
|
if (nodes.length === 0) return;
|
|
@@ -1947,7 +2158,7 @@ function ReaGraph({ onCopyNode, extraToolbarContent }) {
|
|
|
1947
2158
|
},
|
|
1948
2159
|
[nodes.length]
|
|
1949
2160
|
);
|
|
1950
|
-
|
|
2161
|
+
useEffect3(() => {
|
|
1951
2162
|
isMountedRef.current = true;
|
|
1952
2163
|
fitToScreen("mount");
|
|
1953
2164
|
const state = useGraphSelection.getState();
|
|
@@ -1967,7 +2178,7 @@ function ReaGraph({ onCopyNode, extraToolbarContent }) {
|
|
|
1967
2178
|
isMountedRef.current = false;
|
|
1968
2179
|
};
|
|
1969
2180
|
}, [fitToScreen, setSelections, setSelectedEdge, useGraphSelection]);
|
|
1970
|
-
|
|
2181
|
+
useEffect3(() => {
|
|
1971
2182
|
if (isMountedRef.current) fitToScreen("counts-changed");
|
|
1972
2183
|
}, [nodes.length, edges.length, fitToScreen]);
|
|
1973
2184
|
function updateLayout(next) {
|
|
@@ -2009,14 +2220,14 @@ function ReaGraph({ onCopyNode, extraToolbarContent }) {
|
|
|
2009
2220
|
setSelectedEdge(null);
|
|
2010
2221
|
if (onCanvasClick) onCanvasClick(e);
|
|
2011
2222
|
}
|
|
2012
|
-
|
|
2223
|
+
useEffect3(() => {
|
|
2013
2224
|
if (!isMountedRef.current) return;
|
|
2014
2225
|
if (selections.length > 0 && selections.length <= 2) {
|
|
2015
2226
|
const selectedNodes = selections.map((id) => nodes.find((n) => n.id === id)).filter(Boolean);
|
|
2016
2227
|
setSelectedNodeIds(selectedNodes.map((n) => n.id));
|
|
2017
2228
|
}
|
|
2018
2229
|
}, [selections, nodes]);
|
|
2019
|
-
|
|
2230
|
+
useEffect3(() => {
|
|
2020
2231
|
if (!isMountedRef.current) return;
|
|
2021
2232
|
const currentSelectedIds = useGraphSelection.getState().selectedNodeIds;
|
|
2022
2233
|
if (!currentSelectedIds.length) return;
|
|
@@ -2035,7 +2246,7 @@ function ReaGraph({ onCopyNode, extraToolbarContent }) {
|
|
|
2035
2246
|
setSelectedEdge,
|
|
2036
2247
|
useGraphSelection
|
|
2037
2248
|
]);
|
|
2038
|
-
|
|
2249
|
+
useEffect3(() => {
|
|
2039
2250
|
if (!isMountedRef.current) return;
|
|
2040
2251
|
const currentSelectedIds = useGraphSelection.getState().selectedNodeIds;
|
|
2041
2252
|
if (!currentSelectedIds.length) return;
|
|
@@ -2047,7 +2258,7 @@ function ReaGraph({ onCopyNode, extraToolbarContent }) {
|
|
|
2047
2258
|
if (stillPresentIds.length < 2) setSelectedEdge(null);
|
|
2048
2259
|
}
|
|
2049
2260
|
}, [nodes, setSelectedNodeIds, setSelectedEdge, useGraphSelection]);
|
|
2050
|
-
|
|
2261
|
+
useEffect3(() => {
|
|
2051
2262
|
if (!fullscreen) return;
|
|
2052
2263
|
const prevOverflow = document.body.style.overflow;
|
|
2053
2264
|
document.body.style.overflow = "hidden";
|
|
@@ -2061,7 +2272,7 @@ function ReaGraph({ onCopyNode, extraToolbarContent }) {
|
|
|
2061
2272
|
window.removeEventListener("keydown", handleKey);
|
|
2062
2273
|
};
|
|
2063
2274
|
}, [fullscreen, fitToScreen]);
|
|
2064
|
-
|
|
2275
|
+
useEffect3(() => {
|
|
2065
2276
|
if (!fullscreen) return;
|
|
2066
2277
|
const id = setTimeout(() => {
|
|
2067
2278
|
if (canvas.current) {
|
|
@@ -2070,7 +2281,7 @@ function ReaGraph({ onCopyNode, extraToolbarContent }) {
|
|
|
2070
2281
|
}, 50);
|
|
2071
2282
|
return () => clearTimeout(id);
|
|
2072
2283
|
}, [fullscreen, fitToScreen]);
|
|
2073
|
-
|
|
2284
|
+
useEffect3(() => {
|
|
2074
2285
|
if (!isMountedRef.current) return;
|
|
2075
2286
|
const handleResize = () => {
|
|
2076
2287
|
if (isMountedRef.current && canvas.current) {
|
|
@@ -2082,8 +2293,8 @@ function ReaGraph({ onCopyNode, extraToolbarContent }) {
|
|
|
2082
2293
|
window.removeEventListener("resize", handleResize);
|
|
2083
2294
|
};
|
|
2084
2295
|
}, [fitToScreen]);
|
|
2085
|
-
const firstDataRef =
|
|
2086
|
-
|
|
2296
|
+
const firstDataRef = useRef2(true);
|
|
2297
|
+
useEffect3(() => {
|
|
2087
2298
|
if (!isMountedRef.current) return;
|
|
2088
2299
|
if (nodes.length > 0) {
|
|
2089
2300
|
if (firstDataRef.current) {
|
|
@@ -2096,18 +2307,18 @@ function ReaGraph({ onCopyNode, extraToolbarContent }) {
|
|
|
2096
2307
|
}, [nodes.length, fitToScreen]);
|
|
2097
2308
|
if (nodes.length === 0) {
|
|
2098
2309
|
devLog8("[ReGraph] empty state render");
|
|
2099
|
-
return /* @__PURE__ */
|
|
2100
|
-
/* @__PURE__ */
|
|
2101
|
-
/* @__PURE__ */
|
|
2310
|
+
return /* @__PURE__ */ jsxs6(Card2, { className: "relative w-full h-full items-center justify-center text-slate-500 gap-2 shadow-xs p-4", children: [
|
|
2311
|
+
/* @__PURE__ */ jsx7("div", { children: "No data to display." }),
|
|
2312
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
2102
2313
|
"Please",
|
|
2103
2314
|
" ",
|
|
2104
|
-
/* @__PURE__ */
|
|
2315
|
+
/* @__PURE__ */ jsx7("span", { className: "font-semibold", children: "run a query, check filters, or add a node" }),
|
|
2105
2316
|
" ",
|
|
2106
2317
|
"to the workbench to populate the graph."
|
|
2107
2318
|
] })
|
|
2108
2319
|
] });
|
|
2109
2320
|
}
|
|
2110
|
-
return /* @__PURE__ */
|
|
2321
|
+
return /* @__PURE__ */ jsxs6(
|
|
2111
2322
|
"div",
|
|
2112
2323
|
{
|
|
2113
2324
|
className: cn(
|
|
@@ -2115,7 +2326,7 @@ function ReaGraph({ onCopyNode, extraToolbarContent }) {
|
|
|
2115
2326
|
fullscreen ? "fixed inset-0 z-50 w-screen h-screen p-0 m-0" : "relative w-full h-full"
|
|
2116
2327
|
),
|
|
2117
2328
|
children: [
|
|
2118
|
-
/* @__PURE__ */
|
|
2329
|
+
/* @__PURE__ */ jsx7(Card2, { className: "h-full shadow-xs p-4", children: /* @__PURE__ */ jsx7(
|
|
2119
2330
|
GraphCanvas,
|
|
2120
2331
|
{
|
|
2121
2332
|
ref: canvas,
|
|
@@ -2140,21 +2351,22 @@ function ReaGraph({ onCopyNode, extraToolbarContent }) {
|
|
|
2140
2351
|
elementId: data.id,
|
|
2141
2352
|
elementType
|
|
2142
2353
|
});
|
|
2143
|
-
return /* @__PURE__ */
|
|
2354
|
+
return /* @__PURE__ */ jsx7(
|
|
2144
2355
|
ReaContextMenu_default,
|
|
2145
2356
|
{
|
|
2146
2357
|
data,
|
|
2147
2358
|
onClose,
|
|
2148
2359
|
elementType,
|
|
2149
2360
|
useGraphExploration,
|
|
2150
|
-
onCopyNode
|
|
2361
|
+
onCopyNode,
|
|
2362
|
+
getNodeEdgeTypes
|
|
2151
2363
|
}
|
|
2152
2364
|
);
|
|
2153
2365
|
}
|
|
2154
2366
|
}
|
|
2155
2367
|
) }),
|
|
2156
|
-
hoveredNode && /* @__PURE__ */
|
|
2157
|
-
/* @__PURE__ */
|
|
2368
|
+
hoveredNode && /* @__PURE__ */ jsx7(NodeHoverInfo_default, { node: hoveredNode }),
|
|
2369
|
+
/* @__PURE__ */ jsx7(
|
|
2158
2370
|
LayoutAndCameraControls_default,
|
|
2159
2371
|
{
|
|
2160
2372
|
fitToScreen,
|
|
@@ -2166,7 +2378,7 @@ function ReaGraph({ onCopyNode, extraToolbarContent }) {
|
|
|
2166
2378
|
isFocusMode,
|
|
2167
2379
|
onResetView: () => {
|
|
2168
2380
|
useGraphExploration.getState().resetView();
|
|
2169
|
-
|
|
2381
|
+
toast2.success(
|
|
2170
2382
|
isFocusMode ? "Focus mode cleared" : "Hidden elements restored"
|
|
2171
2383
|
);
|
|
2172
2384
|
},
|
|
@@ -2181,12 +2393,12 @@ var ReaGraph_default = ReaGraph;
|
|
|
2181
2393
|
|
|
2182
2394
|
// src/components/cyto/CytoscapeGraph.tsx
|
|
2183
2395
|
import {
|
|
2184
|
-
useEffect as
|
|
2185
|
-
useRef as
|
|
2186
|
-
useState as
|
|
2187
|
-
useCallback as
|
|
2396
|
+
useEffect as useEffect4,
|
|
2397
|
+
useRef as useRef3,
|
|
2398
|
+
useState as useState6,
|
|
2399
|
+
useCallback as useCallback4
|
|
2188
2400
|
} from "react";
|
|
2189
|
-
import { devLog as devLog10, errorLog as
|
|
2401
|
+
import { devLog as devLog10, errorLog as errorLog3 } from "@petrarca/sonnet-core";
|
|
2190
2402
|
import cytoscape from "cytoscape";
|
|
2191
2403
|
import fcose from "cytoscape-fcose";
|
|
2192
2404
|
import cola from "cytoscape-cola";
|
|
@@ -2208,7 +2420,7 @@ import {
|
|
|
2208
2420
|
SimpleTooltip as SimpleTooltip3
|
|
2209
2421
|
} from "@petrarca/sonnet-ui";
|
|
2210
2422
|
import { LayoutPanelTop as LayoutPanelTop2, Monitor, Frame, Eye as Eye2, Minus } from "lucide-react";
|
|
2211
|
-
import { Fragment as Fragment2, jsx as
|
|
2423
|
+
import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2212
2424
|
function ViewControls2({
|
|
2213
2425
|
zoomIn,
|
|
2214
2426
|
zoomOut,
|
|
@@ -2219,17 +2431,17 @@ function ViewControls2({
|
|
|
2219
2431
|
isFocusMode,
|
|
2220
2432
|
onResetView
|
|
2221
2433
|
}) {
|
|
2222
|
-
return /* @__PURE__ */
|
|
2223
|
-
/* @__PURE__ */
|
|
2224
|
-
/* @__PURE__ */
|
|
2225
|
-
/* @__PURE__ */
|
|
2226
|
-
/* @__PURE__ */
|
|
2227
|
-
(hasHiddenElements || isFocusMode) && onResetView && /* @__PURE__ */
|
|
2434
|
+
return /* @__PURE__ */ jsxs7(Fragment2, { children: [
|
|
2435
|
+
/* @__PURE__ */ jsx8(SimpleTooltip3, { label: "Zoom In", side: "left", children: /* @__PURE__ */ jsx8(Button3, { variant: "ghost", size: "icon", onClick: zoomIn, children: /* @__PURE__ */ jsx8("span", { style: { fontWeight: 600 }, children: "+" }) }) }),
|
|
2436
|
+
/* @__PURE__ */ jsx8(SimpleTooltip3, { label: "Zoom Out", side: "left", children: /* @__PURE__ */ jsx8(Button3, { variant: "ghost", size: "icon", onClick: zoomOut, children: /* @__PURE__ */ jsx8(Minus, {}) }) }),
|
|
2437
|
+
/* @__PURE__ */ jsx8(SimpleTooltip3, { label: "Fullscreen", side: "left", children: /* @__PURE__ */ jsx8(Button3, { variant: "ghost", size: "icon", onClick: toggleFullscreen, children: !fullscreen ? /* @__PURE__ */ jsx8(Monitor, {}) : /* @__PURE__ */ jsx8(Frame, {}) }) }),
|
|
2438
|
+
/* @__PURE__ */ jsx8(SimpleTooltip3, { label: "Fit to screen", side: "left", children: /* @__PURE__ */ jsx8(Button3, { variant: "ghost", size: "icon", onClick: fitToScreen, children: /* @__PURE__ */ jsx8(Frame, {}) }) }),
|
|
2439
|
+
(hasHiddenElements || isFocusMode) && onResetView && /* @__PURE__ */ jsx8(
|
|
2228
2440
|
SimpleTooltip3,
|
|
2229
2441
|
{
|
|
2230
2442
|
label: isFocusMode ? "Reset Focus" : "Show All Hidden",
|
|
2231
2443
|
side: "left",
|
|
2232
|
-
children: /* @__PURE__ */
|
|
2444
|
+
children: /* @__PURE__ */ jsx8(Button3, { variant: "ghost", size: "icon", onClick: onResetView, children: /* @__PURE__ */ jsx8(Eye2, {}) })
|
|
2233
2445
|
}
|
|
2234
2446
|
)
|
|
2235
2447
|
] });
|
|
@@ -2264,12 +2476,12 @@ var LAYOUT_GROUPS = [
|
|
|
2264
2476
|
}
|
|
2265
2477
|
];
|
|
2266
2478
|
function LayoutDropdown2({ currentLayout, updateLayout }) {
|
|
2267
|
-
return /* @__PURE__ */
|
|
2268
|
-
/* @__PURE__ */
|
|
2269
|
-
/* @__PURE__ */
|
|
2270
|
-
groupIdx > 0 && /* @__PURE__ */
|
|
2271
|
-
/* @__PURE__ */
|
|
2272
|
-
group.items.map((item) => /* @__PURE__ */
|
|
2479
|
+
return /* @__PURE__ */ jsxs7(DropdownMenu3, { children: [
|
|
2480
|
+
/* @__PURE__ */ jsx8(SimpleTooltip3, { label: "Layout", side: "left", children: /* @__PURE__ */ jsx8(DropdownMenuTrigger3, { asChild: true, children: /* @__PURE__ */ jsx8(Button3, { variant: "ghost", size: "icon", children: /* @__PURE__ */ jsx8(LayoutPanelTop2, {}) }) }) }),
|
|
2481
|
+
/* @__PURE__ */ jsx8(DropdownMenuContent3, { side: "left", align: "start", children: LAYOUT_GROUPS.map((group, groupIdx) => /* @__PURE__ */ jsxs7("div", { children: [
|
|
2482
|
+
groupIdx > 0 && /* @__PURE__ */ jsx8(DropdownMenuSeparator2, {}),
|
|
2483
|
+
/* @__PURE__ */ jsx8(DropdownMenuLabel2, { children: group.label }),
|
|
2484
|
+
group.items.map((item) => /* @__PURE__ */ jsx8(
|
|
2273
2485
|
DropdownMenuItem3,
|
|
2274
2486
|
{
|
|
2275
2487
|
onClick: () => updateLayout(item.layout),
|
|
@@ -2294,9 +2506,9 @@ function CytoscapeControls({
|
|
|
2294
2506
|
onResetView,
|
|
2295
2507
|
extraToolbarContent
|
|
2296
2508
|
}) {
|
|
2297
|
-
return /* @__PURE__ */
|
|
2298
|
-
/* @__PURE__ */
|
|
2299
|
-
/* @__PURE__ */
|
|
2509
|
+
return /* @__PURE__ */ jsxs7("div", { className: "absolute right-2 top-2 flex flex-col border bg-white rounded-md shadow-sm z-10", children: [
|
|
2510
|
+
/* @__PURE__ */ jsx8(RendererDropdown, {}),
|
|
2511
|
+
/* @__PURE__ */ jsx8(
|
|
2300
2512
|
ViewControls2,
|
|
2301
2513
|
{
|
|
2302
2514
|
zoomIn,
|
|
@@ -2310,7 +2522,7 @@ function CytoscapeControls({
|
|
|
2310
2522
|
}
|
|
2311
2523
|
),
|
|
2312
2524
|
extraToolbarContent,
|
|
2313
|
-
/* @__PURE__ */
|
|
2525
|
+
/* @__PURE__ */ jsx8(
|
|
2314
2526
|
LayoutDropdown2,
|
|
2315
2527
|
{
|
|
2316
2528
|
currentLayout,
|
|
@@ -2590,12 +2802,13 @@ function getLayoutPreset(options) {
|
|
|
2590
2802
|
}
|
|
2591
2803
|
|
|
2592
2804
|
// src/components/cyto/contextMenuConfig.ts
|
|
2593
|
-
import { devLog as devLog9, errorLog } from "@petrarca/sonnet-core";
|
|
2594
|
-
import { toast as
|
|
2805
|
+
import { devLog as devLog9, errorLog as errorLog2 } from "@petrarca/sonnet-core";
|
|
2806
|
+
import { toast as toast3 } from "sonner";
|
|
2595
2807
|
var createNodeContextMenu = ({
|
|
2596
2808
|
cy,
|
|
2597
2809
|
useGraphExploration,
|
|
2598
|
-
onCopyNode
|
|
2810
|
+
onCopyNode,
|
|
2811
|
+
onExpandRequest
|
|
2599
2812
|
}) => {
|
|
2600
2813
|
devLog9("[CxtMenu] Initializing node context menu");
|
|
2601
2814
|
return cy.cxtmenu({
|
|
@@ -2617,7 +2830,7 @@ var createNodeContextMenu = ({
|
|
|
2617
2830
|
if (visualGraph) {
|
|
2618
2831
|
onCopyNode?.(visualGraph);
|
|
2619
2832
|
} else {
|
|
2620
|
-
|
|
2833
|
+
errorLog2("[CxtMenu] visualGraph not found in element data");
|
|
2621
2834
|
}
|
|
2622
2835
|
}
|
|
2623
2836
|
},
|
|
@@ -2647,21 +2860,23 @@ var createNodeContextMenu = ({
|
|
|
2647
2860
|
},
|
|
2648
2861
|
{
|
|
2649
2862
|
content: "Expand",
|
|
2650
|
-
select:
|
|
2863
|
+
select: (ele) => {
|
|
2651
2864
|
const nodeId = ele.id();
|
|
2652
|
-
devLog9("[CxtMenu]
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2865
|
+
devLog9("[CxtMenu] Expand request for node:", nodeId);
|
|
2866
|
+
if (onExpandRequest) {
|
|
2867
|
+
const pos = ele.renderedPosition();
|
|
2868
|
+
const label = ele.data("label") || nodeId;
|
|
2869
|
+
onExpandRequest({ nodeId, nodeLabel: label, x: pos.x, y: pos.y });
|
|
2870
|
+
} else {
|
|
2871
|
+
useGraphExploration.getState().expandNode(nodeId).catch((error) => {
|
|
2872
|
+
errorLog2("[CxtMenu] Expansion failed:", error);
|
|
2873
|
+
toast3.error("Failed to expand node");
|
|
2874
|
+
});
|
|
2659
2875
|
}
|
|
2660
2876
|
}
|
|
2661
2877
|
}
|
|
2662
2878
|
],
|
|
2663
2879
|
menuRadius: 60,
|
|
2664
|
-
// Increased for more items (default is 100)
|
|
2665
2880
|
fillColor: "rgba(0, 0, 0, 0.75)",
|
|
2666
2881
|
activeFillColor: "rgba(59, 130, 246, 0.75)",
|
|
2667
2882
|
// blue-500
|
|
@@ -2746,8 +2961,49 @@ var createEdgeContextMenu = ({
|
|
|
2746
2961
|
};
|
|
2747
2962
|
|
|
2748
2963
|
// src/components/cyto/CytoscapeGraph.tsx
|
|
2749
|
-
import { toast as
|
|
2750
|
-
import { jsx as
|
|
2964
|
+
import { toast as toast4 } from "sonner";
|
|
2965
|
+
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2966
|
+
function CytoscapeExpandOverlay({
|
|
2967
|
+
expandRequest,
|
|
2968
|
+
containerRef,
|
|
2969
|
+
useGraphExploration,
|
|
2970
|
+
getNodeEdgeTypes,
|
|
2971
|
+
onClose
|
|
2972
|
+
}) {
|
|
2973
|
+
return /* @__PURE__ */ jsx9(
|
|
2974
|
+
"div",
|
|
2975
|
+
{
|
|
2976
|
+
className: "absolute z-50",
|
|
2977
|
+
style: {
|
|
2978
|
+
left: Math.min(
|
|
2979
|
+
Math.max(expandRequest.x, 120),
|
|
2980
|
+
(containerRef.current?.clientWidth ?? 800) - 120
|
|
2981
|
+
),
|
|
2982
|
+
top: Math.min(
|
|
2983
|
+
Math.max(expandRequest.y, 10),
|
|
2984
|
+
(containerRef.current?.clientHeight ?? 600) - 260
|
|
2985
|
+
),
|
|
2986
|
+
transform: "translate(-50%, 12px)"
|
|
2987
|
+
},
|
|
2988
|
+
children: /* @__PURE__ */ jsx9(
|
|
2989
|
+
ExpandOptionsPanel_default,
|
|
2990
|
+
{
|
|
2991
|
+
nodeLabel: expandRequest.nodeLabel,
|
|
2992
|
+
onExpand: (options) => {
|
|
2993
|
+
const { nodeId } = expandRequest;
|
|
2994
|
+
onClose();
|
|
2995
|
+
useGraphExploration.getState().expandNode(nodeId, options).catch((err) => {
|
|
2996
|
+
errorLog3("[CxtMenu] Expansion failed:", err);
|
|
2997
|
+
toast4.error("Failed to expand node");
|
|
2998
|
+
});
|
|
2999
|
+
},
|
|
3000
|
+
onBack: onClose,
|
|
3001
|
+
getEdgeTypes: getNodeEdgeTypes ? () => getNodeEdgeTypes(Number(expandRequest.nodeId)) : void 0
|
|
3002
|
+
}
|
|
3003
|
+
)
|
|
3004
|
+
}
|
|
3005
|
+
);
|
|
3006
|
+
}
|
|
2751
3007
|
try {
|
|
2752
3008
|
cytoscape.use(fcose);
|
|
2753
3009
|
cytoscape.use(cola);
|
|
@@ -2825,12 +3081,12 @@ function applyLayout({
|
|
|
2825
3081
|
try {
|
|
2826
3082
|
cy.layout(layoutOpts).run();
|
|
2827
3083
|
} catch (e) {
|
|
2828
|
-
|
|
3084
|
+
errorLog3("Layout error, falling back to dagre:", e);
|
|
2829
3085
|
if (chosen === "klay") {
|
|
2830
3086
|
try {
|
|
2831
3087
|
cy.layout(getPreset("dagre")).run();
|
|
2832
3088
|
} catch (inner) {
|
|
2833
|
-
|
|
3089
|
+
errorLog3("Fallback layout also failed, using grid:", inner);
|
|
2834
3090
|
cy.layout(getPreset("grid")).run();
|
|
2835
3091
|
}
|
|
2836
3092
|
} else {
|
|
@@ -3037,8 +3293,8 @@ function computeGraphViewState({
|
|
|
3037
3293
|
};
|
|
3038
3294
|
}
|
|
3039
3295
|
function useFullscreen(fitToScreen, cyRef) {
|
|
3040
|
-
const [fullscreen, setFullscreen] =
|
|
3041
|
-
|
|
3296
|
+
const [fullscreen, setFullscreen] = useState6(false);
|
|
3297
|
+
useEffect4(() => {
|
|
3042
3298
|
if (fullscreen) {
|
|
3043
3299
|
const prevOverflow = document.body.style.overflow;
|
|
3044
3300
|
document.body.style.overflow = "hidden";
|
|
@@ -3053,7 +3309,7 @@ function useFullscreen(fitToScreen, cyRef) {
|
|
|
3053
3309
|
};
|
|
3054
3310
|
}
|
|
3055
3311
|
}, [fullscreen, fitToScreen]);
|
|
3056
|
-
|
|
3312
|
+
useEffect4(() => {
|
|
3057
3313
|
if (!fullscreen) return;
|
|
3058
3314
|
const id = setTimeout(() => {
|
|
3059
3315
|
if (cyRef.current) {
|
|
@@ -3066,7 +3322,7 @@ function useFullscreen(fitToScreen, cyRef) {
|
|
|
3066
3322
|
return {
|
|
3067
3323
|
fullscreen,
|
|
3068
3324
|
setFullscreen,
|
|
3069
|
-
toggleFullscreen:
|
|
3325
|
+
toggleFullscreen: useCallback4(() => setFullscreen((f) => !f), [])
|
|
3070
3326
|
};
|
|
3071
3327
|
}
|
|
3072
3328
|
function setupCytoscapeEventHandlers({
|
|
@@ -3078,7 +3334,8 @@ function setupCytoscapeEventHandlers({
|
|
|
3078
3334
|
setSelectedEdgeStore,
|
|
3079
3335
|
clearSelectionStore,
|
|
3080
3336
|
useGraphExploration,
|
|
3081
|
-
onCopyNode
|
|
3337
|
+
onCopyNode,
|
|
3338
|
+
onExpandRequest
|
|
3082
3339
|
}) {
|
|
3083
3340
|
const updateSelectedNodeIds = (nodeIds) => {
|
|
3084
3341
|
setSelectedNodeIdsStore(nodeIds);
|
|
@@ -3166,22 +3423,31 @@ function setupCytoscapeEventHandlers({
|
|
|
3166
3423
|
cy.on("tap", (evt) => {
|
|
3167
3424
|
if (evt.target === cy) clearAll();
|
|
3168
3425
|
});
|
|
3169
|
-
createNodeContextMenu({
|
|
3426
|
+
createNodeContextMenu({
|
|
3427
|
+
cy,
|
|
3428
|
+
useGraphExploration,
|
|
3429
|
+
onCopyNode,
|
|
3430
|
+
onExpandRequest
|
|
3431
|
+
});
|
|
3170
3432
|
createEdgeContextMenu({ cy, useGraphExploration });
|
|
3171
3433
|
}
|
|
3172
3434
|
function CytoscapeGraph({
|
|
3173
3435
|
layout: initialLayout = "auto",
|
|
3174
3436
|
fitPadding = 30,
|
|
3175
3437
|
onCopyNode,
|
|
3176
|
-
extraToolbarContent
|
|
3438
|
+
extraToolbarContent,
|
|
3439
|
+
getNodeEdgeTypes
|
|
3177
3440
|
}) {
|
|
3178
|
-
const containerRef =
|
|
3179
|
-
const cyRef =
|
|
3180
|
-
const isInitializedRef =
|
|
3181
|
-
const [currentLayout, setCurrentLayout] =
|
|
3182
|
-
const
|
|
3183
|
-
|
|
3184
|
-
|
|
3441
|
+
const containerRef = useRef3(null);
|
|
3442
|
+
const cyRef = useRef3(null);
|
|
3443
|
+
const isInitializedRef = useRef3(false);
|
|
3444
|
+
const [currentLayout, setCurrentLayout] = useState6(initialLayout);
|
|
3445
|
+
const [expandRequest, setExpandRequest] = useState6(
|
|
3446
|
+
null
|
|
3447
|
+
);
|
|
3448
|
+
const nodesRef = useRef3([]);
|
|
3449
|
+
const edgesRef = useRef3([]);
|
|
3450
|
+
const pendingFocusActionRef = useRef3(null);
|
|
3185
3451
|
const cytoData = useCytoscapeData();
|
|
3186
3452
|
const live = useLiveGraphData();
|
|
3187
3453
|
const nodes = live.nodes;
|
|
@@ -3201,13 +3467,13 @@ function CytoscapeGraph({
|
|
|
3201
3467
|
setSelectedEdge: setSelectedEdgeStore,
|
|
3202
3468
|
clear: clearSelectionStore
|
|
3203
3469
|
} = useSelection3.getState();
|
|
3204
|
-
const selectedNodeIdsRef =
|
|
3470
|
+
const selectedNodeIdsRef = useRef3(
|
|
3205
3471
|
useSelection3.getState().selectedNodeIds
|
|
3206
3472
|
);
|
|
3207
|
-
const selectedEdgeRef =
|
|
3473
|
+
const selectedEdgeRef = useRef3(
|
|
3208
3474
|
useSelection3.getState().selectedEdge
|
|
3209
3475
|
);
|
|
3210
|
-
|
|
3476
|
+
useEffect4(() => {
|
|
3211
3477
|
const state = useSelection3.getState();
|
|
3212
3478
|
selectedNodeIdsRef.current = state.selectedNodeIds;
|
|
3213
3479
|
selectedEdgeRef.current = state.selectedEdge;
|
|
@@ -3227,13 +3493,13 @@ function CytoscapeGraph({
|
|
|
3227
3493
|
});
|
|
3228
3494
|
}
|
|
3229
3495
|
}, [useSelection3]);
|
|
3230
|
-
|
|
3496
|
+
useEffect4(() => {
|
|
3231
3497
|
nodesRef.current = nodes;
|
|
3232
3498
|
}, [nodes]);
|
|
3233
|
-
|
|
3499
|
+
useEffect4(() => {
|
|
3234
3500
|
edgesRef.current = edges;
|
|
3235
3501
|
}, [edges]);
|
|
3236
|
-
|
|
3502
|
+
useEffect4(() => {
|
|
3237
3503
|
if (!containerRef.current || cyRef.current) return;
|
|
3238
3504
|
isInitializedRef.current = true;
|
|
3239
3505
|
cyRef.current = cytoscape({
|
|
@@ -3384,7 +3650,8 @@ function CytoscapeGraph({
|
|
|
3384
3650
|
setSelectedEdgeStore,
|
|
3385
3651
|
clearSelectionStore,
|
|
3386
3652
|
useGraphExploration,
|
|
3387
|
-
onCopyNode
|
|
3653
|
+
onCopyNode,
|
|
3654
|
+
onExpandRequest: setExpandRequest
|
|
3388
3655
|
});
|
|
3389
3656
|
}
|
|
3390
3657
|
return () => {
|
|
@@ -3392,10 +3659,10 @@ function CytoscapeGraph({
|
|
|
3392
3659
|
cyRef.current = null;
|
|
3393
3660
|
};
|
|
3394
3661
|
}, []);
|
|
3395
|
-
const elementIdsRef =
|
|
3396
|
-
const lastLayoutRef =
|
|
3397
|
-
const lastFitPaddingRef =
|
|
3398
|
-
|
|
3662
|
+
const elementIdsRef = useRef3("");
|
|
3663
|
+
const lastLayoutRef = useRef3("");
|
|
3664
|
+
const lastFitPaddingRef = useRef3(fitPadding);
|
|
3665
|
+
useEffect4(() => {
|
|
3399
3666
|
const cy = cyRef.current;
|
|
3400
3667
|
if (!cy || !isInitializedRef.current) return;
|
|
3401
3668
|
const currentIds = nodes.map((n) => n.id_).sort().join(",") + "|" + edges.map((e) => e.id_).sort().join(",");
|
|
@@ -3468,12 +3735,12 @@ function CytoscapeGraph({
|
|
|
3468
3735
|
});
|
|
3469
3736
|
}
|
|
3470
3737
|
}, [nodes, edges, currentLayout, fitPadding]);
|
|
3471
|
-
|
|
3738
|
+
useEffect4(() => {
|
|
3472
3739
|
if (!cyRef.current) return;
|
|
3473
3740
|
cyRef.current.elements().unselect();
|
|
3474
3741
|
clearSelectionStore();
|
|
3475
3742
|
}, [lastDataChangeTime, clearSelectionStore]);
|
|
3476
|
-
|
|
3743
|
+
useEffect4(() => {
|
|
3477
3744
|
const unsubscribe = GraphFocus_default.subscribe((state) => {
|
|
3478
3745
|
handleFocusStateChange({
|
|
3479
3746
|
focusAction: state.focusAction,
|
|
@@ -3492,15 +3759,15 @@ function CytoscapeGraph({
|
|
|
3492
3759
|
const updateLayout = (newLayout) => {
|
|
3493
3760
|
setCurrentLayout(newLayout);
|
|
3494
3761
|
};
|
|
3495
|
-
const fitToScreen =
|
|
3762
|
+
const fitToScreen = useCallback4(() => {
|
|
3496
3763
|
if (cyRef.current) {
|
|
3497
3764
|
cyRef.current.fit(void 0, fitPadding);
|
|
3498
3765
|
}
|
|
3499
3766
|
}, [fitPadding]);
|
|
3500
|
-
|
|
3767
|
+
useEffect4(() => {
|
|
3501
3768
|
fitToScreen();
|
|
3502
3769
|
}, [nodes.length, fitToScreen]);
|
|
3503
|
-
|
|
3770
|
+
useEffect4(() => {
|
|
3504
3771
|
if (!isInitializedRef.current) return;
|
|
3505
3772
|
const handleResize = () => cyRef.current?.resize();
|
|
3506
3773
|
window.addEventListener("resize", handleResize);
|
|
@@ -3519,18 +3786,28 @@ function CytoscapeGraph({
|
|
|
3519
3786
|
isFocusMode,
|
|
3520
3787
|
fullscreen
|
|
3521
3788
|
});
|
|
3522
|
-
return /* @__PURE__ */
|
|
3523
|
-
/* @__PURE__ */
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3789
|
+
return /* @__PURE__ */ jsx9("div", { className: outerClass, children: /* @__PURE__ */ jsxs8("div", { className: innerClass, children: [
|
|
3790
|
+
/* @__PURE__ */ jsx9("div", { ref: containerRef, className: "absolute inset-0" }),
|
|
3791
|
+
expandRequest && /* @__PURE__ */ jsx9(
|
|
3792
|
+
CytoscapeExpandOverlay,
|
|
3793
|
+
{
|
|
3794
|
+
expandRequest,
|
|
3795
|
+
containerRef,
|
|
3796
|
+
useGraphExploration,
|
|
3797
|
+
getNodeEdgeTypes,
|
|
3798
|
+
onClose: () => setExpandRequest(null)
|
|
3799
|
+
}
|
|
3800
|
+
),
|
|
3801
|
+
showEmptyMessage && /* @__PURE__ */ jsx9("div", { className: "absolute inset-0 flex items-center justify-center text-xs text-gray-500 pointer-events-none select-none", children: "No graph data to visualize (run a query or check the filters)" }),
|
|
3802
|
+
showFilteredMessage && /* @__PURE__ */ jsx9("div", { className: "absolute inset-0 flex items-center justify-center text-xs text-gray-500 pointer-events-none select-none", children: 'All elements are hidden or filtered (click "Reset Focus" to restore)' }),
|
|
3803
|
+
showControls && /* @__PURE__ */ jsx9(
|
|
3527
3804
|
CytoscapeControls_default,
|
|
3528
3805
|
{
|
|
3529
3806
|
updateLayout,
|
|
3530
3807
|
fitToScreen,
|
|
3531
3808
|
onResetView: () => {
|
|
3532
3809
|
resetView();
|
|
3533
|
-
|
|
3810
|
+
toast4.success(
|
|
3534
3811
|
isFocusMode ? "Focus mode cleared" : "Hidden elements restored"
|
|
3535
3812
|
);
|
|
3536
3813
|
},
|
|
@@ -3571,26 +3848,29 @@ function CytoscapeGraph({
|
|
|
3571
3848
|
var CytoscapeGraph_default = CytoscapeGraph;
|
|
3572
3849
|
|
|
3573
3850
|
// src/components/GraphVisualizer.tsx
|
|
3574
|
-
import { jsx as
|
|
3851
|
+
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
3575
3852
|
function GraphVisualizer({
|
|
3576
3853
|
onCopyNode,
|
|
3577
|
-
extraToolbarContent
|
|
3854
|
+
extraToolbarContent,
|
|
3855
|
+
getNodeEdgeTypes
|
|
3578
3856
|
}) {
|
|
3579
3857
|
const { renderer } = useGraphRenderer();
|
|
3580
|
-
return /* @__PURE__ */
|
|
3581
|
-
renderer === "reagraph" && /* @__PURE__ */
|
|
3858
|
+
return /* @__PURE__ */ jsx10("div", { className: "relative w-full h-full flex flex-col overflow-hidden", children: /* @__PURE__ */ jsxs9("div", { className: "flex-1 h-full", children: [
|
|
3859
|
+
renderer === "reagraph" && /* @__PURE__ */ jsx10(
|
|
3582
3860
|
ReaGraph_default,
|
|
3583
3861
|
{
|
|
3584
3862
|
onCopyNode,
|
|
3585
|
-
extraToolbarContent
|
|
3863
|
+
extraToolbarContent,
|
|
3864
|
+
getNodeEdgeTypes
|
|
3586
3865
|
},
|
|
3587
3866
|
"reagraph"
|
|
3588
3867
|
),
|
|
3589
|
-
renderer === "cytoscape" && /* @__PURE__ */
|
|
3868
|
+
renderer === "cytoscape" && /* @__PURE__ */ jsx10(
|
|
3590
3869
|
CytoscapeGraph_default,
|
|
3591
3870
|
{
|
|
3592
3871
|
onCopyNode,
|
|
3593
|
-
extraToolbarContent
|
|
3872
|
+
extraToolbarContent,
|
|
3873
|
+
getNodeEdgeTypes
|
|
3594
3874
|
},
|
|
3595
3875
|
"cytoscape"
|
|
3596
3876
|
)
|
|
@@ -3602,18 +3882,19 @@ var GraphVisualizer_default = GraphVisualizer;
|
|
|
3602
3882
|
import { Card as Card5 } from "@petrarca/sonnet-ui";
|
|
3603
3883
|
|
|
3604
3884
|
// src/components/ActionPanel/NodeInfoCard.tsx
|
|
3605
|
-
import { useState as
|
|
3885
|
+
import { useState as useState7 } from "react";
|
|
3606
3886
|
import {
|
|
3607
3887
|
Card as Card3,
|
|
3608
3888
|
Collapsible,
|
|
3609
3889
|
CollapsibleContent,
|
|
3610
|
-
CollapsibleTrigger
|
|
3890
|
+
CollapsibleTrigger,
|
|
3891
|
+
PropertyList
|
|
3611
3892
|
} from "@petrarca/sonnet-ui";
|
|
3612
3893
|
import { copyTextToClipboard } from "@petrarca/sonnet-core";
|
|
3613
|
-
import { jsx as
|
|
3894
|
+
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
3614
3895
|
function NodeInfoCard({ node }) {
|
|
3615
|
-
const [showProperties, setShowProperties] =
|
|
3616
|
-
return /* @__PURE__ */
|
|
3896
|
+
const [showProperties, setShowProperties] = useState7(false);
|
|
3897
|
+
return /* @__PURE__ */ jsxs10(
|
|
3617
3898
|
Card3,
|
|
3618
3899
|
{
|
|
3619
3900
|
className: "w-full rounded-lg overflow-hidden bg-muted/30 border shadow-none p-3",
|
|
@@ -3621,9 +3902,9 @@ function NodeInfoCard({ node }) {
|
|
|
3621
3902
|
borderLeft: `4px solid ${node.visual.color}`
|
|
3622
3903
|
},
|
|
3623
3904
|
children: [
|
|
3624
|
-
/* @__PURE__ */
|
|
3625
|
-
/* @__PURE__ */
|
|
3626
|
-
/* @__PURE__ */
|
|
3905
|
+
/* @__PURE__ */ jsx11("p", { className: "text-sm leading-tight font-medium mb-0", children: node.label_ }),
|
|
3906
|
+
/* @__PURE__ */ jsx11("p", { className: "text-sm leading-tight mb-1", children: node.visual.displayName }),
|
|
3907
|
+
/* @__PURE__ */ jsx11(
|
|
3627
3908
|
"p",
|
|
3628
3909
|
{
|
|
3629
3910
|
className: "text-xs text-muted-foreground cursor-pointer select-all mb-2",
|
|
@@ -3632,23 +3913,9 @@ function NodeInfoCard({ node }) {
|
|
|
3632
3913
|
children: node.id_
|
|
3633
3914
|
}
|
|
3634
3915
|
),
|
|
3635
|
-
/* @__PURE__ */
|
|
3636
|
-
/* @__PURE__ */
|
|
3637
|
-
/* @__PURE__ */
|
|
3638
|
-
/* @__PURE__ */ jsx10("p", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wide mb-1", children: "Properties" }),
|
|
3639
|
-
Object.entries(node.properties_ || {}).map(([key, value]) => /* @__PURE__ */ jsxs9("li", { className: "mb-2 leading-tight", children: [
|
|
3640
|
-
/* @__PURE__ */ jsx10("p", { className: "text-xs text-muted-foreground uppercase tracking-wide", children: key }),
|
|
3641
|
-
/* @__PURE__ */ jsx10(
|
|
3642
|
-
"p",
|
|
3643
|
-
{
|
|
3644
|
-
className: "text-sm truncate max-w-[190px] cursor-pointer",
|
|
3645
|
-
onClick: () => copyTextToClipboard(String(value)),
|
|
3646
|
-
title: "Click to copy value",
|
|
3647
|
-
children: String(value)
|
|
3648
|
-
}
|
|
3649
|
-
)
|
|
3650
|
-
] }, key))
|
|
3651
|
-
] }) })
|
|
3916
|
+
/* @__PURE__ */ jsxs10(Collapsible, { open: showProperties, onOpenChange: setShowProperties, children: [
|
|
3917
|
+
/* @__PURE__ */ jsx11(CollapsibleTrigger, { asChild: true, children: /* @__PURE__ */ jsx11("button", { className: "text-xs cursor-pointer", children: showProperties ? "Hide" : "Show more" }) }),
|
|
3918
|
+
/* @__PURE__ */ jsx11(CollapsibleContent, { children: /* @__PURE__ */ jsx11("div", { className: "mt-2", children: /* @__PURE__ */ jsx11(PropertyList, { properties: node.properties_ || {}, showHeader: true }) }) })
|
|
3652
3919
|
] })
|
|
3653
3920
|
]
|
|
3654
3921
|
}
|
|
@@ -3657,19 +3924,20 @@ function NodeInfoCard({ node }) {
|
|
|
3657
3924
|
var NodeInfoCard_default = NodeInfoCard;
|
|
3658
3925
|
|
|
3659
3926
|
// src/components/ActionPanel/EdgeInfoCard.tsx
|
|
3660
|
-
import { useState as
|
|
3927
|
+
import { useState as useState8 } from "react";
|
|
3661
3928
|
import {
|
|
3662
3929
|
Card as Card4,
|
|
3663
3930
|
Collapsible as Collapsible2,
|
|
3664
3931
|
CollapsibleContent as CollapsibleContent2,
|
|
3665
|
-
CollapsibleTrigger as CollapsibleTrigger2
|
|
3932
|
+
CollapsibleTrigger as CollapsibleTrigger2,
|
|
3933
|
+
PropertyList as PropertyList2
|
|
3666
3934
|
} from "@petrarca/sonnet-ui";
|
|
3667
3935
|
import { ArrowDown } from "lucide-react";
|
|
3668
3936
|
import { copyTextToClipboard as copyTextToClipboard2 } from "@petrarca/sonnet-core";
|
|
3669
|
-
import { jsx as
|
|
3937
|
+
import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
3670
3938
|
function EdgeInfoCard({ edge }) {
|
|
3671
|
-
const [showProperties, setShowProperties] =
|
|
3672
|
-
return /* @__PURE__ */
|
|
3939
|
+
const [showProperties, setShowProperties] = useState8(false);
|
|
3940
|
+
return /* @__PURE__ */ jsxs11(
|
|
3673
3941
|
Card4,
|
|
3674
3942
|
{
|
|
3675
3943
|
className: "w-full rounded-lg overflow-hidden bg-muted/30 border shadow-none p-3",
|
|
@@ -3677,11 +3945,11 @@ function EdgeInfoCard({ edge }) {
|
|
|
3677
3945
|
borderLeft: `4px solid ${edge.visual.color}`
|
|
3678
3946
|
},
|
|
3679
3947
|
children: [
|
|
3680
|
-
/* @__PURE__ */
|
|
3681
|
-
/* @__PURE__ */
|
|
3682
|
-
/* @__PURE__ */
|
|
3948
|
+
/* @__PURE__ */ jsxs11("p", { className: "text-sm leading-tight mb-1", children: [
|
|
3949
|
+
/* @__PURE__ */ jsx12(ArrowDown, { className: "inline-block mr-1 opacity-70 align-middle h-3.5 w-3.5" }),
|
|
3950
|
+
/* @__PURE__ */ jsx12("strong", { className: "font-medium align-middle", children: edge.label_ })
|
|
3683
3951
|
] }),
|
|
3684
|
-
edge.id_ && /* @__PURE__ */
|
|
3952
|
+
edge.id_ && /* @__PURE__ */ jsx12(
|
|
3685
3953
|
"p",
|
|
3686
3954
|
{
|
|
3687
3955
|
className: "text-xs text-muted-foreground select-all cursor-pointer mt-1 mb-2",
|
|
@@ -3690,23 +3958,9 @@ function EdgeInfoCard({ edge }) {
|
|
|
3690
3958
|
children: edge.id_
|
|
3691
3959
|
}
|
|
3692
3960
|
),
|
|
3693
|
-
edge.properties_ && Object.keys(edge.properties_).length > 0 && /* @__PURE__ */
|
|
3694
|
-
/* @__PURE__ */
|
|
3695
|
-
/* @__PURE__ */
|
|
3696
|
-
/* @__PURE__ */ jsx11("p", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wide mb-1", children: "Properties" }),
|
|
3697
|
-
Object.entries(edge.properties_ || {}).map(([key, value]) => /* @__PURE__ */ jsxs10("li", { className: "mb-2 leading-tight", children: [
|
|
3698
|
-
/* @__PURE__ */ jsx11("p", { className: "text-xs text-muted-foreground uppercase tracking-wide", children: key }),
|
|
3699
|
-
/* @__PURE__ */ jsx11(
|
|
3700
|
-
"p",
|
|
3701
|
-
{
|
|
3702
|
-
className: "text-sm truncate max-w-[190px] cursor-pointer",
|
|
3703
|
-
onClick: () => copyTextToClipboard2(String(value)),
|
|
3704
|
-
title: "Click to copy value",
|
|
3705
|
-
children: String(value)
|
|
3706
|
-
}
|
|
3707
|
-
)
|
|
3708
|
-
] }, key))
|
|
3709
|
-
] }) })
|
|
3961
|
+
edge.properties_ && Object.keys(edge.properties_).length > 0 && /* @__PURE__ */ jsxs11(Collapsible2, { open: showProperties, onOpenChange: setShowProperties, children: [
|
|
3962
|
+
/* @__PURE__ */ jsx12(CollapsibleTrigger2, { asChild: true, children: /* @__PURE__ */ jsx12("button", { className: "text-xs cursor-pointer", children: showProperties ? "Hide" : "Show more" }) }),
|
|
3963
|
+
/* @__PURE__ */ jsx12(CollapsibleContent2, { children: /* @__PURE__ */ jsx12("div", { className: "mt-2", children: /* @__PURE__ */ jsx12(PropertyList2, { properties: edge.properties_ || {}, showHeader: true }) }) })
|
|
3710
3964
|
] })
|
|
3711
3965
|
]
|
|
3712
3966
|
}
|
|
@@ -3718,7 +3972,7 @@ var EdgeInfoCard_default = EdgeInfoCard;
|
|
|
3718
3972
|
import { Badge } from "@petrarca/sonnet-ui";
|
|
3719
3973
|
import { formatNumber, devLog as devLog11 } from "@petrarca/sonnet-core";
|
|
3720
3974
|
import { useMemo as useMemo4 } from "react";
|
|
3721
|
-
import { Fragment as Fragment3, jsx as
|
|
3975
|
+
import { Fragment as Fragment3, jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
3722
3976
|
function computeEdgeToNodeLabels(nodesById, edgesById) {
|
|
3723
3977
|
const mapping = {};
|
|
3724
3978
|
for (const edge of Object.values(edgesById)) {
|
|
@@ -3751,7 +4005,7 @@ function AllToggleBadge({
|
|
|
3751
4005
|
badgeKey
|
|
3752
4006
|
}) {
|
|
3753
4007
|
const bgColor = allDisabled ? colorPalette["faded"] : colorPalette["neutral"];
|
|
3754
|
-
return /* @__PURE__ */
|
|
4008
|
+
return /* @__PURE__ */ jsxs12(
|
|
3755
4009
|
Badge,
|
|
3756
4010
|
{
|
|
3757
4011
|
className: "cursor-pointer text-xs px-2.5 py-0.5",
|
|
@@ -3786,7 +4040,7 @@ function NodeLabelBadges({
|
|
|
3786
4040
|
colorPalette,
|
|
3787
4041
|
label
|
|
3788
4042
|
);
|
|
3789
|
-
return /* @__PURE__ */
|
|
4043
|
+
return /* @__PURE__ */ jsxs12(
|
|
3790
4044
|
Badge,
|
|
3791
4045
|
{
|
|
3792
4046
|
className: "cursor-pointer text-xs px-2.5 py-0.5",
|
|
@@ -3824,7 +4078,7 @@ function EdgeLabelBadges({
|
|
|
3824
4078
|
colorPalette,
|
|
3825
4079
|
"neutral"
|
|
3826
4080
|
);
|
|
3827
|
-
return /* @__PURE__ */
|
|
4081
|
+
return /* @__PURE__ */ jsxs12(
|
|
3828
4082
|
Badge,
|
|
3829
4083
|
{
|
|
3830
4084
|
className: "cursor-pointer text-xs px-2.5 py-0.5",
|
|
@@ -3901,12 +4155,12 @@ function GraphOverview({
|
|
|
3901
4155
|
toggleAllEdgeLabelsDisabled();
|
|
3902
4156
|
}
|
|
3903
4157
|
};
|
|
3904
|
-
return /* @__PURE__ */
|
|
3905
|
-
/* @__PURE__ */
|
|
3906
|
-
allLabels.length > 0 && /* @__PURE__ */
|
|
3907
|
-
/* @__PURE__ */
|
|
3908
|
-
/* @__PURE__ */
|
|
3909
|
-
/* @__PURE__ */
|
|
4158
|
+
return /* @__PURE__ */ jsxs12(Fragment3, { children: [
|
|
4159
|
+
/* @__PURE__ */ jsx13("p", { className: "mt-2 text-sm font-semibold", children: "Overview" }),
|
|
4160
|
+
allLabels.length > 0 && /* @__PURE__ */ jsxs12("div", { children: [
|
|
4161
|
+
/* @__PURE__ */ jsx13("p", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wide mb-2", children: "Node Labels" }),
|
|
4162
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex flex-col items-start gap-2", children: [
|
|
4163
|
+
/* @__PURE__ */ jsx13(
|
|
3910
4164
|
AllToggleBadge,
|
|
3911
4165
|
{
|
|
3912
4166
|
allDisabled: allLabelsDisabled,
|
|
@@ -3916,7 +4170,7 @@ function GraphOverview({
|
|
|
3916
4170
|
badgeKey: "all"
|
|
3917
4171
|
}
|
|
3918
4172
|
),
|
|
3919
|
-
/* @__PURE__ */
|
|
4173
|
+
/* @__PURE__ */ jsx13(
|
|
3920
4174
|
NodeLabelBadges,
|
|
3921
4175
|
{
|
|
3922
4176
|
labels: allLabels,
|
|
@@ -3929,10 +4183,10 @@ function GraphOverview({
|
|
|
3929
4183
|
)
|
|
3930
4184
|
] })
|
|
3931
4185
|
] }),
|
|
3932
|
-
allEdgeLabels.length > 0 && /* @__PURE__ */
|
|
3933
|
-
/* @__PURE__ */
|
|
3934
|
-
/* @__PURE__ */
|
|
3935
|
-
/* @__PURE__ */
|
|
4186
|
+
allEdgeLabels.length > 0 && /* @__PURE__ */ jsxs12("div", { children: [
|
|
4187
|
+
/* @__PURE__ */ jsx13("p", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wide mb-2", children: "Edge Types" }),
|
|
4188
|
+
/* @__PURE__ */ jsxs12("div", { className: "flex flex-col items-start gap-2", children: [
|
|
4189
|
+
/* @__PURE__ */ jsx13(
|
|
3936
4190
|
AllToggleBadge,
|
|
3937
4191
|
{
|
|
3938
4192
|
allDisabled: allEdgeLabelsDisabled,
|
|
@@ -3942,7 +4196,7 @@ function GraphOverview({
|
|
|
3942
4196
|
badgeKey: "edge-all"
|
|
3943
4197
|
}
|
|
3944
4198
|
),
|
|
3945
|
-
/* @__PURE__ */
|
|
4199
|
+
/* @__PURE__ */ jsx13(
|
|
3946
4200
|
EdgeLabelBadges,
|
|
3947
4201
|
{
|
|
3948
4202
|
labels: allEdgeLabels,
|
|
@@ -3968,16 +4222,16 @@ function Overview() {
|
|
|
3968
4222
|
);
|
|
3969
4223
|
}, [baseNormalized]);
|
|
3970
4224
|
if (stats && stats.values != null && stats.values > 0) {
|
|
3971
|
-
return /* @__PURE__ */
|
|
3972
|
-
/* @__PURE__ */
|
|
3973
|
-
/* @__PURE__ */
|
|
4225
|
+
return /* @__PURE__ */ jsxs12(Fragment3, { children: [
|
|
4226
|
+
/* @__PURE__ */ jsx13("p", { className: "mt-2 text-sm font-semibold", children: "Overview" }),
|
|
4227
|
+
/* @__PURE__ */ jsxs12("p", { className: "text-sm text-muted-foreground", children: [
|
|
3974
4228
|
formatNumber(stats.values),
|
|
3975
4229
|
" Values"
|
|
3976
4230
|
] })
|
|
3977
4231
|
] });
|
|
3978
4232
|
}
|
|
3979
4233
|
if (stats && stats.nodes > 0 && colorPalette) {
|
|
3980
|
-
return /* @__PURE__ */
|
|
4234
|
+
return /* @__PURE__ */ jsx13(
|
|
3981
4235
|
GraphOverview,
|
|
3982
4236
|
{
|
|
3983
4237
|
stats,
|
|
@@ -3994,7 +4248,7 @@ var Overview_default = Overview;
|
|
|
3994
4248
|
|
|
3995
4249
|
// src/components/ActionPanel/ActionPanel.tsx
|
|
3996
4250
|
import { useMemo as useMemo5 } from "react";
|
|
3997
|
-
import { jsx as
|
|
4251
|
+
import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
3998
4252
|
function ActionPanel({ actions }) {
|
|
3999
4253
|
const useSelection3 = useWorkspaceSelection();
|
|
4000
4254
|
const selectedNodeIds = useSelection3(
|
|
@@ -4010,18 +4264,18 @@ function ActionPanel({ actions }) {
|
|
|
4010
4264
|
const secondNode = selectedNodes?.[1];
|
|
4011
4265
|
const hasEdge = !!selectedEdge;
|
|
4012
4266
|
const showOverview = !firstNode && !hasEdge;
|
|
4013
|
-
return /* @__PURE__ */
|
|
4267
|
+
return /* @__PURE__ */ jsxs13(
|
|
4014
4268
|
Card5,
|
|
4015
4269
|
{
|
|
4016
4270
|
className: "h-full min-w-64 flex flex-col bg-card shadow-none p-4",
|
|
4017
4271
|
style: { maxHeight: "100%", overflow: "hidden" },
|
|
4018
4272
|
children: [
|
|
4019
|
-
actions && /* @__PURE__ */
|
|
4020
|
-
/* @__PURE__ */
|
|
4021
|
-
firstNode && /* @__PURE__ */
|
|
4022
|
-
hasEdge && selectedEdge && /* @__PURE__ */
|
|
4023
|
-
secondNode && /* @__PURE__ */
|
|
4024
|
-
showOverview && /* @__PURE__ */
|
|
4273
|
+
actions && /* @__PURE__ */ jsx14("div", { className: "flex-shrink-0 mb-2", children: actions }),
|
|
4274
|
+
/* @__PURE__ */ jsx14("div", { className: "flex-1 overflow-auto pr-1", children: /* @__PURE__ */ jsxs13("div", { className: "flex flex-col gap-3", children: [
|
|
4275
|
+
firstNode && /* @__PURE__ */ jsx14(NodeInfoCard_default, { node: firstNode }),
|
|
4276
|
+
hasEdge && selectedEdge && /* @__PURE__ */ jsx14(EdgeInfoCard_default, { edge: selectedEdge }),
|
|
4277
|
+
secondNode && /* @__PURE__ */ jsx14(NodeInfoCard_default, { node: secondNode }),
|
|
4278
|
+
showOverview && /* @__PURE__ */ jsx14(Overview_default, {})
|
|
4025
4279
|
] }) })
|
|
4026
4280
|
]
|
|
4027
4281
|
}
|
|
@@ -4030,10 +4284,10 @@ function ActionPanel({ actions }) {
|
|
|
4030
4284
|
var ActionPanel_default = ActionPanel;
|
|
4031
4285
|
|
|
4032
4286
|
// src/components/GraphA11yList/GraphA11yList.tsx
|
|
4033
|
-
import { useMemo as useMemo6, useRef as
|
|
4287
|
+
import { useMemo as useMemo6, useRef as useRef4 } from "react";
|
|
4034
4288
|
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
4035
4289
|
import { cn as cn2 } from "@petrarca/sonnet-core";
|
|
4036
|
-
import { jsx as
|
|
4290
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
4037
4291
|
var SR_ONLY = "absolute h-px w-px overflow-hidden whitespace-nowrap border-0 p-0 [clip:rect(0,0,0,0)] [clip-path:inset(50%)] -m-px";
|
|
4038
4292
|
function GraphA11yList({
|
|
4039
4293
|
visible = false,
|
|
@@ -4068,7 +4322,7 @@ function GraphA11yList({
|
|
|
4068
4322
|
}));
|
|
4069
4323
|
return [...nodeRows, ...edgeRows];
|
|
4070
4324
|
}, [live.nodes, live.edges]);
|
|
4071
|
-
const parentRef =
|
|
4325
|
+
const parentRef = useRef4(null);
|
|
4072
4326
|
const virtualizer = useVirtualizer({
|
|
4073
4327
|
count: rows.length,
|
|
4074
4328
|
getScrollElement: () => parentRef.current,
|
|
@@ -4085,18 +4339,18 @@ function GraphA11yList({
|
|
|
4085
4339
|
}
|
|
4086
4340
|
};
|
|
4087
4341
|
const isSelected = (row) => row.kind === "node" ? selectedNodeIds.includes(row.id) : selectedEdge?.id_ === row.edge.id_;
|
|
4088
|
-
return /* @__PURE__ */
|
|
4342
|
+
return /* @__PURE__ */ jsx15(
|
|
4089
4343
|
"div",
|
|
4090
4344
|
{
|
|
4091
4345
|
role: "listbox",
|
|
4092
4346
|
"aria-label": "Graph elements",
|
|
4093
4347
|
className: cn2(visible ? "rounded-md border" : SR_ONLY, className),
|
|
4094
|
-
children: /* @__PURE__ */
|
|
4348
|
+
children: /* @__PURE__ */ jsx15(
|
|
4095
4349
|
"div",
|
|
4096
4350
|
{
|
|
4097
4351
|
ref: parentRef,
|
|
4098
4352
|
style: { maxHeight: visible ? maxHeight : void 0, overflow: "auto" },
|
|
4099
|
-
children: /* @__PURE__ */
|
|
4353
|
+
children: /* @__PURE__ */ jsx15(
|
|
4100
4354
|
"div",
|
|
4101
4355
|
{
|
|
4102
4356
|
style: {
|
|
@@ -4108,7 +4362,7 @@ function GraphA11yList({
|
|
|
4108
4362
|
const row = rows[vi.index];
|
|
4109
4363
|
if (!row) return null;
|
|
4110
4364
|
const selected = isSelected(row);
|
|
4111
|
-
return /* @__PURE__ */
|
|
4365
|
+
return /* @__PURE__ */ jsx15(
|
|
4112
4366
|
"button",
|
|
4113
4367
|
{
|
|
4114
4368
|
type: "button",
|
|
@@ -4126,7 +4380,7 @@ function GraphA11yList({
|
|
|
4126
4380
|
height: `${vi.size}px`,
|
|
4127
4381
|
transform: `translateY(${vi.start}px)`
|
|
4128
4382
|
},
|
|
4129
|
-
children: /* @__PURE__ */
|
|
4383
|
+
children: /* @__PURE__ */ jsx15("span", { className: "truncate", children: row.label })
|
|
4130
4384
|
},
|
|
4131
4385
|
vi.key
|
|
4132
4386
|
);
|