react-dashstream 0.3.1 → 0.3.2

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 CHANGED
@@ -69,6 +69,21 @@ Click a service to expand its topology. Click a component to drill into its inte
69
69
 
70
70
  ---
71
71
 
72
+ ## AI assistant skills
73
+
74
+ Published with the package under **`skills/`** — each folder is a small, topic-focused reference for coding agents (Cursor, OpenCode, etc.):
75
+
76
+ | Skill | Focus |
77
+ | ----- | ----- |
78
+ | `dashstream-core` | Package overview, install, theming, exports, types, pitfalls |
79
+ | `dashstream-3d-dashboard` | `AIOPsDashboard`, services, nodes, positioning, connections |
80
+ | `dashstream-live-data` | `DataProvider`, bindings, hooks, endpoint contract |
81
+ | `dashstream-component-dialogs` | Drill-down metrics, internals, sparklines, alerts |
82
+ | `dashstream-event-view` | `EventView`, event API, event-to-dashboard bridge |
83
+ | `dashstream-datacenter-view` | `DatacenterView`, topology, geography, buildings |
84
+
85
+ ---
86
+
72
87
  ## Theme (light / dark)
73
88
 
74
89
  The dashboard ships with **light** and **dark** visual modes. `AIOPsDashboard` defaults to **light**; the header includes a control to toggle modes.
@@ -139,7 +154,7 @@ See `example/Dashboard.tsx` in this package for a complete two-service example w
139
154
 
140
155
  The demo app (`src/App.tsx`) uses `example/SaudiMapView.tsx`, a thin wrapper around `DatacenterView` that composes the map with **`DatacenterSite`** / shape components (`TowerDC`, `FlatDC`, …). Scenario data (configs and drill-down services) lives in `example/saudiMapDemoData.tsx`; optional mock metric sliders use `example/DemoMetricPanel.tsx` + `example/DemoMetricPanel.css` (not part of the published package).
141
156
 
142
- **Agent-oriented reference:** see **`dashstream-skill.md`** (section **DatacenterView — topology / geography map**) for props, types, mock vs live data, and composition with `DataProvider`.
157
+ **Agent-oriented reference:** see **`skills/dashstream-datacenter-view/SKILL.md`** for props, types, mock vs live data, and composition with `DataProvider`. Other topics live under **`skills/<name>/SKILL.md`** — see **AI assistant skills** below.
143
158
 
144
159
  ### Minimal import
145
160
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-dashstream",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "type": "module",
5
5
  "author": "Busaud",
6
6
  "license": "MIT",
@@ -16,7 +16,7 @@
16
16
  "files": [
17
17
  "dist",
18
18
  "README.md",
19
- "dashstream-skill.md"
19
+ "skills"
20
20
  ],
21
21
  "main": "./dist/index.js",
22
22
  "module": "./dist/index.js",
@@ -0,0 +1,318 @@
1
+ ---
2
+ name: dashstream-3d-dashboard
3
+ description: Build 3D carousel dashboards with AIOPsDashboard, services, and nodes
4
+ license: MIT
5
+ compatibility: opencode
6
+ metadata:
7
+ audience: developers
8
+ workflow: react
9
+ ---
10
+
11
+ ## What I do
12
+
13
+ - Guide building a 3D carousel dashboard with `AIOPsDashboard`
14
+ - Document `Service`, `ServerNode`, `DatabaseNode`, `WebDispatcherNode`, `MessageServerNode`, `HumanNode`
15
+ - Explain node positioning, connections, and compact offsets
16
+ - Provide minimal and full static dashboard examples
17
+
18
+ ## When to use me
19
+
20
+ Use this when creating or modifying a 3D dashboard layout — adding services, positioning nodes, or configuring connections.
21
+
22
+ For live data wiring, see **dashstream-live-data**. For drill-down details, see **dashstream-component-dialogs**.
23
+
24
+ ---
25
+
26
+ ## AIOPsDashboard — the shell
27
+
28
+ The top-level component that renders the header, carousel, and optional data layer.
29
+
30
+ ```tsx
31
+ import "react-dashstream/dist/index.css";
32
+ import { AIOPsDashboard, Service, ServerNode, DatabaseNode } from "react-dashstream";
33
+
34
+ <AIOPsDashboard
35
+ brandName="MY DASHBOARD"
36
+ brandTag="3D MONITOR"
37
+ services={[{ name: "Svc", status: "online" }]}
38
+ >
39
+ <Service name="Svc" status="online" connections={[...]}>
40
+ {/* nodes go here */}
41
+ </Service>
42
+ </AIOPsDashboard>
43
+ ```
44
+
45
+ Key props (see **dashstream-core** for full `AIOPsDashboardProps`):
46
+
47
+ | Prop | Type | Default | Notes |
48
+ |------|------|---------|-------|
49
+ | `brandName` | `string` | `"BUSAUD AIOps"` | Header brand |
50
+ | `brandTag` | `string` | `"3D MONITOR"` | Header tag |
51
+ | `services` | `ServiceMeta[]` | — | Metadata for ServiceDialog panels |
52
+ | `backgroundImage` | `string` | — | Dark mode background |
53
+ | `lightBackgroundImage` | `string` | — | Light mode background |
54
+ | `theme` / `onThemeChange` | `DashboardTheme` | — | Controlled theme |
55
+ | `logoUrl` | `string` | — | Logo image URL |
56
+ | `carouselSpeed` | `number` | `0.006` | Rotation speed |
57
+ | `fontFamily` | `string` | — | CSS font-family |
58
+ | `children` | `ReactNode` | — | `Service` children |
59
+
60
+ ---
61
+
62
+ ## Service — per-service container
63
+
64
+ Each `Service` wraps one logical service's nodes and connections.
65
+
66
+ ```tsx
67
+ <Service
68
+ name="My Service"
69
+ status="online"
70
+ connections={[
71
+ { from: [330, 200], to: [200, 380], visibleAtPhase: 3 },
72
+ { from: [330, 200], to: [460, 380], visibleAtPhase: 3 },
73
+ { from: [200, 380], to: [330, 520], visibleAtPhase: 4 },
74
+ { from: [460, 380], to: [330, 520], visibleAtPhase: 4 },
75
+ ]}
76
+ >
77
+ {/* compound nodes */}
78
+ </Service>
79
+ ```
80
+
81
+ - `name` must match keys in `dataBindings`, `serviceDataBindings`, and `ServiceMeta.name` exactly.
82
+ - `connections` are `ConnectionConfig[]` — animated SVG dashed lines between node positions.
83
+
84
+ ### ConnectionConfig
85
+
86
+ ```ts
87
+ interface ConnectionConfig {
88
+ from: [number, number]; // [x, y] matching source node's ex/ey
89
+ to: [number, number]; // [x, y] matching target node's ex/ey
90
+ visibleAtPhase?: number; // Default: 0
91
+ color?: string; // Default: "#00e5ff"
92
+ duration?: string; // Default: "1.2s"
93
+ }
94
+ ```
95
+
96
+ ---
97
+
98
+ ## Compound nodes
99
+
100
+ All compound nodes share common positioning props:
101
+
102
+ | Prop | Type | Notes |
103
+ |------|------|-------|
104
+ | `name` | `string` | Display name + event bridge matching key |
105
+ | `subLabel` | `string` | Secondary label below name |
106
+ | `status` | `ComponentStatus` | `"online"` / `"warning"` / `"critical"` / `"offline"` |
107
+ | `ex` | `number` | X position in the ~660×640 scene |
108
+ | `ey` | `number` | Y position in the ~660×640 scene |
109
+ | `compactOffset` | `{ x, y }` | Offset in compact carousel view |
110
+ | `zIndex` | `number` | Z-order layering |
111
+ | `alert` | `AlertConfig` | Callout positioning (see dashstream-component-dialogs) |
112
+ | `dialogMetrics` | `ComponentDialogMetric[]` | Custom gauges (see dashstream-component-dialogs) |
113
+ | `subComponents` | `SubComponentConfig[]` | Custom drill-down internals (see dashstream-component-dialogs) |
114
+ | `graphSeries` | `GraphSeries[]` | Custom sparklines (see dashstream-component-dialogs) |
115
+
116
+ ### ServerNode
117
+
118
+ ```tsx
119
+ <ServerNode
120
+ ex={200} ey={380}
121
+ compactOffset={{ x: -30, y: -20 }}
122
+ zIndex={8}
123
+ name="SRV-01"
124
+ subLabel="APP SERVER"
125
+ status="online"
126
+ cpuLoad={42}
127
+ memLoad={60}
128
+ />
129
+ ```
130
+
131
+ Extra props: `cpuLoad` (number), `memLoad` (number).
132
+
133
+ ### DatabaseNode
134
+
135
+ ```tsx
136
+ <DatabaseNode
137
+ ex={460} ey={520}
138
+ compactOffset={{ x: 30, y: 20 }}
139
+ zIndex={7}
140
+ name="DB-01"
141
+ subLabel="PRIMARY"
142
+ status="online"
143
+ capacity={55}
144
+ />
145
+ ```
146
+
147
+ Extra props: `capacity` (number).
148
+
149
+ ### WebDispatcherNode
150
+
151
+ ```tsx
152
+ <WebDispatcherNode
153
+ ex={330} ey={230}
154
+ compactOffset={{ x: 0, y: -30 }}
155
+ zIndex={9}
156
+ name="WD-01"
157
+ subLabel="DISPATCHER"
158
+ status="online"
159
+ traffic={45}
160
+ />
161
+ ```
162
+
163
+ Extra props: `traffic` (number).
164
+
165
+ ### MessageServerNode
166
+
167
+ ```tsx
168
+ <MessageServerNode
169
+ ex={330} ey={230}
170
+ compactOffset={{ x: 0, y: -30 }}
171
+ zIndex={9}
172
+ name="MSG-01"
173
+ subLabel="MESSAGE SERVER"
174
+ status="online"
175
+ queueDepth={30}
176
+ />
177
+ ```
178
+
179
+ Extra props: `queueDepth` (number).
180
+
181
+ ### HumanNode
182
+
183
+ ```tsx
184
+ <HumanNode
185
+ ex={330} ey={100}
186
+ compactOffset={{ x: 0, y: -40 }}
187
+ zIndex={10}
188
+ name="USERS"
189
+ subLabel="500 ACTIVE"
190
+ status="online"
191
+ />
192
+ ```
193
+
194
+ ---
195
+
196
+ ## Node positioning guide
197
+
198
+ The topology scene is ~660×640 pixels.
199
+
200
+ | Layer | Typical `ey` | `visibleAtPhase` | Component |
201
+ | ----- | ------------ | ---------------- | --------- |
202
+ | Users (top) | 100 | 2 | `HumanNode` |
203
+ | Dispatcher | 230 | 2 | `WebDispatcherNode` |
204
+ | App servers | 350–380 | 3 | `ServerNode` |
205
+ | Databases | 500–520 | 4 | `DatabaseNode` |
206
+
207
+ Center X = `330`. Left/right columns: `200` / `460`. Three-column: `165` / `330` / `495`.
208
+
209
+ `compactOffset` controls node position in the compact carousel view relative to center.
210
+
211
+ ---
212
+
213
+ ## Usage patterns
214
+
215
+ ### Minimal static dashboard
216
+
217
+ ```tsx
218
+ import "react-dashstream/dist/index.css";
219
+ import { AIOPsDashboard, Service, ServerNode, DatabaseNode } from "react-dashstream";
220
+
221
+ <AIOPsDashboard brandName="MY DASHBOARD" services={[{ name: "Svc", status: "online" }]}>
222
+ <Service
223
+ name="Svc"
224
+ status="online"
225
+ connections={[{ from: [330, 200], to: [330, 380], visibleAtPhase: 3 }]}
226
+ >
227
+ <ServerNode
228
+ ex={330} ey={380}
229
+ compactOffset={{ x: 0, y: 0 }}
230
+ zIndex={8}
231
+ name="SRV-01"
232
+ status="online"
233
+ cpuLoad={42}
234
+ memLoad={60}
235
+ />
236
+ </Service>
237
+ </AIOPsDashboard>
238
+ ```
239
+
240
+ ### Multi-node service
241
+
242
+ ```tsx
243
+ function MyService({ name, status, cpuLoad, memLoad, dbCapacity, dbStatus }: any) {
244
+ return (
245
+ <Service
246
+ name={name}
247
+ status={status ?? "online"}
248
+ connections={[
249
+ { from: [330, 200], to: [200, 380], visibleAtPhase: 3 },
250
+ { from: [330, 200], to: [460, 380], visibleAtPhase: 3 },
251
+ { from: [200, 380], to: [330, 520], visibleAtPhase: 4 },
252
+ { from: [460, 380], to: [330, 520], visibleAtPhase: 4 },
253
+ ]}
254
+ >
255
+ <ServerNode
256
+ ex={200} ey={380}
257
+ compactOffset={{ x: -30, y: -20 }}
258
+ zIndex={8}
259
+ name="SRV-01"
260
+ subLabel="APP SERVER"
261
+ status={status ?? "online"}
262
+ cpuLoad={cpuLoad ?? 42}
263
+ memLoad={memLoad ?? 60}
264
+ alert={{ offsetX: -160, offsetY: -60, align: "left" }}
265
+ />
266
+ <DatabaseNode
267
+ ex={460} ey={380}
268
+ compactOffset={{ x: 30, y: -20 }}
269
+ zIndex={7}
270
+ name="DB-01"
271
+ subLabel="PRIMARY"
272
+ status={dbStatus ?? "online"}
273
+ capacity={dbCapacity ?? 55}
274
+ alert={{ offsetX: 160, offsetY: -60, align: "right" }}
275
+ />
276
+ </Service>
277
+ );
278
+ }
279
+ ```
280
+
281
+ ### Multi-component services (flat prefix convention)
282
+
283
+ When a service has multiple nodes of the same type, use flat prefixed props:
284
+
285
+ ```tsx
286
+ interface ServiceXProps {
287
+ name: string;
288
+ status?: ComponentStatus;
289
+ srv1CpuLoad?: number;
290
+ srv1MemLoad?: number;
291
+ srv1Status?: ComponentStatus;
292
+ srv2CpuLoad?: number;
293
+ srv2MemLoad?: number;
294
+ srv2Status?: ComponentStatus;
295
+ dbCapacity?: number;
296
+ dbStatus?: ComponentStatus;
297
+ }
298
+
299
+ function ServiceX({
300
+ name, status = "online",
301
+ srv1CpuLoad = 54, srv1MemLoad = 58, srv1Status = "online",
302
+ srv2CpuLoad = 63, srv2MemLoad = 66, srv2Status = "online",
303
+ dbCapacity = 68, dbStatus = "online",
304
+ }: ServiceXProps) {
305
+ return (
306
+ <Service name={name} status={status} connections={[/* ... */]}>
307
+ <ServerNode name="SRV-X1" status={srv1Status}
308
+ cpuLoad={srv1CpuLoad} memLoad={srv1MemLoad} ... />
309
+ <ServerNode name="SRV-X2" status={srv2Status}
310
+ cpuLoad={srv2CpuLoad} memLoad={srv2MemLoad} ... />
311
+ <DatabaseNode name="DB-X1" status={dbStatus}
312
+ capacity={dbCapacity} ... />
313
+ </Service>
314
+ );
315
+ }
316
+ ```
317
+
318
+ Use a consistent convention like `srv1CpuLoad`, `srv2CpuLoad`. The service component maps each prefixed prop to the correct node.
@@ -0,0 +1,287 @@
1
+ ---
2
+ name: dashstream-component-dialogs
3
+ description: Configure drill-down dialogs with custom metrics, internals, sparklines, and alerts
4
+ license: MIT
5
+ compatibility: opencode
6
+ metadata:
7
+ audience: developers
8
+ workflow: react
9
+ ---
10
+
11
+ ## What I do
12
+
13
+ - Document the ComponentDialog system (gauges, drill-down internals, sparkline graphs)
14
+ - Explain `dialogMetrics`, `subComponents`, and `graphSeries` props
15
+ - Cover automatic threshold-based alerts and custom alert positioning
16
+ - Show how to wire live data into dialog metrics via service props
17
+
18
+ ## When to use me
19
+
20
+ Use this when customizing what appears in the drill-down panel when a user clicks a node — custom gauges, internal 3D sub-components, sparkline charts, or alert callouts.
21
+
22
+ ---
23
+
24
+ ## Component dialog — default gauges
25
+
26
+ The **ComponentDialog** appears when clicking a node. Default gauges are derived from node type:
27
+
28
+ - **Server**: CPU (from `cpuLoad`), Memory (from `memLoad`), Storage
29
+ - **Database**: Capacity (from `capacity`), Memory, Storage
30
+ - **Dispatcher**: Traffic (from `traffic`), Memory, Storage
31
+ - **Message Server**: Queue (from `queueDepth`), Memory, Storage
32
+
33
+ Default thresholds: warn at 70, critical at 85.
34
+
35
+ ---
36
+
37
+ ## Custom dialogMetrics
38
+
39
+ Override default gauges with `dialogMetrics` on any compound node:
40
+
41
+ ```tsx
42
+ <ServerNode
43
+ name="SRV-01"
44
+ status="online"
45
+ cpuLoad={67}
46
+ memLoad={72}
47
+ ex={200} ey={380}
48
+ compactOffset={{ x: -30, y: -20 }}
49
+ zIndex={8}
50
+ dialogMetrics={[
51
+ { id: "cpu", label: "CPU", sublabel: "PROCESSOR", value: 67, unit: "%" },
52
+ { id: "mem", label: "MEMORY", sublabel: "HEAP USAGE", value: 72, unit: "%" },
53
+ { id: "iops", label: "IOPS", sublabel: "DISK OPS", value: 45, unit: "k/s", icon: "disk" },
54
+ {
55
+ id: "threads",
56
+ label: "THREADS",
57
+ sublabel: "ACTIVE",
58
+ value: 82,
59
+ unit: "%",
60
+ warnAt: 60,
61
+ critAt: 80,
62
+ icon: "cpu",
63
+ },
64
+ ]}
65
+ />
66
+ ```
67
+
68
+ ```ts
69
+ interface ComponentDialogMetric {
70
+ id: string; // Unique key
71
+ label: string; // Upper label
72
+ sublabel: string; // Lower label
73
+ value: number; // 0–100
74
+ unit?: string; // Default "%"
75
+ icon?: "cpu" | "mem" | "disk"; // Default "cpu"
76
+ warnAt?: number; // Default 70
77
+ critAt?: number; // Default 85
78
+ color?: string; // Override bar color (bypasses threshold coloring)
79
+ }
80
+ ```
81
+
82
+ All compound nodes accept `dialogMetrics`: `ServerNode`, `DatabaseNode`, `WebDispatcherNode`, `MessageServerNode`.
83
+
84
+ **When provided, all default gauges are removed** — you must define every metric you want shown.
85
+
86
+ ---
87
+
88
+ ## Drill-down internals — custom subComponents
89
+
90
+ When clicking a node, the drill-down shows internal 3D sub-components. Default sub-components are auto-generated per type. Override with `subComponents`:
91
+
92
+ ```tsx
93
+ import { CPU3D, Memory3D, DriveBay3D, ThreadPool3D, NetworkBlock3D, Platter3D, Port3D } from "react-dashstream";
94
+ import type { SubComponentConfig } from "react-dashstream";
95
+
96
+ const internals: SubComponentConfig[] = [
97
+ { id: "cpu-0", label: "CPU-0", status: "online",
98
+ element: <CPU3D label="CPU-0" load={67} color="#00e5ff" /> },
99
+ { id: "heap", label: "HEAP", status: "warning",
100
+ element: <Memory3D label="HEAP" usedPercent={92} color="#8855ee" status="warning" /> },
101
+ { id: "drive", label: "DRIVE-0", status: "online",
102
+ element: <DriveBay3D label="DRIVE-0" color="#00e5ff" activity={true} /> },
103
+ { id: "threads", label: "THREADS", status: "online",
104
+ element: <ThreadPool3D label="THREADS" color="#00e5ff" /> },
105
+ { id: "net", label: "NET", status: "online",
106
+ element: <NetworkBlock3D label="NET" color="#00e5ff" /> },
107
+ ];
108
+
109
+ <ServerNode subComponents={internals} ... />
110
+ ```
111
+
112
+ ```ts
113
+ interface SubComponentConfig {
114
+ id: string; // Unique key
115
+ label: string; // Display name
116
+ status: ComponentStatus; // LED color
117
+ detail?: string; // Fault description
118
+ element: ReactNode; // 3D element to render
119
+ }
120
+ ```
121
+
122
+ All compound nodes accept `subComponents`. **When provided, all auto-generated sub-components are removed.**
123
+
124
+ ---
125
+
126
+ ## Graph series — custom sparklines
127
+
128
+ The drill-down's historical panel shows sparkline charts. Default graphs are auto-generated. Override with `graphSeries`:
129
+
130
+ ```tsx
131
+ import type { GraphSeries } from "react-dashstream";
132
+
133
+ const graphs: GraphSeries[] = [
134
+ { id: "cpu", label: "CPU-0", unit: "%", color: "#00e5ff", data: [45, 52, 67, 71, 68, 55] },
135
+ { id: "mem", label: "HEAP", unit: "%", color: "#8855ee", data: [60, 65, 72, 78, 82, 75] },
136
+ { id: "iops", label: "DISK", unit: "k/s", color: "#ff8c00", data: [12, 15, 22, 18, 25, 20] },
137
+ ];
138
+
139
+ <ServerNode graphSeries={graphs} ... />
140
+ ```
141
+
142
+ ```ts
143
+ interface GraphSeries {
144
+ id: string; // Unique key
145
+ label: string; // Label above sparkline
146
+ unit: string; // Suffix
147
+ color: string; // Line color
148
+ data: number[]; // Points (most recent last)
149
+ }
150
+ ```
151
+
152
+ All compound nodes accept `graphSeries`. **When provided, all auto-generated sparklines are removed.**
153
+
154
+ ---
155
+
156
+ ## Alerts — automatic threshold detection
157
+
158
+ Nodes auto-render `NodeCallout` alerts when metrics breach thresholds:
159
+
160
+ - **Warning** at 70% → orange callout
161
+ - **Critical** at 85% → red callout
162
+
163
+ Sources (checked in priority order):
164
+
165
+ 1. `dialogMetrics` values vs their `warnAt`/`critAt`
166
+ 2. Context values (`cpuLoad`, `memLoad`, `traffic`, `queueDepth`, `capacity`) vs default thresholds
167
+
168
+ ```tsx
169
+ // Auto-alert from cpuLoad > 85
170
+ <ServerNode cpuLoad={92} memLoad={64}
171
+ alert={{ offsetX: -160, offsetY: -60, align: "left" }}
172
+ ... />
173
+
174
+ // Custom message
175
+ <ServerNode cpuLoad={92}
176
+ alert={{ msg: "CPU overload — scale out", offsetX: -160, offsetY: -60, align: "left" }}
177
+ ... />
178
+
179
+ // Custom thresholds via dialogMetrics
180
+ <ServerNode
181
+ dialogMetrics={[
182
+ { id: "cpu", label: "CPU", sublabel: "PROCESSOR", value: 67,
183
+ warnAt: 50, critAt: 75 },
184
+ ]}
185
+ alert={{ offsetX: -160, offsetY: -60, align: "left" }}
186
+ ... />
187
+ ```
188
+
189
+ ### Alert prop shape
190
+
191
+ ```ts
192
+ alert?: {
193
+ msg?: string; // Custom message (auto-generated if omitted)
194
+ offsetX?: number; // X offset from node (default 110)
195
+ offsetY?: number; // Y offset from node (default -30)
196
+ align?: "left" | "right" | "top" | "bottom"; // Default "right"
197
+ internalRef?: string; // Sub-component ID
198
+ }
199
+ ```
200
+
201
+ Alert `align` options: `"left"`, `"right"`, `"top"`, `"bottom"`.
202
+
203
+ ---
204
+
205
+ ## ServiceDialog — static and live metrics
206
+
207
+ The **ServiceDialog** panel shows KPIs when a service is expanded.
208
+
209
+ ### Static metrics via ServiceMeta
210
+
211
+ ```tsx
212
+ const services: ServiceMeta[] = [
213
+ {
214
+ name: "My Service",
215
+ status: "online",
216
+ metrics: [
217
+ { label: "Uptime", value: "99.99%", color: "#00ff88" },
218
+ { label: "Avg Latency", value: "8ms", color: "#00e5ff" },
219
+ ],
220
+ alerts: [
221
+ { level: "info", message: "All Systems Nominal" },
222
+ { level: "warning", message: "High CPU on SRV-01" },
223
+ { level: "critical", message: "DB connection pool exhausted" },
224
+ ],
225
+ },
226
+ ];
227
+ ```
228
+
229
+ ### Live metrics via serviceDataBindings
230
+
231
+ See **dashstream-live-data** for `serviceDataBindings` configuration.
232
+
233
+ ---
234
+
235
+ ## Full example — service with all dialog features
236
+
237
+ ```tsx
238
+ import { CPU3D, Memory3D } from "react-dashstream";
239
+
240
+ function MyService({ name, status, cpuLoad, memLoad, dbCapacity, dbStatus }: any) {
241
+ return (
242
+ <Service
243
+ name={name}
244
+ status={status ?? "online"}
245
+ connections={[
246
+ { from: [330, 200], to: [200, 380], visibleAtPhase: 3 },
247
+ { from: [330, 200], to: [460, 380], visibleAtPhase: 3 },
248
+ ]}
249
+ >
250
+ <ServerNode
251
+ ex={200} ey={380}
252
+ compactOffset={{ x: -30, y: -20 }}
253
+ zIndex={8}
254
+ name="SRV-01"
255
+ subLabel="APP SERVER"
256
+ status={status ?? "online"}
257
+ cpuLoad={cpuLoad ?? 42}
258
+ memLoad={memLoad ?? 60}
259
+ alert={{ offsetX: -160, offsetY: -60, align: "left" }}
260
+ dialogMetrics={[
261
+ { id: "cpu", label: "CPU", sublabel: "PROCESSOR", value: cpuLoad ?? 42 },
262
+ { id: "mem", label: "MEMORY", sublabel: "HEAP", value: memLoad ?? 60 },
263
+ ]}
264
+ subComponents={[
265
+ { id: "cpu", label: "CPU-0", status: "online",
266
+ element: <CPU3D label="CPU-0" load={cpuLoad ?? 42} /> },
267
+ { id: "mem", label: "HEAP", status: "online",
268
+ element: <Memory3D label="HEAP" usedPercent={memLoad ?? 60} /> },
269
+ ]}
270
+ graphSeries={[
271
+ { id: "cpu", label: "CPU", unit: "%", color: "#00e5ff", data: [45, 52, 67, 71, 68] },
272
+ ]}
273
+ />
274
+ <DatabaseNode
275
+ ex={460} ey={380}
276
+ compactOffset={{ x: 30, y: -20 }}
277
+ zIndex={7}
278
+ name="DB-01"
279
+ subLabel="PRIMARY"
280
+ status={dbStatus ?? "online"}
281
+ capacity={dbCapacity ?? 55}
282
+ alert={{ offsetX: 160, offsetY: -60, align: "right" }}
283
+ />
284
+ </Service>
285
+ );
286
+ }
287
+ ```