@principal-ai/subsystems-react 0.17.0 → 0.18.0
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.d.ts +7 -44
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -32
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +9 -199
- package/src/components/ConfigurationSelector.tsx +0 -133
- package/src/components/GraphRenderer.tsx +0 -3195
- package/src/components/MultiCanvasRenderer.tsx +0 -295
- package/src/components/NodeTooltip.tsx +0 -279
- package/src/components/PendingChanges.test.tsx +0 -375
- package/src/components/SelectionSidebar.tsx +0 -352
- package/src/components/SequenceDiagramRenderer.tsx +0 -1156
- package/src/components/WorkflowSequenceDiagram.tsx +0 -270
- package/src/components/dashboard/DashboardRenderer.tsx +0 -317
- package/src/components/dashboard/MetricPanel.tsx +0 -254
- package/src/components/dashboard/MockDataProvider.ts +0 -330
- package/src/components/dashboard/components/BarChart.tsx +0 -299
- package/src/components/dashboard/components/LineChart.tsx +0 -279
- package/src/components/dashboard/components/MetricCard.tsx +0 -270
- package/src/components/dashboard/components/SourceLink.tsx +0 -63
- package/src/components/dashboard/components/TimeRangeSelector.tsx +0 -280
- package/src/components/dashboard/components/index.ts +0 -5
- package/src/components/dashboard/index.ts +0 -47
- package/src/components/dashboard/types.ts +0 -126
- package/src/components/state-view/PipelineView.tsx +0 -347
- package/src/components/state-view/index.ts +0 -14
- package/src/components/state-view/types.ts +0 -261
- package/src/components/state-view/useStateView.ts +0 -205
- package/src/contexts/GraphEditContext.tsx +0 -27
- package/src/contexts/TooltipPortalContext.ts +0 -8
- package/src/edges/CustomEdge.tsx +0 -402
- package/src/edges/GenericEdge.tsx +0 -36
- package/src/hooks/usePathBasedEvents.ts +0 -192
- package/src/hooks/useSequenceLayout.ts +0 -543
- package/src/hooks/useUndoRedo.ts +0 -144
- package/src/nodes/CustomNode.tsx +0 -1231
- package/src/nodes/GenericNode.tsx +0 -55
- package/src/nodes/otel/OtelBoundaryNode.tsx +0 -224
- package/src/nodes/otel/OtelEventNode.tsx +0 -225
- package/src/nodes/otel/OtelResourceNode.tsx +0 -251
- package/src/nodes/otel/OtelScopeNode.tsx +0 -221
- package/src/nodes/otel/OtelSpanConventionNode.tsx +0 -295
- package/src/nodes/otel/index.ts +0 -23
- package/src/nodes/otel/shared/NodeBadges.tsx +0 -295
- package/src/nodes/otel/shared/NodeContent.tsx +0 -204
- package/src/nodes/otel/shared/index.ts +0 -8
- package/src/nodes/otel/shared/types.ts +0 -138
- package/src/nodes/otel/shared/useNodeBehavior.ts +0 -114
- package/src/stories/Audit/BoundaryNodes.stories.tsx +0 -385
- package/src/stories/Audit/CanvasEdgeTypes.stories.tsx +0 -1448
- package/src/stories/Audit/CanvasNodeTypes.stories.tsx +0 -1049
- package/src/stories/Audit/ColorPriority.stories.tsx +0 -895
- package/src/stories/Audit/DiamondBadges.stories.tsx +0 -629
- package/src/stories/Audit/NodeDimensionsTesting.stories.tsx +0 -724
- package/src/stories/Audit/NodeFieldsAudit.stories.tsx +0 -996
- package/src/stories/Audit/NodeFontSizeTesting.stories.tsx +0 -715
- package/src/stories/Audit/NodeShapes.stories.tsx +0 -1208
- package/src/stories/Audit/WideNodesTesting.stories.tsx +0 -1045
- package/src/stories/Components/DashboardRenderer.stories.tsx +0 -263
- package/src/stories/Components/GraphRenderer.stories.tsx +0 -3236
- package/src/stories/Components/MultiCanvasRenderer.stories.tsx +0 -370
- package/src/stories/Components/SequenceDiagram.stories.tsx +0 -255
- package/src/stories/Components/StateView.stories.tsx +0 -417
- package/src/stories/Components/TraceViewer.stories.tsx +0 -442
- package/src/stories/Components/WorkflowSequenceDiagram.stories.tsx +0 -802
- package/src/stories/Features/AnimationWorkshop.stories.tsx +0 -727
- package/src/stories/Features/ChangeTypeVisual.stories.tsx +0 -67
- package/src/stories/Features/EventDrivenAnimations.stories.tsx +0 -513
- package/src/stories/Features/MultiConfig.stories.tsx +0 -539
- package/src/stories/Layout/ElkEdgeRouting.stories.tsx +0 -539
- package/src/stories/Layout/GraphOrientation.stories.tsx +0 -500
- package/src/stories/Layout/MultiDirectionalConnections.stories.tsx +0 -352
- package/src/stories/Nodes/NodeDefinitionComparison.stories.tsx +0 -560
- package/src/stories/Nodes/NodeNameFallbacks.stories.tsx +0 -491
- package/src/stories/Nodes/NumericColors.stories.tsx +0 -440
- package/src/stories/OTEL/EventNameDisplay.stories.tsx +0 -694
- package/src/stories/OTEL/EventNameFallback.stories.tsx +0 -578
- package/src/stories/OTEL/OtelComponents.stories.tsx +0 -422
- package/src/stories/OTEL/OtelNodeTypesPrototype.stories.tsx +0 -806
- package/src/stories/OTEL/RawEventCards.stories.tsx +0 -57
- package/src/stories/OTEL/SpanBadges.stories.tsx +0 -840
- package/src/stories/OTEL/ValidationEventsCanvas.stories.tsx +0 -209
- package/src/stories/RealWorld/BacklogMdCanvases.stories.tsx +0 -721
- package/src/stories/RealWorld/FileCitySequence.stories.tsx +0 -516
- package/src/stories/RealWorld/RealCanvasFiles.stories.tsx +0 -336
- package/src/stories/__traces__/test-run.canvas.json +0 -241
- package/src/stories/data/activity-feed-analytics.dashboard.json +0 -300
- package/src/stories/data/file-city-images-transformed.otel.canvas.json +0 -295
- package/src/stories/data/file-city-workflows.json +0 -269
- package/src/stories/data/graph-converter-test-execution.json +0 -443
- package/src/stories/data/graph-converter-test.workflow.json +0 -105
- package/src/stories/data/graph-converter-validated-execution.json +0 -58
- package/src/utils/animationMapping.ts +0 -166
- package/src/utils/canvasBounds.ts +0 -146
- package/src/utils/graphConverter.ts +0 -148
- package/src/utils/iconResolver.tsx +0 -53
- package/src/utils/orientationUtils.ts +0 -73
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import type { NodeTypeDefinition } from '@principal-ai/subsystems-core';
|
|
3
|
-
|
|
4
|
-
export interface GenericNodeProps {
|
|
5
|
-
/** Node ID */
|
|
6
|
-
id: string;
|
|
7
|
-
|
|
8
|
-
/** Node type definition from configuration */
|
|
9
|
-
typeDefinition: NodeTypeDefinition;
|
|
10
|
-
|
|
11
|
-
/** Node data */
|
|
12
|
-
data: Record<string, unknown>;
|
|
13
|
-
|
|
14
|
-
/** Current state (if applicable) */
|
|
15
|
-
state?: string;
|
|
16
|
-
|
|
17
|
-
/** Whether this node has violations */
|
|
18
|
-
hasViolations?: boolean;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Generic node renderer that adapts based on NodeTypeDefinition
|
|
23
|
-
* TODO: Implement different shapes, icons, and states
|
|
24
|
-
*/
|
|
25
|
-
export const GenericNode: React.FC<GenericNodeProps> = ({
|
|
26
|
-
id,
|
|
27
|
-
typeDefinition,
|
|
28
|
-
state,
|
|
29
|
-
hasViolations,
|
|
30
|
-
}) => {
|
|
31
|
-
// Get color based on state or default
|
|
32
|
-
const color =
|
|
33
|
-
state && typeDefinition.states?.[state]?.color
|
|
34
|
-
? typeDefinition.states[state].color
|
|
35
|
-
: typeDefinition.color || '#888';
|
|
36
|
-
|
|
37
|
-
return (
|
|
38
|
-
<div
|
|
39
|
-
style={{
|
|
40
|
-
padding: '10px',
|
|
41
|
-
border: `2px solid ${hasViolations ? 'red' : color}`,
|
|
42
|
-
borderRadius: typeDefinition.shape === 'circle' ? '50%' : '4px',
|
|
43
|
-
backgroundColor: 'white',
|
|
44
|
-
minWidth: '60px',
|
|
45
|
-
textAlign: 'center',
|
|
46
|
-
}}
|
|
47
|
-
>
|
|
48
|
-
<div style={{ fontSize: '12px', fontWeight: 'bold' }}>{id}</div>
|
|
49
|
-
{state && <div style={{ fontSize: '10px', color: '#666' }}>{state}</div>}
|
|
50
|
-
<div style={{ fontSize: '10px' }}>
|
|
51
|
-
<strong>TODO:</strong> Render shapes, icons
|
|
52
|
-
</div>
|
|
53
|
-
</div>
|
|
54
|
-
);
|
|
55
|
-
};
|
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OTEL Boundary Node
|
|
3
|
-
*
|
|
4
|
-
* Renders boundary nodes as rounded rectangles with:
|
|
5
|
-
* - Direction identifier (inbound/outbound)
|
|
6
|
-
* - Direction badge (arrow indicating flow)
|
|
7
|
-
* - Status and references badges
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import React from 'react';
|
|
11
|
-
import { Handle, Position, NodeResizer } from '@xyflow/react';
|
|
12
|
-
import type { NodeProps, Node } from '@xyflow/react';
|
|
13
|
-
import { useTheme } from '@principal-ade/industry-theme';
|
|
14
|
-
import { NodeTooltip } from '../../components/NodeTooltip';
|
|
15
|
-
import type { OtelInfo } from '../../components/NodeTooltip';
|
|
16
|
-
import { NodeBadges } from './shared/NodeBadges';
|
|
17
|
-
import { NodeContent } from './shared/NodeContent';
|
|
18
|
-
import { useNodeBehavior } from './shared/useNodeBehavior';
|
|
19
|
-
import type { BoundaryData } from './shared/types';
|
|
20
|
-
|
|
21
|
-
export interface OtelBoundaryNodeData extends Record<string, unknown> {
|
|
22
|
-
name: string;
|
|
23
|
-
typeDefinition: {
|
|
24
|
-
color?: string;
|
|
25
|
-
icon?: string;
|
|
26
|
-
states?: Record<string, { color?: string; label?: string; icon?: string }>;
|
|
27
|
-
};
|
|
28
|
-
state?: string;
|
|
29
|
-
hasViolations?: boolean;
|
|
30
|
-
data: {
|
|
31
|
-
color?: string;
|
|
32
|
-
scopeColor?: string;
|
|
33
|
-
spanColor?: string;
|
|
34
|
-
stroke?: string;
|
|
35
|
-
icon?: string;
|
|
36
|
-
status?: 'draft' | 'approved' | 'implemented';
|
|
37
|
-
description?: string;
|
|
38
|
-
sources?: string[];
|
|
39
|
-
references?: string[];
|
|
40
|
-
states?: Record<string, { color?: string; label?: string; icon?: string }>;
|
|
41
|
-
boundary?: BoundaryData;
|
|
42
|
-
otel?: { files?: string[] };
|
|
43
|
-
};
|
|
44
|
-
editable?: boolean;
|
|
45
|
-
tooltipsEnabled?: boolean;
|
|
46
|
-
shiftKeyPressed?: boolean;
|
|
47
|
-
isHighlighted?: boolean;
|
|
48
|
-
isActive?: boolean;
|
|
49
|
-
isHidden?: boolean;
|
|
50
|
-
animationType?: 'pulse' | 'flash' | 'shake' | 'entry' | null;
|
|
51
|
-
animationDuration?: number;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export const OtelBoundaryNode: React.FC<NodeProps<Node<OtelBoundaryNodeData>>> = ({
|
|
55
|
-
data,
|
|
56
|
-
selected,
|
|
57
|
-
dragging,
|
|
58
|
-
}) => {
|
|
59
|
-
const { theme } = useTheme();
|
|
60
|
-
const nodeProps = data;
|
|
61
|
-
const {
|
|
62
|
-
typeDefinition,
|
|
63
|
-
state,
|
|
64
|
-
hasViolations,
|
|
65
|
-
data: nodeData,
|
|
66
|
-
editable = false,
|
|
67
|
-
tooltipsEnabled = true,
|
|
68
|
-
shiftKeyPressed = false,
|
|
69
|
-
isHighlighted = false,
|
|
70
|
-
isActive = true,
|
|
71
|
-
isHidden = false,
|
|
72
|
-
animationType,
|
|
73
|
-
animationDuration = 1000,
|
|
74
|
-
} = nodeProps;
|
|
75
|
-
|
|
76
|
-
const {
|
|
77
|
-
nodeRef,
|
|
78
|
-
showTooltip,
|
|
79
|
-
handleMouseDown,
|
|
80
|
-
handleMouseEnter,
|
|
81
|
-
handleMouseLeave,
|
|
82
|
-
handleResizeEnd,
|
|
83
|
-
} = useNodeBehavior({ editable, tooltipsEnabled, shiftKeyPressed, selected, dragging });
|
|
84
|
-
|
|
85
|
-
const nodeOpacity = isHidden ? 0.4 : isActive ? 1 : 0.1;
|
|
86
|
-
|
|
87
|
-
// Color resolution
|
|
88
|
-
const scopeColor = nodeData.scopeColor as string | undefined;
|
|
89
|
-
const spanColor = nodeData.spanColor as string | undefined;
|
|
90
|
-
const nodeDataColor = nodeData.color as string | undefined;
|
|
91
|
-
// Fill color priority: explicit color > scope color > type definition color > default cyan
|
|
92
|
-
const baseFillColor = nodeDataColor || scopeColor || typeDefinition.color || '#06b6d4';
|
|
93
|
-
const fillColor = baseFillColor;
|
|
94
|
-
// Stroke color priority: explicit stroke > span color (workflow context) > fill color
|
|
95
|
-
const nodeDataStroke = nodeData.stroke as string | undefined;
|
|
96
|
-
const strokeColor = nodeDataStroke || spanColor || fillColor;
|
|
97
|
-
|
|
98
|
-
// Display info
|
|
99
|
-
const displayName = nodeProps.name;
|
|
100
|
-
const boundaryData = nodeData.boundary;
|
|
101
|
-
const identifier = boundaryData?.direction;
|
|
102
|
-
|
|
103
|
-
// Badge data
|
|
104
|
-
const status = nodeData.status;
|
|
105
|
-
const sourceFiles = nodeData.otel?.files || nodeData.sources;
|
|
106
|
-
const references = nodeData.references;
|
|
107
|
-
const description = nodeData.description;
|
|
108
|
-
|
|
109
|
-
// Icon
|
|
110
|
-
const icon =
|
|
111
|
-
(nodeData.icon as string) ||
|
|
112
|
-
(state && nodeData.states?.[state]?.icon) ||
|
|
113
|
-
typeDefinition.icon;
|
|
114
|
-
|
|
115
|
-
const stateDefinitions = nodeData.states || typeDefinition.states;
|
|
116
|
-
|
|
117
|
-
const getAnimationClass = () => {
|
|
118
|
-
switch (animationType) {
|
|
119
|
-
case 'pulse': return 'node-pulse';
|
|
120
|
-
case 'flash': return 'node-flash';
|
|
121
|
-
case 'shake': return 'node-shake';
|
|
122
|
-
case 'entry': return 'node-entry';
|
|
123
|
-
default: return '';
|
|
124
|
-
}
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
const borderStyle = status === 'draft' ? 'dotted' : status === 'approved' ? 'dashed' : 'solid';
|
|
128
|
-
|
|
129
|
-
const boundaryStyle: React.CSSProperties = {
|
|
130
|
-
padding: '12px 16px',
|
|
131
|
-
backgroundColor: fillColor,
|
|
132
|
-
color: '#000',
|
|
133
|
-
border: `2px ${borderStyle} ${hasViolations ? '#D0021B' : strokeColor}`,
|
|
134
|
-
fontSize: theme.fontSizes[0],
|
|
135
|
-
fontWeight: theme.fontWeights.medium,
|
|
136
|
-
fontFamily: theme.fonts.body,
|
|
137
|
-
width: '100%',
|
|
138
|
-
height: '100%',
|
|
139
|
-
minWidth: 20,
|
|
140
|
-
minHeight: 20,
|
|
141
|
-
display: 'flex',
|
|
142
|
-
flexDirection: 'column',
|
|
143
|
-
alignItems: 'center',
|
|
144
|
-
justifyContent: 'center',
|
|
145
|
-
gap: '4px',
|
|
146
|
-
boxShadow: isHighlighted
|
|
147
|
-
? '0 0 0 3px #3b82f6, 0 0 20px rgba(59, 130, 246, 0.5)'
|
|
148
|
-
: selected
|
|
149
|
-
? `0 0 0 2px ${strokeColor}`
|
|
150
|
-
: '0 2px 4px rgba(0,0,0,0.1)',
|
|
151
|
-
opacity: nodeOpacity,
|
|
152
|
-
transition: 'box-shadow 0.2s ease, opacity 0.3s ease',
|
|
153
|
-
animationDuration: animationType ? `${animationDuration}ms` : undefined,
|
|
154
|
-
boxSizing: 'border-box',
|
|
155
|
-
borderRadius: '8px', // Rounded corners for boundary nodes
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
const handleStyle = editable
|
|
159
|
-
? { background: fillColor, width: 12, height: 12, border: '2px solid white', boxShadow: '0 0 0 1px ' + fillColor }
|
|
160
|
-
: { background: fillColor, width: 8, height: 8, opacity: 0, pointerEvents: 'none' as const };
|
|
161
|
-
|
|
162
|
-
return (
|
|
163
|
-
<>
|
|
164
|
-
{editable && (
|
|
165
|
-
<NodeResizer
|
|
166
|
-
color={strokeColor}
|
|
167
|
-
isVisible={selected}
|
|
168
|
-
minWidth={40}
|
|
169
|
-
minHeight={30}
|
|
170
|
-
onResizeEnd={handleResizeEnd}
|
|
171
|
-
handleStyle={{ width: 8, height: 8, borderRadius: 2, zIndex: 20 }}
|
|
172
|
-
lineStyle={{ borderWidth: 1, zIndex: 20 }}
|
|
173
|
-
/>
|
|
174
|
-
)}
|
|
175
|
-
|
|
176
|
-
<Handle type="target" position={Position.Top} id="top" style={handleStyle} />
|
|
177
|
-
<Handle type="target" position={Position.Bottom} id="bottom" style={handleStyle} />
|
|
178
|
-
<Handle type="target" position={Position.Left} id="left" style={handleStyle} />
|
|
179
|
-
<Handle type="target" position={Position.Right} id="right" style={handleStyle} />
|
|
180
|
-
|
|
181
|
-
<div
|
|
182
|
-
ref={nodeRef}
|
|
183
|
-
style={{ position: 'relative', width: '100%', height: '100%' }}
|
|
184
|
-
onMouseDown={handleMouseDown}
|
|
185
|
-
onMouseEnter={handleMouseEnter}
|
|
186
|
-
onMouseLeave={handleMouseLeave}
|
|
187
|
-
>
|
|
188
|
-
<NodeBadges
|
|
189
|
-
shape="rectangle"
|
|
190
|
-
status={status}
|
|
191
|
-
sourceFiles={sourceFiles}
|
|
192
|
-
references={references}
|
|
193
|
-
boundary={boundaryData}
|
|
194
|
-
opacity={nodeOpacity}
|
|
195
|
-
/>
|
|
196
|
-
<div style={boundaryStyle} className={getAnimationClass()}>
|
|
197
|
-
<NodeContent
|
|
198
|
-
displayName={displayName}
|
|
199
|
-
identifier={identifier}
|
|
200
|
-
icon={icon}
|
|
201
|
-
state={state}
|
|
202
|
-
stateDefinitions={stateDefinitions}
|
|
203
|
-
hasViolations={hasViolations}
|
|
204
|
-
/>
|
|
205
|
-
</div>
|
|
206
|
-
{tooltipsEnabled && (
|
|
207
|
-
<NodeTooltip
|
|
208
|
-
description={description}
|
|
209
|
-
otel={nodeData.otel as OtelInfo}
|
|
210
|
-
sources={nodeData.sources}
|
|
211
|
-
references={references}
|
|
212
|
-
visible={showTooltip}
|
|
213
|
-
nodeRef={nodeRef}
|
|
214
|
-
/>
|
|
215
|
-
)}
|
|
216
|
-
</div>
|
|
217
|
-
|
|
218
|
-
<Handle type="source" position={Position.Top} id="top-out" style={handleStyle} />
|
|
219
|
-
<Handle type="source" position={Position.Bottom} id="bottom-out" style={handleStyle} />
|
|
220
|
-
<Handle type="source" position={Position.Left} id="left-out" style={handleStyle} />
|
|
221
|
-
<Handle type="source" position={Position.Right} id="right-out" style={handleStyle} />
|
|
222
|
-
</>
|
|
223
|
-
);
|
|
224
|
-
};
|
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OTEL Event Node
|
|
3
|
-
*
|
|
4
|
-
* Renders event nodes as rectangles with:
|
|
5
|
-
* - Event name identifier
|
|
6
|
-
* - Event attributes schema
|
|
7
|
-
* - Status, sources, and references badges
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import React from 'react';
|
|
11
|
-
import { Handle, Position, NodeResizer } from '@xyflow/react';
|
|
12
|
-
import type { NodeProps, Node } from '@xyflow/react';
|
|
13
|
-
import { useTheme } from '@principal-ade/industry-theme';
|
|
14
|
-
import { NodeTooltip } from '../../components/NodeTooltip';
|
|
15
|
-
import type { OtelInfo } from '../../components/NodeTooltip';
|
|
16
|
-
import { NodeBadges } from './shared/NodeBadges';
|
|
17
|
-
import { NodeContent } from './shared/NodeContent';
|
|
18
|
-
import { useNodeBehavior } from './shared/useNodeBehavior';
|
|
19
|
-
|
|
20
|
-
export interface OtelEventNodeData extends Record<string, unknown> {
|
|
21
|
-
name: string;
|
|
22
|
-
typeDefinition: {
|
|
23
|
-
color?: string;
|
|
24
|
-
icon?: string;
|
|
25
|
-
states?: Record<string, { color?: string; label?: string; icon?: string }>;
|
|
26
|
-
};
|
|
27
|
-
state?: string;
|
|
28
|
-
hasViolations?: boolean;
|
|
29
|
-
data: {
|
|
30
|
-
color?: string;
|
|
31
|
-
scopeColor?: string;
|
|
32
|
-
spanColor?: string;
|
|
33
|
-
stroke?: string;
|
|
34
|
-
icon?: string;
|
|
35
|
-
status?: 'draft' | 'approved' | 'implemented';
|
|
36
|
-
description?: string;
|
|
37
|
-
sources?: string[];
|
|
38
|
-
references?: string[];
|
|
39
|
-
states?: Record<string, { color?: string; label?: string; icon?: string }>;
|
|
40
|
-
event?: { name?: string; description?: string; attributes?: Record<string, unknown> };
|
|
41
|
-
eventRef?: string;
|
|
42
|
-
otel?: { files?: string[] };
|
|
43
|
-
};
|
|
44
|
-
editable?: boolean;
|
|
45
|
-
tooltipsEnabled?: boolean;
|
|
46
|
-
shiftKeyPressed?: boolean;
|
|
47
|
-
isHighlighted?: boolean;
|
|
48
|
-
isActive?: boolean;
|
|
49
|
-
isHidden?: boolean;
|
|
50
|
-
animationType?: 'pulse' | 'flash' | 'shake' | 'entry' | null;
|
|
51
|
-
animationDuration?: number;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export const OtelEventNode: React.FC<NodeProps<Node<OtelEventNodeData>>> = ({
|
|
55
|
-
data,
|
|
56
|
-
selected,
|
|
57
|
-
dragging,
|
|
58
|
-
}) => {
|
|
59
|
-
const { theme } = useTheme();
|
|
60
|
-
const nodeProps = data;
|
|
61
|
-
const {
|
|
62
|
-
typeDefinition,
|
|
63
|
-
state,
|
|
64
|
-
hasViolations,
|
|
65
|
-
data: nodeData,
|
|
66
|
-
editable = false,
|
|
67
|
-
tooltipsEnabled = true,
|
|
68
|
-
shiftKeyPressed = false,
|
|
69
|
-
isHighlighted = false,
|
|
70
|
-
isActive = true,
|
|
71
|
-
isHidden = false,
|
|
72
|
-
animationType,
|
|
73
|
-
animationDuration = 1000,
|
|
74
|
-
} = nodeProps;
|
|
75
|
-
|
|
76
|
-
const {
|
|
77
|
-
nodeRef,
|
|
78
|
-
showTooltip,
|
|
79
|
-
handleMouseDown,
|
|
80
|
-
handleMouseEnter,
|
|
81
|
-
handleMouseLeave,
|
|
82
|
-
handleResizeEnd,
|
|
83
|
-
} = useNodeBehavior({ editable, tooltipsEnabled, shiftKeyPressed, selected, dragging });
|
|
84
|
-
|
|
85
|
-
const nodeOpacity = isHidden ? 0.4 : isActive ? 1 : 0.1;
|
|
86
|
-
|
|
87
|
-
// Color resolution
|
|
88
|
-
const scopeColor = nodeData.scopeColor as string | undefined;
|
|
89
|
-
const spanColor = nodeData.spanColor as string | undefined;
|
|
90
|
-
|
|
91
|
-
// OTEL nodes use scope-based coloring exclusively
|
|
92
|
-
// Priority: scopeColor (from library.yaml) → typeDefinition.color → default
|
|
93
|
-
// Note: node.fill and node.color fields are intentionally ignored (validation enforces this)
|
|
94
|
-
const baseFillColor = scopeColor || typeDefinition.color || '#3b82f6';
|
|
95
|
-
const fillColor = baseFillColor;
|
|
96
|
-
// Stroke color priority: explicit stroke > span color (workflow context) > fill color
|
|
97
|
-
const nodeDataStroke = nodeData.stroke as string | undefined;
|
|
98
|
-
const strokeColor = nodeDataStroke || spanColor || fillColor;
|
|
99
|
-
|
|
100
|
-
// Display info
|
|
101
|
-
const displayName = nodeProps.name;
|
|
102
|
-
const eventData = nodeData.event;
|
|
103
|
-
const identifier = eventData?.name || (nodeData.eventRef as string);
|
|
104
|
-
|
|
105
|
-
// Badge data
|
|
106
|
-
const status = nodeData.status;
|
|
107
|
-
const sourceFiles = nodeData.otel?.files || nodeData.sources;
|
|
108
|
-
const references = nodeData.references;
|
|
109
|
-
const description = nodeData.description;
|
|
110
|
-
|
|
111
|
-
// Icon
|
|
112
|
-
const icon =
|
|
113
|
-
(nodeData.icon as string) ||
|
|
114
|
-
(state && nodeData.states?.[state]?.icon) ||
|
|
115
|
-
typeDefinition.icon;
|
|
116
|
-
|
|
117
|
-
const stateDefinitions = nodeData.states || typeDefinition.states;
|
|
118
|
-
|
|
119
|
-
const getAnimationClass = () => {
|
|
120
|
-
switch (animationType) {
|
|
121
|
-
case 'pulse': return 'node-pulse';
|
|
122
|
-
case 'flash': return 'node-flash';
|
|
123
|
-
case 'shake': return 'node-shake';
|
|
124
|
-
case 'entry': return 'node-entry';
|
|
125
|
-
default: return '';
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
const borderStyle = status === 'draft' ? 'dotted' : status === 'approved' ? 'dashed' : 'solid';
|
|
130
|
-
|
|
131
|
-
const rectangleStyle: React.CSSProperties = {
|
|
132
|
-
padding: '12px 16px',
|
|
133
|
-
backgroundColor: fillColor,
|
|
134
|
-
color: '#000',
|
|
135
|
-
border: `2px ${borderStyle} ${hasViolations ? '#D0021B' : strokeColor}`,
|
|
136
|
-
fontSize: theme.fontSizes[0],
|
|
137
|
-
fontWeight: theme.fontWeights.medium,
|
|
138
|
-
fontFamily: theme.fonts.body,
|
|
139
|
-
width: '100%',
|
|
140
|
-
height: '100%',
|
|
141
|
-
minWidth: 20,
|
|
142
|
-
minHeight: 20,
|
|
143
|
-
display: 'flex',
|
|
144
|
-
flexDirection: 'column',
|
|
145
|
-
alignItems: 'center',
|
|
146
|
-
justifyContent: 'center',
|
|
147
|
-
gap: '4px',
|
|
148
|
-
boxShadow: isHighlighted
|
|
149
|
-
? '0 0 0 3px #3b82f6, 0 0 20px rgba(59, 130, 246, 0.5)'
|
|
150
|
-
: selected
|
|
151
|
-
? `0 0 0 2px ${strokeColor}`
|
|
152
|
-
: '0 2px 4px rgba(0,0,0,0.1)',
|
|
153
|
-
opacity: nodeOpacity,
|
|
154
|
-
transition: 'box-shadow 0.2s ease, opacity 0.3s ease',
|
|
155
|
-
animationDuration: animationType ? `${animationDuration}ms` : undefined,
|
|
156
|
-
boxSizing: 'border-box',
|
|
157
|
-
borderRadius: 0,
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
const handleStyle = editable
|
|
161
|
-
? { background: fillColor, width: 12, height: 12, border: '2px solid white', boxShadow: '0 0 0 1px ' + fillColor }
|
|
162
|
-
: { background: fillColor, width: 8, height: 8, opacity: 0, pointerEvents: 'none' as const };
|
|
163
|
-
|
|
164
|
-
return (
|
|
165
|
-
<>
|
|
166
|
-
{editable && (
|
|
167
|
-
<NodeResizer
|
|
168
|
-
color={strokeColor}
|
|
169
|
-
isVisible={selected}
|
|
170
|
-
minWidth={40}
|
|
171
|
-
minHeight={30}
|
|
172
|
-
onResizeEnd={handleResizeEnd}
|
|
173
|
-
handleStyle={{ width: 8, height: 8, borderRadius: 2, zIndex: 20 }}
|
|
174
|
-
lineStyle={{ borderWidth: 1, zIndex: 20 }}
|
|
175
|
-
/>
|
|
176
|
-
)}
|
|
177
|
-
|
|
178
|
-
<Handle type="target" position={Position.Top} id="top" style={handleStyle} />
|
|
179
|
-
<Handle type="target" position={Position.Bottom} id="bottom" style={handleStyle} />
|
|
180
|
-
<Handle type="target" position={Position.Left} id="left" style={handleStyle} />
|
|
181
|
-
<Handle type="target" position={Position.Right} id="right" style={handleStyle} />
|
|
182
|
-
|
|
183
|
-
<div
|
|
184
|
-
ref={nodeRef}
|
|
185
|
-
style={{ position: 'relative', width: '100%', height: '100%' }}
|
|
186
|
-
onMouseDown={handleMouseDown}
|
|
187
|
-
onMouseEnter={handleMouseEnter}
|
|
188
|
-
onMouseLeave={handleMouseLeave}
|
|
189
|
-
>
|
|
190
|
-
<NodeBadges
|
|
191
|
-
shape="rectangle"
|
|
192
|
-
status={status}
|
|
193
|
-
sourceFiles={sourceFiles}
|
|
194
|
-
references={references}
|
|
195
|
-
opacity={nodeOpacity}
|
|
196
|
-
/>
|
|
197
|
-
<div style={rectangleStyle} className={getAnimationClass()}>
|
|
198
|
-
<NodeContent
|
|
199
|
-
displayName={displayName}
|
|
200
|
-
identifier={identifier}
|
|
201
|
-
icon={icon}
|
|
202
|
-
state={state}
|
|
203
|
-
stateDefinitions={stateDefinitions}
|
|
204
|
-
hasViolations={hasViolations}
|
|
205
|
-
/>
|
|
206
|
-
</div>
|
|
207
|
-
{tooltipsEnabled && (
|
|
208
|
-
<NodeTooltip
|
|
209
|
-
description={description}
|
|
210
|
-
otel={nodeData.otel as OtelInfo}
|
|
211
|
-
sources={nodeData.sources}
|
|
212
|
-
references={references}
|
|
213
|
-
visible={showTooltip}
|
|
214
|
-
nodeRef={nodeRef}
|
|
215
|
-
/>
|
|
216
|
-
)}
|
|
217
|
-
</div>
|
|
218
|
-
|
|
219
|
-
<Handle type="source" position={Position.Top} id="top-out" style={handleStyle} />
|
|
220
|
-
<Handle type="source" position={Position.Bottom} id="bottom-out" style={handleStyle} />
|
|
221
|
-
<Handle type="source" position={Position.Left} id="left-out" style={handleStyle} />
|
|
222
|
-
<Handle type="source" position={Position.Right} id="right-out" style={handleStyle} />
|
|
223
|
-
</>
|
|
224
|
-
);
|
|
225
|
-
};
|