@truedat/dd 8.11.6 → 8.11.7

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 (43) hide show
  1. package/package.json +4 -3
  2. package/src/components/Graphs.js +30 -4
  3. package/src/components/LineageContextMenu.js +185 -58
  4. package/src/components/LineageDownloadButton.js +16 -6
  5. package/src/components/LineageEventsPanel.js +80 -27
  6. package/src/components/LineageEventsTable.js +7 -3
  7. package/src/components/LineageGraph.js +5144 -306
  8. package/src/components/LineageGraphToolbar.js +896 -0
  9. package/src/components/LineageInspectorPanel.js +748 -0
  10. package/src/components/LineageResourceNode.js +501 -0
  11. package/src/components/LineageRoutes.js +1 -2
  12. package/src/components/LineageSelectionPanel.js +28 -12
  13. package/src/components/StructureGraph.js +8 -1
  14. package/src/components/StructureGraphView.js +14 -0
  15. package/src/components/StructureImpact.js +2 -22
  16. package/src/components/StructureLineage.js +2 -19
  17. package/src/components/StructuresUploadEventsTable.js +0 -3
  18. package/src/components/__tests__/LineageContextMenu.spec.js +42 -0
  19. package/src/components/__tests__/LineageGraph.spec.js +896 -0
  20. package/src/components/__tests__/LineageGraphInteractions.spec.js +660 -0
  21. package/src/components/__tests__/LineageGraphLayout.spec.js +620 -0
  22. package/src/components/__tests__/LineageGraphToolbar.spec.js +366 -0
  23. package/src/components/__tests__/LineageHierarchy.spec.js +116 -0
  24. package/src/components/__tests__/LineageInspectorPanel.spec.js +357 -0
  25. package/src/components/__tests__/LineageResourceNode.spec.js +338 -0
  26. package/src/components/__tests__/LineageRoutes.spec.js +27 -9
  27. package/src/components/__tests__/__snapshots__/LineageDownloadButton.spec.js.snap +23 -3
  28. package/src/components/__tests__/__snapshots__/LineageForm.spec.js.snap +23 -3
  29. package/src/components/__tests__/lineageEventHelpers.spec.js +60 -0
  30. package/src/components/lineageEventHelpers.js +53 -17
  31. package/src/reducers/__tests__/lineageEvents.spec.js +164 -0
  32. package/src/reducers/__tests__/lineageQuery.spec.js +11 -0
  33. package/src/reducers/lineageEvents.js +68 -2
  34. package/src/reducers/lineageQuery.js +2 -6
  35. package/src/styles/LineageGraphColors.less +105 -0
  36. package/src/styles/LineageGraphCore.less +20 -0
  37. package/src/styles/LineageResourceNode.less +711 -0
  38. package/src/styles/lineageGraph.less +2973 -84
  39. package/src/utils/__tests__/lineageGraphIndex.spec.js +52 -0
  40. package/src/utils/__tests__/lineageLayout.spec.js +234 -0
  41. package/src/utils/__tests__/lineageTopology.spec.js +256 -0
  42. package/src/utils/lineageGraphIndex.js +296 -0
  43. package/src/utils/lineageLayout.js +1047 -0
@@ -0,0 +1,501 @@
1
+ import LineageQueryOrigin from "@truedat/core/components/graph/LineageQueryOrigin";
2
+ import { memo, useContext } from "react";
3
+ import PropTypes from "prop-types";
4
+ import { Icon } from "semantic-ui-react";
5
+ import { useIntl } from "react-intl";
6
+ import { Handle, Position } from "@truedat/core/components/graph/FlowPorts";
7
+ import { EdgeHoverContext } from "@truedat/core/components/graph/ColoredEdge";
8
+
9
+ const nodeText = (value) => {
10
+ if (value === undefined || value === null) return "";
11
+ if (typeof value === "object") {
12
+ return nodeText(value.name || value.label || value.value || value.id);
13
+ }
14
+
15
+ return `${value}`;
16
+ };
17
+
18
+ const fieldName = (field) => {
19
+ if (typeof field === "string") return field;
20
+
21
+ return nodeText(
22
+ field?.name ||
23
+ field?.label ||
24
+ field?.field ||
25
+ field?.external_id ||
26
+ field?.id,
27
+ );
28
+ };
29
+
30
+ const fieldType = (field) =>
31
+ typeof field === "object" && field
32
+ ? nodeText(
33
+ field.type || field.data_type || field.dataType || field.metadata?.type,
34
+ )
35
+ : "";
36
+
37
+ const fieldKey = (field, index) => `${fieldName(field) || "field"}-${index}`;
38
+ const fieldSourceHandleId = (index) => `field-source-${index}`;
39
+ const fieldTargetHandleId = (index) => `field-target-${index}`;
40
+ const fieldSourceLeftHandleId = (index) => `field-source-left-${index}`;
41
+ const fieldTargetRightHandleId = (index) => `field-target-right-${index}`;
42
+
43
+ const toQualityScore = (value) => {
44
+ if (value === undefined || value === null || value === "") return undefined;
45
+
46
+ const number =
47
+ typeof value === "number"
48
+ ? value
49
+ : Number(`${value}`.trim().replace(/%$/, ""));
50
+
51
+ if (!Number.isFinite(number)) return undefined;
52
+
53
+ return number <= 1 ? number * 100 : number;
54
+ };
55
+
56
+ export const lineageQualityLevel = (quality) => {
57
+ const score = toQualityScore(quality);
58
+
59
+ if (score === undefined) return undefined;
60
+ if (score >= 90) return "good";
61
+ if (score >= 75) return "warning";
62
+
63
+ return "poor";
64
+ };
65
+
66
+ const statusClass = (status) => {
67
+ const text = nodeText(status);
68
+ if (!text) return "";
69
+ return text.toLowerCase().replace(/[^a-z0-9]+/g, "-");
70
+ };
71
+
72
+ const focusModifier = (focusSelected, focusDirect, focusDimmed) => {
73
+ if (focusSelected) return "td-lineage-resource-node--focus-selected";
74
+ if (focusDirect) return "td-lineage-resource-node--focus-direct";
75
+ if (focusDimmed) return "td-lineage-resource-node--focus-dimmed";
76
+ return "";
77
+ };
78
+
79
+ const LineageField = ({
80
+ edgeState,
81
+ field,
82
+ index,
83
+ showHandles,
84
+ sourceConnected,
85
+ sourceLeftConnected,
86
+ targetConnected,
87
+ targetRightConnected,
88
+ }) => {
89
+ const name = fieldName(field);
90
+ const type = fieldType(field);
91
+ const isPK =
92
+ typeof field === "object" &&
93
+ (field?.isPK || field?.is_pk || field?.primary_key);
94
+ const isFK =
95
+ typeof field === "object" &&
96
+ (field?.isFK || field?.is_fk || field?.foreign_key);
97
+ const isCDE =
98
+ typeof field === "object" &&
99
+ (field?.isCDE ||
100
+ field?.is_cde ||
101
+ field?.critical_data_element ||
102
+ field?.metadata?.isCDE ||
103
+ field?.metadata?.is_cde);
104
+ const className = [
105
+ "td-lineage-resource-node__field",
106
+ edgeState ? `td-lineage-resource-node__field--${edgeState}` : "",
107
+ ]
108
+ .filter(Boolean)
109
+ .join(" ");
110
+
111
+ return (
112
+ <div className={className}>
113
+ {showHandles ? (
114
+ <Handle
115
+ id={fieldTargetHandleId(index)}
116
+ type="target"
117
+ position={Position.Left}
118
+ className={`td-lineage-resource-node__field-handle td-lineage-resource-node__field-handle--target td-lineage-resource-node__field-handle--edge-target${
119
+ targetConnected ? " td-lineage-node-handle--connected" : ""
120
+ }`}
121
+ />
122
+ ) : null}
123
+ <span className="td-lineage-resource-node__field-name" title={name}>
124
+ {isPK ? (
125
+ <span className="td-lineage-resource-node__field-key">PK</span>
126
+ ) : null}
127
+ {isFK ? (
128
+ <span className="td-lineage-resource-node__field-key">FK</span>
129
+ ) : null}
130
+ {isCDE ? (
131
+ <Icon
132
+ aria-label="Critical data element"
133
+ className="td-lineage-resource-node__field-cde"
134
+ name="certificate"
135
+ />
136
+ ) : null}
137
+ {name}
138
+ </span>
139
+ {type ? (
140
+ <span
141
+ className="td-lineage-resource-node__field-key td-lineage-resource-node__field-type-badge"
142
+ title={type}
143
+ >
144
+ {type}
145
+ </span>
146
+ ) : null}
147
+ {showHandles ? (
148
+ <Handle
149
+ id={fieldSourceLeftHandleId(index)}
150
+ type="source"
151
+ position={Position.Left}
152
+ className={`td-lineage-resource-node__field-handle td-lineage-resource-node__field-handle--source-left td-lineage-resource-node__field-handle--edge-source${
153
+ sourceLeftConnected ? " td-lineage-node-handle--connected" : ""
154
+ }`}
155
+ />
156
+ ) : null}
157
+ {showHandles ? (
158
+ <Handle
159
+ id={fieldSourceHandleId(index)}
160
+ type="source"
161
+ position={Position.Right}
162
+ className={`td-lineage-resource-node__field-handle td-lineage-resource-node__field-handle--source td-lineage-resource-node__field-handle--edge-source${
163
+ sourceConnected ? " td-lineage-node-handle--connected" : ""
164
+ }`}
165
+ />
166
+ ) : null}
167
+ {showHandles ? (
168
+ <Handle
169
+ id={fieldTargetRightHandleId(index)}
170
+ type="target"
171
+ position={Position.Right}
172
+ className={`td-lineage-resource-node__field-handle td-lineage-resource-node__field-handle--target-right td-lineage-resource-node__field-handle--edge-target${
173
+ targetRightConnected ? " td-lineage-node-handle--connected" : ""
174
+ }`}
175
+ />
176
+ ) : null}
177
+ </div>
178
+ );
179
+ };
180
+
181
+ LineageField.propTypes = {
182
+ edgeState: PropTypes.oneOf(["source", "target", "dimmed"]),
183
+ field: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
184
+ index: PropTypes.number,
185
+ showHandles: PropTypes.bool,
186
+ sourceConnected: PropTypes.bool,
187
+ sourceLeftConnected: PropTypes.bool,
188
+ targetConnected: PropTypes.bool,
189
+ targetRightConnected: PropTypes.bool,
190
+ };
191
+
192
+ const LineageResourceNode = ({ id, data }) => {
193
+ const { formatMessage } = useIntl();
194
+ const hoverCtx = useContext(EdgeHoverContext);
195
+ const isHovered = hoverCtx?.hoveredNodeId === id;
196
+ const isConnected =
197
+ (hoverCtx?.connectedNodeIds && hoverCtx.connectedNodeIds.has(id)) ||
198
+ (hoverCtx?.hoveredEdgeEndpoints &&
199
+ (hoverCtx.hoveredEdgeEndpoints.source === id ||
200
+ hoverCtx.hoveredEdgeEndpoints.target === id));
201
+ const handleMouseEnter = () => hoverCtx?.setHoveredNodeId(id);
202
+ const handleMouseLeave = () => hoverCtx?.setHoveredNodeId(null);
203
+ const {
204
+ connectedHandleIds = [],
205
+ entityType,
206
+ fields = [],
207
+ fieldHandleLimit = fields.length,
208
+ fieldsExpanded,
209
+ focusDimmed,
210
+ focusDirect,
211
+ focusSelected,
212
+ hiddenFieldsCount = 0,
213
+ isActive,
214
+ queryOrigin,
215
+ kind,
216
+ label,
217
+ lineageNode,
218
+ onToggleFields,
219
+ quality,
220
+ status,
221
+ systemTypeClassName,
222
+ systemTypeLabel,
223
+ systemTypeMissing,
224
+ totalFields = fields.length,
225
+ variant,
226
+ } = data;
227
+ const connectedHandles = new Set(connectedHandleIds);
228
+ const compact = variant === "lineage-compact";
229
+ const fieldLike = variant === "lineage-field";
230
+ const redesigned = variant === "lineage-redesigned" || fieldLike;
231
+ const resolvedKind = data.kind || data.lineageKind;
232
+ const isLeaf = totalFields === 0;
233
+ const entityTypeBadge = entityType ? (
234
+ <span className="td-lineage-resource-node__entity-badge" title={entityType}>
235
+ {formatMessage({
236
+ id: `lineage.graph.entity_type.${entityType}`,
237
+ defaultMessage: entityType,
238
+ })}
239
+ </span>
240
+ ) : null;
241
+ const statusText = status || "";
242
+ const qualityLevel = lineageQualityLevel(quality);
243
+ const hoveredEdgeTouchesNode =
244
+ hoverCtx?.hoveredEdgeEndpoints?.source === id ||
245
+ hoverCtx?.hoveredEdgeEndpoints?.target === id;
246
+ const fieldLikeSource =
247
+ fieldLike && hoverCtx?.hoveredEdgeEndpoints?.source === id;
248
+ const fieldLikeTarget =
249
+ fieldLike && hoverCtx?.hoveredEdgeEndpoints?.target === id;
250
+ const fieldLikePrimaryKey =
251
+ fieldLike &&
252
+ (lineageNode?.isPK ||
253
+ lineageNode?.is_pk ||
254
+ lineageNode?.primary_key ||
255
+ lineageNode?.metadata?.isPK ||
256
+ lineageNode?.metadata?.is_pk);
257
+ const fieldLikeCDE =
258
+ fieldLike &&
259
+ (lineageNode?.isCDE ||
260
+ lineageNode?.is_cde ||
261
+ lineageNode?.critical_data_element ||
262
+ lineageNode?.metadata?.isCDE ||
263
+ lineageNode?.metadata?.is_cde);
264
+ const edgeStateForField = (index) => {
265
+ if (!hoveredEdgeTouchesNode) return undefined;
266
+
267
+ if (
268
+ hoverCtx.hoveredEdgeEndpoints.source === id &&
269
+ hoverCtx.hoveredEdgeEndpoints.sourceFieldIndex === index
270
+ ) {
271
+ return "source";
272
+ }
273
+
274
+ if (
275
+ hoverCtx.hoveredEdgeEndpoints.target === id &&
276
+ hoverCtx.hoveredEdgeEndpoints.targetFieldIndex === index
277
+ ) {
278
+ return "target";
279
+ }
280
+
281
+ return "dimmed";
282
+ };
283
+ const hasFieldDisclosure = totalFields > 6 && onToggleFields;
284
+ const fieldsId = `lineage-node-fields-${id || "unknown"}`;
285
+ const fieldDisclosureLabel = fieldsExpanded
286
+ ? formatMessage({
287
+ id: "lineage.graph.node.fields.less",
288
+ defaultMessage: "Show less",
289
+ })
290
+ : formatMessage(
291
+ {
292
+ id: "lineage.graph.node.fields.more",
293
+ defaultMessage: "+ {count} elements",
294
+ },
295
+ { count: hiddenFieldsCount },
296
+ );
297
+ const resolvedStatusClass = statusClass(status);
298
+ const className = [
299
+ "td-lineage-resource-node",
300
+ compact ? "td-lineage-resource-node--compact" : "",
301
+ redesigned ? "td-lineage-resource-node--redesigned" : "",
302
+ isLeaf ? "td-lineage-resource-node--leaf" : "",
303
+ fieldLike ? "td-lineage-resource-node--field-like" : "",
304
+ fieldLikeSource ? "td-lineage-resource-node--field-source" : "",
305
+ fieldLikeTarget ? "td-lineage-resource-node--field-target" : "",
306
+ kind ? `td-lineage-resource-node--${kind}` : "",
307
+ systemTypeClassName
308
+ ? `td-lineage-resource-node--system-type-${systemTypeClassName}`
309
+ : "",
310
+ resolvedStatusClass
311
+ ? `td-lineage-resource-node--status-${resolvedStatusClass}`
312
+ : "",
313
+ qualityLevel ? `td-lineage-resource-node--quality-${qualityLevel}` : "",
314
+ focusModifier(focusSelected, focusDirect, focusDimmed),
315
+ isActive ? "td-lineage-resource-node--active" : "",
316
+ queryOrigin ? "td-lineage-resource-node--query-origin" : "",
317
+ isHovered ? "td-lineage-resource-node--hovered" : "",
318
+ isConnected ? "td-lineage-resource-node--connected" : "",
319
+ ]
320
+ .filter(Boolean)
321
+ .join(" ");
322
+
323
+ return (
324
+ <div
325
+ className={className}
326
+ onMouseEnter={handleMouseEnter}
327
+ onMouseLeave={handleMouseLeave}
328
+ >
329
+ <Handle
330
+ className={
331
+ connectedHandles.has("start-node")
332
+ ? "td-lineage-node-handle--connected"
333
+ : ""
334
+ }
335
+ id="start-node"
336
+ type="target"
337
+ position={Position.Left}
338
+ />
339
+ <Handle
340
+ className={
341
+ connectedHandles.has("source-left-node")
342
+ ? "td-lineage-node-handle--connected"
343
+ : ""
344
+ }
345
+ id="source-left-node"
346
+ type="source"
347
+ position={Position.Left}
348
+ />
349
+ <div className="td-lineage-resource-node__header">
350
+ <span className="td-lineage-resource-node__title">
351
+ {fieldLikePrimaryKey ? (
352
+ <span className="td-lineage-resource-node__field-key">PK</span>
353
+ ) : null}
354
+ {fieldLikeCDE ? (
355
+ <Icon
356
+ aria-label="Critical data element"
357
+ className="td-lineage-resource-node__field-cde"
358
+ name="certificate"
359
+ />
360
+ ) : null}
361
+ <span className="td-lineage-resource-node__label" title={label}>
362
+ {label}
363
+ </span>
364
+ <LineageQueryOrigin origin={queryOrigin} />
365
+ {!queryOrigin &&
366
+ !fieldLike &&
367
+ !systemTypeMissing &&
368
+ systemTypeLabel ? (
369
+ <span className="td-lineage-resource-node__kind">
370
+ <span className="td-lineage-resource-node__system-group">
371
+ {systemTypeLabel}
372
+ </span>
373
+ </span>
374
+ ) : null}
375
+ </span>
376
+ <span className="td-lineage-resource-node__header-meta">
377
+ {entityTypeBadge}
378
+ {quality ? (
379
+ <span
380
+ className={`td-lineage-resource-node__quality${
381
+ qualityLevel
382
+ ? ` td-lineage-resource-node__quality--${qualityLevel}`
383
+ : ""
384
+ }`}
385
+ >
386
+ <Icon name="bolt" />
387
+ {quality} QC
388
+ </span>
389
+ ) : null}
390
+ {status ? (
391
+ <span
392
+ className="td-lineage-resource-node__header-status"
393
+ title={statusText}
394
+ >
395
+ <span className="td-lineage-resource-node__status-dot" />
396
+ </span>
397
+ ) : null}
398
+ </span>
399
+ </div>
400
+ {fields.length ? (
401
+ <div
402
+ className={`td-lineage-resource-node__fields nowheel${
403
+ fieldsExpanded && totalFields > 10
404
+ ? " td-lineage-resource-node__fields--scrollable"
405
+ : ""
406
+ }`}
407
+ id={fieldsId}
408
+ onWheel={(event) => event.stopPropagation()}
409
+ >
410
+ {fields.map((field, index) => (
411
+ <LineageField
412
+ edgeState={edgeStateForField(index)}
413
+ field={field}
414
+ index={index}
415
+ key={fieldKey(field, index)}
416
+ showHandles={index < fieldHandleLimit}
417
+ sourceConnected={connectedHandles.has(fieldSourceHandleId(index))}
418
+ sourceLeftConnected={connectedHandles.has(
419
+ fieldSourceLeftHandleId(index),
420
+ )}
421
+ targetConnected={connectedHandles.has(fieldTargetHandleId(index))}
422
+ targetRightConnected={connectedHandles.has(
423
+ fieldTargetRightHandleId(index),
424
+ )}
425
+ />
426
+ ))}
427
+ </div>
428
+ ) : null}
429
+ {hasFieldDisclosure ? (
430
+ <button
431
+ aria-controls={fieldsId}
432
+ aria-expanded={Boolean(fieldsExpanded)}
433
+ className="td-lineage-resource-node__field-more nodrag nopan nowheel"
434
+ onClick={(event) => {
435
+ event.preventDefault();
436
+ event.stopPropagation();
437
+ onToggleFields();
438
+ }}
439
+ onMouseDown={(event) => event.stopPropagation()}
440
+ onPointerDown={(event) => event.stopPropagation()}
441
+ type="button"
442
+ >
443
+ {fieldDisclosureLabel}
444
+ </button>
445
+ ) : null}
446
+ <Handle
447
+ className={
448
+ connectedHandles.has("end-node")
449
+ ? "td-lineage-node-handle--connected"
450
+ : ""
451
+ }
452
+ id="end-node"
453
+ type="source"
454
+ position={Position.Right}
455
+ />
456
+ <Handle
457
+ className={
458
+ connectedHandles.has("target-right-node")
459
+ ? "td-lineage-node-handle--connected"
460
+ : ""
461
+ }
462
+ id="target-right-node"
463
+ type="target"
464
+ position={Position.Right}
465
+ />
466
+ </div>
467
+ );
468
+ };
469
+
470
+ LineageResourceNode.propTypes = {
471
+ id: PropTypes.string,
472
+ data: PropTypes.shape({
473
+ allFields: PropTypes.array,
474
+ connectedHandleIds: PropTypes.arrayOf(PropTypes.string),
475
+ entityType: PropTypes.string,
476
+ fields: PropTypes.array,
477
+ fieldHandleLimit: PropTypes.number,
478
+ fieldsExpanded: PropTypes.bool,
479
+ focusDimmed: PropTypes.bool,
480
+ focusDirect: PropTypes.bool,
481
+ focusSelected: PropTypes.bool,
482
+ hiddenFieldsCount: PropTypes.number,
483
+ iconName: PropTypes.string,
484
+ isActive: PropTypes.bool,
485
+ queryOrigin: PropTypes.oneOf(["direct", "contained"]),
486
+ kind: PropTypes.string,
487
+ label: PropTypes.string,
488
+ lineageNode: PropTypes.object,
489
+ meta: PropTypes.string,
490
+ onToggleFields: PropTypes.func,
491
+ quality: PropTypes.string,
492
+ status: PropTypes.string,
493
+ systemTypeClassName: PropTypes.string,
494
+ systemTypeLabel: PropTypes.string,
495
+ systemTypeMissing: PropTypes.bool,
496
+ totalFields: PropTypes.number,
497
+ variant: PropTypes.string,
498
+ }),
499
+ };
500
+
501
+ export default memo(LineageResourceNode);
@@ -9,9 +9,8 @@ export const LineageRoutes = () => {
9
9
  return (
10
10
  <Routes>
11
11
  <Route path={GRAPHS} element={<ProtectedRoute authorization="lineage" />}>
12
- <Route index element={<Graphs />} />
13
12
  <Route
14
- path=":id"
13
+ path=":id?"
15
14
  element={
16
15
  <>
17
16
  <Graphs />
@@ -3,6 +3,7 @@ import PropTypes from "prop-types";
3
3
  import { connect } from "react-redux";
4
4
  import { FormattedMessage, useIntl } from "react-intl";
5
5
  import { Button, Icon } from "semantic-ui-react";
6
+ import { TrendingUpDown } from "lucide-react";
6
7
  import { fetchLineageEvents } from "../routines";
7
8
  import LineageForm from "./LineageForm";
8
9
  import LineageEventsPanel from "./LineageEventsPanel";
@@ -24,10 +25,7 @@ export const LineageSelectionPanel = ({
24
25
  const toggleLabel = formatMessage({
25
26
  id: collapsed ? "lineage.sidebar.expand" : "lineage.sidebar.collapse",
26
27
  });
27
- const activeRailLabel =
28
- activeSidebarTab === "events"
29
- ? "lineage.sidebar.tabs.graphs"
30
- : "lineage.sidebar.tabs.lineage";
28
+ const activeRailLabel = "lineage.sidebar.rail";
31
29
  const openTab = (tab) => {
32
30
  setActiveSidebarTab(tab);
33
31
  if (tab === "events") fetchLineageEvents();
@@ -40,14 +38,28 @@ export const LineageSelectionPanel = ({
40
38
  useEffect(() => {
41
39
  if (collapsed) return;
42
40
 
43
- const handleClickOutside = (e) => {
41
+ const handleGraphInteraction = (e) => {
42
+ if (e.target.closest?.(".lineage-events-panel__status-popup")) return;
44
43
  if (sidebarRef.current && !sidebarRef.current.contains(e.target)) {
45
44
  onToggle();
46
45
  }
47
46
  };
48
47
 
49
- document.addEventListener("mousedown", handleClickOutside);
50
- return () => document.removeEventListener("mousedown", handleClickOutside);
48
+ document.addEventListener("mousedown", handleGraphInteraction, {
49
+ capture: true,
50
+ });
51
+ document.addEventListener("wheel", handleGraphInteraction, {
52
+ capture: true,
53
+ passive: true,
54
+ });
55
+ return () => {
56
+ document.removeEventListener("mousedown", handleGraphInteraction, {
57
+ capture: true,
58
+ });
59
+ document.removeEventListener("wheel", handleGraphInteraction, {
60
+ capture: true,
61
+ });
62
+ };
51
63
  }, [collapsed, onToggle]);
52
64
 
53
65
  return (
@@ -67,7 +79,7 @@ export const LineageSelectionPanel = ({
67
79
  type="button"
68
80
  >
69
81
  <span className="lineage-view__sidebar-tab-icon">
70
- <Icon name="sitemap" />
82
+ <TrendingUpDown size={16} aria-hidden="true" />
71
83
  </span>
72
84
  <span className="lineage-view__sidebar-tab-label">
73
85
  <FormattedMessage
@@ -113,16 +125,17 @@ export const LineageSelectionPanel = ({
113
125
  <div
114
126
  className={`lineage-view__sidebar-content lineage-view__sidebar-content--${activeSidebarTab}`}
115
127
  >
116
- {activeSidebarTab === "lineage" ? (
128
+ <div hidden={activeSidebarTab !== "lineage"}>
117
129
  <LineageForm
118
130
  autoCollapse={false}
119
131
  collapsible={false}
120
132
  onGraphSubmit={onGraphLoad}
121
133
  showDownloadButton={false}
122
134
  />
123
- ) : (
135
+ </div>
136
+ {activeSidebarTab === "events" ? (
124
137
  <LineageEventsPanel onGraphLoad={onGraphLoad} />
125
- )}
138
+ ) : null}
126
139
  </div>
127
140
  </div>
128
141
  <Button
@@ -140,7 +153,10 @@ export const LineageSelectionPanel = ({
140
153
  >
141
154
  <Icon name="angle right" />
142
155
  <span>
143
- <FormattedMessage id={activeRailLabel} />
156
+ <FormattedMessage
157
+ id={activeRailLabel}
158
+ defaultMessage="Trazar linaje"
159
+ />
144
160
  </span>
145
161
  </Button>
146
162
  </aside>
@@ -14,6 +14,7 @@ export const StructureGraph = ({
14
14
  id,
15
15
  graphId,
16
16
  height,
17
+ simplified,
17
18
  type,
18
19
  }) => {
19
20
  useEffect(() => {
@@ -25,7 +26,12 @@ export const StructureGraph = ({
25
26
  return degree ? (
26
27
  <>
27
28
  <GraphRedirector />
28
- <LineageGraph height={height || "640px"} graph={graph} />
29
+ <LineageGraph
30
+ height={height || "640px"}
31
+ graph={graph}
32
+ simplified={simplified}
33
+ structureId={id}
34
+ />
29
35
  </>
30
36
  ) : null;
31
37
  };
@@ -38,6 +44,7 @@ StructureGraph.propTypes = {
38
44
  id: PropTypes.string,
39
45
  graphId: PropTypes.number,
40
46
  height: PropTypes.string,
47
+ simplified: PropTypes.bool,
41
48
  type: PropTypes.string,
42
49
  };
43
50
 
@@ -0,0 +1,14 @@
1
+ import PropTypes from "prop-types";
2
+ import StructureGraph from "./StructureGraph";
3
+
4
+ export const StructureGraphView = (props) => (
5
+ <div className="structure-lineage">
6
+ <StructureGraph {...props} height="100%" simplified />
7
+ </div>
8
+ );
9
+
10
+ StructureGraphView.propTypes = {
11
+ graph: PropTypes.object,
12
+ };
13
+
14
+ export default StructureGraphView;
@@ -1,25 +1,5 @@
1
1
  import { connect } from "react-redux";
2
- import PropTypes from "prop-types";
3
- import { Grid } from "semantic-ui-react";
4
- import StructureGraph from "./StructureGraph";
5
- import LineageDownloadButton from "./LineageDownloadButton";
6
-
7
- export const StructureImpact = (props) => (
8
- <>
9
- <Grid>
10
- <Grid.Row>
11
- <Grid.Column width={1} floated="right">
12
- <LineageDownloadButton graph={props.graph} />
13
- </Grid.Column>
14
- </Grid.Row>
15
- </Grid>
16
- <StructureGraph {...props} />
17
- </>
18
- );
19
-
20
- StructureImpact.propTypes = {
21
- graph: PropTypes.object,
22
- };
2
+ import StructureGraphView from "./StructureGraphView";
23
3
 
24
4
  const mapStateToProps = ({
25
5
  structureImpactId: graphId,
@@ -30,4 +10,4 @@ const mapStateToProps = ({
30
10
  type: "impact",
31
11
  });
32
12
 
33
- export default connect(mapStateToProps)(StructureImpact);
13
+ export default connect(mapStateToProps)(StructureGraphView);