@principal-ai/principal-view-react 0.14.14 → 0.14.16
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/components/SequenceDiagramRenderer.d.ts +61 -0
- package/dist/components/SequenceDiagramRenderer.d.ts.map +1 -0
- package/dist/components/SequenceDiagramRenderer.js +184 -0
- package/dist/components/SequenceDiagramRenderer.js.map +1 -0
- package/dist/components/dashboard/DashboardRenderer.d.ts +9 -0
- package/dist/components/dashboard/DashboardRenderer.d.ts.map +1 -0
- package/dist/components/dashboard/DashboardRenderer.js +179 -0
- package/dist/components/dashboard/DashboardRenderer.js.map +1 -0
- package/dist/components/dashboard/MetricPanel.d.ts +9 -0
- package/dist/components/dashboard/MetricPanel.d.ts.map +1 -0
- package/dist/components/dashboard/MetricPanel.js +103 -0
- package/dist/components/dashboard/MetricPanel.js.map +1 -0
- package/dist/components/dashboard/MockDataProvider.d.ts +30 -0
- package/dist/components/dashboard/MockDataProvider.d.ts.map +1 -0
- package/dist/components/dashboard/MockDataProvider.js +270 -0
- package/dist/components/dashboard/MockDataProvider.js.map +1 -0
- package/dist/components/dashboard/components/BarChart.d.ts +9 -0
- package/dist/components/dashboard/components/BarChart.d.ts.map +1 -0
- package/dist/components/dashboard/components/BarChart.js +167 -0
- package/dist/components/dashboard/components/BarChart.js.map +1 -0
- package/dist/components/dashboard/components/LineChart.d.ts +9 -0
- package/dist/components/dashboard/components/LineChart.d.ts.map +1 -0
- package/dist/components/dashboard/components/LineChart.js +141 -0
- package/dist/components/dashboard/components/LineChart.js.map +1 -0
- package/dist/components/dashboard/components/MetricCard.d.ts +8 -0
- package/dist/components/dashboard/components/MetricCard.d.ts.map +1 -0
- package/dist/components/dashboard/components/MetricCard.js +163 -0
- package/dist/components/dashboard/components/MetricCard.js.map +1 -0
- package/dist/components/dashboard/components/SourceLink.d.ts +8 -0
- package/dist/components/dashboard/components/SourceLink.d.ts.map +1 -0
- package/dist/components/dashboard/components/SourceLink.js +39 -0
- package/dist/components/dashboard/components/SourceLink.js.map +1 -0
- package/dist/components/dashboard/components/TimeRangeSelector.d.ts +8 -0
- package/dist/components/dashboard/components/TimeRangeSelector.d.ts.map +1 -0
- package/dist/components/dashboard/components/TimeRangeSelector.js +167 -0
- package/dist/components/dashboard/components/TimeRangeSelector.js.map +1 -0
- package/dist/components/dashboard/components/index.d.ts +6 -0
- package/dist/components/dashboard/components/index.d.ts.map +1 -0
- package/dist/components/dashboard/components/index.js +6 -0
- package/dist/components/dashboard/components/index.js.map +1 -0
- package/dist/components/dashboard/index.d.ts +6 -0
- package/dist/components/dashboard/index.d.ts.map +1 -0
- package/dist/components/dashboard/index.js +8 -0
- package/dist/components/dashboard/index.js.map +1 -0
- package/dist/components/dashboard/types.d.ts +74 -0
- package/dist/components/dashboard/types.d.ts.map +1 -0
- package/dist/components/dashboard/types.js +8 -0
- package/dist/components/dashboard/types.js.map +1 -0
- package/dist/hooks/useSequenceLayout.d.ts +148 -0
- package/dist/hooks/useSequenceLayout.d.ts.map +1 -0
- package/dist/hooks/useSequenceLayout.js +225 -0
- package/dist/hooks/useSequenceLayout.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/components/SequenceDiagramRenderer.tsx +459 -0
- package/src/components/dashboard/DashboardRenderer.tsx +317 -0
- package/src/components/dashboard/MetricPanel.tsx +254 -0
- package/src/components/dashboard/MockDataProvider.ts +330 -0
- package/src/components/dashboard/components/BarChart.tsx +299 -0
- package/src/components/dashboard/components/LineChart.tsx +279 -0
- package/src/components/dashboard/components/MetricCard.tsx +270 -0
- package/src/components/dashboard/components/SourceLink.tsx +63 -0
- package/src/components/dashboard/components/TimeRangeSelector.tsx +280 -0
- package/src/components/dashboard/components/index.ts +5 -0
- package/src/components/dashboard/index.ts +47 -0
- package/src/components/dashboard/types.ts +126 -0
- package/src/hooks/useSequenceLayout.ts +413 -0
- package/src/index.ts +62 -0
- package/src/stories/SequenceDiagram.stories.tsx +306 -0
- package/src/stories/dashboard/DashboardRenderer.stories.tsx +263 -0
- package/src/stories/dashboard/sample-dashboards/activity-feed-analytics.dashboard.json +300 -0
- package/src/stories/data/graph-converter-test-execution.json +50 -50
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
import { SequenceDiagramRenderer } from '../components/SequenceDiagramRenderer';
|
|
4
|
+
import type { SequenceEvent, SequenceEdge } from '../hooks/useSequenceLayout';
|
|
5
|
+
import { ThemeProvider, defaultEditorTheme } from '@principal-ade/industry-theme';
|
|
6
|
+
|
|
7
|
+
const meta = {
|
|
8
|
+
title: 'Components/SequenceDiagram',
|
|
9
|
+
component: SequenceDiagramRenderer,
|
|
10
|
+
parameters: {
|
|
11
|
+
layout: 'fullscreen',
|
|
12
|
+
},
|
|
13
|
+
tags: ['autodocs'],
|
|
14
|
+
decorators: [
|
|
15
|
+
(Story) => (
|
|
16
|
+
<ThemeProvider theme={defaultEditorTheme}>
|
|
17
|
+
<div style={{ padding: 20, height: '100vh', boxSizing: 'border-box' }}>
|
|
18
|
+
<Story />
|
|
19
|
+
</div>
|
|
20
|
+
</ThemeProvider>
|
|
21
|
+
),
|
|
22
|
+
],
|
|
23
|
+
} satisfies Meta<typeof SequenceDiagramRenderer>;
|
|
24
|
+
|
|
25
|
+
export default meta;
|
|
26
|
+
type Story = StoryObj<typeof meta>;
|
|
27
|
+
|
|
28
|
+
// ============================================================================
|
|
29
|
+
// Sample Data
|
|
30
|
+
// ============================================================================
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Simple authentication flow across two namespaces
|
|
34
|
+
*/
|
|
35
|
+
const simpleAuthFlow: { events: SequenceEvent[]; edges: SequenceEdge[] } = {
|
|
36
|
+
events: [
|
|
37
|
+
{ id: '1', name: 'auth.validation.started', label: 'Validation Started' },
|
|
38
|
+
{ id: '2', name: 'database.query.findUser', label: 'Find User' },
|
|
39
|
+
{ id: '3', name: 'auth.validation.completed', label: 'Validation Completed' },
|
|
40
|
+
{ id: '4', name: 'auth.token.generated', label: 'Token Generated' },
|
|
41
|
+
],
|
|
42
|
+
edges: [
|
|
43
|
+
{ id: 'e1', fromEvent: '1', toEvent: '2' },
|
|
44
|
+
{ id: 'e2', fromEvent: '2', toEvent: '3' },
|
|
45
|
+
{ id: 'e3', fromEvent: '3', toEvent: '4' },
|
|
46
|
+
],
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* More complex flow with multiple actors
|
|
51
|
+
*/
|
|
52
|
+
const complexOrderFlow: { events: SequenceEvent[]; edges: SequenceEdge[] } = {
|
|
53
|
+
events: [
|
|
54
|
+
{ id: '1', name: 'api.request.received', label: 'Request Received' },
|
|
55
|
+
{ id: '2', name: 'auth.session.validate', label: 'Validate Session' },
|
|
56
|
+
{ id: '3', name: 'order.validation.started', label: 'Validate Order' },
|
|
57
|
+
{ id: '4', name: 'inventory.check.availability', label: 'Check Stock' },
|
|
58
|
+
{ id: '5', name: 'order.validation.completed', label: 'Order Valid' },
|
|
59
|
+
{ id: '6', name: 'payment.charge.initiated', label: 'Initiate Charge' },
|
|
60
|
+
{ id: '7', name: 'payment.charge.completed', label: 'Charge Complete' },
|
|
61
|
+
{ id: '8', name: 'order.fulfillment.started', label: 'Start Fulfillment' },
|
|
62
|
+
{ id: '9', name: 'inventory.reserve.items', label: 'Reserve Items' },
|
|
63
|
+
{ id: '10', name: 'notification.email.sent', label: 'Confirmation Email' },
|
|
64
|
+
{ id: '11', name: 'api.response.sent', label: 'Response Sent' },
|
|
65
|
+
],
|
|
66
|
+
edges: [
|
|
67
|
+
{ id: 'e1', fromEvent: '1', toEvent: '2' },
|
|
68
|
+
{ id: 'e2', fromEvent: '2', toEvent: '3' },
|
|
69
|
+
{ id: 'e3', fromEvent: '3', toEvent: '4' },
|
|
70
|
+
{ id: 'e4', fromEvent: '4', toEvent: '5' },
|
|
71
|
+
{ id: 'e5', fromEvent: '5', toEvent: '6' },
|
|
72
|
+
{ id: 'e6', fromEvent: '6', toEvent: '7' },
|
|
73
|
+
{ id: 'e7', fromEvent: '7', toEvent: '8' },
|
|
74
|
+
{ id: 'e8', fromEvent: '8', toEvent: '9' },
|
|
75
|
+
{ id: 'e9', fromEvent: '9', toEvent: '10' },
|
|
76
|
+
{ id: 'e10', fromEvent: '10', toEvent: '11' },
|
|
77
|
+
],
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Flow with hierarchical namespaces (sub-namespaces)
|
|
82
|
+
*/
|
|
83
|
+
const hierarchicalFlow: { events: SequenceEvent[]; edges: SequenceEdge[] } = {
|
|
84
|
+
events: [
|
|
85
|
+
{ id: '1', name: 'auth.login.started', label: 'Login Started' },
|
|
86
|
+
{ id: '2', name: 'auth.login.validation.credentials', label: 'Check Credentials' },
|
|
87
|
+
{ id: '3', name: 'auth.login.validation.mfa', label: 'Check MFA' },
|
|
88
|
+
{ id: '4', name: 'auth.login.session.create', label: 'Create Session' },
|
|
89
|
+
{ id: '5', name: 'auth.login.completed', label: 'Login Completed' },
|
|
90
|
+
],
|
|
91
|
+
edges: [
|
|
92
|
+
{ id: 'e1', fromEvent: '1', toEvent: '2' },
|
|
93
|
+
{ id: 'e2', fromEvent: '2', toEvent: '3' },
|
|
94
|
+
{ id: 'e3', fromEvent: '3', toEvent: '4' },
|
|
95
|
+
{ id: 'e4', fromEvent: '4', toEvent: '5' },
|
|
96
|
+
],
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Flow with same-namespace sequential events
|
|
101
|
+
*/
|
|
102
|
+
const sameNamespaceFlow: { events: SequenceEvent[]; edges: SequenceEdge[] } = {
|
|
103
|
+
events: [
|
|
104
|
+
{ id: '1', name: 'processor.step1', label: 'Step 1' },
|
|
105
|
+
{ id: '2', name: 'processor.step2', label: 'Step 2' },
|
|
106
|
+
{ id: '3', name: 'processor.step3', label: 'Step 3' },
|
|
107
|
+
{ id: '4', name: 'external.callback', label: 'External Callback' },
|
|
108
|
+
{ id: '5', name: 'processor.step4', label: 'Step 4' },
|
|
109
|
+
],
|
|
110
|
+
edges: [
|
|
111
|
+
{ id: 'e1', fromEvent: '1', toEvent: '2' },
|
|
112
|
+
{ id: 'e2', fromEvent: '2', toEvent: '3' },
|
|
113
|
+
{ id: 'e3', fromEvent: '3', toEvent: '4' },
|
|
114
|
+
{ id: 'e4', fromEvent: '4', toEvent: '5' },
|
|
115
|
+
],
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// ============================================================================
|
|
119
|
+
// Stories
|
|
120
|
+
// ============================================================================
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Basic two-namespace flow showing authentication
|
|
124
|
+
*/
|
|
125
|
+
export const SimpleFlow: Story = {
|
|
126
|
+
args: {
|
|
127
|
+
events: simpleAuthFlow.events,
|
|
128
|
+
edges: simpleAuthFlow.edges,
|
|
129
|
+
height: 500,
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Complex multi-actor e-commerce order flow
|
|
135
|
+
*/
|
|
136
|
+
export const ComplexFlow: Story = {
|
|
137
|
+
args: {
|
|
138
|
+
events: complexOrderFlow.events,
|
|
139
|
+
edges: complexOrderFlow.edges,
|
|
140
|
+
height: 700,
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Flow with hierarchical namespaces to test sub-namespace handling
|
|
146
|
+
*/
|
|
147
|
+
export const HierarchicalNamespaces: Story = {
|
|
148
|
+
args: {
|
|
149
|
+
events: hierarchicalFlow.events,
|
|
150
|
+
edges: hierarchicalFlow.edges,
|
|
151
|
+
height: 500,
|
|
152
|
+
layoutOptions: {
|
|
153
|
+
namespaceStrategy: 'all-but-last',
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Same story but with first-segment namespace strategy
|
|
160
|
+
*/
|
|
161
|
+
export const HierarchicalCollapsedToFirst: Story = {
|
|
162
|
+
args: {
|
|
163
|
+
events: hierarchicalFlow.events,
|
|
164
|
+
edges: hierarchicalFlow.edges,
|
|
165
|
+
height: 500,
|
|
166
|
+
layoutOptions: {
|
|
167
|
+
namespaceStrategy: 'first',
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Flow testing same-namespace edge rendering
|
|
174
|
+
*/
|
|
175
|
+
export const SameNamespaceEdges: Story = {
|
|
176
|
+
args: {
|
|
177
|
+
events: sameNamespaceFlow.events,
|
|
178
|
+
edges: sameNamespaceFlow.edges,
|
|
179
|
+
height: 500,
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Interactive example with collapse toggle
|
|
185
|
+
*/
|
|
186
|
+
export const WithCollapseToggle: Story = {
|
|
187
|
+
render: () => {
|
|
188
|
+
const [collapsed, setCollapsed] = useState<string[]>([]);
|
|
189
|
+
|
|
190
|
+
const handleToggle = (namespace: string) => {
|
|
191
|
+
setCollapsed((prev) =>
|
|
192
|
+
prev.includes(namespace)
|
|
193
|
+
? prev.filter((n) => n !== namespace)
|
|
194
|
+
: [...prev, namespace]
|
|
195
|
+
);
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
return (
|
|
199
|
+
<div>
|
|
200
|
+
<div style={{ marginBottom: 16 }}>
|
|
201
|
+
<strong>Collapsed namespaces:</strong>{' '}
|
|
202
|
+
{collapsed.length ? collapsed.join(', ') : 'none'}
|
|
203
|
+
<br />
|
|
204
|
+
<small>Click on lane headers with children to toggle collapse</small>
|
|
205
|
+
</div>
|
|
206
|
+
<SequenceDiagramRenderer
|
|
207
|
+
events={hierarchicalFlow.events}
|
|
208
|
+
edges={hierarchicalFlow.edges}
|
|
209
|
+
height={500}
|
|
210
|
+
layoutOptions={{
|
|
211
|
+
collapsedNamespaces: collapsed,
|
|
212
|
+
}}
|
|
213
|
+
onToggleCollapse={handleToggle}
|
|
214
|
+
/>
|
|
215
|
+
</div>
|
|
216
|
+
);
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Custom layout options
|
|
222
|
+
*/
|
|
223
|
+
export const CustomLayout: Story = {
|
|
224
|
+
args: {
|
|
225
|
+
events: simpleAuthFlow.events,
|
|
226
|
+
edges: simpleAuthFlow.edges,
|
|
227
|
+
height: 500,
|
|
228
|
+
layoutOptions: {
|
|
229
|
+
laneWidth: 250,
|
|
230
|
+
laneGap: 80,
|
|
231
|
+
eventSpacing: 100,
|
|
232
|
+
nodeWidth: 220,
|
|
233
|
+
nodeHeight: 60,
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Arrow-centric mode: minimal markers with labels on arrows
|
|
240
|
+
* This is the traditional UML sequence diagram style
|
|
241
|
+
*/
|
|
242
|
+
export const ArrowCentric: Story = {
|
|
243
|
+
args: {
|
|
244
|
+
events: simpleAuthFlow.events,
|
|
245
|
+
edges: simpleAuthFlow.edges,
|
|
246
|
+
height: 500,
|
|
247
|
+
layoutOptions: {
|
|
248
|
+
arrowCentric: true,
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Arrow-centric with complex multi-actor flow
|
|
255
|
+
*/
|
|
256
|
+
export const ArrowCentricComplex: Story = {
|
|
257
|
+
args: {
|
|
258
|
+
events: complexOrderFlow.events,
|
|
259
|
+
edges: complexOrderFlow.edges,
|
|
260
|
+
height: 700,
|
|
261
|
+
layoutOptions: {
|
|
262
|
+
arrowCentric: true,
|
|
263
|
+
eventSpacing: 60,
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Compact layout for smaller diagrams
|
|
270
|
+
*/
|
|
271
|
+
export const CompactLayout: Story = {
|
|
272
|
+
args: {
|
|
273
|
+
events: simpleAuthFlow.events,
|
|
274
|
+
edges: simpleAuthFlow.edges,
|
|
275
|
+
height: 400,
|
|
276
|
+
layoutOptions: {
|
|
277
|
+
laneWidth: 150,
|
|
278
|
+
laneGap: 30,
|
|
279
|
+
eventSpacing: 60,
|
|
280
|
+
nodeWidth: 130,
|
|
281
|
+
nodeHeight: 40,
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Empty state
|
|
288
|
+
*/
|
|
289
|
+
export const EmptyDiagram: Story = {
|
|
290
|
+
args: {
|
|
291
|
+
events: [],
|
|
292
|
+
edges: [],
|
|
293
|
+
height: 300,
|
|
294
|
+
},
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Single event (edge case)
|
|
299
|
+
*/
|
|
300
|
+
export const SingleEvent: Story = {
|
|
301
|
+
args: {
|
|
302
|
+
events: [{ id: '1', name: 'system.startup', label: 'System Startup' }],
|
|
303
|
+
edges: [],
|
|
304
|
+
height: 300,
|
|
305
|
+
},
|
|
306
|
+
};
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DashboardRenderer Stories
|
|
3
|
+
*
|
|
4
|
+
* Storybook stories for testing and iterating on dashboard rendering.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
8
|
+
import { ThemeProvider, defaultEditorTheme } from '@principal-ade/industry-theme';
|
|
9
|
+
import { DashboardRenderer } from '../../components/dashboard';
|
|
10
|
+
import activityFeedDashboard from './sample-dashboards/activity-feed-analytics.dashboard.json';
|
|
11
|
+
import type { DashboardDefinition } from '../../components/dashboard';
|
|
12
|
+
|
|
13
|
+
const meta: Meta<typeof DashboardRenderer> = {
|
|
14
|
+
title: 'Dashboard/DashboardRenderer',
|
|
15
|
+
component: DashboardRenderer,
|
|
16
|
+
parameters: {
|
|
17
|
+
layout: 'fullscreen',
|
|
18
|
+
},
|
|
19
|
+
decorators: [
|
|
20
|
+
(Story) => (
|
|
21
|
+
<ThemeProvider theme={defaultEditorTheme}>
|
|
22
|
+
<div style={{ minHeight: '100vh' }}>
|
|
23
|
+
<Story />
|
|
24
|
+
</div>
|
|
25
|
+
</ThemeProvider>
|
|
26
|
+
),
|
|
27
|
+
],
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export default meta;
|
|
31
|
+
type Story = StoryObj<typeof DashboardRenderer>;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Activity Feed Analytics Dashboard
|
|
35
|
+
*
|
|
36
|
+
* Full dashboard example based on the web-ade activity feed use case.
|
|
37
|
+
* Shows mobile vs desktop view percentages, traffic trends, and engagement metrics.
|
|
38
|
+
*/
|
|
39
|
+
export const ActivityFeedAnalytics: Story = {
|
|
40
|
+
args: {
|
|
41
|
+
dashboard: activityFeedDashboard as DashboardDefinition,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* With Metric Click Handler
|
|
47
|
+
*
|
|
48
|
+
* Demonstrates handling metric clicks - useful for drill-down navigation.
|
|
49
|
+
*/
|
|
50
|
+
export const WithClickHandlers: Story = {
|
|
51
|
+
args: {
|
|
52
|
+
dashboard: activityFeedDashboard as DashboardDefinition,
|
|
53
|
+
onMetricClick: (metricId) => {
|
|
54
|
+
alert(`Clicked metric: ${metricId}`);
|
|
55
|
+
},
|
|
56
|
+
onSourceClick: (source) => {
|
|
57
|
+
alert(`Navigate to: ${source.storyboard}/${source.workflow}`);
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Minimal Dashboard
|
|
64
|
+
*
|
|
65
|
+
* A simple dashboard with just a few metrics.
|
|
66
|
+
*/
|
|
67
|
+
export const MinimalDashboard: Story = {
|
|
68
|
+
args: {
|
|
69
|
+
dashboard: {
|
|
70
|
+
id: 'minimal',
|
|
71
|
+
name: 'Minimal Dashboard',
|
|
72
|
+
description: 'A simple dashboard with basic metrics',
|
|
73
|
+
metrics: [
|
|
74
|
+
{
|
|
75
|
+
id: 'total-requests',
|
|
76
|
+
name: 'Total Requests',
|
|
77
|
+
type: 'counter',
|
|
78
|
+
unit: 'requests',
|
|
79
|
+
sources: [{ storyboard: 'api', workflow: 'request-handler' }],
|
|
80
|
+
query: { derivation: 'count', window: '1h' },
|
|
81
|
+
_mockData: { current: 145892, previous: 132456, trend: 'up' },
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
id: 'error-rate',
|
|
85
|
+
name: 'Error Rate',
|
|
86
|
+
type: 'gauge',
|
|
87
|
+
unit: '%',
|
|
88
|
+
sources: [{ storyboard: 'api', workflow: 'request-handler' }],
|
|
89
|
+
query: { derivation: 'error_rate', window: '1h' },
|
|
90
|
+
thresholds: { warning: 1.0, critical: 5.0 },
|
|
91
|
+
_mockData: { current: 0.3, previous: 0.5, trend: 'down' },
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
id: 'p99-latency',
|
|
95
|
+
name: 'P99 Latency',
|
|
96
|
+
type: 'histogram',
|
|
97
|
+
unit: 'ms',
|
|
98
|
+
sources: [{ storyboard: 'api', workflow: 'request-handler' }],
|
|
99
|
+
query: { derivation: 'p99' },
|
|
100
|
+
_mockData: { current: 245, previous: 312, trend: 'down' },
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
layout: {
|
|
104
|
+
rows: [
|
|
105
|
+
{
|
|
106
|
+
title: 'Key Metrics',
|
|
107
|
+
panels: [
|
|
108
|
+
{ id: 'total-requests', span: 4 },
|
|
109
|
+
{ id: 'error-rate', span: 4 },
|
|
110
|
+
{ id: 'p99-latency', span: 4 },
|
|
111
|
+
],
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
},
|
|
115
|
+
} as DashboardDefinition,
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Time Series Focus
|
|
121
|
+
*
|
|
122
|
+
* Dashboard focused on time series visualizations.
|
|
123
|
+
*/
|
|
124
|
+
export const TimeSeriesFocus: Story = {
|
|
125
|
+
args: {
|
|
126
|
+
dashboard: {
|
|
127
|
+
id: 'time-series',
|
|
128
|
+
name: 'Time Series Dashboard',
|
|
129
|
+
description: 'Focus on time-based trends',
|
|
130
|
+
metrics: [
|
|
131
|
+
{
|
|
132
|
+
id: 'hourly-requests',
|
|
133
|
+
name: 'Hourly Requests',
|
|
134
|
+
type: 'counter',
|
|
135
|
+
unit: 'requests',
|
|
136
|
+
sources: [{ storyboard: 'api', workflow: 'handler' }],
|
|
137
|
+
query: { derivation: 'count', timeGroup: 'hour' },
|
|
138
|
+
display: { component: 'LineChart', size: 'large' },
|
|
139
|
+
_mockData: {
|
|
140
|
+
series: [
|
|
141
|
+
{ date: '00:00', value: 1200 },
|
|
142
|
+
{ date: '04:00', value: 800 },
|
|
143
|
+
{ date: '08:00', value: 2400 },
|
|
144
|
+
{ date: '12:00', value: 3200 },
|
|
145
|
+
{ date: '16:00', value: 2800 },
|
|
146
|
+
{ date: '20:00', value: 1800 },
|
|
147
|
+
],
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
id: 'requests-by-status',
|
|
152
|
+
name: 'Requests by Status',
|
|
153
|
+
type: 'counter',
|
|
154
|
+
unit: 'requests',
|
|
155
|
+
sources: [{ storyboard: 'api', workflow: 'handler' }],
|
|
156
|
+
query: { derivation: 'count', groupBy: ['status'], timeGroup: 'hour' },
|
|
157
|
+
display: { component: 'StackedBarChart', size: 'large' },
|
|
158
|
+
_mockData: {
|
|
159
|
+
series: [
|
|
160
|
+
{ date: '00:00', success: 1150, error: 50 },
|
|
161
|
+
{ date: '04:00', success: 780, error: 20 },
|
|
162
|
+
{ date: '08:00', success: 2300, error: 100 },
|
|
163
|
+
{ date: '12:00', success: 3050, error: 150 },
|
|
164
|
+
{ date: '16:00', success: 2650, error: 150 },
|
|
165
|
+
{ date: '20:00', success: 1720, error: 80 },
|
|
166
|
+
],
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
],
|
|
170
|
+
layout: {
|
|
171
|
+
rows: [
|
|
172
|
+
{
|
|
173
|
+
title: 'Traffic Over Time',
|
|
174
|
+
panels: [{ id: 'hourly-requests', span: 12 }],
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
title: 'Status Breakdown',
|
|
178
|
+
panels: [{ id: 'requests-by-status', span: 12 }],
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
},
|
|
182
|
+
} as DashboardDefinition,
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* With Thresholds
|
|
188
|
+
*
|
|
189
|
+
* Shows metrics with warning and critical thresholds.
|
|
190
|
+
*/
|
|
191
|
+
export const WithThresholds: Story = {
|
|
192
|
+
args: {
|
|
193
|
+
dashboard: {
|
|
194
|
+
id: 'thresholds',
|
|
195
|
+
name: 'SLO Dashboard',
|
|
196
|
+
description: 'Service level objectives with thresholds',
|
|
197
|
+
metrics: [
|
|
198
|
+
{
|
|
199
|
+
id: 'availability',
|
|
200
|
+
name: 'Availability',
|
|
201
|
+
type: 'gauge',
|
|
202
|
+
unit: '%',
|
|
203
|
+
sources: [{ storyboard: 'infra', workflow: 'health-check' }],
|
|
204
|
+
query: { derivation: 'success_rate' },
|
|
205
|
+
thresholds: { warning: 99.9, critical: 99.0 },
|
|
206
|
+
_mockData: { current: 99.95, trend: 'flat' },
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
id: 'error-budget',
|
|
210
|
+
name: 'Error Budget Remaining',
|
|
211
|
+
type: 'gauge',
|
|
212
|
+
unit: '%',
|
|
213
|
+
sources: [{ storyboard: 'infra', workflow: 'slo-tracker' }],
|
|
214
|
+
query: { derivation: 'percentage' },
|
|
215
|
+
thresholds: { warning: 25, critical: 10 },
|
|
216
|
+
_mockData: { current: 67.3, previous: 72.1, trend: 'down' },
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
id: 'latency-slo',
|
|
220
|
+
name: 'Latency SLO',
|
|
221
|
+
type: 'gauge',
|
|
222
|
+
unit: '%',
|
|
223
|
+
description: 'Percentage of requests under 200ms',
|
|
224
|
+
sources: [{ storyboard: 'api', workflow: 'handler' }],
|
|
225
|
+
query: { derivation: 'percentage', filter: 'duration < 200' },
|
|
226
|
+
thresholds: { warning: 95, critical: 90 },
|
|
227
|
+
_mockData: { current: 97.2, previous: 96.8, trend: 'up' },
|
|
228
|
+
},
|
|
229
|
+
],
|
|
230
|
+
layout: {
|
|
231
|
+
rows: [
|
|
232
|
+
{
|
|
233
|
+
title: 'Service Level Objectives',
|
|
234
|
+
panels: [
|
|
235
|
+
{ id: 'availability', span: 4 },
|
|
236
|
+
{ id: 'error-budget', span: 4 },
|
|
237
|
+
{ id: 'latency-slo', span: 4 },
|
|
238
|
+
],
|
|
239
|
+
},
|
|
240
|
+
],
|
|
241
|
+
},
|
|
242
|
+
} as DashboardDefinition,
|
|
243
|
+
},
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Empty Dashboard
|
|
248
|
+
*
|
|
249
|
+
* Edge case: dashboard with no metrics.
|
|
250
|
+
*/
|
|
251
|
+
export const EmptyDashboard: Story = {
|
|
252
|
+
args: {
|
|
253
|
+
dashboard: {
|
|
254
|
+
id: 'empty',
|
|
255
|
+
name: 'Empty Dashboard',
|
|
256
|
+
description: 'This dashboard has no metrics configured yet',
|
|
257
|
+
metrics: [],
|
|
258
|
+
layout: {
|
|
259
|
+
rows: [],
|
|
260
|
+
},
|
|
261
|
+
} as DashboardDefinition,
|
|
262
|
+
},
|
|
263
|
+
};
|