react-dashstream 0.3.1 → 0.3.3

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.
@@ -0,0 +1,198 @@
1
+ ---
2
+ name: dashstream-datacenter-view
3
+ description: Build topology maps with DatacenterView, buildings, geography, and drill-down
4
+ license: MIT
5
+ compatibility: opencode
6
+ metadata:
7
+ audience: developers
8
+ workflow: react
9
+ ---
10
+
11
+ ## What I do
12
+
13
+ - Document `DatacenterView` — SVG topology or geographic map with CSS 3D building markers
14
+ - Explain both array config and declarative JSX composition APIs
15
+ - Cover sites, building variants, connections, metric bindings, and geography
16
+ - Show how drill-down integrates with `AIOPsDashboard`
17
+
18
+ ## When to use me
19
+
20
+ Use this when building a datacenter topology map, geographic view, or configuring building markers with drill-down dashboards.
21
+
22
+ ---
23
+
24
+ ## Overview
25
+
26
+ 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.
27
+
28
+ ---
29
+
30
+ ## Data model
31
+
32
+ - **`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`).
33
+ - **`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. **`DatacenterSite`** can supply `label` / `subtitle` per `siteId`; the **`siteLabels`** prop merges on top (prop wins on conflict).
34
+
35
+ ---
36
+
37
+ ## Minimal usage (array config)
38
+
39
+ ```tsx
40
+ import "react-dashstream/dist/index.css";
41
+ import { DatacenterView } from "react-dashstream";
42
+ import type { DatacenterBuildingConfig, DatacenterConnection } from "react-dashstream";
43
+
44
+ const dataCenters: DatacenterBuildingConfig[] = [
45
+ /* id, x, y (%), metrics, services, renderServices, variant, siteId? … */
46
+ ];
47
+ const connections: DatacenterConnection[] = [];
48
+
49
+ <DatacenterView dataCenters={dataCenters} connections={connections} />
50
+ ```
51
+
52
+ ---
53
+
54
+ ## Declarative JSX topology
55
+
56
+ Instead of a `dataCenters` array, pass `children` using `DatacenterSite` and shape components:
57
+
58
+ ```tsx
59
+ import "react-dashstream/dist/index.css";
60
+ import { DatacenterView, DatacenterSite, TowerDC, FlatDC } from "react-dashstream";
61
+
62
+ <DatacenterView connections={[]}>
63
+ <DatacenterSite siteId="riyadh-hub" x={42} y={38} label="Riyadh hub" subtitle="Primary region">
64
+ <TowerDC
65
+ id="dc-east-1"
66
+ name="East tower"
67
+ subtitle="Tier III"
68
+ status="online"
69
+ metrics={{
70
+ carbonEmissions: 0,
71
+ powerUtilization: 0,
72
+ cooling: 0,
73
+ pue: 1.4,
74
+ uptime: 99.9,
75
+ activeServers: 0,
76
+ temperature: 22,
77
+ networkThroughput: 0,
78
+ }}
79
+ services={[]}
80
+ >
81
+ {/* Service / ServerNode / … drill-down tree */}
82
+ </TowerDC>
83
+ <FlatDC
84
+ id="dc-flat-2"
85
+ name="Flat block"
86
+ subtitle="Storage"
87
+ status="online"
88
+ metrics={{
89
+ carbonEmissions: 0,
90
+ powerUtilization: 0,
91
+ cooling: 0,
92
+ pue: 1.3,
93
+ uptime: 99.5,
94
+ activeServers: 0,
95
+ temperature: 21,
96
+ networkThroughput: 0,
97
+ }}
98
+ services={[]}
99
+ />
100
+ </DatacenterSite>
101
+ </DatacenterView>
102
+ ```
103
+
104
+ **Available building shapes:** `StandardDC`, `TowerDC`, `FlatDC`, `StorageDC`, `GoogleDC`, `MicroDC`, `OfficeDC` (alias of `MicroDC`). Use `Datacenter` with `variant` for a single generic component.
105
+
106
+ Building components render `null` on the map; `children` on each building are the drill-down `Service` tree (same as `renderServices()` in the array API).
107
+
108
+ `collectDatacenterTree(children)` is available if you need the resolved `DatacenterBuildingConfig[]` outside the view.
109
+
110
+ ---
111
+
112
+ ## Connections
113
+
114
+ ```ts
115
+ interface DatacenterConnection {
116
+ from: string; // Building id or siteId
117
+ to: string; // Building id or siteId
118
+ throughput: string; // Label (e.g. "10 Gbps")
119
+ isExternal?: boolean; // External link styling
120
+ }
121
+ ```
122
+
123
+ ---
124
+
125
+ ## DatacenterMetrics
126
+
127
+ ```ts
128
+ interface DatacenterMetrics {
129
+ carbonEmissions: number;
130
+ powerUtilization: number;
131
+ cooling: number;
132
+ pue: number;
133
+ uptime: number;
134
+ activeServers: number;
135
+ temperature: number;
136
+ networkThroughput: number;
137
+ }
138
+ ```
139
+
140
+ Used on markers and for site-level aggregation.
141
+
142
+ ---
143
+
144
+ ## Mock metrics
145
+
146
+ Pass `dataCenters` with embedded `metrics`. No `DataProvider` required.
147
+
148
+ ---
149
+
150
+ ## PromQL (live) metrics on markers
151
+
152
+ 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`).
153
+ 2. Pass **`metricBindings`**: `Record<buildingId, Partial<Record<keyof DatacenterMetrics, DataBinding>>>` — same `DataBinding` shape as service-level bindings (`string` or `{ query, transform? }`).
154
+ 3. `DatacenterView` calls `useAIOpsDataOptional()` and merges transformed numbers over each building's static `metrics` (site-level rows aggregate the merged per-building values).
155
+
156
+ This path is **independent** of `AIOPsDashboard`'s `dataBindings` (which key off service `name` on carousel children).
157
+
158
+ ---
159
+
160
+ ## Drill-down dashboard
161
+
162
+ `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.
163
+
164
+ ---
165
+
166
+ ## Geography (optional)
167
+
168
+ `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`).
169
+
170
+ ---
171
+
172
+ ## DatacenterViewProps (full reference)
173
+
174
+ | Prop | Type | Default | Notes |
175
+ |------|------|---------|-------|
176
+ | `children` | `ReactNode` | — | Declarative topology (`DatacenterSite`, `TowerDC`, …). When set, `dataCenters` is ignored (dev warning if both are passed) |
177
+ | `dataCenters` | `DatacenterBuildingConfig[]` | `[]` | Flat / JSON-friendly config; required unless `children` is used |
178
+ | `connections` | `DatacenterConnection[]` | `[]` | Link lines between building or site ids |
179
+ | `metricBindings` | `DatacenterMetricBindings` | — | Building id → metric field → PromQL `DataBinding`; needs `DataProvider` + `extractDatacenterMetricQueries` |
180
+ | `dataTransform` | `(raw: unknown) => unknown` | `defaultDataTransform` | Applied to each binding unless overridden per binding |
181
+ | `geography` | `DatacenterGeography` | — | `outlinePathD` + optional `referencePoints` (SVG coords) |
182
+ | `showGeography` | `boolean` | `false` | When true, draws outline + reference points |
183
+ | `mapTitle` | `string` | `"Geography — Operations"` | Header when `showGeography` |
184
+ | `topologyTitle` | `string` | `"Network topology"` | Header when not showing geography |
185
+ | `topologyAffiliatesLabel` | `string` | `"AFFILIATES"` | Label in topology-only mode (affiliates zone) |
186
+ | `brandText` | `string` | `"AIOps"` | Header brand |
187
+ | `headerTag` | `string` | `"COMMAND CENTER"` | Corner tag |
188
+ | `initialBuildingId` | `string` | — | Building id to open when `openDashboardOnMount` is true |
189
+ | `openDashboardOnMount` | `boolean` | `false` | Auto-zoom into `initialBuildingId` |
190
+ | `onNavigateEvents` | `() => void` | — | e.g. switch app view to event console |
191
+ | `theme` | `DashboardTheme` | — | Passed through to drill-down dashboard |
192
+ | `onThemeChange` | `(t) => void` | — | |
193
+ | `backgroundImage` / `lightBackgroundImage` | `string` | — | Drill-down `AIOPsDashboard` backgrounds |
194
+ | `aiOpsDashboardProps` | `Partial<AIOPsDashboardProps>` | — | Spread first; `services`, children, theme, branding overridden from selection |
195
+ | `defaultBuildingBrand` | `string` | `"AIOps"` | Fallback label on 3D building faces |
196
+ | `siteLabels` | `Record<string, DatacenterSiteLabels>` | — | Per-siteId titles for multi-building markers |
197
+ | `showMapScaleControls` | `boolean` | `true` | Size / hover sliders in header (map mode) |
198
+ | `mapFooter` | `ReactNode` | — | Rendered below the map when drill-down is not active |
@@ -0,0 +1,212 @@
1
+ ---
2
+ name: dashstream-event-view
3
+ description: Set up the EventView operations console and event-to-dashboard bridge
4
+ license: MIT
5
+ compatibility: opencode
6
+ metadata:
7
+ audience: developers
8
+ workflow: react
9
+ ---
10
+
11
+ ## What I do
12
+
13
+ - Document `EventView` — the operations event console table component
14
+ - Explain `EventApiConfig`, `EventFieldMapping`, and `AIOpsEvent` types
15
+ - Cover credential resolution, severity mapping, and API polling
16
+ - Document the event-to-dashboard bridge (`eventApiConfig` on `AIOPsDashboard`)
17
+
18
+ ## When to use me
19
+
20
+ Use this when setting up an event console, configuring event API integration, or enabling automatic node alerts from events on the 3D dashboard.
21
+
22
+ ---
23
+
24
+ ## EventView — Operations Event Console
25
+
26
+ 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).
27
+
28
+ ### API mode (primary usage)
29
+
30
+ ```tsx
31
+ import "react-dashstream/dist/index.css";
32
+ import { EventView } from "react-dashstream";
33
+ import type { EventApiConfig } from "react-dashstream";
34
+
35
+ const apiConfig: EventApiConfig = {
36
+ baseUrl: "https://your-monitoring-server.example.com",
37
+ payload: { filter: {}, sortBy: "date_reception", sortOrder: "DESC" },
38
+ fieldMapping: {
39
+ id: "mc_ueid",
40
+ occurrence: "date_reception",
41
+ severityLastModified: "severity_last_modified",
42
+ severity: "severity",
43
+ owner: "owner",
44
+ class: "class",
45
+ host: "mc_host",
46
+ message: "msg",
47
+ remedySupportGroup: "ara_remedy_support_group",
48
+ incidentId: "ara_incident_id",
49
+ smsStatus: "ara_sms_status",
50
+ onCallNumber: "ara_on_call_number",
51
+ hostedApplication: "ara_hosted_application",
52
+ monitoringCategory: "ara_hosted_app_monitoring",
53
+ applicationSupportUnit: "ara_application_support_unit",
54
+ },
55
+ };
56
+
57
+ <EventView apiConfig={apiConfig} />
58
+ ```
59
+
60
+ ### How it works
61
+
62
+ 1. Shows credentials modal (or reuses DataProvider credentials if inside `AIOPsDashboard`)
63
+ 2. Sends `POST {baseUrl}/tsws/monitoring/api/v1.0/events/search` with the payload as JSON body
64
+ 3. Auth via headers: `access-key` and `access-secret-key`
65
+ 4. Expects response: `{ eventSeverityCount: {...}, totalCount: N, eventList: [{...}] }`
66
+ 5. Maps each object in `eventList` to `AIOpsEvent` using `fieldMapping`
67
+ 6. Maps severity strings via `severityMap` (default: `CRITICAL→Critical`, `MAJOR→Major`, `MINOR→Minor`)
68
+ 7. Polls on `refreshInterval` (default 60s)
69
+
70
+ ### Props
71
+
72
+ | Prop | Type | Default | Notes |
73
+ | ---- | ---- | ------- | ----- |
74
+ | `apiConfig` | `EventApiConfig` | — | Required for API mode |
75
+ | `events` | `AIOpsEvent[]` | — | Pre-fetched events (skips API calls) |
76
+ | `credentials` | `Credentials` | — | Explicit creds; falls back to DataProvider → modal |
77
+ | `columnWidthsCookie` | `string` | `"ev_col_widths"` | Cookie name for persisting column widths |
78
+ | `title` | `string` | `"Event Console"` | Header title |
79
+ | `theme` | `DashboardTheme` | — | Optional override; else `ThemeProvider` / default |
80
+
81
+ ### Features
82
+
83
+ - Live API polling with configurable interval and manual refresh button
84
+ - Configurable field mapping — any API response shape can be mapped
85
+ - Shared auth — reuses DataProvider credentials when available
86
+ - Severity filter chips with live counts
87
+ - Free-text search across message, host, owner, incident ID
88
+ - Sortable columns (click header: asc → desc → none)
89
+ - Infinite scroll — all matching events in a single scrollable table
90
+ - Resizable columns — drag column edges; widths persist in cookies
91
+ - Loading spinner, error badge, last-refresh timestamp
92
+ - Light / dark table chrome (via `ThemeProvider` or `theme` prop)
93
+
94
+ ---
95
+
96
+ ## EventApiConfig
97
+
98
+ ```ts
99
+ interface EventApiConfig {
100
+ baseUrl: string; // "https://monitoring.example.com"
101
+ endpoint?: string; // default: "/tsws/monitoring/api/v1.0/events/search"
102
+ payload: Record<string, unknown>; // POST body
103
+ fieldMapping: EventFieldMapping; // maps API keys → AIOpsEvent keys
104
+ severityMap?: Record<string, EventSeverity>; // default: { CRITICAL, MAJOR, MINOR }
105
+ refreshInterval?: number; // ms, default 60000
106
+ }
107
+ ```
108
+
109
+ ### EventFieldMapping
110
+
111
+ Maps every `AIOpsEvent` property to the API response field name. All 15 keys required:
112
+
113
+ ```ts
114
+ type EventFieldMapping = Record<keyof AIOpsEvent, string>;
115
+ ```
116
+
117
+ ### AIOpsEvent interface
118
+
119
+ ```ts
120
+ interface AIOpsEvent {
121
+ id: string;
122
+ occurrence: string;
123
+ severityLastModified: string;
124
+ severity: "Minor" | "Major" | "Critical";
125
+ owner: string;
126
+ class: "Self-monitoring" | "SCOM" | "Situation" | "Alarm" | "Event";
127
+ host: string;
128
+ message: string;
129
+ remedySupportGroup: string;
130
+ incidentId: string;
131
+ smsStatus: "" | "SUCCESS" | "FAILED";
132
+ onCallNumber: string;
133
+ hostedApplication: string;
134
+ monitoringCategory: "24/7" | "Office Hours";
135
+ applicationSupportUnit: string;
136
+ }
137
+ ```
138
+
139
+ ---
140
+
141
+ ## Credential resolution order
142
+
143
+ 1. `credentials` prop (if provided)
144
+ 2. `DataProvider` context credentials (when inside `AIOPsDashboard` with `liveData`)
145
+ 3. Built-in credentials modal (same UI as the 3D dashboard)
146
+
147
+ ---
148
+
149
+ ## Severity colors
150
+
151
+ - **Minor** → `#ffb800` (amber)
152
+ - **Major** → `#ff6600` (orange)
153
+ - **Critical** → `#ff2255` (red)
154
+
155
+ ---
156
+
157
+ ## Event-to-dashboard bridge
158
+
159
+ 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.
160
+
161
+ ```tsx
162
+ <AIOPsDashboard
163
+ eventApiConfig={eventApiConfig}
164
+ liveData
165
+ dataEndpoint="..."
166
+ dataBindings={dataBindings}
167
+ services={services}
168
+ >
169
+ <MyService name="My Service" />
170
+ </AIOPsDashboard>
171
+ ```
172
+
173
+ ### How it works internally
174
+
175
+ 1. `AIOPsDashboard` wraps children in `EventAlertsProvider` (inside `DataProvider` when `liveData` is set — shares credentials automatically)
176
+ 2. `EventAlertsProvider` fetches events using the same `fetchEvents` + `mapRawEvent` logic as `EventView`
177
+ 3. Events are grouped by **lower-cased hostname** into a `Map<string, EventHostAlert>`
178
+ 4. `ServiceNode` reads from `EventAlertsContext` via `useEventAlertsOptional()`
179
+ 5. If `componentInfo.name.toLowerCase()` matches an entry, event severity is factored into `resolveNodeSeverity` as a **third severity source** (alongside node status and metric breaches)
180
+ 6. Highest severity among all three sources wins
181
+ 7. `NodeCallout` appears automatically with the event message; multi-event hosts show `"N events – message"`
182
+
183
+ ### Severity mapping
184
+
185
+ | Event severity | → ComponentStatus |
186
+ | -------------- | ----------------- |
187
+ | Critical | `"critical"` |
188
+ | Major | `"warning"` |
189
+ | Minor | `"warning"` |
190
+
191
+ **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" ... />`.
192
+
193
+ ### Credential resolution order (inside AIOPsDashboard)
194
+
195
+ 1. `DataProvider` context credentials (when `liveData` is enabled — same credentials, one login)
196
+ 2. Built-in `CredentialsModal` (when `liveData` is not enabled)
197
+
198
+ **Opt-in:** Without `eventApiConfig`, no events are fetched — zero overhead.
199
+
200
+ **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`.
201
+
202
+ ---
203
+
204
+ ## Generating an EventApiConfig from the AI
205
+
206
+ When asked to set up EventView for a new API, generate the config like this:
207
+
208
+ 1. Set `baseUrl` to the server's protocol + host + port
209
+ 2. Set `endpoint` only if it differs from the default `/tsws/monitoring/api/v1.0/events/search`
210
+ 3. Build `payload` based on the API's expected POST body schema
211
+ 4. Build `fieldMapping` by asking the user which API field maps to each `AIOpsEvent` property
212
+ 5. Set `severityMap` only if the API uses non-standard severity values
@@ -0,0 +1,250 @@
1
+ ---
2
+ name: dashstream-live-data
3
+ description: Wire live PromQL data into DashStream dashboards via DataProvider and bindings
4
+ license: MIT
5
+ compatibility: opencode
6
+ metadata:
7
+ audience: developers
8
+ workflow: react
9
+ ---
10
+
11
+ ## What I do
12
+
13
+ - Explain the 4 data binding paths: node props, service dialog metrics, component dialog metrics, and hooks
14
+ - Document `DataProvider`, `dataBindings`, `serviceDataBindings`, and data hooks
15
+ - Specify the endpoint contract (method, headers, response format)
16
+ - Show patterns for custom transforms and multi-component services
17
+
18
+ ## When to use me
19
+
20
+ Use this when connecting a DashStream dashboard to a live Prometheus/monitoring endpoint, configuring polling, or accessing data programmatically via hooks.
21
+
22
+ ---
23
+
24
+ ## Endpoint contract
25
+
26
+ | Aspect | Requirement |
27
+ | ------ | ----------- |
28
+ | **Method** | `GET` |
29
+ | **URL** | `<dataEndpoint>?query=<urlEncodedQuery>` |
30
+ | **Headers** | `access-key` and `access-secret-key` |
31
+ | **Response** | Plain text body (trimmed). Default transform parses as number. |
32
+ | **Errors** | Non-2xx → counted as failure per query |
33
+
34
+ For JSON responses, provide a custom `dataTransform`:
35
+
36
+ ```tsx
37
+ dataTransform={(raw) => {
38
+ const parsed = JSON.parse(String(raw));
39
+ return parsed?.data?.result?.[0]?.value?.[1] ?? raw;
40
+ }}
41
+ ```
42
+
43
+ ---
44
+
45
+ ## Data path 1 — dataBindings (live props injected into service components)
46
+
47
+ `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.
48
+
49
+ ```ts
50
+ type DataBinding = string | { query: string; transform?: (raw: unknown) => unknown };
51
+ type DataBindings = Record<string, Record<string, DataBinding>>;
52
+ ```
53
+
54
+ - Bare string → uses global `dataTransform` (defaults to numeric parsing)
55
+ - Object `{ query, transform }` → uses per-binding transform
56
+ - Service name key must match child's `name` prop **exactly**
57
+
58
+ ```tsx
59
+ const dataBindings: DataBindings = {
60
+ "My Service": {
61
+ cpuLoad: 'cpu_usage{instance="srv-01"}',
62
+ memLoad: 'memory_usage{instance="srv-01"}',
63
+ status: {
64
+ query: 'cpu_usage{instance="srv-01"}',
65
+ transform: (raw) => {
66
+ const n = Number(raw);
67
+ if (n >= 85) return "critical";
68
+ if (n >= 70) return "warning";
69
+ return "online";
70
+ },
71
+ },
72
+ dbCapacity: 'disk_capacity{instance="db-01"}',
73
+ dbStatus: { query: 'disk_capacity{instance="db-01"}', transform: statusFromValue },
74
+ },
75
+ };
76
+ ```
77
+
78
+ ### Multi-component services
79
+
80
+ When a service has multiple nodes of the same type, use flat prefixed props. Each `DataBinding` maps **one prop → one query** — there is no array or object binding type.
81
+
82
+ ```tsx
83
+ dataBindings={{
84
+ ServiceX: {
85
+ status: { query: 'status{instance="svcx"}', transform: statusFromValue },
86
+ srv1CpuLoad: 'cpu_usage{instance="srvx-01"}',
87
+ srv1MemLoad: 'memory_usage{instance="srvx-01"}',
88
+ srv1Status: { query: 'status{instance="srvx-01"}', transform: statusFromValue },
89
+ srv2CpuLoad: 'cpu_usage{instance="srvx-02"}',
90
+ srv2MemLoad: 'memory_usage{instance="srvx-02"}',
91
+ srv2Status: { query: 'status{instance="srvx-02"}', transform: statusFromValue },
92
+ dbCapacity: 'disk_capacity{instance="dbx-01"}',
93
+ dbStatus: { query: 'status{instance="dbx-01"}', transform: statusFromValue },
94
+ },
95
+ }}
96
+ ```
97
+
98
+ ---
99
+
100
+ ## Data path 2 — serviceDataBindings (live ServiceDialog metrics)
101
+
102
+ Replace static `ServiceMeta.metrics` with live-fetched values:
103
+
104
+ ```tsx
105
+ serviceDataBindings={{
106
+ "My Service": [
107
+ { label: "CPU Load", query: 'cpu_usage{instance="srv-01"}', unit: "%", color: "#00e5ff" },
108
+ { label: "Memory", query: 'memory_usage{instance="srv-01"}', unit: "%", color: "#bb55ff" },
109
+ { label: "Disk", query: 'disk_capacity{instance="db-01"}', unit: "%", color: "#ff8c00" },
110
+ ],
111
+ }}
112
+ ```
113
+
114
+ ```ts
115
+ interface ServiceMetricBinding {
116
+ label: string; // Row label
117
+ query: string; // PromQL query
118
+ unit?: string; // Suffix (e.g. "%", "ms")
119
+ color?: string; // Accent color
120
+ transform?: (raw: unknown) => string; // Custom formatter
121
+ }
122
+ ```
123
+
124
+ When provided, live values **replace** static `ServiceMeta.metrics` for that service.
125
+
126
+ ---
127
+
128
+ ## Data path 3 — live component dialog metrics
129
+
130
+ 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:
131
+
132
+ ```tsx
133
+ function MyService({ name, status = "online", cpuLoad = 42, memLoad = 60, iops = 20 }: any) {
134
+ return (
135
+ <Service name={name} status={status} connections={[/* ... */]}>
136
+ <ServerNode
137
+ name="SRV-01"
138
+ status={status}
139
+ cpuLoad={cpuLoad}
140
+ memLoad={memLoad}
141
+ ex={200} ey={380}
142
+ compactOffset={{ x: -30, y: -20 }}
143
+ zIndex={8}
144
+ dialogMetrics={[
145
+ { id: "cpu", label: "CPU", sublabel: "PROCESSOR", value: cpuLoad },
146
+ { id: "mem", label: "MEMORY", sublabel: "HEAP", value: memLoad },
147
+ { id: "iops", label: "IOPS", sublabel: "DISK OPS", value: iops, icon: "disk", warnAt: 50, critAt: 80 },
148
+ ]}
149
+ />
150
+ </Service>
151
+ );
152
+ }
153
+
154
+ <AIOPsDashboard
155
+ liveData
156
+ dataEndpoint="..."
157
+ dataBindings={{
158
+ "My Service": {
159
+ cpuLoad: 'cpu_usage{instance="srv-01"}',
160
+ memLoad: 'memory_usage{instance="srv-01"}',
161
+ iops: 'disk_iops{instance="srv-01"}',
162
+ status: { query: 'cpu_usage{instance="srv-01"}', transform: statusFromValue },
163
+ },
164
+ }}
165
+ >
166
+ <MyService name="My Service" />
167
+ </AIOPsDashboard>
168
+ ```
169
+
170
+ The dashboard injects `cpuLoad`, `memLoad`, `iops` as live props → they flow into `dialogMetrics` → gauges update automatically on every poll.
171
+
172
+ ---
173
+
174
+ ## Data path 4 — data hooks (programmatic access)
175
+
176
+ Access live data context anywhere inside the dashboard:
177
+
178
+ ```tsx
179
+ import { useAIOpsData, useAIOpsDataOptional, useQueryResult } from "react-dashstream";
180
+
181
+ function CustomWidget() {
182
+ const { data, isRefreshing, lastRefreshError, lastRefreshTime, credentialsSet } = useAIOpsData();
183
+ const cpu = useQueryResult('cpu_usage{instance="srv-01"}');
184
+ return <div>CPU: {String(cpu)}</div>;
185
+ }
186
+ ```
187
+
188
+ | Hook | Returns | Throws? |
189
+ | ---- | ------- | ------- |
190
+ | `useAIOpsData()` | `DataContextValue` | Yes — outside `DataProvider` |
191
+ | `useAIOpsDataOptional()` | `DataContextValue \| null` | No |
192
+ | `useQueryResult(query)` | `unknown \| null` | Yes — outside `DataProvider` |
193
+
194
+ ```ts
195
+ interface DataContextValue {
196
+ data: Record<string, unknown>; // Raw responses keyed by query
197
+ isRefreshing: boolean;
198
+ lastRefreshError: string | null;
199
+ lastRefreshTime: Date | null;
200
+ credentialsSet: boolean;
201
+ setCredentials: (creds: Credentials) => void;
202
+ }
203
+ ```
204
+
205
+ ---
206
+
207
+ ## Standalone DataProvider
208
+
209
+ Use the data layer without `AIOPsDashboard`:
210
+
211
+ ```tsx
212
+ import { DataProvider, useAIOpsData } from "react-dashstream";
213
+
214
+ <DataProvider
215
+ config={{
216
+ endpoint: "https://prometheus.example.com/api/v1/query",
217
+ queries: ['cpu_usage{instance="srv-01"}'],
218
+ refreshInterval: 15000,
219
+ }}
220
+ >
221
+ <MyContent />
222
+ </DataProvider>
223
+ ```
224
+
225
+ ---
226
+
227
+ ## Full live-data dashboard example
228
+
229
+ ```tsx
230
+ <AIOPsDashboard
231
+ brandName="LIVE MONITOR"
232
+ services={services}
233
+ liveData={true}
234
+ dataEndpoint="https://prometheus.example.com/api/v1/query"
235
+ dataRefreshInterval={10000}
236
+ dataBindings={{
237
+ "My Service": {
238
+ cpuLoad: 'cpu_usage{instance="srv-01"}',
239
+ status: { query: 'cpu_usage{instance="srv-01"}', transform: statusFromValue },
240
+ },
241
+ }}
242
+ serviceDataBindings={{
243
+ "My Service": [
244
+ { label: "CPU", query: 'cpu_usage{instance="srv-01"}', unit: "%", color: "#00e5ff" },
245
+ ],
246
+ }}
247
+ >
248
+ <MyService name="My Service" />
249
+ </AIOPsDashboard>
250
+ ```