@principal-ai/principal-view-react 0.13.19 → 0.13.21

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.
@@ -90,6 +90,9 @@ export const CustomNode: React.FC<NodeProps<Node<CustomNodeData>>> = ({ data, se
90
90
  console.log('[CustomNode] Node data:', {
91
91
  name: nodeProps.name,
92
92
  nodeDataKeys: nodeData ? Object.keys(nodeData).join(', ') : 'undefined',
93
+ references: nodeData?.references,
94
+ otelFiles: (nodeData?.otel as { files?: string[] })?.files,
95
+ sources: nodeData?.sources,
93
96
  fullNodeData: nodeData,
94
97
  });
95
98
 
@@ -99,10 +102,13 @@ export const CustomNode: React.FC<NodeProps<Node<CustomNodeData>>> = ({ data, se
99
102
  const showTooltip =
100
103
  (isHovered && !dragging && shiftKeyPressed) || (!editable && !!selected);
101
104
 
102
- // Extract OTEL info, description, and sources for tooltip
103
- const otelInfo = nodeData?.otel as OtelInfo | undefined;
105
+ // Extract OTEL info, description, sources/files, and references for tooltip
106
+ const otelInfo = nodeData?.otel as (OtelInfo & { files?: string[] }) | undefined;
104
107
  const description = nodeData?.description as string | undefined;
105
- const sources = nodeData?.sources as string[] | undefined;
108
+ const sources = nodeData?.sources as string[] | undefined; // deprecated
109
+ const references = nodeData?.references as string[] | undefined;
110
+ // Files from otel.files - these are source code files where the event is instrumented
111
+ const files = otelInfo?.files;
106
112
 
107
113
  // Get badge shape styles based on node shape
108
114
  const getBadgeShapeStyles = (): React.CSSProperties => {
@@ -140,20 +146,71 @@ export const CustomNode: React.FC<NodeProps<Node<CustomNodeData>>> = ({ data, se
140
146
  }
141
147
  };
142
148
 
143
- // Render Sources badge (top-right)
149
+ // Get badge position based on shape - diamonds need badges at their points, not bounding box corners
150
+ const getBadgePosition = (position: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'left' | 'right' | 'top' | 'bottom'): React.CSSProperties => {
151
+ const isDiamondShape = typeDefinition.shape === 'diamond';
152
+
153
+ if (isDiamondShape) {
154
+ // Diamond points are at the middle of each edge of the bounding box
155
+ switch (position) {
156
+ case 'top-left':
157
+ case 'left':
158
+ // Position at the LEFT point of the diamond (center-left)
159
+ return { top: '50%', left: 0, transform: 'translate(-50%, -50%)' };
160
+ case 'top-right':
161
+ case 'right':
162
+ // Position at the RIGHT point of the diamond (center-right)
163
+ return { top: '50%', right: 0, transform: 'translate(50%, -50%)' };
164
+ case 'top':
165
+ // Position at the TOP point of the diamond
166
+ return { top: 0, left: '50%', transform: 'translate(-50%, -50%)' };
167
+ case 'bottom':
168
+ case 'bottom-left':
169
+ case 'bottom-right':
170
+ // Position at the BOTTOM point of the diamond
171
+ return { bottom: 0, left: '50%', transform: 'translate(-50%, 50%)' };
172
+ }
173
+ }
174
+
175
+ // Default positioning for rectangles, circles, hexagons (bounding box corners)
176
+ switch (position) {
177
+ case 'top-left':
178
+ return { top: -6, left: -6 };
179
+ case 'top-right':
180
+ return { top: -6, right: -6 };
181
+ case 'bottom-left':
182
+ return { bottom: -6, left: -6 };
183
+ case 'bottom-right':
184
+ return { bottom: -6, right: -6 };
185
+ case 'left':
186
+ return { top: -6, left: -6 };
187
+ case 'right':
188
+ return { top: -6, right: -6 };
189
+ case 'top':
190
+ return { top: -6, left: '50%', transform: 'translateX(-50%)' };
191
+ case 'bottom':
192
+ return { bottom: -6, left: '50%', transform: 'translateX(-50%)' };
193
+ }
194
+ };
195
+
196
+ // Render Sources badge (top-right) - shows "S" for files where event is instrumented
144
197
  const renderSourcesBadge = () => {
145
- const sources = nodeData?.sources as string[] | undefined;
146
- if (!sources || sources.length === 0) return null;
198
+ // Use otel.files (source code files where event is instrumented)
199
+ // Fall back to deprecated sources field for backwards compatibility
200
+ const sourceFiles = files || sources;
201
+ if (!sourceFiles || sourceFiles.length === 0) return null;
147
202
 
148
203
  const shapeStyles = getBadgeShapeStyles();
204
+ const positionStyles = getBadgePosition('top-right');
149
205
 
150
206
  return (
151
207
  <div
152
208
  style={{
153
209
  position: 'absolute',
154
- top: -6,
155
- right: -6,
210
+ ...positionStyles,
156
211
  ...shapeStyles,
212
+ // Override transform if shape has rotation but we already have a position transform
213
+ ...(typeDefinition.shape === 'diamond' ? { transform: `${positionStyles.transform} rotate(45deg)` } : {}),
157
214
  backgroundColor: '#10b981', // Green for sources
158
215
  color: 'white',
159
216
  fontSize: theme.fontSizes[0],
@@ -166,14 +223,48 @@ export const CustomNode: React.FC<NodeProps<Node<CustomNodeData>>> = ({ data, se
166
223
  zIndex: 10,
167
224
  opacity: nodeOpacity,
168
225
  }}
169
- title={`Sources: ${sources.join(', ')}`}
226
+ title={`Source files: ${sourceFiles.join(', ')}`}
170
227
  >
171
228
  <span style={{ transform: shapeStyles.transform ? 'rotate(-45deg)' : undefined }}>S</span>
172
229
  </div>
173
230
  );
174
231
  };
175
232
 
176
- // Render Boundary badge (top-right) - shown instead of sources badge for boundary nodes
233
+ // Render References badge (bottom-left for rectangles, bottom for diamonds) - shows "R" for external references
234
+ const renderReferencesBadge = () => {
235
+ if (!references || references.length === 0) return null;
236
+
237
+ const shapeStyles = getBadgeShapeStyles();
238
+ const positionStyles = getBadgePosition('bottom-left');
239
+
240
+ return (
241
+ <div
242
+ style={{
243
+ position: 'absolute',
244
+ ...positionStyles,
245
+ ...shapeStyles,
246
+ // Override transform if shape has rotation but we already have a position transform
247
+ ...(typeDefinition.shape === 'diamond' ? { transform: `${positionStyles.transform} rotate(45deg)` } : {}),
248
+ backgroundColor: '#8b5cf6', // Purple for references
249
+ color: 'white',
250
+ fontSize: theme.fontSizes[0],
251
+ fontWeight: theme.fontWeights.bold,
252
+ fontFamily: theme.fonts.body,
253
+ display: 'flex',
254
+ alignItems: 'center',
255
+ justifyContent: 'center',
256
+ boxShadow: '0 1px 3px rgba(0,0,0,0.3)',
257
+ zIndex: 10,
258
+ opacity: nodeOpacity,
259
+ }}
260
+ title={`References: ${references.join(', ')}`}
261
+ >
262
+ <span style={{ transform: shapeStyles.transform ? 'rotate(-45deg)' : undefined }}>R</span>
263
+ </div>
264
+ );
265
+ };
266
+
267
+ // Render Boundary badge (right/left points) - shown instead of sources badge for boundary nodes
177
268
  const renderBoundaryBadge = () => {
178
269
  const boundary = nodeData?.boundary as { direction?: 'outbound' | 'inbound'; node?: Record<string, string> } | undefined;
179
270
  if (!boundary) return null;
@@ -185,13 +276,13 @@ export const CustomNode: React.FC<NodeProps<Node<CustomNodeData>>> = ({ data, se
185
276
  const directionIcon = isOutbound ? '↗' : '↙';
186
277
  const directionTitle = isOutbound ? 'Outbound boundary (calls external system)' : 'Inbound boundary (called by external system)';
187
278
 
279
+ const positionStyles = getBadgePosition(isOutbound ? 'right' : 'left');
280
+
188
281
  return (
189
282
  <div
190
283
  style={{
191
284
  position: 'absolute',
192
- top: -6,
193
- // Inbound badge on left, outbound badge on right
194
- ...(isOutbound ? { right: -6 } : { left: -6 }),
285
+ ...positionStyles,
195
286
  width: 18,
196
287
  height: 18,
197
288
  borderRadius: '50%', // Always circular for boundary badge
@@ -217,7 +308,7 @@ export const CustomNode: React.FC<NodeProps<Node<CustomNodeData>>> = ({ data, se
217
308
  // Check if this is a boundary node
218
309
  const isBoundaryNode = nodeData?.nodeType === 'boundary';
219
310
 
220
- // Render Status badge (top-left)
311
+ // Render Status badge (top-left, or top point for diamonds)
221
312
  const renderStatusBadge = () => {
222
313
  const status = nodeData?.status as 'draft' | 'approved' | 'implemented' | undefined;
223
314
  if (!status) return null;
@@ -242,14 +333,16 @@ export const CustomNode: React.FC<NodeProps<Node<CustomNodeData>>> = ({ data, se
242
333
  };
243
334
 
244
335
  const shapeStyles = getBadgeShapeStyles();
336
+ const positionStyles = getBadgePosition('top-left');
245
337
 
246
338
  return (
247
339
  <div
248
340
  style={{
249
341
  position: 'absolute',
250
- top: -6,
251
- left: -6,
342
+ ...positionStyles,
252
343
  ...shapeStyles,
344
+ // Override transform if shape has rotation but we already have a position transform
345
+ ...(typeDefinition.shape === 'diamond' ? { transform: `${positionStyles.transform} rotate(45deg)` } : {}),
253
346
  backgroundColor: statusColors[status],
254
347
  color: 'white',
255
348
  fontSize: theme.fontSizes[0],
@@ -623,7 +716,12 @@ export const CustomNode: React.FC<NodeProps<Node<CustomNodeData>>> = ({ data, se
623
716
  onMouseLeave={() => setIsHovered(false)}
624
717
  >
625
718
  {renderStatusBadge()}
626
- {isBoundaryNode ? renderBoundaryBadge() : renderSourcesBadge()}
719
+ {isBoundaryNode ? renderBoundaryBadge() : (
720
+ <>
721
+ {renderSourcesBadge()}
722
+ {renderReferencesBadge()}
723
+ </>
724
+ )}
627
725
  <div style={hexagonBorderStyle} className={animationClass}>
628
726
  <div style={hexagonInnerStyle}>
629
727
  {icon && (
@@ -666,6 +764,7 @@ export const CustomNode: React.FC<NodeProps<Node<CustomNodeData>>> = ({ data, se
666
764
  description={description}
667
765
  otel={otelInfo}
668
766
  sources={sources}
767
+ references={references}
669
768
  visible={showTooltip}
670
769
  nodeRef={nodeRef}
671
770
  />
@@ -689,7 +788,12 @@ export const CustomNode: React.FC<NodeProps<Node<CustomNodeData>>> = ({ data, se
689
788
  onMouseLeave={() => setIsHovered(false)}
690
789
  >
691
790
  {renderStatusBadge()}
692
- {isBoundaryNode ? renderBoundaryBadge() : renderSourcesBadge()}
791
+ {isBoundaryNode ? renderBoundaryBadge() : (
792
+ <>
793
+ {renderSourcesBadge()}
794
+ {renderReferencesBadge()}
795
+ </>
796
+ )}
693
797
  <div style={diamondBorderStyle} className={animationClass}>
694
798
  <div style={diamondInnerStyle}>
695
799
  {icon && (
@@ -732,6 +836,7 @@ export const CustomNode: React.FC<NodeProps<Node<CustomNodeData>>> = ({ data, se
732
836
  description={description}
733
837
  otel={otelInfo}
734
838
  sources={sources}
839
+ references={references}
735
840
  visible={showTooltip}
736
841
  nodeRef={nodeRef}
737
842
  />
@@ -745,7 +850,12 @@ export const CustomNode: React.FC<NodeProps<Node<CustomNodeData>>> = ({ data, se
745
850
  onMouseLeave={() => setIsHovered(false)}
746
851
  >
747
852
  {renderStatusBadge()}
748
- {isBoundaryNode ? renderBoundaryBadge() : renderSourcesBadge()}
853
+ {isBoundaryNode ? renderBoundaryBadge() : (
854
+ <>
855
+ {renderSourcesBadge()}
856
+ {renderReferencesBadge()}
857
+ </>
858
+ )}
749
859
  <div style={getShapeStyles()} className={animationClass}>
750
860
  {/* Inner content */}
751
861
  <div
@@ -813,6 +923,7 @@ export const CustomNode: React.FC<NodeProps<Node<CustomNodeData>>> = ({ data, se
813
923
  description={description}
814
924
  otel={otelInfo}
815
925
  sources={sources}
926
+ references={references}
816
927
  visible={showTooltip}
817
928
  nodeRef={nodeRef}
818
929
  />