react-dashstream 0.2.0 → 0.3.0
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/README.md +1245 -1193
- package/dashstream-skill.md +1148 -1062
- package/dist/components/DatacenterView/DatacenterView.d.ts +37 -0
- package/dist/components/DatacenterView/DatacenterView.d.ts.map +1 -0
- package/dist/components/DatacenterView/index.d.ts +3 -0
- package/dist/components/DatacenterView/index.d.ts.map +1 -0
- package/dist/components/DatacenterView/types.d.ts +55 -0
- package/dist/components/DatacenterView/types.d.ts.map +1 -0
- package/dist/components/EventView/EventAlertsContext.d.ts +2 -0
- package/dist/components/EventView/EventAlertsContext.d.ts.map +1 -1
- package/dist/components/EventView/EventView.d.ts.map +1 -1
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/data/DataProvider.d.ts +7 -0
- package/dist/data/DataProvider.d.ts.map +1 -1
- package/dist/data/index.d.ts +2 -2
- package/dist/data/index.d.ts.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2548 -1698
- package/package.json +1 -1
package/dashstream-skill.md
CHANGED
|
@@ -1,1062 +1,1148 @@
|
|
|
1
|
-
# React DashStream — AI Coding Assistant Skill
|
|
2
|
-
|
|
3
|
-
> **Package**: `react-dashstream` (npm)
|
|
4
|
-
> **Version**: 0.2.0
|
|
5
|
-
> **Peer deps**: `react` ^18 || ^19, `react-dom` ^18 || ^19
|
|
6
|
-
> **License**: MIT
|
|
7
|
-
|
|
8
|
-
Use this skill when the user is working with the `react-dashstream` package — a holographic 3D infrastructure monitoring dashboard built entirely with CSS 3D transforms (no WebGL, no canvas).
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## What this package does
|
|
13
|
-
|
|
14
|
-
React DashStream renders a rotating 3D carousel of infrastructure services. Each service can be clicked to expand into a multi-tiered topology showing servers, databases, dispatchers, message servers, and user nodes connected by animated SVG lines. Components can be drilled into to reveal internal sub-components with sparkline graphs and gauges.
|
|
15
|
-
|
|
16
|
-
Two modes:
|
|
17
|
-
|
|
18
|
-
1. **Static mode** — pass props directly for demo or snapshot views.
|
|
19
|
-
2. **Live data mode** — poll an HTTP endpoint with PromQL queries and auto-inject resolved values as component props.
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
## Installation and CSS
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
npm install react-dashstream
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
```tsx
|
|
30
|
-
import "react-dashstream/dist/index.css";
|
|
31
|
-
import { AIOPsDashboard, Service, ServerNode, DatabaseNode } from "react-dashstream";
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
**Always import the CSS file** — without it, no styles render.
|
|
35
|
-
|
|
36
|
-
---
|
|
37
|
-
|
|
38
|
-
## Light / dark theme
|
|
39
|
-
|
|
40
|
-
The dashboard supports **`"light"`** and **`"dark"`** modes.
|
|
41
|
-
|
|
42
|
-
- **`AIOPsDashboard`** defaults to **light** and exposes a header toggle. Use **`backgroundImage`** (dark) and **`lightBackgroundImage`** (light when set).
|
|
43
|
-
- **Controlled mode:** pass **`theme`** and **`onThemeChange`** (`DashboardTheme`) so parent state owns the mode (e.g. sync app chrome + `EventView`).
|
|
44
|
-
- **`ThemeProvider`** (export) + **`useTheme()`** — wrap subtrees so **`EventView`**, **`CredentialsModal`**, **`ServiceDialog`**, and **`ComponentDialog`** match the dashboard. Without a provider, `useTheme()` defaults to **`"dark"`**; prefer wrapping when using `EventView` or the lock screen next to a light dashboard.
|
|
45
|
-
- **`EventView`** accepts optional **`theme`** to override context.
|
|
46
|
-
|
|
47
|
-
When generating multi-view apps (3D + Event Console + credentials), wrap the root in **`ThemeProvider`** with the same value passed to **`AIOPsDashboard`**’s controlled props.
|
|
48
|
-
|
|
49
|
-
---
|
|
50
|
-
|
|
51
|
-
## Architecture
|
|
52
|
-
|
|
53
|
-
```
|
|
54
|
-
AIOPsDashboard ← Shell: header, state, optional DataProvider
|
|
55
|
-
└─ Carousel ← 3D orbit, rotation, hosts dialogs
|
|
56
|
-
└─ Service ← Per-service container, connections, holo base
|
|
57
|
-
├─ ServerNode ← Compound: ServiceNode + Server3D
|
|
58
|
-
├─ DatabaseNode ← Compound: ServiceNode + Database3D
|
|
59
|
-
├─ WebDispatcherNode ← Compound: ServiceNode + WebDispatcher3D
|
|
60
|
-
├─ MessageServerNode ← Compound: ServiceNode + MessageServer3D
|
|
61
|
-
├─ HumanNode ← Compound: ServiceNode + Human3D (SVG)
|
|
62
|
-
├─ SvgConnection ← Animated dashed topology line
|
|
63
|
-
├─ SyncBridge ← DB replication indicator
|
|
64
|
-
├─ NodeCallout ← Alert callout (auto from thresholds)
|
|
65
|
-
└─ HoloBase ← Neon platform (auto-rendered)
|
|
66
|
-
|
|
67
|
-
ServiceDialog ← Service-level KPI panel (auto on expand)
|
|
68
|
-
ComponentDialog ← Drill-down with internals + graphs
|
|
69
|
-
├─ HistoricalGraphPanel ← Sparkline charts
|
|
70
|
-
└─ CPU3D / Memory3D / DriveBay3D / NetworkBlock3D / ThreadPool3D / Platter3D / Port3D
|
|
71
|
-
|
|
72
|
-
DataProvider ← Polling engine + credentials modal
|
|
73
|
-
|
|
74
|
-
EventView ← Standalone event console (table view)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
├──
|
|
84
|
-
├──
|
|
85
|
-
├──
|
|
86
|
-
├──
|
|
87
|
-
├──
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
│
|
|
91
|
-
├──
|
|
92
|
-
│
|
|
93
|
-
|
|
94
|
-
│ ├──
|
|
95
|
-
│ ├──
|
|
96
|
-
│ ├──
|
|
97
|
-
│ ├──
|
|
98
|
-
│ ├──
|
|
99
|
-
│ ├──
|
|
100
|
-
│
|
|
101
|
-
│
|
|
102
|
-
│ │ ├──
|
|
103
|
-
│ │ ├──
|
|
104
|
-
│ │ ├──
|
|
105
|
-
│ │ ├──
|
|
106
|
-
│ │
|
|
107
|
-
│
|
|
108
|
-
|
|
109
|
-
│ ├──
|
|
110
|
-
│ ├──
|
|
111
|
-
│
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
└──
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
}}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
]
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
Default
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
**
|
|
480
|
-
|
|
481
|
-
**
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
<
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
|
729
|
-
|
|
|
730
|
-
|
|
|
731
|
-
|
|
|
732
|
-
|
|
|
733
|
-
|
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
}
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
/>
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
|
948
|
-
|
|
|
949
|
-
| `
|
|
950
|
-
| `
|
|
951
|
-
| `
|
|
952
|
-
| `
|
|
953
|
-
| `
|
|
954
|
-
| `
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1
|
+
# React DashStream — AI Coding Assistant Skill
|
|
2
|
+
|
|
3
|
+
> **Package**: `react-dashstream` (npm)
|
|
4
|
+
> **Version**: 0.2.0
|
|
5
|
+
> **Peer deps**: `react` ^18 || ^19, `react-dom` ^18 || ^19
|
|
6
|
+
> **License**: MIT
|
|
7
|
+
|
|
8
|
+
Use this skill when the user is working with the `react-dashstream` package — a holographic 3D infrastructure monitoring dashboard built entirely with CSS 3D transforms (no WebGL, no canvas).
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## What this package does
|
|
13
|
+
|
|
14
|
+
React DashStream renders a rotating 3D carousel of infrastructure services. Each service can be clicked to expand into a multi-tiered topology showing servers, databases, dispatchers, message servers, and user nodes connected by animated SVG lines. Components can be drilled into to reveal internal sub-components with sparkline graphs and gauges.
|
|
15
|
+
|
|
16
|
+
Two modes:
|
|
17
|
+
|
|
18
|
+
1. **Static mode** — pass props directly for demo or snapshot views.
|
|
19
|
+
2. **Live data mode** — poll an HTTP endpoint with PromQL queries and auto-inject resolved values as component props.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Installation and CSS
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install react-dashstream
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
import "react-dashstream/dist/index.css";
|
|
31
|
+
import { AIOPsDashboard, Service, ServerNode, DatabaseNode } from "react-dashstream";
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Always import the CSS file** — without it, no styles render.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Light / dark theme
|
|
39
|
+
|
|
40
|
+
The dashboard supports **`"light"`** and **`"dark"`** modes.
|
|
41
|
+
|
|
42
|
+
- **`AIOPsDashboard`** defaults to **light** and exposes a header toggle. Use **`backgroundImage`** (dark) and **`lightBackgroundImage`** (light when set).
|
|
43
|
+
- **Controlled mode:** pass **`theme`** and **`onThemeChange`** (`DashboardTheme`) so parent state owns the mode (e.g. sync app chrome + `EventView`).
|
|
44
|
+
- **`ThemeProvider`** (export) + **`useTheme()`** — wrap subtrees so **`EventView`**, **`CredentialsModal`**, **`ServiceDialog`**, and **`ComponentDialog`** match the dashboard. Without a provider, `useTheme()` defaults to **`"dark"`**; prefer wrapping when using `EventView` or the lock screen next to a light dashboard.
|
|
45
|
+
- **`EventView`** accepts optional **`theme`** to override context.
|
|
46
|
+
|
|
47
|
+
When generating multi-view apps (3D + Event Console + credentials), wrap the root in **`ThemeProvider`** with the same value passed to **`AIOPsDashboard`**’s controlled props.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Architecture
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
AIOPsDashboard ← Shell: header, state, optional DataProvider
|
|
55
|
+
└─ Carousel ← 3D orbit, rotation, hosts dialogs
|
|
56
|
+
└─ Service ← Per-service container, connections, holo base
|
|
57
|
+
├─ ServerNode ← Compound: ServiceNode + Server3D
|
|
58
|
+
├─ DatabaseNode ← Compound: ServiceNode + Database3D
|
|
59
|
+
├─ WebDispatcherNode ← Compound: ServiceNode + WebDispatcher3D
|
|
60
|
+
├─ MessageServerNode ← Compound: ServiceNode + MessageServer3D
|
|
61
|
+
├─ HumanNode ← Compound: ServiceNode + Human3D (SVG)
|
|
62
|
+
├─ SvgConnection ← Animated dashed topology line
|
|
63
|
+
├─ SyncBridge ← DB replication indicator
|
|
64
|
+
├─ NodeCallout ← Alert callout (auto from thresholds)
|
|
65
|
+
└─ HoloBase ← Neon platform (auto-rendered)
|
|
66
|
+
|
|
67
|
+
ServiceDialog ← Service-level KPI panel (auto on expand)
|
|
68
|
+
ComponentDialog ← Drill-down with internals + graphs
|
|
69
|
+
├─ HistoricalGraphPanel ← Sparkline charts
|
|
70
|
+
└─ CPU3D / Memory3D / DriveBay3D / NetworkBlock3D / ThreadPool3D / Platter3D / Port3D
|
|
71
|
+
|
|
72
|
+
DataProvider ← Polling engine + credentials modal
|
|
73
|
+
|
|
74
|
+
EventView ← Standalone event console (table view)
|
|
75
|
+
|
|
76
|
+
DatacenterView ← SVG topology / optional geography map + drill-down dashboard
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Source layout
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
src/
|
|
83
|
+
├── index.ts # Public API barrel
|
|
84
|
+
├── AIOPsDashboard.tsx # Dashboard shell + live-data wiring
|
|
85
|
+
├── types.ts # Shared topology/drill-down types
|
|
86
|
+
├── theme.ts # Status tokens, holo palette, 3D face helpers
|
|
87
|
+
├── ThemeContext.ts # DashboardTheme, ThemeProvider, useTheme
|
|
88
|
+
├── styles.css / index.css # Library + dashboard styles
|
|
89
|
+
├── data/
|
|
90
|
+
│ ├── DataProvider.tsx # Polling engine, context, hooks
|
|
91
|
+
│ ├── CredentialsModal.tsx # Auth prompt UI
|
|
92
|
+
│ └── index.ts
|
|
93
|
+
├── components/ # ~30 UI components
|
|
94
|
+
│ ├── Carousel.tsx, Service.tsx, ServiceNode.tsx
|
|
95
|
+
│ ├── ServerNode.tsx, DatabaseNode.tsx, WebDispatcherNode.tsx, etc.
|
|
96
|
+
│ ├── Server3D.tsx, Database3D.tsx, etc.
|
|
97
|
+
│ ├── ServiceDialog.tsx, ComponentDialog.tsx
|
|
98
|
+
│ ├── Internal3DComponents.tsx, HistoricalGraphPanel.tsx
|
|
99
|
+
│ ├── ComponentDrillView.tsx, SvgConnection.tsx, SyncBridge.tsx
|
|
100
|
+
│ ├── NodeCallout.tsx, HoloBase.tsx, CarouselContext.ts
|
|
101
|
+
│ ├── EventView/ # Operations event console
|
|
102
|
+
│ │ ├── EventView.tsx # Table component (filter, sort, search, infinite scroll)
|
|
103
|
+
│ │ ├── EventView.css # Holographic table styles
|
|
104
|
+
│ │ ├── EventAlertsContext.tsx # EventAlertsProvider + per-host alert map
|
|
105
|
+
│ │ ├── fetchEvents.ts # Shared fetch/mapping logic (used by both EventView & provider)
|
|
106
|
+
│ │ ├── types.ts # AIOpsEvent, EventSeverity, EventApiConfig, etc.
|
|
107
|
+
│ │ ├── mockData.ts # 28 realistic mock events
|
|
108
|
+
│ │ └── index.ts
|
|
109
|
+
│ ├── DatacenterView/ # Topology map + CSS 3D building markers
|
|
110
|
+
│ │ ├── DatacenterView.tsx
|
|
111
|
+
│ │ ├── DatacenterView.css
|
|
112
|
+
│ │ ├── types.ts
|
|
113
|
+
│ │ └── index.ts
|
|
114
|
+
│ └── index.ts
|
|
115
|
+
├── services/
|
|
116
|
+
│ ├── SAPService.tsx, ExchangeService.tsx
|
|
117
|
+
│ ├── sapSubComponents.tsx
|
|
118
|
+
│ └── index.ts
|
|
119
|
+
example/
|
|
120
|
+
├── Dashboard.tsx
|
|
121
|
+
└── services/
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Complete data flow reference
|
|
127
|
+
|
|
128
|
+
There are **10 distinct data paths** in this package. Understanding them is critical for building live dashboards.
|
|
129
|
+
|
|
130
|
+
### 1. Data bindings — live props injected into service components
|
|
131
|
+
|
|
132
|
+
`dataBindings` maps **service name → prop name → PromQL query**. The dashboard polls each query, applies a transform, and injects the result as a prop on the matched child component.
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
type DataBinding = string | { query: string; transform?: (raw: unknown) => unknown };
|
|
136
|
+
type DataBindings = Record<string, Record<string, DataBinding>>;
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
- Bare string → uses global `dataTransform` (defaults to numeric parsing)
|
|
140
|
+
- Object `{ query, transform }` → uses per-binding transform
|
|
141
|
+
- Service name key must match child's `name` prop **exactly**
|
|
142
|
+
|
|
143
|
+
```tsx
|
|
144
|
+
const dataBindings: DataBindings = {
|
|
145
|
+
"My Service": {
|
|
146
|
+
cpuLoad: 'cpu_usage{instance="srv-01"}', // bare string → number
|
|
147
|
+
memLoad: 'memory_usage{instance="srv-01"}', // bare string → number
|
|
148
|
+
status: {
|
|
149
|
+
// object → custom transform
|
|
150
|
+
query: 'cpu_usage{instance="srv-01"}',
|
|
151
|
+
transform: (raw) => {
|
|
152
|
+
const n = Number(raw);
|
|
153
|
+
if (n >= 85) return "critical";
|
|
154
|
+
if (n >= 70) return "warning";
|
|
155
|
+
return "online";
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
dbCapacity: 'disk_capacity{instance="db-01"}',
|
|
159
|
+
dbStatus: { query: 'disk_capacity{instance="db-01"}', transform: statusFromValue },
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
#### Multi-component services
|
|
165
|
+
|
|
166
|
+
When a service has multiple nodes of the same type (e.g. three servers), use a flat naming convention with prefixes. Each `DataBinding` maps **one prop → one query** — there is no array or object binding type.
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
interface ServiceXProps {
|
|
170
|
+
name: string;
|
|
171
|
+
status?: ComponentStatus;
|
|
172
|
+
srv1CpuLoad?: number;
|
|
173
|
+
srv1MemLoad?: number;
|
|
174
|
+
srv1Status?: ComponentStatus;
|
|
175
|
+
srv2CpuLoad?: number;
|
|
176
|
+
srv2MemLoad?: number;
|
|
177
|
+
srv2Status?: ComponentStatus;
|
|
178
|
+
srv3CpuLoad?: number;
|
|
179
|
+
srv3MemLoad?: number;
|
|
180
|
+
srv3Status?: ComponentStatus;
|
|
181
|
+
dbCapacity?: number;
|
|
182
|
+
dbStatus?: ComponentStatus;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function ServiceX({
|
|
186
|
+
name, status = "online",
|
|
187
|
+
srv1CpuLoad = 54, srv1MemLoad = 58, srv1Status = "online",
|
|
188
|
+
srv2CpuLoad = 63, srv2MemLoad = 66, srv2Status = "online",
|
|
189
|
+
srv3CpuLoad = 78, srv3MemLoad = 71, srv3Status = "online",
|
|
190
|
+
dbCapacity = 68, dbStatus = "online",
|
|
191
|
+
}: ServiceXProps) {
|
|
192
|
+
return (
|
|
193
|
+
<Service name={name} status={status} connections={[/* ... */]}>
|
|
194
|
+
<ServerNode name="SRV-X1" status={srv1Status}
|
|
195
|
+
cpuLoad={srv1CpuLoad} memLoad={srv1MemLoad} ... />
|
|
196
|
+
<ServerNode name="SRV-X2" status={srv2Status}
|
|
197
|
+
cpuLoad={srv2CpuLoad} memLoad={srv2MemLoad} ... />
|
|
198
|
+
<ServerNode name="SRV-X3" status={srv3Status}
|
|
199
|
+
cpuLoad={srv3CpuLoad} memLoad={srv3MemLoad} ... />
|
|
200
|
+
<DatabaseNode name="DB-X1" status={dbStatus}
|
|
201
|
+
capacity={dbCapacity} ... />
|
|
202
|
+
</Service>
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Bind each prefixed prop individually:
|
|
208
|
+
|
|
209
|
+
```tsx
|
|
210
|
+
dataBindings={{
|
|
211
|
+
ServiceX: {
|
|
212
|
+
status: { query: 'status{instance="svcx"}', transform: statusFromValue },
|
|
213
|
+
srv1CpuLoad: 'cpu_usage{instance="srvx-01"}',
|
|
214
|
+
srv1MemLoad: 'memory_usage{instance="srvx-01"}',
|
|
215
|
+
srv1Status: { query: 'status{instance="srvx-01"}', transform: statusFromValue },
|
|
216
|
+
srv2CpuLoad: 'cpu_usage{instance="srvx-02"}',
|
|
217
|
+
srv2MemLoad: 'memory_usage{instance="srvx-02"}',
|
|
218
|
+
srv2Status: { query: 'status{instance="srvx-02"}', transform: statusFromValue },
|
|
219
|
+
srv3CpuLoad: 'cpu_usage{instance="srvx-03"}',
|
|
220
|
+
srv3MemLoad: 'memory_usage{instance="srvx-03"}',
|
|
221
|
+
srv3Status: { query: 'status{instance="srvx-03"}', transform: statusFromValue },
|
|
222
|
+
dbCapacity: 'disk_capacity{instance="dbx-01"}',
|
|
223
|
+
dbStatus: { query: 'status{instance="dbx-01"}', transform: statusFromValue },
|
|
224
|
+
},
|
|
225
|
+
}}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Use a consistent convention like `srv1CpuLoad`, `srv2CpuLoad`. The service component maps each prefixed prop to the correct node.
|
|
229
|
+
|
|
230
|
+
### 2. Service dialog — static ServiceMeta metrics
|
|
231
|
+
|
|
232
|
+
The **ServiceDialog** panel shows KPIs when a service is expanded. Static metrics are passed via `ServiceMeta`:
|
|
233
|
+
|
|
234
|
+
```tsx
|
|
235
|
+
const services: ServiceMeta[] = [
|
|
236
|
+
{
|
|
237
|
+
name: "My Service",
|
|
238
|
+
status: "online",
|
|
239
|
+
metrics: [
|
|
240
|
+
{ label: "Uptime", value: "99.99%", color: "#00ff88" },
|
|
241
|
+
{ label: "Avg Latency", value: "8ms", color: "#00e5ff" },
|
|
242
|
+
],
|
|
243
|
+
alerts: [
|
|
244
|
+
{ level: "info", message: "All Systems Nominal" },
|
|
245
|
+
{ level: "warning", message: "High CPU on SRV-01" },
|
|
246
|
+
{ level: "critical", message: "DB connection pool exhausted" },
|
|
247
|
+
],
|
|
248
|
+
},
|
|
249
|
+
];
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### 3. Service dialog — live serviceDataBindings
|
|
253
|
+
|
|
254
|
+
Replace static metrics with live-fetched values using `serviceDataBindings`:
|
|
255
|
+
|
|
256
|
+
```tsx
|
|
257
|
+
serviceDataBindings={{
|
|
258
|
+
"My Service": [
|
|
259
|
+
{ label: "CPU Load", query: 'cpu_usage{instance="srv-01"}', unit: "%", color: "#00e5ff" },
|
|
260
|
+
{ label: "Memory", query: 'memory_usage{instance="srv-01"}', unit: "%", color: "#bb55ff" },
|
|
261
|
+
{ label: "Disk", query: 'disk_capacity{instance="db-01"}', unit: "%", color: "#ff8c00" },
|
|
262
|
+
],
|
|
263
|
+
}}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
```ts
|
|
267
|
+
interface ServiceMetricBinding {
|
|
268
|
+
label: string; // Row label
|
|
269
|
+
query: string; // PromQL query
|
|
270
|
+
unit?: string; // Suffix (e.g. "%", "ms")
|
|
271
|
+
color?: string; // Accent color
|
|
272
|
+
transform?: (raw: unknown) => string; // Custom formatter
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
When provided, live values **replace** static `ServiceMeta.metrics` for that service.
|
|
277
|
+
|
|
278
|
+
### 4. Component dialog — default gauges
|
|
279
|
+
|
|
280
|
+
The **ComponentDialog** appears when clicking a node. Default gauges are derived from node type:
|
|
281
|
+
|
|
282
|
+
- **Server**: CPU (from `cpuLoad`), Memory (from `memLoad`), Storage
|
|
283
|
+
- **Database**: Capacity (from `capacity`), Memory, Storage
|
|
284
|
+
- **Dispatcher**: Traffic (from `traffic`), Memory, Storage
|
|
285
|
+
- **Message Server**: Queue (from `queueDepth`), Memory, Storage
|
|
286
|
+
|
|
287
|
+
Default thresholds: warn at 70, critical at 85.
|
|
288
|
+
|
|
289
|
+
### 5. Component dialog — custom dialogMetrics
|
|
290
|
+
|
|
291
|
+
Override default gauges with `dialogMetrics` on any compound node:
|
|
292
|
+
|
|
293
|
+
```tsx
|
|
294
|
+
<ServerNode
|
|
295
|
+
name="SRV-01"
|
|
296
|
+
status="online"
|
|
297
|
+
cpuLoad={67}
|
|
298
|
+
memLoad={72}
|
|
299
|
+
ex={200}
|
|
300
|
+
ey={380}
|
|
301
|
+
compactOffset={{ x: -30, y: -20 }}
|
|
302
|
+
zIndex={8}
|
|
303
|
+
dialogMetrics={[
|
|
304
|
+
{ id: "cpu", label: "CPU", sublabel: "PROCESSOR", value: 67, unit: "%" },
|
|
305
|
+
{ id: "mem", label: "MEMORY", sublabel: "HEAP USAGE", value: 72, unit: "%" },
|
|
306
|
+
{ id: "iops", label: "IOPS", sublabel: "DISK OPS", value: 45, unit: "k/s", icon: "disk" },
|
|
307
|
+
{
|
|
308
|
+
id: "threads",
|
|
309
|
+
label: "THREADS",
|
|
310
|
+
sublabel: "ACTIVE",
|
|
311
|
+
value: 82,
|
|
312
|
+
unit: "%",
|
|
313
|
+
warnAt: 60,
|
|
314
|
+
critAt: 80,
|
|
315
|
+
icon: "cpu",
|
|
316
|
+
},
|
|
317
|
+
]}
|
|
318
|
+
/>
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
```ts
|
|
322
|
+
interface ComponentDialogMetric {
|
|
323
|
+
id: string; // Unique key
|
|
324
|
+
label: string; // Upper label
|
|
325
|
+
sublabel: string; // Lower label
|
|
326
|
+
value: number; // 0–100
|
|
327
|
+
unit?: string; // Default "%"
|
|
328
|
+
icon?: "cpu" | "mem" | "disk"; // Default "cpu"
|
|
329
|
+
warnAt?: number; // Default 70
|
|
330
|
+
critAt?: number; // Default 85
|
|
331
|
+
color?: string; // Override bar color (bypasses threshold coloring)
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
All compound nodes accept `dialogMetrics`: `ServerNode`, `DatabaseNode`, `WebDispatcherNode`, `MessageServerNode`.
|
|
336
|
+
|
|
337
|
+
**Live component dialog metrics pattern**: To feed live query values into custom gauges, expose each metric as a prop on your service component. Use `dataBindings` to inject them. Then build the `dialogMetrics` array from those props:
|
|
338
|
+
|
|
339
|
+
```tsx
|
|
340
|
+
// Service component — accepts individual metric props, builds dialogMetrics from them
|
|
341
|
+
function MyService({ name, status = "online", cpuLoad = 42, memLoad = 60, iops = 20 }: any) {
|
|
342
|
+
return (
|
|
343
|
+
<Service
|
|
344
|
+
name={name}
|
|
345
|
+
status={status}
|
|
346
|
+
connections={
|
|
347
|
+
[
|
|
348
|
+
/* ... */
|
|
349
|
+
]
|
|
350
|
+
}
|
|
351
|
+
>
|
|
352
|
+
<ServerNode
|
|
353
|
+
name="SRV-01"
|
|
354
|
+
status={status}
|
|
355
|
+
cpuLoad={cpuLoad}
|
|
356
|
+
memLoad={memLoad}
|
|
357
|
+
ex={200}
|
|
358
|
+
ey={380}
|
|
359
|
+
compactOffset={{ x: -30, y: -20 }}
|
|
360
|
+
zIndex={8}
|
|
361
|
+
dialogMetrics={[
|
|
362
|
+
{ id: "cpu", label: "CPU", sublabel: "PROCESSOR", value: cpuLoad },
|
|
363
|
+
{ id: "mem", label: "MEMORY", sublabel: "HEAP", value: memLoad },
|
|
364
|
+
{
|
|
365
|
+
id: "iops",
|
|
366
|
+
label: "IOPS",
|
|
367
|
+
sublabel: "DISK OPS",
|
|
368
|
+
value: iops,
|
|
369
|
+
icon: "disk",
|
|
370
|
+
warnAt: 50,
|
|
371
|
+
critAt: 80,
|
|
372
|
+
},
|
|
373
|
+
]}
|
|
374
|
+
/>
|
|
375
|
+
</Service>
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// Dashboard — bind each prop to a query
|
|
380
|
+
<AIOPsDashboard
|
|
381
|
+
liveData
|
|
382
|
+
dataEndpoint="..."
|
|
383
|
+
dataBindings={{
|
|
384
|
+
"My Service": {
|
|
385
|
+
cpuLoad: 'cpu_usage{instance="srv-01"}',
|
|
386
|
+
memLoad: 'memory_usage{instance="srv-01"}',
|
|
387
|
+
iops: 'disk_iops{instance="srv-01"}',
|
|
388
|
+
status: { query: 'cpu_usage{instance="srv-01"}', transform: statusFromValue },
|
|
389
|
+
},
|
|
390
|
+
}}
|
|
391
|
+
>
|
|
392
|
+
<MyService name="My Service" />
|
|
393
|
+
</AIOPsDashboard>;
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
The dashboard injects `cpuLoad`, `memLoad`, `iops` as live props → they flow into `dialogMetrics` → gauges update automatically on every poll. Works for any number of custom metrics.
|
|
397
|
+
|
|
398
|
+
### 6. Alerts — automatic threshold detection
|
|
399
|
+
|
|
400
|
+
Nodes auto-render `NodeCallout` alerts when metrics breach thresholds:
|
|
401
|
+
|
|
402
|
+
- **Warning** at 70% → orange callout
|
|
403
|
+
- **Critical** at 85% → red callout
|
|
404
|
+
|
|
405
|
+
Sources (checked in priority order):
|
|
406
|
+
|
|
407
|
+
1. `dialogMetrics` values vs their `warnAt`/`critAt`
|
|
408
|
+
2. Context values (`cpuLoad`, `memLoad`, `traffic`, `queueDepth`, `capacity`) vs default thresholds
|
|
409
|
+
|
|
410
|
+
```tsx
|
|
411
|
+
// Auto-alert from cpuLoad > 85
|
|
412
|
+
<ServerNode cpuLoad={92} memLoad={64}
|
|
413
|
+
alert={{ offsetX: -160, offsetY: -60, align: "left" }}
|
|
414
|
+
... />
|
|
415
|
+
|
|
416
|
+
// Custom message
|
|
417
|
+
<ServerNode cpuLoad={92}
|
|
418
|
+
alert={{ msg: "CPU overload — scale out", offsetX: -160, offsetY: -60, align: "left" }}
|
|
419
|
+
... />
|
|
420
|
+
|
|
421
|
+
// Custom thresholds via dialogMetrics
|
|
422
|
+
<ServerNode
|
|
423
|
+
dialogMetrics={[
|
|
424
|
+
{ id: "cpu", label: "CPU", sublabel: "PROCESSOR", value: 67,
|
|
425
|
+
warnAt: 50, critAt: 75 }, // Alert at 67 because critAt=75
|
|
426
|
+
]}
|
|
427
|
+
alert={{ offsetX: -160, offsetY: -60, align: "left" }}
|
|
428
|
+
... />
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
Alert `align` options: `"left"`, `"right"`, `"top"`, `"bottom"`.
|
|
432
|
+
|
|
433
|
+
Alert prop shape:
|
|
434
|
+
|
|
435
|
+
```ts
|
|
436
|
+
alert?: {
|
|
437
|
+
msg?: string; // Custom message (auto-generated if omitted)
|
|
438
|
+
offsetX?: number; // X offset from node (default 110)
|
|
439
|
+
offsetY?: number; // Y offset from node (default -30)
|
|
440
|
+
align?: "left" | "right" | "top" | "bottom"; // Default "right"
|
|
441
|
+
internalRef?: string; // Sub-component ID
|
|
442
|
+
}
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
### 7. Event-to-dashboard bridge — automatic node alerts from events API
|
|
446
|
+
|
|
447
|
+
When `eventApiConfig` is passed to `AIOPsDashboard`, events are fetched in the background and nodes whose `name` (case-insensitive) matches an event `host` automatically show alert callouts.
|
|
448
|
+
|
|
449
|
+
```tsx
|
|
450
|
+
<AIOPsDashboard
|
|
451
|
+
eventApiConfig={eventApiConfig} // same EventApiConfig used for EventView
|
|
452
|
+
liveData
|
|
453
|
+
dataEndpoint="..."
|
|
454
|
+
dataBindings={dataBindings}
|
|
455
|
+
services={services}
|
|
456
|
+
>
|
|
457
|
+
<MyService name="My Service" />
|
|
458
|
+
</AIOPsDashboard>
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
**How it works internally:**
|
|
462
|
+
|
|
463
|
+
1. `AIOPsDashboard` wraps children in `EventAlertsProvider` (inside `DataProvider` when `liveData` is set — shares credentials automatically)
|
|
464
|
+
2. `EventAlertsProvider` fetches events using the same `fetchEvents` + `mapRawEvent` logic as `EventView`
|
|
465
|
+
3. Events are grouped by **lower-cased hostname** into a `Map<string, EventHostAlert>`
|
|
466
|
+
4. `ServiceNode` reads from `EventAlertsContext` via `useEventAlertsOptional()`
|
|
467
|
+
5. If `componentInfo.name.toLowerCase()` matches an entry, event severity is factored into the existing `resolveNodeSeverity` pipeline as a **third severity source** (alongside node status and metric breaches)
|
|
468
|
+
6. Highest severity among all three sources wins
|
|
469
|
+
7. `NodeCallout` appears automatically with the event message; multi-event hosts show `"N events – message"`
|
|
470
|
+
|
|
471
|
+
**Severity mapping:**
|
|
472
|
+
|
|
473
|
+
| Event severity | → ComponentStatus |
|
|
474
|
+
| -------------- | ----------------- |
|
|
475
|
+
| Critical | `"critical"` |
|
|
476
|
+
| Major | `"warning"` |
|
|
477
|
+
| Minor | `"warning"` |
|
|
478
|
+
|
|
479
|
+
**Key requirement:** Node `name` props must match event `host` values from the API (case-insensitive). Example: if the API returns `host: "SAP-PRD-APP01"`, the node must be `<ServerNode name="SAP-PRD-APP01" ... />`.
|
|
480
|
+
|
|
481
|
+
**Credential resolution order** (for EventAlertsProvider inside AIOPsDashboard):
|
|
482
|
+
|
|
483
|
+
1. `DataProvider` context credentials (when `liveData` is enabled — same credentials, one login)
|
|
484
|
+
2. Built-in `CredentialsModal` (when `liveData` is not enabled)
|
|
485
|
+
|
|
486
|
+
**Opt-in:** Without `eventApiConfig`, no events are fetched — zero overhead.
|
|
487
|
+
|
|
488
|
+
**When generating an `AIOPsDashboard` with event bridge:** Reuse the same `EventApiConfig` object that the user already has for their `EventView`. Just add it as `eventApiConfig` on `AIOPsDashboard`.
|
|
489
|
+
|
|
490
|
+
### 8. Drill-down internals — custom subComponents
|
|
491
|
+
|
|
492
|
+
When clicking a node, the drill-down shows internal 3D sub-components. Default sub-components are auto-generated per type. Override with `subComponents`:
|
|
493
|
+
|
|
494
|
+
```tsx
|
|
495
|
+
import { CPU3D, Memory3D, DriveBay3D, ThreadPool3D, NetworkBlock3D, Platter3D, Port3D } from "react-dashstream";
|
|
496
|
+
import type { SubComponentConfig } from "react-dashstream";
|
|
497
|
+
|
|
498
|
+
const internals: SubComponentConfig[] = [
|
|
499
|
+
{ id: "cpu-0", label: "CPU-0", status: "online",
|
|
500
|
+
element: <CPU3D label="CPU-0" load={67} color="#00e5ff" /> },
|
|
501
|
+
{ id: "heap", label: "HEAP", status: "warning",
|
|
502
|
+
element: <Memory3D label="HEAP" usedPercent={92} color="#8855ee" status="warning" /> },
|
|
503
|
+
{ id: "drive", label: "DRIVE-0", status: "online",
|
|
504
|
+
element: <DriveBay3D label="DRIVE-0" color="#00e5ff" activity={true} /> },
|
|
505
|
+
{ id: "threads", label: "THREADS", status: "online",
|
|
506
|
+
element: <ThreadPool3D label="THREADS" color="#00e5ff" /> },
|
|
507
|
+
{ id: "net", label: "NET", status: "online",
|
|
508
|
+
element: <NetworkBlock3D label="NET" color="#00e5ff" /> },
|
|
509
|
+
];
|
|
510
|
+
|
|
511
|
+
<ServerNode subComponents={internals} ... />
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
```ts
|
|
515
|
+
interface SubComponentConfig {
|
|
516
|
+
id: string; // Unique key
|
|
517
|
+
label: string; // Display name
|
|
518
|
+
status: ComponentStatus; // LED color
|
|
519
|
+
detail?: string; // Fault description
|
|
520
|
+
element: ReactNode; // 3D element to render
|
|
521
|
+
}
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
All compound nodes accept `subComponents`.
|
|
525
|
+
|
|
526
|
+
### 9. Graph series — custom sparklines
|
|
527
|
+
|
|
528
|
+
The drill-down's historical panel shows sparkline charts. Default graphs are auto-generated. Override with `graphSeries`:
|
|
529
|
+
|
|
530
|
+
```tsx
|
|
531
|
+
import type { GraphSeries } from "react-dashstream";
|
|
532
|
+
|
|
533
|
+
const graphs: GraphSeries[] = [
|
|
534
|
+
{ id: "cpu", label: "CPU-0", unit: "%", color: "#00e5ff", data: [45, 52, 67, 71, 68, 55] },
|
|
535
|
+
{ id: "mem", label: "HEAP", unit: "%", color: "#8855ee", data: [60, 65, 72, 78, 82, 75] },
|
|
536
|
+
{ id: "iops", label: "DISK", unit: "k/s", color: "#ff8c00", data: [12, 15, 22, 18, 25, 20] },
|
|
537
|
+
];
|
|
538
|
+
|
|
539
|
+
<ServerNode graphSeries={graphs} ... />
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
```ts
|
|
543
|
+
interface GraphSeries {
|
|
544
|
+
id: string; // Unique key
|
|
545
|
+
label: string; // Label above sparkline
|
|
546
|
+
unit: string; // Suffix
|
|
547
|
+
color: string; // Line color
|
|
548
|
+
data: number[]; // Points (most recent last)
|
|
549
|
+
}
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
All compound nodes accept `graphSeries`.
|
|
553
|
+
|
|
554
|
+
### 10. Data hooks — programmatic access
|
|
555
|
+
|
|
556
|
+
Access live data context anywhere inside the dashboard:
|
|
557
|
+
|
|
558
|
+
```tsx
|
|
559
|
+
import { useAIOpsData, useAIOpsDataOptional, useQueryResult } from "react-dashstream";
|
|
560
|
+
|
|
561
|
+
function CustomWidget() {
|
|
562
|
+
const { data, isRefreshing, lastRefreshError, lastRefreshTime, credentialsSet } = useAIOpsData();
|
|
563
|
+
const cpu = useQueryResult('cpu_usage{instance="srv-01"}');
|
|
564
|
+
return <div>CPU: {String(cpu)}</div>;
|
|
565
|
+
}
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
| Hook | Returns | Throws? |
|
|
569
|
+
| ------------------------ | -------------------------- | ---------------------------- |
|
|
570
|
+
| `useAIOpsData()` | `DataContextValue` | Yes — outside `DataProvider` |
|
|
571
|
+
| `useAIOpsDataOptional()` | `DataContextValue \| null` | No |
|
|
572
|
+
| `useQueryResult(query)` | `unknown \| null` | Yes — outside `DataProvider` |
|
|
573
|
+
|
|
574
|
+
```ts
|
|
575
|
+
interface DataContextValue {
|
|
576
|
+
data: Record<string, unknown>; // Raw responses keyed by query
|
|
577
|
+
isRefreshing: boolean;
|
|
578
|
+
lastRefreshError: string | null;
|
|
579
|
+
lastRefreshTime: Date | null;
|
|
580
|
+
credentialsSet: boolean;
|
|
581
|
+
setCredentials: (creds: Credentials) => void;
|
|
582
|
+
}
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
---
|
|
586
|
+
|
|
587
|
+
## Exports
|
|
588
|
+
|
|
589
|
+
Everything below is exported from `react-dashstream`.
|
|
590
|
+
|
|
591
|
+
### Default export
|
|
592
|
+
|
|
593
|
+
`AIOPsDashboard` — main dashboard shell component.
|
|
594
|
+
|
|
595
|
+
### Compound nodes
|
|
596
|
+
|
|
597
|
+
`ServerNode`, `DatabaseNode`, `WebDispatcherNode`, `MessageServerNode`, `HumanNode`
|
|
598
|
+
|
|
599
|
+
### Layout
|
|
600
|
+
|
|
601
|
+
`Carousel`, `Service`, `ServiceNode`
|
|
602
|
+
|
|
603
|
+
### 3D models
|
|
604
|
+
|
|
605
|
+
`Server3D`, `Database3D`, `WebDispatcher3D`, `MessageServer3D`, `Human3D`
|
|
606
|
+
|
|
607
|
+
### Internal 3D components (for drill-down)
|
|
608
|
+
|
|
609
|
+
`CPU3D`, `Memory3D`, `DriveBay3D`, `NetworkBlock3D`, `ThreadPool3D`, `Platter3D`, `Port3D`
|
|
610
|
+
|
|
611
|
+
### Indicators and connections
|
|
612
|
+
|
|
613
|
+
`SvgConnection`, `SyncBridge`, `NodeCallout`, `HoloBase`
|
|
614
|
+
|
|
615
|
+
### Dialogs
|
|
616
|
+
|
|
617
|
+
`ServiceDialog`, `ComponentDialog`, `HistoricalGraphPanel`, `ComponentDrillView`
|
|
618
|
+
|
|
619
|
+
### Pre-built services
|
|
620
|
+
|
|
621
|
+
`SAPService`, `ExchangeService`
|
|
622
|
+
|
|
623
|
+
SAP helpers: `computeSAPServiceStatus`, `computeSAPDialogMetrics`, `computeSAPDialogAlerts`, `SAP_CONNECTIONS`
|
|
624
|
+
|
|
625
|
+
Exchange helpers: `computeExchangeServiceStatus`, `computeExchangeDialogMetrics`, `computeExchangeDialogAlerts`, `EXCHANGE_CONNECTIONS`
|
|
626
|
+
|
|
627
|
+
SAP sub-component helpers: `getServerSubComponents`, `getServerGraphSeries`, `getDispatcherSubComponents`, `getDispatcherGraphSeries`, `getMessageServerSubComponents`, `getMessageServerGraphSeries`, `getDatabaseSubComponents`, `getDatabaseGraphSeries`
|
|
628
|
+
|
|
629
|
+
### Data layer
|
|
630
|
+
|
|
631
|
+
`DataProvider`, `useAIOpsData`, `useAIOpsDataOptional`, `useQueryResult`, `extractUniqueQueries`, `extractDatacenterMetricQueries`, `defaultDataTransform`
|
|
632
|
+
|
|
633
|
+
### Datacenter topology map
|
|
634
|
+
|
|
635
|
+
`DatacenterView` — plus types `DatacenterViewProps`, `DatacenterBuildingConfig`, `DatacenterBuildingVariant`, `DatacenterConnection`, `DatacenterGeography`, `DatacenterMetrics`, `DatacenterSiteLabels`, `DatacenterViewPhase`
|
|
636
|
+
|
|
637
|
+
### Event alerts
|
|
638
|
+
|
|
639
|
+
`EventAlertsProvider`, `useEventAlerts`, `useEventAlertsOptional`
|
|
640
|
+
|
|
641
|
+
### Theme
|
|
642
|
+
|
|
643
|
+
`STATUS_CFG`, `HOLO_CYAN` (`"#00e5ff"`), `HOLO_BLUE` (`"#0055cc"`), `HOLO_SURFACE`, `HOLO_GLASS`, `makeFaceStyles(W, H, D)`
|
|
644
|
+
|
|
645
|
+
`ThemeProvider`, `useTheme`, type `DashboardTheme` (`"light" | "dark"`)
|
|
646
|
+
|
|
647
|
+
### Context hooks
|
|
648
|
+
|
|
649
|
+
`CarouselContext`, `CarouselItemContext`, `useCarouselContext`, `useCarouselItemContext`, `ServiceContext`
|
|
650
|
+
|
|
651
|
+
### Type exports
|
|
652
|
+
|
|
653
|
+
`AIOPsDashboardProps`, `ServiceMeta`, `ServiceMetricBinding`, `DashboardTheme`, `ComponentStatus`, `StatusCfg`, `FaceName`, `Base3DProps`, `ComponentType`, `ComponentContext`, `ComponentDialogMetric`, `SubComponentConfig`, `GraphSeries`, `SelectedComponent`, `ConnectionConfig`, `ViewState`, `DataBinding`, `DataBindings`, `DatacenterMetricBindings`, `DataProviderConfig`, `Credentials`, `DataContextValue`, `ServiceProps`, `ServiceContextValue`, `ServiceNodeProps`, `CarouselProps`, `ServerNodeProps`, `DatabaseNodeProps`, `HumanNodeProps`, `WebDispatcherNodeProps`, `MessageServerNodeProps`, `SvgConnectionProps`, `SyncBridgeProps`, `NodeCalloutProps`, `ServiceDialogProps`, `ServiceDialogMetric`, `ServiceDialogAlert`, `ComponentDialogProps`, `ComponentDrillViewProps`, `CarouselContextValue`, `CarouselItemContextValue`, `SAPServiceProps`, `SAPServiceOwnProps`, `SAPServiceConfig`, `ExchangeServiceProps`, `ExchangeServiceOwnProps`, `ExchangeServiceConfig`, `EventHostAlert`, `EventAlertsContextValue`, `EventAlertsProviderProps`, `DatacenterViewProps`, `DatacenterBuildingConfig`, `DatacenterBuildingVariant`, `DatacenterConnection`, `DatacenterGeography`, `DatacenterMetrics`, `DatacenterSiteLabels`, `DatacenterViewPhase`
|
|
654
|
+
|
|
655
|
+
---
|
|
656
|
+
|
|
657
|
+
## Key types quick reference
|
|
658
|
+
|
|
659
|
+
### AIOPsDashboardProps
|
|
660
|
+
|
|
661
|
+
`DashboardTheme` is `"light" | "dark"` (exported).
|
|
662
|
+
|
|
663
|
+
```ts
|
|
664
|
+
interface AIOPsDashboardProps {
|
|
665
|
+
title?: string;
|
|
666
|
+
brandName?: string; // Default: "BUSAUD AIOps"
|
|
667
|
+
brandTag?: string; // Default: "3D MONITOR"
|
|
668
|
+
services?: ServiceMeta[];
|
|
669
|
+
backgroundImage?: string;
|
|
670
|
+
lightBackgroundImage?: string; // Used in light mode when set
|
|
671
|
+
theme?: DashboardTheme; // Controlled theme (pair with onThemeChange)
|
|
672
|
+
onThemeChange?: (theme: DashboardTheme) => void;
|
|
673
|
+
logoUrl?: string;
|
|
674
|
+
carouselSpeed?: number; // Default: 0.006
|
|
675
|
+
fontFamily?: string;
|
|
676
|
+
liveData?: boolean; // Default: false
|
|
677
|
+
dataEndpoint?: string;
|
|
678
|
+
dataBindings?: DataBindings;
|
|
679
|
+
dataTransform?: (raw: unknown) => unknown;
|
|
680
|
+
dataRefreshInterval?: number; // Default: 60000
|
|
681
|
+
serviceDataBindings?: Record<string, ServiceMetricBinding[]>;
|
|
682
|
+
eventApiConfig?: EventApiConfig; // Enable event-to-dashboard bridge
|
|
683
|
+
children: React.ReactNode;
|
|
684
|
+
}
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
### ServiceMeta
|
|
688
|
+
|
|
689
|
+
```ts
|
|
690
|
+
interface ServiceMeta {
|
|
691
|
+
name: string; // Must match child component name
|
|
692
|
+
status: ComponentStatus;
|
|
693
|
+
dbSync?: boolean; // Default: true
|
|
694
|
+
metrics?: ServiceDialogMetric[];
|
|
695
|
+
alerts?: ServiceDialogAlert[];
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
interface ServiceDialogMetric {
|
|
699
|
+
label: string;
|
|
700
|
+
value: string;
|
|
701
|
+
color: string;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
interface ServiceDialogAlert {
|
|
705
|
+
level: "info" | "warning" | "critical";
|
|
706
|
+
message: string;
|
|
707
|
+
}
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
### ConnectionConfig
|
|
711
|
+
|
|
712
|
+
```ts
|
|
713
|
+
interface ConnectionConfig {
|
|
714
|
+
from: [number, number];
|
|
715
|
+
to: [number, number];
|
|
716
|
+
visibleAtPhase?: number; // Default: 0
|
|
717
|
+
color?: string; // Default: "#00e5ff"
|
|
718
|
+
duration?: string; // Default: "1.2s"
|
|
719
|
+
}
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
### ComponentStatus
|
|
723
|
+
|
|
724
|
+
```ts
|
|
725
|
+
type ComponentStatus = "online" | "warning" | "critical" | "offline";
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
| Status | Color | Glow |
|
|
729
|
+
| ---------- | --------- | -------- |
|
|
730
|
+
| `online` | `#00e5ff` | cyan |
|
|
731
|
+
| `warning` | `#ff8c00` | orange |
|
|
732
|
+
| `critical` | `#ff2255` | red |
|
|
733
|
+
| `offline` | `#1e3a5a` | dim blue |
|
|
734
|
+
|
|
735
|
+
---
|
|
736
|
+
|
|
737
|
+
## Endpoint contract
|
|
738
|
+
|
|
739
|
+
| Aspect | Requirement |
|
|
740
|
+
| ------------ | -------------------------------------------------------------- |
|
|
741
|
+
| **Method** | `GET` |
|
|
742
|
+
| **URL** | `<dataEndpoint>?query=<urlEncodedQuery>` |
|
|
743
|
+
| **Headers** | `access-key` and `access-secret-key` |
|
|
744
|
+
| **Response** | Plain text body (trimmed). Default transform parses as number. |
|
|
745
|
+
| **Errors** | Non-2xx → counted as failure per query |
|
|
746
|
+
|
|
747
|
+
For JSON responses, provide a custom `dataTransform`:
|
|
748
|
+
|
|
749
|
+
```tsx
|
|
750
|
+
dataTransform={(raw) => {
|
|
751
|
+
const parsed = JSON.parse(String(raw));
|
|
752
|
+
return parsed?.data?.result?.[0]?.value?.[1] ?? raw;
|
|
753
|
+
}}
|
|
754
|
+
```
|
|
755
|
+
|
|
756
|
+
---
|
|
757
|
+
|
|
758
|
+
## Standalone DataProvider
|
|
759
|
+
|
|
760
|
+
Use the data layer without `AIOPsDashboard`:
|
|
761
|
+
|
|
762
|
+
```tsx
|
|
763
|
+
import { DataProvider, useAIOpsData } from "react-dashstream";
|
|
764
|
+
|
|
765
|
+
<DataProvider
|
|
766
|
+
config={{
|
|
767
|
+
endpoint: "https://prometheus.example.com/api/v1/query",
|
|
768
|
+
queries: ['cpu_usage{instance="srv-01"}'],
|
|
769
|
+
refreshInterval: 15000,
|
|
770
|
+
}}
|
|
771
|
+
>
|
|
772
|
+
<MyContent />
|
|
773
|
+
</DataProvider>;
|
|
774
|
+
```
|
|
775
|
+
|
|
776
|
+
---
|
|
777
|
+
|
|
778
|
+
## Node positioning guide
|
|
779
|
+
|
|
780
|
+
The topology scene is ~660×640 pixels.
|
|
781
|
+
|
|
782
|
+
| Layer | Typical `ey` | `visibleAtPhase` | Component |
|
|
783
|
+
| ----------- | ------------ | ---------------- | ------------------- |
|
|
784
|
+
| Users (top) | 100 | 2 | `HumanNode` |
|
|
785
|
+
| Dispatcher | 230 | 2 | `WebDispatcherNode` |
|
|
786
|
+
| App servers | 350–380 | 3 | `ServerNode` |
|
|
787
|
+
| Databases | 500–520 | 4 | `DatabaseNode` |
|
|
788
|
+
|
|
789
|
+
Center X = `330`. Left/right columns: `200` / `460`. Three-column: `165` / `330` / `495`.
|
|
790
|
+
|
|
791
|
+
`compactOffset` controls node position in the compact carousel view relative to center.
|
|
792
|
+
|
|
793
|
+
---
|
|
794
|
+
|
|
795
|
+
## Usage patterns
|
|
796
|
+
|
|
797
|
+
### Minimal static dashboard
|
|
798
|
+
|
|
799
|
+
```tsx
|
|
800
|
+
import "react-dashstream/dist/index.css";
|
|
801
|
+
import { AIOPsDashboard, Service, ServerNode, DatabaseNode } from "react-dashstream";
|
|
802
|
+
|
|
803
|
+
<AIOPsDashboard brandName="MY DASHBOARD" services={[{ name: "Svc", status: "online" }]}>
|
|
804
|
+
<Service
|
|
805
|
+
name="Svc"
|
|
806
|
+
status="online"
|
|
807
|
+
connections={[{ from: [330, 200], to: [330, 380], visibleAtPhase: 3 }]}
|
|
808
|
+
>
|
|
809
|
+
<ServerNode
|
|
810
|
+
ex={330}
|
|
811
|
+
ey={380}
|
|
812
|
+
compactOffset={{ x: 0, y: 0 }}
|
|
813
|
+
zIndex={8}
|
|
814
|
+
name="SRV-01"
|
|
815
|
+
status="online"
|
|
816
|
+
cpuLoad={42}
|
|
817
|
+
memLoad={60}
|
|
818
|
+
/>
|
|
819
|
+
</Service>
|
|
820
|
+
</AIOPsDashboard>;
|
|
821
|
+
```
|
|
822
|
+
|
|
823
|
+
### Full live-data dashboard
|
|
824
|
+
|
|
825
|
+
```tsx
|
|
826
|
+
<AIOPsDashboard
|
|
827
|
+
brandName="LIVE MONITOR"
|
|
828
|
+
services={services}
|
|
829
|
+
liveData={true}
|
|
830
|
+
dataEndpoint="https://prometheus.example.com/api/v1/query"
|
|
831
|
+
dataRefreshInterval={10000}
|
|
832
|
+
dataBindings={{
|
|
833
|
+
"My Service": {
|
|
834
|
+
cpuLoad: 'cpu_usage{instance="srv-01"}',
|
|
835
|
+
status: { query: 'cpu_usage{instance="srv-01"}', transform: statusFromValue },
|
|
836
|
+
},
|
|
837
|
+
}}
|
|
838
|
+
serviceDataBindings={{
|
|
839
|
+
"My Service": [{ label: "CPU", query: 'cpu_usage{instance="srv-01"}', unit: "%", color: "#00e5ff" }],
|
|
840
|
+
}}
|
|
841
|
+
>
|
|
842
|
+
<MyService name="My Service" />
|
|
843
|
+
</AIOPsDashboard>
|
|
844
|
+
```
|
|
845
|
+
|
|
846
|
+
### Custom service with all data features
|
|
847
|
+
|
|
848
|
+
```tsx
|
|
849
|
+
function MyService({ name, status, cpuLoad, memLoad, dbCapacity, dbStatus }: any) {
|
|
850
|
+
return (
|
|
851
|
+
<Service
|
|
852
|
+
name={name}
|
|
853
|
+
status={status ?? "online"}
|
|
854
|
+
connections={[
|
|
855
|
+
{ from: [330, 200], to: [200, 380], visibleAtPhase: 3 },
|
|
856
|
+
{ from: [330, 200], to: [460, 380], visibleAtPhase: 3 },
|
|
857
|
+
]}
|
|
858
|
+
>
|
|
859
|
+
<ServerNode
|
|
860
|
+
ex={200}
|
|
861
|
+
ey={380}
|
|
862
|
+
compactOffset={{ x: -30, y: -20 }}
|
|
863
|
+
zIndex={8}
|
|
864
|
+
name="SRV-01"
|
|
865
|
+
subLabel="APP SERVER"
|
|
866
|
+
status={status ?? "online"}
|
|
867
|
+
cpuLoad={cpuLoad ?? 42}
|
|
868
|
+
memLoad={memLoad ?? 60}
|
|
869
|
+
alert={{ offsetX: -160, offsetY: -60, align: "left" }}
|
|
870
|
+
dialogMetrics={[
|
|
871
|
+
{ id: "cpu", label: "CPU", sublabel: "PROCESSOR", value: cpuLoad ?? 42 },
|
|
872
|
+
{ id: "mem", label: "MEMORY", sublabel: "HEAP", value: memLoad ?? 60 },
|
|
873
|
+
]}
|
|
874
|
+
subComponents={[
|
|
875
|
+
{
|
|
876
|
+
id: "cpu",
|
|
877
|
+
label: "CPU-0",
|
|
878
|
+
status: "online",
|
|
879
|
+
element: <CPU3D label="CPU-0" load={cpuLoad ?? 42} />,
|
|
880
|
+
},
|
|
881
|
+
{
|
|
882
|
+
id: "mem",
|
|
883
|
+
label: "HEAP",
|
|
884
|
+
status: "online",
|
|
885
|
+
element: <Memory3D label="HEAP" usedPercent={memLoad ?? 60} />,
|
|
886
|
+
},
|
|
887
|
+
]}
|
|
888
|
+
graphSeries={[
|
|
889
|
+
{ id: "cpu", label: "CPU", unit: "%", color: "#00e5ff", data: [45, 52, 67, 71, 68] },
|
|
890
|
+
]}
|
|
891
|
+
/>
|
|
892
|
+
<DatabaseNode
|
|
893
|
+
ex={460}
|
|
894
|
+
ey={380}
|
|
895
|
+
compactOffset={{ x: 30, y: -20 }}
|
|
896
|
+
zIndex={7}
|
|
897
|
+
name="DB-01"
|
|
898
|
+
subLabel="PRIMARY"
|
|
899
|
+
status={dbStatus ?? "online"}
|
|
900
|
+
capacity={dbCapacity ?? 55}
|
|
901
|
+
alert={{ offsetX: 160, offsetY: -60, align: "right" }}
|
|
902
|
+
/>
|
|
903
|
+
</Service>
|
|
904
|
+
);
|
|
905
|
+
}
|
|
906
|
+
```
|
|
907
|
+
|
|
908
|
+
---
|
|
909
|
+
|
|
910
|
+
## DatacenterView — topology / geography map
|
|
911
|
+
|
|
912
|
+
SVG-based **network topology** (grid) or optional **geographic outline** (consumer-supplied SVG path `d`), CSS **3D building** markers, animated links, and **drill-down** into a nested `AIOPsDashboard` when the user selects a site or building.
|
|
913
|
+
|
|
914
|
+
### Data model
|
|
915
|
+
|
|
916
|
+
- **`DatacenterBuildingConfig`** — one marker on the map (`id`, `name`, `subtitle`, `x` / `y` as **percent** of the 800×600 scene, `status`, `metrics`, `services`, `renderServices`, `variant`, optional `brand`, `isExternal`).
|
|
917
|
+
- **`siteId`** — optional; multiple buildings with the same `siteId` share **one marker**, **combined metrics** (sums / averages for PUE, temperature, uptime), and a **multi-building cluster** visualization (each building’s `variant` is shown). Optional **`siteLabels`** (`Record<string, { label: string; subtitle?: string }>`) overrides auto-generated titles.
|
|
918
|
+
- **`DatacenterConnection`** — `from` / `to` endpoint ids (building `id` or `siteId`), `throughput` label, optional `isExternal`.
|
|
919
|
+
- **`DatacenterMetrics`** — numeric KPIs used on markers and for aggregation.
|
|
920
|
+
|
|
921
|
+
### Mock metrics
|
|
922
|
+
|
|
923
|
+
Pass **`dataCenters`** with embedded **`metrics`**. No `DataProvider` required.
|
|
924
|
+
|
|
925
|
+
### PromQL (live) metrics on markers
|
|
926
|
+
|
|
927
|
+
1. Wrap the tree in **`DataProvider`** with `config.queries` including every query used by **`metricBindings`**, collected via **`extractDatacenterMetricQueries(metricBindings)`** (and merge with queries for any nested `AIOPsDashboard` if you use `aiOpsDashboardProps`).
|
|
928
|
+
2. Pass **`metricBindings`**: `Record<buildingId, Partial<Record<keyof DatacenterMetrics, DataBinding>>>` — same **`DataBinding`** shape as service-level bindings (`string` or `{ query, transform? }`).
|
|
929
|
+
3. **`DatacenterView`** calls **`useAIOpsDataOptional()`** and merges transformed numbers over each building’s static `metrics` (site-level rows aggregate the merged per-building values).
|
|
930
|
+
|
|
931
|
+
This path is **independent** of `AIOPsDashboard`’s **`dataBindings`** (which key off **service `name`** on carousel children).
|
|
932
|
+
|
|
933
|
+
### Drill-down dashboard
|
|
934
|
+
|
|
935
|
+
**`aiOpsDashboardProps`** is spread onto the inner **`AIOPsDashboard`**; **`services`**, **`theme`**, **`children`** (from `renderServices()`), and branding are forced from the selected building so the map stays consistent. Use **`aiOpsDashboardProps`** for **`liveData`**, **`dataEndpoint`**, **`dataBindings`**, **`serviceDataBindings`**, etc., for **service-level** PromQL inside the opened datacenter.
|
|
936
|
+
|
|
937
|
+
### Geography (optional)
|
|
938
|
+
|
|
939
|
+
**`showGeography`** and **`geography: { outlinePathD, referencePoints? }`** — the package does **not** ship country assets; the app parses or provides an SVG path `d` string (see `example/SaudiMapView.tsx`).
|
|
940
|
+
|
|
941
|
+
### DatacenterViewProps (reference)
|
|
942
|
+
|
|
943
|
+
| Prop | Type | Default | Notes |
|
|
944
|
+
|------|------|---------|--------|
|
|
945
|
+
| `dataCenters` | `DatacenterBuildingConfig[]` | (required) | Mock baseline metrics in each config; merged with live values when `metricBindings` + `DataProvider` present |
|
|
946
|
+
| `connections` | `DatacenterConnection[]` | `[]` | Link lines between building or site ids |
|
|
947
|
+
| `metricBindings` | `DatacenterMetricBindings` | — | Building **id** → metric field → PromQL `DataBinding`; needs `DataProvider` + `extractDatacenterMetricQueries` |
|
|
948
|
+
| `dataTransform` | `(raw: unknown) => unknown` | `defaultDataTransform` | Applied to each binding unless overridden per binding |
|
|
949
|
+
| `geography` | `DatacenterGeography` | — | `outlinePathD` + optional `referencePoints` (SVG coords) |
|
|
950
|
+
| `showGeography` | `boolean` | `false` | When true, draws outline + reference points |
|
|
951
|
+
| `mapTitle` | `string` | `"Geography — Operations"` | Header when `showGeography` |
|
|
952
|
+
| `topologyTitle` | `string` | `"Network topology"` | Header when not showing geography |
|
|
953
|
+
| `topologyAffiliatesLabel` | `string` | `"AFFILIATES"` | Label in topology-only mode (affiliates zone) |
|
|
954
|
+
| `brandText` | `string` | `"AIOps"` | Header brand |
|
|
955
|
+
| `headerTag` | `string` | `"COMMAND CENTER"` | Corner tag |
|
|
956
|
+
| `initialBuildingId` | `string` | — | Building `id` to open when `openDashboardOnMount` is true |
|
|
957
|
+
| `openDashboardOnMount` | `boolean` | `false` | Auto-zoom into `initialBuildingId` |
|
|
958
|
+
| `onNavigateEvents` | `() => void` | — | e.g. switch app view to event console |
|
|
959
|
+
| `theme` | `DashboardTheme` | — | Passed through to drill-down dashboard |
|
|
960
|
+
| `onThemeChange` | `(t) => void` | — | |
|
|
961
|
+
| `backgroundImage` / `lightBackgroundImage` | `string` | — | Drill-down `AIOPsDashboard` backgrounds |
|
|
962
|
+
| `aiOpsDashboardProps` | `Partial<AIOPsDashboardProps>` | — | Spread first; `services`, children, theme, branding overridden from selection |
|
|
963
|
+
| `defaultBuildingBrand` | `string` | `"AIOps"` | Fallback label on 3D building faces |
|
|
964
|
+
| `siteLabels` | `Record<string, DatacenterSiteLabels>` | — | Per-`siteId` titles for multi-building markers |
|
|
965
|
+
| `showMapScaleControls` | `boolean` | `true` | Size / hover sliders in header (map mode) |
|
|
966
|
+
| `mapFooter` | `ReactNode` | — | Rendered below the map when drill-down is **not** active |
|
|
967
|
+
|
|
968
|
+
### Minimal usage
|
|
969
|
+
|
|
970
|
+
```tsx
|
|
971
|
+
import "react-dashstream/dist/index.css";
|
|
972
|
+
import { DatacenterView } from "react-dashstream";
|
|
973
|
+
import type { DatacenterBuildingConfig, DatacenterConnection } from "react-dashstream";
|
|
974
|
+
|
|
975
|
+
const dataCenters: DatacenterBuildingConfig[] = [
|
|
976
|
+
/* id, x, y (%), metrics, services, renderServices, variant, siteId? … */
|
|
977
|
+
];
|
|
978
|
+
const connections: DatacenterConnection[] = [];
|
|
979
|
+
|
|
980
|
+
<DatacenterView dataCenters={dataCenters} connections={connections} />;
|
|
981
|
+
```
|
|
982
|
+
|
|
983
|
+
---
|
|
984
|
+
|
|
985
|
+
## EventView — Operations Event Console
|
|
986
|
+
|
|
987
|
+
Table component for displaying infrastructure events from a live API. Uses the same `access-key` / `access-secret-key` authentication and holographic theme as the 3D dashboard. No built-in default data — requires either `apiConfig` (to fetch from an API) or `events` (pre-fetched array).
|
|
988
|
+
|
|
989
|
+
### API mode (primary usage)
|
|
990
|
+
|
|
991
|
+
```tsx
|
|
992
|
+
import "react-dashstream/dist/index.css";
|
|
993
|
+
import { EventView } from "react-dashstream";
|
|
994
|
+
import type { EventApiConfig } from "react-dashstream";
|
|
995
|
+
|
|
996
|
+
const apiConfig: EventApiConfig = {
|
|
997
|
+
baseUrl: "https://your-monitoring-server.example.com",
|
|
998
|
+
payload: { filter: {}, sortBy: "date_reception", sortOrder: "DESC" },
|
|
999
|
+
fieldMapping: {
|
|
1000
|
+
id: "mc_ueid",
|
|
1001
|
+
occurrence: "date_reception",
|
|
1002
|
+
severityLastModified: "severity_last_modified",
|
|
1003
|
+
severity: "severity",
|
|
1004
|
+
owner: "owner",
|
|
1005
|
+
class: "class",
|
|
1006
|
+
host: "mc_host",
|
|
1007
|
+
message: "msg",
|
|
1008
|
+
remedySupportGroup: "ara_remedy_support_group",
|
|
1009
|
+
incidentId: "ara_incident_id",
|
|
1010
|
+
smsStatus: "ara_sms_status",
|
|
1011
|
+
onCallNumber: "ara_on_call_number",
|
|
1012
|
+
hostedApplication: "ara_hosted_application",
|
|
1013
|
+
monitoringCategory: "ara_hosted_app_monitoring",
|
|
1014
|
+
applicationSupportUnit: "ara_application_support_unit",
|
|
1015
|
+
},
|
|
1016
|
+
};
|
|
1017
|
+
|
|
1018
|
+
<EventView apiConfig={apiConfig} />;
|
|
1019
|
+
```
|
|
1020
|
+
|
|
1021
|
+
### How it works
|
|
1022
|
+
|
|
1023
|
+
1. Shows credentials modal (or reuses DataProvider credentials if inside `AIOPsDashboard`)
|
|
1024
|
+
2. Sends `POST {baseUrl}/tsws/monitoring/api/v1.0/events/search` with the payload as JSON body
|
|
1025
|
+
3. Auth via headers: `access-key` and `access-secret-key`
|
|
1026
|
+
4. Expects response: `{ eventSeverityCount: {...}, totalCount: N, eventList: [{...}] }`
|
|
1027
|
+
5. Maps each object in `eventList` to `AIOpsEvent` using `fieldMapping`
|
|
1028
|
+
6. Maps severity strings via `severityMap` (default: `CRITICAL→Critical`, `MAJOR→Major`, `MINOR→Minor`)
|
|
1029
|
+
7. Polls on `refreshInterval` (default 60s)
|
|
1030
|
+
|
|
1031
|
+
### Props
|
|
1032
|
+
|
|
1033
|
+
| Prop | Type | Default | Notes |
|
|
1034
|
+
| -------------------- | ---------------- | ----------------- | -------------------------------------------------- |
|
|
1035
|
+
| `apiConfig` | `EventApiConfig` | — | Required for API mode |
|
|
1036
|
+
| `events` | `AIOpsEvent[]` | — | Pre-fetched events (skips API calls) |
|
|
1037
|
+
| `credentials` | `Credentials` | — | Explicit creds; falls back to DataProvider → modal |
|
|
1038
|
+
| `columnWidthsCookie` | `string` | `"ev_col_widths"` | Cookie name for persisting column widths |
|
|
1039
|
+
| `title` | `string` | `"Event Console"` | Header title |
|
|
1040
|
+
| `theme` | `DashboardTheme` | — | Optional override; else `ThemeProvider` / default |
|
|
1041
|
+
|
|
1042
|
+
### EventApiConfig
|
|
1043
|
+
|
|
1044
|
+
```ts
|
|
1045
|
+
interface EventApiConfig {
|
|
1046
|
+
baseUrl: string; // "https://monitoring.example.com"
|
|
1047
|
+
endpoint?: string; // default: "/tsws/monitoring/api/v1.0/events/search"
|
|
1048
|
+
payload: Record<string, unknown>; // POST body
|
|
1049
|
+
fieldMapping: EventFieldMapping; // maps API keys → AIOpsEvent keys
|
|
1050
|
+
severityMap?: Record<string, EventSeverity>; // default: { CRITICAL, MAJOR, MINOR }
|
|
1051
|
+
refreshInterval?: number; // ms, default 60000
|
|
1052
|
+
}
|
|
1053
|
+
```
|
|
1054
|
+
|
|
1055
|
+
### EventFieldMapping
|
|
1056
|
+
|
|
1057
|
+
Maps every `AIOpsEvent` property to the API response field name. All 15 keys required:
|
|
1058
|
+
|
|
1059
|
+
```ts
|
|
1060
|
+
type EventFieldMapping = Record<keyof AIOpsEvent, string>;
|
|
1061
|
+
```
|
|
1062
|
+
|
|
1063
|
+
### AIOpsEvent interface
|
|
1064
|
+
|
|
1065
|
+
```ts
|
|
1066
|
+
interface AIOpsEvent {
|
|
1067
|
+
id: string;
|
|
1068
|
+
occurrence: string;
|
|
1069
|
+
severityLastModified: string;
|
|
1070
|
+
severity: "Minor" | "Major" | "Critical";
|
|
1071
|
+
owner: string;
|
|
1072
|
+
class: "Self-monitoring" | "SCOM" | "Situation" | "Alarm" | "Event";
|
|
1073
|
+
host: string;
|
|
1074
|
+
message: string;
|
|
1075
|
+
remedySupportGroup: string;
|
|
1076
|
+
incidentId: string;
|
|
1077
|
+
smsStatus: "" | "SUCCESS" | "FAILED";
|
|
1078
|
+
onCallNumber: string;
|
|
1079
|
+
hostedApplication: string;
|
|
1080
|
+
monitoringCategory: "24/7" | "Office Hours";
|
|
1081
|
+
applicationSupportUnit: string;
|
|
1082
|
+
}
|
|
1083
|
+
```
|
|
1084
|
+
|
|
1085
|
+
### Credential resolution order
|
|
1086
|
+
|
|
1087
|
+
1. `credentials` prop (if provided)
|
|
1088
|
+
2. `DataProvider` context credentials (when inside `AIOPsDashboard` with `liveData`)
|
|
1089
|
+
3. Built-in credentials modal (same UI as the 3D dashboard)
|
|
1090
|
+
|
|
1091
|
+
### Severity colors
|
|
1092
|
+
|
|
1093
|
+
- **Minor** → `#ffb800` (amber)
|
|
1094
|
+
- **Major** → `#ff6600` (orange)
|
|
1095
|
+
- **Critical** → `#ff2255` (red)
|
|
1096
|
+
|
|
1097
|
+
### Features
|
|
1098
|
+
|
|
1099
|
+
- Live API polling with configurable interval and manual refresh button
|
|
1100
|
+
- Configurable field mapping — any API response shape can be mapped
|
|
1101
|
+
- Shared auth — reuses DataProvider credentials when available
|
|
1102
|
+
- Severity filter chips with live counts
|
|
1103
|
+
- Free-text search across message, host, owner, incident ID
|
|
1104
|
+
- Sortable columns (click header: asc → desc → none)
|
|
1105
|
+
- Infinite scroll — all matching events in a single scrollable table
|
|
1106
|
+
- Resizable columns — drag column edges; widths persist in cookies
|
|
1107
|
+
- Loading spinner, error badge, last-refresh timestamp
|
|
1108
|
+
- Light / dark table chrome (via `ThemeProvider` or `theme` prop), scan-line header, severity badges
|
|
1109
|
+
|
|
1110
|
+
### Generating an EventApiConfig from the AI
|
|
1111
|
+
|
|
1112
|
+
When asked to set up EventView for a new API, generate the config like this:
|
|
1113
|
+
|
|
1114
|
+
1. Set `baseUrl` to the server's protocol + host + port
|
|
1115
|
+
2. Set `endpoint` only if it differs from the default `/tsws/monitoring/api/v1.0/events/search`
|
|
1116
|
+
3. Build `payload` based on the API's expected POST body schema
|
|
1117
|
+
4. Build `fieldMapping` by asking the user which API field maps to each `AIOpsEvent` property
|
|
1118
|
+
5. Set `severityMap` only if the API uses non-standard severity values
|
|
1119
|
+
|
|
1120
|
+
---
|
|
1121
|
+
|
|
1122
|
+
## Build and development
|
|
1123
|
+
|
|
1124
|
+
```bash
|
|
1125
|
+
npm run dev # Vite dev server (loads example/Dashboard.tsx)
|
|
1126
|
+
npm run build # TypeScript check + Vite library build
|
|
1127
|
+
npm run build:lib # Vite library build only
|
|
1128
|
+
npm run preview # Preview production build
|
|
1129
|
+
```
|
|
1130
|
+
|
|
1131
|
+
Output: `dist/index.js` (ESM), `dist/index.d.ts`, `dist/index.css`.
|
|
1132
|
+
|
|
1133
|
+
---
|
|
1134
|
+
|
|
1135
|
+
## Common pitfalls
|
|
1136
|
+
|
|
1137
|
+
1. **Missing CSS import** — Always import `react-dashstream/dist/index.css`.
|
|
1138
|
+
2. **Name mismatch** — `name` on child components must exactly match keys in `dataBindings`, `serviceDataBindings`, and `ServiceMeta.name`.
|
|
1139
|
+
3. **Credentials are in-memory only** — Page refresh requires re-entering credentials.
|
|
1140
|
+
4. **Default transform is plain-text** — For JSON endpoints, provide a custom `dataTransform`.
|
|
1141
|
+
5. **Polling only** — No WebSocket/SSE support; uses `setInterval`.
|
|
1142
|
+
6. **`visibleAtPhase` matters** — Nodes without proper values won't animate during expansion.
|
|
1143
|
+
7. **Connection coordinates** — `from`/`to` arrays use `[x, y]` matching `ex`/`ey` of connected nodes.
|
|
1144
|
+
8. **`dialogMetrics` replaces defaults** — When provided, all default gauges (CPU/Memory/Storage) are removed.
|
|
1145
|
+
9. **`subComponents` replaces defaults** — When provided, all auto-generated sub-components are removed.
|
|
1146
|
+
10. **`graphSeries` replaces defaults** — When provided, all auto-generated sparklines are removed.
|
|
1147
|
+
11. **Event bridge matching** — Node `name` must match event `host` (case-insensitive) for `eventApiConfig` to highlight nodes automatically.
|
|
1148
|
+
12. **Theme context** — `EventView` and `CredentialsModal` use `useTheme()`. Without `ThemeProvider`, context defaults to `"dark"`. Wrap the app (or use `EventView`’s `theme` prop) so light dashboards are not paired with a dark event console or lock screen.
|