react-dashstream 0.0.8 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dashstream-skill.md +842 -0
  2. package/package.json +3 -2
@@ -0,0 +1,842 @@
1
+ # React DashStream — AI Coding Assistant Skill
2
+
3
+ > **Package**: `react-dashstream` (npm)
4
+ > **Version**: 0.0.4
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
+ ## Architecture
39
+
40
+ ```
41
+ AIOPsDashboard ← Shell: header, state, optional DataProvider
42
+ └─ Carousel ← 3D orbit, rotation, hosts dialogs
43
+ └─ Service ← Per-service container, connections, holo base
44
+ ├─ ServerNode ← Compound: ServiceNode + Server3D
45
+ ├─ DatabaseNode ← Compound: ServiceNode + Database3D
46
+ ├─ WebDispatcherNode ← Compound: ServiceNode + WebDispatcher3D
47
+ ├─ MessageServerNode ← Compound: ServiceNode + MessageServer3D
48
+ ├─ HumanNode ← Compound: ServiceNode + Human3D (SVG)
49
+ ├─ SvgConnection ← Animated dashed topology line
50
+ ├─ SyncBridge ← DB replication indicator
51
+ ├─ NodeCallout ← Alert callout (auto from thresholds)
52
+ └─ HoloBase ← Neon platform (auto-rendered)
53
+
54
+ ServiceDialog ← Service-level KPI panel (auto on expand)
55
+ ComponentDialog ← Drill-down with internals + graphs
56
+ ├─ HistoricalGraphPanel ← Sparkline charts
57
+ └─ CPU3D / Memory3D / DriveBay3D / NetworkBlock3D / ThreadPool3D / Platter3D / Port3D
58
+
59
+ DataProvider ← Polling engine + credentials modal
60
+ ```
61
+
62
+ ### Source layout
63
+
64
+ ```
65
+ src/
66
+ ├── index.ts # Public API barrel
67
+ ├── AIOPsDashboard.tsx # Dashboard shell + live-data wiring
68
+ ├── types.ts # Shared topology/drill-down types
69
+ ├── theme.ts # Status tokens, holo palette, 3D face helpers
70
+ ├── styles.css / index.css # Library + dashboard styles
71
+ ├── data/
72
+ │ ├── DataProvider.tsx # Polling engine, context, hooks
73
+ │ ├── CredentialsModal.tsx # Auth prompt UI
74
+ │ └── index.ts
75
+ ├── components/ # ~30 UI components
76
+ │ ├── Carousel.tsx, Service.tsx, ServiceNode.tsx
77
+ │ ├── ServerNode.tsx, DatabaseNode.tsx, WebDispatcherNode.tsx, etc.
78
+ │ ├── Server3D.tsx, Database3D.tsx, etc.
79
+ │ ├── ServiceDialog.tsx, ComponentDialog.tsx
80
+ │ ├── Internal3DComponents.tsx, HistoricalGraphPanel.tsx
81
+ │ ├── ComponentDrillView.tsx, SvgConnection.tsx, SyncBridge.tsx
82
+ │ ├── NodeCallout.tsx, HoloBase.tsx, CarouselContext.ts
83
+ │ └── index.ts
84
+ ├── services/
85
+ │ ├── SAPService.tsx, ExchangeService.tsx
86
+ │ ├── sapSubComponents.tsx
87
+ │ └── index.ts
88
+ example/
89
+ ├── Dashboard.tsx
90
+ └── services/
91
+ ```
92
+
93
+ ---
94
+
95
+ ## Complete data flow reference
96
+
97
+ There are **9 distinct data paths** in this package. Understanding them is critical for building live dashboards.
98
+
99
+ ### 1. Data bindings — live props injected into service components
100
+
101
+ `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.
102
+
103
+ ```ts
104
+ type DataBinding = string | { query: string; transform?: (raw: unknown) => unknown };
105
+ type DataBindings = Record<string, Record<string, DataBinding>>;
106
+ ```
107
+
108
+ - Bare string → uses global `dataTransform` (defaults to numeric parsing)
109
+ - Object `{ query, transform }` → uses per-binding transform
110
+ - Service name key must match child's `name` prop **exactly**
111
+
112
+ ```tsx
113
+ const dataBindings: DataBindings = {
114
+ "My Service": {
115
+ cpuLoad: 'cpu_usage{instance="srv-01"}', // bare string → number
116
+ memLoad: 'memory_usage{instance="srv-01"}', // bare string → number
117
+ status: {
118
+ // object → custom transform
119
+ query: 'cpu_usage{instance="srv-01"}',
120
+ transform: (raw) => {
121
+ const n = Number(raw);
122
+ if (n >= 85) return "critical";
123
+ if (n >= 70) return "warning";
124
+ return "online";
125
+ },
126
+ },
127
+ dbCapacity: 'disk_capacity{instance="db-01"}',
128
+ dbStatus: { query: 'disk_capacity{instance="db-01"}', transform: statusFromValue },
129
+ },
130
+ };
131
+ ```
132
+
133
+ #### Multi-component services
134
+
135
+ 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.
136
+
137
+ ```tsx
138
+ interface ServiceXProps {
139
+ name: string;
140
+ status?: ComponentStatus;
141
+ srv1CpuLoad?: number;
142
+ srv1MemLoad?: number;
143
+ srv1Status?: ComponentStatus;
144
+ srv2CpuLoad?: number;
145
+ srv2MemLoad?: number;
146
+ srv2Status?: ComponentStatus;
147
+ srv3CpuLoad?: number;
148
+ srv3MemLoad?: number;
149
+ srv3Status?: ComponentStatus;
150
+ dbCapacity?: number;
151
+ dbStatus?: ComponentStatus;
152
+ }
153
+
154
+ function ServiceX({
155
+ name, status = "online",
156
+ srv1CpuLoad = 54, srv1MemLoad = 58, srv1Status = "online",
157
+ srv2CpuLoad = 63, srv2MemLoad = 66, srv2Status = "online",
158
+ srv3CpuLoad = 78, srv3MemLoad = 71, srv3Status = "online",
159
+ dbCapacity = 68, dbStatus = "online",
160
+ }: ServiceXProps) {
161
+ return (
162
+ <Service name={name} status={status} connections={[/* ... */]}>
163
+ <ServerNode name="SRV-X1" status={srv1Status}
164
+ cpuLoad={srv1CpuLoad} memLoad={srv1MemLoad} ... />
165
+ <ServerNode name="SRV-X2" status={srv2Status}
166
+ cpuLoad={srv2CpuLoad} memLoad={srv2MemLoad} ... />
167
+ <ServerNode name="SRV-X3" status={srv3Status}
168
+ cpuLoad={srv3CpuLoad} memLoad={srv3MemLoad} ... />
169
+ <DatabaseNode name="DB-X1" status={dbStatus}
170
+ capacity={dbCapacity} ... />
171
+ </Service>
172
+ );
173
+ }
174
+ ```
175
+
176
+ Bind each prefixed prop individually:
177
+
178
+ ```tsx
179
+ dataBindings={{
180
+ ServiceX: {
181
+ status: { query: 'status{instance="svcx"}', transform: statusFromValue },
182
+ srv1CpuLoad: 'cpu_usage{instance="srvx-01"}',
183
+ srv1MemLoad: 'memory_usage{instance="srvx-01"}',
184
+ srv1Status: { query: 'status{instance="srvx-01"}', transform: statusFromValue },
185
+ srv2CpuLoad: 'cpu_usage{instance="srvx-02"}',
186
+ srv2MemLoad: 'memory_usage{instance="srvx-02"}',
187
+ srv2Status: { query: 'status{instance="srvx-02"}', transform: statusFromValue },
188
+ srv3CpuLoad: 'cpu_usage{instance="srvx-03"}',
189
+ srv3MemLoad: 'memory_usage{instance="srvx-03"}',
190
+ srv3Status: { query: 'status{instance="srvx-03"}', transform: statusFromValue },
191
+ dbCapacity: 'disk_capacity{instance="dbx-01"}',
192
+ dbStatus: { query: 'status{instance="dbx-01"}', transform: statusFromValue },
193
+ },
194
+ }}
195
+ ```
196
+
197
+ Use a consistent convention like `srv1CpuLoad`, `srv2CpuLoad`. The service component maps each prefixed prop to the correct node.
198
+
199
+ ### 2. Service dialog — static ServiceMeta metrics
200
+
201
+ The **ServiceDialog** panel shows KPIs when a service is expanded. Static metrics are passed via `ServiceMeta`:
202
+
203
+ ```tsx
204
+ const services: ServiceMeta[] = [
205
+ {
206
+ name: "My Service",
207
+ status: "online",
208
+ metrics: [
209
+ { label: "Uptime", value: "99.99%", color: "#00ff88" },
210
+ { label: "Avg Latency", value: "8ms", color: "#00e5ff" },
211
+ ],
212
+ alerts: [
213
+ { level: "info", message: "All Systems Nominal" },
214
+ { level: "warning", message: "High CPU on SRV-01" },
215
+ { level: "critical", message: "DB connection pool exhausted" },
216
+ ],
217
+ },
218
+ ];
219
+ ```
220
+
221
+ ### 3. Service dialog — live serviceDataBindings
222
+
223
+ Replace static metrics with live-fetched values using `serviceDataBindings`:
224
+
225
+ ```tsx
226
+ serviceDataBindings={{
227
+ "My Service": [
228
+ { label: "CPU Load", query: 'cpu_usage{instance="srv-01"}', unit: "%", color: "#00e5ff" },
229
+ { label: "Memory", query: 'memory_usage{instance="srv-01"}', unit: "%", color: "#bb55ff" },
230
+ { label: "Disk", query: 'disk_capacity{instance="db-01"}', unit: "%", color: "#ff8c00" },
231
+ ],
232
+ }}
233
+ ```
234
+
235
+ ```ts
236
+ interface ServiceMetricBinding {
237
+ label: string; // Row label
238
+ query: string; // PromQL query
239
+ unit?: string; // Suffix (e.g. "%", "ms")
240
+ color?: string; // Accent color
241
+ transform?: (raw: unknown) => string; // Custom formatter
242
+ }
243
+ ```
244
+
245
+ When provided, live values **replace** static `ServiceMeta.metrics` for that service.
246
+
247
+ ### 4. Component dialog — default gauges
248
+
249
+ The **ComponentDialog** appears when clicking a node. Default gauges are derived from node type:
250
+
251
+ - **Server**: CPU (from `cpuLoad`), Memory (from `memLoad`), Storage
252
+ - **Database**: Capacity (from `capacity`), Memory, Storage
253
+ - **Dispatcher**: Traffic (from `traffic`), Memory, Storage
254
+ - **Message Server**: Queue (from `queueDepth`), Memory, Storage
255
+
256
+ Default thresholds: warn at 70, critical at 85.
257
+
258
+ ### 5. Component dialog — custom dialogMetrics
259
+
260
+ Override default gauges with `dialogMetrics` on any compound node:
261
+
262
+ ```tsx
263
+ <ServerNode
264
+ name="SRV-01"
265
+ status="online"
266
+ cpuLoad={67}
267
+ memLoad={72}
268
+ ex={200}
269
+ ey={380}
270
+ compactOffset={{ x: -30, y: -20 }}
271
+ zIndex={8}
272
+ dialogMetrics={[
273
+ { id: "cpu", label: "CPU", sublabel: "PROCESSOR", value: 67, unit: "%" },
274
+ { id: "mem", label: "MEMORY", sublabel: "HEAP USAGE", value: 72, unit: "%" },
275
+ { id: "iops", label: "IOPS", sublabel: "DISK OPS", value: 45, unit: "k/s", icon: "disk" },
276
+ {
277
+ id: "threads",
278
+ label: "THREADS",
279
+ sublabel: "ACTIVE",
280
+ value: 82,
281
+ unit: "%",
282
+ warnAt: 60,
283
+ critAt: 80,
284
+ icon: "cpu",
285
+ },
286
+ ]}
287
+ />
288
+ ```
289
+
290
+ ```ts
291
+ interface ComponentDialogMetric {
292
+ id: string; // Unique key
293
+ label: string; // Upper label
294
+ sublabel: string; // Lower label
295
+ value: number; // 0–100
296
+ unit?: string; // Default "%"
297
+ icon?: "cpu" | "mem" | "disk"; // Default "cpu"
298
+ warnAt?: number; // Default 70
299
+ critAt?: number; // Default 85
300
+ color?: string; // Override bar color (bypasses threshold coloring)
301
+ }
302
+ ```
303
+
304
+ All compound nodes accept `dialogMetrics`: `ServerNode`, `DatabaseNode`, `WebDispatcherNode`, `MessageServerNode`.
305
+
306
+ **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:
307
+
308
+ ```tsx
309
+ // Service component — accepts individual metric props, builds dialogMetrics from them
310
+ function MyService({ name, status = "online", cpuLoad = 42, memLoad = 60, iops = 20 }: any) {
311
+ return (
312
+ <Service
313
+ name={name}
314
+ status={status}
315
+ connections={
316
+ [
317
+ /* ... */
318
+ ]
319
+ }
320
+ >
321
+ <ServerNode
322
+ name="SRV-01"
323
+ status={status}
324
+ cpuLoad={cpuLoad}
325
+ memLoad={memLoad}
326
+ ex={200}
327
+ ey={380}
328
+ compactOffset={{ x: -30, y: -20 }}
329
+ zIndex={8}
330
+ dialogMetrics={[
331
+ { id: "cpu", label: "CPU", sublabel: "PROCESSOR", value: cpuLoad },
332
+ { id: "mem", label: "MEMORY", sublabel: "HEAP", value: memLoad },
333
+ {
334
+ id: "iops",
335
+ label: "IOPS",
336
+ sublabel: "DISK OPS",
337
+ value: iops,
338
+ icon: "disk",
339
+ warnAt: 50,
340
+ critAt: 80,
341
+ },
342
+ ]}
343
+ />
344
+ </Service>
345
+ );
346
+ }
347
+
348
+ // Dashboard — bind each prop to a query
349
+ <AIOPsDashboard
350
+ liveData
351
+ dataEndpoint="..."
352
+ dataBindings={{
353
+ "My Service": {
354
+ cpuLoad: 'cpu_usage{instance="srv-01"}',
355
+ memLoad: 'memory_usage{instance="srv-01"}',
356
+ iops: 'disk_iops{instance="srv-01"}',
357
+ status: { query: 'cpu_usage{instance="srv-01"}', transform: statusFromValue },
358
+ },
359
+ }}
360
+ >
361
+ <MyService name="My Service" />
362
+ </AIOPsDashboard>;
363
+ ```
364
+
365
+ 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.
366
+
367
+ ### 6. Alerts — automatic threshold detection
368
+
369
+ Nodes auto-render `NodeCallout` alerts when metrics breach thresholds:
370
+
371
+ - **Warning** at 70% → orange callout
372
+ - **Critical** at 85% → red callout
373
+
374
+ Sources (checked in priority order):
375
+
376
+ 1. `dialogMetrics` values vs their `warnAt`/`critAt`
377
+ 2. Context values (`cpuLoad`, `memLoad`, `traffic`, `queueDepth`, `capacity`) vs default thresholds
378
+
379
+ ```tsx
380
+ // Auto-alert from cpuLoad > 85
381
+ <ServerNode cpuLoad={92} memLoad={64}
382
+ alert={{ offsetX: -160, offsetY: -60, align: "left" }}
383
+ ... />
384
+
385
+ // Custom message
386
+ <ServerNode cpuLoad={92}
387
+ alert={{ msg: "CPU overload — scale out", offsetX: -160, offsetY: -60, align: "left" }}
388
+ ... />
389
+
390
+ // Custom thresholds via dialogMetrics
391
+ <ServerNode
392
+ dialogMetrics={[
393
+ { id: "cpu", label: "CPU", sublabel: "PROCESSOR", value: 67,
394
+ warnAt: 50, critAt: 75 }, // Alert at 67 because critAt=75
395
+ ]}
396
+ alert={{ offsetX: -160, offsetY: -60, align: "left" }}
397
+ ... />
398
+ ```
399
+
400
+ Alert `align` options: `"left"`, `"right"`, `"top"`, `"bottom"`.
401
+
402
+ Alert prop shape:
403
+
404
+ ```ts
405
+ alert?: {
406
+ msg?: string; // Custom message (auto-generated if omitted)
407
+ offsetX?: number; // X offset from node (default 110)
408
+ offsetY?: number; // Y offset from node (default -30)
409
+ align?: "left" | "right" | "top" | "bottom"; // Default "right"
410
+ internalRef?: string; // Sub-component ID
411
+ }
412
+ ```
413
+
414
+ ### 7. Drill-down internals — custom subComponents
415
+
416
+ When clicking a node, the drill-down shows internal 3D sub-components. Default sub-components are auto-generated per type. Override with `subComponents`:
417
+
418
+ ```tsx
419
+ import { CPU3D, Memory3D, DriveBay3D, ThreadPool3D, NetworkBlock3D, Platter3D, Port3D } from "react-dashstream";
420
+ import type { SubComponentConfig } from "react-dashstream";
421
+
422
+ const internals: SubComponentConfig[] = [
423
+ { id: "cpu-0", label: "CPU-0", status: "online",
424
+ element: <CPU3D label="CPU-0" load={67} color="#00e5ff" /> },
425
+ { id: "heap", label: "HEAP", status: "warning",
426
+ element: <Memory3D label="HEAP" usedPercent={92} color="#8855ee" status="warning" /> },
427
+ { id: "drive", label: "DRIVE-0", status: "online",
428
+ element: <DriveBay3D label="DRIVE-0" color="#00e5ff" activity={true} /> },
429
+ { id: "threads", label: "THREADS", status: "online",
430
+ element: <ThreadPool3D label="THREADS" color="#00e5ff" /> },
431
+ { id: "net", label: "NET", status: "online",
432
+ element: <NetworkBlock3D label="NET" color="#00e5ff" /> },
433
+ ];
434
+
435
+ <ServerNode subComponents={internals} ... />
436
+ ```
437
+
438
+ ```ts
439
+ interface SubComponentConfig {
440
+ id: string; // Unique key
441
+ label: string; // Display name
442
+ status: ComponentStatus; // LED color
443
+ detail?: string; // Fault description
444
+ element: ReactNode; // 3D element to render
445
+ }
446
+ ```
447
+
448
+ All compound nodes accept `subComponents`.
449
+
450
+ ### 8. Graph series — custom sparklines
451
+
452
+ The drill-down's historical panel shows sparkline charts. Default graphs are auto-generated. Override with `graphSeries`:
453
+
454
+ ```tsx
455
+ import type { GraphSeries } from "react-dashstream";
456
+
457
+ const graphs: GraphSeries[] = [
458
+ { id: "cpu", label: "CPU-0", unit: "%", color: "#00e5ff", data: [45, 52, 67, 71, 68, 55] },
459
+ { id: "mem", label: "HEAP", unit: "%", color: "#8855ee", data: [60, 65, 72, 78, 82, 75] },
460
+ { id: "iops", label: "DISK", unit: "k/s", color: "#ff8c00", data: [12, 15, 22, 18, 25, 20] },
461
+ ];
462
+
463
+ <ServerNode graphSeries={graphs} ... />
464
+ ```
465
+
466
+ ```ts
467
+ interface GraphSeries {
468
+ id: string; // Unique key
469
+ label: string; // Label above sparkline
470
+ unit: string; // Suffix
471
+ color: string; // Line color
472
+ data: number[]; // Points (most recent last)
473
+ }
474
+ ```
475
+
476
+ All compound nodes accept `graphSeries`.
477
+
478
+ ### 9. Data hooks — programmatic access
479
+
480
+ Access live data context anywhere inside the dashboard:
481
+
482
+ ```tsx
483
+ import { useAIOpsData, useAIOpsDataOptional, useQueryResult } from "react-dashstream";
484
+
485
+ function CustomWidget() {
486
+ const { data, isRefreshing, lastRefreshError, lastRefreshTime, credentialsSet } = useAIOpsData();
487
+ const cpu = useQueryResult('cpu_usage{instance="srv-01"}');
488
+ return <div>CPU: {String(cpu)}</div>;
489
+ }
490
+ ```
491
+
492
+ | Hook | Returns | Throws? |
493
+ | ------------------------ | -------------------------- | ---------------------------- |
494
+ | `useAIOpsData()` | `DataContextValue` | Yes — outside `DataProvider` |
495
+ | `useAIOpsDataOptional()` | `DataContextValue \| null` | No |
496
+ | `useQueryResult(query)` | `unknown \| null` | Yes — outside `DataProvider` |
497
+
498
+ ```ts
499
+ interface DataContextValue {
500
+ data: Record<string, unknown>; // Raw responses keyed by query
501
+ isRefreshing: boolean;
502
+ lastRefreshError: string | null;
503
+ lastRefreshTime: Date | null;
504
+ credentialsSet: boolean;
505
+ setCredentials: (creds: Credentials) => void;
506
+ }
507
+ ```
508
+
509
+ ---
510
+
511
+ ## Exports
512
+
513
+ Everything below is exported from `react-dashstream`.
514
+
515
+ ### Default export
516
+
517
+ `AIOPsDashboard` — main dashboard shell component.
518
+
519
+ ### Compound nodes
520
+
521
+ `ServerNode`, `DatabaseNode`, `WebDispatcherNode`, `MessageServerNode`, `HumanNode`
522
+
523
+ ### Layout
524
+
525
+ `Carousel`, `Service`, `ServiceNode`
526
+
527
+ ### 3D models
528
+
529
+ `Server3D`, `Database3D`, `WebDispatcher3D`, `MessageServer3D`, `Human3D`
530
+
531
+ ### Internal 3D components (for drill-down)
532
+
533
+ `CPU3D`, `Memory3D`, `DriveBay3D`, `NetworkBlock3D`, `ThreadPool3D`, `Platter3D`, `Port3D`
534
+
535
+ ### Indicators and connections
536
+
537
+ `SvgConnection`, `SyncBridge`, `NodeCallout`, `HoloBase`
538
+
539
+ ### Dialogs
540
+
541
+ `ServiceDialog`, `ComponentDialog`, `HistoricalGraphPanel`, `ComponentDrillView`
542
+
543
+ ### Pre-built services
544
+
545
+ `SAPService`, `ExchangeService`
546
+
547
+ SAP helpers: `computeSAPServiceStatus`, `computeSAPDialogMetrics`, `computeSAPDialogAlerts`, `SAP_CONNECTIONS`
548
+
549
+ Exchange helpers: `computeExchangeServiceStatus`, `computeExchangeDialogMetrics`, `computeExchangeDialogAlerts`, `EXCHANGE_CONNECTIONS`
550
+
551
+ SAP sub-component helpers: `getServerSubComponents`, `getServerGraphSeries`, `getDispatcherSubComponents`, `getDispatcherGraphSeries`, `getMessageServerSubComponents`, `getMessageServerGraphSeries`, `getDatabaseSubComponents`, `getDatabaseGraphSeries`
552
+
553
+ ### Data layer
554
+
555
+ `DataProvider`, `useAIOpsData`, `useAIOpsDataOptional`, `useQueryResult`, `defaultDataTransform`
556
+
557
+ ### Theme
558
+
559
+ `STATUS_CFG`, `HOLO_CYAN` (`"#00e5ff"`), `HOLO_BLUE` (`"#0055cc"`), `HOLO_SURFACE`, `HOLO_GLASS`, `makeFaceStyles(W, H, D)`
560
+
561
+ ### Context hooks
562
+
563
+ `CarouselContext`, `CarouselItemContext`, `useCarouselContext`, `useCarouselItemContext`, `ServiceContext`
564
+
565
+ ### Type exports
566
+
567
+ `AIOPsDashboardProps`, `ServiceMeta`, `ServiceMetricBinding`, `ComponentStatus`, `StatusCfg`, `FaceName`, `Base3DProps`, `ComponentType`, `ComponentContext`, `ComponentDialogMetric`, `SubComponentConfig`, `GraphSeries`, `SelectedComponent`, `ConnectionConfig`, `ViewState`, `DataBinding`, `DataBindings`, `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`
568
+
569
+ ---
570
+
571
+ ## Key types quick reference
572
+
573
+ ### AIOPsDashboardProps
574
+
575
+ ```ts
576
+ interface AIOPsDashboardProps {
577
+ title?: string;
578
+ brandName?: string; // Default: "BUSAUD AIOps"
579
+ brandTag?: string; // Default: "3D MONITOR"
580
+ services?: ServiceMeta[];
581
+ backgroundImage?: string;
582
+ logoUrl?: string;
583
+ carouselSpeed?: number; // Default: 0.006
584
+ fontFamily?: string;
585
+ liveData?: boolean; // Default: false
586
+ dataEndpoint?: string;
587
+ dataBindings?: DataBindings;
588
+ dataTransform?: (raw: unknown) => unknown;
589
+ dataRefreshInterval?: number; // Default: 60000
590
+ serviceDataBindings?: Record<string, ServiceMetricBinding[]>;
591
+ children: React.ReactNode;
592
+ }
593
+ ```
594
+
595
+ ### ServiceMeta
596
+
597
+ ```ts
598
+ interface ServiceMeta {
599
+ name: string; // Must match child component name
600
+ status: ComponentStatus;
601
+ dbSync?: boolean; // Default: true
602
+ metrics?: ServiceDialogMetric[];
603
+ alerts?: ServiceDialogAlert[];
604
+ }
605
+
606
+ interface ServiceDialogMetric {
607
+ label: string;
608
+ value: string;
609
+ color: string;
610
+ }
611
+
612
+ interface ServiceDialogAlert {
613
+ level: "info" | "warning" | "critical";
614
+ message: string;
615
+ }
616
+ ```
617
+
618
+ ### ConnectionConfig
619
+
620
+ ```ts
621
+ interface ConnectionConfig {
622
+ from: [number, number];
623
+ to: [number, number];
624
+ visibleAtPhase?: number; // Default: 0
625
+ color?: string; // Default: "#00e5ff"
626
+ duration?: string; // Default: "1.2s"
627
+ }
628
+ ```
629
+
630
+ ### ComponentStatus
631
+
632
+ ```ts
633
+ type ComponentStatus = "online" | "warning" | "critical" | "offline";
634
+ ```
635
+
636
+ | Status | Color | Glow |
637
+ | ---------- | --------- | -------- |
638
+ | `online` | `#00e5ff` | cyan |
639
+ | `warning` | `#ff8c00` | orange |
640
+ | `critical` | `#ff2255` | red |
641
+ | `offline` | `#1e3a5a` | dim blue |
642
+
643
+ ---
644
+
645
+ ## Endpoint contract
646
+
647
+ | Aspect | Requirement |
648
+ | ------------ | -------------------------------------------------------------- |
649
+ | **Method** | `GET` |
650
+ | **URL** | `<dataEndpoint>?query=<urlEncodedQuery>` |
651
+ | **Headers** | `access-key` and `access-secret-key` |
652
+ | **Response** | Plain text body (trimmed). Default transform parses as number. |
653
+ | **Errors** | Non-2xx → counted as failure per query |
654
+
655
+ For JSON responses, provide a custom `dataTransform`:
656
+
657
+ ```tsx
658
+ dataTransform={(raw) => {
659
+ const parsed = JSON.parse(String(raw));
660
+ return parsed?.data?.result?.[0]?.value?.[1] ?? raw;
661
+ }}
662
+ ```
663
+
664
+ ---
665
+
666
+ ## Standalone DataProvider
667
+
668
+ Use the data layer without `AIOPsDashboard`:
669
+
670
+ ```tsx
671
+ import { DataProvider, useAIOpsData } from "react-dashstream";
672
+
673
+ <DataProvider
674
+ config={{
675
+ endpoint: "https://prometheus.example.com/api/v1/query",
676
+ queries: ['cpu_usage{instance="srv-01"}'],
677
+ refreshInterval: 15000,
678
+ }}
679
+ >
680
+ <MyContent />
681
+ </DataProvider>;
682
+ ```
683
+
684
+ ---
685
+
686
+ ## Node positioning guide
687
+
688
+ The topology scene is ~660×640 pixels.
689
+
690
+ | Layer | Typical `ey` | `visibleAtPhase` | Component |
691
+ | ----------- | ------------ | ---------------- | ------------------- |
692
+ | Users (top) | 100 | 2 | `HumanNode` |
693
+ | Dispatcher | 230 | 2 | `WebDispatcherNode` |
694
+ | App servers | 350–380 | 3 | `ServerNode` |
695
+ | Databases | 500–520 | 4 | `DatabaseNode` |
696
+
697
+ Center X = `330`. Left/right columns: `200` / `460`. Three-column: `165` / `330` / `495`.
698
+
699
+ `compactOffset` controls node position in the compact carousel view relative to center.
700
+
701
+ ---
702
+
703
+ ## Usage patterns
704
+
705
+ ### Minimal static dashboard
706
+
707
+ ```tsx
708
+ import "react-dashstream/dist/index.css";
709
+ import { AIOPsDashboard, Service, ServerNode, DatabaseNode } from "react-dashstream";
710
+
711
+ <AIOPsDashboard brandName="MY DASHBOARD" services={[{ name: "Svc", status: "online" }]}>
712
+ <Service
713
+ name="Svc"
714
+ status="online"
715
+ connections={[{ from: [330, 200], to: [330, 380], visibleAtPhase: 3 }]}
716
+ >
717
+ <ServerNode
718
+ ex={330}
719
+ ey={380}
720
+ compactOffset={{ x: 0, y: 0 }}
721
+ zIndex={8}
722
+ name="SRV-01"
723
+ status="online"
724
+ cpuLoad={42}
725
+ memLoad={60}
726
+ />
727
+ </Service>
728
+ </AIOPsDashboard>;
729
+ ```
730
+
731
+ ### Full live-data dashboard
732
+
733
+ ```tsx
734
+ <AIOPsDashboard
735
+ brandName="LIVE MONITOR"
736
+ services={services}
737
+ liveData={true}
738
+ dataEndpoint="https://prometheus.example.com/api/v1/query"
739
+ dataRefreshInterval={10000}
740
+ dataBindings={{
741
+ "My Service": {
742
+ cpuLoad: 'cpu_usage{instance="srv-01"}',
743
+ status: { query: 'cpu_usage{instance="srv-01"}', transform: statusFromValue },
744
+ },
745
+ }}
746
+ serviceDataBindings={{
747
+ "My Service": [{ label: "CPU", query: 'cpu_usage{instance="srv-01"}', unit: "%", color: "#00e5ff" }],
748
+ }}
749
+ >
750
+ <MyService name="My Service" />
751
+ </AIOPsDashboard>
752
+ ```
753
+
754
+ ### Custom service with all data features
755
+
756
+ ```tsx
757
+ function MyService({ name, status, cpuLoad, memLoad, dbCapacity, dbStatus }: any) {
758
+ return (
759
+ <Service
760
+ name={name}
761
+ status={status ?? "online"}
762
+ connections={[
763
+ { from: [330, 200], to: [200, 380], visibleAtPhase: 3 },
764
+ { from: [330, 200], to: [460, 380], visibleAtPhase: 3 },
765
+ ]}
766
+ >
767
+ <ServerNode
768
+ ex={200}
769
+ ey={380}
770
+ compactOffset={{ x: -30, y: -20 }}
771
+ zIndex={8}
772
+ name="SRV-01"
773
+ subLabel="APP SERVER"
774
+ status={status ?? "online"}
775
+ cpuLoad={cpuLoad ?? 42}
776
+ memLoad={memLoad ?? 60}
777
+ alert={{ offsetX: -160, offsetY: -60, align: "left" }}
778
+ dialogMetrics={[
779
+ { id: "cpu", label: "CPU", sublabel: "PROCESSOR", value: cpuLoad ?? 42 },
780
+ { id: "mem", label: "MEMORY", sublabel: "HEAP", value: memLoad ?? 60 },
781
+ ]}
782
+ subComponents={[
783
+ {
784
+ id: "cpu",
785
+ label: "CPU-0",
786
+ status: "online",
787
+ element: <CPU3D label="CPU-0" load={cpuLoad ?? 42} />,
788
+ },
789
+ {
790
+ id: "mem",
791
+ label: "HEAP",
792
+ status: "online",
793
+ element: <Memory3D label="HEAP" usedPercent={memLoad ?? 60} />,
794
+ },
795
+ ]}
796
+ graphSeries={[
797
+ { id: "cpu", label: "CPU", unit: "%", color: "#00e5ff", data: [45, 52, 67, 71, 68] },
798
+ ]}
799
+ />
800
+ <DatabaseNode
801
+ ex={460}
802
+ ey={380}
803
+ compactOffset={{ x: 30, y: -20 }}
804
+ zIndex={7}
805
+ name="DB-01"
806
+ subLabel="PRIMARY"
807
+ status={dbStatus ?? "online"}
808
+ capacity={dbCapacity ?? 55}
809
+ alert={{ offsetX: 160, offsetY: -60, align: "right" }}
810
+ />
811
+ </Service>
812
+ );
813
+ }
814
+ ```
815
+
816
+ ---
817
+
818
+ ## Build and development
819
+
820
+ ```bash
821
+ npm run dev # Vite dev server (loads example/Dashboard.tsx)
822
+ npm run build # TypeScript check + Vite library build
823
+ npm run build:lib # Vite library build only
824
+ npm run preview # Preview production build
825
+ ```
826
+
827
+ Output: `dist/index.js` (ESM), `dist/index.d.ts`, `dist/index.css`.
828
+
829
+ ---
830
+
831
+ ## Common pitfalls
832
+
833
+ 1. **Missing CSS import** — Always import `react-dashstream/dist/index.css`.
834
+ 2. **Name mismatch** — `name` on child components must exactly match keys in `dataBindings`, `serviceDataBindings`, and `ServiceMeta.name`.
835
+ 3. **Credentials are in-memory only** — Page refresh requires re-entering credentials.
836
+ 4. **Default transform is plain-text** — For JSON endpoints, provide a custom `dataTransform`.
837
+ 5. **Polling only** — No WebSocket/SSE support; uses `setInterval`.
838
+ 6. **`visibleAtPhase` matters** — Nodes without proper values won't animate during expansion.
839
+ 7. **Connection coordinates** — `from`/`to` arrays use `[x, y]` matching `ex`/`ey` of connected nodes.
840
+ 8. **`dialogMetrics` replaces defaults** — When provided, all default gauges (CPU/Memory/Storage) are removed.
841
+ 9. **`subComponents` replaces defaults** — When provided, all auto-generated sub-components are removed.
842
+ 10. **`graphSeries` replaces defaults** — When provided, all auto-generated sparklines are removed.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-dashstream",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
4
4
  "type": "module",
5
5
  "author": "Busaud",
6
6
  "license": "MIT",
@@ -15,7 +15,8 @@
15
15
  ],
16
16
  "files": [
17
17
  "dist",
18
- "README.md"
18
+ "README.md",
19
+ "dashstream-skill.md"
19
20
  ],
20
21
  "main": "./dist/index.js",
21
22
  "module": "./dist/index.js",