@eventcatalog/visualiser 4.1.0 → 4.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/dist/index.mjs CHANGED
@@ -1,10 +1,10 @@
1
1
  // src/components/NodeGraph.tsx
2
2
  import {
3
- useEffect as useEffect9,
3
+ useEffect as useEffect10,
4
4
  useMemo as useMemo18,
5
5
  useState as useState15,
6
- useCallback as useCallback12,
7
- useRef as useRef7,
6
+ useCallback as useCallback13,
7
+ useRef as useRef8,
8
8
  memo as memo40
9
9
  } from "react";
10
10
  import { createPortal } from "react-dom";
@@ -5210,10 +5210,12 @@ var FlowExpandedNode_default = memo21(function FlowExpandedNode({
5210
5210
  });
5211
5211
 
5212
5212
  // src/nodes/Entity.tsx
5213
- import { Handle as Handle16, Position as Position15 } from "@xyflow/react";
5213
+ import { Handle as Handle16, Position as Position15, useUpdateNodeInternals } from "@xyflow/react";
5214
5214
  import * as ContextMenu2 from "@radix-ui/react-context-menu";
5215
- import { memo as memo22, useState as useState4, useMemo as useMemo9 } from "react";
5215
+ import { memo as memo22, useCallback as useCallback3, useEffect as useEffect3, useMemo as useMemo9, useRef as useRef3, useState as useState4 } from "react";
5216
+ import { ChevronDownIcon, ChevronRightIcon } from "@heroicons/react/20/solid";
5216
5217
  import { Fragment as Fragment5, jsx as jsx25, jsxs as jsxs23 } from "react/jsx-runtime";
5218
+ var ENTITY_TARGET_HANDLE_ID = "__eventcatalog-entity-target";
5217
5219
  function classNames15(...classes) {
5218
5220
  return classes.filter(Boolean).join(" ");
5219
5221
  }
@@ -5223,12 +5225,27 @@ var getPropertyTypeLabel = (property) => {
5223
5225
  }
5224
5226
  return property.type;
5225
5227
  };
5228
+ var getNestedEntityProperties = (property) => {
5229
+ if (property.properties?.length) return property.properties;
5230
+ if (property.type === "array" && property.items?.properties?.length) {
5231
+ return property.items.properties;
5232
+ }
5233
+ return [];
5234
+ };
5226
5235
  var Entity_default = memo22(function EntityNode({
5236
+ id,
5227
5237
  data,
5228
5238
  sourcePosition,
5229
5239
  targetPosition
5230
5240
  }) {
5231
- const { mode, entity, externalToDomain, domainName } = data;
5241
+ const {
5242
+ mode,
5243
+ entity,
5244
+ externalToDomain,
5245
+ domainName,
5246
+ entityTargetHandle = ENTITY_TARGET_HANDLE_ID,
5247
+ referencePropertyNames = EMPTY_ARRAY
5248
+ } = data;
5232
5249
  const {
5233
5250
  name,
5234
5251
  version,
@@ -5243,7 +5260,123 @@ var Entity_default = memo22(function EntityNode({
5243
5260
  } = styles || {};
5244
5261
  const Icon = useMemo9(() => getIcon(icon), [icon]);
5245
5262
  const [hoveredProperty, setHoveredProperty] = useState4(null);
5263
+ const [expandedProperties, setExpandedProperties] = useState4(
5264
+ () => /* @__PURE__ */ new Set()
5265
+ );
5266
+ const previousExpandedProperties = useRef3(expandedProperties);
5267
+ const updateNodeInternals = useUpdateNodeInternals();
5246
5268
  const portalContainer = usePortalContainer();
5269
+ const referenceProperties = useMemo9(
5270
+ () => new Set(referencePropertyNames),
5271
+ [referencePropertyNames]
5272
+ );
5273
+ const toggleProperty = useCallback3((propertyPath) => {
5274
+ setExpandedProperties((current) => {
5275
+ const next = new Set(current);
5276
+ if (next.has(propertyPath)) {
5277
+ next.delete(propertyPath);
5278
+ } else {
5279
+ next.add(propertyPath);
5280
+ }
5281
+ return next;
5282
+ });
5283
+ }, []);
5284
+ useEffect3(() => {
5285
+ if (previousExpandedProperties.current === expandedProperties) return;
5286
+ previousExpandedProperties.current = expandedProperties;
5287
+ updateNodeInternals(id);
5288
+ }, [expandedProperties, id, updateNodeInternals]);
5289
+ const renderPropertyRows = (entityProperties, depth = 0, parentPath = "") => entityProperties.map((property, index) => {
5290
+ const propertyPath = parentPath ? `${parentPath}.${property.name}` : property.name;
5291
+ const propertyKey = `${propertyPath}-${index}`;
5292
+ const isHovered = hoveredProperty === propertyKey;
5293
+ const nestedProperties = getNestedEntityProperties(property);
5294
+ const isExpandable = nestedProperties.length > 0;
5295
+ const isExpanded = expandedProperties.has(propertyPath);
5296
+ const isTopLevel = depth === 0;
5297
+ const referencedEntityId = property.references || (isTopLevel && referenceProperties.has(property.name) ? property.items?.type : void 0);
5298
+ return /* @__PURE__ */ jsxs23("div", { children: [
5299
+ /* @__PURE__ */ jsxs23(
5300
+ "div",
5301
+ {
5302
+ className: classNames15(
5303
+ "relative flex items-center justify-between py-2 pr-4 hover:bg-[rgb(var(--ec-page-border)/0.2)]",
5304
+ isExpandable && "nodrag nopan cursor-pointer"
5305
+ ),
5306
+ style: { paddingLeft: `${16 + depth * 16}px` },
5307
+ role: isExpandable ? "button" : void 0,
5308
+ tabIndex: isExpandable ? 0 : void 0,
5309
+ "aria-label": isExpandable ? `${isExpanded ? "Collapse" : "Expand"} ${property.name}` : void 0,
5310
+ "aria-expanded": isExpandable ? isExpanded : void 0,
5311
+ onClick: (event) => {
5312
+ if (!isExpandable) return;
5313
+ const target = event.target;
5314
+ if (target.closest(".react-flow__handle")) return;
5315
+ toggleProperty(propertyPath);
5316
+ },
5317
+ onKeyDown: (event) => {
5318
+ if (!isExpandable || event.key !== "Enter" && event.key !== " ")
5319
+ return;
5320
+ event.preventDefault();
5321
+ toggleProperty(propertyPath);
5322
+ },
5323
+ onMouseEnter: () => property.description && setHoveredProperty(propertyKey),
5324
+ onMouseLeave: () => setHoveredProperty(null),
5325
+ children: [
5326
+ isTopLevel && /* @__PURE__ */ jsxs23(Fragment5, { children: [
5327
+ /* @__PURE__ */ jsx25(
5328
+ Handle16,
5329
+ {
5330
+ type: "target",
5331
+ position: Position15.Left,
5332
+ id: `${property.name}-target`,
5333
+ className: "!w-3 !h-3 !bg-[rgb(var(--ec-card-bg))] !border-2 !border-[rgb(var(--ec-page-border))] !rounded-full !left-[-0px]",
5334
+ style: HANDLE_LEFT_OFFSET_STYLE
5335
+ }
5336
+ ),
5337
+ /* @__PURE__ */ jsx25(
5338
+ Handle16,
5339
+ {
5340
+ type: "source",
5341
+ position: Position15.Right,
5342
+ id: `${property.name}-source`,
5343
+ className: "!w-3 !h-3 !bg-[rgb(var(--ec-card-bg))] !border-2 !border-[rgb(var(--ec-page-border))] !rounded-full !right-[-0px]",
5344
+ style: HANDLE_RIGHT_OFFSET_STYLE
5345
+ }
5346
+ )
5347
+ ] }),
5348
+ /* @__PURE__ */ jsxs23("div", { className: "flex-1 flex items-center justify-between gap-3 min-w-0", children: [
5349
+ /* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-1 min-w-0", children: [
5350
+ isExpandable && /* @__PURE__ */ jsx25(
5351
+ "span",
5352
+ {
5353
+ className: "shrink-0 text-[rgb(var(--ec-page-text-muted))]",
5354
+ "aria-hidden": "true",
5355
+ children: isExpanded ? /* @__PURE__ */ jsx25(ChevronDownIcon, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx25(ChevronRightIcon, { className: "h-3.5 w-3.5" })
5356
+ }
5357
+ ),
5358
+ /* @__PURE__ */ jsx25("span", { className: "text-sm font-medium text-[rgb(var(--ec-page-text))] truncate", children: property.name }),
5359
+ property.required && /* @__PURE__ */ jsx25("span", { className: "text-red-500 text-xs", children: "*" })
5360
+ ] }),
5361
+ /* @__PURE__ */ jsx25("span", { className: "text-sm text-[rgb(var(--ec-page-text-muted))] font-mono shrink-0", children: getPropertyTypeLabel(property) })
5362
+ ] }),
5363
+ referencedEntityId && /* @__PURE__ */ jsx25("div", { className: "absolute right-2 top-1/2 transform -translate-y-1/2", children: /* @__PURE__ */ jsx25(
5364
+ "div",
5365
+ {
5366
+ className: "w-2 h-2 bg-blue-500 rounded-full",
5367
+ title: `References ${referencedEntityId}`
5368
+ }
5369
+ ) }),
5370
+ isHovered && property.description && /* @__PURE__ */ jsxs23("div", { className: "absolute left-full ml-2 top-1/2 transform -translate-y-1/2 z-[9999] w-[200px] bg-gray-900 text-white text-xs rounded-lg py-2 px-3 pointer-events-none shadow-xl max-w-xl opacity-100", children: [
5371
+ /* @__PURE__ */ jsx25("div", { className: "text-gray-200 whitespace-normal break-words", children: property.description }),
5372
+ /* @__PURE__ */ jsx25("div", { className: "absolute right-full top-1/2 transform -translate-y-1/2 border-4 border-transparent border-r-gray-900" })
5373
+ ] })
5374
+ ]
5375
+ }
5376
+ ),
5377
+ isExpandable && isExpanded && /* @__PURE__ */ jsx25("div", { className: "divide-y divide-[rgb(var(--ec-page-border))] border-t border-[rgb(var(--ec-page-border))] bg-[rgb(var(--ec-content-hover)/0.18)]", children: renderPropertyRows(nestedProperties, depth + 1, propertyPath) })
5378
+ ] }, propertyKey);
5379
+ });
5247
5380
  return /* @__PURE__ */ jsxs23(ContextMenu2.Root, { children: [
5248
5381
  /* @__PURE__ */ jsx25(ContextMenu2.Trigger, { children: /* @__PURE__ */ jsxs23(
5249
5382
  "div",
@@ -5257,10 +5390,20 @@ var Entity_default = memo22(function EntityNode({
5257
5390
  "div",
5258
5391
  {
5259
5392
  className: classNames15(
5260
- "px-4 py-2 rounded-t-lg border-b border-[rgb(var(--ec-page-border))]",
5393
+ "relative px-4 py-2 rounded-t-lg border-b border-[rgb(var(--ec-page-border))]",
5261
5394
  externalToDomain ? "bg-amber-500/20" : "bg-blue-500/15"
5262
5395
  ),
5263
5396
  children: [
5397
+ /* @__PURE__ */ jsx25(
5398
+ Handle16,
5399
+ {
5400
+ type: "target",
5401
+ position: Position15.Left,
5402
+ id: entityTargetHandle,
5403
+ className: "!w-3 !h-3 !bg-[rgb(var(--ec-card-bg))] !border-2 !border-[rgb(var(--ec-page-border))] !rounded-full !left-[-0px]",
5404
+ style: HANDLE_LEFT_OFFSET_STYLE
5405
+ }
5406
+ ),
5264
5407
  /* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-2 min-w-0", children: [
5265
5408
  Icon && /* @__PURE__ */ jsx25(Icon, { className: "w-4 h-4 text-[rgb(var(--ec-page-text-muted))]" }),
5266
5409
  /* @__PURE__ */ jsx25(
@@ -5286,59 +5429,7 @@ var Entity_default = memo22(function EntityNode({
5286
5429
  ]
5287
5430
  }
5288
5431
  ),
5289
- properties.length > 0 ? /* @__PURE__ */ jsx25("div", { className: "divide-y divide-[rgb(var(--ec-page-border))] relative", children: properties.map((property, index) => {
5290
- const propertyKey = `${property.name}-${index}`;
5291
- const isHovered = hoveredProperty === propertyKey;
5292
- return /* @__PURE__ */ jsxs23(
5293
- "div",
5294
- {
5295
- className: "relative flex items-center justify-between px-4 py-2 hover:bg-[rgb(var(--ec-page-border)/0.2)]",
5296
- onMouseEnter: () => property.description && setHoveredProperty(propertyKey),
5297
- onMouseLeave: () => setHoveredProperty(null),
5298
- children: [
5299
- /* @__PURE__ */ jsx25(
5300
- Handle16,
5301
- {
5302
- type: "target",
5303
- position: Position15.Left,
5304
- id: `${property.name}-target`,
5305
- className: "!w-3 !h-3 !bg-[rgb(var(--ec-card-bg))] !border-2 !border-[rgb(var(--ec-page-border))] !rounded-full !left-[-0px]",
5306
- style: HANDLE_LEFT_OFFSET_STYLE
5307
- }
5308
- ),
5309
- /* @__PURE__ */ jsx25(
5310
- Handle16,
5311
- {
5312
- type: "source",
5313
- position: Position15.Right,
5314
- id: `${property.name}-source`,
5315
- className: "!w-3 !h-3 !bg-[rgb(var(--ec-card-bg))] !border-2 !border-[rgb(var(--ec-page-border))] !rounded-full !right-[-0px]",
5316
- style: HANDLE_RIGHT_OFFSET_STYLE
5317
- }
5318
- ),
5319
- /* @__PURE__ */ jsxs23("div", { className: "flex-1 flex items-center justify-between", children: [
5320
- /* @__PURE__ */ jsxs23("div", { className: "flex items-center gap-1", children: [
5321
- /* @__PURE__ */ jsx25("span", { className: "text-sm font-medium text-[rgb(var(--ec-page-text))]", children: property.name }),
5322
- property.required && /* @__PURE__ */ jsx25("span", { className: "text-red-500 text-xs", children: "*" })
5323
- ] }),
5324
- /* @__PURE__ */ jsx25("span", { className: "text-sm text-[rgb(var(--ec-page-text-muted))] font-mono", children: getPropertyTypeLabel(property) })
5325
- ] }),
5326
- (property.references || property.type === "array" && property.items?.type) && /* @__PURE__ */ jsx25("div", { className: "absolute right-2 top-1/2 transform -translate-y-1/2", children: /* @__PURE__ */ jsx25(
5327
- "div",
5328
- {
5329
- className: "w-2 h-2 bg-blue-500 rounded-full",
5330
- title: `References ${property.references || property.items.type}`
5331
- }
5332
- ) }),
5333
- isHovered && property.description && /* @__PURE__ */ jsxs23("div", { className: "absolute left-full ml-2 top-1/2 transform -translate-y-1/2 z-[9999] w-[200px] bg-gray-900 text-white text-xs rounded-lg py-2 px-3 pointer-events-none shadow-xl max-w-xl opacity-100", children: [
5334
- /* @__PURE__ */ jsx25("div", { className: "text-gray-200 whitespace-normal break-words", children: property.description }),
5335
- /* @__PURE__ */ jsx25("div", { className: "absolute right-full top-1/2 transform -translate-y-1/2 border-4 border-transparent border-r-gray-900" })
5336
- ] })
5337
- ]
5338
- },
5339
- propertyKey
5340
- );
5341
- }) }) : /* @__PURE__ */ jsx25("div", { className: "px-4 py-3 text-sm text-[rgb(var(--ec-page-text-muted))] text-center", children: "No properties defined" }),
5432
+ properties.length > 0 ? /* @__PURE__ */ jsx25("div", { className: "divide-y divide-[rgb(var(--ec-page-border))] relative", children: renderPropertyRows(properties) }) : /* @__PURE__ */ jsx25("div", { className: "px-4 py-3 text-sm text-[rgb(var(--ec-page-text-muted))] text-center", children: "No properties defined" }),
5342
5433
  properties.length === 0 && /* @__PURE__ */ jsxs23(Fragment5, { children: [
5343
5434
  targetPosition && /* @__PURE__ */ jsx25(Handle16, { type: "target", position: targetPosition }),
5344
5435
  sourcePosition && /* @__PURE__ */ jsx25(Handle16, { type: "source", position: sourcePosition })
@@ -5576,7 +5667,7 @@ import {
5576
5667
  Position as Position17
5577
5668
  } from "@xyflow/react";
5578
5669
  import * as ContextMenu3 from "@radix-ui/react-context-menu";
5579
- import { memo as memo25, useState as useState5, useCallback as useCallback3, useMemo as useMemo10 } from "react";
5670
+ import { memo as memo25, useState as useState5, useCallback as useCallback4, useMemo as useMemo10 } from "react";
5580
5671
  import { jsx as jsx28, jsxs as jsxs26 } from "react/jsx-runtime";
5581
5672
  var Domain_default = memo25(function DomainNode({ data, id: nodeId }) {
5582
5673
  const { mode, domain } = data;
@@ -5589,7 +5680,7 @@ var Domain_default = memo25(function DomainNode({ data, id: nodeId }) {
5589
5680
  const Icon = useMemo10(() => getIcon(icon), [icon]);
5590
5681
  const ServerIcon5 = useMemo10(() => getIcon("ServerIcon"), []);
5591
5682
  const portalContainer = usePortalContainer();
5592
- const handleSelectionChange = useCallback3(
5683
+ const handleSelectionChange = useCallback4(
5593
5684
  ({ nodes: selectedNodes }) => {
5594
5685
  if (selectedNodes.length === 0) {
5595
5686
  setHighlightedServices(/* @__PURE__ */ new Set());
@@ -7177,9 +7268,9 @@ function LabelledStepEdge(props) {
7177
7268
  // src/components/VisualiserSearch.tsx
7178
7269
  import {
7179
7270
  useState as useState6,
7180
- useCallback as useCallback4,
7181
- useRef as useRef3,
7182
- useEffect as useEffect3,
7271
+ useCallback as useCallback5,
7272
+ useRef as useRef4,
7273
+ useEffect as useEffect4,
7183
7274
  forwardRef,
7184
7275
  useImperativeHandle,
7185
7276
  memo as memo36
@@ -7264,11 +7355,11 @@ var VisualiserSearch = memo36(
7264
7355
  const [filteredSuggestions, setFilteredSuggestions] = useState6([]);
7265
7356
  const [showSuggestions, setShowSuggestions] = useState6(false);
7266
7357
  const [selectedSuggestionIndex, setSelectedSuggestionIndex] = useState6(-1);
7267
- const searchInputRef = useRef3(null);
7268
- const containerRef = useRef3(null);
7269
- const suggestionsListRef = useRef3(null);
7270
- const suggestionItemRefs = useRef3([]);
7271
- const hideSuggestions = useCallback4(() => {
7358
+ const searchInputRef = useRef4(null);
7359
+ const containerRef = useRef4(null);
7360
+ const suggestionsListRef = useRef4(null);
7361
+ const suggestionItemRefs = useRef4([]);
7362
+ const hideSuggestions = useCallback5(() => {
7272
7363
  setShowSuggestions(false);
7273
7364
  setSelectedSuggestionIndex(-1);
7274
7365
  }, []);
@@ -7279,7 +7370,7 @@ var VisualiserSearch = memo36(
7279
7370
  }),
7280
7371
  [hideSuggestions]
7281
7372
  );
7282
- const getNodeDisplayName = useCallback4((node) => {
7373
+ const getNodeDisplayName = useCallback5((node) => {
7283
7374
  if (node.type === "messageGroup") {
7284
7375
  return node.data?.groupName || node.id;
7285
7376
  }
@@ -7300,7 +7391,7 @@ var VisualiserSearch = memo36(
7300
7391
  const version = message?.version || agent?.version || agentTool?.version || service?.version || domain?.version || system?.version || entity?.version || channel?.version || dataProduct?.version || data?.version || node.data?.version;
7301
7392
  return formatVersionedName(name, version);
7302
7393
  }, []);
7303
- const getNodeResourceKey = useCallback4(
7394
+ const getNodeResourceKey = useCallback5(
7304
7395
  (node, label) => {
7305
7396
  if (node.type === "messageGroup" || node.type === "messageGroupExpanded") {
7306
7397
  return `${node.type}:${node.id}`.toLowerCase();
@@ -7316,7 +7407,7 @@ var VisualiserSearch = memo36(
7316
7407
  },
7317
7408
  []
7318
7409
  );
7319
- const dedupeSearchSuggestions = useCallback4(
7410
+ const dedupeSearchSuggestions = useCallback5(
7320
7411
  (suggestions) => {
7321
7412
  const uniqueSuggestions = [];
7322
7413
  const indexByResourceKey = /* @__PURE__ */ new Map();
@@ -7340,7 +7431,7 @@ var VisualiserSearch = memo36(
7340
7431
  },
7341
7432
  []
7342
7433
  );
7343
- const getSearchSuggestions = useCallback4(
7434
+ const getSearchSuggestions = useCallback5(
7344
7435
  (nodesToIndex) => {
7345
7436
  const suggestions = nodesToIndex.flatMap((node) => {
7346
7437
  if (node.type === "system-group") return [];
@@ -7386,7 +7477,7 @@ var VisualiserSearch = memo36(
7386
7477
  },
7387
7478
  [dedupeSearchSuggestions, getNodeDisplayName, getNodeResourceKey]
7388
7479
  );
7389
- const getNodeTypeMeta = useCallback4((nodeType) => {
7480
+ const getNodeTypeMeta = useCallback5((nodeType) => {
7390
7481
  const meta = {
7391
7482
  events: {
7392
7483
  label: "Event",
@@ -7534,7 +7625,7 @@ var VisualiserSearch = memo36(
7534
7625
  badgeClass: "border-gray-500/25 bg-gray-500/10 text-gray-700 dark:text-gray-300"
7535
7626
  };
7536
7627
  }, []);
7537
- const handleSearchChange = useCallback4(
7628
+ const handleSearchChange = useCallback5(
7538
7629
  (event) => {
7539
7630
  const query = event.target.value;
7540
7631
  setSearchQuery(query);
@@ -7554,7 +7645,7 @@ var VisualiserSearch = memo36(
7554
7645
  },
7555
7646
  [nodes, getSearchSuggestions]
7556
7647
  );
7557
- const handleSearchFocus = useCallback4(() => {
7648
+ const handleSearchFocus = useCallback5(() => {
7558
7649
  const suggestions = getSearchSuggestions(nodes);
7559
7650
  const search = searchQuery.toLowerCase();
7560
7651
  setFilteredSuggestions(
@@ -7565,7 +7656,7 @@ var VisualiserSearch = memo36(
7565
7656
  setShowSuggestions(true);
7566
7657
  setSelectedSuggestionIndex(-1);
7567
7658
  }, [nodes, searchQuery, getSearchSuggestions]);
7568
- const handleSuggestionClick = useCallback4(
7659
+ const handleSuggestionClick = useCallback5(
7569
7660
  (suggestion) => {
7570
7661
  setSearchQuery("");
7571
7662
  setFilteredSuggestions([]);
@@ -7575,7 +7666,7 @@ var VisualiserSearch = memo36(
7575
7666
  },
7576
7667
  [onNodeSelect]
7577
7668
  );
7578
- const handleSearchKeyDown = useCallback4(
7669
+ const handleSearchKeyDown = useCallback5(
7579
7670
  (event) => {
7580
7671
  switch (event.key) {
7581
7672
  case "ArrowDown":
@@ -7615,7 +7706,7 @@ var VisualiserSearch = memo36(
7615
7706
  handleSuggestionClick
7616
7707
  ]
7617
7708
  );
7618
- const clearSearch = useCallback4(() => {
7709
+ const clearSearch = useCallback5(() => {
7619
7710
  setSearchQuery("");
7620
7711
  setShowSuggestions(false);
7621
7712
  setFilteredSuggestions([]);
@@ -7625,13 +7716,13 @@ var VisualiserSearch = memo36(
7625
7716
  searchInputRef.current.focus();
7626
7717
  }
7627
7718
  }, [onClear]);
7628
- useEffect3(() => {
7719
+ useEffect4(() => {
7629
7720
  suggestionItemRefs.current = suggestionItemRefs.current.slice(
7630
7721
  0,
7631
7722
  filteredSuggestions.length
7632
7723
  );
7633
7724
  }, [filteredSuggestions.length]);
7634
- useEffect3(() => {
7725
+ useEffect4(() => {
7635
7726
  if (!showSuggestions || selectedSuggestionIndex < 0) return;
7636
7727
  const list = suggestionsListRef.current;
7637
7728
  const item = suggestionItemRefs.current[selectedSuggestionIndex];
@@ -7650,7 +7741,7 @@ var VisualiserSearch = memo36(
7650
7741
  selectedSuggestionIndex,
7651
7742
  filteredSuggestions.length
7652
7743
  ]);
7653
- useEffect3(() => {
7744
+ useEffect4(() => {
7654
7745
  const handleClickOutside = (event) => {
7655
7746
  if (containerRef.current && !containerRef.current.contains(event.target)) {
7656
7747
  setShowSuggestions(false);
@@ -7761,13 +7852,13 @@ var VisualiserSearch_default = VisualiserSearch;
7761
7852
  // src/components/StepWalkthrough.tsx
7762
7853
  import {
7763
7854
  useState as useState7,
7764
- useEffect as useEffect4,
7765
- useCallback as useCallback5,
7855
+ useEffect as useEffect5,
7856
+ useCallback as useCallback6,
7766
7857
  useMemo as useMemo15,
7767
- useRef as useRef4,
7858
+ useRef as useRef5,
7768
7859
  memo as memo37
7769
7860
  } from "react";
7770
- import { ChevronLeftIcon, ChevronRightIcon } from "@heroicons/react/24/outline";
7861
+ import { ChevronLeftIcon, ChevronRightIcon as ChevronRightIcon2 } from "@heroicons/react/24/outline";
7771
7862
  import { Fragment as Fragment10, jsx as jsx42, jsxs as jsxs39 } from "react/jsx-runtime";
7772
7863
  var StepWalkthrough_default = memo37(function StepWalkthrough({
7773
7864
  nodes,
@@ -7781,19 +7872,19 @@ var StepWalkthrough_default = memo37(function StepWalkthrough({
7781
7872
  const [availablePaths, setAvailablePaths] = useState7([]);
7782
7873
  const [selectedPathIndex, setSelectedPathIndex] = useState7(0);
7783
7874
  const [startNodeId, setStartNodeId] = useState7(null);
7784
- const nodeIdsKeyRef = useRef4("");
7875
+ const nodeIdsKeyRef = useRef5("");
7785
7876
  const computedNodeIdsKey = nodes.map((n) => n.id).join(",");
7786
7877
  if (computedNodeIdsKey !== nodeIdsKeyRef.current) {
7787
7878
  nodeIdsKeyRef.current = computedNodeIdsKey;
7788
7879
  }
7789
7880
  const nodeIdsKey = nodeIdsKeyRef.current;
7790
- const edgeKeyRef = useRef4("");
7881
+ const edgeKeyRef = useRef5("");
7791
7882
  const computedEdgeKey = edges.map((e) => `${e.source}-${e.target}`).join(",");
7792
7883
  if (computedEdgeKey !== edgeKeyRef.current) {
7793
7884
  edgeKeyRef.current = computedEdgeKey;
7794
7885
  }
7795
7886
  const edgeKey = edgeKeyRef.current;
7796
- useEffect4(() => {
7887
+ useEffect5(() => {
7797
7888
  if (isFlowVisualization && nodes.length > 0) {
7798
7889
  const incomingEdgeMap = /* @__PURE__ */ new Map();
7799
7890
  nodes.forEach((node) => incomingEdgeMap.set(node.id, 0));
@@ -7815,7 +7906,7 @@ var StepWalkthrough_default = memo37(function StepWalkthrough({
7815
7906
  }
7816
7907
  }
7817
7908
  }, [nodeIdsKey, edgeKey, isFlowVisualization, startNodeId]);
7818
- useEffect4(() => {
7909
+ useEffect5(() => {
7819
7910
  if (currentNodeId) {
7820
7911
  const currentExists = nodes.some(
7821
7912
  (n) => n.id === currentNodeId
@@ -7844,7 +7935,7 @@ var StepWalkthrough_default = memo37(function StepWalkthrough({
7844
7935
  setAvailablePaths([]);
7845
7936
  }
7846
7937
  }, [currentNodeId, nodeIdsKey, edgeKey]);
7847
- const handleNextStep = useCallback5(() => {
7938
+ const handleNextStep = useCallback6(() => {
7848
7939
  if (currentStepIndex === -1) {
7849
7940
  if (startNodeId) {
7850
7941
  setPathHistory([startNodeId]);
@@ -7871,7 +7962,7 @@ var StepWalkthrough_default = memo37(function StepWalkthrough({
7871
7962
  currentNodeId,
7872
7963
  onStepChange
7873
7964
  ]);
7874
- const handlePreviousStep = useCallback5(() => {
7965
+ const handlePreviousStep = useCallback6(() => {
7875
7966
  if (currentStepIndex > 0) {
7876
7967
  const newIndex = currentStepIndex - 1;
7877
7968
  const prevNodeId = pathHistory[newIndex];
@@ -7884,10 +7975,10 @@ var StepWalkthrough_default = memo37(function StepWalkthrough({
7884
7975
  onStepChange(null);
7885
7976
  }
7886
7977
  }, [currentStepIndex, pathHistory, onStepChange]);
7887
- const handlePathSelection = useCallback5((index) => {
7978
+ const handlePathSelection = useCallback6((index) => {
7888
7979
  setSelectedPathIndex(index);
7889
7980
  }, []);
7890
- const handleFinish = useCallback5(() => {
7981
+ const handleFinish = useCallback6(() => {
7891
7982
  setCurrentNodeId(null);
7892
7983
  setCurrentStepIndex(-1);
7893
7984
  setPathHistory([]);
@@ -7992,7 +8083,7 @@ var StepWalkthrough_default = memo37(function StepWalkthrough({
7992
8083
  className: "flex items-center justify-center px-4 py-2 text-xs font-medium bg-[rgb(var(--ec-accent))] text-white rounded-md hover:bg-[rgb(var(--ec-accent-hover))] focus:outline-none focus:ring-2 focus:ring-[rgb(var(--ec-accent))] focus:ring-offset-2 transition-colors",
7993
8084
  children: [
7994
8085
  "Next",
7995
- /* @__PURE__ */ jsx42(ChevronRightIcon, { className: "w-4 h-4 ml-1" })
8086
+ /* @__PURE__ */ jsx42(ChevronRightIcon2, { className: "w-4 h-4 ml-1" })
7996
8087
  ]
7997
8088
  }
7998
8089
  ) : /* @__PURE__ */ jsx42(
@@ -8009,7 +8100,7 @@ var StepWalkthrough_default = memo37(function StepWalkthrough({
8009
8100
  });
8010
8101
 
8011
8102
  // src/components/StudioModal.tsx
8012
- import { useState as useState8, useCallback as useCallback6 } from "react";
8103
+ import { useState as useState8, useCallback as useCallback7 } from "react";
8013
8104
  import * as Dialog2 from "@radix-ui/react-dialog";
8014
8105
  import { CheckIcon, ClipboardIcon, ExternalLinkIcon } from "lucide-react";
8015
8106
  import { useReactFlow as useReactFlow2 } from "@xyflow/react";
@@ -8082,7 +8173,7 @@ var StudioModal = ({ isOpen, onClose }) => {
8082
8173
  const [copySuccess, setCopySuccess] = useState8(false);
8083
8174
  const portalContainer = usePortalContainer();
8084
8175
  const { toObject } = useReactFlow2();
8085
- const handleCopyToClipboard = useCallback6(async () => {
8176
+ const handleCopyToClipboard = useCallback7(async () => {
8086
8177
  const visualizerData = toObject();
8087
8178
  const studioData = exportNodeGraphForStudio(visualizerData);
8088
8179
  try {
@@ -8179,7 +8270,7 @@ var StudioModal = ({ isOpen, onClose }) => {
8179
8270
  var StudioModal_default = StudioModal;
8180
8271
 
8181
8272
  // src/components/FocusModeModal.tsx
8182
- import { useState as useState10, useCallback as useCallback8, useEffect as useEffect6 } from "react";
8273
+ import { useState as useState10, useCallback as useCallback9, useEffect as useEffect7 } from "react";
8183
8274
  import * as Dialog3 from "@radix-ui/react-dialog";
8184
8275
  import { XIcon as XIcon2, FocusIcon } from "lucide-react";
8185
8276
  import {
@@ -8189,10 +8280,10 @@ import {
8189
8280
  // src/components/FocusMode/FocusModeContent.tsx
8190
8281
  import {
8191
8282
  useMemo as useMemo16,
8192
- useCallback as useCallback7,
8193
- useEffect as useEffect5,
8283
+ useCallback as useCallback8,
8284
+ useEffect as useEffect6,
8194
8285
  useState as useState9,
8195
- useRef as useRef5
8286
+ useRef as useRef6
8196
8287
  } from "react";
8197
8288
  import {
8198
8289
  ReactFlow,
@@ -8463,16 +8554,16 @@ var FocusModeContent = ({
8463
8554
  const [needsFitView, setNeedsFitView] = useState9(false);
8464
8555
  const [hoveredEdgeId, setHoveredEdgeId] = useState9(null);
8465
8556
  const [isReady, setIsReady] = useState9(false);
8466
- const reactFlowInitialized = useRef5(false);
8467
- const animationTimeoutRef = useRef5(null);
8468
- useEffect5(() => {
8557
+ const reactFlowInitialized = useRef6(false);
8558
+ const animationTimeoutRef = useRef6(null);
8559
+ useEffect6(() => {
8469
8560
  return () => {
8470
8561
  if (animationTimeoutRef.current) {
8471
8562
  clearTimeout(animationTimeoutRef.current);
8472
8563
  }
8473
8564
  };
8474
8565
  }, []);
8475
- const calculateFocusedGraph = useCallback7(
8566
+ const calculateFocusedGraph = useCallback8(
8476
8567
  (centerId) => {
8477
8568
  const centerNode = allNodes.find((n) => n.id === centerId);
8478
8569
  if (!centerNode) {
@@ -8561,13 +8652,13 @@ var FocusModeContent = ({
8561
8652
  );
8562
8653
  const [displayNodes, setDisplayNodes] = useNodesState(initialGraph.nodes);
8563
8654
  const [displayEdges, setDisplayEdges] = useEdgesState(initialGraph.edges);
8564
- useEffect5(() => {
8655
+ useEffect6(() => {
8565
8656
  const { nodes, edges } = calculateFocusedGraph(centerNodeId);
8566
8657
  setDisplayNodes(nodes);
8567
8658
  setDisplayEdges(edges);
8568
8659
  setNeedsFitView(true);
8569
8660
  }, [centerNodeId, calculateFocusedGraph, setDisplayNodes, setDisplayEdges]);
8570
- useEffect5(() => {
8661
+ useEffect6(() => {
8571
8662
  if (needsFitView && reactFlowInitialized.current) {
8572
8663
  const timer = setTimeout(() => {
8573
8664
  fitView({ padding: 0.2, duration: 300 });
@@ -8576,14 +8667,14 @@ var FocusModeContent = ({
8576
8667
  return () => clearTimeout(timer);
8577
8668
  }
8578
8669
  }, [needsFitView, displayNodes, fitView]);
8579
- const handleInit = useCallback7(() => {
8670
+ const handleInit = useCallback8(() => {
8580
8671
  reactFlowInitialized.current = true;
8581
8672
  requestAnimationFrame(() => {
8582
8673
  fitView({ padding: 0.2, duration: 0 });
8583
8674
  setIsReady(true);
8584
8675
  });
8585
8676
  }, [fitView]);
8586
- const handleSwitchNode = useCallback7(
8677
+ const handleSwitchNode = useCallback8(
8587
8678
  (nodeId, direction) => {
8588
8679
  if (nodeId === centerNodeId || isAnimating) return;
8589
8680
  setIsAnimating(true);
@@ -8619,7 +8710,7 @@ var FocusModeContent = ({
8619
8710
  },
8620
8711
  [centerNodeId, isAnimating, setDisplayNodes, onSwitchCenter]
8621
8712
  );
8622
- const handleNodeClick = useCallback7(
8713
+ const handleNodeClick = useCallback8(
8623
8714
  (_, clickedNode) => {
8624
8715
  if (clickedNode.id === centerNodeId || isAnimating) return;
8625
8716
  const direction = (clickedNode.position?.x ?? 0) < 0 ? "left" : "right";
@@ -8627,13 +8718,13 @@ var FocusModeContent = ({
8627
8718
  },
8628
8719
  [centerNodeId, isAnimating, handleSwitchNode]
8629
8720
  );
8630
- const handleEdgeMouseEnter = useCallback7(
8721
+ const handleEdgeMouseEnter = useCallback8(
8631
8722
  (_, edge) => {
8632
8723
  setHoveredEdgeId(edge.id);
8633
8724
  },
8634
8725
  []
8635
8726
  );
8636
- const handleEdgeMouseLeave = useCallback7(() => {
8727
+ const handleEdgeMouseLeave = useCallback8(() => {
8637
8728
  setHoveredEdgeId(null);
8638
8729
  }, []);
8639
8730
  const edgesWithHover = useMemo16(() => {
@@ -8717,12 +8808,12 @@ var FocusModeModal = ({
8717
8808
  );
8718
8809
  const isDark = useDarkMode();
8719
8810
  const portalContainer = usePortalContainer();
8720
- useEffect6(() => {
8811
+ useEffect7(() => {
8721
8812
  if (isOpen && initialNodeId) {
8722
8813
  setCenterNodeId(initialNodeId);
8723
8814
  }
8724
8815
  }, [isOpen, initialNodeId]);
8725
- const handleSwitchCenter = useCallback8(
8816
+ const handleSwitchCenter = useCallback9(
8726
8817
  (newCenterNodeId, _direction) => {
8727
8818
  setCenterNodeId(newCenterNodeId);
8728
8819
  },
@@ -8876,7 +8967,7 @@ var FocusModeModal = ({
8876
8967
  var FocusModeModal_default = FocusModeModal;
8877
8968
 
8878
8969
  // src/components/MermaidView.tsx
8879
- import { useState as useState11, useEffect as useEffect7, useRef as useRef6, useCallback as useCallback9 } from "react";
8970
+ import { useState as useState11, useEffect as useEffect8, useRef as useRef7, useCallback as useCallback10 } from "react";
8880
8971
  import { CheckIcon as CheckIcon2, ClipboardIcon as ClipboardIcon2 } from "lucide-react";
8881
8972
 
8882
8973
  // src/utils/export-mermaid.ts
@@ -9170,17 +9261,17 @@ var MermaidView = ({
9170
9261
  const [previewSvg, setPreviewSvg] = useState11(null);
9171
9262
  const [previewError, setPreviewError] = useState11(null);
9172
9263
  const [isRendering, setIsRendering] = useState11(true);
9173
- const containerRef = useRef6(null);
9174
- const svgContainerRef = useRef6(null);
9175
- const panZoomInstanceRef = useRef6(null);
9176
- useEffect7(() => {
9264
+ const containerRef = useRef7(null);
9265
+ const svgContainerRef = useRef7(null);
9266
+ const panZoomInstanceRef = useRef7(null);
9267
+ useEffect8(() => {
9177
9268
  const code = convertToMermaid(nodes, edges, {
9178
9269
  includeStyles: true,
9179
9270
  direction: "LR"
9180
9271
  });
9181
9272
  setMermaidCode(code);
9182
9273
  }, [nodes, edges]);
9183
- useEffect7(() => {
9274
+ useEffect8(() => {
9184
9275
  if (!mermaidCode) return;
9185
9276
  let cancelled = false;
9186
9277
  setIsRendering(true);
@@ -9225,7 +9316,7 @@ var MermaidView = ({
9225
9316
  cancelled = true;
9226
9317
  };
9227
9318
  }, [mermaidCode]);
9228
- useEffect7(() => {
9319
+ useEffect8(() => {
9229
9320
  if (!previewSvg || !svgContainerRef.current) return;
9230
9321
  const initZoom = async () => {
9231
9322
  const svgElement = svgContainerRef.current?.querySelector("svg");
@@ -9264,7 +9355,7 @@ var MermaidView = ({
9264
9355
  }
9265
9356
  };
9266
9357
  }, [previewSvg]);
9267
- const handleCopyToClipboard = useCallback9(async () => {
9358
+ const handleCopyToClipboard = useCallback10(async () => {
9268
9359
  await copyToClipboard(mermaidCode);
9269
9360
  setCopySuccess(true);
9270
9361
  setTimeout(() => setCopySuccess(false), 2e3);
@@ -9377,7 +9468,7 @@ var MermaidView = ({
9377
9468
  var MermaidView_default = MermaidView;
9378
9469
 
9379
9470
  // src/hooks/use-channel-visibility.ts
9380
- import { useCallback as useCallback10, useMemo as useMemo17, useState as useState12, useEffect as useEffect8 } from "react";
9471
+ import { useCallback as useCallback11, useMemo as useMemo17, useState as useState12, useEffect as useEffect9 } from "react";
9381
9472
 
9382
9473
  // src/utils/utils/utils.ts
9383
9474
  import { MarkerType as MarkerType6, Position as Position25 } from "@xyflow/react";
@@ -9505,7 +9596,7 @@ var useChannelVisibility = ({
9505
9596
  const [hideChannels, setHideChannels] = useState12(false);
9506
9597
  const [initialNodes, setInitialNodes] = useState12(nodes);
9507
9598
  const [initialEdges, setInitialEdges] = useState12(edges);
9508
- useEffect8(() => {
9599
+ useEffect9(() => {
9509
9600
  const storedHideChannels = localStorage.getItem(
9510
9601
  "EventCatalog:hideChannels"
9511
9602
  );
@@ -9513,14 +9604,14 @@ var useChannelVisibility = ({
9513
9604
  setHideChannels(storedHideChannels === "true");
9514
9605
  }
9515
9606
  }, []);
9516
- useEffect8(() => {
9607
+ useEffect9(() => {
9517
9608
  const hasChannels = nodes.some((node) => node.type === "channels");
9518
9609
  if (!hideChannels || hasChannels) {
9519
9610
  setInitialNodes(nodes);
9520
9611
  setInitialEdges(edges);
9521
9612
  }
9522
9613
  }, [nodes, edges, hideChannels]);
9523
- const toggleChannelsVisibility = useCallback10(() => {
9614
+ const toggleChannelsVisibility = useCallback11(() => {
9524
9615
  setHideChannels((prev) => {
9525
9616
  const newValue = !prev;
9526
9617
  localStorage.setItem(
@@ -9570,7 +9661,7 @@ var useChannelVisibility = ({
9570
9661
  (edge, index, self) => index === self.findIndex((t) => t.id === edge.id)
9571
9662
  );
9572
9663
  }, [edges, channels]);
9573
- useEffect8(() => {
9664
+ useEffect9(() => {
9574
9665
  if (skipProcessing) {
9575
9666
  return;
9576
9667
  }
@@ -10759,7 +10850,7 @@ var buildMessageGroupExpansionNodes = ({
10759
10850
  };
10760
10851
 
10761
10852
  // src/components/NotesToolbarButton.tsx
10762
- import { useState as useState14, useCallback as useCallback11 } from "react";
10853
+ import { useState as useState14, useCallback as useCallback12 } from "react";
10763
10854
  import {
10764
10855
  MessageCircle as MessageCircle3,
10765
10856
  AlertTriangle as AlertTriangle2,
@@ -11047,7 +11138,7 @@ function AllNotesModal({
11047
11138
  const portalContainer = usePortalContainer();
11048
11139
  const totalNotes = noteGroups.reduce((sum, g) => sum + g.notes.length, 0);
11049
11140
  const selected = noteGroups[selectedIdx] || noteGroups[0];
11050
- const handleNavigate = useCallback11(
11141
+ const handleNavigate = useCallback12(
11051
11142
  (nodeId) => {
11052
11143
  const node = nodes.find((n) => n.id === nodeId);
11053
11144
  if (!node) return;
@@ -11490,6 +11581,7 @@ import { Fragment as Fragment15, jsx as jsx52, jsxs as jsxs49 } from "react/jsx-
11490
11581
  var POSITION_CHANGE_THRESHOLD = 1;
11491
11582
  var LARGE_GRAPH_NODE_THRESHOLD = 30;
11492
11583
  var NODE_ORIGIN = [0.1, 0.1];
11584
+ var INITIAL_FIT_VIEW_OPTIONS = { padding: 0.2, duration: 0 };
11493
11585
  var MINIMAP_STYLE = {
11494
11586
  backgroundColor: "rgb(var(--ec-page-bg))",
11495
11587
  border: "1px solid rgb(var(--ec-page-border))",
@@ -11675,7 +11767,7 @@ var NodeGraphBuilder = ({
11675
11767
  onSaveLayout,
11676
11768
  onResetLayout
11677
11769
  }) => {
11678
- useEffect9(() => {
11770
+ useEffect10(() => {
11679
11771
  if (onBuildUrl) {
11680
11772
  setBuildUrlFn(onBuildUrl);
11681
11773
  }
@@ -11749,7 +11841,19 @@ var NodeGraphBuilder = ({
11749
11841
  const [edges, setEdges, onEdgesChange] = useEdgesState2(initialEdges);
11750
11842
  const { fitView, getNodes, getIntersectingNodes, getZoom, setCenter } = useReactFlow5();
11751
11843
  const storeApi = useStoreApi();
11752
- useEffect9(() => {
11844
+ const previousGraphInputRef = useRef8({
11845
+ nodes: initialNodes,
11846
+ edges: initialEdges
11847
+ });
11848
+ useEffect10(() => {
11849
+ const previousGraphInput = previousGraphInputRef.current;
11850
+ previousGraphInputRef.current = {
11851
+ nodes: initialNodes,
11852
+ edges: initialEdges
11853
+ };
11854
+ if (previousGraphInput.nodes === initialNodes && previousGraphInput.edges === initialEdges) {
11855
+ return;
11856
+ }
11753
11857
  setNodes(initialNodes);
11754
11858
  setEdges(initialEdges);
11755
11859
  requestAnimationFrame(() => {
@@ -11765,28 +11869,28 @@ var NodeGraphBuilder = ({
11765
11869
  const [showMinimap, setShowMinimap] = useState15(false);
11766
11870
  const [hasLayoutChanges, setHasLayoutChanges] = useState15(false);
11767
11871
  const [isSavingLayout, setIsSavingLayout] = useState15(false);
11768
- const initialPositionsRef = useRef7(
11872
+ const initialPositionsRef = useRef8(
11769
11873
  {}
11770
11874
  );
11771
11875
  const [focusModeOpen, setFocusModeOpen] = useState15(false);
11772
11876
  const [focusedNodeId, setFocusedNodeId] = useState15(null);
11773
11877
  const [isNotesModalOpen, setIsNotesModalOpen] = useState15(false);
11774
- const openNotesModal = useCallback12(() => setIsNotesModalOpen(true), []);
11775
- const interactionCountRef = useRef7(0);
11776
- const startInteraction = useCallback12(() => {
11878
+ const openNotesModal = useCallback13(() => setIsNotesModalOpen(true), []);
11879
+ const interactionCountRef = useRef8(0);
11880
+ const startInteraction = useCallback13(() => {
11777
11881
  interactionCountRef.current += 1;
11778
11882
  if (interactionCountRef.current === 1) {
11779
11883
  reactFlowWrapperRef.current?.classList.add("ec-interaction-active");
11780
11884
  }
11781
11885
  }, []);
11782
- const endInteraction = useCallback12(() => {
11886
+ const endInteraction = useCallback13(() => {
11783
11887
  interactionCountRef.current = Math.max(0, interactionCountRef.current - 1);
11784
11888
  if (interactionCountRef.current === 0) {
11785
11889
  reactFlowWrapperRef.current?.classList.remove("ec-interaction-active");
11786
11890
  }
11787
11891
  }, []);
11788
- const hoveredEdgeNodesRef = useRef7([]);
11789
- const handleEdgeMouseEnter = useCallback12(
11892
+ const hoveredEdgeNodesRef = useRef8([]);
11893
+ const handleEdgeMouseEnter = useCallback13(
11790
11894
  (_, edge) => {
11791
11895
  const wrapper = reactFlowWrapperRef.current;
11792
11896
  if (!wrapper) return;
@@ -11798,15 +11902,15 @@ var NodeGraphBuilder = ({
11798
11902
  },
11799
11903
  []
11800
11904
  );
11801
- const handleEdgeMouseLeave = useCallback12(() => {
11905
+ const handleEdgeMouseLeave = useCallback13(() => {
11802
11906
  hoveredEdgeNodesRef.current.forEach(
11803
11907
  (el) => el.classList.remove("ec-edge-hover-node")
11804
11908
  );
11805
11909
  hoveredEdgeNodesRef.current = [];
11806
11910
  }, []);
11807
- const hoveredNodeEdgesRef = useRef7([]);
11808
- const hoveredNodePeersRef = useRef7([]);
11809
- const handleNodeMouseEnter = useCallback12(
11911
+ const hoveredNodeEdgesRef = useRef8([]);
11912
+ const hoveredNodePeersRef = useRef8([]);
11913
+ const handleNodeMouseEnter = useCallback13(
11810
11914
  (_, node) => {
11811
11915
  const wrapper = reactFlowWrapperRef.current;
11812
11916
  if (!wrapper) return;
@@ -11835,7 +11939,7 @@ var NodeGraphBuilder = ({
11835
11939
  },
11836
11940
  []
11837
11941
  );
11838
- const handleNodeMouseLeave = useCallback12(() => {
11942
+ const handleNodeMouseLeave = useCallback13(() => {
11839
11943
  hoveredNodeEdgesRef.current.forEach(
11840
11944
  (el) => el.classList.remove("ec-node-hover-edge")
11841
11945
  );
@@ -11856,14 +11960,14 @@ var NodeGraphBuilder = ({
11856
11960
  setEdges,
11857
11961
  skipProcessing: !hasChannels
11858
11962
  });
11859
- const searchRef = useRef7(null);
11860
- const reactFlowWrapperRef = useRef7(null);
11861
- const scrollableContainerRef = useRef7(null);
11862
- const nodesRef = useRef7(nodes);
11963
+ const searchRef = useRef8(null);
11964
+ const reactFlowWrapperRef = useRef8(null);
11965
+ const scrollableContainerRef = useRef8(null);
11966
+ const nodesRef = useRef8(nodes);
11863
11967
  nodesRef.current = nodes;
11864
- const edgesRef = useRef7(edges);
11968
+ const edgesRef = useRef8(edges);
11865
11969
  edgesRef.current = edges;
11866
- const hideChannelsRef = useRef7(hideChannels);
11970
+ const hideChannelsRef = useRef8(hideChannels);
11867
11971
  hideChannelsRef.current = hideChannels;
11868
11972
  const wrapperNodeIds = useMemo18(() => {
11869
11973
  const ids = /* @__PURE__ */ new Set();
@@ -11882,13 +11986,13 @@ var NodeGraphBuilder = ({
11882
11986
  ),
11883
11987
  [edges, wrapperNodeIds]
11884
11988
  );
11885
- const animateLayout = useCallback12(() => {
11989
+ const animateLayout = useCallback13(() => {
11886
11990
  const wrapper = reactFlowWrapperRef.current;
11887
11991
  if (!wrapper) return;
11888
11992
  wrapper.classList.add("ec-animating-layout");
11889
11993
  setTimeout(() => wrapper.classList.remove("ec-animating-layout"), 400);
11890
11994
  }, []);
11891
- const relayoutGraph = useCallback12(
11995
+ const relayoutGraph = useCallback13(
11892
11996
  (nextNodes, nextEdges, anchor) => {
11893
11997
  const g = new dagre3.graphlib.Graph({ compound: true });
11894
11998
  g.setGraph({ rankdir: "LR", ranksep: 300, nodesep: 50 });
@@ -11960,7 +12064,7 @@ var NodeGraphBuilder = ({
11960
12064
  },
11961
12065
  []
11962
12066
  );
11963
- const makeRoomForRenderedExpandedGroup = useCallback12(
12067
+ const makeRoomForRenderedExpandedGroup = useCallback13(
11964
12068
  (groupNodeId, groupBounds) => {
11965
12069
  const padding = 80;
11966
12070
  const protectedBounds = {
@@ -11989,7 +12093,7 @@ var NodeGraphBuilder = ({
11989
12093
  },
11990
12094
  [getIntersectingNodes, setNodes]
11991
12095
  );
11992
- const layoutSubFlowChildren = useCallback12(
12096
+ const layoutSubFlowChildren = useCallback13(
11993
12097
  (children, edges2, sizeOf, opts) => {
11994
12098
  const { padding, headerH, fallbackW = 240, fallbackH = 120 } = opts;
11995
12099
  const g = new dagre3.graphlib.Graph();
@@ -12039,7 +12143,7 @@ var NodeGraphBuilder = ({
12039
12143
  },
12040
12144
  []
12041
12145
  );
12042
- const handleCollapseGroup = useCallback12(
12146
+ const handleCollapseGroup = useCallback13(
12043
12147
  (e) => {
12044
12148
  const target = e.target;
12045
12149
  const collapseBtn = target.closest(
@@ -12116,7 +12220,7 @@ var NodeGraphBuilder = ({
12116
12220
  animateLayout
12117
12221
  ]
12118
12222
  );
12119
- useEffect9(() => {
12223
+ useEffect10(() => {
12120
12224
  if (isDevMode && initialNodes.length > 0) {
12121
12225
  const positions = {};
12122
12226
  initialNodes.forEach((node) => {
@@ -12125,7 +12229,7 @@ var NodeGraphBuilder = ({
12125
12229
  initialPositionsRef.current = positions;
12126
12230
  }
12127
12231
  }, [isDevMode, initialNodes]);
12128
- const checkForLayoutChanges = useCallback12(() => {
12232
+ const checkForLayoutChanges = useCallback13(() => {
12129
12233
  if (!isDevMode) return;
12130
12234
  const initial = initialPositionsRef.current;
12131
12235
  if (Object.keys(initial).length === 0) return;
@@ -12135,7 +12239,7 @@ var NodeGraphBuilder = ({
12135
12239
  });
12136
12240
  setHasLayoutChanges(hasChanges);
12137
12241
  }, [isDevMode]);
12138
- const handleNodesChange = useCallback12(
12242
+ const handleNodesChange = useCallback13(
12139
12243
  (changes) => {
12140
12244
  onNodesChange(changes);
12141
12245
  const hasDragEnd = changes.some(
@@ -12147,7 +12251,7 @@ var NodeGraphBuilder = ({
12147
12251
  },
12148
12252
  [onNodesChange, checkForLayoutChanges]
12149
12253
  );
12150
- const resetNodesAndEdges = useCallback12(() => {
12254
+ const resetNodesAndEdges = useCallback13(() => {
12151
12255
  setNodes(
12152
12256
  (nds) => nds.map((node) => {
12153
12257
  node.style = { ...node.style, opacity: 1 };
@@ -12166,7 +12270,7 @@ var NodeGraphBuilder = ({
12166
12270
  })
12167
12271
  );
12168
12272
  }, [setNodes, setEdges, animateMessages]);
12169
- useEffect9(() => {
12273
+ useEffect10(() => {
12170
12274
  if (!focusNodeId) return;
12171
12275
  const targetNode = nodesRef.current.find((node) => node.id === focusNodeId);
12172
12276
  if (!targetNode) return;
@@ -12184,13 +12288,13 @@ var NodeGraphBuilder = ({
12184
12288
  });
12185
12289
  });
12186
12290
  }, [focusNodeId, focusRequestId, fitView, setNodes]);
12187
- useEffect9(() => {
12291
+ useEffect10(() => {
12188
12292
  if (fitRequestId == null) return;
12189
12293
  requestAnimationFrame(() => {
12190
12294
  fitView({ duration: 400, padding: 0.2 });
12191
12295
  });
12192
12296
  }, [fitRequestId, fitView]);
12193
- const handleNodeClick = useCallback12(
12297
+ const handleNodeClick = useCallback13(
12194
12298
  (_, node) => {
12195
12299
  if (onNodeClick) {
12196
12300
  onNodeClick(node);
@@ -12589,7 +12693,7 @@ var NodeGraphBuilder = ({
12589
12693
  setCenter
12590
12694
  ]
12591
12695
  );
12592
- const toggleAnimateMessages = useCallback12(() => {
12696
+ const toggleAnimateMessages = useCallback13(() => {
12593
12697
  setAnimateMessages((prev) => {
12594
12698
  const next = !prev;
12595
12699
  localStorage.setItem(
@@ -12599,10 +12703,10 @@ var NodeGraphBuilder = ({
12599
12703
  return next;
12600
12704
  });
12601
12705
  }, []);
12602
- const handleFitView = useCallback12(() => {
12706
+ const handleFitView = useCallback13(() => {
12603
12707
  fitView({ duration: 400, padding: 0.2 });
12604
12708
  }, [fitView]);
12605
- useEffect9(() => {
12709
+ useEffect10(() => {
12606
12710
  if (disableMessageAnimation) {
12607
12711
  setAnimateMessages(false);
12608
12712
  return;
@@ -12628,7 +12732,7 @@ var NodeGraphBuilder = ({
12628
12732
  }
12629
12733
  }
12630
12734
  }, [animated, disableMessageAnimation, initialNodes.length]);
12631
- useEffect9(() => {
12735
+ useEffect10(() => {
12632
12736
  setEdges(
12633
12737
  (eds) => eds.map((edge) => {
12634
12738
  const preservesOwnRenderer = edge.type === "flow-edge" || edge.type === "multiline" || edge.type === "default" || edge.type === "step" || edge.type === "smoothstep" || edge.data?.animated === false;
@@ -12645,12 +12749,12 @@ var NodeGraphBuilder = ({
12645
12749
  })
12646
12750
  );
12647
12751
  }, [animateMessages]);
12648
- useEffect9(() => {
12752
+ useEffect10(() => {
12649
12753
  setTimeout(() => {
12650
12754
  fitView({ duration: 800 });
12651
12755
  }, 150);
12652
12756
  }, []);
12653
- const generateMermaidCode = useCallback12(() => {
12757
+ const generateMermaidCode = useCallback13(() => {
12654
12758
  try {
12655
12759
  return convertToMermaid(nodesRef.current, edgesRef.current, {
12656
12760
  includeStyles: true,
@@ -12661,7 +12765,7 @@ var NodeGraphBuilder = ({
12661
12765
  return "";
12662
12766
  }
12663
12767
  }, []);
12664
- useEffect9(() => {
12768
+ useEffect10(() => {
12665
12769
  if (zoomOnScroll) return;
12666
12770
  const findScrollableContainer = () => {
12667
12771
  const selectors = [
@@ -12706,34 +12810,34 @@ var NodeGraphBuilder = ({
12706
12810
  };
12707
12811
  }
12708
12812
  }, [zoomOnScroll]);
12709
- const handlePaneClick = useCallback12(() => {
12813
+ const handlePaneClick = useCallback13(() => {
12710
12814
  searchRef.current?.hideSuggestions();
12711
12815
  resetNodesAndEdges();
12712
12816
  fitView({ duration: 800 });
12713
12817
  }, [resetNodesAndEdges, fitView]);
12714
- const handleNodeSelect = useCallback12(
12818
+ const handleNodeSelect = useCallback13(
12715
12819
  (node) => {
12716
12820
  handleNodeClick(null, node);
12717
12821
  },
12718
12822
  [handleNodeClick]
12719
12823
  );
12720
- const handleSearchClear = useCallback12(() => {
12824
+ const handleSearchClear = useCallback13(() => {
12721
12825
  resetNodesAndEdges();
12722
12826
  fitView({ duration: 800 });
12723
12827
  }, [resetNodesAndEdges, fitView]);
12724
- const downloadImage = useCallback12((dataUrl, filename) => {
12828
+ const downloadImage = useCallback13((dataUrl, filename) => {
12725
12829
  const a = document.createElement("a");
12726
12830
  a.setAttribute("download", `${filename || "eventcatalog"}.png`);
12727
12831
  a.setAttribute("href", dataUrl);
12728
12832
  a.click();
12729
12833
  }, []);
12730
- const openStudioModal = useCallback12(() => {
12834
+ const openStudioModal = useCallback13(() => {
12731
12835
  setIsStudioModalOpen(true);
12732
12836
  }, [setIsStudioModalOpen]);
12733
- const openChat = useCallback12(() => {
12837
+ const openChat = useCallback13(() => {
12734
12838
  window.dispatchEvent(new CustomEvent("eventcatalog:open-chat"));
12735
12839
  }, []);
12736
- const handleSaveLayout = useCallback12(async () => {
12840
+ const handleSaveLayout = useCallback13(async () => {
12737
12841
  if (!resourceKey || !onSaveLayout) return false;
12738
12842
  const positions = {};
12739
12843
  nodesRef.current.forEach((node) => {
@@ -12744,11 +12848,11 @@ var NodeGraphBuilder = ({
12744
12848
  });
12745
12849
  return await onSaveLayout(resourceKey, positions);
12746
12850
  }, [resourceKey, onSaveLayout]);
12747
- const handleResetLayout = useCallback12(async () => {
12851
+ const handleResetLayout = useCallback13(async () => {
12748
12852
  if (!resourceKey || !onResetLayout) return false;
12749
12853
  return await onResetLayout(resourceKey);
12750
12854
  }, [resourceKey, onResetLayout]);
12751
- const handleQuickSaveLayout = useCallback12(async () => {
12855
+ const handleQuickSaveLayout = useCallback13(async () => {
12752
12856
  setIsSavingLayout(true);
12753
12857
  const success = await handleSaveLayout();
12754
12858
  setIsSavingLayout(false);
@@ -12761,17 +12865,17 @@ var NodeGraphBuilder = ({
12761
12865
  setHasLayoutChanges(false);
12762
12866
  }
12763
12867
  }, [handleSaveLayout]);
12764
- const handleCopyArchitectureCode = useCallback12(async () => {
12868
+ const handleCopyArchitectureCode = useCallback13(async () => {
12765
12869
  const code = generateMermaidCode();
12766
12870
  await copyToClipboard(code);
12767
12871
  }, [generateMermaidCode]);
12768
- const handleCopyShareUrl = useCallback12(async () => {
12872
+ const handleCopyShareUrl = useCallback13(async () => {
12769
12873
  const url = typeof window !== "undefined" ? window.location.href : "";
12770
12874
  await copyToClipboard(url);
12771
12875
  setShareUrlCopySuccess(true);
12772
12876
  setTimeout(() => setShareUrlCopySuccess(false), 2e3);
12773
12877
  }, []);
12774
- const toggleFullScreen = useCallback12(() => {
12878
+ const toggleFullScreen = useCallback13(() => {
12775
12879
  if (!document.fullscreenElement) {
12776
12880
  reactFlowWrapperRef.current?.requestFullscreen().catch((err) => {
12777
12881
  console.error(
@@ -12782,7 +12886,7 @@ var NodeGraphBuilder = ({
12782
12886
  document.exitFullscreen();
12783
12887
  }
12784
12888
  }, []);
12785
- useEffect9(() => {
12889
+ useEffect10(() => {
12786
12890
  const handleFullscreenChange = () => {
12787
12891
  _setIsFullscreen(!!document.fullscreenElement);
12788
12892
  setTimeout(() => {
@@ -12794,7 +12898,7 @@ var NodeGraphBuilder = ({
12794
12898
  document.removeEventListener("fullscreenchange", handleFullscreenChange);
12795
12899
  };
12796
12900
  }, [fitView]);
12797
- const handleExportVisual = useCallback12(() => {
12901
+ const handleExportVisual = useCallback13(() => {
12798
12902
  const nodesBounds = getNodesBounds(getNodes(), {
12799
12903
  nodeLookup: storeApi.getState().nodeLookup
12800
12904
  });
@@ -12823,7 +12927,7 @@ var NodeGraphBuilder = ({
12823
12927
  if (controls) controls.style.display = "block";
12824
12928
  });
12825
12929
  }, [getNodes, storeApi, downloadImage, title]);
12826
- const handleLegendClick = useCallback12(
12930
+ const handleLegendClick = useCallback13(
12827
12931
  (collectionType, groupId) => {
12828
12932
  const isLegendTarget = (node) => {
12829
12933
  if (groupId) {
@@ -12858,7 +12962,7 @@ var NodeGraphBuilder = ({
12858
12962
  },
12859
12963
  [nodes, edges, setNodes, setEdges, fitView]
12860
12964
  );
12861
- const getNodesByCollectionWithColors = useCallback12((nodes2) => {
12965
+ const getNodesByCollectionWithColors = useCallback13((nodes2) => {
12862
12966
  const colorClasses = {
12863
12967
  events: "bg-orange-600",
12864
12968
  agent: "bg-sky-600",
@@ -12919,7 +13023,7 @@ var NodeGraphBuilder = ({
12919
13023
  );
12920
13024
  return { ...legendForDomains, ...legendForNodes };
12921
13025
  }, []);
12922
- const legendKeyRef = useRef7("");
13026
+ const legendKeyRef = useRef8("");
12923
13027
  const computedLegendKey = nodes.map((n) => `${n.id}:${n.type}:${n.data.group?.id || ""}`).join(",");
12924
13028
  if (computedLegendKey !== legendKeyRef.current) {
12925
13029
  legendKeyRef.current = computedLegendKey;
@@ -12929,7 +13033,7 @@ var NodeGraphBuilder = ({
12929
13033
  () => getNodesByCollectionWithColors(nodes),
12930
13034
  [getNodesByCollectionWithColors, legendKey]
12931
13035
  );
12932
- const nodeIdsKeyRef = useRef7("");
13036
+ const nodeIdsKeyRef = useRef8("");
12933
13037
  const computedNodeIdsKey = nodes.map((n) => n.id).join(",");
12934
13038
  if (computedNodeIdsKey !== nodeIdsKeyRef.current) {
12935
13039
  nodeIdsKeyRef.current = computedNodeIdsKey;
@@ -12955,7 +13059,7 @@ var NodeGraphBuilder = ({
12955
13059
  () => allNoteGroups.reduce((sum, g) => sum + g.notes.length, 0),
12956
13060
  [allNoteGroups]
12957
13061
  );
12958
- const handleStepChange = useCallback12(
13062
+ const handleStepChange = useCallback13(
12959
13063
  (nodeId, highlightPaths, shouldZoomOut) => {
12960
13064
  if (nodeId === null) {
12961
13065
  resetNodesAndEdges();
@@ -13131,6 +13235,7 @@ var NodeGraphBuilder = ({
13131
13235
  nodes,
13132
13236
  edges,
13133
13237
  fitView: true,
13238
+ fitViewOptions: INITIAL_FIT_VIEW_OPTIONS,
13134
13239
  onNodesChange: handleNodesChange,
13135
13240
  onEdgesChange,
13136
13241
  onEdgeMouseEnter: handleEdgeMouseEnter,
@@ -13468,14 +13573,14 @@ var NodeGraph = ({
13468
13573
  const [elem, setElem] = useState15(null);
13469
13574
  const [showFooter, setShowFooter] = useState15(true);
13470
13575
  const [isStudioModalOpen, setIsStudioModalOpen] = useState15(false);
13471
- const openStudioModal = useCallback12(() => {
13576
+ const openStudioModal = useCallback13(() => {
13472
13577
  setIsStudioModalOpen(true);
13473
13578
  }, []);
13474
13579
  const containerToRenderInto = portalId || `${id}-portal`;
13475
- useEffect9(() => {
13580
+ useEffect10(() => {
13476
13581
  setElem(document.getElementById(containerToRenderInto));
13477
13582
  }, []);
13478
- useEffect9(() => {
13583
+ useEffect10(() => {
13479
13584
  const urlParams = new URLSearchParams(window.location.search);
13480
13585
  const embed = urlParams.get("embed");
13481
13586
  if (embed === "true") {
@@ -13608,6 +13713,7 @@ export {
13608
13713
  DataNode_default as Data,
13609
13714
  DataProduct_default as DataProductNode,
13610
13715
  Domain_default as DomainNode,
13716
+ ENTITY_TARGET_HANDLE_ID,
13611
13717
  EVENT,
13612
13718
  Entity_default as EntityNode,
13613
13719
  EventNode_default as Event,
@@ -13663,7 +13769,9 @@ export {
13663
13769
  getColorFromString,
13664
13770
  getEdgeLabelForMessageAsSource,
13665
13771
  getEdgeLabelForServiceAsTarget,
13772
+ getNestedEntityProperties,
13666
13773
  getNodesAndEdgesFromDagre,
13774
+ getPropertyTypeLabel,
13667
13775
  layoutGraph,
13668
13776
  nodeComponents,
13669
13777
  nodeConfigs,