@aiready/visualizer 0.6.14 → 0.6.19
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/graph/index.d.ts +2 -22
- package/dist/index.d.ts +1 -1
- package/package.json +2 -2
- package/web/dist/assets/{index-Zc8kVQDw.js → index-CkabxYJ5.js} +557 -496
- package/web/dist/assets/index-CkabxYJ5.js.map +1 -0
- package/web/dist/index.html +1 -1
- package/web/dist/assets/index-Zc8kVQDw.js.map +0 -1
|
@@ -24895,7 +24895,67 @@ function superRefine(fn) {
|
|
|
24895
24895
|
return /* @__PURE__ */ _superRefine(fn);
|
|
24896
24896
|
}
|
|
24897
24897
|
//#endregion
|
|
24898
|
-
//#region ../../core/dist/chunk-
|
|
24898
|
+
//#region ../../core/dist/chunk-SQHS6PFL.mjs
|
|
24899
|
+
var LeadSource = /* @__PURE__ */ ((LeadSource2) => {
|
|
24900
|
+
LeadSource2["ClawMoreHero"] = "clawmore-hero";
|
|
24901
|
+
LeadSource2["ClawMoreWaitlist"] = "clawmore-waitlist";
|
|
24902
|
+
LeadSource2["ClawMoreBeta"] = "clawmore-beta";
|
|
24903
|
+
LeadSource2["AiReadyPlatform"] = "aiready-platform";
|
|
24904
|
+
return LeadSource2;
|
|
24905
|
+
})(LeadSource || {});
|
|
24906
|
+
var LeadSourceSchema = nativeEnum(LeadSource);
|
|
24907
|
+
object({
|
|
24908
|
+
id: string(),
|
|
24909
|
+
email: string().email(),
|
|
24910
|
+
name: string().min(1),
|
|
24911
|
+
interest: string().default("General"),
|
|
24912
|
+
notes: string().optional(),
|
|
24913
|
+
timestamp: string().datetime(),
|
|
24914
|
+
source: LeadSourceSchema,
|
|
24915
|
+
status: _enum([
|
|
24916
|
+
"new",
|
|
24917
|
+
"contacted",
|
|
24918
|
+
"qualified",
|
|
24919
|
+
"converted",
|
|
24920
|
+
"archived"
|
|
24921
|
+
]).default("new")
|
|
24922
|
+
}).omit({
|
|
24923
|
+
id: true,
|
|
24924
|
+
timestamp: true,
|
|
24925
|
+
status: true
|
|
24926
|
+
});
|
|
24927
|
+
object({
|
|
24928
|
+
id: string(),
|
|
24929
|
+
accountId: string(),
|
|
24930
|
+
userId: string(),
|
|
24931
|
+
stripeSubscriptionId: string(),
|
|
24932
|
+
tokenStrategy: _enum(["managed", "byok"]).default("managed"),
|
|
24933
|
+
byokConfig: object({
|
|
24934
|
+
openaiKey: string().optional(),
|
|
24935
|
+
anthropicKey: string().optional(),
|
|
24936
|
+
openrouterKey: string().optional()
|
|
24937
|
+
}).optional(),
|
|
24938
|
+
baseFeeCents: number().default(2900),
|
|
24939
|
+
includedComputeCents: number().default(1500),
|
|
24940
|
+
includedTokenCents: number().default(500),
|
|
24941
|
+
prepaidTokenBalanceCents: number().default(0),
|
|
24942
|
+
currentMonthlyTokenSpendCents: number().default(0),
|
|
24943
|
+
status: _enum([
|
|
24944
|
+
"provisioning",
|
|
24945
|
+
"active",
|
|
24946
|
+
"warning",
|
|
24947
|
+
"quarantined",
|
|
24948
|
+
"suspended"
|
|
24949
|
+
]).default("provisioning"),
|
|
24950
|
+
lastCostSyncAt: string().datetime().optional(),
|
|
24951
|
+
region: string().default("ap-southeast-2"),
|
|
24952
|
+
alertThresholds: array$1(number()).default([
|
|
24953
|
+
50,
|
|
24954
|
+
80,
|
|
24955
|
+
100,
|
|
24956
|
+
150
|
|
24957
|
+
])
|
|
24958
|
+
});
|
|
24899
24959
|
var Severity = /* @__PURE__ */ ((Severity2) => {
|
|
24900
24960
|
Severity2["Critical"] = "critical";
|
|
24901
24961
|
Severity2["Major"] = "major";
|
|
@@ -25069,66 +25129,6 @@ object({
|
|
|
25069
25129
|
}).optional()
|
|
25070
25130
|
}).optional()
|
|
25071
25131
|
}).catchall(any());
|
|
25072
|
-
var LeadSource = /* @__PURE__ */ ((LeadSource2) => {
|
|
25073
|
-
LeadSource2["ClawMoreHero"] = "clawmore-hero";
|
|
25074
|
-
LeadSource2["ClawMoreWaitlist"] = "clawmore-waitlist";
|
|
25075
|
-
LeadSource2["ClawMoreBeta"] = "clawmore-beta";
|
|
25076
|
-
LeadSource2["AiReadyPlatform"] = "aiready-platform";
|
|
25077
|
-
return LeadSource2;
|
|
25078
|
-
})(LeadSource || {});
|
|
25079
|
-
var LeadSourceSchema = nativeEnum(LeadSource);
|
|
25080
|
-
object({
|
|
25081
|
-
id: string(),
|
|
25082
|
-
email: string().email(),
|
|
25083
|
-
name: string().min(1),
|
|
25084
|
-
interest: string().default("General"),
|
|
25085
|
-
notes: string().optional(),
|
|
25086
|
-
timestamp: string().datetime(),
|
|
25087
|
-
source: LeadSourceSchema,
|
|
25088
|
-
status: _enum([
|
|
25089
|
-
"new",
|
|
25090
|
-
"contacted",
|
|
25091
|
-
"qualified",
|
|
25092
|
-
"converted",
|
|
25093
|
-
"archived"
|
|
25094
|
-
]).default("new")
|
|
25095
|
-
}).omit({
|
|
25096
|
-
id: true,
|
|
25097
|
-
timestamp: true,
|
|
25098
|
-
status: true
|
|
25099
|
-
});
|
|
25100
|
-
object({
|
|
25101
|
-
id: string(),
|
|
25102
|
-
accountId: string(),
|
|
25103
|
-
userId: string(),
|
|
25104
|
-
stripeSubscriptionId: string(),
|
|
25105
|
-
tokenStrategy: _enum(["managed", "byok"]).default("managed"),
|
|
25106
|
-
byokConfig: object({
|
|
25107
|
-
openaiKey: string().optional(),
|
|
25108
|
-
anthropicKey: string().optional(),
|
|
25109
|
-
openrouterKey: string().optional()
|
|
25110
|
-
}).optional(),
|
|
25111
|
-
baseFeeCents: number().default(2900),
|
|
25112
|
-
includedComputeCents: number().default(1500),
|
|
25113
|
-
includedTokenCents: number().default(500),
|
|
25114
|
-
prepaidTokenBalanceCents: number().default(0),
|
|
25115
|
-
currentMonthlyTokenSpendCents: number().default(0),
|
|
25116
|
-
status: _enum([
|
|
25117
|
-
"provisioning",
|
|
25118
|
-
"active",
|
|
25119
|
-
"warning",
|
|
25120
|
-
"quarantined",
|
|
25121
|
-
"suspended"
|
|
25122
|
-
]).default("provisioning"),
|
|
25123
|
-
lastCostSyncAt: string().datetime().optional(),
|
|
25124
|
-
region: string().default("ap-southeast-2"),
|
|
25125
|
-
alertThresholds: array$1(number()).default([
|
|
25126
|
-
50,
|
|
25127
|
-
80,
|
|
25128
|
-
100,
|
|
25129
|
-
150
|
|
25130
|
-
])
|
|
25131
|
-
});
|
|
25132
25132
|
//#endregion
|
|
25133
25133
|
//#region ../../../node_modules/.pnpm/d3-dispatch@3.0.1/node_modules/d3-dispatch/src/dispatch.js
|
|
25134
25134
|
var noop = { value: () => {} };
|
|
@@ -28335,182 +28335,16 @@ function ScoreCircle({ score, progress: customProgress, isInView = true, size =
|
|
|
28335
28335
|
});
|
|
28336
28336
|
}
|
|
28337
28337
|
(0, import_react.createContext)(void 0);
|
|
28338
|
-
|
|
28339
|
-
|
|
28340
|
-
|
|
28341
|
-
const x = node.x ?? 0;
|
|
28342
|
-
const y = node.y ?? 0;
|
|
28343
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", {
|
|
28344
|
-
className: "cursor-pointer node",
|
|
28345
|
-
"data-id": node.id,
|
|
28346
|
-
transform: `translate(${x},${y})`,
|
|
28347
|
-
onClick: () => onClick?.(node),
|
|
28348
|
-
onDoubleClick: (e) => onDoubleClick?.(e, node),
|
|
28349
|
-
onMouseEnter: () => onMouseEnter?.(node),
|
|
28350
|
-
onMouseLeave: () => onMouseLeave?.(),
|
|
28351
|
-
onMouseDown: (e) => onMouseDown?.(e, node),
|
|
28352
|
-
children: [
|
|
28353
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
|
|
28354
|
-
r: nodeSize,
|
|
28355
|
-
fill: nodeColor,
|
|
28356
|
-
stroke: isSelected ? "#000" : isHovered ? "#666" : "none",
|
|
28357
|
-
strokeWidth: pinned ? 3 : isSelected ? 2.5 : isHovered ? 2 : 1.5,
|
|
28358
|
-
opacity: isHovered || isSelected ? 1 : .9
|
|
28359
|
-
}),
|
|
28360
|
-
pinned && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
|
|
28361
|
-
r: nodeSize + 4,
|
|
28362
|
-
fill: "none",
|
|
28363
|
-
stroke: "#ff6b6b",
|
|
28364
|
-
strokeWidth: 1,
|
|
28365
|
-
opacity: .5,
|
|
28366
|
-
className: "pointer-events-none"
|
|
28367
|
-
}),
|
|
28368
|
-
showLabel && node.label && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("text", {
|
|
28369
|
-
y: nodeSize + 15,
|
|
28370
|
-
fill: "#333",
|
|
28371
|
-
fontSize: "12",
|
|
28372
|
-
textAnchor: "middle",
|
|
28373
|
-
dominantBaseline: "middle",
|
|
28374
|
-
pointerEvents: "none",
|
|
28375
|
-
className: "select-none",
|
|
28376
|
-
children: node.label
|
|
28377
|
-
})
|
|
28378
|
-
]
|
|
28379
|
-
}, node.id);
|
|
28380
|
-
};
|
|
28381
|
-
var NodeItem_default = NodeItem;
|
|
28382
|
-
var LinkItem = ({ link, onClick, defaultWidth, showLabel = true, nodes = [] }) => {
|
|
28383
|
-
const src = link.source?.id ?? (typeof link.source === "string" ? link.source : void 0);
|
|
28384
|
-
const tgt = link.target?.id ?? (typeof link.target === "string" ? link.target : void 0);
|
|
28385
|
-
const getNodePosition = (nodeOrId) => {
|
|
28386
|
-
if (typeof nodeOrId === "object" && nodeOrId !== null) {
|
|
28387
|
-
const node = nodeOrId;
|
|
28388
|
-
return {
|
|
28389
|
-
x: node.x ?? 0,
|
|
28390
|
-
y: node.y ?? 0
|
|
28391
|
-
};
|
|
28392
|
-
} else if (typeof nodeOrId === "string") {
|
|
28393
|
-
const found = nodes.find((n) => n.id === nodeOrId);
|
|
28394
|
-
if (found) return {
|
|
28395
|
-
x: found.x ?? 0,
|
|
28396
|
-
y: found.y ?? 0
|
|
28397
|
-
};
|
|
28398
|
-
}
|
|
28399
|
-
return null;
|
|
28400
|
-
};
|
|
28401
|
-
const sourcePos = getNodePosition(link.source);
|
|
28402
|
-
const targetPos = getNodePosition(link.target);
|
|
28403
|
-
if (!sourcePos || !targetPos) return null;
|
|
28404
|
-
const midX = (sourcePos.x + targetPos.x) / 2;
|
|
28405
|
-
const midY = (sourcePos.y + targetPos.y) / 2;
|
|
28406
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", {
|
|
28407
|
-
x1: sourcePos.x,
|
|
28408
|
-
y1: sourcePos.y,
|
|
28409
|
-
x2: targetPos.x,
|
|
28410
|
-
y2: targetPos.y,
|
|
28411
|
-
"data-source": src,
|
|
28412
|
-
"data-target": tgt,
|
|
28413
|
-
stroke: link.color,
|
|
28414
|
-
strokeWidth: link.width ?? defaultWidth ?? 1,
|
|
28415
|
-
opacity: .6,
|
|
28416
|
-
className: "cursor-pointer transition-opacity hover:opacity-100",
|
|
28417
|
-
onClick: () => onClick?.(link)
|
|
28418
|
-
}), showLabel && link.label && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("text", {
|
|
28419
|
-
x: midX,
|
|
28420
|
-
y: midY,
|
|
28421
|
-
fill: "#666",
|
|
28422
|
-
fontSize: "10",
|
|
28423
|
-
textAnchor: "middle",
|
|
28424
|
-
dominantBaseline: "middle",
|
|
28425
|
-
pointerEvents: "none",
|
|
28426
|
-
children: link.label
|
|
28427
|
-
})] });
|
|
28428
|
-
};
|
|
28429
|
-
var LinkItem_default = LinkItem;
|
|
28430
|
-
var DEFAULT_NODE_COLOR = "#64748b";
|
|
28431
|
-
var DEFAULT_NODE_SIZE = 10;
|
|
28432
|
-
var DEFAULT_LINK_COLOR = "#94a3b8";
|
|
28433
|
-
var DEFAULT_LINK_WIDTH = 1;
|
|
28434
|
-
var CIRCULAR_LAYOUT_RADIUS_RATIO = .35;
|
|
28435
|
-
var FIT_VIEW_PADDING = 40;
|
|
28436
|
-
var TRANSITION_DURATION_MS = 300;
|
|
28437
|
-
var PACKAGE_BOUNDARY_FILL = "rgba(148,163,184,0.06)";
|
|
28438
|
-
var PACKAGE_BOUNDARY_STROKE = "#475569";
|
|
28439
|
-
var PACKAGE_BOUNDARY_STROKE_WIDTH = 2;
|
|
28440
|
-
var PACKAGE_BOUNDARY_DASH = "6 6";
|
|
28441
|
-
var PACKAGE_LABEL_FONT_SIZE = 11;
|
|
28442
|
-
var PACKAGE_LABEL_COLOR = "#475569";
|
|
28443
|
-
var PackageBoundaries = ({ packageBounds }) => {
|
|
28444
|
-
if (!packageBounds || Object.keys(packageBounds).length === 0) return null;
|
|
28445
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("g", {
|
|
28446
|
-
className: "package-boundaries",
|
|
28447
|
-
pointerEvents: "none",
|
|
28448
|
-
children: Object.entries(packageBounds).map(([pid, b]) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
|
|
28449
|
-
cx: b.x,
|
|
28450
|
-
cy: b.y,
|
|
28451
|
-
r: b.r,
|
|
28452
|
-
fill: PACKAGE_BOUNDARY_FILL,
|
|
28453
|
-
stroke: PACKAGE_BOUNDARY_STROKE,
|
|
28454
|
-
strokeWidth: PACKAGE_BOUNDARY_STROKE_WIDTH,
|
|
28455
|
-
strokeDasharray: PACKAGE_BOUNDARY_DASH,
|
|
28456
|
-
opacity: .9
|
|
28457
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("text", {
|
|
28458
|
-
x: b.x,
|
|
28459
|
-
y: Math.max(12, b.y - b.r + 14),
|
|
28460
|
-
fill: PACKAGE_LABEL_COLOR,
|
|
28461
|
-
fontSize: PACKAGE_LABEL_FONT_SIZE,
|
|
28462
|
-
textAnchor: "middle",
|
|
28463
|
-
pointerEvents: "none",
|
|
28464
|
-
children: pid.replace(/^pkg:/, "")
|
|
28465
|
-
})] }, pid))
|
|
28466
|
-
});
|
|
28467
|
-
};
|
|
28468
|
-
PackageBoundaries.displayName = "PackageBoundaries";
|
|
28469
|
-
function applyCircularLayout(nodes, width, height) {
|
|
28470
|
-
const centerX = width / 2;
|
|
28471
|
-
const centerY = height / 2;
|
|
28472
|
-
const radius = Math.min(width, height) * CIRCULAR_LAYOUT_RADIUS_RATIO;
|
|
28473
|
-
nodes.forEach((node, i) => {
|
|
28474
|
-
const angle = 2 * Math.PI * i / nodes.length;
|
|
28475
|
-
node.fx = centerX + Math.cos(angle) * radius;
|
|
28476
|
-
node.fy = centerY + Math.sin(angle) * radius;
|
|
28477
|
-
node.x = node.fx;
|
|
28478
|
-
node.y = node.fy;
|
|
28479
|
-
});
|
|
28338
|
+
function pinNode(node) {
|
|
28339
|
+
node.fx = node.x;
|
|
28340
|
+
node.fy = node.y;
|
|
28480
28341
|
}
|
|
28481
|
-
function
|
|
28482
|
-
|
|
28483
|
-
|
|
28484
|
-
const key = n.packageGroup || n.group || "root";
|
|
28485
|
-
if (!groups.has(key)) groups.set(key, []);
|
|
28486
|
-
groups.get(key).push(n);
|
|
28487
|
-
});
|
|
28488
|
-
const groupArray = Array.from(groups.entries());
|
|
28489
|
-
const cols = Math.ceil(Math.sqrt(groupArray.length));
|
|
28490
|
-
const groupSpacingX = width * .8 / cols;
|
|
28491
|
-
const groupSpacingY = height * .8 / Math.ceil(groupArray.length / cols);
|
|
28492
|
-
groupArray.forEach(([groupKey, groupNodes], gi) => {
|
|
28493
|
-
const col = gi % cols;
|
|
28494
|
-
const row = Math.floor(gi / cols);
|
|
28495
|
-
const groupX = (col + .5) * groupSpacingX;
|
|
28496
|
-
const groupY = (row + .5) * groupSpacingY;
|
|
28497
|
-
if (groupKey.startsWith("pkg:") || groupKey === groupKey) groupNodes.forEach((n, ni) => {
|
|
28498
|
-
const angle = 2 * Math.PI * ni / groupNodes.length;
|
|
28499
|
-
const r = Math.min(80, 20 + groupNodes.length * 8);
|
|
28500
|
-
n.fx = groupX + Math.cos(angle) * r;
|
|
28501
|
-
n.fy = groupY + Math.sin(angle) * r;
|
|
28502
|
-
n.x = n.fx;
|
|
28503
|
-
n.y = n.fy;
|
|
28504
|
-
});
|
|
28505
|
-
});
|
|
28342
|
+
function unpinNode(node) {
|
|
28343
|
+
node.fx = null;
|
|
28344
|
+
node.fy = null;
|
|
28506
28345
|
}
|
|
28507
|
-
function
|
|
28508
|
-
nodes.forEach(
|
|
28509
|
-
if (node.fx === void 0 || node.fx === null) {
|
|
28510
|
-
node.x = Math.random() * width;
|
|
28511
|
-
node.y = Math.random() * height;
|
|
28512
|
-
}
|
|
28513
|
-
});
|
|
28346
|
+
function unpinAllNodes(nodes) {
|
|
28347
|
+
nodes.forEach(unpinNode);
|
|
28514
28348
|
}
|
|
28515
28349
|
function useGraphZoom(svgRef, gRef, enableZoom, setTransform, transformRef) {
|
|
28516
28350
|
(0, import_react.useEffect)(() => {
|
|
@@ -28576,42 +28410,103 @@ function useWindowDrag(enableDrag, svgRef, transformRef, dragActiveRef, dragNode
|
|
|
28576
28410
|
onDragEnd
|
|
28577
28411
|
]);
|
|
28578
28412
|
}
|
|
28579
|
-
function
|
|
28580
|
-
|
|
28581
|
-
|
|
28413
|
+
function useNodeInteractions(enableDrag, _nodes, _pinnedNodes, setPinnedNodes, restart, stop) {
|
|
28414
|
+
return {
|
|
28415
|
+
handleDragStart: (0, import_react.useCallback)((event, node) => {
|
|
28416
|
+
if (!enableDrag) return;
|
|
28417
|
+
event.preventDefault();
|
|
28418
|
+
event.stopPropagation();
|
|
28419
|
+
pinNode(node);
|
|
28420
|
+
setPinnedNodes((prev) => /* @__PURE__ */ new Set([...prev, node.id]));
|
|
28421
|
+
stop();
|
|
28422
|
+
}, [
|
|
28423
|
+
enableDrag,
|
|
28424
|
+
stop,
|
|
28425
|
+
setPinnedNodes
|
|
28426
|
+
]),
|
|
28427
|
+
handleNodeDoubleClick: (0, import_react.useCallback)((event, node) => {
|
|
28428
|
+
event.stopPropagation();
|
|
28429
|
+
if (!enableDrag) return;
|
|
28430
|
+
if (node.fx === null || node.fx === void 0) {
|
|
28431
|
+
pinNode(node);
|
|
28432
|
+
setPinnedNodes((prev) => /* @__PURE__ */ new Set([...prev, node.id]));
|
|
28433
|
+
} else {
|
|
28434
|
+
unpinNode(node);
|
|
28435
|
+
setPinnedNodes((prev) => {
|
|
28436
|
+
const next = new Set(prev);
|
|
28437
|
+
next.delete(node.id);
|
|
28438
|
+
return next;
|
|
28439
|
+
});
|
|
28440
|
+
}
|
|
28441
|
+
restart();
|
|
28442
|
+
}, [
|
|
28443
|
+
enableDrag,
|
|
28444
|
+
restart,
|
|
28445
|
+
setPinnedNodes
|
|
28446
|
+
])
|
|
28447
|
+
};
|
|
28582
28448
|
}
|
|
28583
|
-
|
|
28584
|
-
|
|
28585
|
-
|
|
28449
|
+
var DEFAULT_NODE_COLOR = "#64748b";
|
|
28450
|
+
var DEFAULT_NODE_SIZE = 10;
|
|
28451
|
+
var DEFAULT_LINK_COLOR = "#94a3b8";
|
|
28452
|
+
var DEFAULT_LINK_WIDTH = 1;
|
|
28453
|
+
var CIRCULAR_LAYOUT_RADIUS_RATIO = .35;
|
|
28454
|
+
var FIT_VIEW_PADDING = 40;
|
|
28455
|
+
var TRANSITION_DURATION_MS = 300;
|
|
28456
|
+
var PACKAGE_BOUNDARY_FILL = "rgba(148,163,184,0.06)";
|
|
28457
|
+
var PACKAGE_BOUNDARY_STROKE = "#475569";
|
|
28458
|
+
var PACKAGE_BOUNDARY_STROKE_WIDTH = 2;
|
|
28459
|
+
var PACKAGE_BOUNDARY_DASH = "6 6";
|
|
28460
|
+
var PACKAGE_LABEL_FONT_SIZE = 11;
|
|
28461
|
+
var PACKAGE_LABEL_COLOR = "#475569";
|
|
28462
|
+
function applyCircularLayout(nodes, width, height) {
|
|
28463
|
+
const centerX = width / 2;
|
|
28464
|
+
const centerY = height / 2;
|
|
28465
|
+
const radius = Math.min(width, height) * CIRCULAR_LAYOUT_RADIUS_RATIO;
|
|
28466
|
+
nodes.forEach((node, i) => {
|
|
28467
|
+
const angle = 2 * Math.PI * i / nodes.length;
|
|
28468
|
+
node.fx = centerX + Math.cos(angle) * radius;
|
|
28469
|
+
node.fy = centerY + Math.sin(angle) * radius;
|
|
28470
|
+
node.x = node.fx;
|
|
28471
|
+
node.y = node.fy;
|
|
28472
|
+
});
|
|
28586
28473
|
}
|
|
28587
|
-
function
|
|
28588
|
-
|
|
28474
|
+
function applyHierarchicalLayout(nodes, width, height) {
|
|
28475
|
+
const groups = /* @__PURE__ */ new Map();
|
|
28476
|
+
nodes.forEach((n) => {
|
|
28477
|
+
const key = n.packageGroup || n.group || "root";
|
|
28478
|
+
if (!groups.has(key)) groups.set(key, []);
|
|
28479
|
+
groups.get(key).push(n);
|
|
28480
|
+
});
|
|
28481
|
+
const groupArray = Array.from(groups.entries());
|
|
28482
|
+
const cols = Math.ceil(Math.sqrt(groupArray.length));
|
|
28483
|
+
const groupSpacingX = width * .8 / cols;
|
|
28484
|
+
const groupSpacingY = height * .8 / Math.ceil(groupArray.length / cols);
|
|
28485
|
+
groupArray.forEach(([groupKey, groupNodes], gi) => {
|
|
28486
|
+
const col = gi % cols;
|
|
28487
|
+
const row = Math.floor(gi / cols);
|
|
28488
|
+
const groupX = (col + .5) * groupSpacingX;
|
|
28489
|
+
const groupY = (row + .5) * groupSpacingY;
|
|
28490
|
+
if (groupKey.startsWith("pkg:") || groupKey === groupKey) groupNodes.forEach((n, ni) => {
|
|
28491
|
+
const angle = 2 * Math.PI * ni / groupNodes.length;
|
|
28492
|
+
const r = Math.min(80, 20 + groupNodes.length * 8);
|
|
28493
|
+
n.fx = groupX + Math.cos(angle) * r;
|
|
28494
|
+
n.fy = groupY + Math.sin(angle) * r;
|
|
28495
|
+
n.x = n.fx;
|
|
28496
|
+
n.y = n.fy;
|
|
28497
|
+
});
|
|
28498
|
+
});
|
|
28589
28499
|
}
|
|
28590
|
-
|
|
28591
|
-
|
|
28592
|
-
|
|
28593
|
-
|
|
28594
|
-
|
|
28595
|
-
|
|
28596
|
-
y: 0
|
|
28500
|
+
function applyInitialForceLayout(nodes, width, height) {
|
|
28501
|
+
nodes.forEach((node) => {
|
|
28502
|
+
if (node.fx === void 0 || node.fx === null) {
|
|
28503
|
+
node.x = Math.random() * width;
|
|
28504
|
+
node.y = Math.random() * height;
|
|
28505
|
+
}
|
|
28597
28506
|
});
|
|
28598
|
-
|
|
28599
|
-
|
|
28600
|
-
const
|
|
28601
|
-
const [pinnedNodes, setPinnedNodes] = (0, import_react.useState)(/* @__PURE__ */ new Set());
|
|
28602
|
-
const internalDragEnabledRef = (0, import_react.useRef)(enableDrag);
|
|
28603
|
-
const [layout, setLayout] = (0, import_react.useState)(externalLayout || "force");
|
|
28604
|
-
(0, import_react.useEffect)(() => {
|
|
28605
|
-
if (externalLayout && externalLayout !== layout) setLayout(externalLayout);
|
|
28606
|
-
}, [externalLayout, layout]);
|
|
28607
|
-
const handleLayoutChange = (0, import_react.useCallback)((newLayout) => {
|
|
28608
|
-
setLayout(newLayout);
|
|
28609
|
-
onLayoutChange?.(newLayout);
|
|
28610
|
-
}, [onLayoutChange]);
|
|
28611
|
-
(0, import_react.useEffect)(() => {
|
|
28612
|
-
internalDragEnabledRef.current = enableDrag;
|
|
28613
|
-
}, [enableDrag]);
|
|
28614
|
-
const nodes = import_react.useMemo(() => {
|
|
28507
|
+
}
|
|
28508
|
+
function useGraphLayout(initialNodes, width, height, layout, restart) {
|
|
28509
|
+
const nodes = (0, import_react.useMemo)(() => {
|
|
28615
28510
|
if (!initialNodes || !initialNodes.length) return initialNodes;
|
|
28616
28511
|
const copy = initialNodes.map((n) => ({ ...n }));
|
|
28617
28512
|
if (layout === "circular") applyCircularLayout(copy, width, height);
|
|
@@ -28624,9 +28519,6 @@ var ForceDirectedGraph = (0, import_react.forwardRef)(({ nodes: initialNodes, li
|
|
|
28624
28519
|
height,
|
|
28625
28520
|
layout
|
|
28626
28521
|
]);
|
|
28627
|
-
const restart = import_react.useCallback(() => {}, []);
|
|
28628
|
-
const stop = import_react.useCallback(() => {}, []);
|
|
28629
|
-
const setForcesEnabled = import_react.useCallback((enabled) => {}, []);
|
|
28630
28522
|
(0, import_react.useEffect)(() => {
|
|
28631
28523
|
if (!nodes || nodes.length === 0) return;
|
|
28632
28524
|
if (layout === "circular") applyCircularLayout(nodes, width, height);
|
|
@@ -28639,16 +28531,18 @@ var ForceDirectedGraph = (0, import_react.forwardRef)(({ nodes: initialNodes, li
|
|
|
28639
28531
|
height,
|
|
28640
28532
|
restart
|
|
28641
28533
|
]);
|
|
28642
|
-
|
|
28643
|
-
|
|
28644
|
-
|
|
28645
|
-
|
|
28646
|
-
|
|
28647
|
-
|
|
28648
|
-
setForcesEnabled
|
|
28649
|
-
|
|
28650
|
-
|
|
28651
|
-
|
|
28534
|
+
return { nodes };
|
|
28535
|
+
}
|
|
28536
|
+
function useSimulationControls() {
|
|
28537
|
+
return {
|
|
28538
|
+
restart: (0, import_react.useCallback)(() => {}, []),
|
|
28539
|
+
stop: (0, import_react.useCallback)(() => {}, []),
|
|
28540
|
+
setForcesEnabled: (0, import_react.useCallback)((enabled) => {}, [])
|
|
28541
|
+
};
|
|
28542
|
+
}
|
|
28543
|
+
function useImperativeHandleMethods({ nodes, pinnedNodes, setPinnedNodes, restart, width, height, layout, handleLayoutChange, svgRef, gRef, setTransform, internalDragEnabledRef }) {
|
|
28544
|
+
return {
|
|
28545
|
+
pinAll: (0, import_react.useCallback)(() => {
|
|
28652
28546
|
const newPinned = /* @__PURE__ */ new Set();
|
|
28653
28547
|
nodes.forEach((node) => {
|
|
28654
28548
|
pinNode(node);
|
|
@@ -28656,18 +28550,30 @@ var ForceDirectedGraph = (0, import_react.forwardRef)(({ nodes: initialNodes, li
|
|
|
28656
28550
|
});
|
|
28657
28551
|
setPinnedNodes(newPinned);
|
|
28658
28552
|
restart();
|
|
28659
|
-
},
|
|
28660
|
-
|
|
28553
|
+
}, [
|
|
28554
|
+
nodes,
|
|
28555
|
+
setPinnedNodes,
|
|
28556
|
+
restart
|
|
28557
|
+
]),
|
|
28558
|
+
unpinAll: (0, import_react.useCallback)(() => {
|
|
28661
28559
|
unpinAllNodes(nodes);
|
|
28662
28560
|
setPinnedNodes(/* @__PURE__ */ new Set());
|
|
28663
28561
|
restart();
|
|
28664
|
-
},
|
|
28665
|
-
|
|
28562
|
+
}, [
|
|
28563
|
+
nodes,
|
|
28564
|
+
setPinnedNodes,
|
|
28565
|
+
restart
|
|
28566
|
+
]),
|
|
28567
|
+
resetLayout: (0, import_react.useCallback)(() => {
|
|
28666
28568
|
unpinAllNodes(nodes);
|
|
28667
28569
|
setPinnedNodes(/* @__PURE__ */ new Set());
|
|
28668
28570
|
restart();
|
|
28669
|
-
},
|
|
28670
|
-
|
|
28571
|
+
}, [
|
|
28572
|
+
nodes,
|
|
28573
|
+
setPinnedNodes,
|
|
28574
|
+
restart
|
|
28575
|
+
]),
|
|
28576
|
+
fitView: (0, import_react.useCallback)(() => {
|
|
28671
28577
|
if (!svgRef.current || !nodes.length) return;
|
|
28672
28578
|
let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
|
|
28673
28579
|
nodes.forEach((node) => {
|
|
@@ -28689,111 +28595,233 @@ var ForceDirectedGraph = (0, import_react.forwardRef)(({ nodes: initialNodes, li
|
|
|
28689
28595
|
svg.transition().duration(TRANSITION_DURATION_MS).call(zoom_default().transform, newTransform);
|
|
28690
28596
|
setTransform(newTransform);
|
|
28691
28597
|
}
|
|
28692
|
-
},
|
|
28693
|
-
|
|
28694
|
-
|
|
28598
|
+
}, [
|
|
28599
|
+
nodes,
|
|
28600
|
+
width,
|
|
28601
|
+
height,
|
|
28602
|
+
svgRef,
|
|
28603
|
+
gRef,
|
|
28604
|
+
setTransform
|
|
28605
|
+
]),
|
|
28606
|
+
getPinnedNodes: (0, import_react.useCallback)(() => Array.from(pinnedNodes), [pinnedNodes]),
|
|
28607
|
+
setDragMode: (0, import_react.useCallback)((enabled) => {
|
|
28695
28608
|
internalDragEnabledRef.current = enabled;
|
|
28696
|
-
},
|
|
28697
|
-
setLayout: (newLayout) =>
|
|
28698
|
-
|
|
28699
|
-
|
|
28700
|
-
|
|
28701
|
-
|
|
28702
|
-
|
|
28703
|
-
|
|
28704
|
-
|
|
28705
|
-
|
|
28706
|
-
|
|
28707
|
-
|
|
28708
|
-
|
|
28709
|
-
|
|
28710
|
-
|
|
28711
|
-
|
|
28712
|
-
|
|
28713
|
-
|
|
28714
|
-
|
|
28715
|
-
|
|
28609
|
+
}, [internalDragEnabledRef]),
|
|
28610
|
+
setLayout: (0, import_react.useCallback)((newLayout) => {
|
|
28611
|
+
handleLayoutChange(newLayout);
|
|
28612
|
+
}, [handleLayoutChange]),
|
|
28613
|
+
getLayout: (0, import_react.useCallback)(() => layout, [layout])
|
|
28614
|
+
};
|
|
28615
|
+
}
|
|
28616
|
+
var ControlButton = ({ onClick, active = false, icon, label, disabled = false }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
28617
|
+
className: "relative group",
|
|
28618
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
28619
|
+
onClick,
|
|
28620
|
+
disabled,
|
|
28621
|
+
className: cn("p-2 rounded-lg transition-all duration-200", active ? "bg-blue-500 text-white shadow-md hover:bg-blue-600" : "bg-gray-100 text-gray-700 hover:bg-gray-200", disabled && "opacity-50 cursor-not-allowed hover:bg-gray-100", "dark:bg-gray-700 dark:text-gray-200 dark:hover:bg-gray-600 dark:active:bg-blue-600"),
|
|
28622
|
+
title: label,
|
|
28623
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
28624
|
+
className: "text-lg",
|
|
28625
|
+
children: icon
|
|
28626
|
+
})
|
|
28627
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
28628
|
+
className: "absolute left-full ml-2 px-2 py-1 bg-gray-900 text-white text-xs rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition-opacity duration-200 pointer-events-none z-50",
|
|
28629
|
+
children: label
|
|
28630
|
+
})]
|
|
28631
|
+
});
|
|
28632
|
+
var GraphControls = ({ dragEnabled = true, onDragToggle, manualLayout = false, onManualLayoutToggle, onPinAll, onUnpinAll, onReset, onFitView, pinnedCount = 0, totalNodes = 0, visible = true, position = "top-left", className }) => {
|
|
28633
|
+
if (!visible) return null;
|
|
28634
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
28635
|
+
className: cn("fixed z-40 bg-white dark:bg-gray-800 rounded-lg shadow-lg p-2 border border-gray-200 dark:border-gray-700", {
|
|
28636
|
+
"top-left": "top-4 left-4",
|
|
28637
|
+
"top-right": "top-4 right-4",
|
|
28638
|
+
"bottom-left": "bottom-4 left-4",
|
|
28639
|
+
"bottom-right": "bottom-4 right-4"
|
|
28640
|
+
}[position], className),
|
|
28641
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
28642
|
+
className: "flex flex-col gap-2",
|
|
28643
|
+
children: [
|
|
28644
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ControlButton, {
|
|
28645
|
+
onClick: () => onDragToggle?.(!dragEnabled),
|
|
28646
|
+
active: dragEnabled,
|
|
28647
|
+
icon: "✋",
|
|
28648
|
+
label: dragEnabled ? "Drag enabled" : "Drag disabled"
|
|
28649
|
+
}),
|
|
28650
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ControlButton, {
|
|
28651
|
+
onClick: () => onManualLayoutToggle?.(!manualLayout),
|
|
28652
|
+
active: manualLayout,
|
|
28653
|
+
icon: "🔧",
|
|
28654
|
+
label: manualLayout ? "Manual layout: ON" : "Manual layout: OFF"
|
|
28655
|
+
}),
|
|
28656
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "w-8 h-px bg-gray-300 dark:bg-gray-600 mx-auto my-1" }),
|
|
28657
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
28658
|
+
className: "flex gap-1",
|
|
28659
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ControlButton, {
|
|
28660
|
+
onClick: () => onPinAll?.(),
|
|
28661
|
+
disabled: totalNodes === 0,
|
|
28662
|
+
icon: "📌",
|
|
28663
|
+
label: `Pin all nodes (${totalNodes})`
|
|
28664
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ControlButton, {
|
|
28665
|
+
onClick: () => onUnpinAll?.(),
|
|
28666
|
+
disabled: pinnedCount === 0,
|
|
28667
|
+
icon: "📍",
|
|
28668
|
+
label: `Unpin all (${pinnedCount} pinned)`
|
|
28669
|
+
})]
|
|
28670
|
+
}),
|
|
28671
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "w-8 h-px bg-gray-300 dark:bg-gray-600 mx-auto my-1" }),
|
|
28672
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ControlButton, {
|
|
28673
|
+
onClick: () => onFitView?.(),
|
|
28674
|
+
disabled: totalNodes === 0,
|
|
28675
|
+
icon: "🎯",
|
|
28676
|
+
label: "Fit all nodes in view"
|
|
28677
|
+
}),
|
|
28678
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(ControlButton, {
|
|
28679
|
+
onClick: () => onReset?.(),
|
|
28680
|
+
disabled: totalNodes === 0,
|
|
28681
|
+
icon: "↺",
|
|
28682
|
+
label: "Reset to auto-layout"
|
|
28683
|
+
})
|
|
28684
|
+
]
|
|
28685
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
28686
|
+
className: "mt-3 pt-3 border-t border-gray-200 dark:border-gray-700 text-xs text-gray-600 dark:text-gray-400",
|
|
28687
|
+
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
28688
|
+
className: "whitespace-nowrap",
|
|
28689
|
+
children: [
|
|
28690
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: "Nodes:" }),
|
|
28691
|
+
" ",
|
|
28692
|
+
totalNodes
|
|
28693
|
+
]
|
|
28694
|
+
}), pinnedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
28695
|
+
className: "whitespace-nowrap",
|
|
28696
|
+
children: [
|
|
28697
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: "Pinned:" }),
|
|
28698
|
+
" ",
|
|
28699
|
+
pinnedCount
|
|
28700
|
+
]
|
|
28701
|
+
})]
|
|
28702
|
+
})]
|
|
28716
28703
|
});
|
|
28717
|
-
|
|
28718
|
-
|
|
28719
|
-
|
|
28720
|
-
|
|
28721
|
-
|
|
28722
|
-
|
|
28723
|
-
|
|
28724
|
-
|
|
28725
|
-
|
|
28726
|
-
|
|
28727
|
-
|
|
28728
|
-
|
|
28729
|
-
|
|
28730
|
-
|
|
28731
|
-
|
|
28732
|
-
|
|
28733
|
-
|
|
28734
|
-
|
|
28735
|
-
|
|
28736
|
-
|
|
28737
|
-
|
|
28738
|
-
|
|
28739
|
-
|
|
28740
|
-
|
|
28741
|
-
|
|
28742
|
-
|
|
28743
|
-
|
|
28744
|
-
|
|
28745
|
-
|
|
28746
|
-
|
|
28747
|
-
|
|
28748
|
-
|
|
28749
|
-
|
|
28750
|
-
|
|
28751
|
-
|
|
28752
|
-
|
|
28753
|
-
|
|
28754
|
-
|
|
28755
|
-
|
|
28756
|
-
|
|
28757
|
-
|
|
28758
|
-
|
|
28759
|
-
|
|
28760
|
-
|
|
28761
|
-
|
|
28762
|
-
|
|
28763
|
-
|
|
28764
|
-
|
|
28765
|
-
|
|
28766
|
-
|
|
28767
|
-
|
|
28768
|
-
|
|
28769
|
-
|
|
28770
|
-
|
|
28771
|
-
|
|
28772
|
-
|
|
28773
|
-
|
|
28774
|
-
|
|
28775
|
-
|
|
28776
|
-
|
|
28777
|
-
|
|
28778
|
-
|
|
28779
|
-
internalDragEnabledRef
|
|
28780
|
-
]);
|
|
28781
|
-
const handleNodeDoubleClick = (0, import_react.useCallback)((event, node) => {
|
|
28782
|
-
event.stopPropagation();
|
|
28783
|
-
if (!enableDrag) return;
|
|
28784
|
-
if (node.fx === null || node.fx === void 0) {
|
|
28785
|
-
pinNode(node);
|
|
28786
|
-
setPinnedNodes((prev) => /* @__PURE__ */ new Set([...prev, node.id]));
|
|
28787
|
-
} else {
|
|
28788
|
-
unpinNode(node);
|
|
28789
|
-
setPinnedNodes((prev) => {
|
|
28790
|
-
const next = new Set(prev);
|
|
28791
|
-
next.delete(node.id);
|
|
28792
|
-
return next;
|
|
28793
|
-
});
|
|
28704
|
+
};
|
|
28705
|
+
GraphControls.displayName = "GraphControls";
|
|
28706
|
+
var NodeItem = ({ node, isSelected, isHovered, pinned, defaultNodeSize, defaultNodeColor, showLabel = true, onClick, onDoubleClick, onMouseEnter, onMouseLeave, onMouseDown }) => {
|
|
28707
|
+
const nodeSize = node.size || defaultNodeSize;
|
|
28708
|
+
const nodeColor = node.color || defaultNodeColor;
|
|
28709
|
+
const x = node.x ?? 0;
|
|
28710
|
+
const y = node.y ?? 0;
|
|
28711
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", {
|
|
28712
|
+
className: "cursor-pointer node",
|
|
28713
|
+
"data-id": node.id,
|
|
28714
|
+
transform: `translate(${x},${y})`,
|
|
28715
|
+
onClick: () => onClick?.(node),
|
|
28716
|
+
onDoubleClick: (e) => onDoubleClick?.(e, node),
|
|
28717
|
+
onMouseEnter: () => onMouseEnter?.(node),
|
|
28718
|
+
onMouseLeave: () => onMouseLeave?.(),
|
|
28719
|
+
onMouseDown: (e) => onMouseDown?.(e, node),
|
|
28720
|
+
children: [
|
|
28721
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
|
|
28722
|
+
r: nodeSize,
|
|
28723
|
+
fill: nodeColor,
|
|
28724
|
+
stroke: isSelected ? "#000" : isHovered ? "#666" : "none",
|
|
28725
|
+
strokeWidth: pinned ? 3 : isSelected ? 2.5 : isHovered ? 2 : 1.5,
|
|
28726
|
+
opacity: isHovered || isSelected ? 1 : .9
|
|
28727
|
+
}),
|
|
28728
|
+
pinned && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
|
|
28729
|
+
r: nodeSize + 4,
|
|
28730
|
+
fill: "none",
|
|
28731
|
+
stroke: "#ff6b6b",
|
|
28732
|
+
strokeWidth: 1,
|
|
28733
|
+
opacity: .5,
|
|
28734
|
+
className: "pointer-events-none"
|
|
28735
|
+
}),
|
|
28736
|
+
showLabel && node.label && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("text", {
|
|
28737
|
+
y: nodeSize + 15,
|
|
28738
|
+
fill: "#333",
|
|
28739
|
+
fontSize: "12",
|
|
28740
|
+
textAnchor: "middle",
|
|
28741
|
+
dominantBaseline: "middle",
|
|
28742
|
+
pointerEvents: "none",
|
|
28743
|
+
className: "select-none",
|
|
28744
|
+
children: node.label
|
|
28745
|
+
})
|
|
28746
|
+
]
|
|
28747
|
+
}, node.id);
|
|
28748
|
+
};
|
|
28749
|
+
var NodeItem_default = NodeItem;
|
|
28750
|
+
var LinkItem = ({ link, onClick, defaultWidth, showLabel = true, nodes = [] }) => {
|
|
28751
|
+
const src = link.source?.id ?? (typeof link.source === "string" ? link.source : void 0);
|
|
28752
|
+
const tgt = link.target?.id ?? (typeof link.target === "string" ? link.target : void 0);
|
|
28753
|
+
const getNodePosition = (nodeOrId) => {
|
|
28754
|
+
if (typeof nodeOrId === "object" && nodeOrId !== null) {
|
|
28755
|
+
const node = nodeOrId;
|
|
28756
|
+
return {
|
|
28757
|
+
x: node.x ?? 0,
|
|
28758
|
+
y: node.y ?? 0
|
|
28759
|
+
};
|
|
28760
|
+
} else if (typeof nodeOrId === "string") {
|
|
28761
|
+
const found = nodes.find((n) => n.id === nodeOrId);
|
|
28762
|
+
if (found) return {
|
|
28763
|
+
x: found.x ?? 0,
|
|
28764
|
+
y: found.y ?? 0
|
|
28765
|
+
};
|
|
28794
28766
|
}
|
|
28795
|
-
|
|
28796
|
-
}
|
|
28767
|
+
return null;
|
|
28768
|
+
};
|
|
28769
|
+
const sourcePos = getNodePosition(link.source);
|
|
28770
|
+
const targetPos = getNodePosition(link.target);
|
|
28771
|
+
if (!sourcePos || !targetPos) return null;
|
|
28772
|
+
const midX = (sourcePos.x + targetPos.x) / 2;
|
|
28773
|
+
const midY = (sourcePos.y + targetPos.y) / 2;
|
|
28774
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", {
|
|
28775
|
+
x1: sourcePos.x,
|
|
28776
|
+
y1: sourcePos.y,
|
|
28777
|
+
x2: targetPos.x,
|
|
28778
|
+
y2: targetPos.y,
|
|
28779
|
+
"data-source": src,
|
|
28780
|
+
"data-target": tgt,
|
|
28781
|
+
stroke: link.color,
|
|
28782
|
+
strokeWidth: link.width ?? defaultWidth ?? 1,
|
|
28783
|
+
opacity: .6,
|
|
28784
|
+
className: "cursor-pointer transition-opacity hover:opacity-100",
|
|
28785
|
+
onClick: () => onClick?.(link)
|
|
28786
|
+
}), showLabel && link.label && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("text", {
|
|
28787
|
+
x: midX,
|
|
28788
|
+
y: midY,
|
|
28789
|
+
fill: "#666",
|
|
28790
|
+
fontSize: "10",
|
|
28791
|
+
textAnchor: "middle",
|
|
28792
|
+
dominantBaseline: "middle",
|
|
28793
|
+
pointerEvents: "none",
|
|
28794
|
+
children: link.label
|
|
28795
|
+
})] });
|
|
28796
|
+
};
|
|
28797
|
+
var LinkItem_default = LinkItem;
|
|
28798
|
+
var PackageBoundaries = ({ packageBounds }) => {
|
|
28799
|
+
if (!packageBounds || Object.keys(packageBounds).length === 0) return null;
|
|
28800
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("g", {
|
|
28801
|
+
className: "package-boundaries",
|
|
28802
|
+
pointerEvents: "none",
|
|
28803
|
+
children: Object.entries(packageBounds).map(([pid, b]) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", {
|
|
28804
|
+
cx: b.x,
|
|
28805
|
+
cy: b.y,
|
|
28806
|
+
r: b.r,
|
|
28807
|
+
fill: PACKAGE_BOUNDARY_FILL,
|
|
28808
|
+
stroke: PACKAGE_BOUNDARY_STROKE,
|
|
28809
|
+
strokeWidth: PACKAGE_BOUNDARY_STROKE_WIDTH,
|
|
28810
|
+
strokeDasharray: PACKAGE_BOUNDARY_DASH,
|
|
28811
|
+
opacity: .9
|
|
28812
|
+
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("text", {
|
|
28813
|
+
x: b.x,
|
|
28814
|
+
y: Math.max(12, b.y - b.r + 14),
|
|
28815
|
+
fill: PACKAGE_LABEL_COLOR,
|
|
28816
|
+
fontSize: PACKAGE_LABEL_FONT_SIZE,
|
|
28817
|
+
textAnchor: "middle",
|
|
28818
|
+
pointerEvents: "none",
|
|
28819
|
+
children: pid.replace(/^pkg:/, "")
|
|
28820
|
+
})] }, pid))
|
|
28821
|
+
});
|
|
28822
|
+
};
|
|
28823
|
+
PackageBoundaries.displayName = "PackageBoundaries";
|
|
28824
|
+
var GraphCanvas = ({ svgRef, gRef, width, height, className, nodes, links, pinnedNodes, selectedNodeId, hoveredNodeId, defaultNodeColor = DEFAULT_NODE_COLOR, defaultNodeSize = DEFAULT_NODE_SIZE, defaultLinkColor = DEFAULT_LINK_COLOR, defaultLinkWidth = DEFAULT_LINK_WIDTH, showNodeLabels = true, showLinkLabels = false, onNodeClick, onNodeHover, onLinkClick, packageBounds, handleNodeDoubleClick, handleDragStart, restart, setPinnedNodes }) => {
|
|
28797
28825
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", {
|
|
28798
28826
|
ref: svgRef,
|
|
28799
28827
|
width,
|
|
@@ -28819,7 +28847,7 @@ var ForceDirectedGraph = (0, import_react.forwardRef)(({ nodes: initialNodes, li
|
|
|
28819
28847
|
}) }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", {
|
|
28820
28848
|
ref: gRef,
|
|
28821
28849
|
children: [
|
|
28822
|
-
|
|
28850
|
+
links.map((link, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LinkItem_default, {
|
|
28823
28851
|
link,
|
|
28824
28852
|
onClick: onLinkClick,
|
|
28825
28853
|
defaultWidth: defaultLinkWidth,
|
|
@@ -28844,114 +28872,147 @@ var ForceDirectedGraph = (0, import_react.forwardRef)(({ nodes: initialNodes, li
|
|
|
28844
28872
|
]
|
|
28845
28873
|
})]
|
|
28846
28874
|
});
|
|
28847
|
-
}
|
|
28848
|
-
ForceDirectedGraph.
|
|
28849
|
-
|
|
28850
|
-
|
|
28851
|
-
const
|
|
28852
|
-
|
|
28853
|
-
|
|
28854
|
-
|
|
28855
|
-
"bottom-right": "bottom-4 right-4"
|
|
28856
|
-
};
|
|
28857
|
-
const ControlButton = ({ onClick, active = false, icon, label, disabled = false }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
28858
|
-
className: "relative group",
|
|
28859
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
|
|
28860
|
-
onClick,
|
|
28861
|
-
disabled,
|
|
28862
|
-
className: cn("p-2 rounded-lg transition-all duration-200", active ? "bg-blue-500 text-white shadow-md hover:bg-blue-600" : "bg-gray-100 text-gray-700 hover:bg-gray-200", disabled && "opacity-50 cursor-not-allowed hover:bg-gray-100", "dark:bg-gray-700 dark:text-gray-200 dark:hover:bg-gray-600 dark:active:bg-blue-600"),
|
|
28863
|
-
title: label,
|
|
28864
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", {
|
|
28865
|
-
className: "text-lg",
|
|
28866
|
-
children: icon
|
|
28867
|
-
})
|
|
28868
|
-
}), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", {
|
|
28869
|
-
className: "absolute left-full ml-2 px-2 py-1 bg-gray-900 text-white text-xs rounded whitespace-nowrap opacity-0 group-hover:opacity-100 transition-opacity duration-200 pointer-events-none z-50",
|
|
28870
|
-
children: label
|
|
28871
|
-
})]
|
|
28875
|
+
};
|
|
28876
|
+
var ForceDirectedGraph = (0, import_react.forwardRef)(({ nodes: initialNodes, links: initialLinks, width, height, enableZoom = true, enableDrag = true, onNodeClick, onNodeHover, onLinkClick, selectedNodeId, hoveredNodeId, defaultNodeColor, defaultNodeSize, defaultLinkColor, defaultLinkWidth, showNodeLabels, showLinkLabels, className, manualLayout = false, onManualLayoutChange, packageBounds, layout: externalLayout, onLayoutChange }, ref) => {
|
|
28877
|
+
const svgRef = (0, import_react.useRef)(null);
|
|
28878
|
+
const gRef = (0, import_react.useRef)(null);
|
|
28879
|
+
const [transform, setTransform] = (0, import_react.useState)({
|
|
28880
|
+
k: 1,
|
|
28881
|
+
x: 0,
|
|
28882
|
+
y: 0
|
|
28872
28883
|
});
|
|
28873
|
-
|
|
28874
|
-
|
|
28875
|
-
|
|
28876
|
-
|
|
28877
|
-
|
|
28878
|
-
|
|
28879
|
-
|
|
28880
|
-
|
|
28881
|
-
|
|
28882
|
-
|
|
28883
|
-
|
|
28884
|
-
|
|
28885
|
-
|
|
28886
|
-
|
|
28887
|
-
|
|
28888
|
-
|
|
28889
|
-
|
|
28890
|
-
|
|
28891
|
-
|
|
28892
|
-
|
|
28893
|
-
|
|
28894
|
-
|
|
28895
|
-
|
|
28896
|
-
|
|
28897
|
-
|
|
28898
|
-
|
|
28899
|
-
|
|
28900
|
-
|
|
28901
|
-
|
|
28902
|
-
|
|
28903
|
-
|
|
28904
|
-
|
|
28905
|
-
|
|
28906
|
-
|
|
28907
|
-
|
|
28908
|
-
|
|
28909
|
-
|
|
28910
|
-
|
|
28911
|
-
|
|
28912
|
-
|
|
28913
|
-
|
|
28914
|
-
|
|
28915
|
-
|
|
28916
|
-
|
|
28917
|
-
|
|
28918
|
-
|
|
28919
|
-
|
|
28920
|
-
|
|
28921
|
-
|
|
28922
|
-
|
|
28923
|
-
|
|
28924
|
-
|
|
28925
|
-
|
|
28926
|
-
|
|
28927
|
-
|
|
28928
|
-
]
|
|
28929
|
-
}),
|
|
28930
|
-
pinnedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
28931
|
-
className: "whitespace-nowrap",
|
|
28932
|
-
children: [
|
|
28933
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: "Pinned:" }),
|
|
28934
|
-
" ",
|
|
28935
|
-
pinnedCount
|
|
28936
|
-
]
|
|
28937
|
-
}),
|
|
28938
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", {
|
|
28939
|
-
className: "mt-2 text-gray-500 dark:text-gray-500 leading-snug",
|
|
28940
|
-
children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: "Tips:" }), /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("ul", {
|
|
28941
|
-
className: "mt-1 ml-1 space-y-0.5",
|
|
28942
|
-
children: [
|
|
28943
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: "• Drag nodes to reposition" }),
|
|
28944
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: "• Double-click to pin/unpin" }),
|
|
28945
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: "• Double-click canvas to unpin all" }),
|
|
28946
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: "• Scroll to zoom" })
|
|
28947
|
-
]
|
|
28948
|
-
})]
|
|
28949
|
-
})
|
|
28950
|
-
]
|
|
28951
|
-
})]
|
|
28884
|
+
const transformRef = (0, import_react.useRef)(transform);
|
|
28885
|
+
const dragNodeRef = (0, import_react.useRef)(null);
|
|
28886
|
+
const dragActiveRef = (0, import_react.useRef)(false);
|
|
28887
|
+
const [pinnedNodes, setPinnedNodes] = (0, import_react.useState)(/* @__PURE__ */ new Set());
|
|
28888
|
+
const internalDragEnabledRef = (0, import_react.useRef)(enableDrag);
|
|
28889
|
+
const [layout, setLayout] = (0, import_react.useState)(externalLayout || "force");
|
|
28890
|
+
(0, import_react.useEffect)(() => {
|
|
28891
|
+
if (externalLayout && externalLayout !== layout) setLayout(externalLayout);
|
|
28892
|
+
}, [externalLayout, layout]);
|
|
28893
|
+
const handleLayoutChange = (0, import_react.useCallback)((newLayout) => {
|
|
28894
|
+
setLayout(newLayout);
|
|
28895
|
+
onLayoutChange?.(newLayout);
|
|
28896
|
+
}, [onLayoutChange]);
|
|
28897
|
+
(0, import_react.useEffect)(() => {
|
|
28898
|
+
internalDragEnabledRef.current = enableDrag;
|
|
28899
|
+
}, [enableDrag]);
|
|
28900
|
+
const { restart, stop, setForcesEnabled } = useSimulationControls();
|
|
28901
|
+
const { nodes } = useGraphLayout(initialNodes, width, height, layout, restart);
|
|
28902
|
+
(0, import_react.useEffect)(() => {
|
|
28903
|
+
setForcesEnabled(!(manualLayout || pinnedNodes.size > 0));
|
|
28904
|
+
}, [
|
|
28905
|
+
manualLayout,
|
|
28906
|
+
pinnedNodes,
|
|
28907
|
+
setForcesEnabled
|
|
28908
|
+
]);
|
|
28909
|
+
(0, import_react.useImperativeHandle)(ref, () => useImperativeHandleMethods({
|
|
28910
|
+
nodes,
|
|
28911
|
+
pinnedNodes,
|
|
28912
|
+
setPinnedNodes,
|
|
28913
|
+
restart,
|
|
28914
|
+
width,
|
|
28915
|
+
height,
|
|
28916
|
+
layout,
|
|
28917
|
+
handleLayoutChange,
|
|
28918
|
+
svgRef,
|
|
28919
|
+
gRef,
|
|
28920
|
+
setTransform,
|
|
28921
|
+
internalDragEnabledRef
|
|
28922
|
+
}), [
|
|
28923
|
+
nodes,
|
|
28924
|
+
pinnedNodes,
|
|
28925
|
+
restart,
|
|
28926
|
+
width,
|
|
28927
|
+
height,
|
|
28928
|
+
layout,
|
|
28929
|
+
handleLayoutChange,
|
|
28930
|
+
setForcesEnabled
|
|
28931
|
+
]);
|
|
28932
|
+
(0, import_react.useEffect)(() => {
|
|
28933
|
+
onManualLayoutChange?.(manualLayout);
|
|
28934
|
+
}, [manualLayout, onManualLayoutChange]);
|
|
28935
|
+
useGraphZoom(svgRef, gRef, enableZoom, setTransform, transformRef);
|
|
28936
|
+
useWindowDrag(enableDrag, svgRef, transformRef, dragActiveRef, dragNodeRef, () => {
|
|
28937
|
+
setForcesEnabled(true);
|
|
28938
|
+
restart();
|
|
28952
28939
|
});
|
|
28953
|
-
|
|
28954
|
-
|
|
28940
|
+
(0, import_react.useEffect)(() => {
|
|
28941
|
+
if (!gRef.current) return;
|
|
28942
|
+
const g = select_default$1(gRef.current);
|
|
28943
|
+
g.selectAll("g.node").each(function() {
|
|
28944
|
+
const d = select_default$1(this).datum();
|
|
28945
|
+
if (d) select_default$1(this).attr("transform", `translate(${d.x || 0},${d.y || 0})`);
|
|
28946
|
+
});
|
|
28947
|
+
g.selectAll("line").each(function() {
|
|
28948
|
+
const l = select_default$1(this).datum();
|
|
28949
|
+
if (!l) return;
|
|
28950
|
+
const s = typeof l.source === "object" ? l.source : nodes.find((n) => n.id === l.source);
|
|
28951
|
+
const t = typeof l.target === "object" ? l.target : nodes.find((n) => n.id === l.target);
|
|
28952
|
+
if (s && t) select_default$1(this).attr("x1", s.x).attr("y1", s.y).attr("x2", t.x).attr("y2", t.y);
|
|
28953
|
+
});
|
|
28954
|
+
}, [nodes, initialLinks]);
|
|
28955
|
+
const { handleDragStart, handleNodeDoubleClick } = useNodeInteractions(enableDrag, nodes, pinnedNodes, setPinnedNodes, restart, stop);
|
|
28956
|
+
(0, import_react.useEffect)(() => {
|
|
28957
|
+
if (!gRef.current || !enableDrag) return;
|
|
28958
|
+
const g = select_default$1(gRef.current);
|
|
28959
|
+
const dragBehavior = drag_default().on("start", (event) => {
|
|
28960
|
+
const id = (event.sourceEvent?.target || event.target).closest?.("g.node")?.getAttribute("data-id");
|
|
28961
|
+
if (!id || !internalDragEnabledRef.current) return;
|
|
28962
|
+
const node = nodes.find((n) => n.id === id);
|
|
28963
|
+
if (!node) return;
|
|
28964
|
+
if (!event.active) restart();
|
|
28965
|
+
dragActiveRef.current = true;
|
|
28966
|
+
dragNodeRef.current = node;
|
|
28967
|
+
}).on("drag", (event) => {
|
|
28968
|
+
if (!dragActiveRef.current || !dragNodeRef.current || !svgRef.current) return;
|
|
28969
|
+
const rect = svgRef.current.getBoundingClientRect();
|
|
28970
|
+
dragNodeRef.current.fx = (event.sourceEvent.clientX - rect.left - transform.x) / transform.k;
|
|
28971
|
+
dragNodeRef.current.fy = (event.sourceEvent.clientY - rect.top - transform.y) / transform.k;
|
|
28972
|
+
}).on("end", () => {
|
|
28973
|
+
setForcesEnabled(true);
|
|
28974
|
+
restart();
|
|
28975
|
+
});
|
|
28976
|
+
g.selectAll("g.node").call(dragBehavior);
|
|
28977
|
+
return () => {
|
|
28978
|
+
g.selectAll("g.node").on(".drag", null);
|
|
28979
|
+
};
|
|
28980
|
+
}, [
|
|
28981
|
+
gRef,
|
|
28982
|
+
enableDrag,
|
|
28983
|
+
nodes,
|
|
28984
|
+
transform,
|
|
28985
|
+
restart,
|
|
28986
|
+
setForcesEnabled
|
|
28987
|
+
]);
|
|
28988
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GraphCanvas, {
|
|
28989
|
+
svgRef,
|
|
28990
|
+
gRef,
|
|
28991
|
+
width,
|
|
28992
|
+
height,
|
|
28993
|
+
className,
|
|
28994
|
+
nodes,
|
|
28995
|
+
links: initialLinks,
|
|
28996
|
+
pinnedNodes,
|
|
28997
|
+
selectedNodeId,
|
|
28998
|
+
hoveredNodeId,
|
|
28999
|
+
defaultNodeColor,
|
|
29000
|
+
defaultNodeSize,
|
|
29001
|
+
defaultLinkColor,
|
|
29002
|
+
defaultLinkWidth,
|
|
29003
|
+
showNodeLabels,
|
|
29004
|
+
showLinkLabels,
|
|
29005
|
+
onNodeClick,
|
|
29006
|
+
onNodeHover,
|
|
29007
|
+
onLinkClick,
|
|
29008
|
+
packageBounds,
|
|
29009
|
+
handleNodeDoubleClick,
|
|
29010
|
+
handleDragStart,
|
|
29011
|
+
restart,
|
|
29012
|
+
setPinnedNodes
|
|
29013
|
+
});
|
|
29014
|
+
});
|
|
29015
|
+
ForceDirectedGraph.displayName = "ForceDirectedGraph";
|
|
28955
29016
|
//#endregion
|
|
28956
29017
|
//#region src/components/LegendPanel.tsx
|
|
28957
29018
|
function LegendItemWithToggle({ color, label, isGlow = false, isLine = false, colors, isVisible, onToggle }) {
|
|
@@ -29286,4 +29347,4 @@ function App() {
|
|
|
29286
29347
|
(0, import_client.createRoot)(document.getElementById("root")).render(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.StrictMode, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(App, {}) }));
|
|
29287
29348
|
//#endregion
|
|
29288
29349
|
|
|
29289
|
-
//# sourceMappingURL=index-
|
|
29350
|
+
//# sourceMappingURL=index-CkabxYJ5.js.map
|