modviz 0.1.2
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/README.md +261 -0
- package/dist/client/_shell.html +0 -0
- package/dist/client/android-chrome-192x192.png +0 -0
- package/dist/client/android-chrome-512x512.png +0 -0
- package/dist/client/apple-touch-icon.png +0 -0
- package/dist/client/assets/app-Sjrldkrg.css +2 -0
- package/dist/client/assets/button-aOWckyNs.js +1 -0
- package/dist/client/assets/check-C0EQe2S8.js +1 -0
- package/dist/client/assets/chevron-down-DrspihmT.js +1 -0
- package/dist/client/assets/chevron-right-DIJHr8AN.js +1 -0
- package/dist/client/assets/colors-CQoWjU5E.js +1 -0
- package/dist/client/assets/command-kkF7_wdz.js +45 -0
- package/dist/client/assets/compare-K6jVFsiI.js +1 -0
- package/dist/client/assets/compare-TOnoe1EP.js +2 -0
- package/dist/client/assets/configure-DnlSnhtN.js +1 -0
- package/dist/client/assets/explorer-C7NclVKg.js +2 -0
- package/dist/client/assets/explorer-Xu2X6XXF.js +1 -0
- package/dist/client/assets/external-link-B9eNA-li.js +1 -0
- package/dist/client/assets/flamegraph-CRVZSAlj.js +13 -0
- package/dist/client/assets/floating-ui.dom-DLIT5tPE.js +1 -0
- package/dist/client/assets/formatting-CiC0SYI8.js +1 -0
- package/dist/client/assets/graph-6Vr74V1k.js +2 -0
- package/dist/client/assets/graph-CVzypIGU.js +2 -0
- package/dist/client/assets/graph-command-menu-D2MoVT2B.js +4 -0
- package/dist/client/assets/graph-command-menu-VWiiW3qy.css +1 -0
- package/dist/client/assets/hierarchy-C8xxGb_u.js +2 -0
- package/dist/client/assets/hierarchy-iO7d4oSK.js +2 -0
- package/dist/client/assets/import-display-D-jRyyjM.js +5 -0
- package/dist/client/assets/imports-CPggnrs-.js +2 -0
- package/dist/client/assets/imports-CodbPyUJ.js +1 -0
- package/dist/client/assets/index-Dj_rhLdR.js +12 -0
- package/dist/client/assets/input-BCFMF0aR.js +1 -0
- package/dist/client/assets/jsx-runtime-DWSWI4JT.js +1 -0
- package/dist/client/assets/lazyRouteComponent-PTSyFp1J.js +1 -0
- package/dist/client/assets/loading-state-CyC_hrTF.js +1 -0
- package/dist/client/assets/modviz-data-BiRqoDI5.js +1 -0
- package/dist/client/assets/modviz-layout-Do93E-IB.js +1 -0
- package/dist/client/assets/modviz-sigma-Xl8qHaxK.js +312 -0
- package/dist/client/assets/portal-BgAm3V3j.js +1 -0
- package/dist/client/assets/routes-DBtN8hrZ.js +1 -0
- package/dist/client/assets/schemas-B4zfTepZ.js +39 -0
- package/dist/client/assets/search-BYHxNrYn.js +1 -0
- package/dist/client/assets/search-params-BaZRBvGI.js +1 -0
- package/dist/client/assets/setup-view-j1o0TuZz.js +1 -0
- package/dist/client/assets/summary-D703Zh3x.js +1 -0
- package/dist/client/assets/tooltip-B1VDU9HG.js +1 -0
- package/dist/client/assets/trace-B67CM5s2.js +2 -0
- package/dist/client/assets/trace-Bwwdw3AM.js +1 -0
- package/dist/client/assets/treemap-BZf2shzY.js +5 -0
- package/dist/client/assets/treemap-Csroy8Gy.js +2 -0
- package/dist/client/assets/utils-DkkZd0ys.js +1 -0
- package/dist/client/favicon-16x16.png +0 -0
- package/dist/client/favicon-32x32.png +0 -0
- package/dist/client/favicon.ico +0 -0
- package/dist/client/favicon.png +0 -0
- package/dist/client/site.webmanifest +19 -0
- package/dist/mod/cli-options.js +225 -0
- package/dist/mod/cli.js +519 -0
- package/dist/mod/index.js +3 -0
- package/dist/mod/llm-analysis.js +29 -0
- package/dist/mod/llm-output.js +742 -0
- package/dist/mod/module-graph-plugins.js +60 -0
- package/dist/mod/production-server.js +103 -0
- package/dist/mod/runtime-host.js +217 -0
- package/dist/mod/snapshot-history.js +73 -0
- package/dist/mod/types.js +3 -0
- package/dist/server/assets/__23tanstack-start-plugin-adapters-3QxJs4a0.js +5 -0
- package/dist/server/assets/_tanstack-start-manifest_v-DMytuIue.js +188 -0
- package/dist/server/assets/button-Bqnnid5i.js +41 -0
- package/dist/server/assets/colors-DhAxrYua.js +100 -0
- package/dist/server/assets/command-SdxShIbL.js +138 -0
- package/dist/server/assets/compare-BFMiiUsB.js +562 -0
- package/dist/server/assets/compare-CpOqTpYu.js +10 -0
- package/dist/server/assets/configure-Bvd45DTI.js +288 -0
- package/dist/server/assets/explorer-C7dODpSv.js +379 -0
- package/dist/server/assets/explorer-CpSb0JTa.js +20 -0
- package/dist/server/assets/flamegraph-CdW-VG6I.js +198 -0
- package/dist/server/assets/formatting-iDlL4tA-.js +4 -0
- package/dist/server/assets/graph-C1G9H5O4.js +438 -0
- package/dist/server/assets/graph-DAGFGioS.js +45 -0
- package/dist/server/assets/graph-command-menu-BV5GtOWx.js +249 -0
- package/dist/server/assets/hierarchy-B4K-Zfn9.js +16 -0
- package/dist/server/assets/hierarchy-BGpWSG-f.js +104 -0
- package/dist/server/assets/import-display-BVIOWcsm.js +124 -0
- package/dist/server/assets/imports-B6JBDl_h.js +379 -0
- package/dist/server/assets/imports-BGe5tZJT.js +28 -0
- package/dist/server/assets/input-C5r-hBix.js +19 -0
- package/dist/server/assets/loading-state-CrvCWTtw.js +23 -0
- package/dist/server/assets/modviz-data-CUyTorv0.js +197 -0
- package/dist/server/assets/modviz-layout-BAH2ogse.js +253 -0
- package/dist/server/assets/modviz-server-DoMlAyFW.js +195 -0
- package/dist/server/assets/modviz-sigma-XYxARWqd.js +1441 -0
- package/dist/server/assets/rolldown-runtime-rSIU-vHC.js +13 -0
- package/dist/server/assets/router-DYJ-zDbU.js +353 -0
- package/dist/server/assets/routes-DInCacpY.js +244 -0
- package/dist/server/assets/search-params-BNApPgkX.js +26 -0
- package/dist/server/assets/setup-view-DjI49Iqr.js +91 -0
- package/dist/server/assets/start-Ba3KII43.js +4 -0
- package/dist/server/assets/summary-z3lXkLCQ.js +208 -0
- package/dist/server/assets/tooltip-Ck0DDfF7.js +24 -0
- package/dist/server/assets/trace-ColKOf9g.js +16 -0
- package/dist/server/assets/trace-eVs-hIZO.js +578 -0
- package/dist/server/assets/treemap-BbZ9M4GF.js +17 -0
- package/dist/server/assets/treemap-CrgWFoCF.js +912 -0
- package/dist/server/assets/utils-BQZm0uva.js +8 -0
- package/dist/server/server.js +5259 -0
- package/dist/shared/modviz-compare.js +120 -0
- package/dist/shared/modviz-trace.js +244 -0
- package/package.json +135 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-rSIU-vHC.js";
|
|
2
|
+
import { useEffect, useRef } from "react";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { Flamegraph, normalizeTreeNode } from "nanovis";
|
|
5
|
+
//#region src/components/graph/map-to-flamegraph.ts
|
|
6
|
+
function convertToNanovisHierarchyData(output, entryNodeId, options = {}) {
|
|
7
|
+
const maxDepth = options.maxDepth ?? 6;
|
|
8
|
+
const maxChildren = options.maxChildren ?? 24;
|
|
9
|
+
const includeExternal = options.includeExternal ?? true;
|
|
10
|
+
const entryNode = output.nodes.find((node) => node.path === entryNodeId);
|
|
11
|
+
const nodeMap = /* @__PURE__ */ new Map();
|
|
12
|
+
output.nodes.forEach((node) => {
|
|
13
|
+
nodeMap.set(node.path, {
|
|
14
|
+
id: node.path,
|
|
15
|
+
text: node.path.split("/").slice(-2).join("/"),
|
|
16
|
+
subtext: node.package?.name,
|
|
17
|
+
sizeSelf: node.importees.length + 1,
|
|
18
|
+
children: [],
|
|
19
|
+
meta: {
|
|
20
|
+
path: node.path,
|
|
21
|
+
type: node.type,
|
|
22
|
+
package: node.package?.name,
|
|
23
|
+
importees: node.importees,
|
|
24
|
+
imports: node.imports.length,
|
|
25
|
+
exports: node.exports.length,
|
|
26
|
+
originalNode: node
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
if (!entryNode) return {
|
|
31
|
+
id: "module-graph-root",
|
|
32
|
+
text: "Module Graph",
|
|
33
|
+
subtext: "No entrypoints found",
|
|
34
|
+
sizeSelf: 1,
|
|
35
|
+
children: [],
|
|
36
|
+
meta: {
|
|
37
|
+
path: "",
|
|
38
|
+
importees: [],
|
|
39
|
+
imports: 0,
|
|
40
|
+
exports: 0,
|
|
41
|
+
originalNode: {}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const rootNode = Object.assign({}, nodeMap.get(entryNodeId), { children: [] });
|
|
45
|
+
const allVisited = /* @__PURE__ */ new Set();
|
|
46
|
+
const stack = [{
|
|
47
|
+
depth: 0,
|
|
48
|
+
nodePath: entryNodeId,
|
|
49
|
+
parent: rootNode,
|
|
50
|
+
visited: new Set([entryNodeId])
|
|
51
|
+
}];
|
|
52
|
+
let stackSize = 0;
|
|
53
|
+
const childrenMap = /* @__PURE__ */ new Map();
|
|
54
|
+
while (stack.length > 0) {
|
|
55
|
+
stackSize++;
|
|
56
|
+
const { depth, nodePath, parent, visited } = stack.pop();
|
|
57
|
+
const wasAlreadyVisited = allVisited.has(nodePath);
|
|
58
|
+
allVisited.add(nodePath);
|
|
59
|
+
const node = nodeMap.get(nodePath);
|
|
60
|
+
if (!node) continue;
|
|
61
|
+
const currentTreeNode = Object.assign({}, node, { children: wasAlreadyVisited ? childrenMap.get(nodePath) : [] });
|
|
62
|
+
!wasAlreadyVisited && childrenMap.set(nodePath, currentTreeNode.children);
|
|
63
|
+
if (parent.children) parent.children.push(currentTreeNode);
|
|
64
|
+
if (wasAlreadyVisited) continue;
|
|
65
|
+
if (depth >= maxDepth) continue;
|
|
66
|
+
const importees = currentTreeNode.meta.importees.filter((importee) => includeExternal || !importee.includes("node_modules")).sort((left, right) => {
|
|
67
|
+
const leftNode = nodeMap.get(left);
|
|
68
|
+
return (nodeMap.get(right)?.meta.importees.length ?? 0) - (leftNode?.meta.importees.length ?? 0);
|
|
69
|
+
});
|
|
70
|
+
const visibleImportees = importees.slice(0, maxChildren);
|
|
71
|
+
visibleImportees.forEach((importee) => {
|
|
72
|
+
if (visited.has(importee)) {
|
|
73
|
+
const importeeNode = nodeMap.get(importee);
|
|
74
|
+
if (!importeeNode) return;
|
|
75
|
+
const importeeTreeNode = Object.assign({}, importeeNode, { children: [] });
|
|
76
|
+
currentTreeNode.children.push(importeeTreeNode);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
visited.add(importee);
|
|
80
|
+
stack.push({
|
|
81
|
+
depth: depth + 1,
|
|
82
|
+
nodePath: importee,
|
|
83
|
+
parent: currentTreeNode,
|
|
84
|
+
visited: new Set([...visited, importee])
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
if (importees.length > visibleImportees.length) currentTreeNode.children.push({
|
|
88
|
+
id: `${nodePath}#truncated`,
|
|
89
|
+
text: `… ${importees.length - visibleImportees.length} more`,
|
|
90
|
+
subtext: "pruned",
|
|
91
|
+
sizeSelf: 1,
|
|
92
|
+
children: [],
|
|
93
|
+
meta: {
|
|
94
|
+
path: `${nodePath}#truncated`,
|
|
95
|
+
importees: [],
|
|
96
|
+
imports: 0,
|
|
97
|
+
exports: 0,
|
|
98
|
+
originalNode: currentTreeNode.meta.originalNode
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
return rootNode;
|
|
103
|
+
}
|
|
104
|
+
//#endregion
|
|
105
|
+
//#region src/components/graph/flamegraph.tsx
|
|
106
|
+
var flamegraph_exports = /* @__PURE__ */ __exportAll({ Flamegraph: () => Flamegraph$1 });
|
|
107
|
+
var Flamegraph$1 = (props) => {
|
|
108
|
+
const containerRef = useRef(null);
|
|
109
|
+
const flamegraphRef = useRef(null);
|
|
110
|
+
const tooltipRef = useRef(null);
|
|
111
|
+
useEffect(() => {
|
|
112
|
+
if (!containerRef.current) return;
|
|
113
|
+
const entryNodeId = props.entryNodeId ?? props.output.metadata.entrypoints[0];
|
|
114
|
+
const flamegraph = new Flamegraph(normalizeTreeNode(convertToNanovisHierarchyData(props.output, entryNodeId, props.options)));
|
|
115
|
+
flamegraphRef.current = flamegraph;
|
|
116
|
+
const unsubSelect = flamegraph.events.on("select", (node) => {
|
|
117
|
+
console.log("Selected node:", {
|
|
118
|
+
text: node?.text,
|
|
119
|
+
subtext: node?.subtext,
|
|
120
|
+
meta: node?.meta
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
const unsubHover = flamegraph.events.on("hover", (node, event) => {
|
|
124
|
+
if (!tooltipRef.current) return;
|
|
125
|
+
if (node && node.meta) {
|
|
126
|
+
tooltipRef.current.style.display = "block";
|
|
127
|
+
if (event) {
|
|
128
|
+
tooltipRef.current.style.left = `${event.clientX + 10}px`;
|
|
129
|
+
tooltipRef.current.style.top = `${event.clientY - 10}px`;
|
|
130
|
+
}
|
|
131
|
+
tooltipRef.current.innerHTML = `
|
|
132
|
+
<div style="font-weight: bold; margin-bottom: 8px; color: #4CAF50;">
|
|
133
|
+
${node.text || "root"}
|
|
134
|
+
</div>
|
|
135
|
+
${node.meta.path ? `<div style="color: #ddd; font-size: 10px; margin-bottom: 4px;">${node.meta.path}</div>` : ""}
|
|
136
|
+
<div style="margin-bottom: 4px;">
|
|
137
|
+
Size: <span style="color: #FFD700;">${node.sizeSelf || 0}</span>
|
|
138
|
+
</div>
|
|
139
|
+
${node.meta.type ? `<div style="margin-bottom: 4px;">Type: <span style="color: #87CEEB;">${node.meta.type}</span></div>` : ""}
|
|
140
|
+
${node.meta.package ? `<div style="margin-bottom: 4px;">Package: <span style="color: #DDA0DD;">${node.meta.package}</span></div>` : ""}
|
|
141
|
+
${node.meta.imports !== void 0 ? `<div style="margin-bottom: 4px;">Imports: <span style="color: #F0E68C;">${node.meta.imports}</span></div>` : ""}
|
|
142
|
+
${node.meta.exports !== void 0 ? `<div>Exports: <span style="color: #F0E68C;">${node.meta.exports}</span></div>` : ""}
|
|
143
|
+
`;
|
|
144
|
+
} else tooltipRef.current.style.display = "none";
|
|
145
|
+
});
|
|
146
|
+
containerRef.current.innerHTML = "";
|
|
147
|
+
containerRef.current.appendChild(flamegraph.el);
|
|
148
|
+
return () => {
|
|
149
|
+
unsubSelect();
|
|
150
|
+
unsubHover();
|
|
151
|
+
if (flamegraphRef.current) flamegraphRef.current = null;
|
|
152
|
+
};
|
|
153
|
+
}, [
|
|
154
|
+
props.entryNodeId,
|
|
155
|
+
props.options,
|
|
156
|
+
props.output
|
|
157
|
+
]);
|
|
158
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
159
|
+
className: "relative w-full h-full min-h-0 flex flex-col",
|
|
160
|
+
children: [
|
|
161
|
+
/* @__PURE__ */ jsx("div", {
|
|
162
|
+
ref: containerRef,
|
|
163
|
+
className: "flex-1 min-h-0",
|
|
164
|
+
style: { minHeight: "400px" }
|
|
165
|
+
}),
|
|
166
|
+
/* @__PURE__ */ jsx("div", {
|
|
167
|
+
ref: tooltipRef,
|
|
168
|
+
style: {
|
|
169
|
+
position: "fixed",
|
|
170
|
+
background: "rgba(0, 0, 0, 0.9)",
|
|
171
|
+
color: "white",
|
|
172
|
+
padding: "12px",
|
|
173
|
+
borderRadius: "6px",
|
|
174
|
+
fontSize: "12px",
|
|
175
|
+
fontFamily: "monospace",
|
|
176
|
+
maxWidth: "300px",
|
|
177
|
+
boxShadow: "0 4px 8px rgba(0,0,0,0.3)",
|
|
178
|
+
pointerEvents: "none",
|
|
179
|
+
zIndex: 1e3,
|
|
180
|
+
display: "none"
|
|
181
|
+
}
|
|
182
|
+
}),
|
|
183
|
+
/* @__PURE__ */ jsxs("div", {
|
|
184
|
+
className: "absolute bottom-4 left-4 bg-black bg-opacity-70 text-white p-3 rounded text-xs font-mono z-10",
|
|
185
|
+
children: [
|
|
186
|
+
/* @__PURE__ */ jsx("div", {
|
|
187
|
+
className: "font-bold mb-2",
|
|
188
|
+
children: "Module Graph Flamegraph"
|
|
189
|
+
}),
|
|
190
|
+
/* @__PURE__ */ jsx("div", { children: "Click: Select node" }),
|
|
191
|
+
/* @__PURE__ */ jsx("div", { children: "Hover: View details" })
|
|
192
|
+
]
|
|
193
|
+
})
|
|
194
|
+
]
|
|
195
|
+
});
|
|
196
|
+
};
|
|
197
|
+
//#endregion
|
|
198
|
+
export { flamegraph_exports as n, Flamegraph$1 as t };
|
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
import { l as isNodeDetailsOpenAtom, o as currentNodeIdAtom, s as highlightedNodeIdAtom, t as GraphCommandMenu, u as selectedNodeIdsAtom } from "./graph-command-menu-BV5GtOWx.js";
|
|
2
|
+
import { t as Button } from "./button-Bqnnid5i.js";
|
|
3
|
+
import { t as Input } from "./input-C5r-hBix.js";
|
|
4
|
+
import { d as getWorkspacePackageNames, f as isModvizBundleReady, l as getNodeGroupingLabel, m as useModvizBundle, o as filterNodesByScope } from "./modviz-data-CUyTorv0.js";
|
|
5
|
+
import { t as LoadingState } from "./loading-state-CrvCWTtw.js";
|
|
6
|
+
import { n as getDefaultGraphLayoutSettings, t as Route$1 } from "./graph-DAGFGioS.js";
|
|
7
|
+
import { t as ModvizLayout } from "./modviz-layout-BAH2ogse.js";
|
|
8
|
+
import { t as SetupView } from "./setup-view-DjI49Iqr.js";
|
|
9
|
+
import { Suspense, lazy, useEffect, useMemo, useState } from "react";
|
|
10
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
+
import { Eye, RotateCcw, Settings2, X } from "lucide-react";
|
|
12
|
+
import { Portal } from "@ark-ui/react/portal";
|
|
13
|
+
import { useAtom } from "@xstate/store/react";
|
|
14
|
+
import { FloatingPanel } from "@ark-ui/react/floating-panel";
|
|
15
|
+
//#region src/components/graph/graph-settings-panel.tsx
|
|
16
|
+
var areGraphSettingsEqual = (left, right) => {
|
|
17
|
+
return left.iterations === right.iterations && left.gravity === right.gravity && left.scalingRatio === right.scalingRatio && left.strongGravityMode === right.strongGravityMode && left.linLogMode === right.linLogMode && left.adjustSizes === right.adjustSizes && left.outboundAttractionDistribution === right.outboundAttractionDistribution && left.hideClusterLabels === right.hideClusterLabels && left.nodeSizeScale === right.nodeSizeScale;
|
|
18
|
+
};
|
|
19
|
+
function NumberField(props) {
|
|
20
|
+
return /* @__PURE__ */ jsxs("label", {
|
|
21
|
+
className: "space-y-2 text-sm text-slate-700 dark:text-slate-200",
|
|
22
|
+
children: [
|
|
23
|
+
/* @__PURE__ */ jsxs("span", {
|
|
24
|
+
className: "flex items-center justify-between gap-3 font-medium",
|
|
25
|
+
children: [/* @__PURE__ */ jsx("span", { children: props.label }), /* @__PURE__ */ jsx("span", {
|
|
26
|
+
className: "text-xs text-slate-500 dark:text-slate-400",
|
|
27
|
+
children: props.value
|
|
28
|
+
})]
|
|
29
|
+
}),
|
|
30
|
+
/* @__PURE__ */ jsx(Input, {
|
|
31
|
+
type: "number",
|
|
32
|
+
value: String(props.value),
|
|
33
|
+
min: props.min,
|
|
34
|
+
max: props.max,
|
|
35
|
+
step: props.step,
|
|
36
|
+
onChange: (event) => props.onChange(Number(event.currentTarget.value))
|
|
37
|
+
}),
|
|
38
|
+
/* @__PURE__ */ jsx("p", {
|
|
39
|
+
className: "text-xs leading-5 text-slate-500 dark:text-slate-400",
|
|
40
|
+
children: props.help
|
|
41
|
+
})
|
|
42
|
+
]
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
function ToggleField(props) {
|
|
46
|
+
return /* @__PURE__ */ jsxs("label", {
|
|
47
|
+
className: "flex items-start gap-3 rounded-2xl border border-slate-200/70 bg-slate-50/80 p-3 dark:border-slate-800 dark:bg-slate-900/70",
|
|
48
|
+
children: [/* @__PURE__ */ jsx("input", {
|
|
49
|
+
type: "checkbox",
|
|
50
|
+
className: "mt-1 size-4 rounded border-slate-300",
|
|
51
|
+
checked: props.checked,
|
|
52
|
+
onChange: (event) => props.onChange(event.currentTarget.checked)
|
|
53
|
+
}), /* @__PURE__ */ jsxs("span", { children: [/* @__PURE__ */ jsx("span", {
|
|
54
|
+
className: "block text-sm font-medium text-slate-800 dark:text-slate-100",
|
|
55
|
+
children: props.label
|
|
56
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
57
|
+
className: "mt-1 block text-xs leading-5 text-slate-500 dark:text-slate-400",
|
|
58
|
+
children: props.help
|
|
59
|
+
})] })]
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
function GraphSettingsPanel(props) {
|
|
63
|
+
if (!props.open) return null;
|
|
64
|
+
return /* @__PURE__ */ jsx(GraphSettingsPanelContent, { ...props }, JSON.stringify(props.settings));
|
|
65
|
+
}
|
|
66
|
+
function GraphSettingsPanelContent(props) {
|
|
67
|
+
const [draftSettings, setDraftSettings] = useState(props.settings);
|
|
68
|
+
const hasChanges = useMemo(() => !areGraphSettingsEqual(draftSettings, props.settings), [draftSettings, props.settings]);
|
|
69
|
+
const updateSetting = (key, value) => {
|
|
70
|
+
setDraftSettings({
|
|
71
|
+
...draftSettings,
|
|
72
|
+
[key]: value
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
const applyChanges = () => {
|
|
76
|
+
if (!hasChanges) return;
|
|
77
|
+
props.onSettingsChange(draftSettings);
|
|
78
|
+
};
|
|
79
|
+
const resetSettings = () => {
|
|
80
|
+
setDraftSettings(props.onReset());
|
|
81
|
+
};
|
|
82
|
+
return /* @__PURE__ */ jsx(FloatingPanel.Root, {
|
|
83
|
+
open: true,
|
|
84
|
+
defaultSize: {
|
|
85
|
+
width: 420,
|
|
86
|
+
height: 640
|
|
87
|
+
},
|
|
88
|
+
minSize: {
|
|
89
|
+
width: 360,
|
|
90
|
+
height: 520
|
|
91
|
+
},
|
|
92
|
+
persistRect: true,
|
|
93
|
+
lazyMount: true,
|
|
94
|
+
children: /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(FloatingPanel.Positioner, {
|
|
95
|
+
className: "z-50",
|
|
96
|
+
children: /* @__PURE__ */ jsxs(FloatingPanel.Content, {
|
|
97
|
+
className: "flex h-full flex-col overflow-hidden rounded-[24px] border border-slate-200 bg-white shadow-[0_24px_80px_-36px_rgba(15,23,42,0.75)] dark:border-slate-800 dark:bg-slate-950",
|
|
98
|
+
children: [/* @__PURE__ */ jsx(FloatingPanel.DragTrigger, { children: /* @__PURE__ */ jsxs(FloatingPanel.Header, {
|
|
99
|
+
className: "flex cursor-move items-center justify-between border-b border-slate-200 bg-slate-50/90 px-4 py-3 dark:border-slate-800 dark:bg-slate-900/80",
|
|
100
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
101
|
+
className: "flex items-center gap-2",
|
|
102
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
103
|
+
className: "rounded-xl bg-sky-100 p-2 text-sky-700 dark:bg-sky-500/15 dark:text-sky-300",
|
|
104
|
+
children: /* @__PURE__ */ jsx(Settings2, { className: "size-4" })
|
|
105
|
+
}), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(FloatingPanel.Title, {
|
|
106
|
+
className: "text-sm font-semibold text-slate-900 dark:text-slate-100",
|
|
107
|
+
children: "Graph settings"
|
|
108
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
109
|
+
className: "text-xs text-slate-500 dark:text-slate-400",
|
|
110
|
+
children: "Layout controls for cluster spacing, gravity, and legibility."
|
|
111
|
+
})] })]
|
|
112
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
113
|
+
className: "flex items-center gap-2",
|
|
114
|
+
children: [
|
|
115
|
+
/* @__PURE__ */ jsxs(Button, {
|
|
116
|
+
variant: "outline",
|
|
117
|
+
size: "sm",
|
|
118
|
+
onClick: resetSettings,
|
|
119
|
+
children: [/* @__PURE__ */ jsx(RotateCcw, { className: "size-4" }), "Reset"]
|
|
120
|
+
}),
|
|
121
|
+
/* @__PURE__ */ jsx(Button, {
|
|
122
|
+
size: "sm",
|
|
123
|
+
onClick: applyChanges,
|
|
124
|
+
disabled: !hasChanges,
|
|
125
|
+
children: "Apply"
|
|
126
|
+
}),
|
|
127
|
+
/* @__PURE__ */ jsx(Button, {
|
|
128
|
+
variant: "ghost",
|
|
129
|
+
size: "icon",
|
|
130
|
+
onClick: () => props.onOpenChange(false),
|
|
131
|
+
children: /* @__PURE__ */ jsx(X, { className: "size-4" })
|
|
132
|
+
})
|
|
133
|
+
]
|
|
134
|
+
})]
|
|
135
|
+
}) }), /* @__PURE__ */ jsx(FloatingPanel.Body, {
|
|
136
|
+
className: "flex-1 overflow-y-auto px-4 py-4",
|
|
137
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
138
|
+
className: "space-y-5",
|
|
139
|
+
children: [
|
|
140
|
+
/* @__PURE__ */ jsx(NumberField, {
|
|
141
|
+
label: "Iterations",
|
|
142
|
+
value: draftSettings.iterations,
|
|
143
|
+
min: 10,
|
|
144
|
+
max: 500,
|
|
145
|
+
step: 10,
|
|
146
|
+
onChange: (value) => updateSetting("iterations", Math.max(10, value || 10)),
|
|
147
|
+
help: "Higher values let ForceAtlas2 settle longer before the graph renders."
|
|
148
|
+
}),
|
|
149
|
+
/* @__PURE__ */ jsx(NumberField, {
|
|
150
|
+
label: "Gravity",
|
|
151
|
+
value: draftSettings.gravity,
|
|
152
|
+
min: 0,
|
|
153
|
+
max: 1500,
|
|
154
|
+
step: 1,
|
|
155
|
+
onChange: (value) => updateSetting("gravity", Math.max(0, value || 0)),
|
|
156
|
+
help: "Pulls nodes back toward the center. Lower gravity spreads clusters out more."
|
|
157
|
+
}),
|
|
158
|
+
/* @__PURE__ */ jsx(NumberField, {
|
|
159
|
+
label: "Scaling ratio",
|
|
160
|
+
value: draftSettings.scalingRatio,
|
|
161
|
+
min: 1,
|
|
162
|
+
max: 500,
|
|
163
|
+
step: 1,
|
|
164
|
+
onChange: (value) => updateSetting("scalingRatio", Math.max(1, value || 1)),
|
|
165
|
+
help: "Primary spacing control. Higher values increase separation between nodes and clusters."
|
|
166
|
+
}),
|
|
167
|
+
/* @__PURE__ */ jsx(NumberField, {
|
|
168
|
+
label: "Node size scale",
|
|
169
|
+
value: draftSettings.nodeSizeScale,
|
|
170
|
+
min: .5,
|
|
171
|
+
max: 4,
|
|
172
|
+
step: .1,
|
|
173
|
+
onChange: (value) => updateSetting("nodeSizeScale", Math.max(.5, Number(value.toFixed(1)) || 1)),
|
|
174
|
+
help: "Amplifies the node size derived from inbound edge count."
|
|
175
|
+
}),
|
|
176
|
+
/* @__PURE__ */ jsxs("div", {
|
|
177
|
+
className: "grid gap-3",
|
|
178
|
+
children: [
|
|
179
|
+
/* @__PURE__ */ jsx(ToggleField, {
|
|
180
|
+
label: "Strong gravity mode",
|
|
181
|
+
checked: draftSettings.strongGravityMode,
|
|
182
|
+
onChange: (checked) => updateSetting("strongGravityMode", checked),
|
|
183
|
+
help: "Keeps distant nodes from drifting too far out of frame."
|
|
184
|
+
}),
|
|
185
|
+
/* @__PURE__ */ jsx(ToggleField, {
|
|
186
|
+
label: "LinLog mode",
|
|
187
|
+
checked: draftSettings.linLogMode,
|
|
188
|
+
onChange: (checked) => updateSetting("linLogMode", checked),
|
|
189
|
+
help: "Often improves community separation in clustered graphs."
|
|
190
|
+
}),
|
|
191
|
+
/* @__PURE__ */ jsx(ToggleField, {
|
|
192
|
+
label: "Adjust sizes",
|
|
193
|
+
checked: draftSettings.adjustSizes,
|
|
194
|
+
onChange: (checked) => updateSetting("adjustSizes", checked),
|
|
195
|
+
help: "Uses node size during layout to reduce collisions."
|
|
196
|
+
}),
|
|
197
|
+
/* @__PURE__ */ jsx(ToggleField, {
|
|
198
|
+
label: "Outbound attraction distribution",
|
|
199
|
+
checked: draftSettings.outboundAttractionDistribution,
|
|
200
|
+
onChange: (checked) => updateSetting("outboundAttractionDistribution", checked),
|
|
201
|
+
help: "Balances attraction when hubs create too much pull."
|
|
202
|
+
}),
|
|
203
|
+
/* @__PURE__ */ jsx(ToggleField, {
|
|
204
|
+
label: "Hide cluster labels",
|
|
205
|
+
checked: draftSettings.hideClusterLabels,
|
|
206
|
+
onChange: (checked) => updateSetting("hideClusterLabels", checked),
|
|
207
|
+
help: "Useful when labels cover dense areas during exploration."
|
|
208
|
+
})
|
|
209
|
+
]
|
|
210
|
+
})
|
|
211
|
+
]
|
|
212
|
+
})
|
|
213
|
+
})]
|
|
214
|
+
})
|
|
215
|
+
}) })
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
//#endregion
|
|
219
|
+
//#region src/routes/graph.tsx?tsr-split=component
|
|
220
|
+
var Sigma = lazy(() => import("./modviz-sigma-XYxARWqd.js").then((module) => ({ default: module.ModvizSigma })));
|
|
221
|
+
function GraphRoute() {
|
|
222
|
+
const bundle = useModvizBundle();
|
|
223
|
+
const search = Route$1.useSearch();
|
|
224
|
+
const navigate = Route$1.useNavigate();
|
|
225
|
+
const [settingsOpen, setSettingsOpen] = useState(false);
|
|
226
|
+
const [refreshNonce, setRefreshNonce] = useState(0);
|
|
227
|
+
const currentNodeId = useAtom(currentNodeIdAtom);
|
|
228
|
+
const isNodeDetailsOpen = useAtom(isNodeDetailsOpenAtom);
|
|
229
|
+
const selectedNodeIds = useAtom(selectedNodeIdsAtom);
|
|
230
|
+
if (!isModvizBundleReady(bundle)) return /* @__PURE__ */ jsx(ModvizLayout, {
|
|
231
|
+
title: "Bubble Graph",
|
|
232
|
+
description: "Force-directed cluster view for spatial exploration.",
|
|
233
|
+
children: /* @__PURE__ */ jsx(SetupView, { bundle })
|
|
234
|
+
});
|
|
235
|
+
const workspacePackageNames = useMemo(() => getWorkspacePackageNames(bundle.graph), [bundle.graph]);
|
|
236
|
+
const defaultLayoutSettings = useMemo(() => getDefaultGraphLayoutSettings(bundle.graph.nodes.length), [bundle.graph.nodes.length]);
|
|
237
|
+
const layoutSettings = useMemo(() => ({
|
|
238
|
+
adjustSizes: search.adjustSizes,
|
|
239
|
+
gravity: search.gravity,
|
|
240
|
+
hideClusterLabels: search.hideClusterLabels,
|
|
241
|
+
iterations: search.iterations,
|
|
242
|
+
linLogMode: search.linLogMode,
|
|
243
|
+
nodeSizeScale: search.nodeSizeScale,
|
|
244
|
+
outboundAttractionDistribution: search.outboundAttractionDistribution,
|
|
245
|
+
scalingRatio: search.scalingRatio,
|
|
246
|
+
strongGravityMode: search.strongGravityMode
|
|
247
|
+
}), [search]);
|
|
248
|
+
const scope = search.scope;
|
|
249
|
+
const externalGrouping = search.externalGrouping;
|
|
250
|
+
const filteredByScope = useMemo(() => filterNodesByScope(bundle.graph.nodes, workspacePackageNames, scope), [
|
|
251
|
+
bundle.graph.nodes,
|
|
252
|
+
scope,
|
|
253
|
+
workspacePackageNames
|
|
254
|
+
]);
|
|
255
|
+
const filteredNodes = useMemo(() => {
|
|
256
|
+
if (!search.cluster) return filteredByScope;
|
|
257
|
+
return filteredByScope.filter((node) => getNodeGroupingLabel(node, workspacePackageNames, externalGrouping) === search.cluster);
|
|
258
|
+
}, [
|
|
259
|
+
externalGrouping,
|
|
260
|
+
filteredByScope,
|
|
261
|
+
search.cluster,
|
|
262
|
+
workspacePackageNames
|
|
263
|
+
]);
|
|
264
|
+
const sigmaKey = useMemo(() => JSON.stringify({
|
|
265
|
+
cluster: search.cluster,
|
|
266
|
+
externalGrouping,
|
|
267
|
+
layoutSettings,
|
|
268
|
+
refreshNonce,
|
|
269
|
+
scope
|
|
270
|
+
}), [
|
|
271
|
+
externalGrouping,
|
|
272
|
+
layoutSettings,
|
|
273
|
+
refreshNonce,
|
|
274
|
+
scope,
|
|
275
|
+
search.cluster
|
|
276
|
+
]);
|
|
277
|
+
const updateSearch = (patch) => navigate({
|
|
278
|
+
replace: true,
|
|
279
|
+
search: (previous) => ({
|
|
280
|
+
...previous,
|
|
281
|
+
...patch
|
|
282
|
+
})
|
|
283
|
+
});
|
|
284
|
+
const setFocusedNode = (nodePath) => {
|
|
285
|
+
highlightedNodeIdAtom.set(nodePath);
|
|
286
|
+
currentNodeIdAtom.set(nodePath);
|
|
287
|
+
selectedNodeIdsAtom.set((prev) => nodePath ? prev.includes(nodePath) ? prev.filter((id) => id !== nodePath) : [...prev, nodePath] : []);
|
|
288
|
+
};
|
|
289
|
+
useEffect(() => {
|
|
290
|
+
if (!search.focus) return;
|
|
291
|
+
setFocusedNode(search.focus);
|
|
292
|
+
}, [search.focus]);
|
|
293
|
+
return /* @__PURE__ */ jsxs(ModvizLayout, {
|
|
294
|
+
title: "Bubble Graph",
|
|
295
|
+
description: "Force-directed cluster view for spatial exploration. Open this only when you need the full graph canvas, then tune spacing and gravity from the floating settings panel.",
|
|
296
|
+
actions: /* @__PURE__ */ jsxs(Button, {
|
|
297
|
+
variant: "outline",
|
|
298
|
+
onClick: () => setSettingsOpen(true),
|
|
299
|
+
children: [/* @__PURE__ */ jsx(Settings2, { className: "size-4" }), "Layout settings"]
|
|
300
|
+
}),
|
|
301
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
302
|
+
className: "flex h-[calc(100vh-14rem)] min-h-[680px] flex-col gap-4",
|
|
303
|
+
children: [
|
|
304
|
+
/* @__PURE__ */ jsxs("section", {
|
|
305
|
+
className: "flex flex-wrap items-center gap-2 rounded-[24px] border border-slate-200/70 bg-white/90 p-4 shadow-[0_16px_50px_-32px_rgba(15,23,42,0.55)] dark:border-slate-800 dark:bg-slate-950/70",
|
|
306
|
+
children: [[
|
|
307
|
+
["all", "All nodes"],
|
|
308
|
+
["workspace", "Monorepo only"],
|
|
309
|
+
["external", "node_modules only"]
|
|
310
|
+
].map(([value, label]) => /* @__PURE__ */ jsx(Button, {
|
|
311
|
+
variant: scope === value ? "default" : "outline",
|
|
312
|
+
size: "sm",
|
|
313
|
+
onClick: () => updateSearch({
|
|
314
|
+
scope: value,
|
|
315
|
+
cluster: ""
|
|
316
|
+
}),
|
|
317
|
+
children: label
|
|
318
|
+
}, value)), /* @__PURE__ */ jsxs("label", {
|
|
319
|
+
className: "ml-auto flex items-center gap-2 text-sm text-slate-600 dark:text-slate-300",
|
|
320
|
+
children: [/* @__PURE__ */ jsx("span", { children: "External grouping" }), /* @__PURE__ */ jsxs("select", {
|
|
321
|
+
className: "h-9 rounded-md border border-input bg-transparent px-3 text-sm shadow-xs outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50",
|
|
322
|
+
value: externalGrouping,
|
|
323
|
+
onChange: (event) => updateSearch({
|
|
324
|
+
cluster: "",
|
|
325
|
+
externalGrouping: event.currentTarget.value
|
|
326
|
+
}),
|
|
327
|
+
children: [/* @__PURE__ */ jsx("option", {
|
|
328
|
+
value: "package",
|
|
329
|
+
children: "by package"
|
|
330
|
+
}), /* @__PURE__ */ jsx("option", {
|
|
331
|
+
value: "combined",
|
|
332
|
+
children: "single node_modules cluster"
|
|
333
|
+
})]
|
|
334
|
+
})]
|
|
335
|
+
})]
|
|
336
|
+
}),
|
|
337
|
+
/* @__PURE__ */ jsxs("section", {
|
|
338
|
+
className: "flex flex-wrap items-center gap-3 rounded-[24px] border border-slate-200/70 bg-white/90 p-4 shadow-[0_16px_50px_-32px_rgba(15,23,42,0.55)] dark:border-slate-800 dark:bg-slate-950/70",
|
|
339
|
+
children: [
|
|
340
|
+
/* @__PURE__ */ jsx("div", {
|
|
341
|
+
className: "min-w-[18rem] flex-1",
|
|
342
|
+
children: /* @__PURE__ */ jsx(GraphCommandMenu, {
|
|
343
|
+
nodes: filteredNodes,
|
|
344
|
+
onHighlight: (value) => {
|
|
345
|
+
if (!value) return highlightedNodeIdAtom.set(null);
|
|
346
|
+
highlightedNodeIdAtom.set(value);
|
|
347
|
+
},
|
|
348
|
+
onSelect: (value) => {
|
|
349
|
+
highlightedNodeIdAtom.set(null);
|
|
350
|
+
if (!value) {
|
|
351
|
+
setFocusedNode(null);
|
|
352
|
+
updateSearch({ focus: "" });
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
setFocusedNode(value);
|
|
356
|
+
updateSearch({ focus: value });
|
|
357
|
+
}
|
|
358
|
+
})
|
|
359
|
+
}),
|
|
360
|
+
/* @__PURE__ */ jsxs(Button, {
|
|
361
|
+
variant: "outline",
|
|
362
|
+
onClick: () => isNodeDetailsOpenAtom.set(true),
|
|
363
|
+
disabled: !currentNodeId,
|
|
364
|
+
children: [/* @__PURE__ */ jsx(Eye, { className: "size-4" }), isNodeDetailsOpen ? "Details open" : "Open details"]
|
|
365
|
+
}),
|
|
366
|
+
/* @__PURE__ */ jsxs(Button, {
|
|
367
|
+
variant: "outline",
|
|
368
|
+
onClick: () => setFocusedNode(null),
|
|
369
|
+
disabled: selectedNodeIds.length === 0,
|
|
370
|
+
children: [
|
|
371
|
+
"Clear selection (",
|
|
372
|
+
selectedNodeIds.length,
|
|
373
|
+
")"
|
|
374
|
+
]
|
|
375
|
+
}),
|
|
376
|
+
/* @__PURE__ */ jsxs(Button, {
|
|
377
|
+
variant: "outline",
|
|
378
|
+
onClick: () => setRefreshNonce((value) => value + 1),
|
|
379
|
+
children: [/* @__PURE__ */ jsx(RotateCcw, { className: "size-4" }), "Refresh canvas"]
|
|
380
|
+
}),
|
|
381
|
+
currentNodeId ? /* @__PURE__ */ jsx(Button, {
|
|
382
|
+
variant: "outline",
|
|
383
|
+
onClick: () => {
|
|
384
|
+
setFocusedNode(null);
|
|
385
|
+
isNodeDetailsOpenAtom.set(false);
|
|
386
|
+
updateSearch({ focus: "" });
|
|
387
|
+
},
|
|
388
|
+
children: "Clear current node"
|
|
389
|
+
}) : null,
|
|
390
|
+
/* @__PURE__ */ jsxs("div", {
|
|
391
|
+
className: "text-sm text-slate-500 dark:text-slate-400",
|
|
392
|
+
children: [
|
|
393
|
+
filteredNodes.length,
|
|
394
|
+
" nodes, ",
|
|
395
|
+
bundle.graph.metadata.packages.length,
|
|
396
|
+
" workspace packages",
|
|
397
|
+
selectedNodeIds.length > 0 ? ` • ${selectedNodeIds.length} selected` : "",
|
|
398
|
+
currentNodeId ? ` • current ${currentNodeId.split("/").at(-1)}` : "",
|
|
399
|
+
search.cluster ? ` • filtered to ${search.cluster}` : ""
|
|
400
|
+
]
|
|
401
|
+
})
|
|
402
|
+
]
|
|
403
|
+
}),
|
|
404
|
+
/* @__PURE__ */ jsx("section", {
|
|
405
|
+
className: "min-h-0 flex-1 overflow-hidden rounded-[28px] border border-slate-200/70 bg-white/90 shadow-[0_20px_70px_-36px_rgba(15,23,42,0.55)] dark:border-slate-800 dark:bg-slate-950/70",
|
|
406
|
+
children: /* @__PURE__ */ jsx(Suspense, {
|
|
407
|
+
fallback: /* @__PURE__ */ jsx(LoadingState, {
|
|
408
|
+
label: "Loading graph…",
|
|
409
|
+
description: "Preparing the Sigma canvas and layout pass."
|
|
410
|
+
}),
|
|
411
|
+
children: /* @__PURE__ */ jsx(Sigma, {
|
|
412
|
+
output: {
|
|
413
|
+
...bundle.graph,
|
|
414
|
+
nodes: filteredNodes
|
|
415
|
+
},
|
|
416
|
+
entryNode: search.focus || bundle.graph.metadata.entrypoints[0],
|
|
417
|
+
externalGrouping,
|
|
418
|
+
layoutSettings,
|
|
419
|
+
packages: bundle.graph.metadata.packages,
|
|
420
|
+
nodes: filteredNodes
|
|
421
|
+
}, sigmaKey)
|
|
422
|
+
})
|
|
423
|
+
})
|
|
424
|
+
]
|
|
425
|
+
}), /* @__PURE__ */ jsx(GraphSettingsPanel, {
|
|
426
|
+
open: settingsOpen,
|
|
427
|
+
settings: layoutSettings,
|
|
428
|
+
onOpenChange: setSettingsOpen,
|
|
429
|
+
onSettingsChange: (nextSettings) => updateSearch(nextSettings),
|
|
430
|
+
onReset: () => {
|
|
431
|
+
updateSearch(defaultLayoutSettings);
|
|
432
|
+
return defaultLayoutSettings;
|
|
433
|
+
}
|
|
434
|
+
})]
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
//#endregion
|
|
438
|
+
export { GraphRoute as component };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { t as parseSearchParam } from "./search-params-BNApPgkX.js";
|
|
2
|
+
import { createFileRoute, lazyRouteComponent } from "@tanstack/react-router";
|
|
3
|
+
//#region src/components/graph/common/graph-layout-settings.ts
|
|
4
|
+
var getDefaultGraphLayoutSettings = (nodeCount) => {
|
|
5
|
+
const densityFactor = Math.max(1, Math.sqrt(Math.max(nodeCount, 1)));
|
|
6
|
+
return {
|
|
7
|
+
iterations: Math.min(420, Math.max(220, Math.round(170 + densityFactor * 2.4))),
|
|
8
|
+
gravity: Number(Math.max(.15, Math.min(1.2, densityFactor / 90)).toFixed(2)),
|
|
9
|
+
scalingRatio: Math.min(220, Math.max(40, Math.round(28 + densityFactor * 2.6))),
|
|
10
|
+
strongGravityMode: false,
|
|
11
|
+
linLogMode: true,
|
|
12
|
+
adjustSizes: true,
|
|
13
|
+
outboundAttractionDistribution: true,
|
|
14
|
+
hideClusterLabels: false,
|
|
15
|
+
nodeSizeScale: .85
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/routes/graph.tsx
|
|
20
|
+
var $$splitComponentImporter = () => import("./graph-C1G9H5O4.js");
|
|
21
|
+
var validateGraphSearch = (search) => {
|
|
22
|
+
const defaults = getDefaultGraphLayoutSettings(3961);
|
|
23
|
+
return {
|
|
24
|
+
adjustSizes: parseSearchParam.boolean(search.adjustSizes, defaults.adjustSizes),
|
|
25
|
+
cluster: parseSearchParam.string(search.cluster),
|
|
26
|
+
externalGrouping: search.externalGrouping === "combined" ? "combined" : "package",
|
|
27
|
+
focus: parseSearchParam.string(search.focus),
|
|
28
|
+
gravity: parseSearchParam.number(search.gravity, defaults.gravity),
|
|
29
|
+
hideClusterLabels: parseSearchParam.boolean(search.hideClusterLabels, defaults.hideClusterLabels),
|
|
30
|
+
iterations: Math.round(parseSearchParam.number(search.iterations, defaults.iterations)),
|
|
31
|
+
linLogMode: parseSearchParam.boolean(search.linLogMode, defaults.linLogMode),
|
|
32
|
+
nodeSizeScale: parseSearchParam.number(search.nodeSizeScale, defaults.nodeSizeScale),
|
|
33
|
+
outboundAttractionDistribution: parseSearchParam.boolean(search.outboundAttractionDistribution, defaults.outboundAttractionDistribution),
|
|
34
|
+
scalingRatio: parseSearchParam.number(search.scalingRatio, defaults.scalingRatio),
|
|
35
|
+
scope: search.scope === "workspace" || search.scope === "external" ? search.scope : "all",
|
|
36
|
+
strongGravityMode: parseSearchParam.boolean(search.strongGravityMode, defaults.strongGravityMode)
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
var Route = createFileRoute("/graph")({
|
|
40
|
+
ssr: false,
|
|
41
|
+
validateSearch: validateGraphSearch,
|
|
42
|
+
component: lazyRouteComponent($$splitComponentImporter, "component")
|
|
43
|
+
});
|
|
44
|
+
//#endregion
|
|
45
|
+
export { getDefaultGraphLayoutSettings as n, Route as t };
|