@principal-ai/principal-view-react 0.6.21 → 0.6.23

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.
@@ -640,3 +640,437 @@ export const ServiceArchitectureEditable: Story = {
640
640
  },
641
641
  },
642
642
  };
643
+
644
+ // ============================================================================
645
+ // OTEL Log Association Canvas
646
+ // ============================================================================
647
+
648
+ /**
649
+ * OTEL Log Association architecture canvas
650
+ * Demonstrates OTEL badges, tooltips, and info panel integration
651
+ */
652
+ const otelLogAssociationCanvas: ExtendedCanvas = {
653
+ nodes: [
654
+ {
655
+ id: 'otel-log',
656
+ type: 'text',
657
+ text: 'OtelLog',
658
+ x: -304,
659
+ y: 147,
660
+ width: 120,
661
+ height: 118,
662
+ pv: {
663
+ nodeType: 'otel-type',
664
+ name: 'OtelLog',
665
+ description:
666
+ 'OpenTelemetry log record with timestamp, severity, body, resource, and trace context',
667
+ otel: {
668
+ kind: 'type',
669
+ category: 'log',
670
+ isNew: true,
671
+ },
672
+ shape: 'rectangle',
673
+ icon: 'FileText',
674
+ fill: '#4A90E2',
675
+ },
676
+ },
677
+ {
678
+ id: 'otel-resource',
679
+ type: 'text',
680
+ text: 'OtelResource',
681
+ x: -305,
682
+ y: 316,
683
+ width: 120,
684
+ height: 117,
685
+ pv: {
686
+ nodeType: 'otel-type',
687
+ name: 'OtelResource',
688
+ description: 'OTEL resource attributes like service.name, k8s.*, deployment.*',
689
+ otel: {
690
+ kind: 'type',
691
+ category: 'resource',
692
+ },
693
+ shape: 'rectangle',
694
+ icon: 'Box',
695
+ fill: '#4A90E2',
696
+ },
697
+ },
698
+ {
699
+ id: 'canvas-scope',
700
+ type: 'text',
701
+ text: 'CanvasScope',
702
+ x: -77,
703
+ y: -48,
704
+ width: 130,
705
+ height: 118,
706
+ pv: {
707
+ nodeType: 'service',
708
+ name: 'CanvasScope',
709
+ description: 'Filters which logs are relevant to this canvas based on resource attributes',
710
+ shape: 'hexagon',
711
+ icon: 'Filter',
712
+ fill: '#9B59B6',
713
+ },
714
+ },
715
+ {
716
+ id: 'log-router',
717
+ type: 'text',
718
+ text: 'LogRouter',
719
+ x: -80,
720
+ y: 150,
721
+ width: 130,
722
+ height: 118,
723
+ pv: {
724
+ nodeType: 'otel-service',
725
+ name: 'LogRouter',
726
+ description: 'Routes incoming OTEL logs to canvas nodes based on scope and resourceMatch criteria',
727
+ otel: {
728
+ kind: 'service',
729
+ category: 'router',
730
+ isNew: true,
731
+ },
732
+ shape: 'hexagon',
733
+ icon: 'GitBranch',
734
+ fill: '#7ED321',
735
+ },
736
+ },
737
+ {
738
+ id: 'resource-matcher',
739
+ type: 'text',
740
+ text: 'ResourceMatcher',
741
+ x: -82,
742
+ y: 440,
743
+ width: 130,
744
+ height: 119,
745
+ pv: {
746
+ nodeType: 'service',
747
+ name: 'ResourceMatcher',
748
+ description: 'Matches log resources against node resourceMatch criteria',
749
+ otel: {
750
+ kind: 'service',
751
+ category: 'match',
752
+ },
753
+ shape: 'hexagon',
754
+ icon: 'Search',
755
+ fill: '#7ED321',
756
+ },
757
+ },
758
+ {
759
+ id: 'resource-match',
760
+ type: 'text',
761
+ text: 'ResourceMatch',
762
+ x: 179,
763
+ y: 445,
764
+ width: 120,
765
+ height: 117,
766
+ pv: {
767
+ nodeType: 'otel-type',
768
+ name: 'ResourceMatch',
769
+ description: 'Criteria for matching OTEL resources to canvas nodes',
770
+ otel: {
771
+ kind: 'type',
772
+ category: 'match',
773
+ },
774
+ shape: 'rectangle',
775
+ icon: 'Target',
776
+ fill: '#4A90E2',
777
+ },
778
+ },
779
+ {
780
+ id: 'match-operator',
781
+ type: 'text',
782
+ text: 'MatchOperator',
783
+ x: 178,
784
+ y: 632,
785
+ width: 120,
786
+ height: 117,
787
+ pv: {
788
+ nodeType: 'otel-type',
789
+ name: 'MatchOperator',
790
+ description: 'Matching operators: exact, glob, regex, exists, oneOf',
791
+ otel: {
792
+ kind: 'type',
793
+ category: 'match',
794
+ },
795
+ shape: 'diamond',
796
+ icon: 'Code',
797
+ fill: '#F5A623',
798
+ },
799
+ },
800
+ {
801
+ id: 'canvas-node',
802
+ type: 'text',
803
+ text: 'Canvas Node',
804
+ x: 172,
805
+ y: 277,
806
+ width: 132,
807
+ height: 121,
808
+ pv: {
809
+ nodeType: 'service',
810
+ name: 'Canvas Node',
811
+ description: 'A node in the canvas that can receive routed logs',
812
+ shape: 'rectangle',
813
+ icon: 'Square',
814
+ fill: '#00BCD4',
815
+ },
816
+ },
817
+ {
818
+ id: 'routing-result',
819
+ type: 'text',
820
+ text: 'LogRoutingResult',
821
+ x: 169,
822
+ y: 80,
823
+ width: 150,
824
+ height: 135,
825
+ pv: {
826
+ nodeType: 'otel-type',
827
+ name: 'LogRoutingResult',
828
+ description: 'Result of routing a log: routed, orphaned, or out-of-scope',
829
+ otel: {
830
+ kind: 'type',
831
+ category: 'audit',
832
+ },
833
+ shape: 'rectangle',
834
+ icon: 'CheckCircle',
835
+ fill: '#4A90E2',
836
+ },
837
+ },
838
+ {
839
+ id: 'audit-collector',
840
+ type: 'text',
841
+ text: 'AuditCollector',
842
+ x: 380,
843
+ y: 150,
844
+ width: 130,
845
+ height: 117,
846
+ pv: {
847
+ nodeType: 'otel-service',
848
+ name: 'AuditCollector',
849
+ description: 'Tracks routing metrics, orphaned logs, silent nodes, and generates coverage reports',
850
+ otel: {
851
+ kind: 'service',
852
+ category: 'collector',
853
+ isNew: true,
854
+ },
855
+ shape: 'hexagon',
856
+ icon: 'BarChart2',
857
+ fill: '#7ED321',
858
+ },
859
+ },
860
+ {
861
+ id: 'orphaned-log',
862
+ type: 'text',
863
+ text: 'OrphanedLog',
864
+ x: 618,
865
+ y: 150,
866
+ width: 127,
867
+ height: 118,
868
+ pv: {
869
+ nodeType: 'otel-type',
870
+ name: 'OrphanedLog',
871
+ description:
872
+ 'Logs that matched canvas scope but no node resourceMatch - indicates missing nodes or misconfiguration',
873
+ otel: {
874
+ kind: 'type',
875
+ category: 'audit',
876
+ isNew: true,
877
+ },
878
+ shape: 'rectangle',
879
+ icon: 'AlertTriangle',
880
+ fill: '#D0021B',
881
+ },
882
+ },
883
+ {
884
+ id: 'audit-report',
885
+ type: 'text',
886
+ text: 'AuditReport',
887
+ x: 618,
888
+ y: 288,
889
+ width: 124,
890
+ height: 123,
891
+ pv: {
892
+ nodeType: 'otel-type',
893
+ name: 'AuditReport',
894
+ description: 'Coverage report with node activity, orphans, and recommendations',
895
+ otel: {
896
+ kind: 'type',
897
+ category: 'audit',
898
+ },
899
+ shape: 'rectangle',
900
+ icon: 'FileText',
901
+ fill: '#4A90E2',
902
+ },
903
+ },
904
+ ],
905
+ edges: [
906
+ {
907
+ id: 'log-to-router',
908
+ fromNode: 'otel-log',
909
+ toNode: 'log-router',
910
+ fromSide: 'right',
911
+ toSide: 'left',
912
+ label: 'route()',
913
+ pv: { edgeType: 'http-request' },
914
+ },
915
+ {
916
+ id: 'router-checks-scope',
917
+ fromNode: 'log-router',
918
+ toNode: 'canvas-scope',
919
+ fromSide: 'top',
920
+ toSide: 'bottom',
921
+ label: 'isInScope()',
922
+ pv: { edgeType: 'http-request' },
923
+ },
924
+ {
925
+ id: 'router-uses-matcher',
926
+ fromNode: 'log-router',
927
+ toNode: 'resource-matcher',
928
+ fromSide: 'bottom',
929
+ toSide: 'top',
930
+ label: 'match()',
931
+ pv: { edgeType: 'http-request' },
932
+ },
933
+ {
934
+ id: 'matcher-uses-match',
935
+ fromNode: 'resource-matcher',
936
+ toNode: 'resource-match',
937
+ fromSide: 'right',
938
+ toSide: 'left',
939
+ label: 'criteria',
940
+ pv: { edgeType: 'db-query' },
941
+ },
942
+ {
943
+ id: 'match-has-operator',
944
+ fromNode: 'resource-match',
945
+ toNode: 'match-operator',
946
+ fromSide: 'bottom',
947
+ toSide: 'top',
948
+ label: 'operators',
949
+ pv: { edgeType: 'db-query' },
950
+ },
951
+ {
952
+ id: 'router-to-node',
953
+ fromNode: 'log-router',
954
+ toNode: 'canvas-node',
955
+ fromSide: 'right',
956
+ toSide: 'left',
957
+ label: 'routed',
958
+ pv: { edgeType: 'http-request' },
959
+ },
960
+ {
961
+ id: 'router-returns-result',
962
+ fromNode: 'log-router',
963
+ toNode: 'routing-result',
964
+ fromSide: 'right',
965
+ toSide: 'left',
966
+ label: 'returns',
967
+ pv: { edgeType: 'http-request' },
968
+ },
969
+ {
970
+ id: 'result-to-audit',
971
+ fromNode: 'routing-result',
972
+ toNode: 'audit-collector',
973
+ fromSide: 'right',
974
+ toSide: 'left',
975
+ label: 'track()',
976
+ pv: { edgeType: 'http-request' },
977
+ },
978
+ {
979
+ id: 'audit-tracks-orphans',
980
+ fromNode: 'audit-collector',
981
+ toNode: 'orphaned-log',
982
+ fromSide: 'right',
983
+ toSide: 'left',
984
+ label: 'unmatched',
985
+ pv: { edgeType: 'db-query' },
986
+ },
987
+ {
988
+ id: 'audit-generates-report',
989
+ fromNode: 'audit-collector',
990
+ toNode: 'audit-report',
991
+ fromSide: 'right',
992
+ toSide: 'left',
993
+ label: 'generate()',
994
+ pv: { edgeType: 'db-query' },
995
+ },
996
+ {
997
+ id: 'node-has-match',
998
+ fromNode: 'canvas-node',
999
+ toNode: 'resource-match',
1000
+ fromSide: 'bottom',
1001
+ toSide: 'top',
1002
+ label: 'resourceMatch',
1003
+ pv: { edgeType: 'db-query' },
1004
+ },
1005
+ {
1006
+ id: 'log-has-resource',
1007
+ fromNode: 'otel-log',
1008
+ toNode: 'otel-resource',
1009
+ fromSide: 'bottom',
1010
+ toSide: 'top',
1011
+ label: 'resource',
1012
+ pv: { edgeType: 'db-query' },
1013
+ },
1014
+ ],
1015
+ pv: {
1016
+ version: '1.0.0',
1017
+ name: 'OTEL Log Association Architecture',
1018
+ description: 'Shows how OtelLog flows through LogRouter to Canvas Nodes, with audit tracking',
1019
+ nodeTypes: {
1020
+ service: {
1021
+ label: 'Component',
1022
+ description: 'System component',
1023
+ shape: 'hexagon',
1024
+ },
1025
+ 'otel-type': {
1026
+ label: 'Type',
1027
+ description: 'TypeScript type or interface representing OTEL concepts',
1028
+ shape: 'rectangle',
1029
+ },
1030
+ 'otel-service': {
1031
+ label: 'Service',
1032
+ description: 'Runtime service component for OTEL processing',
1033
+ shape: 'hexagon',
1034
+ },
1035
+ },
1036
+ edgeTypes: {
1037
+ 'http-request': {
1038
+ label: 'Flow',
1039
+ style: 'solid',
1040
+ color: '#4A90E2',
1041
+ directed: true,
1042
+ },
1043
+ 'db-query': {
1044
+ label: 'Reference',
1045
+ style: 'dashed',
1046
+ color: '#999',
1047
+ directed: true,
1048
+ },
1049
+ },
1050
+ },
1051
+ };
1052
+
1053
+ export const OtelLogAssociation: Story = {
1054
+ args: {
1055
+ canvas: otelLogAssociationCanvas,
1056
+ width: 1000,
1057
+ height: 800,
1058
+ },
1059
+ parameters: {
1060
+ docs: {
1061
+ description: {
1062
+ story: `
1063
+ **OTEL Log Association Architecture** - Demonstrates the new OTEL visualization features:
1064
+ - **OTEL Badges**: Circular badges (T/S/I) in the top-right corner of nodes indicating Type, Service, or Instance
1065
+ - **Hover Tooltips**: Hover over any node to see the OTEL kind, category, NEW indicator, and description
1066
+ - **Node Info Panel**: Click a node to see the OpenTelemetry section in the info panel
1067
+
1068
+ Color coding:
1069
+ - **Blue (T)**: Type nodes - TypeScript types/interfaces
1070
+ - **Green (S)**: Service nodes - Runtime services
1071
+ - **Purple (I)**: Instance nodes - Specific running instances
1072
+ `,
1073
+ },
1074
+ },
1075
+ },
1076
+ };
@@ -0,0 +1,286 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import React, { useState } from 'react';
3
+ import { ThemeProvider } from '@principal-ade/industry-theme';
4
+ import { GraphRenderer } from '../components/GraphRenderer';
5
+ import { NodeInfoPanel } from '../components/NodeInfoPanel';
6
+ import { NodeTooltip } from '../components/NodeTooltip';
7
+ import type { NodeState, NodeTypeDefinition } from '@principal-ai/principal-view-core';
8
+
9
+ // OTEL Log Association canvas data
10
+ const otelCanvas = {
11
+ nodes: [
12
+ {
13
+ id: 'otel-log',
14
+ type: 'text',
15
+ text: 'OtelLog',
16
+ x: -304,
17
+ y: 147,
18
+ width: 120,
19
+ height: 118,
20
+ pv: {
21
+ nodeType: 'otel-type',
22
+ name: 'OtelLog',
23
+ description:
24
+ 'OpenTelemetry log record with timestamp, severity, body, resource, and trace context',
25
+ otel: {
26
+ kind: 'type',
27
+ category: 'log',
28
+ isNew: true,
29
+ },
30
+ shape: 'rectangle',
31
+ icon: 'FileText',
32
+ fill: '#4A90E2',
33
+ },
34
+ },
35
+ {
36
+ id: 'log-router',
37
+ type: 'text',
38
+ text: 'LogRouter',
39
+ x: -80,
40
+ y: 150,
41
+ width: 130,
42
+ height: 118,
43
+ pv: {
44
+ nodeType: 'otel-service',
45
+ name: 'LogRouter',
46
+ description: 'Routes incoming OTEL logs to canvas nodes based on scope and resourceMatch criteria',
47
+ otel: {
48
+ kind: 'service',
49
+ category: 'router',
50
+ isNew: true,
51
+ },
52
+ shape: 'hexagon',
53
+ icon: 'GitBranch',
54
+ fill: '#7ED321',
55
+ },
56
+ },
57
+ {
58
+ id: 'orphaned-log',
59
+ type: 'text',
60
+ text: 'OrphanedLog',
61
+ x: 150,
62
+ y: 150,
63
+ width: 127,
64
+ height: 118,
65
+ pv: {
66
+ nodeType: 'otel-type',
67
+ name: 'OrphanedLog',
68
+ description:
69
+ 'Logs that matched canvas scope but no node resourceMatch - indicates missing nodes or misconfiguration',
70
+ otel: {
71
+ kind: 'type',
72
+ category: 'audit',
73
+ isNew: true,
74
+ },
75
+ shape: 'rectangle',
76
+ icon: 'AlertTriangle',
77
+ fill: '#D0021B',
78
+ },
79
+ },
80
+ {
81
+ id: 'match-operator',
82
+ type: 'text',
83
+ text: 'MatchOperator',
84
+ x: -80,
85
+ y: 300,
86
+ width: 120,
87
+ height: 117,
88
+ pv: {
89
+ nodeType: 'service',
90
+ name: 'MatchOperator',
91
+ description: 'Matching operators: exact, glob, regex, exists, oneOf',
92
+ shape: 'diamond',
93
+ icon: 'Code',
94
+ fill: '#F5A623',
95
+ },
96
+ },
97
+ ],
98
+ edges: [
99
+ {
100
+ id: 'log-to-router',
101
+ fromNode: 'otel-log',
102
+ toNode: 'log-router',
103
+ fromSide: 'right',
104
+ toSide: 'left',
105
+ label: 'route()',
106
+ },
107
+ {
108
+ id: 'router-to-orphan',
109
+ fromNode: 'log-router',
110
+ toNode: 'orphaned-log',
111
+ fromSide: 'right',
112
+ toSide: 'left',
113
+ label: 'unmatched',
114
+ },
115
+ {
116
+ id: 'router-to-operator',
117
+ fromNode: 'log-router',
118
+ toNode: 'match-operator',
119
+ fromSide: 'bottom',
120
+ toSide: 'top',
121
+ label: 'uses',
122
+ },
123
+ ],
124
+ pv: {
125
+ version: '1.0.0',
126
+ name: 'OTEL Components Demo',
127
+ description: 'Demonstrates OTEL badges, tooltips, and info panel',
128
+ nodeTypes: {
129
+ 'otel-type': {
130
+ label: 'Type',
131
+ description: 'TypeScript type or interface representing OTEL concepts',
132
+ shape: 'rectangle',
133
+ },
134
+ 'otel-service': {
135
+ label: 'Service',
136
+ description: 'Runtime service component for OTEL processing',
137
+ shape: 'hexagon',
138
+ },
139
+ service: {
140
+ label: 'Component',
141
+ description: 'System component',
142
+ shape: 'hexagon',
143
+ },
144
+ },
145
+ },
146
+ };
147
+
148
+ const meta: Meta = {
149
+ title: 'OTEL/Components',
150
+ parameters: {
151
+ layout: 'fullscreen',
152
+ },
153
+ };
154
+
155
+ export default meta;
156
+
157
+ /**
158
+ * Shows nodes with OTEL badges (T/S/I circles) and hover tooltips.
159
+ * Hover over any node to see the tooltip with OTEL kind, category, and description.
160
+ */
161
+ export const OtelBadgesAndTooltips: StoryObj = {
162
+ render: () => (
163
+ <ThemeProvider theme="technology">
164
+ <div style={{ width: '100%', height: '600px' }}>
165
+ <GraphRenderer
166
+ canvas={otelCanvas}
167
+ initialViewport={{ x: 200, y: 50, zoom: 1 }}
168
+ />
169
+ </div>
170
+ </ThemeProvider>
171
+ ),
172
+ };
173
+
174
+ /**
175
+ * Standalone NodeTooltip component demo showing all OTEL kinds.
176
+ */
177
+ export const TooltipVariants: StoryObj = {
178
+ render: () => (
179
+ <ThemeProvider theme="technology">
180
+ <div style={{ padding: '40px', display: 'flex', gap: '80px', flexWrap: 'wrap' }}>
181
+ <div style={{ position: 'relative', width: '200px', height: '150px' }}>
182
+ <div
183
+ style={{
184
+ padding: '20px',
185
+ border: '2px solid #4A90E2',
186
+ borderRadius: '8px',
187
+ textAlign: 'center',
188
+ }}
189
+ >
190
+ Type Node (hover below)
191
+ </div>
192
+ <NodeTooltip
193
+ description="OpenTelemetry log record with timestamp, severity, body"
194
+ otel={{ kind: 'type', category: 'log', isNew: true }}
195
+ visible={true}
196
+ />
197
+ </div>
198
+
199
+ <div style={{ position: 'relative', width: '200px', height: '150px' }}>
200
+ <div
201
+ style={{
202
+ padding: '20px',
203
+ border: '2px solid #7ED321',
204
+ borderRadius: '8px',
205
+ textAlign: 'center',
206
+ }}
207
+ >
208
+ Service Node (hover below)
209
+ </div>
210
+ <NodeTooltip
211
+ description="Routes logs to canvas nodes based on resourceMatch"
212
+ otel={{ kind: 'service', category: 'router' }}
213
+ visible={true}
214
+ />
215
+ </div>
216
+
217
+ <div style={{ position: 'relative', width: '200px', height: '150px' }}>
218
+ <div
219
+ style={{
220
+ padding: '20px',
221
+ border: '2px solid #9B59B6',
222
+ borderRadius: '8px',
223
+ textAlign: 'center',
224
+ }}
225
+ >
226
+ Instance Node (hover below)
227
+ </div>
228
+ <NodeTooltip
229
+ description="A specific running instance of a service"
230
+ otel={{ kind: 'instance', category: 'runtime' }}
231
+ visible={true}
232
+ />
233
+ </div>
234
+ </div>
235
+ </ThemeProvider>
236
+ ),
237
+ };
238
+
239
+ /**
240
+ * NodeInfoPanel with OTEL information section.
241
+ */
242
+ export const InfoPanelWithOtel: StoryObj = {
243
+ render: () => {
244
+ const [selectedNode] = useState<NodeState>({
245
+ id: 'log-router',
246
+ type: 'otel-service',
247
+ name: 'LogRouter',
248
+ data: {
249
+ description: 'Routes incoming OTEL logs to canvas nodes based on scope and resourceMatch criteria',
250
+ otel: {
251
+ kind: 'service',
252
+ category: 'router',
253
+ isNew: true,
254
+ },
255
+ icon: 'GitBranch',
256
+ color: '#7ED321',
257
+ sources: ['src/services/LogRouter.ts'],
258
+ },
259
+ position: { x: 0, y: 0 },
260
+ createdAt: Date.now(),
261
+ updatedAt: Date.now(),
262
+ });
263
+
264
+ const typeDefinition: NodeTypeDefinition = {
265
+ shape: 'hexagon',
266
+ color: '#7ED321',
267
+ icon: 'GitBranch',
268
+ };
269
+
270
+ return (
271
+ <ThemeProvider theme="technology">
272
+ <div style={{ padding: '20px', position: 'relative', minHeight: '400px' }}>
273
+ <h3 style={{ marginBottom: '20px' }}>NodeInfoPanel with OTEL Section</h3>
274
+ <p style={{ marginBottom: '20px', color: '#666' }}>
275
+ The panel shows the OpenTelemetry section with kind badge, category, and NEW indicator.
276
+ </p>
277
+ <NodeInfoPanel
278
+ node={selectedNode}
279
+ typeDefinition={typeDefinition}
280
+ onClose={() => {}}
281
+ />
282
+ </div>
283
+ </ThemeProvider>
284
+ );
285
+ },
286
+ };