reactbridge-sdk 0.2.3 → 0.2.4
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 +78 -0
- package/dist/components/analytics/AnalyticsDashboard.d.ts +3 -3
- package/dist/components/analytics/AnalyticsDashboard.d.ts.map +1 -1
- package/dist/index.esm.js +225 -107
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +225 -107
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ A flexible React SDK for building intelligent conversational interfaces with LLM
|
|
|
10
10
|
🤖 **Intelligent Context** - Automatic context diffing and injection
|
|
11
11
|
⚡ **Two-Step Orchestration** - Seamless action execution and feedback loop
|
|
12
12
|
📦 **TypeScript First** - Full type safety and IntelliSense support
|
|
13
|
+
📈 **Analytics Admin UI** - Widgets, reports, and dashboards for AI-generated insights
|
|
13
14
|
|
|
14
15
|
## Installation
|
|
15
16
|
|
|
@@ -187,6 +188,83 @@ function CustomChat() {
|
|
|
187
188
|
}
|
|
188
189
|
```
|
|
189
190
|
|
|
191
|
+
## Analytics Suite
|
|
192
|
+
|
|
193
|
+
The SDK ships with DirectivSys analytics components for visualizing AI-generated metrics, observations, and directives and for executing recommended actions.
|
|
194
|
+
|
|
195
|
+
### Components
|
|
196
|
+
|
|
197
|
+
- `AnalyticsWidget` — Floating entry point that opens a drawer of analytics configs; best for adding analytics everywhere in your admin UI.
|
|
198
|
+
- `AnalyticsReport` — Full report view for a single `analyticsType` (metrics, observations, directives) with optional back/close controls.
|
|
199
|
+
- `AnalyticsDashboard` — Full-width dashboard that lists all analytics configs on the left and shows the selected report on the right. Supports manual refresh, optional `autoRefreshInterval`, and directive status filtering.
|
|
200
|
+
|
|
201
|
+
```tsx
|
|
202
|
+
import {
|
|
203
|
+
ReactBridgeProvider,
|
|
204
|
+
AnalyticsWidget,
|
|
205
|
+
AnalyticsReport,
|
|
206
|
+
AnalyticsDashboard,
|
|
207
|
+
} from 'reactbridge-sdk';
|
|
208
|
+
|
|
209
|
+
const handleDirectiveAction = async (directive, action) => {
|
|
210
|
+
if (action === 'decline') return { success: true };
|
|
211
|
+
|
|
212
|
+
// Execute the directive in your system
|
|
213
|
+
const result = await api.executeDirective(directive);
|
|
214
|
+
return { success: result.ok, error: result.error };
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
function Admin() {
|
|
218
|
+
return (
|
|
219
|
+
<ReactBridgeProvider apiKey="your-api-key">
|
|
220
|
+
<AnalyticsWidget onDirectiveAction={handleDirectiveAction} />
|
|
221
|
+
|
|
222
|
+
<AnalyticsReport
|
|
223
|
+
analyticsType="InventoryHealth"
|
|
224
|
+
onDirectiveAction={handleDirectiveAction}
|
|
225
|
+
/>
|
|
226
|
+
|
|
227
|
+
<AnalyticsDashboard
|
|
228
|
+
onDirectiveAction={handleDirectiveAction}
|
|
229
|
+
autoRefreshInterval={300}
|
|
230
|
+
/>
|
|
231
|
+
</ReactBridgeProvider>
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**Directive actions:** The callback receives the directive plus the requested action (`execute` or `decline`) and should return `{ success: boolean, error?: string }`. On success, directive status becomes `executed`; failures become `failed`; declines become `declined`. Directive statuses are `proposed`, `executed`, `declined`, and `failed`. Priorities are numeric (higher = more urgent).
|
|
237
|
+
|
|
238
|
+
### Analytics Hooks
|
|
239
|
+
|
|
240
|
+
- `useAnalyticsConfigs()` — Fetches all analytics configs (`configs`, `isLoading`, `error`, `refetch`).
|
|
241
|
+
- `useAnalyticsResult(analyticsType)` — Fetches the latest result for a given analytics type (`result`, `isLoading`, `error`, `refetch`).
|
|
242
|
+
- `useDirectiveAction(onDirectiveAction?)` — Wraps your handler, updates directive status in the backend, and exposes `handleAction`, `isProcessing`, and `error`.
|
|
243
|
+
|
|
244
|
+
```tsx
|
|
245
|
+
import { useAnalyticsConfigs, useAnalyticsResult, useDirectiveAction } from 'reactbridge-sdk';
|
|
246
|
+
|
|
247
|
+
const { configs } = useAnalyticsConfigs();
|
|
248
|
+
const { result, refetch } = useAnalyticsResult('InventoryHealth');
|
|
249
|
+
const { handleAction, isProcessing } = useDirectiveAction(handleDirectiveAction);
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Analytics API Client
|
|
253
|
+
|
|
254
|
+
```tsx
|
|
255
|
+
import { AnalyticsAPI } from 'reactbridge-sdk';
|
|
256
|
+
|
|
257
|
+
const api = new AnalyticsAPI({ apiKey: 'your-api-key' });
|
|
258
|
+
const configs = await api.getConfigs();
|
|
259
|
+
const result = await api.getLatestResult('InventoryHealth');
|
|
260
|
+
await api.updateDirectiveStatus(directiveId, 'executed');
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### More Docs
|
|
264
|
+
|
|
265
|
+
- Detailed components and hooks: [ANALYTICS_README.md](ANALYTICS_README.md)
|
|
266
|
+
- Full dashboard guide: [ANALYTICS_DASHBOARD_README.md](ANALYTICS_DASHBOARD_README.md)
|
|
267
|
+
|
|
190
268
|
## Voice Input/Output
|
|
191
269
|
|
|
192
270
|
The SDK supports voice input (Speech-to-Text) and voice output (Text-to-Speech) for a fully conversational experience.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import type { DirectiveActionCallback } from
|
|
3
|
-
import type { Theme } from
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { DirectiveActionCallback } from "../../types/analytics";
|
|
3
|
+
import type { Theme } from "../../types";
|
|
4
4
|
export interface AnalyticsDashboardProps {
|
|
5
5
|
onDirectiveAction: DirectiveActionCallback;
|
|
6
6
|
className?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnalyticsDashboard.d.ts","sourceRoot":"","sources":["../../../src/components/analytics/AnalyticsDashboard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAKnD,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"AnalyticsDashboard.d.ts","sourceRoot":"","sources":["../../../src/components/analytics/AnalyticsDashboard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAKnD,OAAO,KAAK,EAEV,uBAAuB,EACxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,WAAW,uBAAuB;IACtC,iBAAiB,EAAE,uBAAuB,CAAC;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,wBAAgB,kBAAkB,CAAC,EACjC,iBAAiB,EACjB,SAAc,EACd,WAAkB,EAClB,mBAAuB,EACvB,KAAK,EAAE,WAAW,GACnB,EAAE,uBAAuB,qBA+vBzB"}
|
package/dist/index.esm.js
CHANGED
|
@@ -2151,11 +2151,11 @@ const AnalyticsWidget = ({ position = 'bottom-right', theme: customTheme, onDire
|
|
|
2151
2151
|
isOpen && (React.createElement(AnalyticsDrawer, { isOpen: isOpen, onClose: () => setIsOpen(false), configs: configs, isLoading: isLoading, theme: theme, onDirectiveAction: onDirectiveAction }))));
|
|
2152
2152
|
};
|
|
2153
2153
|
|
|
2154
|
-
function AnalyticsDashboard({ onDirectiveAction, className =
|
|
2154
|
+
function AnalyticsDashboard({ onDirectiveAction, className = "", showRefresh = true, autoRefreshInterval = 0, theme: customTheme, }) {
|
|
2155
2155
|
const { theme: contextTheme } = useReactBridgeContext();
|
|
2156
2156
|
const theme = customTheme || contextTheme;
|
|
2157
2157
|
const [selectedAnalytics, setSelectedAnalytics] = useState(null);
|
|
2158
|
-
const [directiveFilter, setDirectiveFilter] = useState(
|
|
2158
|
+
const [directiveFilter, setDirectiveFilter] = useState("all");
|
|
2159
2159
|
// Fetch analytics configurations
|
|
2160
2160
|
const { configs, isLoading: configsLoading, error: configsError, refetch: refetchConfigs, } = useAnalyticsConfigs();
|
|
2161
2161
|
// Fetch latest result for selected analytics
|
|
@@ -2191,20 +2191,20 @@ function AnalyticsDashboard({ onDirectiveAction, className = '', showRefresh = t
|
|
|
2191
2191
|
// Refetch result to get updated directive statuses
|
|
2192
2192
|
refetchResult();
|
|
2193
2193
|
});
|
|
2194
|
-
const filteredDirectives = (result === null || result === void 0 ? void 0 : result.directives.filter(d => {
|
|
2195
|
-
if (directiveFilter ===
|
|
2194
|
+
const filteredDirectives = (result === null || result === void 0 ? void 0 : result.directives.filter((d) => {
|
|
2195
|
+
if (directiveFilter === "all")
|
|
2196
2196
|
return true;
|
|
2197
2197
|
return d.status === directiveFilter;
|
|
2198
2198
|
})) || [];
|
|
2199
|
-
const selectedConfig = configs === null || configs === void 0 ? void 0 : configs.find(c => c.analyticsType === selectedAnalytics);
|
|
2200
|
-
const proposedCount = (result === null || result === void 0 ? void 0 : result.directives.filter(d => d.status ===
|
|
2201
|
-
const executedCount = (result === null || result === void 0 ? void 0 : result.directives.filter(d => d.status ===
|
|
2202
|
-
const declinedCount = (result === null || result === void 0 ? void 0 : result.directives.filter(d => d.status ===
|
|
2199
|
+
const selectedConfig = configs === null || configs === void 0 ? void 0 : configs.find((c) => c.analyticsType === selectedAnalytics);
|
|
2200
|
+
const proposedCount = (result === null || result === void 0 ? void 0 : result.directives.filter((d) => d.status === "proposed").length) || 0;
|
|
2201
|
+
const executedCount = (result === null || result === void 0 ? void 0 : result.directives.filter((d) => d.status === "executed").length) || 0;
|
|
2202
|
+
const declinedCount = (result === null || result === void 0 ? void 0 : result.directives.filter((d) => d.status === "declined").length) || 0;
|
|
2203
2203
|
const containerStyle = {
|
|
2204
|
-
display:
|
|
2204
|
+
display: "flex",
|
|
2205
2205
|
gap: theme.spacing.lg,
|
|
2206
|
-
width:
|
|
2207
|
-
minHeight:
|
|
2206
|
+
width: "100%",
|
|
2207
|
+
minHeight: "540px",
|
|
2208
2208
|
backgroundColor: theme.colors.background,
|
|
2209
2209
|
color: theme.colors.text,
|
|
2210
2210
|
border: `1px solid ${theme.colors.border}`,
|
|
@@ -2213,44 +2213,44 @@ function AnalyticsDashboard({ onDirectiveAction, className = '', showRefresh = t
|
|
|
2213
2213
|
padding: theme.spacing.lg,
|
|
2214
2214
|
};
|
|
2215
2215
|
const sidebarStyle = {
|
|
2216
|
-
width:
|
|
2216
|
+
width: "320px",
|
|
2217
2217
|
borderRight: `1px solid ${theme.colors.border}`,
|
|
2218
2218
|
paddingRight: theme.spacing.lg,
|
|
2219
|
-
display:
|
|
2220
|
-
flexDirection:
|
|
2219
|
+
display: "flex",
|
|
2220
|
+
flexDirection: "column",
|
|
2221
2221
|
gap: theme.spacing.sm,
|
|
2222
2222
|
};
|
|
2223
2223
|
const listItemStyle = (isActive, isDisabled) => ({
|
|
2224
|
-
width:
|
|
2225
|
-
textAlign:
|
|
2224
|
+
width: "100%",
|
|
2225
|
+
textAlign: "left",
|
|
2226
2226
|
padding: theme.spacing.md,
|
|
2227
2227
|
backgroundColor: isActive ? theme.colors.primary : theme.colors.surface,
|
|
2228
|
-
color: isActive ?
|
|
2228
|
+
color: isActive ? "#fff" : theme.colors.text,
|
|
2229
2229
|
border: `1px solid ${isActive ? theme.colors.primary : theme.colors.border}`,
|
|
2230
2230
|
borderRadius: theme.borderRadius,
|
|
2231
|
-
cursor: isDisabled ?
|
|
2231
|
+
cursor: isDisabled ? "not-allowed" : "pointer",
|
|
2232
2232
|
opacity: isDisabled ? 0.6 : 1,
|
|
2233
|
-
transition:
|
|
2234
|
-
boxShadow: isActive ? theme.boxShadow :
|
|
2233
|
+
transition: "transform 0.15s ease, box-shadow 0.15s ease",
|
|
2234
|
+
boxShadow: isActive ? theme.boxShadow : "none",
|
|
2235
2235
|
});
|
|
2236
2236
|
const pillStyle = (bg) => ({
|
|
2237
2237
|
fontSize: theme.fontSizes.xs,
|
|
2238
|
-
padding:
|
|
2239
|
-
borderRadius:
|
|
2238
|
+
padding: "2px 8px",
|
|
2239
|
+
borderRadius: "999px",
|
|
2240
2240
|
backgroundColor: bg,
|
|
2241
|
-
color:
|
|
2241
|
+
color: "#fff",
|
|
2242
2242
|
fontWeight: 600,
|
|
2243
2243
|
});
|
|
2244
2244
|
const placeholderStyle = {
|
|
2245
2245
|
flex: 1,
|
|
2246
|
-
minHeight:
|
|
2247
|
-
display:
|
|
2248
|
-
flexDirection:
|
|
2249
|
-
alignItems:
|
|
2250
|
-
justifyContent:
|
|
2246
|
+
minHeight: "420px",
|
|
2247
|
+
display: "flex",
|
|
2248
|
+
flexDirection: "column",
|
|
2249
|
+
alignItems: "center",
|
|
2250
|
+
justifyContent: "center",
|
|
2251
2251
|
gap: theme.spacing.sm,
|
|
2252
2252
|
color: theme.colors.textSecondary,
|
|
2253
|
-
textAlign:
|
|
2253
|
+
textAlign: "center",
|
|
2254
2254
|
};
|
|
2255
2255
|
const cardStyle = {
|
|
2256
2256
|
backgroundColor: theme.colors.surface,
|
|
@@ -2260,35 +2260,42 @@ function AnalyticsDashboard({ onDirectiveAction, className = '', showRefresh = t
|
|
|
2260
2260
|
};
|
|
2261
2261
|
const statusBadgeStyle = (status) => {
|
|
2262
2262
|
const colors = {
|
|
2263
|
-
proposed: { bg: theme.colors.primary, text:
|
|
2264
|
-
executed: { bg: theme.colors.success, text:
|
|
2265
|
-
declined: { bg: theme.colors.error, text:
|
|
2266
|
-
ok: { bg:
|
|
2267
|
-
warning: { bg:
|
|
2268
|
-
critical: { bg:
|
|
2269
|
-
high: { bg:
|
|
2270
|
-
medium: { bg:
|
|
2271
|
-
low: { bg:
|
|
2263
|
+
proposed: { bg: theme.colors.primary, text: "#fff" },
|
|
2264
|
+
executed: { bg: theme.colors.success, text: "#fff" },
|
|
2265
|
+
declined: { bg: theme.colors.error, text: "#fff" },
|
|
2266
|
+
ok: { bg: "#d1fae5", text: "#065f46" },
|
|
2267
|
+
warning: { bg: "#fef3c7", text: "#92400e" },
|
|
2268
|
+
critical: { bg: "#fee2e2", text: "#991b1b" },
|
|
2269
|
+
high: { bg: "#fee2e2", text: "#991b1b" },
|
|
2270
|
+
medium: { bg: "#fef3c7", text: "#92400e" },
|
|
2271
|
+
low: { bg: "#e0ecff", text: "#1e3a8a" },
|
|
2272
|
+
};
|
|
2273
|
+
const palette = colors[status] || {
|
|
2274
|
+
bg: theme.colors.surface,
|
|
2275
|
+
text: theme.colors.text,
|
|
2272
2276
|
};
|
|
2273
|
-
const palette = colors[status] || { bg: theme.colors.surface, text: theme.colors.text };
|
|
2274
2277
|
return {
|
|
2275
2278
|
fontSize: theme.fontSizes.xs,
|
|
2276
|
-
padding:
|
|
2277
|
-
borderRadius:
|
|
2279
|
+
padding: "2px 8px",
|
|
2280
|
+
borderRadius: "999px",
|
|
2278
2281
|
backgroundColor: palette.bg,
|
|
2279
2282
|
color: palette.text,
|
|
2280
2283
|
fontWeight: 700,
|
|
2281
|
-
textTransform:
|
|
2284
|
+
textTransform: "capitalize",
|
|
2282
2285
|
};
|
|
2283
2286
|
};
|
|
2284
|
-
const directiveCardStyle = (status) => (Object.assign(Object.assign({}, cardStyle), { borderLeft: `4px solid ${status ===
|
|
2287
|
+
const directiveCardStyle = (status) => (Object.assign(Object.assign({}, cardStyle), { borderLeft: `4px solid ${status === "executed"
|
|
2285
2288
|
? theme.colors.success
|
|
2286
|
-
: status ===
|
|
2289
|
+
: status === "declined"
|
|
2287
2290
|
? theme.colors.error
|
|
2288
|
-
: theme.colors.primary}`, display:
|
|
2291
|
+
: theme.colors.primary}`, display: "flex", flexDirection: "column", gap: theme.spacing.sm }));
|
|
2289
2292
|
return (React.createElement("div", { className: className, style: containerStyle },
|
|
2290
2293
|
React.createElement("div", { style: sidebarStyle },
|
|
2291
|
-
React.createElement("div", { style: {
|
|
2294
|
+
React.createElement("div", { style: {
|
|
2295
|
+
display: "flex",
|
|
2296
|
+
justifyContent: "space-between",
|
|
2297
|
+
alignItems: "center",
|
|
2298
|
+
} },
|
|
2292
2299
|
React.createElement("h3", { style: { margin: 0, fontSize: theme.fontSizes.lg } }, "Analytics"),
|
|
2293
2300
|
showRefresh && (React.createElement("button", { type: "button", onClick: handleRefresh, disabled: configsLoading, style: {
|
|
2294
2301
|
border: `1px solid ${theme.colors.border}`,
|
|
@@ -2296,43 +2303,58 @@ function AnalyticsDashboard({ onDirectiveAction, className = '', showRefresh = t
|
|
|
2296
2303
|
color: theme.colors.text,
|
|
2297
2304
|
padding: `${theme.spacing.xs} ${theme.spacing.sm}`,
|
|
2298
2305
|
borderRadius: theme.borderRadius,
|
|
2299
|
-
cursor: configsLoading ?
|
|
2300
|
-
} }, configsLoading ?
|
|
2306
|
+
cursor: configsLoading ? "not-allowed" : "pointer",
|
|
2307
|
+
} }, configsLoading ? "Refreshing..." : "Refresh"))),
|
|
2301
2308
|
configsLoading && (React.createElement("div", { style: placeholderStyle }, "Loading analytics...")),
|
|
2302
2309
|
configsError && (React.createElement("div", { style: placeholderStyle },
|
|
2303
2310
|
"Error loading analytics: ",
|
|
2304
2311
|
configsError.message)),
|
|
2305
2312
|
configs && configs.length === 0 && (React.createElement("div", { style: placeholderStyle }, "No analytics configured. Configure analytics in your DirectivSys dashboard.")),
|
|
2306
|
-
configs && configs.length > 0 && (React.createElement("div", { style: {
|
|
2313
|
+
configs && configs.length > 0 && (React.createElement("div", { style: {
|
|
2314
|
+
display: "flex",
|
|
2315
|
+
flexDirection: "column",
|
|
2316
|
+
gap: theme.spacing.sm,
|
|
2317
|
+
} }, configs.map((config) => {
|
|
2307
2318
|
const isActive = selectedAnalytics === config.analyticsType;
|
|
2308
|
-
return (React.createElement("button", { key: config.configId, type: "button", onClick: () => config.isEnabled &&
|
|
2319
|
+
return (React.createElement("button", { key: config.configId, type: "button", onClick: () => config.isEnabled &&
|
|
2320
|
+
setSelectedAnalytics(config.analyticsType), style: listItemStyle(isActive, !config.isEnabled), disabled: !config.isEnabled },
|
|
2309
2321
|
React.createElement("div", { style: {
|
|
2310
|
-
display:
|
|
2311
|
-
justifyContent:
|
|
2312
|
-
alignItems:
|
|
2322
|
+
display: "flex",
|
|
2323
|
+
justifyContent: "space-between",
|
|
2324
|
+
alignItems: "center",
|
|
2313
2325
|
marginBottom: theme.spacing.xs,
|
|
2314
|
-
width:
|
|
2326
|
+
width: "100%",
|
|
2315
2327
|
} },
|
|
2316
2328
|
React.createElement("span", { style: { fontSize: theme.fontSizes.md, fontWeight: 600 } }, config.analyticsType),
|
|
2317
|
-
!config.isEnabled && React.createElement("span", { style: pillStyle(theme.colors.textSecondary) }, "Disabled")),
|
|
2329
|
+
!config.isEnabled && (React.createElement("span", { style: pillStyle(theme.colors.textSecondary) }, "Disabled"))),
|
|
2318
2330
|
React.createElement("div", { style: {
|
|
2319
2331
|
fontSize: theme.fontSizes.sm,
|
|
2320
|
-
color: isActive
|
|
2332
|
+
color: isActive
|
|
2333
|
+
? "rgba(255,255,255,0.9)"
|
|
2334
|
+
: theme.colors.textSecondary,
|
|
2321
2335
|
marginBottom: theme.spacing.xs,
|
|
2322
2336
|
} }, config.templateDescription),
|
|
2323
2337
|
React.createElement("div", { style: {
|
|
2324
|
-
display:
|
|
2325
|
-
justifyContent:
|
|
2326
|
-
width:
|
|
2338
|
+
display: "flex",
|
|
2339
|
+
justifyContent: "space-between",
|
|
2340
|
+
width: "100%",
|
|
2327
2341
|
fontSize: theme.fontSizes.xs,
|
|
2328
|
-
color: isActive
|
|
2342
|
+
color: isActive
|
|
2343
|
+
? "rgba(255,255,255,0.8)"
|
|
2344
|
+
: theme.colors.textSecondary,
|
|
2329
2345
|
} },
|
|
2330
|
-
React.createElement("span", { style: { textTransform:
|
|
2346
|
+
React.createElement("span", { style: { textTransform: "capitalize" } }, config.frequency),
|
|
2331
2347
|
config.lastExecutedAt && (React.createElement("span", null,
|
|
2332
|
-
"Last:
|
|
2348
|
+
"Last:",
|
|
2349
|
+
" ",
|
|
2333
2350
|
new Date(config.lastExecutedAt).toLocaleDateString())))));
|
|
2334
2351
|
})))),
|
|
2335
|
-
React.createElement("div", { style: {
|
|
2352
|
+
React.createElement("div", { style: {
|
|
2353
|
+
flex: 1,
|
|
2354
|
+
display: "flex",
|
|
2355
|
+
flexDirection: "column",
|
|
2356
|
+
gap: theme.spacing.lg,
|
|
2357
|
+
} },
|
|
2336
2358
|
!selectedAnalytics && (React.createElement("div", { style: placeholderStyle },
|
|
2337
2359
|
React.createElement("h3", { style: { margin: 0, color: theme.colors.text } }, "No analytics selected"),
|
|
2338
2360
|
React.createElement("p", { style: { margin: 0 } }, "Select an analytics type from the left to view results."))),
|
|
@@ -2343,92 +2365,188 @@ function AnalyticsDashboard({ onDirectiveAction, className = '', showRefresh = t
|
|
|
2343
2365
|
selectedAnalytics && !resultLoading && !result && (React.createElement("div", { style: placeholderStyle },
|
|
2344
2366
|
React.createElement("h3", { style: { margin: 0, color: theme.colors.text } }, "No results yet"),
|
|
2345
2367
|
React.createElement("p", { style: { margin: 0 } }, "This analytics has not run yet. Results will appear after the first run."))),
|
|
2346
|
-
selectedAnalytics && result && (React.createElement("div", { style: {
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2368
|
+
selectedAnalytics && result && (React.createElement("div", { style: {
|
|
2369
|
+
display: "flex",
|
|
2370
|
+
flexDirection: "column",
|
|
2371
|
+
gap: theme.spacing.lg,
|
|
2372
|
+
} },
|
|
2373
|
+
React.createElement("div", { style: {
|
|
2374
|
+
display: "flex",
|
|
2375
|
+
flexDirection: "column",
|
|
2376
|
+
gap: theme.spacing.xs,
|
|
2377
|
+
} },
|
|
2378
|
+
React.createElement("h2", { style: {
|
|
2379
|
+
margin: 0,
|
|
2380
|
+
fontSize: theme.fontSizes.xl,
|
|
2381
|
+
color: theme.colors.text,
|
|
2382
|
+
} }, selectedConfig === null || selectedConfig === void 0 ? void 0 : selectedConfig.analyticsType),
|
|
2383
|
+
React.createElement("p", { style: {
|
|
2384
|
+
margin: 0,
|
|
2385
|
+
color: theme.colors.textSecondary,
|
|
2386
|
+
fontSize: theme.fontSizes.sm,
|
|
2387
|
+
} },
|
|
2350
2388
|
"Generated: ",
|
|
2351
2389
|
new Date(result.createdAt).toLocaleString())),
|
|
2352
|
-
result.metrics && result.metrics.length > 0 && (React.createElement("div", { style: {
|
|
2390
|
+
result.metrics && result.metrics.length > 0 && (React.createElement("div", { style: {
|
|
2391
|
+
display: "flex",
|
|
2392
|
+
flexDirection: "column",
|
|
2393
|
+
gap: theme.spacing.md,
|
|
2394
|
+
} },
|
|
2353
2395
|
React.createElement("h3", { style: { margin: 0, fontSize: theme.fontSizes.lg } }, "Metrics"),
|
|
2354
2396
|
React.createElement("div", { style: {
|
|
2355
|
-
display:
|
|
2356
|
-
gridTemplateColumns:
|
|
2397
|
+
display: "grid",
|
|
2398
|
+
gridTemplateColumns: "repeat(auto-fill, minmax(220px, 1fr))",
|
|
2357
2399
|
gap: theme.spacing.md,
|
|
2358
|
-
} }, result.metrics.map((metric, index) => (React.createElement("div", { key: index, style: Object.assign(Object.assign({}, cardStyle), { borderLeft: `4px solid ${metric.status ===
|
|
2400
|
+
} }, result.metrics.map((metric, index) => (React.createElement("div", { key: index, style: Object.assign(Object.assign({}, cardStyle), { borderLeft: `4px solid ${metric.status === "ok"
|
|
2359
2401
|
? theme.colors.success
|
|
2360
|
-
: metric.status ===
|
|
2361
|
-
?
|
|
2402
|
+
: metric.status === "warning"
|
|
2403
|
+
? "#f59e0b"
|
|
2362
2404
|
: theme.colors.error}` }) },
|
|
2363
2405
|
React.createElement("div", { style: {
|
|
2364
|
-
display:
|
|
2365
|
-
justifyContent:
|
|
2366
|
-
alignItems:
|
|
2406
|
+
display: "flex",
|
|
2407
|
+
justifyContent: "space-between",
|
|
2408
|
+
alignItems: "center",
|
|
2367
2409
|
marginBottom: theme.spacing.xs,
|
|
2368
2410
|
} },
|
|
2369
|
-
React.createElement("span", { style: {
|
|
2411
|
+
React.createElement("span", { style: {
|
|
2412
|
+
fontWeight: 600,
|
|
2413
|
+
maxWidth: "100%",
|
|
2414
|
+
overflow: "hidden",
|
|
2415
|
+
textOverflow: "ellipsis",
|
|
2416
|
+
whiteSpace: "nowrap",
|
|
2417
|
+
display: "inline-block",
|
|
2418
|
+
}, title: metric.name }, metric.name),
|
|
2370
2419
|
React.createElement("span", { style: statusBadgeStyle(metric.status) }, metric.status)),
|
|
2371
|
-
React.createElement("div", { style: {
|
|
2420
|
+
React.createElement("div", { style: {
|
|
2421
|
+
fontSize: theme.fontSizes.xl,
|
|
2422
|
+
fontWeight: 700,
|
|
2423
|
+
} },
|
|
2372
2424
|
metric.value,
|
|
2373
2425
|
" ",
|
|
2374
2426
|
metric.unit),
|
|
2375
|
-
React.createElement("div", { style: {
|
|
2376
|
-
|
|
2427
|
+
React.createElement("div", { style: {
|
|
2428
|
+
color: theme.colors.textSecondary,
|
|
2429
|
+
fontSize: theme.fontSizes.sm,
|
|
2430
|
+
} }, metric.explanation))))))),
|
|
2431
|
+
result.observations && result.observations.length > 0 && (React.createElement("div", { style: {
|
|
2432
|
+
display: "flex",
|
|
2433
|
+
flexDirection: "column",
|
|
2434
|
+
gap: theme.spacing.md,
|
|
2435
|
+
} },
|
|
2377
2436
|
React.createElement("h3", { style: { margin: 0, fontSize: theme.fontSizes.lg } }, "Observations"),
|
|
2378
|
-
React.createElement("div", { style: {
|
|
2437
|
+
React.createElement("div", { style: {
|
|
2438
|
+
display: "flex",
|
|
2439
|
+
flexDirection: "column",
|
|
2440
|
+
gap: theme.spacing.sm,
|
|
2441
|
+
} }, result.observations.map((observation, index) => (React.createElement("div", { key: index, style: Object.assign(Object.assign({}, cardStyle), { borderLeft: `4px solid ${observation.severity === "high"
|
|
2379
2442
|
? theme.colors.error
|
|
2380
|
-
: observation.severity ===
|
|
2381
|
-
?
|
|
2382
|
-
: theme.colors.primary}`, display:
|
|
2383
|
-
React.createElement("div", { style: {
|
|
2443
|
+
: observation.severity === "medium"
|
|
2444
|
+
? "#f59e0b"
|
|
2445
|
+
: theme.colors.primary}`, display: "flex", flexDirection: "column", gap: theme.spacing.xs }) },
|
|
2446
|
+
React.createElement("div", { style: {
|
|
2447
|
+
display: "flex",
|
|
2448
|
+
gap: theme.spacing.sm,
|
|
2449
|
+
alignItems: "center",
|
|
2450
|
+
} },
|
|
2384
2451
|
React.createElement("span", { style: statusBadgeStyle(observation.severity) }, observation.severity),
|
|
2385
|
-
React.createElement("span", { style: {
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2452
|
+
React.createElement("span", { style: {
|
|
2453
|
+
color: theme.colors.textSecondary,
|
|
2454
|
+
fontSize: theme.fontSizes.sm,
|
|
2455
|
+
} }, observation.scope)),
|
|
2456
|
+
React.createElement("div", { style: {
|
|
2457
|
+
color: theme.colors.text,
|
|
2458
|
+
fontSize: theme.fontSizes.sm,
|
|
2459
|
+
} }, observation.text))))))),
|
|
2460
|
+
result.directives && result.directives.length > 0 && (React.createElement("div", { style: {
|
|
2461
|
+
display: "flex",
|
|
2462
|
+
flexDirection: "column",
|
|
2463
|
+
gap: theme.spacing.md,
|
|
2464
|
+
} },
|
|
2465
|
+
React.createElement("div", { style: {
|
|
2466
|
+
display: "flex",
|
|
2467
|
+
justifyContent: "space-between",
|
|
2468
|
+
alignItems: "center",
|
|
2469
|
+
} },
|
|
2389
2470
|
React.createElement("h3", { style: { margin: 0, fontSize: theme.fontSizes.lg } }, "Recommended actions"),
|
|
2390
|
-
React.createElement("div", { style: { display:
|
|
2391
|
-
React.createElement("button", { type: "button", onClick: () => setDirectiveFilter(
|
|
2471
|
+
React.createElement("div", { style: { display: "flex", gap: theme.spacing.xs } },
|
|
2472
|
+
React.createElement("button", { type: "button", onClick: () => setDirectiveFilter("all"), style: Object.assign(Object.assign({}, pillStyle(directiveFilter === "all"
|
|
2473
|
+
? theme.colors.primary
|
|
2474
|
+
: theme.colors.surface)), { border: `1px solid ${theme.colors.border}`, color: directiveFilter === "all"
|
|
2475
|
+
? "#fff"
|
|
2476
|
+
: theme.colors.text }) },
|
|
2392
2477
|
"All (",
|
|
2393
2478
|
result.directives.length,
|
|
2394
2479
|
")"),
|
|
2395
|
-
React.createElement("button", { type: "button", onClick: () => setDirectiveFilter(
|
|
2480
|
+
React.createElement("button", { type: "button", onClick: () => setDirectiveFilter("proposed"), style: Object.assign(Object.assign({}, pillStyle(directiveFilter === "proposed"
|
|
2481
|
+
? theme.colors.primary
|
|
2482
|
+
: theme.colors.surface)), { border: `1px solid ${theme.colors.border}`, color: directiveFilter === "proposed"
|
|
2483
|
+
? "#fff"
|
|
2484
|
+
: theme.colors.text }) },
|
|
2396
2485
|
"Proposed (",
|
|
2397
2486
|
proposedCount,
|
|
2398
2487
|
")"),
|
|
2399
|
-
React.createElement("button", { type: "button", onClick: () => setDirectiveFilter(
|
|
2488
|
+
React.createElement("button", { type: "button", onClick: () => setDirectiveFilter("executed"), style: Object.assign(Object.assign({}, pillStyle(directiveFilter === "executed"
|
|
2489
|
+
? theme.colors.primary
|
|
2490
|
+
: theme.colors.surface)), { border: `1px solid ${theme.colors.border}`, color: directiveFilter === "executed"
|
|
2491
|
+
? "#fff"
|
|
2492
|
+
: theme.colors.text }) },
|
|
2400
2493
|
"Executed (",
|
|
2401
2494
|
executedCount,
|
|
2402
2495
|
")"),
|
|
2403
|
-
React.createElement("button", { type: "button", onClick: () => setDirectiveFilter(
|
|
2496
|
+
React.createElement("button", { type: "button", onClick: () => setDirectiveFilter("declined"), style: Object.assign(Object.assign({}, pillStyle(directiveFilter === "declined"
|
|
2497
|
+
? theme.colors.primary
|
|
2498
|
+
: theme.colors.surface)), { border: `1px solid ${theme.colors.border}`, color: directiveFilter === "declined"
|
|
2499
|
+
? "#fff"
|
|
2500
|
+
: theme.colors.text }) },
|
|
2404
2501
|
"Declined (",
|
|
2405
2502
|
declinedCount,
|
|
2406
2503
|
")"))),
|
|
2407
2504
|
filteredDirectives.length === 0 && (React.createElement("div", { style: placeholderStyle }, "No directives match the selected filter.")),
|
|
2408
|
-
React.createElement("div", { style: {
|
|
2505
|
+
React.createElement("div", { style: {
|
|
2506
|
+
display: "flex",
|
|
2507
|
+
flexDirection: "column",
|
|
2508
|
+
gap: theme.spacing.sm,
|
|
2509
|
+
} }, filteredDirectives.map((directive) => (React.createElement("div", { key: directive.directiveId, style: directiveCardStyle(directive.status) },
|
|
2409
2510
|
React.createElement("div", { style: {
|
|
2410
|
-
display:
|
|
2411
|
-
justifyContent:
|
|
2412
|
-
alignItems:
|
|
2511
|
+
display: "flex",
|
|
2512
|
+
justifyContent: "space-between",
|
|
2513
|
+
alignItems: "center",
|
|
2413
2514
|
gap: theme.spacing.sm,
|
|
2414
|
-
flexWrap:
|
|
2515
|
+
flexWrap: "wrap",
|
|
2415
2516
|
} },
|
|
2416
|
-
React.createElement("div", { style: {
|
|
2517
|
+
React.createElement("div", { style: {
|
|
2518
|
+
display: "flex",
|
|
2519
|
+
flexDirection: "column",
|
|
2520
|
+
gap: theme.spacing.xs,
|
|
2521
|
+
} },
|
|
2417
2522
|
React.createElement("span", { style: { fontWeight: 700 } }, directive.action),
|
|
2418
|
-
React.createElement("span", { style: {
|
|
2523
|
+
React.createElement("span", { style: {
|
|
2524
|
+
color: theme.colors.textSecondary,
|
|
2525
|
+
fontSize: theme.fontSizes.sm,
|
|
2526
|
+
} },
|
|
2419
2527
|
"Priority: ",
|
|
2420
2528
|
directive.priority)),
|
|
2421
2529
|
React.createElement("span", { style: statusBadgeStyle(directive.status) }, directive.status)),
|
|
2422
|
-
React.createElement("div", { style: {
|
|
2423
|
-
|
|
2530
|
+
React.createElement("div", { style: {
|
|
2531
|
+
color: theme.colors.text,
|
|
2532
|
+
fontSize: theme.fontSizes.sm,
|
|
2533
|
+
} }, directive.rationale),
|
|
2534
|
+
directive.parameters &&
|
|
2535
|
+
directive.parameters.length > 0 && (React.createElement("div", { style: {
|
|
2536
|
+
color: theme.colors.textSecondary,
|
|
2537
|
+
fontSize: theme.fontSizes.sm,
|
|
2538
|
+
} },
|
|
2424
2539
|
React.createElement("strong", { style: { color: theme.colors.text } }, "Parameters:"),
|
|
2425
|
-
React.createElement("ul", { style: {
|
|
2540
|
+
React.createElement("ul", { style: {
|
|
2541
|
+
margin: `${theme.spacing.xs} 0 0 16px`,
|
|
2542
|
+
padding: 0,
|
|
2543
|
+
} }, directive.parameters.map((param, index) => (React.createElement("li", { key: index, style: { marginBottom: theme.spacing.xs } },
|
|
2426
2544
|
React.createElement("code", null, param.name),
|
|
2427
2545
|
": ",
|
|
2428
2546
|
param.value)))))),
|
|
2429
|
-
directive.status ===
|
|
2430
|
-
React.createElement("button", { type: "button", onClick: () => handleDirectiveAction(directive,
|
|
2431
|
-
React.createElement("button", { type: "button", onClick: () => handleDirectiveAction(directive,
|
|
2547
|
+
directive.status === "proposed" && (React.createElement("div", { style: { display: "flex", gap: theme.spacing.sm } },
|
|
2548
|
+
React.createElement("button", { type: "button", onClick: () => handleDirectiveAction(directive, "execute"), disabled: isProcessing, style: Object.assign(Object.assign({}, pillStyle(theme.colors.success)), { border: "none", cursor: isProcessing ? "not-allowed" : "pointer" }) }, isProcessing ? "Processing..." : "Execute"),
|
|
2549
|
+
React.createElement("button", { type: "button", onClick: () => handleDirectiveAction(directive, "decline"), disabled: isProcessing, style: Object.assign(Object.assign({}, pillStyle(theme.colors.error)), { border: "none", cursor: isProcessing ? "not-allowed" : "pointer" }) }, "Decline"))))))))))))));
|
|
2432
2550
|
}
|
|
2433
2551
|
|
|
2434
2552
|
export { AnalyticsAPI, AnalyticsDashboard, AnalyticsReport, AnalyticsWidget, DirectivesPanel, MetricsPanel, ObservationsPanel, ReactBridgeAPI, ReactBridgeChatbox, ReactBridgeProvider, ReactBridgeSearch, WebSpeechSTTProvider, WebSpeechTTSProvider, createCustomTheme, darkTheme, getTheme, lightTheme, useAnalyticsConfigs, useAnalyticsResult, useDirectiveAction, useReactBridge, useReactBridgeContext };
|