@principal-ai/principal-view-react 0.16.55 → 0.16.57

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 (125) hide show
  1. package/dist/graphify/consolidated.d.ts +16 -1
  2. package/dist/graphify/consolidated.d.ts.map +1 -1
  3. package/dist/graphify/index.d.ts +1 -1
  4. package/dist/graphify/index.d.ts.map +1 -1
  5. package/dist/graphify/index.js.map +1 -1
  6. package/dist/graphify/kind.d.ts +1 -1
  7. package/dist/graphify/kind.d.ts.map +1 -1
  8. package/dist/graphify/kind.js +7 -1
  9. package/dist/graphify/kind.js.map +1 -1
  10. package/dist/index.d.ts +5 -4
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +3 -2
  13. package/dist/index.js.map +1 -1
  14. package/dist/pierre/constructColors.d.ts +24 -0
  15. package/dist/pierre/constructColors.d.ts.map +1 -0
  16. package/dist/pierre/constructColors.js +91 -0
  17. package/dist/pierre/constructColors.js.map +1 -0
  18. package/dist/pierre/index.d.ts +2 -0
  19. package/dist/pierre/index.d.ts.map +1 -1
  20. package/dist/pierre/index.js +1 -0
  21. package/dist/pierre/index.js.map +1 -1
  22. package/dist/pierre/pierreSyntaxTheme.d.ts +11 -0
  23. package/dist/pierre/pierreSyntaxTheme.d.ts.map +1 -0
  24. package/dist/pierre/pierreSyntaxTheme.js +20 -0
  25. package/dist/pierre/pierreSyntaxTheme.js.map +1 -0
  26. package/dist/pierre/syntaxTokens.d.ts +11 -0
  27. package/dist/pierre/syntaxTokens.d.ts.map +1 -0
  28. package/dist/pierre/syntaxTokens.js +51 -0
  29. package/dist/pierre/syntaxTokens.js.map +1 -0
  30. package/dist/stories/Subsystem/ComponentGraph/fixtures.d.ts +8 -0
  31. package/dist/stories/Subsystem/ComponentGraph/fixtures.d.ts.map +1 -0
  32. package/dist/stories/Subsystem/ComponentGraph/fixtures.js +116 -0
  33. package/dist/stories/Subsystem/ComponentGraph/fixtures.js.map +1 -0
  34. package/dist/subsystem/ComponentDeclaration.d.ts +2 -2
  35. package/dist/subsystem/ComponentDeclaration.d.ts.map +1 -1
  36. package/dist/subsystem/ComponentDeclaration.js +47 -24
  37. package/dist/subsystem/ComponentDeclaration.js.map +1 -1
  38. package/dist/subsystem/SubsystemComponentGraph.d.ts.map +1 -1
  39. package/dist/subsystem/SubsystemComponentGraph.js +23 -2
  40. package/dist/subsystem/SubsystemComponentGraph.js.map +1 -1
  41. package/dist/subsystem/formatDeclaration.d.ts.map +1 -1
  42. package/dist/subsystem/formatDeclaration.js +49 -10
  43. package/dist/subsystem/formatDeclaration.js.map +1 -1
  44. package/dist/subsystem/model.d.ts +57 -12
  45. package/dist/subsystem/model.d.ts.map +1 -1
  46. package/dist/subsystem/model.js +54 -24
  47. package/dist/subsystem/model.js.map +1 -1
  48. package/dist/subsystem/nodes.d.ts +4 -1
  49. package/dist/subsystem/nodes.d.ts.map +1 -1
  50. package/dist/subsystem/nodes.js +70 -21
  51. package/dist/subsystem/nodes.js.map +1 -1
  52. package/dist/subsystem/tokenizeComponent.d.ts +4 -3
  53. package/dist/subsystem/tokenizeComponent.d.ts.map +1 -1
  54. package/dist/subsystem/tokenizeComponent.js +7 -12
  55. package/dist/subsystem/tokenizeComponent.js.map +1 -1
  56. package/dist/subsystem/tokenizeFormatted.d.ts +3 -6
  57. package/dist/subsystem/tokenizeFormatted.d.ts.map +1 -1
  58. package/dist/subsystem/tokenizeFormatted.js +4 -75
  59. package/dist/subsystem/tokenizeFormatted.js.map +1 -1
  60. package/package.json +3 -1
  61. package/src/graphify/consolidated.ts +18 -1
  62. package/src/graphify/index.ts +1 -0
  63. package/src/graphify/kind.ts +7 -1
  64. package/src/index.ts +5 -3
  65. package/src/pierre/constructColors.test.ts +52 -0
  66. package/src/pierre/constructColors.ts +112 -0
  67. package/src/pierre/index.ts +5 -0
  68. package/src/pierre/pierreSyntaxTheme.ts +23 -0
  69. package/src/pierre/syntaxTokens.test.ts +35 -0
  70. package/src/pierre/syntaxTokens.ts +60 -0
  71. package/src/stories/{BoundaryNodes.stories.tsx → Audit/BoundaryNodes.stories.tsx} +1 -1
  72. package/src/stories/{CanvasEdgeTypes.stories.tsx → Audit/CanvasEdgeTypes.stories.tsx} +1 -1
  73. package/src/stories/{CanvasNodeTypes.stories.tsx → Audit/CanvasNodeTypes.stories.tsx} +1 -1
  74. package/src/stories/{ColorPriority.stories.tsx → Audit/ColorPriority.stories.tsx} +1 -1
  75. package/src/stories/{DiamondBadges.stories.tsx → Audit/DiamondBadges.stories.tsx} +1 -1
  76. package/src/stories/{NodeDimensionsTesting.stories.tsx → Audit/NodeDimensionsTesting.stories.tsx} +2 -2
  77. package/src/stories/{NodeFieldsAudit.stories.tsx → Audit/NodeFieldsAudit.stories.tsx} +1 -1
  78. package/src/stories/{NodeFontSizeTesting.stories.tsx → Audit/NodeFontSizeTesting.stories.tsx} +2 -2
  79. package/src/stories/{NodeShapes.stories.tsx → Audit/NodeShapes.stories.tsx} +1 -1
  80. package/src/stories/{WideNodesTesting.stories.tsx → Audit/WideNodesTesting.stories.tsx} +2 -2
  81. package/src/stories/{dashboard → Components}/DashboardRenderer.stories.tsx +2 -2
  82. package/src/stories/{GraphRenderer.stories.tsx → Components/GraphRenderer.stories.tsx} +2 -2
  83. package/src/stories/{MultiCanvasRenderer.stories.tsx → Components/MultiCanvasRenderer.stories.tsx} +2 -2
  84. package/src/stories/{SequenceDiagram.stories.tsx → Components/SequenceDiagram.stories.tsx} +2 -2
  85. package/src/stories/{StateView.stories.tsx → Components/StateView.stories.tsx} +2 -2
  86. package/src/stories/{TraceViewer.stories.tsx → Components/TraceViewer.stories.tsx} +3 -3
  87. package/src/stories/{WorkflowSequenceDiagram.stories.tsx → Components/WorkflowSequenceDiagram.stories.tsx} +1 -1
  88. package/src/stories/{AnimationWorkshop.stories.tsx → Features/AnimationWorkshop.stories.tsx} +5 -5
  89. package/src/stories/{ChangeTypeVisual.stories.tsx → Features/ChangeTypeVisual.stories.tsx} +2 -2
  90. package/src/stories/{EventDrivenAnimations.stories.tsx → Features/EventDrivenAnimations.stories.tsx} +2 -2
  91. package/src/stories/{MultiConfig.stories.tsx → Features/MultiConfig.stories.tsx} +2 -2
  92. package/src/stories/{ElkEdgeRouting.stories.tsx → Layout/ElkEdgeRouting.stories.tsx} +2 -2
  93. package/src/stories/{GraphOrientation.stories.tsx → Layout/GraphOrientation.stories.tsx} +3 -3
  94. package/src/stories/{MultiDirectionalConnections.stories.tsx → Layout/MultiDirectionalConnections.stories.tsx} +2 -2
  95. package/src/stories/{NodeDefinitionComparison.stories.tsx → Nodes/NodeDefinitionComparison.stories.tsx} +2 -2
  96. package/src/stories/{NodeNameFallbacks.stories.tsx → Nodes/NodeNameFallbacks.stories.tsx} +2 -2
  97. package/src/stories/{NumericColors.stories.tsx → Nodes/NumericColors.stories.tsx} +2 -2
  98. package/src/stories/{EventNameDisplay.stories.tsx → OTEL/EventNameDisplay.stories.tsx} +2 -2
  99. package/src/stories/{EventNameFallback.stories.tsx → OTEL/EventNameFallback.stories.tsx} +2 -2
  100. package/src/stories/{OtelComponents.stories.tsx → OTEL/OtelComponents.stories.tsx} +3 -3
  101. package/src/stories/{OtelNodeTypesPrototype.stories.tsx → OTEL/OtelNodeTypesPrototype.stories.tsx} +2 -2
  102. package/src/stories/{RawEventCards.stories.tsx → OTEL/RawEventCards.stories.tsx} +3 -3
  103. package/src/stories/{SpanBadges.stories.tsx → OTEL/SpanBadges.stories.tsx} +1 -1
  104. package/src/stories/{ValidationEventsCanvas.stories.tsx → OTEL/ValidationEventsCanvas.stories.tsx} +3 -3
  105. package/src/stories/{BacklogMdCanvases.stories.tsx → RealWorld/BacklogMdCanvases.stories.tsx} +2 -2
  106. package/src/stories/{FileCitySequence.stories.tsx → RealWorld/FileCitySequence.stories.tsx} +4 -4
  107. package/src/stories/{RealCanvasFiles.stories.tsx → RealWorld/RealCanvasFiles.stories.tsx} +7 -7
  108. package/src/stories/{ComponentDeclarationAudit.stories.tsx → Subsystem/ComponentDeclarationAudit.stories.tsx} +19 -20
  109. package/src/stories/Subsystem/ComponentGraph/Appearance.stories.tsx +365 -0
  110. package/src/stories/Subsystem/ComponentGraph/Basics.stories.tsx +137 -0
  111. package/src/stories/Subsystem/ComponentGraph/Captures.stories.tsx +238 -0
  112. package/src/stories/Subsystem/ComponentGraph/DetailPanel.stories.tsx +315 -0
  113. package/src/stories/Subsystem/ComponentGraph/Scenarios.stories.tsx +959 -0
  114. package/src/stories/Subsystem/ComponentGraph/Spotlights.stories.tsx +646 -0
  115. package/src/stories/Subsystem/ComponentGraph/fixtures.ts +129 -0
  116. package/src/subsystem/ComponentDeclaration.tsx +64 -26
  117. package/src/subsystem/SubsystemComponentGraph.tsx +26 -6
  118. package/src/subsystem/formatDeclaration.ts +57 -11
  119. package/src/subsystem/model.test.ts +38 -6
  120. package/src/subsystem/model.ts +110 -31
  121. package/src/subsystem/nodes.tsx +103 -27
  122. package/src/subsystem/tokenizeComponent.ts +12 -12
  123. package/src/subsystem/tokenizeFormatted.ts +9 -82
  124. package/src/stories/SubsystemComponentGraph.stories.tsx +0 -1225
  125. /package/src/stories/{dashboard/sample-dashboards → data}/activity-feed-analytics.dashboard.json +0 -0
@@ -0,0 +1,365 @@
1
+ import React, { useState } from 'react';
2
+ import '@xyflow/react/dist/style.css';
3
+ import type { Meta, StoryObj } from '@storybook/react';
4
+ import { ThemeProvider, defaultEditorTheme } from '@principal-ade/industry-theme';
5
+ import { SubsystemComponentGraph } from '../../../subsystem/SubsystemComponentGraph';
6
+ import type { SubsystemComponent, SubsystemComponentEdge } from '../../../subsystem/model';
7
+ import type { GraphifyComponentDetail } from '../../../graphify';
8
+ import { investigateOnlyComponents, investigateOnlyEdges } from './fixtures';
9
+
10
+ const meta = {
11
+ title: 'Subsystem/ComponentGraph/Appearance',
12
+ component: SubsystemComponentGraph,
13
+ parameters: {
14
+ layout: 'fullscreen',
15
+ },
16
+ tags: ['autodocs'],
17
+ decorators: [
18
+ (Story) => (
19
+ <ThemeProvider theme={defaultEditorTheme}>
20
+ <Story />
21
+ </ThemeProvider>
22
+ ),
23
+ ],
24
+ } satisfies Meta<typeof SubsystemComponentGraph>;
25
+
26
+ export default meta;
27
+ type Story = StoryObj<typeof meta>;
28
+
29
+ /** Same pipeline as Captures/InvestigateOnly with a narrower `maxNodeWidth` (140) — long names wrap. */
30
+ export const NarrowMaxWidth: Story = {
31
+ render: () => (
32
+ <div style={{ width: '100%', height: '100vh', display: 'flex', flexDirection: 'column' }}>
33
+ <SubsystemComponentGraph
34
+ components={investigateOnlyComponents}
35
+ edges={investigateOnlyEdges}
36
+ maxNodeWidth={140}
37
+ />
38
+ </div>
39
+ ),
40
+ };
41
+
42
+ // ---------------------------------------------------------------------------
43
+ // Naming-convention wrap check — one node per common symbol convention.
44
+ // ---------------------------------------------------------------------------
45
+ const namingConventionComponents: SubsystemComponent[] = [
46
+ {
47
+ id: 'camel',
48
+ name: 'accumulateToAgentSessionEvents',
49
+ construct: 'function',
50
+ file: 'src/event-processing/accumulator.ts',
51
+ purl: 'pkg:github/principal-ai/agent-monitoring',
52
+ symbol: 'accumulateToAgentSessionEvents',
53
+ },
54
+ {
55
+ id: 'snake',
56
+ name: 'repo_normalized_universal_event',
57
+ construct: 'interface',
58
+ file: 'src/event-processing/repo_normalized.ts',
59
+ purl: 'pkg:github/principal-ai/agent-monitoring',
60
+ symbol: 'repo_normalized_universal_event',
61
+ },
62
+ {
63
+ id: 'pascal',
64
+ name: 'RepoNormalizedUniversalAgentSessionEvent',
65
+ construct: 'class',
66
+ file: 'src/event-processing/RepoNormalized.ts',
67
+ purl: 'pkg:github/principal-ai/agent-monitoring',
68
+ symbol: 'RepoNormalizedUniversalAgentSessionEvent',
69
+ },
70
+ {
71
+ id: 'acronym',
72
+ name: 'ProcessSSEStreamForEventToken',
73
+ construct: 'function',
74
+ file: 'src/event-processing/sse.ts',
75
+ purl: 'pkg:github/principal-ai/agent-monitoring',
76
+ symbol: 'ProcessSSEStreamForEventToken',
77
+ },
78
+ {
79
+ id: 'method',
80
+ name: 'normalize',
81
+ construct: 'function',
82
+ file: 'src/session/SessionReader.ts',
83
+ purl: 'pkg:github/principal-ai/agent-monitoring',
84
+ symbol: 'SessionReader.normalize',
85
+ },
86
+ {
87
+ id: 'pkg',
88
+ name: 'trail-viewer',
89
+ construct: 'external',
90
+ file: '',
91
+ purl: 'pkg:npm/@principal-ai/trail-viewer',
92
+ symbol: '',
93
+ },
94
+ ];
95
+
96
+ const namingConventionEdges: SubsystemComponentEdge[] = [];
97
+
98
+ /** Nodes with compact `maxNodeWidth` so the different conventions visibly wrap
99
+ * at their word boundaries (camelCase, snake_case, PascalCase, acronyms). */
100
+ export const NamingConventions: Story = {
101
+ render: () => (
102
+ <div style={{ width: '100%', height: '100vh', display: 'flex', flexDirection: 'column' }}>
103
+ <SubsystemComponentGraph
104
+ components={namingConventionComponents}
105
+ edges={namingConventionEdges}
106
+ maxNodeWidth={180}
107
+ />
108
+ </div>
109
+ ),
110
+ };
111
+
112
+ // ---------------------------------------------------------------------------
113
+ // Kind variations — one column per kind (class / function / type / module /
114
+ // external), rows going bare → detailed. Click a node to see its declaration
115
+ // panel; type names inside it are clickable when they match another node here.
116
+ // ---------------------------------------------------------------------------
117
+ const variationPurl = 'pkg:github/principal-ai/agent-monitoring';
118
+
119
+ const kindVariationComponents: SubsystemComponent[] = [
120
+ // --- class: bare → members only → relationships only
121
+ {
122
+ id: 'cls-bare',
123
+ name: 'SessionStore',
124
+ construct: 'class',
125
+ file: 'src/session/SessionStore.ts',
126
+ purl: variationPurl,
127
+ purpose: 'no drill-down — renders a plain `class SessionStore`',
128
+ symbol: 'SessionStore',
129
+ layer: 1,
130
+ },
131
+ {
132
+ id: 'cls-members',
133
+ name: 'Transcoder',
134
+ construct: 'class',
135
+ file: 'src/session/Transcoder.ts',
136
+ purl: variationPurl,
137
+ purpose: 'members only — methods with typed params + returns, a typed field',
138
+ symbol: 'Transcoder',
139
+ layer: 1,
140
+ detail: {
141
+ kind: 'class',
142
+ methods: [
143
+ { nodeId: 'tm1', name: 'encode', parameters: [{ type: 'RawFrame' }], returnType: 'Uint8Array' },
144
+ { nodeId: 'tm2', name: 'decode', parameters: [{ type: 'Uint8Array' }], returnType: 'RawFrame' },
145
+ { nodeId: 'tm3', name: 'reset' },
146
+ ],
147
+ properties: [{ name: 'bufferSize', type: 'number' }],
148
+ extends: [],
149
+ implements: [],
150
+ instantiations: [],
151
+ references: [],
152
+ } satisfies GraphifyComponentDetail,
153
+ },
154
+ {
155
+ id: 'cls-relations',
156
+ name: 'HttpTransport',
157
+ construct: 'class',
158
+ file: 'src/transport/HttpTransport.ts',
159
+ purl: variationPurl,
160
+ purpose: 'relationships only — extends + implements, constructed-by comment; empty body elides the braces',
161
+ symbol: 'HttpTransport',
162
+ layer: 1,
163
+ detail: {
164
+ kind: 'class',
165
+ methods: [],
166
+ properties: [],
167
+ extends: ['BaseTransport'],
168
+ implements: ['Transport'],
169
+ instantiations: [{ nodeId: 'x1', name: 'main' }],
170
+ references: [],
171
+ } satisfies GraphifyComponentDetail,
172
+ },
173
+
174
+ // --- function: bare → signature only → signature + call relationships
175
+ {
176
+ id: 'fn-bare',
177
+ name: 'bootstrap',
178
+ construct: 'function',
179
+ file: 'src/bootstrap.ts',
180
+ purl: variationPurl,
181
+ purpose: 'no drill-down — renders a plain `function bootstrap()`',
182
+ symbol: 'bootstrap',
183
+ layer: 2,
184
+ },
185
+ {
186
+ id: 'fn-signature',
187
+ name: 'normalizeSession',
188
+ construct: 'function',
189
+ file: 'src/event-processing/normalize.ts',
190
+ purl: variationPurl,
191
+ purpose: 'signature only — named + positional (type-only) params, array return; no callers/callees comments',
192
+ symbol: 'normalizeSession',
193
+ layer: 2,
194
+ detail: {
195
+ kind: 'function',
196
+ parameters: [
197
+ { name: 'session', type: 'SessionRecord' },
198
+ { type: 'NormalizeOptions' },
199
+ ],
200
+ returnType: 'SessionEvent[]',
201
+ callers: [],
202
+ callees: [],
203
+ } satisfies GraphifyComponentDetail,
204
+ },
205
+ {
206
+ id: 'fn-calls',
207
+ name: 'mergeSessions',
208
+ construct: 'function',
209
+ file: 'src/session/merge.ts',
210
+ purl: variationPurl,
211
+ purpose: 'signature + call relationships — union-typed param, generic return, called-by / calls trailing comments',
212
+ symbol: 'mergeSessions',
213
+ layer: 2,
214
+ detail: {
215
+ kind: 'function',
216
+ parameters: [
217
+ { name: 'sessions', type: 'SessionRecord[]' },
218
+ { name: 'strategy', type: `'append' | 'replace'` },
219
+ ],
220
+ returnType: 'Promise<SessionEvent[]>',
221
+ callers: [{ nodeId: 'c1', name: 'capture-session', source_location: 'L88' }],
222
+ callees: [{ nodeId: 'c2', name: 'toUniversalEvents', source_location: 'L64' }],
223
+ } satisfies GraphifyComponentDetail,
224
+ },
225
+
226
+ // --- type: bare → fields only → fields + implementors + used-by
227
+ {
228
+ id: 'ty-bare',
229
+ name: 'RawFrame',
230
+ construct: 'interface',
231
+ file: 'src/session/RawFrame.ts',
232
+ purl: variationPurl,
233
+ purpose: 'no drill-down — renders a plain `interface RawFrame`',
234
+ symbol: 'RawFrame',
235
+ layer: 3,
236
+ },
237
+ {
238
+ id: 'ty-fields',
239
+ name: 'SessionRecord',
240
+ construct: 'interface',
241
+ file: 'src/session/transcript.ts',
242
+ purl: variationPurl,
243
+ purpose: 'fields only — typed interface body, nothing else',
244
+ symbol: 'SessionRecord',
245
+ layer: 3,
246
+ detail: {
247
+ kind: 'type',
248
+ properties: [
249
+ { name: 'id', type: 'string' },
250
+ { name: 'admittedSeq', type: 'number' },
251
+ ],
252
+ usedBy: [],
253
+ implementors: [],
254
+ } satisfies GraphifyComponentDetail,
255
+ },
256
+ {
257
+ id: 'ty-full',
258
+ name: 'Transport',
259
+ construct: 'interface',
260
+ file: 'src/transport/Transport.ts',
261
+ purl: variationPurl,
262
+ purpose: 'full — fields + implemented-by (clicks through to HttpTransport) + used-by comments',
263
+ symbol: 'Transport',
264
+ layer: 3,
265
+ detail: {
266
+ kind: 'type',
267
+ properties: [{ name: 'name', type: 'string' }],
268
+ usedBy: [{ nodeId: 'u1', name: 'main', context: 'parameter_type' }],
269
+ implementors: ['HttpTransport'],
270
+ } satisfies GraphifyComponentDetail,
271
+ },
272
+
273
+ // --- module: bare → exports only → exports + imports
274
+ {
275
+ id: 'mod-bare',
276
+ name: 'transcript',
277
+ construct: 'module',
278
+ file: 'src/session/transcript.ts',
279
+ purl: variationPurl,
280
+ purpose: 'no drill-down — symbol-less module named from its file basename',
281
+ symbol: '',
282
+ layer: 4,
283
+ },
284
+ {
285
+ id: 'mod-exports',
286
+ name: 'paths',
287
+ construct: 'module',
288
+ file: 'src/session/paths.ts',
289
+ purl: variationPurl,
290
+ purpose: 'exports only — export statement + defines comment',
291
+ symbol: '',
292
+ layer: 4,
293
+ detail: {
294
+ kind: 'module',
295
+ exports: ['extractToolName', 'extractFilePath'],
296
+ imports: [],
297
+ symbols: ['extractToolName', 'extractFilePath'],
298
+ } satisfies GraphifyComponentDetail,
299
+ },
300
+ {
301
+ id: 'mod-full',
302
+ name: 'index',
303
+ construct: 'module',
304
+ file: 'src/index.ts',
305
+ purl: variationPurl,
306
+ purpose: 'full — import statements + re-export statement + defines comment',
307
+ symbol: '',
308
+ layer: 4,
309
+ detail: {
310
+ kind: 'module',
311
+ exports: ['SessionReader', 'SessionStore'],
312
+ imports: [{ nodeId: 'i1', name: 'transcript', relation: 'imports_from' }],
313
+ symbols: ['SessionReader', 'SessionStore'],
314
+ } satisfies GraphifyComponentDetail,
315
+ },
316
+
317
+ // --- external: bare → labeled
318
+ {
319
+ id: 'ext-bare',
320
+ name: 'left-pad',
321
+ construct: 'external',
322
+ file: '',
323
+ purl: 'pkg:npm/left-pad',
324
+ purpose: 'no drill-down — renders a plain `external left-pad`',
325
+ symbol: '',
326
+ layer: 5,
327
+ },
328
+ {
329
+ id: 'ext-label',
330
+ name: 'trail-viewer',
331
+ construct: 'external',
332
+ file: '',
333
+ purl: 'pkg:npm/@principal-ai/trail-viewer',
334
+ purpose: 'labeled — the full purl as a quoted string literal',
335
+ symbol: '',
336
+ layer: 5,
337
+ detail: {
338
+ kind: 'external',
339
+ label: 'pkg:npm/@principal-ai/trail-viewer',
340
+ } satisfies GraphifyComponentDetail,
341
+ },
342
+ ];
343
+
344
+ const kindVariationEdges: SubsystemComponentEdge[] = [];
345
+
346
+ function KindVariationsDemo() {
347
+ const [selected, setSelected] = useState<string | null>(null);
348
+ return (
349
+ <div style={{ width: '100%', height: '100vh', display: 'flex', flexDirection: 'column' }}>
350
+ <SubsystemComponentGraph
351
+ components={kindVariationComponents}
352
+ edges={kindVariationEdges}
353
+ onSelect={(id) => setSelected(id)}
354
+ />
355
+ <div style={{ marginTop: 8, fontFamily: 'monospace', fontSize: 12, color: '#aaa' }}>
356
+ columns: class · function · type · module · external — each goes bare → detailed
357
+ {selected ? ` · selected: ${selected}` : ''}
358
+ </div>
359
+ </div>
360
+ );
361
+ }
362
+
363
+ export const KindVariations: Story = {
364
+ render: () => <KindVariationsDemo />,
365
+ };
@@ -0,0 +1,137 @@
1
+ import React, { useState } from 'react';
2
+ import '@xyflow/react/dist/style.css';
3
+ import type { Meta, StoryObj } from '@storybook/react';
4
+ import { ThemeProvider, defaultEditorTheme } from '@principal-ade/industry-theme';
5
+ import { SubsystemComponentGraph } from '../../../subsystem/SubsystemComponentGraph';
6
+ import type { SubsystemComponent, SubsystemComponentEdge } from '../../../subsystem/model';
7
+ import { components, edges } from './fixtures';
8
+
9
+ const meta = {
10
+ title: 'Subsystem/ComponentGraph/Basics',
11
+ component: SubsystemComponentGraph,
12
+ parameters: {
13
+ layout: 'fullscreen',
14
+ },
15
+ tags: ['autodocs'],
16
+ decorators: [
17
+ (Story) => (
18
+ <ThemeProvider theme={defaultEditorTheme}>
19
+ <Story />
20
+ </ThemeProvider>
21
+ ),
22
+ ],
23
+ } satisfies Meta<typeof SubsystemComponentGraph>;
24
+
25
+ export default meta;
26
+ type Story = StoryObj<typeof meta>;
27
+
28
+ // ---------------------------------------------------------------------------
29
+ // Minimal: two nodes, one edge — the simplest possible label layout test.
30
+ // ---------------------------------------------------------------------------
31
+ const twoNodeComponents = components([
32
+ ['src', 'TranscriptParser', 'class', 'transcript.ts', 'pkg:github/principal-ai/agent-monitoring', 'parses session records'],
33
+ ['dst', 'SessionReader', 'class', 'SessionReader.ts', 'pkg:github/principal-ai/agent-monitoring', 'normalizes sessions into events'],
34
+ ]);
35
+
36
+ const twoNodeEdges = edges([
37
+ ['src', 'dst', 'imports'],
38
+ ]);
39
+
40
+ function TwoNodeDemo({ showEdgeLabels = true }: { showEdgeLabels?: boolean }) {
41
+ const [selected, setSelected] = useState<string | null>(null);
42
+ const [selectedEdge, setSelectedEdge] = useState<SubsystemComponentEdge | null>(null);
43
+ return (
44
+ <div style={{ width: '100%', height: '100vh', display: 'flex', flexDirection: 'column' }}>
45
+ <SubsystemComponentGraph
46
+ components={twoNodeComponents}
47
+ edges={twoNodeEdges}
48
+ onSelect={(id) => setSelected(id)}
49
+ onEdgeSelect={(e) => setSelectedEdge(e)}
50
+ showEdgeLabels={showEdgeLabels}
51
+ />
52
+ <div style={{ marginTop: 8, fontFamily: 'monospace', fontSize: 12, color: '#aaa' }}>
53
+ {selectedEdge
54
+ ? `edge: ${selectedEdge.from} --${selectedEdge.mechanism}--> ${selectedEdge.to}`
55
+ : selected
56
+ ? `selected: ${selected}`
57
+ : 'click a component or edge to select it'}
58
+ </div>
59
+ </div>
60
+ );
61
+ }
62
+
63
+ export const TwoNodeSingleEdge: Story = {
64
+ render: () => <TwoNodeDemo />,
65
+ };
66
+
67
+ export const TwoNodeNoLabels: Story = {
68
+ render: () => <TwoNodeDemo showEdgeLabels={false} />,
69
+ };
70
+
71
+ // ---------------------------------------------------------------------------
72
+ // Playground: control the number of nodes in left and right layers.
73
+ // All left nodes connect to all right nodes (fan-in / fan-out).
74
+ // ---------------------------------------------------------------------------
75
+ function PlaygroundDemo({ leftCount, rightCount, showEdgeLabels }: { leftCount: number; rightCount: number; showEdgeLabels: boolean }) {
76
+ const comps: SubsystemComponent[] = [];
77
+ const edgeList: SubsystemComponentEdge[] = [];
78
+
79
+ for (let i = 0; i < leftCount; i++) {
80
+ comps.push({
81
+ id: `l${i}`,
82
+ name: `Left${i}`,
83
+ construct: 'class',
84
+ file: `left${i}.ts`,
85
+ purl: 'pkg:github/principal-ai/playground',
86
+ purpose: `left layer node ${i}`,
87
+ });
88
+ }
89
+ for (let i = 0; i < rightCount; i++) {
90
+ comps.push({
91
+ id: `r${i}`,
92
+ name: `Right${i}`,
93
+ construct: 'class',
94
+ file: `right${i}.ts`,
95
+ purl: 'pkg:github/principal-ai/playground',
96
+ purpose: `right layer node ${i}`,
97
+ });
98
+ }
99
+
100
+ let ei = 0;
101
+ for (let i = 0; i < leftCount; i++) {
102
+ for (let j = 0; j < rightCount; j++) {
103
+ edgeList.push({ id: `e${ei++}`, from: `l${i}`, to: `r${j}`, mechanism: 'imports' });
104
+ }
105
+ }
106
+
107
+ return (
108
+ <div style={{ width: '100%', height: '100vh', display: 'flex', flexDirection: 'column' }}>
109
+ <SubsystemComponentGraph components={comps} edges={edgeList} showEdgeLabels={showEdgeLabels} />
110
+ </div>
111
+ );
112
+ }
113
+
114
+ export const Playground: Story = {
115
+ render: (args) => <PlaygroundDemo {...args} />,
116
+ args: {
117
+ leftCount: 1,
118
+ rightCount: 1,
119
+ showEdgeLabels: true,
120
+ },
121
+ argTypes: {
122
+ leftCount: { control: { type: 'number', min: 0, max: 6, step: 1 } },
123
+ rightCount: { control: { type: 'number', min: 0, max: 6, step: 1 } },
124
+ showEdgeLabels: { control: 'boolean' },
125
+ },
126
+ };
127
+
128
+ // ---------------------------------------------------------------------------
129
+ // Empty state
130
+ // ---------------------------------------------------------------------------
131
+ export const Empty: Story = {
132
+ render: () => (
133
+ <div style={{ width: '100%', height: '100vh', display: 'flex', flexDirection: 'column' }}>
134
+ <SubsystemComponentGraph components={[]} edges={[]} />
135
+ </div>
136
+ ),
137
+ };