@principal-ai/storybook-addon-otel 0.2.2 → 0.2.4
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/package.json +14 -5
- package/.npmignore +0 -20
- package/dist/components/TelemetryPanel.d.ts +0 -11
- package/dist/components/TelemetryPanel.js +0 -235
- package/dist/manager.d.ts +0 -6
package/package.json
CHANGED
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@principal-ai/storybook-addon-otel",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Storybook addon for capturing and visualizing OpenTelemetry data from story interactions",
|
|
5
|
-
"main": "
|
|
5
|
+
"main": "preset.js",
|
|
6
6
|
"types": "dist/preset.d.ts",
|
|
7
7
|
"files": [
|
|
8
|
-
"dist
|
|
8
|
+
"dist/collector.d.ts",
|
|
9
|
+
"dist/collector.js",
|
|
10
|
+
"dist/constants.d.ts",
|
|
11
|
+
"dist/constants.js",
|
|
12
|
+
"dist/decorator.d.ts",
|
|
13
|
+
"dist/decorator.js",
|
|
14
|
+
"dist/index.d.ts",
|
|
15
|
+
"dist/index.js",
|
|
16
|
+
"dist/preset.d.ts",
|
|
17
|
+
"dist/preset.js",
|
|
18
|
+
"dist/preview.js",
|
|
9
19
|
"preset.js",
|
|
10
20
|
"preview.js",
|
|
11
21
|
"manager.js",
|
|
12
|
-
"README.md"
|
|
13
|
-
".npmignore"
|
|
22
|
+
"README.md"
|
|
14
23
|
],
|
|
15
24
|
"exports": {
|
|
16
25
|
".": {
|
package/.npmignore
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# Source files (standalone manager.js used instead)
|
|
2
|
-
src/
|
|
3
|
-
|
|
4
|
-
# Exclude compiled manager files to avoid bundler conflicts in Storybook v10
|
|
5
|
-
dist/manager.js
|
|
6
|
-
dist/manager.d.ts
|
|
7
|
-
dist/components/
|
|
8
|
-
|
|
9
|
-
# Development files
|
|
10
|
-
scripts/
|
|
11
|
-
tsconfig.json
|
|
12
|
-
*.test.ts
|
|
13
|
-
*.test.tsx
|
|
14
|
-
*.spec.ts
|
|
15
|
-
*.spec.tsx
|
|
16
|
-
.DS_Store
|
|
17
|
-
node_modules/
|
|
18
|
-
coverage/
|
|
19
|
-
.nyc_output/
|
|
20
|
-
*.tgz
|
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Telemetry Panel Component
|
|
4
|
-
*
|
|
5
|
-
* Displays captured telemetry in Storybook panel
|
|
6
|
-
*/
|
|
7
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
-
if (k2 === undefined) k2 = k;
|
|
9
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
-
}
|
|
13
|
-
Object.defineProperty(o, k2, desc);
|
|
14
|
-
}) : (function(o, m, k, k2) {
|
|
15
|
-
if (k2 === undefined) k2 = k;
|
|
16
|
-
o[k2] = m[k];
|
|
17
|
-
}));
|
|
18
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
-
}) : function(o, v) {
|
|
21
|
-
o["default"] = v;
|
|
22
|
-
});
|
|
23
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
-
var ownKeys = function(o) {
|
|
25
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
-
var ar = [];
|
|
27
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
-
return ar;
|
|
29
|
-
};
|
|
30
|
-
return ownKeys(o);
|
|
31
|
-
};
|
|
32
|
-
return function (mod) {
|
|
33
|
-
if (mod && mod.__esModule) return mod;
|
|
34
|
-
var result = {};
|
|
35
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
-
__setModuleDefault(result, mod);
|
|
37
|
-
return result;
|
|
38
|
-
};
|
|
39
|
-
})();
|
|
40
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
-
exports.TelemetryPanel = void 0;
|
|
42
|
-
const react_1 = __importStar(require("react"));
|
|
43
|
-
const manager_api_1 = require("@storybook/manager-api");
|
|
44
|
-
const components_1 = require("@storybook/components");
|
|
45
|
-
const theming_1 = require("@storybook/theming");
|
|
46
|
-
const constants_1 = require("../constants");
|
|
47
|
-
const PanelContainer = theming_1.styled.div `
|
|
48
|
-
padding: 16px;
|
|
49
|
-
font-family: monospace;
|
|
50
|
-
font-size: 12px;
|
|
51
|
-
height: 100%;
|
|
52
|
-
overflow: auto;
|
|
53
|
-
background: #1a1a1a;
|
|
54
|
-
color: #e6e6e6;
|
|
55
|
-
`;
|
|
56
|
-
const Header = theming_1.styled.div `
|
|
57
|
-
display: flex;
|
|
58
|
-
justify-content: space-between;
|
|
59
|
-
align-items: center;
|
|
60
|
-
margin-bottom: 16px;
|
|
61
|
-
padding-bottom: 12px;
|
|
62
|
-
border-bottom: 1px solid #333;
|
|
63
|
-
`;
|
|
64
|
-
const Button = theming_1.styled.button `
|
|
65
|
-
background: #3b82f6;
|
|
66
|
-
color: white;
|
|
67
|
-
border: none;
|
|
68
|
-
border-radius: 4px;
|
|
69
|
-
padding: 6px 12px;
|
|
70
|
-
cursor: pointer;
|
|
71
|
-
font-size: 12px;
|
|
72
|
-
margin-left: 8px;
|
|
73
|
-
|
|
74
|
-
&:hover {
|
|
75
|
-
background: #2563eb;
|
|
76
|
-
}
|
|
77
|
-
`;
|
|
78
|
-
const SpanCard = theming_1.styled.div `
|
|
79
|
-
background: #242424;
|
|
80
|
-
border: 1px solid ${props => props.status === 'ERROR' ? '#ef4444' : '#333'};
|
|
81
|
-
border-radius: 6px;
|
|
82
|
-
padding: 12px;
|
|
83
|
-
margin-bottom: 12px;
|
|
84
|
-
`;
|
|
85
|
-
const SpanHeader = theming_1.styled.div `
|
|
86
|
-
display: flex;
|
|
87
|
-
justify-content: space-between;
|
|
88
|
-
align-items: flex-start;
|
|
89
|
-
margin-bottom: 8px;
|
|
90
|
-
`;
|
|
91
|
-
const SpanName = theming_1.styled.div `
|
|
92
|
-
font-weight: 600;
|
|
93
|
-
color: #3b82f6;
|
|
94
|
-
font-size: 13px;
|
|
95
|
-
`;
|
|
96
|
-
const SpanDuration = theming_1.styled.div `
|
|
97
|
-
color: #10b981;
|
|
98
|
-
font-size: 11px;
|
|
99
|
-
`;
|
|
100
|
-
const Attributes = theming_1.styled.div `
|
|
101
|
-
margin-top: 8px;
|
|
102
|
-
padding: 8px;
|
|
103
|
-
background: #1a1a1a;
|
|
104
|
-
border-radius: 4px;
|
|
105
|
-
font-size: 11px;
|
|
106
|
-
`;
|
|
107
|
-
const AttributeRow = theming_1.styled.div `
|
|
108
|
-
padding: 2px 0;
|
|
109
|
-
color: #a0a0a0;
|
|
110
|
-
|
|
111
|
-
span:first-child {
|
|
112
|
-
color: #8b5cf6;
|
|
113
|
-
}
|
|
114
|
-
`;
|
|
115
|
-
const EventList = theming_1.styled.div `
|
|
116
|
-
margin-top: 8px;
|
|
117
|
-
`;
|
|
118
|
-
const Event = theming_1.styled.div `
|
|
119
|
-
padding: 6px 8px;
|
|
120
|
-
background: #1a1a1a;
|
|
121
|
-
border-left: 2px solid #f59e0b;
|
|
122
|
-
margin-bottom: 4px;
|
|
123
|
-
font-size: 11px;
|
|
124
|
-
`;
|
|
125
|
-
const EventName = theming_1.styled.div `
|
|
126
|
-
color: #f59e0b;
|
|
127
|
-
font-weight: 600;
|
|
128
|
-
margin-bottom: 4px;
|
|
129
|
-
`;
|
|
130
|
-
const ViewToggle = theming_1.styled.div `
|
|
131
|
-
display: flex;
|
|
132
|
-
gap: 8px;
|
|
133
|
-
margin-bottom: 16px;
|
|
134
|
-
`;
|
|
135
|
-
const ToggleButton = theming_1.styled.button `
|
|
136
|
-
background: ${props => props.active ? '#3b82f6' : '#333'};
|
|
137
|
-
color: ${props => props.active ? 'white' : '#a0a0a0'};
|
|
138
|
-
border: none;
|
|
139
|
-
border-radius: 4px;
|
|
140
|
-
padding: 6px 16px;
|
|
141
|
-
cursor: pointer;
|
|
142
|
-
font-size: 12px;
|
|
143
|
-
|
|
144
|
-
&:hover {
|
|
145
|
-
background: ${props => props.active ? '#2563eb' : '#404040'};
|
|
146
|
-
}
|
|
147
|
-
`;
|
|
148
|
-
const CanvasPlaceholder = theming_1.styled.div `
|
|
149
|
-
padding: 40px;
|
|
150
|
-
text-align: center;
|
|
151
|
-
color: #666;
|
|
152
|
-
border: 2px dashed #333;
|
|
153
|
-
border-radius: 8px;
|
|
154
|
-
|
|
155
|
-
h3 {
|
|
156
|
-
margin: 0 0 8px 0;
|
|
157
|
-
color: #999;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
p {
|
|
161
|
-
margin: 0;
|
|
162
|
-
font-size: 12px;
|
|
163
|
-
}
|
|
164
|
-
`;
|
|
165
|
-
const TelemetryPanel = ({ active }) => {
|
|
166
|
-
const [spans, setSpans] = (0, react_1.useState)([]);
|
|
167
|
-
const [view, setView] = (0, react_1.useState)('timeline');
|
|
168
|
-
const emit = (0, manager_api_1.useChannel)({
|
|
169
|
-
[constants_1.EVENTS.TELEMETRY_UPDATE]: (newSpans) => {
|
|
170
|
-
console.log('[TelemetryPanel] Received update, spans:', newSpans.length, newSpans);
|
|
171
|
-
setSpans(newSpans);
|
|
172
|
-
},
|
|
173
|
-
});
|
|
174
|
-
console.log('[TelemetryPanel] Render, active:', active, 'spans:', spans.length);
|
|
175
|
-
const handleClear = () => {
|
|
176
|
-
emit(constants_1.EVENTS.CLEAR_TELEMETRY);
|
|
177
|
-
setSpans([]);
|
|
178
|
-
};
|
|
179
|
-
const handleExport = () => {
|
|
180
|
-
const json = JSON.stringify(spans, null, 2);
|
|
181
|
-
const blob = new Blob([json], { type: 'application/json' });
|
|
182
|
-
const url = URL.createObjectURL(blob);
|
|
183
|
-
const a = document.createElement('a');
|
|
184
|
-
a.href = url;
|
|
185
|
-
a.download = 'storybook-telemetry.json';
|
|
186
|
-
a.click();
|
|
187
|
-
URL.revokeObjectURL(url);
|
|
188
|
-
};
|
|
189
|
-
if (!active) {
|
|
190
|
-
return null;
|
|
191
|
-
}
|
|
192
|
-
return (react_1.default.createElement(components_1.AddonPanel, { active: active },
|
|
193
|
-
react_1.default.createElement(PanelContainer, null,
|
|
194
|
-
react_1.default.createElement(Header, null,
|
|
195
|
-
react_1.default.createElement("div", null,
|
|
196
|
-
react_1.default.createElement("strong", null, "OTEL Telemetry"),
|
|
197
|
-
react_1.default.createElement("div", { style: { fontSize: '11px', color: '#666', marginTop: '4px' } },
|
|
198
|
-
spans.length,
|
|
199
|
-
" span",
|
|
200
|
-
spans.length !== 1 ? 's' : '',
|
|
201
|
-
" collected")),
|
|
202
|
-
react_1.default.createElement("div", null,
|
|
203
|
-
react_1.default.createElement(Button, { onClick: handleClear }, "Clear"),
|
|
204
|
-
react_1.default.createElement(Button, { onClick: handleExport }, "Export JSON"))),
|
|
205
|
-
react_1.default.createElement(ViewToggle, null,
|
|
206
|
-
react_1.default.createElement(ToggleButton, { active: view === 'timeline', onClick: () => setView('timeline') }, "Timeline"),
|
|
207
|
-
react_1.default.createElement(ToggleButton, { active: view === 'canvas', onClick: () => setView('canvas') }, "Canvas")),
|
|
208
|
-
view === 'timeline' ? (react_1.default.createElement(react_1.default.Fragment, null, spans.length === 0 ? (react_1.default.createElement("div", { style: { textAlign: 'center', padding: '40px', color: '#666' } }, "No telemetry data yet. Interact with the story to capture spans.")) : (spans.map(span => (react_1.default.createElement(SpanCard, { key: span.id, status: span.status },
|
|
209
|
-
react_1.default.createElement(SpanHeader, null,
|
|
210
|
-
react_1.default.createElement(SpanName, null, span.name),
|
|
211
|
-
span.duration && (react_1.default.createElement(SpanDuration, null,
|
|
212
|
-
span.duration,
|
|
213
|
-
"ms"))),
|
|
214
|
-
Object.keys(span.attributes).length > 0 && (react_1.default.createElement(Attributes, null, Object.entries(span.attributes).map(([key, value]) => (react_1.default.createElement(AttributeRow, { key: key },
|
|
215
|
-
react_1.default.createElement("span", null,
|
|
216
|
-
key,
|
|
217
|
-
":"),
|
|
218
|
-
" ",
|
|
219
|
-
String(value)))))),
|
|
220
|
-
span.events.length > 0 && (react_1.default.createElement(EventList, null, span.events.map((event, idx) => (react_1.default.createElement(Event, { key: idx },
|
|
221
|
-
react_1.default.createElement(EventName, null, event.name),
|
|
222
|
-
Object.entries(event.attributes).map(([key, value]) => (react_1.default.createElement(AttributeRow, { key: key },
|
|
223
|
-
react_1.default.createElement("span", null,
|
|
224
|
-
key,
|
|
225
|
-
":"),
|
|
226
|
-
" ",
|
|
227
|
-
String(value))))))))),
|
|
228
|
-
span.errorMessage && (react_1.default.createElement("div", { style: { marginTop: '8px', color: '#ef4444', fontSize: '11px' } },
|
|
229
|
-
"Error: ",
|
|
230
|
-
span.errorMessage)))))))) : (react_1.default.createElement(CanvasPlaceholder, null,
|
|
231
|
-
react_1.default.createElement("h3", null, "Canvas Visualization"),
|
|
232
|
-
react_1.default.createElement("p", null, "Canvas view will visualize the telemetry flow using your GraphRenderer."),
|
|
233
|
-
react_1.default.createElement("p", { style: { marginTop: '8px', fontSize: '11px' } }, "To implement: Convert spans to canvas format and render with GraphRenderer"))))));
|
|
234
|
-
};
|
|
235
|
-
exports.TelemetryPanel = TelemetryPanel;
|