@redocly/theme 0.57.0-next.1 → 0.57.0-next.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.
Files changed (65) hide show
  1. package/lib/components/Catalog/CatalogCardView/CatalogCard.js +1 -0
  2. package/lib/components/Catalog/CatalogEntity/CatalogEntity.js +36 -25
  3. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsEdge.d.ts +6 -0
  4. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsEdge.js +38 -0
  5. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph.d.ts +6 -0
  6. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph.js +83 -0
  7. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph.lazy.d.ts +2 -0
  8. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph.lazy.js +29 -0
  9. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsLinkedNode.d.ts +8 -0
  10. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsLinkedNode.js +33 -0
  11. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsNode.d.ts +16 -0
  12. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsNode.js +24 -0
  13. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsRootNode.d.ts +7 -0
  14. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsRootNode.js +30 -0
  15. package/lib/components/Catalog/CatalogEntity/CatalogEntityMethodAndPath.js +5 -2
  16. package/lib/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelations.d.ts +1 -0
  17. package/lib/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelations.js +7 -3
  18. package/lib/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelationsTable.js +3 -8
  19. package/lib/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelationsTableContent.d.ts +22 -0
  20. package/lib/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelationsTableContent.js +18 -0
  21. package/lib/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityTeamRelations.js +2 -2
  22. package/lib/components/Catalog/CatalogEntityIcon.d.ts +2 -1
  23. package/lib/components/Catalog/CatalogEntityIcon.js +4 -6
  24. package/lib/components/Catalog/CatalogTableView/CatalogTableViewRow.js +1 -1
  25. package/lib/components/Catalog/variables.js +42 -0
  26. package/lib/components/CatalogClassic/CatalogClassicVirtualizedGroups.js +13 -8
  27. package/lib/core/constants/catalog.d.ts +10 -0
  28. package/lib/core/constants/catalog.js +14 -1
  29. package/lib/core/hooks/catalog/useGraph.d.ts +15 -0
  30. package/lib/core/hooks/catalog/useGraph.js +165 -0
  31. package/lib/core/hooks/index.d.ts +1 -0
  32. package/lib/core/hooks/index.js +1 -0
  33. package/lib/core/openapi/index.d.ts +1 -0
  34. package/lib/core/openapi/index.js +3 -1
  35. package/lib/core/styles/index.d.ts +1 -0
  36. package/lib/core/styles/index.js +3 -0
  37. package/lib/core/styles/xyflow.d.ts +1 -0
  38. package/lib/core/styles/xyflow.js +623 -0
  39. package/lib/core/utils/dynamic.d.ts +5 -3
  40. package/lib/core/utils/dynamic.js +1 -1
  41. package/package.json +3 -2
  42. package/src/components/Catalog/CatalogCardView/CatalogCard.tsx +1 -0
  43. package/src/components/Catalog/CatalogEntity/CatalogEntity.tsx +60 -42
  44. package/src/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsEdge.tsx +63 -0
  45. package/src/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph.lazy.tsx +7 -0
  46. package/src/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph.tsx +91 -0
  47. package/src/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsLinkedNode.tsx +48 -0
  48. package/src/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsNode.tsx +45 -0
  49. package/src/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsRootNode.tsx +49 -0
  50. package/src/components/Catalog/CatalogEntity/CatalogEntityMethodAndPath.tsx +6 -2
  51. package/src/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelations.tsx +8 -2
  52. package/src/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelationsTable.tsx +24 -43
  53. package/src/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelationsTableContent.tsx +76 -0
  54. package/src/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityTeamRelations.tsx +2 -2
  55. package/src/components/Catalog/CatalogEntityIcon.tsx +7 -5
  56. package/src/components/Catalog/CatalogTableView/CatalogTableViewRow.tsx +1 -1
  57. package/src/components/Catalog/variables.ts +42 -0
  58. package/src/components/CatalogClassic/CatalogClassicVirtualizedGroups.tsx +29 -18
  59. package/src/core/constants/catalog.ts +13 -0
  60. package/src/core/hooks/catalog/useGraph.ts +236 -0
  61. package/src/core/hooks/index.ts +1 -0
  62. package/src/core/openapi/index.ts +1 -0
  63. package/src/core/styles/index.ts +1 -0
  64. package/src/core/styles/xyflow.ts +620 -0
  65. package/src/core/utils/dynamic.tsx +17 -15
@@ -88,7 +88,7 @@ export function CatalogEntityTeamRelations({
88
88
  <Tabs forceReady={relations.length > 0} size={TabsSize.MEDIUM}>
89
89
  <TabItem label="Members" icon={<PeopleIcon />} onClick={() => setFilter('type:user')}>
90
90
  <CatalogEntityRelationsTable
91
- key={`members-${relations.length}-${relations.map((r) => r.id).join(',')}`}
91
+ key="members-table"
92
92
  entity={entity}
93
93
  entitiesCatalogConfig={entitiesCatalogConfig}
94
94
  catalogConfig={catalogConfig}
@@ -111,7 +111,7 @@ export function CatalogEntityTeamRelations({
111
111
  onClick={() => setFilter('-type:user')}
112
112
  >
113
113
  <CatalogEntityDefaultRelations
114
- key={`related-${relations.length}-${relations.map((r) => r.id).join(',')}`}
114
+ key="related-entities-table"
115
115
  entity={entity}
116
116
  relations={relations}
117
117
  query={query}
@@ -11,14 +11,15 @@ import { MoleculesIcon } from '@redocly/theme/icons/MoleculesIcon/MoleculesIcon'
11
11
  export type CatalogEntityIconProps = {
12
12
  entityType: string;
13
13
  defaultColor?: boolean;
14
+ forceColor?: string;
14
15
  };
15
16
 
16
17
  const getIconColor = (entityType: EntityType) => `var(--catalog-entity-icon-color-${entityType})`;
17
18
 
18
- const getEntityIcon = ({ entityType, defaultColor }: CatalogEntityIconProps) => {
19
- const iconColor = defaultColor
20
- ? `var(--catalog-entity-icon-color)`
21
- : getIconColor(entityType as EntityType);
19
+ const getEntityIcon = ({ entityType, defaultColor, forceColor }: CatalogEntityIconProps) => {
20
+ const iconColor =
21
+ forceColor ??
22
+ (defaultColor ? `var(--catalog-entity-icon-color)` : getIconColor(entityType as EntityType));
22
23
 
23
24
  const entityIconMap: Record<EntityType, JSX.Element> = {
24
25
  service: <CodeIcon color={iconColor} />,
@@ -36,8 +37,9 @@ const getEntityIcon = ({ entityType, defaultColor }: CatalogEntityIconProps) =>
36
37
  export function CatalogEntityIcon({
37
38
  entityType,
38
39
  defaultColor = false,
40
+ forceColor,
39
41
  }: CatalogEntityIconProps): JSX.Element {
40
- const icon = getEntityIcon({ entityType, defaultColor });
42
+ const icon = getEntityIcon({ entityType, defaultColor, forceColor });
41
43
 
42
44
  if (!icon) {
43
45
  throw new Error(`Unhandled entity type: ${entityType}`);
@@ -101,7 +101,7 @@ export const CatalogTableViewRow = <T extends BaseEntity>({
101
101
  key={entity.id}
102
102
  $columnsWidths={columns.map((column) => column.width || '1fr')}
103
103
  $columnsMinWidths={columns.map((column) => column.minWidth || 'auto')}
104
- to={getEntityDetailsLink()}
104
+ to={getEntityDetailsLink() + '?search='}
105
105
  style={{ color: 'var(--catalog-page-wrapper-text-color)' }}
106
106
  data-component-name="Catalog/CatalogTableView/CatalogTableViewRow"
107
107
  >
@@ -382,4 +382,46 @@ export const catalog = css`
382
382
 
383
383
  --catalog-avatar-bg-color: #ededf2;
384
384
  // @tokens End
385
+
386
+ /**
387
+ * @tokens Catalog entity relations node
388
+ */
389
+ --catalog-entity-relations-node-padding-vertical: 10px;
390
+ --catalog-entity-relations-node-padding-horizontal: 14px;
391
+ --catalog-entity-relations-node-padding: var(--catalog-entity-relations-node-padding-vertical) var(--catalog-entity-relations-node-padding-horizontal);
392
+ --catalog-entity-relations-node-gap: 8px;
393
+ --catalog-entity-relations-node-border-radius: 10px;
394
+
395
+ --catalog-entity-relations-node-bg-color: var(--layer-color);
396
+ --catalog-entity-relations-node-text-color: var(--catalog-card-text-color);
397
+
398
+ --catalog-entity-relations-node-border-color: var(--border-color-secondary);
399
+ --catalog-entity-relations-node-border-width: var(--border-width);
400
+ --catalog-entity-relations-node-border-style: var(--border-style);
401
+
402
+ --catalog-entity-relations-node-font-weight: var(--font-weight-regular);
403
+ --catalog-entity-relations-node-font-weight-root: 600;
404
+
405
+ --catalog-entity-relations-node-root-bg-color: var(--color-blue-6);
406
+ --catalog-entity-relations-node-root-text-color: #ffffff;
407
+ --catalog-entity-relations-node-root-icon-color: #ffffff;
408
+ // @tokens End
409
+
410
+ /**
411
+ * @tokens Catalog entity relations edge
412
+ */
413
+ --catalog-entity-relations-edge-label-bg-color: var(--layer-color);
414
+ --catalog-entity-relations-edge-label-text-color: var(--catalog-card-text-color);
415
+ --catalog-entity-relations-edge-label-border-color: var(--border-color-secondary);
416
+ --catalog-entity-relations-edge-label-border-width: var(--border-width);
417
+ --catalog-entity-relations-edge-label-border-style: var(--border-style);
418
+ --catalog-entity-relations-edge-label-border-radius: 10px;
419
+
420
+ --catalog-entity-relations-edge-label-padding-vertical: 2px;
421
+ --catalog-entity-relations-edge-label-padding-horizontal: 8px;
422
+ --catalog-entity-relations-edge-label-padding: var(--catalog-entity-relations-edge-label-padding-vertical) var(--catalog-entity-relations-edge-label-padding-horizontal);
423
+
424
+ --catalog-entity-relations-edge-label-font-size: 12px;
425
+ --catalog-entity-relations-edge-label-line-height: 1.2;
426
+ // @tokens End
385
427
  `;
@@ -106,6 +106,7 @@ export function CatalogClassicVirtualizedGroups({
106
106
  return ESTIMATED_CARD_HEIGHT;
107
107
  },
108
108
  overscan: 5,
109
+ enabled: shouldVirtualize,
109
110
  });
110
111
 
111
112
  useEffect(() => {
@@ -117,27 +118,29 @@ export function CatalogClassicVirtualizedGroups({
117
118
  // eslint-disable-next-line react-hooks/exhaustive-deps
118
119
  }, [filters, filterTerm, size.width, shouldVirtualize]);
119
120
 
121
+ const renderRow = (rowData: VirtualRowData) => {
122
+ if (rowData.type === 'header') {
123
+ return (
124
+ <SSRHeaderRow key={rowData.key}>
125
+ <CatalogSeparatorLabel>{rowData.groupTitle}</CatalogSeparatorLabel>
126
+ <CounterTag borderless>{rowData.groupCount}</CounterTag>
127
+ </SSRHeaderRow>
128
+ );
129
+ }
130
+
131
+ return (
132
+ <SSRGridRow key={rowData.key}>
133
+ {rowData.items.map((item) => (
134
+ <CatalogClassicCard key={item.link} item={item} />
135
+ ))}
136
+ </SSRGridRow>
137
+ );
138
+ };
139
+
120
140
  if (!isClient) {
121
141
  return (
122
142
  <div ref={parentRef} data-component-name="CatalogClassic/CatalogClassicVirtualizedGroups">
123
- {flatRows.slice(0, 15).map((rowData) => {
124
- if (rowData.type === 'header') {
125
- return (
126
- <SSRHeaderRow key={rowData.key}>
127
- <CatalogSeparatorLabel>{rowData.groupTitle}</CatalogSeparatorLabel>
128
- <CounterTag borderless>{rowData.groupCount}</CounterTag>
129
- </SSRHeaderRow>
130
- );
131
- }
132
-
133
- return (
134
- <SSRGridRow key={rowData.key}>
135
- {rowData.items.map((item) => (
136
- <CatalogClassicCard key={item.link} item={item} />
137
- ))}
138
- </SSRGridRow>
139
- );
140
- })}
143
+ {flatRows.slice(0, 15).map((rowData) => renderRow(rowData))}
141
144
  <LoadingWrapper>
142
145
  <SpinnerLoader color="var(--catalog-classic-description-text-color)" size="20px" />
143
146
  </LoadingWrapper>
@@ -145,6 +148,14 @@ export function CatalogClassicVirtualizedGroups({
145
148
  );
146
149
  }
147
150
 
151
+ if (!shouldVirtualize) {
152
+ return (
153
+ <div ref={parentRef} data-component-name="CatalogClassic/CatalogClassicVirtualizedGroups">
154
+ {flatRows.map((rowData) => renderRow(rowData))}
155
+ </div>
156
+ );
157
+ }
158
+
148
159
  return (
149
160
  <div ref={parentRef} data-component-name="CatalogClassic/CatalogClassicVirtualizedGroups">
150
161
  <div
@@ -57,3 +57,16 @@ export const reverseRelationMap: Record<EntityRelationType, EntityRelationType>
57
57
  triggers: 'triggeredBy',
58
58
  triggeredBy: 'triggers',
59
59
  } as const;
60
+
61
+ export enum GraphHandleType {
62
+ Target = 'target',
63
+ Source = 'source',
64
+ }
65
+
66
+ export enum GraphCustomNodeType {
67
+ CatalogEntity = 'catalogEntity',
68
+ }
69
+
70
+ export enum GraphCustomEdgeType {
71
+ CatalogEdge = 'catalogEdge',
72
+ }
@@ -0,0 +1,236 @@
1
+ import { useCallback, useEffect, useMemo } from 'react';
2
+ import {
3
+ addEdge,
4
+ type Node,
5
+ type Edge,
6
+ type Connection,
7
+ useNodesState,
8
+ useEdgesState,
9
+ Position,
10
+ OnNodesChange,
11
+ OnEdgesChange,
12
+ } from '@xyflow/react';
13
+
14
+ import { type CatalogEntityNodeData } from '@redocly/theme/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsNode';
15
+
16
+ import { BffCatalogEntity, BffCatalogRelatedEntity } from '../../types';
17
+ import {
18
+ GraphCustomEdgeType,
19
+ GraphCustomNodeType,
20
+ GraphHandleType,
21
+ reverseRelationMap,
22
+ } from '../../constants/catalog';
23
+
24
+ export type UseGraphProps = {
25
+ entity: BffCatalogEntity;
26
+ relations: BffCatalogRelatedEntity[];
27
+ };
28
+
29
+ export type UseGraphReturn = {
30
+ nodes: Node<CatalogEntityNodeData>[];
31
+ edges: Edge[];
32
+ onNodesChange: OnNodesChange<Node<CatalogEntityNodeData>>;
33
+ onEdgesChange: OnEdgesChange<Edge>;
34
+ onConnect: (params: Connection) => void;
35
+ };
36
+
37
+ type EntityGraphData = {
38
+ id: string;
39
+ title: string;
40
+ entityType: string;
41
+ relationLabel: string;
42
+ key: string;
43
+ };
44
+
45
+ // TODO: This isn't final implementation, leaved comments for future reference.
46
+ export function useGraph({ entity, relations }: UseGraphProps): UseGraphReturn {
47
+ const rootNodeId = entity.id;
48
+
49
+ // Compute final label for a relation considering its role
50
+ const getRelationLabel = useCallback((relation: BffCatalogRelatedEntity): string => {
51
+ const relationType = relation.relationType;
52
+ if (!relationType) {
53
+ return 'related';
54
+ }
55
+
56
+ return relation.relationRole === 'source' ? reverseRelationMap[relationType] : relationType;
57
+ }, []);
58
+
59
+ const processedRelations = useMemo(() => {
60
+ // Exclude self-relations and deduplicate by id
61
+ const seenIds = new Set<string>();
62
+ const filtered = (relations ?? []).filter((r) => r.id !== rootNodeId && r.key !== entity.key);
63
+
64
+ const unique = [] as Array<{
65
+ id: string;
66
+ title: string;
67
+ entityType: string;
68
+ relationLabel: string;
69
+ key: string;
70
+ }>;
71
+
72
+ for (const r of filtered) {
73
+ if (seenIds.has(r.id)) continue;
74
+ seenIds.add(r.id);
75
+ unique.push({
76
+ id: r.id,
77
+ title: r.title,
78
+ entityType: r.type, // Group by entity type, not relation type
79
+ relationLabel: getRelationLabel(r),
80
+ key: r.key,
81
+ });
82
+ }
83
+
84
+ return unique;
85
+ }, [relations, getRelationLabel, rootNodeId, entity.key]);
86
+
87
+ // Entity data type for layout
88
+
89
+ const computedNodes = useMemo<Node<CatalogEntityNodeData>[]>(() => {
90
+ if (!processedRelations.length) {
91
+ return [
92
+ {
93
+ id: rootNodeId,
94
+ type: GraphCustomNodeType.CatalogEntity,
95
+ position: { x: 0, y: 0 },
96
+ data: {
97
+ label: entity.title,
98
+ entityType: entity.type,
99
+ isRoot: true,
100
+ entityKey: entity.key,
101
+ },
102
+ sourcePosition: Position.Bottom,
103
+ targetPosition: Position.Top,
104
+ },
105
+ ];
106
+ }
107
+
108
+ // Group entities by their entity type
109
+ const entityTypeGroups = new Map<string, EntityGraphData[]>();
110
+ for (const rel of processedRelations) {
111
+ const entityData: EntityGraphData = {
112
+ id: rel.id,
113
+ title: rel.title,
114
+ entityType: rel.entityType,
115
+ relationLabel: rel.relationLabel,
116
+ key: rel.key,
117
+ };
118
+
119
+ const current = entityTypeGroups.get(rel.entityType);
120
+ if (current) {
121
+ current.push(entityData);
122
+ } else {
123
+ entityTypeGroups.set(rel.entityType, [entityData]);
124
+ }
125
+ }
126
+
127
+ // Sort entity types for consistent ordering
128
+ const entityTypes = Array.from(entityTypeGroups.keys()).sort();
129
+
130
+ // Layout constants
131
+ const rootY = 0;
132
+ const verticalGap = 80; // Gap between entities of same type (vertical)
133
+ const horizontalGap = 250; // Gap between different entity types (horizontal)
134
+ const topMargin = 240; // Distance from root to first row of entities
135
+
136
+ // Special handling for single entity type group - root on left, entities on right
137
+ const isSingleGroup = entityTypes.length === 1;
138
+
139
+ let rootX = 0;
140
+ let startX = 0;
141
+
142
+ if (isSingleGroup) {
143
+ // Position root on the left, entities on the right
144
+ rootX = -horizontalGap / 2;
145
+ startX = horizontalGap / 2;
146
+ } else {
147
+ // Calculate starting X position to center all groups (original behavior)
148
+ const totalWidth = (entityTypes.length - 1) * horizontalGap;
149
+ startX = -totalWidth / 2;
150
+ }
151
+
152
+ const nodes: Node<CatalogEntityNodeData>[] = [
153
+ // Root entity
154
+ {
155
+ id: rootNodeId,
156
+ type: GraphCustomNodeType.CatalogEntity,
157
+ position: { x: rootX, y: rootY },
158
+ data: { label: entity.title, entityType: entity.type, isRoot: true, entityKey: entity.key },
159
+ sourcePosition: Position.Bottom,
160
+ targetPosition: Position.Top,
161
+ },
162
+ ];
163
+
164
+ // Position entities by type groups
165
+ for (let typeIndex = 0; typeIndex < entityTypes.length; typeIndex++) {
166
+ const entityType = entityTypes[typeIndex];
167
+ const entitiesOfType = entityTypeGroups.get(entityType) ?? [];
168
+
169
+ // Calculate X position for this entity type group
170
+ const groupX = startX + typeIndex * horizontalGap;
171
+
172
+ // Calculate starting Y position to center entities vertically within the group
173
+ const groupHeight = (entitiesOfType.length - 1) * verticalGap;
174
+ const groupStartY = rootY + topMargin - groupHeight / 2;
175
+
176
+ // Position each entity within the group
177
+ for (let entityIndex = 0; entityIndex < entitiesOfType.length; entityIndex++) {
178
+ const entityData = entitiesOfType[entityIndex];
179
+ const entityY = groupStartY + entityIndex * verticalGap;
180
+
181
+ nodes.push({
182
+ id: entityData.id,
183
+ type: GraphCustomNodeType.CatalogEntity,
184
+ position: { x: groupX, y: entityY },
185
+ data: {
186
+ label: entityData.title,
187
+ entityType: entityData.entityType,
188
+ isRoot: false,
189
+ entityKey: entityData.key,
190
+ },
191
+ sourcePosition: Position.Bottom,
192
+ targetPosition: Position.Top,
193
+ });
194
+ }
195
+ }
196
+
197
+ return nodes;
198
+ }, [rootNodeId, entity.title, entity.type, entity.key, processedRelations]);
199
+
200
+ const computedEdges = useMemo<Edge[]>(() => {
201
+ return processedRelations.map((relation) => ({
202
+ id: `e-${rootNodeId}-${relation.id}`,
203
+ source: rootNodeId,
204
+ target: relation.id,
205
+ sourceHandle: GraphHandleType.Source, // Use the bottom handle of the center node
206
+ targetHandle: GraphHandleType.Target, // Use the target handle (top) of related nodes
207
+ type: GraphCustomEdgeType.CatalogEdge,
208
+ label: relation.relationLabel,
209
+ }));
210
+ }, [rootNodeId, processedRelations]);
211
+
212
+ const [nodes, setNodes, onNodesChange] =
213
+ useNodesState<Node<CatalogEntityNodeData>>(computedNodes);
214
+ const [edges, setEdges, onEdgesChange] = useEdgesState<Edge>(computedEdges);
215
+
216
+ useEffect(() => {
217
+ setNodes(computedNodes);
218
+ }, [computedNodes, setNodes]);
219
+
220
+ useEffect(() => {
221
+ setEdges(computedEdges);
222
+ }, [computedEdges, setEdges]);
223
+
224
+ const onConnect = useCallback(
225
+ (params: Connection) => setEdges((edgesSnapshot) => addEdge(params, edgesSnapshot)),
226
+ [setEdges],
227
+ );
228
+
229
+ return {
230
+ nodes,
231
+ edges,
232
+ onNodesChange,
233
+ onEdgesChange,
234
+ onConnect,
235
+ };
236
+ }
@@ -37,6 +37,7 @@ export * from './use-element-size';
37
37
  export * from './use-time-ago';
38
38
  export * from './use-input-key-commands';
39
39
  export * from './catalog/useCatalogEntities';
40
+ export * from './catalog/useGraph';
40
41
  export * from './use-active-page-version';
41
42
  export * from './use-page-versions';
42
43
  export * from './use-user-teams';
@@ -29,3 +29,4 @@ export { useModalScrollLock } from '../hooks/use-modal-scroll-lock';
29
29
  export { SecurityVariablesEnvSuffix } from '../constants/environments';
30
30
  export { isUndefined, isString, isNotNull, isObject } from '../utils/type-guards';
31
31
  export { ThemeDataContext, type ThemeDataTransferObject } from '../contexts/ThemeDataContext';
32
+ export { ENTITY_RELATION_TYPES } from '../constants/catalog';
@@ -1,2 +1,3 @@
1
1
  export * from './global';
2
2
  export * from './dark';
3
+ export { xyflow } from './xyflow';