react-dashstream 0.0.7 → 0.0.8
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 +637 -320
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -71,376 +71,728 @@ Click a service to expand its topology. Click a component to drill into its inte
|
|
|
71
71
|
|
|
72
72
|
## Full example — multi-service, multi-layer
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
See `example/Dashboard.tsx` in this package for a complete two-service example with Payment Gateway and Auth Service topologies rotating in a 3D carousel.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## External data source monitoring
|
|
79
|
+
|
|
80
|
+
DashStream can connect to any HTTP monitoring endpoint (Prometheus, Grafana, custom APIs) and feed live values into your dashboard. This section covers **every** data path — from node props to service dialogs, component dialogs, alerts, drill-down internals, and graphs.
|
|
81
|
+
|
|
82
|
+
### How it works
|
|
83
|
+
|
|
84
|
+
1. Set `liveData={true}` on `AIOPsDashboard` with `dataEndpoint` and `dataBindings`.
|
|
85
|
+
2. A **credentials modal** appears on first load asking for `access-key` and `access-secret-key` (stored in memory only).
|
|
86
|
+
3. The dashboard polls `GET <endpoint>?query=<encodedQuery>` for each unique query with credentials as HTTP headers.
|
|
87
|
+
4. Resolved values are injected as **props** into child service components matched by `name`.
|
|
88
|
+
5. The header shows **"DATA REFRESH FAILED"** if any queries fail.
|
|
89
|
+
|
|
90
|
+
### Live data props
|
|
91
|
+
|
|
92
|
+
| Prop | Type | Default | Description |
|
|
93
|
+
| --------------------- | ---------------------------------------- | ------------- | ------------------------------------------------------ |
|
|
94
|
+
| `liveData` | `boolean` | `false` | Enable the live data pipeline. |
|
|
95
|
+
| `dataEndpoint` | `string` | — | Base URL. Queries sent as `GET <url>?query=<encoded>`. |
|
|
96
|
+
| `dataBindings` | `DataBindings` | — | Maps service → prop → query. See below. |
|
|
97
|
+
| `dataTransform` | `(raw) => unknown` | Numeric parse | Global transform for raw responses. |
|
|
98
|
+
| `dataRefreshInterval` | `number` | `60000` | Polling interval in ms. |
|
|
99
|
+
| `serviceDataBindings` | `Record<string, ServiceMetricBinding[]>` | — | Live metrics for the service stats dialog. |
|
|
100
|
+
|
|
101
|
+
### Endpoint contract
|
|
102
|
+
|
|
103
|
+
| Aspect | Requirement |
|
|
104
|
+
| ------------ | --------------------------------------------------------------- |
|
|
105
|
+
| **Method** | `GET` |
|
|
106
|
+
| **URL** | `<dataEndpoint>?query=<urlEncodedQuery>` |
|
|
107
|
+
| **Headers** | `access-key` and `access-secret-key` |
|
|
108
|
+
| **Response** | Plain text body (trimmed). Default transform parses as number. |
|
|
109
|
+
| **Errors** | Non-2xx → counted as failure. Partial failures shown in header. |
|
|
110
|
+
|
|
111
|
+
For JSON responses (e.g. Prometheus), provide a custom `dataTransform`:
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
dataTransform={(raw) => {
|
|
115
|
+
const parsed = JSON.parse(String(raw));
|
|
116
|
+
return parsed?.data?.result?.[0]?.value?.[1] ?? raw;
|
|
117
|
+
}}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
### 1. Data bindings — injecting live props into nodes
|
|
123
|
+
|
|
124
|
+
`dataBindings` maps **service name → prop name → query**. Each key in the inner object must match a prop on your service component. The service name must match the child's `name` prop.
|
|
125
|
+
|
|
126
|
+
A binding can be a bare query string or an object with a custom transform:
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
type DataBinding = string | { query: string; transform?: (raw: unknown) => unknown };
|
|
130
|
+
type DataBindings = Record<string, Record<string, DataBinding>>;
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**Example — one service with a server and database:**
|
|
76
134
|
|
|
77
135
|
```tsx
|
|
78
136
|
import "react-dashstream/dist/index.css";
|
|
79
|
-
import {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
|
|
137
|
+
import { AIOPsDashboard, Service, ServerNode, DatabaseNode } from "react-dashstream";
|
|
138
|
+
|
|
139
|
+
function statusFromValue(raw: unknown) {
|
|
140
|
+
const n = Number(raw);
|
|
141
|
+
if (n >= 85) return "critical";
|
|
142
|
+
if (n >= 70) return "warning";
|
|
143
|
+
return "online";
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export default function App() {
|
|
147
|
+
return (
|
|
148
|
+
<AIOPsDashboard
|
|
149
|
+
brandName="LIVE DASHBOARD"
|
|
150
|
+
services={[{ name: "My Service", status: "online" }]}
|
|
151
|
+
liveData={true}
|
|
152
|
+
dataEndpoint="https://prometheus.example.com/api/v1/query"
|
|
153
|
+
dataRefreshInterval={10000}
|
|
154
|
+
dataBindings={{
|
|
155
|
+
"My Service": {
|
|
156
|
+
// bare string → parsed as number automatically
|
|
157
|
+
cpuLoad: 'cpu_usage{instance="srv-01"}',
|
|
158
|
+
memLoad: 'memory_usage{instance="srv-01"}',
|
|
88
159
|
|
|
89
|
-
//
|
|
160
|
+
// object with transform → convert number to status string
|
|
161
|
+
status: {
|
|
162
|
+
query: 'up{instance="srv-01"}',
|
|
163
|
+
transform: statusFromValue,
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
// bind database props too
|
|
167
|
+
dbCapacity: 'disk_capacity{instance="db-01"}',
|
|
168
|
+
dbStatus: {
|
|
169
|
+
query: 'disk_capacity{instance="db-01"}',
|
|
170
|
+
transform: statusFromValue,
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
}}
|
|
174
|
+
>
|
|
175
|
+
<MyService name="My Service" />
|
|
176
|
+
</AIOPsDashboard>
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
The component receives `cpuLoad`, `memLoad`, `status`, `dbCapacity`, and `dbStatus` as live props, overriding their defaults.
|
|
182
|
+
|
|
183
|
+
#### Multi-component services
|
|
184
|
+
|
|
185
|
+
When a service has multiple nodes of the same type (e.g. three servers), use a flat naming convention with prefixes. Each binding maps one prop to one query — there is no array or object binding support.
|
|
186
|
+
|
|
187
|
+
```tsx
|
|
188
|
+
// Service component — accepts prefixed props for each server
|
|
189
|
+
interface ServiceXProps {
|
|
190
|
+
name: string;
|
|
191
|
+
status?: ComponentStatus;
|
|
192
|
+
srv1CpuLoad?: number;
|
|
193
|
+
srv1MemLoad?: number;
|
|
194
|
+
srv1Status?: ComponentStatus;
|
|
195
|
+
srv2CpuLoad?: number;
|
|
196
|
+
srv2MemLoad?: number;
|
|
197
|
+
srv2Status?: ComponentStatus;
|
|
198
|
+
srv3CpuLoad?: number;
|
|
199
|
+
srv3MemLoad?: number;
|
|
200
|
+
srv3Status?: ComponentStatus;
|
|
201
|
+
dbCapacity?: number;
|
|
202
|
+
dbStatus?: ComponentStatus;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function ServiceX({
|
|
206
|
+
name, status = "online",
|
|
207
|
+
srv1CpuLoad = 54, srv1MemLoad = 58, srv1Status = "online",
|
|
208
|
+
srv2CpuLoad = 63, srv2MemLoad = 66, srv2Status = "online",
|
|
209
|
+
srv3CpuLoad = 78, srv3MemLoad = 71, srv3Status = "online",
|
|
210
|
+
dbCapacity = 68, dbStatus = "online",
|
|
211
|
+
}: ServiceXProps) {
|
|
212
|
+
return (
|
|
213
|
+
<Service name={name} status={status} connections={[/* ... */]}>
|
|
214
|
+
<ServerNode name="SRV-X1" status={srv1Status}
|
|
215
|
+
cpuLoad={srv1CpuLoad} memLoad={srv1MemLoad} ... />
|
|
216
|
+
<ServerNode name="SRV-X2" status={srv2Status}
|
|
217
|
+
cpuLoad={srv2CpuLoad} memLoad={srv2MemLoad} ... />
|
|
218
|
+
<ServerNode name="SRV-X3" status={srv3Status}
|
|
219
|
+
cpuLoad={srv3CpuLoad} memLoad={srv3MemLoad} ... />
|
|
220
|
+
<DatabaseNode name="DB-X1" status={dbStatus}
|
|
221
|
+
capacity={dbCapacity} ... />
|
|
222
|
+
</Service>
|
|
223
|
+
);
|
|
224
|
+
}
|
|
90
225
|
|
|
226
|
+
// Dashboard — bind each prefixed prop to its query
|
|
227
|
+
<AIOPsDashboard
|
|
228
|
+
liveData={true}
|
|
229
|
+
dataEndpoint="https://prometheus.example.com/api/v1/query"
|
|
230
|
+
dataBindings={{
|
|
231
|
+
ServiceX: {
|
|
232
|
+
status: { query: 'status{instance="svcx"}', transform: statusFromValue },
|
|
233
|
+
srv1CpuLoad: 'cpu_usage{instance="srvx-01"}',
|
|
234
|
+
srv1MemLoad: 'memory_usage{instance="srvx-01"}',
|
|
235
|
+
srv1Status: { query: 'status{instance="srvx-01"}', transform: statusFromValue },
|
|
236
|
+
srv2CpuLoad: 'cpu_usage{instance="srvx-02"}',
|
|
237
|
+
srv2MemLoad: 'memory_usage{instance="srvx-02"}',
|
|
238
|
+
srv2Status: { query: 'status{instance="srvx-02"}', transform: statusFromValue },
|
|
239
|
+
srv3CpuLoad: 'cpu_usage{instance="srvx-03"}',
|
|
240
|
+
srv3MemLoad: 'memory_usage{instance="srvx-03"}',
|
|
241
|
+
srv3Status: { query: 'status{instance="srvx-03"}', transform: statusFromValue },
|
|
242
|
+
dbCapacity: 'disk_capacity{instance="dbx-01"}',
|
|
243
|
+
dbStatus: { query: 'status{instance="dbx-01"}', transform: statusFromValue },
|
|
244
|
+
},
|
|
245
|
+
}}
|
|
246
|
+
services={[{ name: "ServiceX", status: "online" }]}
|
|
247
|
+
>
|
|
248
|
+
<ServiceX name="ServiceX" />
|
|
249
|
+
</AIOPsDashboard>
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Use a consistent naming convention like `srv1CpuLoad`, `srv2CpuLoad`, etc. The dashboard injects each prefixed prop individually. The service component maps each prop to the correct node.
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
### 2. Service dialog — live KPI metrics
|
|
257
|
+
|
|
258
|
+
The **ServiceDialog** is the stats panel that appears when you click a service. It shows KPI rows and alerts.
|
|
259
|
+
|
|
260
|
+
**Static way** — pass `ServiceMeta` with hardcoded values:
|
|
261
|
+
|
|
262
|
+
```tsx
|
|
91
263
|
const services: ServiceMeta[] = [
|
|
92
264
|
{
|
|
93
|
-
name: "
|
|
94
|
-
status: "critical",
|
|
95
|
-
metrics: [
|
|
96
|
-
{ label: "Service Health", value: "76.3%", color: "#ff8c00" },
|
|
97
|
-
{ label: "Avg Response Time", value: "243ms", color: "#ff8c00" },
|
|
98
|
-
{ label: "Active Connections", value: "1,847", color: "#bb55ff" },
|
|
99
|
-
{ label: "Request Throughput", value: "3.2k req/s", color: "#00e5ff" },
|
|
100
|
-
{ label: "Error Rate", value: "3.81%", color: "#ff2255" },
|
|
101
|
-
],
|
|
102
|
-
alerts: [{ level: "critical", message: "SRV-01 CPU at 99% — immediate action required" }],
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
name: "Auth Service",
|
|
265
|
+
name: "My Service",
|
|
106
266
|
status: "online",
|
|
107
267
|
metrics: [
|
|
108
|
-
{ label: "
|
|
109
|
-
{ label: "Avg
|
|
110
|
-
{ label: "
|
|
111
|
-
{ label: "Auth Rate", value: "920 req/s", color: "#00e5ff" },
|
|
112
|
-
{ label: "Failed Logins", value: "0.03%", color: "#00ff88" },
|
|
268
|
+
{ label: "Uptime", value: "99.99%", color: "#00ff88" },
|
|
269
|
+
{ label: "Avg Latency", value: "8ms", color: "#00e5ff" },
|
|
270
|
+
{ label: "Error Rate", value: "0.02%", color: "#00ff88" },
|
|
113
271
|
],
|
|
114
272
|
alerts: [{ level: "info", message: "All Systems Nominal" }],
|
|
115
273
|
},
|
|
116
274
|
];
|
|
275
|
+
```
|
|
117
276
|
|
|
118
|
-
|
|
277
|
+
**Live way** — use `serviceDataBindings` to fetch values from your endpoint:
|
|
119
278
|
|
|
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
|
-
|
|
279
|
+
```tsx
|
|
280
|
+
<AIOPsDashboard
|
|
281
|
+
services={[{ name: "My Service", status: "online" }]}
|
|
282
|
+
liveData={true}
|
|
283
|
+
dataEndpoint="https://prometheus.example.com/api/v1/query"
|
|
284
|
+
dataBindings={{ /* ... */ }}
|
|
285
|
+
serviceDataBindings={{
|
|
286
|
+
"My Service": [
|
|
287
|
+
{ label: "CPU Load", query: 'cpu_usage{instance="srv-01"}', unit: "%", color: "#00e5ff" },
|
|
288
|
+
{ label: "Memory", query: 'memory_usage{instance="srv-01"}', unit: "%", color: "#bb55ff" },
|
|
289
|
+
{ label: "Disk", query: 'disk_capacity{instance="db-01"}', unit: "%", color: "#ff8c00" },
|
|
290
|
+
],
|
|
291
|
+
}}
|
|
292
|
+
>
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Each `ServiceMetricBinding`:
|
|
296
|
+
|
|
297
|
+
```ts
|
|
298
|
+
interface ServiceMetricBinding {
|
|
299
|
+
label: string; // Row label
|
|
300
|
+
query: string; // PromQL query
|
|
301
|
+
unit?: string; // Suffix (e.g. "%", "ms")
|
|
302
|
+
color?: string; // Accent color
|
|
303
|
+
transform?: (raw: unknown) => string; // Custom formatter
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
When `serviceDataBindings` is provided for a service, live values **replace** the static `ServiceMeta.metrics`.
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
### 3. Component dialog — custom gauges
|
|
312
|
+
|
|
313
|
+
The **ComponentDialog** appears when you click a node (server, database, etc.) inside an expanded service. By default it shows CPU, Memory, and Storage gauges derived from the node's props.
|
|
314
|
+
|
|
315
|
+
**Override these gauges** with the `dialogMetrics` prop on any compound node:
|
|
316
|
+
|
|
317
|
+
```tsx
|
|
318
|
+
<ServerNode
|
|
319
|
+
ex={200}
|
|
320
|
+
ey={380}
|
|
321
|
+
compactOffset={{ x: -30, y: -20 }}
|
|
322
|
+
zIndex={8}
|
|
323
|
+
name="SRV-01"
|
|
324
|
+
subLabel="APP SERVER"
|
|
325
|
+
status="online"
|
|
326
|
+
cpuLoad={67}
|
|
327
|
+
memLoad={72}
|
|
328
|
+
dialogMetrics={[
|
|
329
|
+
{ id: "cpu", label: "CPU", sublabel: "PROCESSOR", value: 67, unit: "%" },
|
|
330
|
+
{ id: "mem", label: "MEMORY", sublabel: "HEAP USAGE", value: 72, unit: "%" },
|
|
331
|
+
{ id: "iops", label: "IOPS", sublabel: "DISK OPS", value: 45, unit: "k/s", icon: "disk" },
|
|
332
|
+
{
|
|
333
|
+
id: "threads",
|
|
334
|
+
label: "THREADS",
|
|
335
|
+
sublabel: "ACTIVE",
|
|
336
|
+
value: 82,
|
|
337
|
+
unit: "%",
|
|
338
|
+
warnAt: 60,
|
|
339
|
+
critAt: 80,
|
|
340
|
+
icon: "cpu",
|
|
341
|
+
},
|
|
342
|
+
]}
|
|
343
|
+
/>
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
Each `ComponentDialogMetric`:
|
|
347
|
+
|
|
348
|
+
```ts
|
|
349
|
+
interface ComponentDialogMetric {
|
|
350
|
+
id: string; // Unique key
|
|
351
|
+
label: string; // Upper label (e.g. "CPU")
|
|
352
|
+
sublabel: string; // Lower label (e.g. "PROCESSOR")
|
|
353
|
+
value: number; // 0–100 gauge value
|
|
354
|
+
unit?: string; // Suffix (default "%")
|
|
355
|
+
icon?: "cpu" | "mem" | "disk"; // Gauge icon (default "cpu")
|
|
356
|
+
warnAt?: number; // Orange threshold (default 70)
|
|
357
|
+
critAt?: number; // Red threshold (default 85)
|
|
358
|
+
color?: string; // Override bar color (bypasses thresholds)
|
|
191
359
|
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
All compound nodes (`ServerNode`, `DatabaseNode`, `WebDispatcherNode`, `MessageServerNode`) accept `dialogMetrics`.
|
|
363
|
+
|
|
364
|
+
**Live component dialog metrics** — to feed live values into custom gauges, expose each metric value as a prop on your service component and use `dataBindings` to inject them. Then build the `dialogMetrics` array from those live props:
|
|
192
365
|
|
|
193
|
-
|
|
366
|
+
```tsx
|
|
367
|
+
// 1. Define your service component with props for each custom metric
|
|
368
|
+
import { Service, ServerNode } from "react-dashstream";
|
|
369
|
+
import type { ComponentStatus } from "react-dashstream";
|
|
370
|
+
|
|
371
|
+
interface MyServiceProps {
|
|
372
|
+
name: string;
|
|
373
|
+
status?: ComponentStatus;
|
|
374
|
+
cpuLoad?: number;
|
|
375
|
+
memLoad?: number;
|
|
376
|
+
iops?: number;
|
|
377
|
+
threadCount?: number;
|
|
378
|
+
}
|
|
194
379
|
|
|
195
|
-
function
|
|
380
|
+
function MyService({
|
|
381
|
+
name,
|
|
382
|
+
status = "online",
|
|
383
|
+
cpuLoad = 42,
|
|
384
|
+
memLoad = 60,
|
|
385
|
+
iops = 20,
|
|
386
|
+
threadCount = 45,
|
|
387
|
+
}: MyServiceProps) {
|
|
196
388
|
return (
|
|
197
389
|
<Service
|
|
198
390
|
name={name}
|
|
199
|
-
status=
|
|
200
|
-
connections={
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
]}
|
|
391
|
+
status={status}
|
|
392
|
+
connections={
|
|
393
|
+
[
|
|
394
|
+
/* ... */
|
|
395
|
+
]
|
|
396
|
+
}
|
|
206
397
|
>
|
|
207
398
|
<ServerNode
|
|
208
399
|
ex={200}
|
|
209
400
|
ey={380}
|
|
210
401
|
compactOffset={{ x: -30, y: -20 }}
|
|
211
402
|
zIndex={8}
|
|
212
|
-
name="
|
|
213
|
-
subLabel="
|
|
214
|
-
status=
|
|
215
|
-
cpuLoad={
|
|
216
|
-
memLoad={
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
403
|
+
name="SRV-01"
|
|
404
|
+
subLabel="APP SERVER"
|
|
405
|
+
status={status}
|
|
406
|
+
cpuLoad={cpuLoad}
|
|
407
|
+
memLoad={memLoad}
|
|
408
|
+
dialogMetrics={[
|
|
409
|
+
{ id: "cpu", label: "CPU", sublabel: "PROCESSOR", value: cpuLoad },
|
|
410
|
+
{ id: "mem", label: "MEMORY", sublabel: "HEAP", value: memLoad },
|
|
411
|
+
{
|
|
412
|
+
id: "iops",
|
|
413
|
+
label: "IOPS",
|
|
414
|
+
sublabel: "DISK OPS",
|
|
415
|
+
value: iops,
|
|
416
|
+
icon: "disk",
|
|
417
|
+
warnAt: 50,
|
|
418
|
+
critAt: 80,
|
|
419
|
+
},
|
|
420
|
+
{
|
|
421
|
+
id: "threads",
|
|
422
|
+
label: "THREADS",
|
|
423
|
+
sublabel: "ACTIVE",
|
|
424
|
+
value: threadCount,
|
|
425
|
+
icon: "cpu",
|
|
426
|
+
warnAt: 60,
|
|
427
|
+
critAt: 85,
|
|
428
|
+
},
|
|
429
|
+
]}
|
|
430
|
+
alert={{ offsetX: -160, offsetY: -60, align: "left" }}
|
|
240
431
|
/>
|
|
241
432
|
</Service>
|
|
242
433
|
);
|
|
243
434
|
}
|
|
244
435
|
|
|
245
|
-
//
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
}
|
|
436
|
+
// 2. Bind each prop to a live query
|
|
437
|
+
<AIOPsDashboard
|
|
438
|
+
liveData={true}
|
|
439
|
+
dataEndpoint="https://prometheus.example.com/api/v1/query"
|
|
440
|
+
dataBindings={{
|
|
441
|
+
"My Service": {
|
|
442
|
+
cpuLoad: 'cpu_usage{instance="srv-01"}',
|
|
443
|
+
memLoad: 'memory_usage{instance="srv-01"}',
|
|
444
|
+
iops: 'disk_iops{instance="srv-01"}',
|
|
445
|
+
threadCount: 'active_threads{instance="srv-01"}',
|
|
446
|
+
status: { query: 'cpu_usage{instance="srv-01"}', transform: statusFromValue },
|
|
447
|
+
},
|
|
448
|
+
}}
|
|
449
|
+
services={[{ name: "My Service", status: "online" }]}
|
|
450
|
+
>
|
|
451
|
+
<MyService name="My Service" />
|
|
452
|
+
</AIOPsDashboard>;
|
|
255
453
|
```
|
|
256
454
|
|
|
455
|
+
The dashboard injects `cpuLoad`, `memLoad`, `iops`, and `threadCount` as live props into `MyService`. Those flow into the `dialogMetrics` array, so the component dialog gauges update automatically on every poll cycle. This works for any number of custom metrics — just add a prop for each one.
|
|
456
|
+
|
|
257
457
|
---
|
|
258
458
|
|
|
259
|
-
|
|
459
|
+
### 4. Alerts — automatic threshold detection
|
|
260
460
|
|
|
261
|
-
|
|
461
|
+
Nodes **automatically** show alert callouts when metrics breach thresholds:
|
|
262
462
|
|
|
263
|
-
|
|
463
|
+
- **Warning** at 70% (orange callout)
|
|
464
|
+
- **Critical** at 85% (red callout)
|
|
465
|
+
|
|
466
|
+
This works from `cpuLoad`, `memLoad`, `traffic`, `queueDepth`, or `capacity` — no extra code needed:
|
|
264
467
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
468
|
+
```tsx
|
|
469
|
+
// This server shows a critical alert automatically because cpuLoad > 85
|
|
470
|
+
<ServerNode
|
|
471
|
+
ex={200}
|
|
472
|
+
ey={380}
|
|
473
|
+
compactOffset={{ x: -30, y: -20 }}
|
|
474
|
+
zIndex={8}
|
|
475
|
+
name="SRV-01"
|
|
476
|
+
subLabel="PROCESSOR"
|
|
477
|
+
status="online"
|
|
478
|
+
cpuLoad={92}
|
|
479
|
+
memLoad={64}
|
|
480
|
+
/>
|
|
481
|
+
```
|
|
270
482
|
|
|
271
|
-
|
|
483
|
+
**Position the callout:**
|
|
272
484
|
|
|
273
485
|
```tsx
|
|
274
|
-
|
|
275
|
-
|
|
486
|
+
<ServerNode
|
|
487
|
+
cpuLoad={92}
|
|
488
|
+
alert={{ offsetX: -160, offsetY: -60, align: "left" }}
|
|
489
|
+
...
|
|
490
|
+
/>
|
|
491
|
+
```
|
|
276
492
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
}}
|
|
299
|
-
serviceDataBindings={{
|
|
300
|
-
"My Service": [
|
|
301
|
-
{ label: "Uptime", query: 'uptime{svc="my-service"}', unit: "%", color: "#00ff88" },
|
|
302
|
-
{ label: "Latency", query: 'latency{svc="my-service"}', unit: "ms", color: "#00e5ff" },
|
|
303
|
-
{
|
|
304
|
-
label: "Error Rate",
|
|
305
|
-
query: 'error_rate{svc="my-service"}',
|
|
306
|
-
unit: "%",
|
|
307
|
-
color: "#ff2255",
|
|
308
|
-
},
|
|
309
|
-
],
|
|
310
|
-
}}
|
|
311
|
-
>
|
|
312
|
-
<Service name="My Service" status="online" connections={[]}>
|
|
313
|
-
<ServerNode
|
|
314
|
-
ex={200}
|
|
315
|
-
ey={380}
|
|
316
|
-
compactOffset={{ x: -30, y: -20 }}
|
|
317
|
-
zIndex={8}
|
|
318
|
-
name="SRV-01"
|
|
319
|
-
subLabel="APP SERVER"
|
|
320
|
-
status="online"
|
|
321
|
-
cpuLoad={0}
|
|
322
|
-
memLoad={0}
|
|
323
|
-
/>
|
|
324
|
-
<DatabaseNode
|
|
325
|
-
ex={460}
|
|
326
|
-
ey={380}
|
|
327
|
-
compactOffset={{ x: 30, y: -20 }}
|
|
328
|
-
zIndex={7}
|
|
329
|
-
name="DB-01"
|
|
330
|
-
subLabel="PRIMARY"
|
|
331
|
-
status="online"
|
|
332
|
-
capacity={55}
|
|
333
|
-
/>
|
|
334
|
-
</Service>
|
|
335
|
-
</AIOPsDashboard>
|
|
336
|
-
);
|
|
337
|
-
}
|
|
493
|
+
**Custom alert message:**
|
|
494
|
+
|
|
495
|
+
```tsx
|
|
496
|
+
<ServerNode
|
|
497
|
+
cpuLoad={92}
|
|
498
|
+
alert={{ msg: "CPU overload — scale out", offsetX: -160, offsetY: -60, align: "left" }}
|
|
499
|
+
...
|
|
500
|
+
/>
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
**Custom thresholds** via `dialogMetrics`:
|
|
504
|
+
|
|
505
|
+
```tsx
|
|
506
|
+
<ServerNode
|
|
507
|
+
dialogMetrics={[
|
|
508
|
+
{ id: "cpu", label: "CPU", sublabel: "PROCESSOR", value: 67,
|
|
509
|
+
warnAt: 50, critAt: 75 }, // Alert triggers at 67% because critAt is 75
|
|
510
|
+
]}
|
|
511
|
+
alert={{ offsetX: -160, offsetY: -60, align: "left" }}
|
|
512
|
+
...
|
|
513
|
+
/>
|
|
338
514
|
```
|
|
339
515
|
|
|
340
|
-
|
|
516
|
+
Alert `align` options: `"left"`, `"right"`, `"top"`, `"bottom"`.
|
|
517
|
+
|
|
518
|
+
---
|
|
519
|
+
|
|
520
|
+
### 5. Drill-down internals — custom sub-components
|
|
521
|
+
|
|
522
|
+
When you click a node in expanded view, a **drill-down** opens showing internal sub-components (CPUs, memory sticks, drives, etc.). By default these are auto-generated based on node type.
|
|
523
|
+
|
|
524
|
+
Provide **custom sub-components** via the `subComponents` prop:
|
|
341
525
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
526
|
+
```tsx
|
|
527
|
+
import { ServerNode, CPU3D, Memory3D, DriveBay3D, ThreadPool3D } from "react-dashstream";
|
|
528
|
+
import type { SubComponentConfig } from "react-dashstream";
|
|
529
|
+
|
|
530
|
+
const internals: SubComponentConfig[] = [
|
|
531
|
+
{
|
|
532
|
+
id: "cpu-0",
|
|
533
|
+
label: "CPU-0",
|
|
534
|
+
status: "online",
|
|
535
|
+
element: <CPU3D label="CPU-0" load={67} color="#00e5ff" />,
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
id: "cpu-1",
|
|
539
|
+
label: "CPU-1",
|
|
540
|
+
status: "warning",
|
|
541
|
+
element: <CPU3D label="CPU-1" load={88} color="#ff8c00" status="warning" />,
|
|
542
|
+
},
|
|
543
|
+
{
|
|
544
|
+
id: "heap",
|
|
545
|
+
label: "HEAP",
|
|
546
|
+
status: "online",
|
|
547
|
+
element: <Memory3D label="HEAP" usedPercent={72} color="#8855ee" />,
|
|
548
|
+
},
|
|
549
|
+
{
|
|
550
|
+
id: "drive",
|
|
551
|
+
label: "DRIVE-0",
|
|
552
|
+
status: "online",
|
|
553
|
+
element: <DriveBay3D label="DRIVE-0" color="#00e5ff" activity={true} />,
|
|
554
|
+
},
|
|
555
|
+
{
|
|
556
|
+
id: "threads",
|
|
557
|
+
label: "THREADS",
|
|
558
|
+
status: "online",
|
|
559
|
+
element: <ThreadPool3D label="THREADS" color="#00e5ff" />,
|
|
560
|
+
},
|
|
561
|
+
];
|
|
350
562
|
|
|
351
|
-
|
|
563
|
+
<ServerNode
|
|
564
|
+
ex={200}
|
|
565
|
+
ey={380}
|
|
566
|
+
compactOffset={{ x: -30, y: -20 }}
|
|
567
|
+
zIndex={8}
|
|
568
|
+
name="SRV-01"
|
|
569
|
+
subLabel="APP SERVER"
|
|
570
|
+
status="online"
|
|
571
|
+
cpuLoad={67}
|
|
572
|
+
memLoad={72}
|
|
573
|
+
subComponents={internals}
|
|
574
|
+
/>;
|
|
575
|
+
```
|
|
352
576
|
|
|
353
|
-
Each
|
|
577
|
+
Each `SubComponentConfig`:
|
|
354
578
|
|
|
355
579
|
```ts
|
|
356
|
-
|
|
357
|
-
|
|
580
|
+
interface SubComponentConfig {
|
|
581
|
+
id: string; // Unique key
|
|
582
|
+
label: string; // Display name
|
|
583
|
+
status: ComponentStatus; // Drives LED color
|
|
584
|
+
detail?: string; // Shown on fault
|
|
585
|
+
element: ReactNode; // The 3D element to render
|
|
586
|
+
}
|
|
358
587
|
```
|
|
359
588
|
|
|
360
|
-
|
|
589
|
+
Available internal 3D components: `CPU3D`, `Memory3D`, `DriveBay3D`, `NetworkBlock3D`, `ThreadPool3D`, `Platter3D`, `Port3D`.
|
|
361
590
|
|
|
362
|
-
|
|
591
|
+
---
|
|
363
592
|
|
|
364
|
-
|
|
593
|
+
### 6. Graph series — custom sparklines
|
|
594
|
+
|
|
595
|
+
The drill-down also shows a **historical graph panel** with sparklines. By default, graphs are auto-generated from mock data.
|
|
596
|
+
|
|
597
|
+
Provide **custom graph data** via the `graphSeries` prop:
|
|
598
|
+
|
|
599
|
+
```tsx
|
|
600
|
+
import type { GraphSeries } from "react-dashstream";
|
|
601
|
+
|
|
602
|
+
const graphs: GraphSeries[] = [
|
|
603
|
+
{ id: "cpu", label: "CPU-0", unit: "%", color: "#00e5ff", data: [45, 52, 67, 71, 68, 55, 62] },
|
|
604
|
+
{ id: "mem", label: "HEAP", unit: "%", color: "#8855ee", data: [60, 65, 72, 78, 82, 75, 70] },
|
|
605
|
+
{ id: "iops", label: "DISK", unit: "k/s", color: "#ff8c00", data: [12, 15, 22, 18, 25, 20, 16] },
|
|
606
|
+
];
|
|
607
|
+
|
|
608
|
+
<ServerNode
|
|
609
|
+
ex={200}
|
|
610
|
+
ey={380}
|
|
611
|
+
compactOffset={{ x: -30, y: -20 }}
|
|
612
|
+
zIndex={8}
|
|
613
|
+
name="SRV-01"
|
|
614
|
+
subLabel="APP SERVER"
|
|
615
|
+
status="online"
|
|
616
|
+
cpuLoad={67}
|
|
617
|
+
memLoad={72}
|
|
618
|
+
graphSeries={graphs}
|
|
619
|
+
/>;
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
Each `GraphSeries`:
|
|
365
623
|
|
|
366
624
|
```ts
|
|
367
|
-
interface
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
unit
|
|
371
|
-
color
|
|
372
|
-
|
|
625
|
+
interface GraphSeries {
|
|
626
|
+
id: string; // Unique key
|
|
627
|
+
label: string; // Label above the sparkline
|
|
628
|
+
unit: string; // Suffix (e.g. "%", "kbps")
|
|
629
|
+
color: string; // Sparkline color
|
|
630
|
+
data: number[]; // Data points (most recent last)
|
|
373
631
|
}
|
|
374
632
|
```
|
|
375
633
|
|
|
376
|
-
|
|
634
|
+
---
|
|
377
635
|
|
|
378
|
-
###
|
|
636
|
+
### 7. Putting it all together
|
|
379
637
|
|
|
380
|
-
|
|
638
|
+
A complete example with live data, service dialog metrics, component dialog gauges, sub-components, graphs, and alert positioning:
|
|
381
639
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
| **Auth headers** | `access-key` and `access-secret-key` |
|
|
387
|
-
| **Response body** | Plain text or JSON. The default transform parses the trimmed body as a number; non-numeric values are returned as strings. |
|
|
388
|
-
| **Error handling** | Non-2xx responses are counted as failures. Partial failures are reported in the header. |
|
|
640
|
+
```tsx
|
|
641
|
+
import "react-dashstream/dist/index.css";
|
|
642
|
+
import { AIOPsDashboard, Service, ServerNode, DatabaseNode, CPU3D, Memory3D } from "react-dashstream";
|
|
643
|
+
import type { ServiceMeta, DataBindings, ServiceMetricBinding } from "react-dashstream";
|
|
389
644
|
|
|
390
|
-
|
|
645
|
+
const services: ServiceMeta[] = [
|
|
646
|
+
{
|
|
647
|
+
name: "My Service",
|
|
648
|
+
status: "online",
|
|
649
|
+
metrics: [{ label: "Uptime", value: "99.99%", color: "#00ff88" }],
|
|
650
|
+
alerts: [{ level: "info", message: "All Systems Nominal" }],
|
|
651
|
+
},
|
|
652
|
+
];
|
|
391
653
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
654
|
+
function statusFromValue(raw: unknown) {
|
|
655
|
+
const n = Number(raw);
|
|
656
|
+
if (n >= 85) return "critical";
|
|
657
|
+
if (n >= 70) return "warning";
|
|
658
|
+
return "online";
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
const dataBindings: DataBindings = {
|
|
662
|
+
"My Service": {
|
|
663
|
+
cpuLoad: 'cpu_usage{instance="srv-01"}',
|
|
664
|
+
memLoad: 'memory_usage{instance="srv-01"}',
|
|
665
|
+
status: { query: 'cpu_usage{instance="srv-01"}', transform: statusFromValue },
|
|
666
|
+
dbCapacity: 'disk_capacity{instance="db-01"}',
|
|
667
|
+
dbStatus: { query: 'disk_capacity{instance="db-01"}', transform: statusFromValue },
|
|
668
|
+
},
|
|
669
|
+
};
|
|
670
|
+
|
|
671
|
+
const serviceDataBindings: Record<string, ServiceMetricBinding[]> = {
|
|
672
|
+
"My Service": [
|
|
673
|
+
{ label: "CPU Load", query: 'cpu_usage{instance="srv-01"}', unit: "%", color: "#00e5ff" },
|
|
674
|
+
{ label: "Memory", query: 'memory_usage{instance="srv-01"}', unit: "%", color: "#bb55ff" },
|
|
675
|
+
{ label: "Disk", query: 'disk_capacity{instance="db-01"}', unit: "%", color: "#ff8c00" },
|
|
676
|
+
],
|
|
677
|
+
};
|
|
678
|
+
|
|
679
|
+
function MyService({ name, status, cpuLoad, memLoad, dbCapacity, dbStatus }: any) {
|
|
680
|
+
return (
|
|
681
|
+
<Service
|
|
682
|
+
name={name}
|
|
683
|
+
status={status ?? "online"}
|
|
684
|
+
connections={[
|
|
685
|
+
{ from: [330, 200], to: [200, 380], visibleAtPhase: 3 },
|
|
686
|
+
{ from: [330, 200], to: [460, 380], visibleAtPhase: 3 },
|
|
687
|
+
]}
|
|
688
|
+
>
|
|
689
|
+
<ServerNode
|
|
690
|
+
ex={200}
|
|
691
|
+
ey={380}
|
|
692
|
+
compactOffset={{ x: -30, y: -20 }}
|
|
693
|
+
zIndex={8}
|
|
694
|
+
name="SRV-01"
|
|
695
|
+
subLabel="APP SERVER"
|
|
696
|
+
status={status ?? "online"}
|
|
697
|
+
cpuLoad={cpuLoad ?? 42}
|
|
698
|
+
memLoad={memLoad ?? 60}
|
|
699
|
+
alert={{ offsetX: -160, offsetY: -60, align: "left" }}
|
|
700
|
+
subComponents={[
|
|
701
|
+
{
|
|
702
|
+
id: "cpu",
|
|
703
|
+
label: "CPU-0",
|
|
704
|
+
status: "online",
|
|
705
|
+
element: <CPU3D label="CPU-0" load={cpuLoad ?? 42} />,
|
|
706
|
+
},
|
|
707
|
+
{
|
|
708
|
+
id: "mem",
|
|
709
|
+
label: "HEAP",
|
|
710
|
+
status: "online",
|
|
711
|
+
element: <Memory3D label="HEAP" usedPercent={memLoad ?? 60} />,
|
|
712
|
+
},
|
|
713
|
+
]}
|
|
714
|
+
graphSeries={[
|
|
715
|
+
{ id: "cpu", label: "CPU", unit: "%", color: "#00e5ff", data: [45, 52, 67, 71, 68] },
|
|
716
|
+
]}
|
|
717
|
+
/>
|
|
718
|
+
<DatabaseNode
|
|
719
|
+
ex={460}
|
|
720
|
+
ey={380}
|
|
721
|
+
compactOffset={{ x: 30, y: -20 }}
|
|
722
|
+
zIndex={7}
|
|
723
|
+
name="DB-01"
|
|
724
|
+
subLabel="PRIMARY"
|
|
725
|
+
status={dbStatus ?? "online"}
|
|
726
|
+
capacity={dbCapacity ?? 55}
|
|
727
|
+
alert={{ offsetX: 160, offsetY: -60, align: "right" }}
|
|
728
|
+
/>
|
|
729
|
+
</Service>
|
|
730
|
+
);
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
export default function App() {
|
|
734
|
+
return (
|
|
735
|
+
<AIOPsDashboard
|
|
736
|
+
brandName="MY DASHBOARD"
|
|
737
|
+
services={services}
|
|
738
|
+
liveData={true}
|
|
739
|
+
dataEndpoint="https://prometheus.example.com/api/v1/query"
|
|
740
|
+
dataRefreshInterval={10000}
|
|
741
|
+
dataBindings={dataBindings}
|
|
742
|
+
serviceDataBindings={serviceDataBindings}
|
|
743
|
+
>
|
|
744
|
+
<MyService name="My Service" />
|
|
745
|
+
</AIOPsDashboard>
|
|
746
|
+
);
|
|
747
|
+
}
|
|
397
748
|
```
|
|
398
749
|
|
|
399
|
-
|
|
750
|
+
---
|
|
400
751
|
|
|
401
|
-
|
|
752
|
+
### 8. Data hooks
|
|
753
|
+
|
|
754
|
+
Access live data anywhere inside the dashboard tree:
|
|
402
755
|
|
|
403
756
|
```tsx
|
|
404
757
|
import { useAIOpsData, useAIOpsDataOptional, useQueryResult } from "react-dashstream";
|
|
405
758
|
|
|
406
759
|
function CustomWidget() {
|
|
407
|
-
const { data, isRefreshing, lastRefreshError
|
|
408
|
-
|
|
409
|
-
const cpuValue = useQueryResult('cpu_usage{instance="srv-01"}');
|
|
760
|
+
const { data, isRefreshing, lastRefreshError } = useAIOpsData();
|
|
761
|
+
const cpu = useQueryResult('cpu_usage{instance="srv-01"}');
|
|
410
762
|
|
|
411
763
|
return (
|
|
412
764
|
<div>
|
|
413
765
|
{isRefreshing && <span>Refreshing...</span>}
|
|
414
|
-
{lastRefreshError && <span>
|
|
415
|
-
<span>CPU: {String(
|
|
766
|
+
{lastRefreshError && <span>{lastRefreshError}</span>}
|
|
767
|
+
<span>CPU: {String(cpu)}</span>
|
|
416
768
|
</div>
|
|
417
769
|
);
|
|
418
770
|
}
|
|
419
771
|
```
|
|
420
772
|
|
|
421
|
-
| Hook |
|
|
422
|
-
| ------------------------ |
|
|
423
|
-
| `useAIOpsData()` |
|
|
424
|
-
| `useAIOpsDataOptional()` |
|
|
425
|
-
| `useQueryResult(query)` |
|
|
773
|
+
| Hook | Returns | Throws? |
|
|
774
|
+
| ------------------------ | -------------------------- | ---------------------------- |
|
|
775
|
+
| `useAIOpsData()` | Full `DataContextValue` | Yes — outside `DataProvider` |
|
|
776
|
+
| `useAIOpsDataOptional()` | `DataContextValue \| null` | No |
|
|
777
|
+
| `useQueryResult(query)` | Raw response or `null` | Yes — outside `DataProvider` |
|
|
426
778
|
|
|
427
|
-
### Standalone DataProvider
|
|
779
|
+
### 9. Standalone DataProvider
|
|
428
780
|
|
|
429
|
-
|
|
781
|
+
Use the data layer without the full dashboard shell:
|
|
430
782
|
|
|
431
783
|
```tsx
|
|
432
784
|
import { DataProvider, useAIOpsData } from "react-dashstream";
|
|
433
785
|
|
|
434
|
-
function
|
|
786
|
+
function MyApp() {
|
|
435
787
|
return (
|
|
436
788
|
<DataProvider
|
|
437
789
|
config={{
|
|
438
790
|
endpoint: "https://prometheus.example.com/api/v1/query",
|
|
439
|
-
queries: ['cpu_usage{instance="srv-01"}'
|
|
791
|
+
queries: ['cpu_usage{instance="srv-01"}'],
|
|
440
792
|
refreshInterval: 15000,
|
|
441
793
|
}}
|
|
442
794
|
>
|
|
443
|
-
<
|
|
795
|
+
<MyContent />
|
|
444
796
|
</DataProvider>
|
|
445
797
|
);
|
|
446
798
|
}
|
|
@@ -462,15 +814,15 @@ function MyCustomDashboard() {
|
|
|
462
814
|
|
|
463
815
|
These combine `ServiceNode` + 3D model + `componentInfo` into a single element:
|
|
464
816
|
|
|
465
|
-
| Component | Key props
|
|
466
|
-
| ------------------- |
|
|
467
|
-
| `ServerNode` | `status`, `cpuLoad`, `memLoad`, `brandLabel` |
|
|
468
|
-
| `DatabaseNode` | `status`, `capacity` | Three-platter database cylinder with capacity bar. |
|
|
469
|
-
| `WebDispatcherNode` | `status`, `traffic`, `activeRoutes` | Network appliance with 8 port LEDs and traffic metrics. |
|
|
470
|
-
| `MessageServerNode` | `status`, `queueDepth`, `msgsPerSec`, `instances` | Message server with instance LEDs and queue metrics. |
|
|
471
|
-
| `HumanNode` | `status`, `scale`
|
|
817
|
+
| Component | Key props | Description |
|
|
818
|
+
| ------------------- | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- |
|
|
819
|
+
| `ServerNode` | `status`, `cpuLoad`, `memLoad`, `brandLabel`, `dialogMetrics`, `subComponents`, `graphSeries`, `alert` | App server tower with LEDs and CPU/memory bars. |
|
|
820
|
+
| `DatabaseNode` | `status`, `capacity`, `dialogMetrics`, `subComponents`, `graphSeries`, `alert` | Three-platter database cylinder with capacity bar. |
|
|
821
|
+
| `WebDispatcherNode` | `status`, `traffic`, `activeRoutes`, `dialogMetrics`, `subComponents`, `graphSeries`, `alert` | Network appliance with 8 port LEDs and traffic metrics. |
|
|
822
|
+
| `MessageServerNode` | `status`, `queueDepth`, `msgsPerSec`, `instances`, `dialogMetrics`, `subComponents`, `graphSeries`, `alert` | Message server with instance LEDs and queue metrics. |
|
|
823
|
+
| `HumanNode` | `status`, `scale` | SVG wireframe person icon for user/actor nodes. |
|
|
472
824
|
|
|
473
|
-
All compound nodes share: `ex`, `ey`, `compactOffset`, `zIndex`, `name`, `subLabel`, `color`, `delay`, `visibleAtPhase
|
|
825
|
+
All compound nodes share: `ex`, `ey`, `compactOffset`, `zIndex`, `name`, `subLabel`, `color`, `delay`, `visibleAtPhase`.
|
|
474
826
|
|
|
475
827
|
### 3D models (low-level)
|
|
476
828
|
|
|
@@ -518,7 +870,7 @@ Compose compound nodes inside a `Service` container. Each node needs:
|
|
|
518
870
|
- **`ex`, `ey`** — Position in the expanded topology (pixels from top-left of scene).
|
|
519
871
|
- **`compactOffset`** — Offset from the service center in the compact carousel view.
|
|
520
872
|
- **`zIndex`** — Stacking order (higher tiers get higher values).
|
|
521
|
-
- **`visibleAtPhase`** — When the node fades in during expansion (0–6). Use `2` for top-tier
|
|
873
|
+
- **`visibleAtPhase`** — When the node fades in during expansion (0–6). Use `2` for top-tier, `3` for middle, etc.
|
|
522
874
|
|
|
523
875
|
Define connection lines between nodes via the `connections` prop on `Service`:
|
|
524
876
|
|
|
@@ -529,41 +881,6 @@ connections={[
|
|
|
529
881
|
]}
|
|
530
882
|
```
|
|
531
883
|
|
|
532
|
-
### Alerts
|
|
533
|
-
|
|
534
|
-
Nodes automatically detect threshold breaches and render alert callouts. Default thresholds:
|
|
535
|
-
|
|
536
|
-
- **Warning** at 70%
|
|
537
|
-
- **Critical** at 85%
|
|
538
|
-
|
|
539
|
-
Position the callout with the `alert` prop:
|
|
540
|
-
|
|
541
|
-
```tsx
|
|
542
|
-
<ServerNode
|
|
543
|
-
alert={{ offsetX: -160, offsetY: -60, align: "left" }}
|
|
544
|
-
cpuLoad={99}
|
|
545
|
-
...
|
|
546
|
-
/>
|
|
547
|
-
```
|
|
548
|
-
|
|
549
|
-
### Service dialog
|
|
550
|
-
|
|
551
|
-
Pass `ServiceMeta` objects to `AIOPsDashboard` via the `services` prop to populate the stats panel that appears when a service is expanded:
|
|
552
|
-
|
|
553
|
-
```tsx
|
|
554
|
-
const services: ServiceMeta[] = [
|
|
555
|
-
{
|
|
556
|
-
name: "My Service",
|
|
557
|
-
status: "online",
|
|
558
|
-
metrics: [
|
|
559
|
-
{ label: "Service Health", value: "99.9%", color: "#00ff88" },
|
|
560
|
-
{ label: "Avg Response Time", value: "14ms", color: "#00e5ff" },
|
|
561
|
-
],
|
|
562
|
-
alerts: [{ level: "info", message: "All Systems Nominal" }],
|
|
563
|
-
},
|
|
564
|
-
];
|
|
565
|
-
```
|
|
566
|
-
|
|
567
884
|
---
|
|
568
885
|
|
|
569
886
|
## Status types
|