reactbridge-sdk 0.2.3 → 0.2.5
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 +236 -107
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +236 -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,qBAwwBzB"}
|
package/dist/index.esm.js
CHANGED
|
@@ -2151,17 +2151,18 @@ 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
|
|
2162
2162
|
const { result, isLoading: resultLoading, error: resultError, refetch: refetchResult, } = useAnalyticsResult(selectedAnalytics);
|
|
2163
2163
|
// Handle directive actions
|
|
2164
2164
|
const { handleAction, isProcessing } = useDirectiveAction(onDirectiveAction);
|
|
2165
|
+
const [processingId, setProcessingId] = useState(null);
|
|
2165
2166
|
// Auto-select first analytics if none selected
|
|
2166
2167
|
useEffect(() => {
|
|
2167
2168
|
if (configs && configs.length > 0 && !selectedAnalytics) {
|
|
@@ -2187,24 +2188,26 @@ function AnalyticsDashboard({ onDirectiveAction, className = '', showRefresh = t
|
|
|
2187
2188
|
}
|
|
2188
2189
|
};
|
|
2189
2190
|
const handleDirectiveAction = (directive, action) => __awaiter(this, void 0, void 0, function* () {
|
|
2191
|
+
setProcessingId(directive.directiveId);
|
|
2190
2192
|
yield handleAction(directive, action);
|
|
2193
|
+
setProcessingId(null);
|
|
2191
2194
|
// Refetch result to get updated directive statuses
|
|
2192
2195
|
refetchResult();
|
|
2193
2196
|
});
|
|
2194
|
-
const filteredDirectives = (result === null || result === void 0 ? void 0 : result.directives.filter(d => {
|
|
2195
|
-
if (directiveFilter ===
|
|
2197
|
+
const filteredDirectives = (result === null || result === void 0 ? void 0 : result.directives.filter((d) => {
|
|
2198
|
+
if (directiveFilter === "all")
|
|
2196
2199
|
return true;
|
|
2197
2200
|
return d.status === directiveFilter;
|
|
2198
2201
|
})) || [];
|
|
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 ===
|
|
2202
|
+
const selectedConfig = configs === null || configs === void 0 ? void 0 : configs.find((c) => c.analyticsType === selectedAnalytics);
|
|
2203
|
+
const proposedCount = (result === null || result === void 0 ? void 0 : result.directives.filter((d) => d.status === "proposed").length) || 0;
|
|
2204
|
+
const executedCount = (result === null || result === void 0 ? void 0 : result.directives.filter((d) => d.status === "executed").length) || 0;
|
|
2205
|
+
const declinedCount = (result === null || result === void 0 ? void 0 : result.directives.filter((d) => d.status === "declined").length) || 0;
|
|
2203
2206
|
const containerStyle = {
|
|
2204
|
-
display:
|
|
2207
|
+
display: "flex",
|
|
2205
2208
|
gap: theme.spacing.lg,
|
|
2206
|
-
width:
|
|
2207
|
-
minHeight:
|
|
2209
|
+
width: "100%",
|
|
2210
|
+
minHeight: "540px",
|
|
2208
2211
|
backgroundColor: theme.colors.background,
|
|
2209
2212
|
color: theme.colors.text,
|
|
2210
2213
|
border: `1px solid ${theme.colors.border}`,
|
|
@@ -2213,44 +2216,44 @@ function AnalyticsDashboard({ onDirectiveAction, className = '', showRefresh = t
|
|
|
2213
2216
|
padding: theme.spacing.lg,
|
|
2214
2217
|
};
|
|
2215
2218
|
const sidebarStyle = {
|
|
2216
|
-
width:
|
|
2219
|
+
width: "320px",
|
|
2217
2220
|
borderRight: `1px solid ${theme.colors.border}`,
|
|
2218
2221
|
paddingRight: theme.spacing.lg,
|
|
2219
|
-
display:
|
|
2220
|
-
flexDirection:
|
|
2222
|
+
display: "flex",
|
|
2223
|
+
flexDirection: "column",
|
|
2221
2224
|
gap: theme.spacing.sm,
|
|
2222
2225
|
};
|
|
2223
2226
|
const listItemStyle = (isActive, isDisabled) => ({
|
|
2224
|
-
width:
|
|
2225
|
-
textAlign:
|
|
2227
|
+
width: "100%",
|
|
2228
|
+
textAlign: "left",
|
|
2226
2229
|
padding: theme.spacing.md,
|
|
2227
2230
|
backgroundColor: isActive ? theme.colors.primary : theme.colors.surface,
|
|
2228
|
-
color: isActive ?
|
|
2231
|
+
color: isActive ? "#fff" : theme.colors.text,
|
|
2229
2232
|
border: `1px solid ${isActive ? theme.colors.primary : theme.colors.border}`,
|
|
2230
2233
|
borderRadius: theme.borderRadius,
|
|
2231
|
-
cursor: isDisabled ?
|
|
2234
|
+
cursor: isDisabled ? "not-allowed" : "pointer",
|
|
2232
2235
|
opacity: isDisabled ? 0.6 : 1,
|
|
2233
|
-
transition:
|
|
2234
|
-
boxShadow: isActive ? theme.boxShadow :
|
|
2236
|
+
transition: "transform 0.15s ease, box-shadow 0.15s ease",
|
|
2237
|
+
boxShadow: isActive ? theme.boxShadow : "none",
|
|
2235
2238
|
});
|
|
2236
2239
|
const pillStyle = (bg) => ({
|
|
2237
2240
|
fontSize: theme.fontSizes.xs,
|
|
2238
|
-
padding:
|
|
2239
|
-
borderRadius:
|
|
2241
|
+
padding: "2px 8px",
|
|
2242
|
+
borderRadius: "999px",
|
|
2240
2243
|
backgroundColor: bg,
|
|
2241
|
-
color:
|
|
2244
|
+
color: "#fff",
|
|
2242
2245
|
fontWeight: 600,
|
|
2243
2246
|
});
|
|
2244
2247
|
const placeholderStyle = {
|
|
2245
2248
|
flex: 1,
|
|
2246
|
-
minHeight:
|
|
2247
|
-
display:
|
|
2248
|
-
flexDirection:
|
|
2249
|
-
alignItems:
|
|
2250
|
-
justifyContent:
|
|
2249
|
+
minHeight: "420px",
|
|
2250
|
+
display: "flex",
|
|
2251
|
+
flexDirection: "column",
|
|
2252
|
+
alignItems: "center",
|
|
2253
|
+
justifyContent: "center",
|
|
2251
2254
|
gap: theme.spacing.sm,
|
|
2252
2255
|
color: theme.colors.textSecondary,
|
|
2253
|
-
textAlign:
|
|
2256
|
+
textAlign: "center",
|
|
2254
2257
|
};
|
|
2255
2258
|
const cardStyle = {
|
|
2256
2259
|
backgroundColor: theme.colors.surface,
|
|
@@ -2260,35 +2263,42 @@ function AnalyticsDashboard({ onDirectiveAction, className = '', showRefresh = t
|
|
|
2260
2263
|
};
|
|
2261
2264
|
const statusBadgeStyle = (status) => {
|
|
2262
2265
|
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:
|
|
2266
|
+
proposed: { bg: theme.colors.primary, text: "#fff" },
|
|
2267
|
+
executed: { bg: theme.colors.success, text: "#fff" },
|
|
2268
|
+
declined: { bg: theme.colors.error, text: "#fff" },
|
|
2269
|
+
ok: { bg: "#d1fae5", text: "#065f46" },
|
|
2270
|
+
warning: { bg: "#fef3c7", text: "#92400e" },
|
|
2271
|
+
critical: { bg: "#fee2e2", text: "#991b1b" },
|
|
2272
|
+
high: { bg: "#fee2e2", text: "#991b1b" },
|
|
2273
|
+
medium: { bg: "#fef3c7", text: "#92400e" },
|
|
2274
|
+
low: { bg: "#e0ecff", text: "#1e3a8a" },
|
|
2275
|
+
};
|
|
2276
|
+
const palette = colors[status] || {
|
|
2277
|
+
bg: theme.colors.surface,
|
|
2278
|
+
text: theme.colors.text,
|
|
2272
2279
|
};
|
|
2273
|
-
const palette = colors[status] || { bg: theme.colors.surface, text: theme.colors.text };
|
|
2274
2280
|
return {
|
|
2275
2281
|
fontSize: theme.fontSizes.xs,
|
|
2276
|
-
padding:
|
|
2277
|
-
borderRadius:
|
|
2282
|
+
padding: "2px 8px",
|
|
2283
|
+
borderRadius: "999px",
|
|
2278
2284
|
backgroundColor: palette.bg,
|
|
2279
2285
|
color: palette.text,
|
|
2280
2286
|
fontWeight: 700,
|
|
2281
|
-
textTransform:
|
|
2287
|
+
textTransform: "capitalize",
|
|
2282
2288
|
};
|
|
2283
2289
|
};
|
|
2284
|
-
const directiveCardStyle = (status) => (Object.assign(Object.assign({}, cardStyle), { borderLeft: `4px solid ${status ===
|
|
2290
|
+
const directiveCardStyle = (status) => (Object.assign(Object.assign({}, cardStyle), { borderLeft: `4px solid ${status === "executed"
|
|
2285
2291
|
? theme.colors.success
|
|
2286
|
-
: status ===
|
|
2292
|
+
: status === "declined"
|
|
2287
2293
|
? theme.colors.error
|
|
2288
|
-
: theme.colors.primary}`, display:
|
|
2294
|
+
: theme.colors.primary}`, display: "flex", flexDirection: "column", gap: theme.spacing.sm }));
|
|
2289
2295
|
return (React.createElement("div", { className: className, style: containerStyle },
|
|
2290
2296
|
React.createElement("div", { style: sidebarStyle },
|
|
2291
|
-
React.createElement("div", { style: {
|
|
2297
|
+
React.createElement("div", { style: {
|
|
2298
|
+
display: "flex",
|
|
2299
|
+
justifyContent: "space-between",
|
|
2300
|
+
alignItems: "center",
|
|
2301
|
+
} },
|
|
2292
2302
|
React.createElement("h3", { style: { margin: 0, fontSize: theme.fontSizes.lg } }, "Analytics"),
|
|
2293
2303
|
showRefresh && (React.createElement("button", { type: "button", onClick: handleRefresh, disabled: configsLoading, style: {
|
|
2294
2304
|
border: `1px solid ${theme.colors.border}`,
|
|
@@ -2296,43 +2306,58 @@ function AnalyticsDashboard({ onDirectiveAction, className = '', showRefresh = t
|
|
|
2296
2306
|
color: theme.colors.text,
|
|
2297
2307
|
padding: `${theme.spacing.xs} ${theme.spacing.sm}`,
|
|
2298
2308
|
borderRadius: theme.borderRadius,
|
|
2299
|
-
cursor: configsLoading ?
|
|
2300
|
-
} }, configsLoading ?
|
|
2309
|
+
cursor: configsLoading ? "not-allowed" : "pointer",
|
|
2310
|
+
} }, configsLoading ? "Refreshing..." : "Refresh"))),
|
|
2301
2311
|
configsLoading && (React.createElement("div", { style: placeholderStyle }, "Loading analytics...")),
|
|
2302
2312
|
configsError && (React.createElement("div", { style: placeholderStyle },
|
|
2303
2313
|
"Error loading analytics: ",
|
|
2304
2314
|
configsError.message)),
|
|
2305
2315
|
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: {
|
|
2316
|
+
configs && configs.length > 0 && (React.createElement("div", { style: {
|
|
2317
|
+
display: "flex",
|
|
2318
|
+
flexDirection: "column",
|
|
2319
|
+
gap: theme.spacing.sm,
|
|
2320
|
+
} }, configs.map((config) => {
|
|
2307
2321
|
const isActive = selectedAnalytics === config.analyticsType;
|
|
2308
|
-
return (React.createElement("button", { key: config.configId, type: "button", onClick: () => config.isEnabled &&
|
|
2322
|
+
return (React.createElement("button", { key: config.configId, type: "button", onClick: () => config.isEnabled &&
|
|
2323
|
+
setSelectedAnalytics(config.analyticsType), style: listItemStyle(isActive, !config.isEnabled), disabled: !config.isEnabled },
|
|
2309
2324
|
React.createElement("div", { style: {
|
|
2310
|
-
display:
|
|
2311
|
-
justifyContent:
|
|
2312
|
-
alignItems:
|
|
2325
|
+
display: "flex",
|
|
2326
|
+
justifyContent: "space-between",
|
|
2327
|
+
alignItems: "center",
|
|
2313
2328
|
marginBottom: theme.spacing.xs,
|
|
2314
|
-
width:
|
|
2329
|
+
width: "100%",
|
|
2315
2330
|
} },
|
|
2316
2331
|
React.createElement("span", { style: { fontSize: theme.fontSizes.md, fontWeight: 600 } }, config.analyticsType),
|
|
2317
|
-
!config.isEnabled && React.createElement("span", { style: pillStyle(theme.colors.textSecondary) }, "Disabled")),
|
|
2332
|
+
!config.isEnabled && (React.createElement("span", { style: pillStyle(theme.colors.textSecondary) }, "Disabled"))),
|
|
2318
2333
|
React.createElement("div", { style: {
|
|
2319
2334
|
fontSize: theme.fontSizes.sm,
|
|
2320
|
-
color: isActive
|
|
2335
|
+
color: isActive
|
|
2336
|
+
? "rgba(255,255,255,0.9)"
|
|
2337
|
+
: theme.colors.textSecondary,
|
|
2321
2338
|
marginBottom: theme.spacing.xs,
|
|
2322
2339
|
} }, config.templateDescription),
|
|
2323
2340
|
React.createElement("div", { style: {
|
|
2324
|
-
display:
|
|
2325
|
-
justifyContent:
|
|
2326
|
-
width:
|
|
2341
|
+
display: "flex",
|
|
2342
|
+
justifyContent: "space-between",
|
|
2343
|
+
width: "100%",
|
|
2327
2344
|
fontSize: theme.fontSizes.xs,
|
|
2328
|
-
color: isActive
|
|
2345
|
+
color: isActive
|
|
2346
|
+
? "rgba(255,255,255,0.8)"
|
|
2347
|
+
: theme.colors.textSecondary,
|
|
2329
2348
|
} },
|
|
2330
|
-
React.createElement("span", { style: { textTransform:
|
|
2349
|
+
React.createElement("span", { style: { textTransform: "capitalize" } }, config.frequency),
|
|
2331
2350
|
config.lastExecutedAt && (React.createElement("span", null,
|
|
2332
|
-
"Last:
|
|
2351
|
+
"Last:",
|
|
2352
|
+
" ",
|
|
2333
2353
|
new Date(config.lastExecutedAt).toLocaleDateString())))));
|
|
2334
2354
|
})))),
|
|
2335
|
-
React.createElement("div", { style: {
|
|
2355
|
+
React.createElement("div", { style: {
|
|
2356
|
+
flex: 1,
|
|
2357
|
+
display: "flex",
|
|
2358
|
+
flexDirection: "column",
|
|
2359
|
+
gap: theme.spacing.lg,
|
|
2360
|
+
} },
|
|
2336
2361
|
!selectedAnalytics && (React.createElement("div", { style: placeholderStyle },
|
|
2337
2362
|
React.createElement("h3", { style: { margin: 0, color: theme.colors.text } }, "No analytics selected"),
|
|
2338
2363
|
React.createElement("p", { style: { margin: 0 } }, "Select an analytics type from the left to view results."))),
|
|
@@ -2343,92 +2368,196 @@ function AnalyticsDashboard({ onDirectiveAction, className = '', showRefresh = t
|
|
|
2343
2368
|
selectedAnalytics && !resultLoading && !result && (React.createElement("div", { style: placeholderStyle },
|
|
2344
2369
|
React.createElement("h3", { style: { margin: 0, color: theme.colors.text } }, "No results yet"),
|
|
2345
2370
|
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
|
-
|
|
2371
|
+
selectedAnalytics && result && (React.createElement("div", { style: {
|
|
2372
|
+
display: "flex",
|
|
2373
|
+
flexDirection: "column",
|
|
2374
|
+
gap: theme.spacing.lg,
|
|
2375
|
+
} },
|
|
2376
|
+
React.createElement("div", { style: {
|
|
2377
|
+
display: "flex",
|
|
2378
|
+
flexDirection: "column",
|
|
2379
|
+
gap: theme.spacing.xs,
|
|
2380
|
+
} },
|
|
2381
|
+
React.createElement("h2", { style: {
|
|
2382
|
+
margin: 0,
|
|
2383
|
+
fontSize: theme.fontSizes.xl,
|
|
2384
|
+
color: theme.colors.text,
|
|
2385
|
+
} }, selectedConfig === null || selectedConfig === void 0 ? void 0 : selectedConfig.analyticsType),
|
|
2386
|
+
React.createElement("p", { style: {
|
|
2387
|
+
margin: 0,
|
|
2388
|
+
color: theme.colors.textSecondary,
|
|
2389
|
+
fontSize: theme.fontSizes.sm,
|
|
2390
|
+
} },
|
|
2350
2391
|
"Generated: ",
|
|
2351
2392
|
new Date(result.createdAt).toLocaleString())),
|
|
2352
|
-
result.metrics && result.metrics.length > 0 && (React.createElement("div", { style: {
|
|
2393
|
+
result.metrics && result.metrics.length > 0 && (React.createElement("div", { style: {
|
|
2394
|
+
display: "flex",
|
|
2395
|
+
flexDirection: "column",
|
|
2396
|
+
gap: theme.spacing.md,
|
|
2397
|
+
} },
|
|
2353
2398
|
React.createElement("h3", { style: { margin: 0, fontSize: theme.fontSizes.lg } }, "Metrics"),
|
|
2354
2399
|
React.createElement("div", { style: {
|
|
2355
|
-
display:
|
|
2356
|
-
gridTemplateColumns:
|
|
2400
|
+
display: "grid",
|
|
2401
|
+
gridTemplateColumns: "repeat(auto-fill, minmax(220px, 1fr))",
|
|
2357
2402
|
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 ===
|
|
2403
|
+
} }, result.metrics.map((metric, index) => (React.createElement("div", { key: index, style: Object.assign(Object.assign({}, cardStyle), { borderLeft: `4px solid ${metric.status === "ok"
|
|
2359
2404
|
? theme.colors.success
|
|
2360
|
-
: metric.status ===
|
|
2361
|
-
?
|
|
2405
|
+
: metric.status === "warning"
|
|
2406
|
+
? "#f59e0b"
|
|
2362
2407
|
: theme.colors.error}` }) },
|
|
2363
2408
|
React.createElement("div", { style: {
|
|
2364
|
-
display:
|
|
2365
|
-
justifyContent:
|
|
2366
|
-
alignItems:
|
|
2409
|
+
display: "flex",
|
|
2410
|
+
justifyContent: "space-between",
|
|
2411
|
+
alignItems: "center",
|
|
2367
2412
|
marginBottom: theme.spacing.xs,
|
|
2368
2413
|
} },
|
|
2369
|
-
React.createElement("span", { style: {
|
|
2414
|
+
React.createElement("span", { style: {
|
|
2415
|
+
fontWeight: 600,
|
|
2416
|
+
maxWidth: "100%",
|
|
2417
|
+
overflow: "hidden",
|
|
2418
|
+
textOverflow: "ellipsis",
|
|
2419
|
+
whiteSpace: "nowrap",
|
|
2420
|
+
display: "inline-block",
|
|
2421
|
+
}, title: metric.name }, metric.name),
|
|
2370
2422
|
React.createElement("span", { style: statusBadgeStyle(metric.status) }, metric.status)),
|
|
2371
|
-
React.createElement("div", { style: {
|
|
2423
|
+
React.createElement("div", { style: {
|
|
2424
|
+
fontSize: theme.fontSizes.xl,
|
|
2425
|
+
fontWeight: 700,
|
|
2426
|
+
} },
|
|
2372
2427
|
metric.value,
|
|
2373
2428
|
" ",
|
|
2374
2429
|
metric.unit),
|
|
2375
|
-
React.createElement("div", { style: {
|
|
2376
|
-
|
|
2430
|
+
React.createElement("div", { style: {
|
|
2431
|
+
color: theme.colors.textSecondary,
|
|
2432
|
+
fontSize: theme.fontSizes.sm,
|
|
2433
|
+
} }, metric.explanation))))))),
|
|
2434
|
+
result.observations && result.observations.length > 0 && (React.createElement("div", { style: {
|
|
2435
|
+
display: "flex",
|
|
2436
|
+
flexDirection: "column",
|
|
2437
|
+
gap: theme.spacing.md,
|
|
2438
|
+
} },
|
|
2377
2439
|
React.createElement("h3", { style: { margin: 0, fontSize: theme.fontSizes.lg } }, "Observations"),
|
|
2378
|
-
React.createElement("div", { style: {
|
|
2440
|
+
React.createElement("div", { style: {
|
|
2441
|
+
display: "flex",
|
|
2442
|
+
flexDirection: "column",
|
|
2443
|
+
gap: theme.spacing.sm,
|
|
2444
|
+
} }, result.observations.map((observation, index) => (React.createElement("div", { key: index, style: Object.assign(Object.assign({}, cardStyle), { borderLeft: `4px solid ${observation.severity === "high"
|
|
2379
2445
|
? theme.colors.error
|
|
2380
|
-
: observation.severity ===
|
|
2381
|
-
?
|
|
2382
|
-
: theme.colors.primary}`, display:
|
|
2383
|
-
React.createElement("div", { style: {
|
|
2446
|
+
: observation.severity === "medium"
|
|
2447
|
+
? "#f59e0b"
|
|
2448
|
+
: theme.colors.primary}`, display: "flex", flexDirection: "column", gap: theme.spacing.xs }) },
|
|
2449
|
+
React.createElement("div", { style: {
|
|
2450
|
+
display: "flex",
|
|
2451
|
+
gap: theme.spacing.sm,
|
|
2452
|
+
alignItems: "center",
|
|
2453
|
+
} },
|
|
2384
2454
|
React.createElement("span", { style: statusBadgeStyle(observation.severity) }, observation.severity),
|
|
2385
|
-
React.createElement("span", { style: {
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2455
|
+
React.createElement("span", { style: {
|
|
2456
|
+
color: theme.colors.textSecondary,
|
|
2457
|
+
fontSize: theme.fontSizes.sm,
|
|
2458
|
+
} }, observation.scope)),
|
|
2459
|
+
React.createElement("div", { style: {
|
|
2460
|
+
color: theme.colors.text,
|
|
2461
|
+
fontSize: theme.fontSizes.sm,
|
|
2462
|
+
} }, observation.text))))))),
|
|
2463
|
+
result.directives && result.directives.length > 0 && (React.createElement("div", { style: {
|
|
2464
|
+
display: "flex",
|
|
2465
|
+
flexDirection: "column",
|
|
2466
|
+
gap: theme.spacing.md,
|
|
2467
|
+
} },
|
|
2468
|
+
React.createElement("div", { style: {
|
|
2469
|
+
display: "flex",
|
|
2470
|
+
justifyContent: "space-between",
|
|
2471
|
+
alignItems: "center",
|
|
2472
|
+
} },
|
|
2389
2473
|
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(
|
|
2474
|
+
React.createElement("div", { style: { display: "flex", gap: theme.spacing.xs } },
|
|
2475
|
+
React.createElement("button", { type: "button", onClick: () => setDirectiveFilter("all"), style: Object.assign(Object.assign({}, pillStyle(directiveFilter === "all"
|
|
2476
|
+
? theme.colors.primary
|
|
2477
|
+
: theme.colors.surface)), { border: `1px solid ${theme.colors.border}`, color: directiveFilter === "all"
|
|
2478
|
+
? "#fff"
|
|
2479
|
+
: theme.colors.text }) },
|
|
2392
2480
|
"All (",
|
|
2393
2481
|
result.directives.length,
|
|
2394
2482
|
")"),
|
|
2395
|
-
React.createElement("button", { type: "button", onClick: () => setDirectiveFilter(
|
|
2483
|
+
React.createElement("button", { type: "button", onClick: () => setDirectiveFilter("proposed"), style: Object.assign(Object.assign({}, pillStyle(directiveFilter === "proposed"
|
|
2484
|
+
? theme.colors.primary
|
|
2485
|
+
: theme.colors.surface)), { border: `1px solid ${theme.colors.border}`, color: directiveFilter === "proposed"
|
|
2486
|
+
? "#fff"
|
|
2487
|
+
: theme.colors.text }) },
|
|
2396
2488
|
"Proposed (",
|
|
2397
2489
|
proposedCount,
|
|
2398
2490
|
")"),
|
|
2399
|
-
React.createElement("button", { type: "button", onClick: () => setDirectiveFilter(
|
|
2491
|
+
React.createElement("button", { type: "button", onClick: () => setDirectiveFilter("executed"), style: Object.assign(Object.assign({}, pillStyle(directiveFilter === "executed"
|
|
2492
|
+
? theme.colors.primary
|
|
2493
|
+
: theme.colors.surface)), { border: `1px solid ${theme.colors.border}`, color: directiveFilter === "executed"
|
|
2494
|
+
? "#fff"
|
|
2495
|
+
: theme.colors.text }) },
|
|
2400
2496
|
"Executed (",
|
|
2401
2497
|
executedCount,
|
|
2402
2498
|
")"),
|
|
2403
|
-
React.createElement("button", { type: "button", onClick: () => setDirectiveFilter(
|
|
2499
|
+
React.createElement("button", { type: "button", onClick: () => setDirectiveFilter("declined"), style: Object.assign(Object.assign({}, pillStyle(directiveFilter === "declined"
|
|
2500
|
+
? theme.colors.primary
|
|
2501
|
+
: theme.colors.surface)), { border: `1px solid ${theme.colors.border}`, color: directiveFilter === "declined"
|
|
2502
|
+
? "#fff"
|
|
2503
|
+
: theme.colors.text }) },
|
|
2404
2504
|
"Declined (",
|
|
2405
2505
|
declinedCount,
|
|
2406
2506
|
")"))),
|
|
2407
2507
|
filteredDirectives.length === 0 && (React.createElement("div", { style: placeholderStyle }, "No directives match the selected filter.")),
|
|
2408
|
-
React.createElement("div", { style: {
|
|
2508
|
+
React.createElement("div", { style: {
|
|
2509
|
+
display: "flex",
|
|
2510
|
+
flexDirection: "column",
|
|
2511
|
+
gap: theme.spacing.sm,
|
|
2512
|
+
} }, filteredDirectives.map((directive) => (React.createElement("div", { key: directive.directiveId, style: directiveCardStyle(directive.status) },
|
|
2409
2513
|
React.createElement("div", { style: {
|
|
2410
|
-
display:
|
|
2411
|
-
justifyContent:
|
|
2412
|
-
alignItems:
|
|
2514
|
+
display: "flex",
|
|
2515
|
+
justifyContent: "space-between",
|
|
2516
|
+
alignItems: "center",
|
|
2413
2517
|
gap: theme.spacing.sm,
|
|
2414
|
-
flexWrap:
|
|
2518
|
+
flexWrap: "wrap",
|
|
2415
2519
|
} },
|
|
2416
|
-
React.createElement("div", { style: {
|
|
2520
|
+
React.createElement("div", { style: {
|
|
2521
|
+
display: "flex",
|
|
2522
|
+
flexDirection: "column",
|
|
2523
|
+
gap: theme.spacing.xs,
|
|
2524
|
+
} },
|
|
2417
2525
|
React.createElement("span", { style: { fontWeight: 700 } }, directive.action),
|
|
2418
|
-
React.createElement("span", { style: {
|
|
2526
|
+
React.createElement("span", { style: {
|
|
2527
|
+
color: theme.colors.textSecondary,
|
|
2528
|
+
fontSize: theme.fontSizes.sm,
|
|
2529
|
+
} },
|
|
2419
2530
|
"Priority: ",
|
|
2420
2531
|
directive.priority)),
|
|
2421
2532
|
React.createElement("span", { style: statusBadgeStyle(directive.status) }, directive.status)),
|
|
2422
|
-
React.createElement("div", { style: {
|
|
2423
|
-
|
|
2533
|
+
React.createElement("div", { style: {
|
|
2534
|
+
color: theme.colors.text,
|
|
2535
|
+
fontSize: theme.fontSizes.sm,
|
|
2536
|
+
} }, directive.rationale),
|
|
2537
|
+
directive.parameters &&
|
|
2538
|
+
directive.parameters.length > 0 && (React.createElement("div", { style: {
|
|
2539
|
+
color: theme.colors.textSecondary,
|
|
2540
|
+
fontSize: theme.fontSizes.sm,
|
|
2541
|
+
} },
|
|
2424
2542
|
React.createElement("strong", { style: { color: theme.colors.text } }, "Parameters:"),
|
|
2425
|
-
React.createElement("ul", { style: {
|
|
2543
|
+
React.createElement("ul", { style: {
|
|
2544
|
+
margin: `${theme.spacing.xs} 0 0 16px`,
|
|
2545
|
+
padding: 0,
|
|
2546
|
+
} }, directive.parameters.map((param, index) => (React.createElement("li", { key: index, style: { marginBottom: theme.spacing.xs } },
|
|
2426
2547
|
React.createElement("code", null, param.name),
|
|
2427
2548
|
": ",
|
|
2428
2549
|
param.value)))))),
|
|
2429
|
-
directive.status ===
|
|
2430
|
-
React.createElement("button", { type: "button", onClick: () => handleDirectiveAction(directive,
|
|
2431
|
-
|
|
2550
|
+
directive.status === "proposed" && (React.createElement("div", { style: { display: "flex", gap: theme.spacing.sm } },
|
|
2551
|
+
React.createElement("button", { type: "button", onClick: () => handleDirectiveAction(directive, "execute"), disabled: isProcessing && processingId === directive.directiveId, style: Object.assign(Object.assign({}, pillStyle(theme.colors.success)), { border: "none", cursor: isProcessing && processingId === directive.directiveId
|
|
2552
|
+
? "not-allowed"
|
|
2553
|
+
: "pointer" }) }, isProcessing && processingId === directive.directiveId
|
|
2554
|
+
? "Processing..."
|
|
2555
|
+
: "Execute"),
|
|
2556
|
+
React.createElement("button", { type: "button", onClick: () => handleDirectiveAction(directive, "decline"), disabled: isProcessing && processingId === directive.directiveId, style: Object.assign(Object.assign({}, pillStyle(theme.colors.error)), { border: "none", cursor: isProcessing && processingId === directive.directiveId
|
|
2557
|
+
? "not-allowed"
|
|
2558
|
+
: "pointer" }) }, isProcessing && processingId === directive.directiveId
|
|
2559
|
+
? "Processing..."
|
|
2560
|
+
: "Decline"))))))))))))));
|
|
2432
2561
|
}
|
|
2433
2562
|
|
|
2434
2563
|
export { AnalyticsAPI, AnalyticsDashboard, AnalyticsReport, AnalyticsWidget, DirectivesPanel, MetricsPanel, ObservationsPanel, ReactBridgeAPI, ReactBridgeChatbox, ReactBridgeProvider, ReactBridgeSearch, WebSpeechSTTProvider, WebSpeechTTSProvider, createCustomTheme, darkTheme, getTheme, lightTheme, useAnalyticsConfigs, useAnalyticsResult, useDirectiveAction, useReactBridge, useReactBridgeContext };
|