reactbridge-sdk 0.2.6 → 0.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/README.md +85 -1
  2. package/dist/components/ReactBridgeChatbox.d.ts.map +1 -1
  3. package/dist/components/ReactBridgeSearch.d.ts +2 -2
  4. package/dist/components/ReactBridgeSearch.d.ts.map +1 -1
  5. package/dist/components/ReportsDashboard.d.ts +13 -0
  6. package/dist/components/ReportsDashboard.d.ts.map +1 -0
  7. package/dist/components/analytics/AnalyticsDashboard.d.ts.map +1 -1
  8. package/dist/components/analytics/AnalyticsDrawer.d.ts +3 -3
  9. package/dist/components/analytics/AnalyticsDrawer.d.ts.map +1 -1
  10. package/dist/components/analytics/AnalyticsReport.d.ts +3 -3
  11. package/dist/components/analytics/AnalyticsReport.d.ts.map +1 -1
  12. package/dist/components/analytics/AnalyticsWidget.d.ts +4 -4
  13. package/dist/components/analytics/DirectivesPanel.d.ts +3 -3
  14. package/dist/components/analytics/DirectivesPanel.d.ts.map +1 -1
  15. package/dist/components/analytics/MetricsPanel.d.ts +3 -3
  16. package/dist/components/analytics/MetricsPanel.d.ts.map +1 -1
  17. package/dist/components/analytics/ObservationsPanel.d.ts +3 -3
  18. package/dist/components/analytics/ObservationsPanel.d.ts.map +1 -1
  19. package/dist/components/reports/DataQualityAutomation.d.ts +12 -0
  20. package/dist/components/reports/DataQualityAutomation.d.ts.map +1 -0
  21. package/dist/components/reports/DataTable.d.ts +24 -0
  22. package/dist/components/reports/DataTable.d.ts.map +1 -0
  23. package/dist/components/reports/DateRangeSelector.d.ts +14 -0
  24. package/dist/components/reports/DateRangeSelector.d.ts.map +1 -0
  25. package/dist/components/reports/ExecutionAuditTrail.d.ts +12 -0
  26. package/dist/components/reports/ExecutionAuditTrail.d.ts.map +1 -0
  27. package/dist/components/reports/ExecutiveDashboard.d.ts +12 -0
  28. package/dist/components/reports/ExecutiveDashboard.d.ts.map +1 -0
  29. package/dist/components/reports/HealthGauge.d.ts +14 -0
  30. package/dist/components/reports/HealthGauge.d.ts.map +1 -0
  31. package/dist/components/reports/LoadingState.d.ts +12 -0
  32. package/dist/components/reports/LoadingState.d.ts.map +1 -0
  33. package/dist/components/reports/MetricCard.d.ts +18 -0
  34. package/dist/components/reports/MetricCard.d.ts.map +1 -0
  35. package/dist/components/reports/PortfolioHealth.d.ts +12 -0
  36. package/dist/components/reports/PortfolioHealth.d.ts.map +1 -0
  37. package/dist/components/reports/ProgressBar.d.ts +15 -0
  38. package/dist/components/reports/ProgressBar.d.ts.map +1 -0
  39. package/dist/components/reports/ReportLayout.d.ts +19 -0
  40. package/dist/components/reports/ReportLayout.d.ts.map +1 -0
  41. package/dist/components/reports/RiskMatrix.d.ts +21 -0
  42. package/dist/components/reports/RiskMatrix.d.ts.map +1 -0
  43. package/dist/components/reports/StatusBadge.d.ts +14 -0
  44. package/dist/components/reports/StatusBadge.d.ts.map +1 -0
  45. package/dist/components/reports/SupplyChainRisk.d.ts +12 -0
  46. package/dist/components/reports/SupplyChainRisk.d.ts.map +1 -0
  47. package/dist/components/reports/TrendChart.d.ts +19 -0
  48. package/dist/components/reports/TrendChart.d.ts.map +1 -0
  49. package/dist/hooks/analytics/useAnalyticsConfigs.d.ts +1 -1
  50. package/dist/hooks/analytics/useAnalyticsResult.d.ts +1 -1
  51. package/dist/hooks/analytics/useDateRange.d.ts +18 -0
  52. package/dist/hooks/analytics/useDateRange.d.ts.map +1 -0
  53. package/dist/hooks/analytics/useDirectiveAction.d.ts +2 -2
  54. package/dist/hooks/analytics/useDirectiveAction.d.ts.map +1 -1
  55. package/dist/hooks/analytics/useReportData.d.ts +24 -0
  56. package/dist/hooks/analytics/useReportData.d.ts.map +1 -0
  57. package/dist/hooks/useReactBridge.d.ts +1 -1
  58. package/dist/hooks/useReactBridge.d.ts.map +1 -1
  59. package/dist/index.d.ts +67 -28
  60. package/dist/index.d.ts.map +1 -1
  61. package/dist/index.esm.js +2338 -389
  62. package/dist/index.esm.js.map +1 -1
  63. package/dist/index.js +2355 -387
  64. package/dist/index.js.map +1 -1
  65. package/dist/provider/ReactBridgeProvider.d.ts +3 -3
  66. package/dist/provider/ReactBridgeProvider.d.ts.map +1 -1
  67. package/dist/themes/dark.d.ts +1 -1
  68. package/dist/themes/index.d.ts +3 -3
  69. package/dist/themes/index.d.ts.map +1 -1
  70. package/dist/themes/light.d.ts +1 -1
  71. package/dist/types/analytics.d.ts +5 -5
  72. package/dist/types/index.d.ts +5 -4
  73. package/dist/types/index.d.ts.map +1 -1
  74. package/dist/types/reports.d.ts +158 -0
  75. package/dist/types/reports.d.ts.map +1 -0
  76. package/dist/utils/analytics-api.d.ts +3 -3
  77. package/dist/utils/analytics-api.d.ts.map +1 -1
  78. package/dist/utils/api.d.ts +12 -1
  79. package/dist/utils/api.d.ts.map +1 -1
  80. package/dist/utils/contextDiff.d.ts +1 -1
  81. package/dist/utils/contextDiff.d.ts.map +1 -1
  82. package/dist/utils/date-range.d.ts +32 -0
  83. package/dist/utils/date-range.d.ts.map +1 -0
  84. package/dist/utils/reports-api.d.ts +19 -0
  85. package/dist/utils/reports-api.d.ts.map +1 -0
  86. package/dist/utils/request-cache.d.ts +32 -0
  87. package/dist/utils/request-cache.d.ts.map +1 -0
  88. package/dist/utils/voice.d.ts.map +1 -1
  89. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -34,7 +34,7 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
34
34
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
35
35
  };
36
36
 
37
- const DEFAULT_BASE_URL$1 = 'https://react-bridge-api-14089992360.northamerica-northeast2.run.app'; // 'http://localhost:5093';
37
+ const DEFAULT_BASE_URL$1 = "https://react-bridge-api-14089992360.northamerica-northeast2.run.app"; // 'http://localhost:5093';
38
38
  class ReactBridgeAPI {
39
39
  constructor(config) {
40
40
  this.config = config;
@@ -47,13 +47,15 @@ class ReactBridgeAPI {
47
47
  // Configure abort signal for fetch with robust fallback.
48
48
  // `ReactBridgeConfig.timeout` is milliseconds. If it's undefined, no timeout is applied.
49
49
  // If it's 0 or a non-positive number, timeout is disabled.
50
- const timeoutMs = typeof this.config.timeout === 'number' ? this.config.timeout : undefined;
50
+ const timeoutMs = typeof this.config.timeout === "number"
51
+ ? this.config.timeout
52
+ : undefined;
51
53
  let controller = null;
52
54
  let timeoutId = null;
53
55
  let signal;
54
- if (typeof timeoutMs === 'number' && timeoutMs > 0) {
56
+ if (typeof timeoutMs === "number" && timeoutMs > 0) {
55
57
  // Prefer built-in AbortSignal.timeout when available
56
- if (typeof AbortSignal.timeout === 'function') {
58
+ if (typeof AbortSignal.timeout === "function") {
57
59
  signal = AbortSignal.timeout(timeoutMs);
58
60
  }
59
61
  else {
@@ -64,43 +66,43 @@ class ReactBridgeAPI {
64
66
  }
65
67
  // Check if this is a multimodal request (has image or document)
66
68
  const hasFile = request.image || request.document;
67
- let headers = Object.assign({ 'X-API-Key': this.config.apiKey }, this.config.headers);
69
+ let headers = Object.assign({ "X-API-Key": this.config.apiKey }, this.config.headers);
68
70
  let body;
69
71
  if (hasFile) {
70
72
  // Use FormData for file uploads
71
73
  const formData = new FormData();
72
74
  // Add text fields
73
- formData.append('userId', request.userId);
74
- formData.append('query', request.query);
75
+ formData.append("userId", request.userId);
76
+ formData.append("query", request.query);
75
77
  if (request.userName)
76
- formData.append('userName', request.userName);
78
+ formData.append("userName", request.userName);
77
79
  if (request.userPreferences)
78
- formData.append('userPreferences', request.userPreferences);
80
+ formData.append("userPreferences", request.userPreferences);
79
81
  if (request.userRecentActivity)
80
- formData.append('userRecentActivity', request.userRecentActivity);
82
+ formData.append("userRecentActivity", request.userRecentActivity);
81
83
  if (request.interfaceState)
82
84
  formData.append("InterfaceStateJson", JSON.stringify(request.interfaceState));
83
85
  if (request.sessionId)
84
- formData.append('sessionId', request.sessionId);
86
+ formData.append("sessionId", request.sessionId);
85
87
  if (request.modalityHint)
86
- formData.append('modalityHint', request.modalityHint);
88
+ formData.append("modalityHint", request.modalityHint);
87
89
  // Add files
88
90
  if (request.image)
89
- formData.append('image', request.image);
91
+ formData.append("image", request.image);
90
92
  if (request.document)
91
- formData.append('document', request.document);
93
+ formData.append("document", request.document);
92
94
  body = formData;
93
95
  // Don't set Content-Type for FormData - let browser set it with boundary
94
- delete headers['Content-Type'];
96
+ delete headers["Content-Type"];
95
97
  }
96
98
  else {
97
99
  // Use JSON for text-only requests
98
- headers['Content-Type'] = 'application/json';
100
+ headers["Content-Type"] = "application/json";
99
101
  body = JSON.stringify(request);
100
102
  }
101
103
  // console.log('Sending request to ReactBridge API:', { url, headers, body, timeoutMs });
102
104
  const response = yield fetch(url, {
103
- method: 'POST',
105
+ method: "POST",
104
106
  headers,
105
107
  body,
106
108
  signal,
@@ -120,7 +122,7 @@ class ReactBridgeAPI {
120
122
  if (error instanceof Error) {
121
123
  throw new Error(`ReactBridge API Error: ${error.message}`);
122
124
  }
123
- throw new Error('ReactBridge API Error: Unknown error occurred');
125
+ throw new Error("ReactBridge API Error: Unknown error occurred");
124
126
  }
125
127
  });
126
128
  }
@@ -140,65 +142,164 @@ class ReactBridgeAPI {
140
142
  });
141
143
  }
142
144
  sendImageRequest(userId_1, imageFile_1) {
143
- return __awaiter(this, arguments, void 0, function* (userId, imageFile, query = '', context) {
145
+ return __awaiter(this, arguments, void 0, function* (userId, imageFile, query = "", context) {
144
146
  const request = Object.assign({ userId,
145
- query, image: imageFile, modalityHint: 'image' }, context);
147
+ query, image: imageFile, modalityHint: "image" }, context);
146
148
  return this.sendMessage(request);
147
149
  });
148
150
  }
149
151
  sendDocumentRequest(userId_1, documentFile_1) {
150
- return __awaiter(this, arguments, void 0, function* (userId, documentFile, query = '', context) {
152
+ return __awaiter(this, arguments, void 0, function* (userId, documentFile, query = "", context) {
151
153
  const request = Object.assign({ userId,
152
- query, document: documentFile, modalityHint: 'document' }, context);
154
+ query, document: documentFile, modalityHint: "document" }, context);
153
155
  return this.sendMessage(request);
154
156
  });
155
157
  }
158
+ /**
159
+ * Report API Methods - Call analytics endpoints directly
160
+ */
161
+ fetchReport(endpoint, params) {
162
+ return __awaiter(this, void 0, void 0, function* () {
163
+ const baseURL = this.config.baseURL || DEFAULT_BASE_URL$1;
164
+ const url = new URL(`${baseURL}/api/reports/${endpoint}`);
165
+ // Add query parameters if provided
166
+ if (params) {
167
+ for (const key in params) {
168
+ if (params.hasOwnProperty(key)) {
169
+ url.searchParams.append(key, params[key]);
170
+ }
171
+ }
172
+ }
173
+ try {
174
+ const response = yield fetch(url.toString(), {
175
+ method: "GET",
176
+ headers: Object.assign({ "X-API-Key": this.config.apiKey, "Content-Type": "application/json" }, this.config.headers),
177
+ });
178
+ if (!response.ok) {
179
+ const errorMessage = this.getErrorMessage(response.status);
180
+ throw new Error(errorMessage);
181
+ }
182
+ return (yield response.json());
183
+ }
184
+ catch (error) {
185
+ if (error instanceof Error) {
186
+ throw error;
187
+ }
188
+ throw new Error("Failed to fetch report data");
189
+ }
190
+ });
191
+ }
192
+ getErrorMessage(status) {
193
+ switch (status) {
194
+ case 401:
195
+ return "Unauthorized: Invalid API key";
196
+ case 404:
197
+ return "Report endpoint not found";
198
+ case 500:
199
+ return "Server error: Unable to fetch report data";
200
+ default:
201
+ return `API Error: ${status}`;
202
+ }
203
+ }
204
+ getExecutiveDashboard(params) {
205
+ return __awaiter(this, void 0, void 0, function* () {
206
+ const queryParams = {};
207
+ if (params === null || params === void 0 ? void 0 : params.startDate)
208
+ queryParams.startDate = params.startDate;
209
+ if (params === null || params === void 0 ? void 0 : params.endDate)
210
+ queryParams.endDate = params.endDate;
211
+ return this.fetchReport("executive-dashboard", queryParams);
212
+ });
213
+ }
214
+ getSupplyChainRisk(params) {
215
+ return __awaiter(this, void 0, void 0, function* () {
216
+ const queryParams = {};
217
+ if (params === null || params === void 0 ? void 0 : params.startDate)
218
+ queryParams.startDate = params.startDate;
219
+ if (params === null || params === void 0 ? void 0 : params.endDate)
220
+ queryParams.endDate = params.endDate;
221
+ return this.fetchReport("supply-chain-risk", queryParams);
222
+ });
223
+ }
224
+ getExecutionAuditTrail(params) {
225
+ return __awaiter(this, void 0, void 0, function* () {
226
+ const queryParams = {};
227
+ if (params === null || params === void 0 ? void 0 : params.startDate)
228
+ queryParams.startDate = params.startDate;
229
+ if (params === null || params === void 0 ? void 0 : params.endDate)
230
+ queryParams.endDate = params.endDate;
231
+ if (params === null || params === void 0 ? void 0 : params.directiveType)
232
+ queryParams.directiveType = params.directiveType;
233
+ return this.fetchReport("execution-audit-trail", queryParams);
234
+ });
235
+ }
236
+ getPortfolioHealth(params) {
237
+ return __awaiter(this, void 0, void 0, function* () {
238
+ const queryParams = {};
239
+ if (params === null || params === void 0 ? void 0 : params.startDate)
240
+ queryParams.startDate = params.startDate;
241
+ if (params === null || params === void 0 ? void 0 : params.endDate)
242
+ queryParams.endDate = params.endDate;
243
+ return this.fetchReport("portfolio-health", queryParams);
244
+ });
245
+ }
246
+ getDataQualityAutomation(params) {
247
+ return __awaiter(this, void 0, void 0, function* () {
248
+ const queryParams = {};
249
+ if (params === null || params === void 0 ? void 0 : params.startDate)
250
+ queryParams.startDate = params.startDate;
251
+ if (params === null || params === void 0 ? void 0 : params.endDate)
252
+ queryParams.endDate = params.endDate;
253
+ return this.fetchReport("data-quality-automation", queryParams);
254
+ });
255
+ }
156
256
  }
157
257
 
158
258
  const lightTheme = {
159
- name: 'light',
259
+ name: "light",
160
260
  colors: {
161
- primary: '#1976d2',
162
- secondary: '#dc004e',
163
- background: '#ffffff',
164
- surface: '#f5f5f5',
165
- text: '#000000',
166
- textSecondary: '#666666',
167
- border: '#e0e0e0',
168
- error: '#f44336',
169
- success: '#4caf50',
261
+ primary: "#1976d2",
262
+ secondary: "#dc004e",
263
+ background: "#ffffff",
264
+ surface: "#f5f5f5",
265
+ text: "#000000",
266
+ textSecondary: "#666666",
267
+ border: "#e0e0e0",
268
+ error: "#f44336",
269
+ success: "#4caf50",
170
270
  },
171
271
  spacing: {
172
- xs: '4px',
173
- sm: '8px',
174
- md: '16px',
175
- lg: '24px',
176
- xl: '32px',
272
+ xs: "4px",
273
+ sm: "8px",
274
+ md: "16px",
275
+ lg: "24px",
276
+ xl: "32px",
177
277
  },
178
278
  fontSizes: {
179
- xs: '12px',
180
- sm: '14px',
181
- md: '16px',
182
- lg: '18px',
183
- xl: '24px',
279
+ xs: "12px",
280
+ sm: "14px",
281
+ md: "16px",
282
+ lg: "18px",
283
+ xl: "24px",
184
284
  },
185
- borderRadius: '8px',
186
- boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)',
285
+ borderRadius: "8px",
286
+ boxShadow: "0 2px 8px rgba(0, 0, 0, 0.1)",
187
287
  };
188
288
 
189
289
  // Default STT Provider using Web Speech API
190
290
  class WebSpeechSTTProvider {
191
291
  constructor() {
192
- if (typeof window !== 'undefined') {
193
- const SpeechRecognitionCtor = window.SpeechRecognition || window.webkitSpeechRecognition;
292
+ if (typeof window !== "undefined") {
293
+ const SpeechRecognitionCtor = window.SpeechRecognition ||
294
+ window.webkitSpeechRecognition;
194
295
  if (SpeechRecognitionCtor) {
195
296
  this.recognition = new SpeechRecognitionCtor();
196
297
  if (!this.recognition) {
197
- throw new Error('Failed to initialize SpeechRecognition');
298
+ throw new Error("Failed to initialize SpeechRecognition");
198
299
  }
199
300
  this.recognition.continuous = false;
200
301
  this.recognition.interimResults = false;
201
- this.recognition.lang = 'en-US';
302
+ this.recognition.lang = "en-US";
202
303
  this.recognition.onresult = (event) => {
203
304
  var _a;
204
305
  const transcript = event.results[0][0].transcript;
@@ -210,7 +311,7 @@ class WebSpeechSTTProvider {
210
311
  };
211
312
  }
212
313
  else {
213
- console.warn('SpeechRecognition API not supported in this browser.');
314
+ console.warn("SpeechRecognition API not supported in this browser.");
214
315
  }
215
316
  }
216
317
  }
@@ -219,7 +320,7 @@ class WebSpeechSTTProvider {
219
320
  this.recognition.start();
220
321
  }
221
322
  else {
222
- throw new Error('Speech recognition not supported');
323
+ throw new Error("Speech recognition not supported");
223
324
  }
224
325
  }
225
326
  stopRecognition() {
@@ -236,16 +337,16 @@ class WebSpeechSTTProvider {
236
337
  // Default TTS Provider using Web Speech API
237
338
  class WebSpeechTTSProvider {
238
339
  speak(text) {
239
- if (typeof window !== 'undefined' && 'speechSynthesis' in window) {
340
+ if (typeof window !== "undefined" && "speechSynthesis" in window) {
240
341
  const utterance = new SpeechSynthesisUtterance(text);
241
342
  window.speechSynthesis.speak(utterance);
242
343
  }
243
344
  else {
244
- console.warn('Text-to-speech not supported');
345
+ console.warn("Text-to-speech not supported");
245
346
  }
246
347
  }
247
348
  stop() {
248
- if (typeof window !== 'undefined' && 'speechSynthesis' in window) {
349
+ if (typeof window !== "undefined" && "speechSynthesis" in window) {
249
350
  window.speechSynthesis.cancel();
250
351
  }
251
352
  }
@@ -257,14 +358,10 @@ function ReactBridgeProvider({ apiKey, config = {}, theme = lightTheme, sttProvi
257
358
  apiKey,
258
359
  baseURL: config.baseURL,
259
360
  // Preserve explicit 0 (to disable timeouts). If not provided, default to 30s
260
- timeout: typeof config.timeout === 'number' ? config.timeout : 30000,
361
+ timeout: typeof config.timeout === "number" ? config.timeout : 30000,
261
362
  headers: config.headers,
262
363
  };
263
- const api = React.useMemo(() => new ReactBridgeAPI(fullConfig), [
264
- fullConfig.apiKey,
265
- fullConfig.baseURL,
266
- fullConfig.timeout,
267
- ]);
364
+ const api = React.useMemo(() => new ReactBridgeAPI(fullConfig), [fullConfig.apiKey, fullConfig.baseURL, fullConfig.timeout]);
268
365
  const [sttProvider, setSTTProvider] = React.useState(initialSTTProvider || new WebSpeechSTTProvider());
269
366
  const [ttsProvider, setTTSProvider] = React.useState(initialTTSProvider || new WebSpeechTTSProvider());
270
367
  const value = {
@@ -281,7 +378,7 @@ function ReactBridgeProvider({ apiKey, config = {}, theme = lightTheme, sttProvi
281
378
  function useReactBridgeContext() {
282
379
  const context = React.useContext(ReactBridgeContext);
283
380
  if (!context) {
284
- throw new Error('useReactBridgeContext must be used within a ReactBridgeProvider');
381
+ throw new Error("useReactBridgeContext must be used within a ReactBridgeProvider");
285
382
  }
286
383
  return context;
287
384
  }
@@ -290,7 +387,8 @@ function hasContextChanged(previous, current) {
290
387
  if (!previous)
291
388
  return true;
292
389
  // Check if page changed
293
- if (previous.interfaceState.currentPageName !== current.interfaceState.currentPageName) {
390
+ if (previous.interfaceState.currentPageName !==
391
+ current.interfaceState.currentPageName) {
294
392
  return true;
295
393
  }
296
394
  // Check if viewing items changed
@@ -300,8 +398,8 @@ function hasContextChanged(previous, current) {
300
398
  return true;
301
399
  }
302
400
  // Check if item IDs changed
303
- const prevIds = prevItems.map(item => item.id).sort();
304
- const currIds = currItems.map(item => item.id).sort();
401
+ const prevIds = prevItems.map((item) => item.id).sort();
402
+ const currIds = currItems.map((item) => item.id).sort();
305
403
  return JSON.stringify(prevIds) !== JSON.stringify(currIds);
306
404
  }
307
405
  function getContextSummary(context) {
@@ -310,14 +408,14 @@ function getContextSummary(context) {
310
408
  parts.push(`Page: ${interfaceState.currentPageName}`);
311
409
  if (interfaceState.viewingItems && interfaceState.viewingItems.length > 0) {
312
410
  parts.push(`Viewing ${interfaceState.viewingItems.length} items:`);
313
- interfaceState.viewingItems.slice(0, 3).forEach(item => {
411
+ interfaceState.viewingItems.slice(0, 3).forEach((item) => {
314
412
  parts.push(` - ${item.name} ($${item.price})`);
315
413
  });
316
414
  if (interfaceState.viewingItems.length > 3) {
317
415
  parts.push(` ... and ${interfaceState.viewingItems.length - 3} more`);
318
416
  }
319
417
  }
320
- return parts.join('\n');
418
+ return parts.join("\n");
321
419
  }
322
420
 
323
421
  function useReactBridge({ onIntentDetected, currentContext, onError, onSpeechStart, onSpeechEnd, onTranscript, onAgentResponse, }) {
@@ -335,17 +433,17 @@ function useReactBridge({ onIntentDetected, currentContext, onError, onSpeechSta
335
433
  const contextSummary = getContextSummary(currentContext);
336
434
  const contextMessage = {
337
435
  id: `context-${Date.now()}`,
338
- role: 'system',
436
+ role: "system",
339
437
  content: `[Context Update]\n${contextSummary}`,
340
438
  timestamp: new Date(),
341
439
  };
342
- setMessages(prev => [...prev, contextMessage]);
440
+ setMessages((prev) => [...prev, contextMessage]);
343
441
  previousContextRef.current = currentContext;
344
442
  }
345
443
  }, [currentContext]);
346
444
  const sendChatQuery = React.useCallback((queryOrOptions_1, ...args_1) => __awaiter(this, [queryOrOptions_1, ...args_1], void 0, function* (queryOrOptions, fromVoiceInput = false) {
347
- const isMultimodal = typeof queryOrOptions === 'object';
348
- const query = isMultimodal ? (queryOrOptions.query || '') : queryOrOptions;
445
+ const isMultimodal = typeof queryOrOptions === "object";
446
+ const query = isMultimodal ? queryOrOptions.query || "" : queryOrOptions;
349
447
  const image = isMultimodal ? queryOrOptions.image : undefined;
350
448
  const document = isMultimodal ? queryOrOptions.document : undefined;
351
449
  if (!query.trim() && !image && !document)
@@ -355,18 +453,22 @@ function useReactBridge({ onIntentDetected, currentContext, onError, onSpeechSta
355
453
  // Add user message with file info if present
356
454
  let messageContent = query;
357
455
  if (image) {
358
- messageContent = messageContent ? `${messageContent} [Image: ${image.name}]` : `[Image: ${image.name}]`;
456
+ messageContent = messageContent
457
+ ? `${messageContent} [Image: ${image.name}]`
458
+ : `[Image: ${image.name}]`;
359
459
  }
360
460
  else if (document) {
361
- messageContent = messageContent ? `${messageContent} [Document: ${document.name}]` : `[Document: ${document.name}]`;
461
+ messageContent = messageContent
462
+ ? `${messageContent} [Document: ${document.name}]`
463
+ : `[Document: ${document.name}]`;
362
464
  }
363
465
  const userMessage = {
364
466
  id: `user-${Date.now()}`,
365
- role: 'user',
467
+ role: "user",
366
468
  content: messageContent,
367
469
  timestamp: new Date(),
368
470
  };
369
- setMessages(prev => [...prev, userMessage]);
471
+ setMessages((prev) => [...prev, userMessage]);
370
472
  try {
371
473
  // Step 1: Send initial request to orchestrator
372
474
  const request = {
@@ -381,12 +483,12 @@ function useReactBridge({ onIntentDetected, currentContext, onError, onSpeechSta
381
483
  // Add multimodal fields
382
484
  image,
383
485
  document,
384
- modalityHint: image ? 'image' : document ? 'document' : undefined,
486
+ modalityHint: image ? "image" : document ? "document" : undefined,
385
487
  };
386
488
  lastRequestRef.current = request;
387
489
  const response = yield api.sendMessage(request);
388
490
  if (!response.success) {
389
- throw new Error(response.error || 'Request failed');
491
+ throw new Error(response.error || "Request failed");
390
492
  }
391
493
  // Update session ID
392
494
  if (response.sessionId) {
@@ -395,12 +497,12 @@ function useReactBridge({ onIntentDetected, currentContext, onError, onSpeechSta
395
497
  // Add assistant message
396
498
  const assistantMessage = {
397
499
  id: `assistant-${Date.now()}`,
398
- role: 'assistant',
500
+ role: "assistant",
399
501
  content: response.message,
400
502
  timestamp: new Date(),
401
503
  toolCall: response.toolCall,
402
504
  };
403
- setMessages(prev => [...prev, assistantMessage]);
505
+ setMessages((prev) => [...prev, assistantMessage]);
404
506
  // Trigger TTS and callback only if input came from voice
405
507
  if (fromVoiceInput) {
406
508
  ttsProvider.speak(response.message);
@@ -418,11 +520,11 @@ function useReactBridge({ onIntentDetected, currentContext, onError, onSpeechSta
418
520
  // Add final assistant message with tool result context
419
521
  const finalMessage = {
420
522
  id: `assistant-final-${Date.now()}`,
421
- role: 'assistant',
523
+ role: "assistant",
422
524
  content: resultResponse.message,
423
525
  timestamp: new Date(),
424
526
  };
425
- setMessages(prev => [...prev, finalMessage]);
527
+ setMessages((prev) => [...prev, finalMessage]);
426
528
  // Trigger TTS for final response only if input came from voice
427
529
  if (fromVoiceInput) {
428
530
  ttsProvider.speak(resultResponse.message);
@@ -435,30 +537,32 @@ function useReactBridge({ onIntentDetected, currentContext, onError, onSpeechSta
435
537
  catch (toolError) {
436
538
  const errorMessage = toolError instanceof Error
437
539
  ? toolError.message
438
- : 'Tool execution failed';
540
+ : "Tool execution failed";
439
541
  const errorMsg = {
440
542
  id: `error-${Date.now()}`,
441
- role: 'assistant',
543
+ role: "assistant",
442
544
  content: `I encountered an error: ${errorMessage}`,
443
545
  timestamp: new Date(),
444
546
  };
445
- setMessages(prev => [...prev, errorMsg]);
547
+ setMessages((prev) => [...prev, errorMsg]);
446
548
  if (onError) {
447
- onError(toolError instanceof Error ? toolError : new Error(errorMessage));
549
+ onError(toolError instanceof Error
550
+ ? toolError
551
+ : new Error(errorMessage));
448
552
  }
449
553
  }
450
554
  }
451
555
  }
452
556
  catch (err) {
453
- const error = err instanceof Error ? err : new Error('Unknown error');
557
+ const error = err instanceof Error ? err : new Error("Unknown error");
454
558
  setError(error);
455
559
  const errorMessage = {
456
560
  id: `error-${Date.now()}`,
457
- role: 'assistant',
561
+ role: "assistant",
458
562
  content: `Sorry, I encountered an error: ${error.message}`,
459
563
  timestamp: new Date(),
460
564
  };
461
- setMessages(prev => [...prev, errorMessage]);
565
+ setMessages((prev) => [...prev, errorMessage]);
462
566
  if (onError) {
463
567
  onError(error);
464
568
  }
@@ -499,7 +603,14 @@ function useReactBridge({ onIntentDetected, currentContext, onError, onSpeechSta
499
603
  });
500
604
  }
501
605
  sttProvider.startRecognition();
502
- }, [sttProvider, sendChatQuery, onSpeechStart, onSpeechEnd, onTranscript, onError]);
606
+ }, [
607
+ sttProvider,
608
+ sendChatQuery,
609
+ onSpeechStart,
610
+ onSpeechEnd,
611
+ onTranscript,
612
+ onError,
613
+ ]);
503
614
  const stopVoiceInput = React.useCallback(() => {
504
615
  setIsListening(false);
505
616
  sttProvider.stopRecognition();
@@ -957,7 +1068,9 @@ toggleButtonClass = defaultToggleButtonClass, toggleButtonTitle = "Open chat ass
957
1068
  padding: theme.spacing.md,
958
1069
  backgroundColor: theme.colors.background,
959
1070
  } },
960
- messages.map((message) => renderMessage ? renderMessage(message) : defaultRenderMessage(message)),
1071
+ messages.map((message) => renderMessage
1072
+ ? renderMessage(message)
1073
+ : defaultRenderMessage(message)),
961
1074
  isLoading && React.createElement(TypingIndicator, { theme: theme }),
962
1075
  React.createElement("div", { ref: messagesEndRef })),
963
1076
  React.createElement("form", { onSubmit: handleSubmit, style: {
@@ -1112,10 +1225,10 @@ const MIC_ICON_SVG = (React.createElement("svg", { xmlns: "http://www.w3.org/200
1112
1225
  // Plus Icon SVG
1113
1226
  const PLUS_ICON_SVG = (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "1em", height: "1em", fill: "currentColor" },
1114
1227
  React.createElement("path", { d: "M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" })));
1115
- function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = 'Search...', width = '100%', maxResults = 5, theme: themeOverride, onError, onSpeechStart, onSpeechEnd, onTranscript, onAgentResponse, }) {
1228
+ function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = "Search...", width = "100%", maxResults = 5, theme: themeOverride, onError, onSpeechStart, onSpeechEnd, onTranscript, onAgentResponse, }) {
1116
1229
  const { theme: contextTheme } = useReactBridgeContext();
1117
1230
  const theme = Object.assign(Object.assign({}, contextTheme), themeOverride);
1118
- const { messages, isLoading, sendChatQuery, isListening, startVoiceInput, stopVoiceInput } = useReactBridge({
1231
+ const { messages, isLoading, sendChatQuery, isListening, startVoiceInput, stopVoiceInput, } = useReactBridge({
1119
1232
  onIntentDetected,
1120
1233
  currentContext,
1121
1234
  onError,
@@ -1124,7 +1237,7 @@ function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = 'Se
1124
1237
  onTranscript,
1125
1238
  onAgentResponse,
1126
1239
  });
1127
- const [inputValue, setInputValue] = React.useState('');
1240
+ const [inputValue, setInputValue] = React.useState("");
1128
1241
  const [isOpen, setIsOpen] = React.useState(false);
1129
1242
  const [isUploadMenuOpen, setIsUploadMenuOpen] = React.useState(false);
1130
1243
  const [selectedFile, setSelectedFile] = React.useState(null);
@@ -1134,13 +1247,14 @@ function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = 'Se
1134
1247
  // Close dropdown and upload menu when clicking outside
1135
1248
  React.useEffect(() => {
1136
1249
  const handleClickOutside = (event) => {
1137
- if (containerRef.current && !containerRef.current.contains(event.target)) {
1250
+ if (containerRef.current &&
1251
+ !containerRef.current.contains(event.target)) {
1138
1252
  setIsOpen(false);
1139
1253
  setIsUploadMenuOpen(false);
1140
1254
  }
1141
1255
  };
1142
- document.addEventListener('mousedown', handleClickOutside);
1143
- return () => document.removeEventListener('mousedown', handleClickOutside);
1256
+ document.addEventListener("mousedown", handleClickOutside);
1257
+ return () => document.removeEventListener("mousedown", handleClickOutside);
1144
1258
  }, []);
1145
1259
  // Open dropdown when there are messages
1146
1260
  React.useEffect(() => {
@@ -1150,9 +1264,10 @@ function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = 'Se
1150
1264
  }, [messages]);
1151
1265
  const handleFileSelect = (type) => {
1152
1266
  if (fileInputRef.current) {
1153
- fileInputRef.current.accept = type === 'image'
1154
- ? 'image/png,image/jpeg,image/jpg,image/webp'
1155
- : 'application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,text/plain';
1267
+ fileInputRef.current.accept =
1268
+ type === "image"
1269
+ ? "image/png,image/jpeg,image/jpg,image/webp"
1270
+ : "application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,text/plain";
1156
1271
  fileInputRef.current.click();
1157
1272
  }
1158
1273
  setIsUploadMenuOpen(false);
@@ -1163,12 +1278,19 @@ function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = 'Se
1163
1278
  if (!file)
1164
1279
  return;
1165
1280
  // Validate file type
1166
- const imageTypes = ['image/png', 'image/jpeg', 'image/jpg', 'image/webp'];
1167
- const documentTypes = ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'text/plain'];
1168
- const allowedTypes = file.type.startsWith('image/') ? imageTypes : documentTypes;
1281
+ const imageTypes = ["image/png", "image/jpeg", "image/jpg", "image/webp"];
1282
+ const documentTypes = [
1283
+ "application/pdf",
1284
+ "application/msword",
1285
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
1286
+ "text/plain",
1287
+ ];
1288
+ const allowedTypes = file.type.startsWith("image/")
1289
+ ? imageTypes
1290
+ : documentTypes;
1169
1291
  if (!allowedTypes.includes(file.type)) {
1170
1292
  if (onError) {
1171
- onError(new Error(`Invalid file type. Please select a valid ${file.type.startsWith('image/') ? 'image' : 'document'} file.`));
1293
+ onError(new Error(`Invalid file type. Please select a valid ${file.type.startsWith("image/") ? "image" : "document"} file.`));
1172
1294
  }
1173
1295
  return;
1174
1296
  }
@@ -1176,13 +1298,13 @@ function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = 'Se
1176
1298
  const maxSize = 10 * 1024 * 1024; // 10MB
1177
1299
  if (file.size > maxSize) {
1178
1300
  if (onError) {
1179
- onError(new Error('File size too large. Please select a file smaller than 10MB.'));
1301
+ onError(new Error("File size too large. Please select a file smaller than 10MB."));
1180
1302
  }
1181
1303
  return;
1182
1304
  }
1183
1305
  setSelectedFile(file);
1184
1306
  // Create preview for images
1185
- if (file.type.startsWith('image/')) {
1307
+ if (file.type.startsWith("image/")) {
1186
1308
  const reader = new FileReader();
1187
1309
  reader.onload = (e) => {
1188
1310
  var _a;
@@ -1199,7 +1321,7 @@ function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = 'Se
1199
1321
  setSelectedFile(null);
1200
1322
  setFilePreview(null);
1201
1323
  if (fileInputRef.current) {
1202
- fileInputRef.current.value = '';
1324
+ fileInputRef.current.value = "";
1203
1325
  }
1204
1326
  };
1205
1327
  const handleSubmit = (e) => __awaiter(this, void 0, void 0, function* () {
@@ -1207,13 +1329,17 @@ function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = 'Se
1207
1329
  if ((!inputValue.trim() && !selectedFile) || isLoading)
1208
1330
  return;
1209
1331
  const query = inputValue.trim();
1210
- setInputValue('');
1332
+ setInputValue("");
1211
1333
  // Handle multimodal request
1212
1334
  if (selectedFile && filePreview) {
1213
1335
  yield sendChatQuery({
1214
1336
  query,
1215
- image: selectedFile.type.startsWith('image/') ? selectedFile : undefined,
1216
- document: selectedFile.type.startsWith('image/') ? undefined : selectedFile,
1337
+ image: selectedFile.type.startsWith("image/")
1338
+ ? selectedFile
1339
+ : undefined,
1340
+ document: selectedFile.type.startsWith("image/")
1341
+ ? undefined
1342
+ : selectedFile,
1217
1343
  });
1218
1344
  removeFile();
1219
1345
  }
@@ -1223,33 +1349,33 @@ function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = 'Se
1223
1349
  });
1224
1350
  // Get only assistant messages (not system messages)
1225
1351
  const displayMessages = messages
1226
- .filter((msg) => msg.role === 'assistant')
1352
+ .filter((msg) => msg.role === "assistant")
1227
1353
  .slice(-maxResults);
1228
1354
  return (React.createElement("div", { ref: containerRef, style: {
1229
- position: 'relative',
1355
+ position: "relative",
1230
1356
  width,
1231
- fontFamily: 'system-ui, -apple-system, sans-serif',
1357
+ fontFamily: "system-ui, -apple-system, sans-serif",
1232
1358
  } },
1233
1359
  React.createElement("form", { onSubmit: handleSubmit },
1234
- React.createElement("div", { style: { position: 'relative' } },
1235
- React.createElement("input", { ref: fileInputRef, type: "file", onChange: handleFileChange, style: { display: 'none' } }),
1360
+ React.createElement("div", { style: { position: "relative" } },
1361
+ React.createElement("input", { ref: fileInputRef, type: "file", onChange: handleFileChange, style: { display: "none" } }),
1236
1362
  React.createElement("input", { type: "text", value: inputValue, onChange: (e) => setInputValue(e.target.value), onFocus: () => displayMessages.length > 0 && setIsOpen(true), placeholder: selectedFile ? `Search with ${selectedFile.name}...` : placeholder, disabled: isLoading, style: {
1237
- width: '100%',
1363
+ width: "100%",
1238
1364
  padding: theme.spacing.md,
1239
- paddingRight: '180px', // Increased to make room for plus, mic, and search buttons
1365
+ paddingRight: "180px", // Increased to make room for plus, mic, and search buttons
1240
1366
  fontSize: theme.fontSizes.md,
1241
1367
  border: `1px solid ${theme.colors.border}`,
1242
1368
  borderRadius: theme.borderRadius,
1243
1369
  backgroundColor: theme.colors.background,
1244
1370
  color: theme.colors.text,
1245
- outline: 'none',
1246
- boxSizing: 'border-box',
1371
+ outline: "none",
1372
+ boxSizing: "border-box",
1247
1373
  } }),
1248
1374
  React.createElement("button", { type: "button", onClick: () => setIsUploadMenuOpen(!isUploadMenuOpen), disabled: isLoading, title: "Upload file", style: {
1249
- position: 'absolute',
1250
- right: '105px', // Position before the mic button
1251
- top: '50%',
1252
- transform: 'translateY(-50%)',
1375
+ position: "absolute",
1376
+ right: "105px", // Position before the mic button
1377
+ top: "50%",
1378
+ transform: "translateY(-50%)",
1253
1379
  padding: theme.spacing.sm,
1254
1380
  marginRight: theme.spacing.xs,
1255
1381
  color: theme.colors.border,
@@ -1264,42 +1390,42 @@ function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = 'Se
1264
1390
  height: "32px",
1265
1391
  } }, PLUS_ICON_SVG),
1266
1392
  isUploadMenuOpen && (React.createElement("div", { style: {
1267
- position: 'absolute',
1268
- right: '105px',
1269
- top: '100%',
1393
+ position: "absolute",
1394
+ right: "105px",
1395
+ top: "100%",
1270
1396
  marginTop: theme.spacing.xs,
1271
1397
  backgroundColor: theme.colors.background,
1272
1398
  border: `1px solid ${theme.colors.border}`,
1273
1399
  borderRadius: theme.borderRadius,
1274
1400
  boxShadow: theme.boxShadow,
1275
1401
  zIndex: 1000,
1276
- minWidth: '120px',
1402
+ minWidth: "120px",
1277
1403
  } },
1278
- React.createElement("button", { type: "button", onClick: () => handleFileSelect('image'), style: {
1279
- width: '100%',
1404
+ React.createElement("button", { type: "button", onClick: () => handleFileSelect("image"), style: {
1405
+ width: "100%",
1280
1406
  padding: theme.spacing.sm,
1281
- backgroundColor: 'transparent',
1282
- border: 'none',
1407
+ backgroundColor: "transparent",
1408
+ border: "none",
1283
1409
  color: theme.colors.text,
1284
- cursor: 'pointer',
1285
- textAlign: 'left',
1410
+ cursor: "pointer",
1411
+ textAlign: "left",
1286
1412
  fontSize: theme.fontSizes.sm,
1287
1413
  } }, "\uD83D\uDCF7 Image"),
1288
- React.createElement("button", { type: "button", onClick: () => handleFileSelect('document'), style: {
1289
- width: '100%',
1414
+ React.createElement("button", { type: "button", onClick: () => handleFileSelect("document"), style: {
1415
+ width: "100%",
1290
1416
  padding: theme.spacing.sm,
1291
- backgroundColor: 'transparent',
1292
- border: 'none',
1417
+ backgroundColor: "transparent",
1418
+ border: "none",
1293
1419
  color: theme.colors.text,
1294
- cursor: 'pointer',
1295
- textAlign: 'left',
1420
+ cursor: "pointer",
1421
+ textAlign: "left",
1296
1422
  fontSize: theme.fontSizes.sm,
1297
1423
  } }, "\uD83D\uDCC4 Document"))),
1298
1424
  React.createElement("button", { type: "button", onClick: isListening ? stopVoiceInput : startVoiceInput, disabled: isLoading, title: isListening ? "Stop recording" : "Start voice input", style: {
1299
- position: 'absolute',
1300
- right: '70px', // Position before the search button
1301
- top: '50%',
1302
- transform: 'translateY(-50%)',
1425
+ position: "absolute",
1426
+ right: "70px", // Position before the search button
1427
+ top: "50%",
1428
+ transform: "translateY(-50%)",
1303
1429
  padding: theme.spacing.sm,
1304
1430
  marginRight: theme.spacing.xs,
1305
1431
  color: isListening ? theme.colors.primary : theme.colors.border,
@@ -1314,67 +1440,73 @@ function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = 'Se
1314
1440
  height: "32px",
1315
1441
  } }, MIC_ICON_SVG),
1316
1442
  React.createElement("button", { type: "submit", disabled: isLoading || (!inputValue.trim() && !selectedFile), style: {
1317
- position: 'absolute',
1443
+ position: "absolute",
1318
1444
  right: theme.spacing.sm,
1319
- top: '50%',
1320
- transform: 'translateY(-50%)',
1445
+ top: "50%",
1446
+ transform: "translateY(-50%)",
1321
1447
  padding: `${theme.spacing.xs} ${theme.spacing.md}`,
1322
1448
  fontSize: theme.fontSizes.sm,
1323
1449
  backgroundColor: theme.colors.primary,
1324
1450
  color: theme.colors.background,
1325
- border: 'none',
1451
+ border: "none",
1326
1452
  borderRadius: theme.borderRadius,
1327
- cursor: isLoading || (!inputValue.trim() && !selectedFile) ? 'not-allowed' : 'pointer',
1453
+ cursor: isLoading || (!inputValue.trim() && !selectedFile)
1454
+ ? "not-allowed"
1455
+ : "pointer",
1328
1456
  opacity: isLoading || (!inputValue.trim() && !selectedFile) ? 0.5 : 1,
1329
- } }, isLoading ? 'Searching...' : 'Search')),
1457
+ } }, isLoading ? "Searching..." : "Search")),
1330
1458
  selectedFile && filePreview && (React.createElement("div", { style: {
1331
1459
  marginTop: theme.spacing.sm,
1332
1460
  padding: theme.spacing.sm,
1333
1461
  backgroundColor: theme.colors.surface,
1334
1462
  border: `1px solid ${theme.colors.border}`,
1335
1463
  borderRadius: theme.borderRadius,
1336
- display: 'flex',
1337
- alignItems: 'center',
1464
+ display: "flex",
1465
+ alignItems: "center",
1338
1466
  gap: theme.spacing.sm,
1339
1467
  } },
1340
- selectedFile.type.startsWith('image/') ? (React.createElement("img", { src: filePreview, alt: "Preview", style: {
1341
- width: '40px',
1342
- height: '40px',
1343
- objectFit: 'cover',
1468
+ selectedFile.type.startsWith("image/") ? (React.createElement("img", { src: filePreview, alt: "Preview", style: {
1469
+ width: "40px",
1470
+ height: "40px",
1471
+ objectFit: "cover",
1344
1472
  borderRadius: theme.borderRadius,
1345
1473
  } })) : (React.createElement("div", { style: {
1346
- width: '40px',
1347
- height: '40px',
1474
+ width: "40px",
1475
+ height: "40px",
1348
1476
  backgroundColor: theme.colors.primary,
1349
1477
  borderRadius: theme.borderRadius,
1350
- display: 'flex',
1351
- alignItems: 'center',
1352
- justifyContent: 'center',
1478
+ display: "flex",
1479
+ alignItems: "center",
1480
+ justifyContent: "center",
1353
1481
  color: theme.colors.background,
1354
1482
  fontSize: theme.fontSizes.lg,
1355
1483
  } }, "\uD83D\uDCC4")),
1356
- React.createElement("div", { style: { flex: 1, fontSize: theme.fontSizes.sm, color: theme.colors.text } },
1357
- React.createElement("div", { style: { fontWeight: 'bold' } }, selectedFile.name),
1484
+ React.createElement("div", { style: {
1485
+ flex: 1,
1486
+ fontSize: theme.fontSizes.sm,
1487
+ color: theme.colors.text,
1488
+ } },
1489
+ React.createElement("div", { style: { fontWeight: "bold" } }, selectedFile.name),
1358
1490
  React.createElement("div", { style: { color: theme.colors.textSecondary } },
1359
1491
  (selectedFile.size / 1024 / 1024).toFixed(2),
1360
1492
  " MB")),
1361
1493
  React.createElement("button", { type: "button", onClick: removeFile, style: {
1362
1494
  padding: theme.spacing.xs,
1363
- backgroundColor: 'transparent',
1364
- border: 'none',
1495
+ backgroundColor: "transparent",
1496
+ border: "none",
1365
1497
  color: theme.colors.textSecondary,
1366
- cursor: 'pointer',
1498
+ cursor: "pointer",
1367
1499
  borderRadius: theme.borderRadius,
1368
- width: '24px',
1369
- height: '24px',
1370
- display: 'flex',
1371
- alignItems: 'center',
1372
- justifyContent: 'center',
1373
- fontSize: '18px',
1500
+ width: "24px",
1501
+ height: "24px",
1502
+ display: "flex",
1503
+ alignItems: "center",
1504
+ justifyContent: "center",
1505
+ fontSize: "18px",
1374
1506
  }, title: "Remove file" }, "\u00D7")))),
1375
1507
  isOpen && displayMessages.length > 0 && (React.createElement("div", { style: {
1376
- position: 'absolute',
1377
- top: '100%',
1508
+ position: "absolute",
1509
+ top: "100%",
1378
1510
  left: 0,
1379
1511
  right: 0,
1380
1512
  marginTop: theme.spacing.xs,
@@ -1382,15 +1514,15 @@ function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = 'Se
1382
1514
  border: `1px solid ${theme.colors.border}`,
1383
1515
  borderRadius: theme.borderRadius,
1384
1516
  boxShadow: theme.boxShadow,
1385
- maxHeight: '300px',
1386
- overflowY: 'auto',
1517
+ maxHeight: "300px",
1518
+ overflowY: "auto",
1387
1519
  zIndex: 1000,
1388
1520
  } }, displayMessages.map((message) => (React.createElement("div", { key: message.id, style: {
1389
1521
  padding: theme.spacing.md,
1390
1522
  borderBottom: `1px solid ${theme.colors.border}`,
1391
1523
  fontSize: theme.fontSizes.sm,
1392
1524
  color: theme.colors.text,
1393
- cursor: 'pointer',
1525
+ cursor: "pointer",
1394
1526
  }, onMouseEnter: (e) => {
1395
1527
  e.currentTarget.style.backgroundColor = theme.colors.surface;
1396
1528
  }, onMouseLeave: (e) => {
@@ -1399,47 +1531,47 @@ function ReactBridgeSearch({ onIntentDetected, currentContext, placeholder = 'Se
1399
1531
  }
1400
1532
 
1401
1533
  const darkTheme = {
1402
- name: 'dark',
1534
+ name: "dark",
1403
1535
  colors: {
1404
- primary: '#90caf9',
1405
- secondary: '#f48fb1',
1406
- background: '#121212',
1407
- surface: '#1e1e1e',
1408
- text: '#ffffff',
1409
- textSecondary: '#b0b0b0',
1410
- border: '#333333',
1411
- error: '#f44336',
1412
- success: '#4caf50',
1536
+ primary: "#90caf9",
1537
+ secondary: "#f48fb1",
1538
+ background: "#121212",
1539
+ surface: "#1e1e1e",
1540
+ text: "#ffffff",
1541
+ textSecondary: "#b0b0b0",
1542
+ border: "#333333",
1543
+ error: "#f44336",
1544
+ success: "#4caf50",
1413
1545
  },
1414
1546
  spacing: {
1415
- xs: '4px',
1416
- sm: '8px',
1417
- md: '16px',
1418
- lg: '24px',
1419
- xl: '32px',
1547
+ xs: "4px",
1548
+ sm: "8px",
1549
+ md: "16px",
1550
+ lg: "24px",
1551
+ xl: "32px",
1420
1552
  },
1421
1553
  fontSizes: {
1422
- xs: '12px',
1423
- sm: '14px',
1424
- md: '16px',
1425
- lg: '18px',
1426
- xl: '24px',
1554
+ xs: "12px",
1555
+ sm: "14px",
1556
+ md: "16px",
1557
+ lg: "18px",
1558
+ xl: "24px",
1427
1559
  },
1428
- borderRadius: '8px',
1429
- boxShadow: '0 2px 8px rgba(0, 0, 0, 0.5)',
1560
+ borderRadius: "8px",
1561
+ boxShadow: "0 2px 8px rgba(0, 0, 0, 0.5)",
1430
1562
  };
1431
1563
 
1432
1564
  function getTheme(mode, customTheme) {
1433
- if (mode === 'custom' && customTheme) {
1565
+ if (mode === "custom" && customTheme) {
1434
1566
  return customTheme;
1435
1567
  }
1436
- return mode === 'dark' ? darkTheme : lightTheme;
1568
+ return mode === "dark" ? darkTheme : lightTheme;
1437
1569
  }
1438
1570
  function createCustomTheme(baseTheme, overrides) {
1439
1571
  return Object.assign(Object.assign(Object.assign({}, baseTheme), overrides), { colors: Object.assign(Object.assign({}, baseTheme.colors), (overrides.colors || {})), spacing: Object.assign(Object.assign({}, baseTheme.spacing), (overrides.spacing || {})), fontSizes: Object.assign(Object.assign({}, baseTheme.fontSizes), (overrides.fontSizes || {})) });
1440
1572
  }
1441
1573
 
1442
- const DEFAULT_BASE_URL = 'https://react-bridge-api-14089992360.northamerica-northeast2.run.app';
1574
+ const DEFAULT_BASE_URL = "https://react-bridge-api-14089992360.northamerica-northeast2.run.app";
1443
1575
  class AnalyticsAPI {
1444
1576
  constructor(config) {
1445
1577
  this.config = config;
@@ -1452,8 +1584,8 @@ class AnalyticsAPI {
1452
1584
  const baseURL = this.config.baseURL || DEFAULT_BASE_URL;
1453
1585
  const url = `${baseURL}/api/analytics/configs`;
1454
1586
  const response = yield fetch(url, {
1455
- method: 'GET',
1456
- headers: Object.assign({ 'X-API-Key': this.config.apiKey }, this.config.headers),
1587
+ method: "GET",
1588
+ headers: Object.assign({ "X-API-Key": this.config.apiKey }, this.config.headers),
1457
1589
  });
1458
1590
  if (!response.ok) {
1459
1591
  throw new Error(`Failed to fetch analytics configs: ${response.statusText}`);
@@ -1469,8 +1601,8 @@ class AnalyticsAPI {
1469
1601
  const baseURL = this.config.baseURL || DEFAULT_BASE_URL;
1470
1602
  const url = `${baseURL}/api/analytics/${analyticsType}/latest`;
1471
1603
  const response = yield fetch(url, {
1472
- method: 'GET',
1473
- headers: Object.assign({ 'X-API-Key': this.config.apiKey, 'Content-Type': 'application/json' }, this.config.headers),
1604
+ method: "GET",
1605
+ headers: Object.assign({ "X-API-Key": this.config.apiKey, "Content-Type": "application/json" }, this.config.headers),
1474
1606
  });
1475
1607
  if (!response.ok) {
1476
1608
  if (response.status === 404) {
@@ -1489,8 +1621,8 @@ class AnalyticsAPI {
1489
1621
  const baseURL = this.config.baseURL || DEFAULT_BASE_URL;
1490
1622
  const url = `${baseURL}/api/analytics/directives/${directiveId}/status`;
1491
1623
  const response = yield fetch(url, {
1492
- method: 'PATCH',
1493
- headers: Object.assign({ 'X-API-Key': this.config.apiKey, 'Content-Type': 'application/json' }, this.config.headers),
1624
+ method: "PATCH",
1625
+ headers: Object.assign({ "X-API-Key": this.config.apiKey, "Content-Type": "application/json" }, this.config.headers),
1494
1626
  body: JSON.stringify({ status }),
1495
1627
  });
1496
1628
  if (!response.ok) {
@@ -1566,14 +1698,14 @@ function useAnalyticsResult(analyticsType) {
1566
1698
  };
1567
1699
  }
1568
1700
 
1569
- const MetricsPanel = ({ metrics, theme }) => {
1701
+ const MetricsPanel = ({ metrics, theme, }) => {
1570
1702
  const getStatusColor = (status) => {
1571
1703
  switch (status) {
1572
- case 'ok':
1704
+ case "ok":
1573
1705
  return theme.colors.success;
1574
- case 'warning':
1575
- return '#FFA500'; // Orange
1576
- case 'critical':
1706
+ case "warning":
1707
+ return "#FFA500"; // Orange
1708
+ case "critical":
1577
1709
  return theme.colors.error;
1578
1710
  default:
1579
1711
  return theme.colors.textSecondary;
@@ -1587,8 +1719,8 @@ const MetricsPanel = ({ metrics, theme }) => {
1587
1719
  color: theme.colors.text,
1588
1720
  } }, "Metrics"),
1589
1721
  React.createElement("div", { style: {
1590
- display: 'grid',
1591
- gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))',
1722
+ display: "grid",
1723
+ gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))",
1592
1724
  gap: theme.spacing.md,
1593
1725
  } }, metrics.map((metric, index) => (React.createElement("div", { key: index, style: {
1594
1726
  padding: theme.spacing.md,
@@ -1597,28 +1729,28 @@ const MetricsPanel = ({ metrics, theme }) => {
1597
1729
  border: `2px solid ${getStatusColor(metric.status)}`,
1598
1730
  } },
1599
1731
  React.createElement("div", { style: {
1600
- display: 'flex',
1601
- justifyContent: 'space-between',
1602
- alignItems: 'center',
1732
+ display: "flex",
1733
+ justifyContent: "space-between",
1734
+ alignItems: "center",
1603
1735
  marginBottom: theme.spacing.xs,
1604
1736
  } },
1605
1737
  React.createElement("span", { style: {
1606
1738
  fontSize: theme.fontSizes.sm,
1607
1739
  color: theme.colors.textSecondary,
1608
- textTransform: 'uppercase',
1609
- letterSpacing: '0.5px',
1610
- } }, metric.name.replace(/_/g, ' ')),
1740
+ textTransform: "uppercase",
1741
+ letterSpacing: "0.5px",
1742
+ } }, metric.name.replace(/_/g, " ")),
1611
1743
  React.createElement("span", { style: {
1612
1744
  fontSize: theme.fontSizes.xs,
1613
- padding: '2px 8px',
1614
- borderRadius: '12px',
1745
+ padding: "2px 8px",
1746
+ borderRadius: "12px",
1615
1747
  backgroundColor: getStatusColor(metric.status),
1616
- color: '#fff',
1617
- textTransform: 'uppercase',
1748
+ color: "#fff",
1749
+ textTransform: "uppercase",
1618
1750
  } }, metric.status)),
1619
1751
  React.createElement("div", { style: {
1620
1752
  fontSize: theme.fontSizes.xl,
1621
- fontWeight: 'bold',
1753
+ fontWeight: "bold",
1622
1754
  color: theme.colors.text,
1623
1755
  marginBottom: theme.spacing.xs,
1624
1756
  } },
@@ -1634,11 +1766,11 @@ const MetricsPanel = ({ metrics, theme }) => {
1634
1766
  const ObservationsPanel = ({ observations, theme, }) => {
1635
1767
  const getSeverityColor = (severity) => {
1636
1768
  switch (severity) {
1637
- case 'low':
1769
+ case "low":
1638
1770
  return theme.colors.success;
1639
- case 'medium':
1640
- return '#FFA500'; // Orange
1641
- case 'high':
1771
+ case "medium":
1772
+ return "#FFA500"; // Orange
1773
+ case "high":
1642
1774
  return theme.colors.error;
1643
1775
  default:
1644
1776
  return theme.colors.textSecondary;
@@ -1651,7 +1783,11 @@ const ObservationsPanel = ({ observations, theme, }) => {
1651
1783
  fontSize: theme.fontSizes.lg,
1652
1784
  color: theme.colors.text,
1653
1785
  } }, "Observations"),
1654
- React.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: theme.spacing.md } }, observations.map((observation, index) => (React.createElement("div", { key: index, style: {
1786
+ React.createElement("div", { style: {
1787
+ display: "flex",
1788
+ flexDirection: "column",
1789
+ gap: theme.spacing.md,
1790
+ } }, observations.map((observation, index) => (React.createElement("div", { key: index, style: {
1655
1791
  padding: theme.spacing.md,
1656
1792
  backgroundColor: theme.colors.surface,
1657
1793
  borderRadius: theme.borderRadius,
@@ -1659,18 +1795,18 @@ const ObservationsPanel = ({ observations, theme, }) => {
1659
1795
  borderLeft: `4px solid ${getSeverityColor(observation.severity)}`,
1660
1796
  } },
1661
1797
  React.createElement("div", { style: {
1662
- display: 'flex',
1663
- justifyContent: 'space-between',
1664
- alignItems: 'center',
1798
+ display: "flex",
1799
+ justifyContent: "space-between",
1800
+ alignItems: "center",
1665
1801
  marginBottom: theme.spacing.xs,
1666
1802
  } },
1667
1803
  React.createElement("span", { style: {
1668
1804
  fontSize: theme.fontSizes.xs,
1669
- padding: '2px 8px',
1670
- borderRadius: '12px',
1805
+ padding: "2px 8px",
1806
+ borderRadius: "12px",
1671
1807
  backgroundColor: getSeverityColor(observation.severity),
1672
- color: '#fff',
1673
- textTransform: 'uppercase',
1808
+ color: "#fff",
1809
+ textTransform: "uppercase",
1674
1810
  } }, observation.severity),
1675
1811
  React.createElement("span", { style: {
1676
1812
  fontSize: theme.fontSizes.xs,
@@ -1679,7 +1815,7 @@ const ObservationsPanel = ({ observations, theme, }) => {
1679
1815
  React.createElement("div", { style: {
1680
1816
  fontSize: theme.fontSizes.md,
1681
1817
  color: theme.colors.text,
1682
- lineHeight: '1.5',
1818
+ lineHeight: "1.5",
1683
1819
  } }, observation.text)))))));
1684
1820
  };
1685
1821
 
@@ -1697,19 +1833,19 @@ function useDirectiveAction(onDirectiveAction) {
1697
1833
  const result = yield onDirectiveAction(directive, action);
1698
1834
  if (result.success) {
1699
1835
  // Update status to 'executed' if action succeeded
1700
- yield api.updateDirectiveStatus(directive.directiveId, 'executed');
1836
+ yield api.updateDirectiveStatus(directive.directiveId, "executed");
1701
1837
  }
1702
1838
  else {
1703
1839
  // Update status to 'failed' if action failed
1704
- yield api.updateDirectiveStatus(directive.directiveId, 'failed');
1705
- throw new Error(result.error || 'Directive execution failed');
1840
+ yield api.updateDirectiveStatus(directive.directiveId, "failed");
1841
+ throw new Error(result.error || "Directive execution failed");
1706
1842
  }
1707
1843
  return { success: true };
1708
1844
  }
1709
1845
  else {
1710
1846
  // No callback provided, just update status to 'declined'
1711
- if (action === 'decline') {
1712
- yield api.updateDirectiveStatus(directive.directiveId, 'declined');
1847
+ if (action === "decline") {
1848
+ yield api.updateDirectiveStatus(directive.directiveId, "declined");
1713
1849
  }
1714
1850
  return { success: true };
1715
1851
  }
@@ -1736,28 +1872,28 @@ const DirectivesPanel = ({ directives, theme, onDirectiveAction, onUpdate, }) =>
1736
1872
  if (priority >= 3)
1737
1873
  return theme.colors.error; // High/Critical
1738
1874
  if (priority === 2)
1739
- return '#FFA500'; // Medium
1875
+ return "#FFA500"; // Medium
1740
1876
  return theme.colors.success; // Low
1741
1877
  };
1742
1878
  const getPriorityLabel = (priority) => {
1743
1879
  if (priority >= 3)
1744
- return 'Critical';
1880
+ return "Critical";
1745
1881
  if (priority === 2)
1746
- return 'High';
1882
+ return "High";
1747
1883
  if (priority === 1)
1748
- return 'Medium';
1749
- return 'Low';
1884
+ return "Medium";
1885
+ return "Low";
1750
1886
  };
1751
1887
  const getStatusLabel = (status) => {
1752
1888
  switch (status) {
1753
- case 'proposed':
1754
- return 'Pending';
1755
- case 'executed':
1756
- return 'Executed ✓';
1757
- case 'declined':
1758
- return 'Declined';
1759
- case 'failed':
1760
- return 'Failed ✗';
1889
+ case "proposed":
1890
+ return "Pending";
1891
+ case "executed":
1892
+ return "Executed ✓";
1893
+ case "declined":
1894
+ return "Declined";
1895
+ case "failed":
1896
+ return "Failed ✗";
1761
1897
  default:
1762
1898
  return status;
1763
1899
  }
@@ -1777,8 +1913,12 @@ const DirectivesPanel = ({ directives, theme, onDirectiveAction, onUpdate, }) =>
1777
1913
  fontSize: theme.fontSizes.lg,
1778
1914
  color: theme.colors.text,
1779
1915
  } }, "Directives"),
1780
- React.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: theme.spacing.md } }, directives.map((directive) => {
1781
- const isDisabled = directive.status !== 'proposed' ||
1916
+ React.createElement("div", { style: {
1917
+ display: "flex",
1918
+ flexDirection: "column",
1919
+ gap: theme.spacing.md,
1920
+ } }, directives.map((directive) => {
1921
+ const isDisabled = directive.status !== "proposed" ||
1782
1922
  isProcessing ||
1783
1923
  processingId === directive.directiveId;
1784
1924
  return (React.createElement("div", { key: directive.directiveId, style: {
@@ -1788,32 +1928,32 @@ const DirectivesPanel = ({ directives, theme, onDirectiveAction, onUpdate, }) =>
1788
1928
  border: `1px solid ${theme.colors.border}`,
1789
1929
  } },
1790
1930
  React.createElement("div", { style: {
1791
- display: 'flex',
1792
- justifyContent: 'space-between',
1793
- alignItems: 'center',
1931
+ display: "flex",
1932
+ justifyContent: "space-between",
1933
+ alignItems: "center",
1794
1934
  marginBottom: theme.spacing.sm,
1795
1935
  } },
1796
1936
  React.createElement("span", { style: {
1797
1937
  fontSize: theme.fontSizes.xs,
1798
- padding: '2px 8px',
1799
- borderRadius: '12px',
1938
+ padding: "2px 8px",
1939
+ borderRadius: "12px",
1800
1940
  backgroundColor: getPriorityColor(directive.priority),
1801
- color: '#fff',
1802
- textTransform: 'uppercase',
1941
+ color: "#fff",
1942
+ textTransform: "uppercase",
1803
1943
  } }, getPriorityLabel(directive.priority)),
1804
1944
  React.createElement("span", { style: {
1805
1945
  fontSize: theme.fontSizes.xs,
1806
- padding: '2px 8px',
1807
- borderRadius: '12px',
1946
+ padding: "2px 8px",
1947
+ borderRadius: "12px",
1808
1948
  backgroundColor: theme.colors.textSecondary,
1809
- color: '#fff',
1949
+ color: "#fff",
1810
1950
  } }, getStatusLabel(directive.status))),
1811
1951
  React.createElement("div", { style: {
1812
1952
  fontSize: theme.fontSizes.lg,
1813
- fontWeight: 'bold',
1953
+ fontWeight: "bold",
1814
1954
  color: theme.colors.text,
1815
1955
  marginBottom: theme.spacing.xs,
1816
- } }, directive.action.replace(/_/g, ' ').toUpperCase()),
1956
+ } }, directive.action.replace(/_/g, " ").toUpperCase()),
1817
1957
  directive.targets.length > 0 && (React.createElement("div", { style: {
1818
1958
  fontSize: theme.fontSizes.sm,
1819
1959
  color: theme.colors.textSecondary,
@@ -1821,7 +1961,7 @@ const DirectivesPanel = ({ directives, theme, onDirectiveAction, onUpdate, }) =>
1821
1961
  } },
1822
1962
  React.createElement("strong", null, "Targets:"),
1823
1963
  " ",
1824
- directive.targets.join(', '))),
1964
+ directive.targets.join(", "))),
1825
1965
  directive.parameters.length > 0 && (React.createElement("div", { style: {
1826
1966
  marginBottom: theme.spacing.sm,
1827
1967
  padding: theme.spacing.sm,
@@ -1830,7 +1970,7 @@ const DirectivesPanel = ({ directives, theme, onDirectiveAction, onUpdate, }) =>
1830
1970
  } }, directive.parameters.map((param, index) => (React.createElement("div", { key: index, style: {
1831
1971
  fontSize: theme.fontSizes.sm,
1832
1972
  color: theme.colors.text,
1833
- marginBottom: '4px',
1973
+ marginBottom: "4px",
1834
1974
  } },
1835
1975
  React.createElement("strong", null,
1836
1976
  param.name,
@@ -1844,35 +1984,37 @@ const DirectivesPanel = ({ directives, theme, onDirectiveAction, onUpdate, }) =>
1844
1984
  fontSize: theme.fontSizes.sm,
1845
1985
  color: theme.colors.textSecondary,
1846
1986
  marginBottom: theme.spacing.md,
1847
- lineHeight: '1.5',
1987
+ lineHeight: "1.5",
1848
1988
  } }, directive.rationale),
1849
- directive.status === 'proposed' && (React.createElement("div", { style: { display: 'flex', gap: theme.spacing.sm } },
1850
- React.createElement("button", { onClick: () => handleDirectiveAction(directive, 'execute'), disabled: isDisabled, style: {
1989
+ directive.status === "proposed" && (React.createElement("div", { style: { display: "flex", gap: theme.spacing.sm } },
1990
+ React.createElement("button", { onClick: () => handleDirectiveAction(directive, "execute"), disabled: isDisabled, style: {
1851
1991
  flex: 1,
1852
1992
  padding: theme.spacing.sm,
1853
1993
  backgroundColor: isDisabled
1854
1994
  ? theme.colors.textSecondary
1855
1995
  : theme.colors.success,
1856
- color: '#fff',
1857
- border: 'none',
1996
+ color: "#fff",
1997
+ border: "none",
1858
1998
  borderRadius: theme.borderRadius,
1859
- cursor: isDisabled ? 'not-allowed' : 'pointer',
1999
+ cursor: isDisabled ? "not-allowed" : "pointer",
1860
2000
  fontSize: theme.fontSizes.sm,
1861
- fontWeight: 'bold',
2001
+ fontWeight: "bold",
1862
2002
  opacity: isDisabled ? 0.6 : 1,
1863
- } }, processingId === directive.directiveId ? 'Processing...' : 'Execute'),
1864
- React.createElement("button", { onClick: () => handleDirectiveAction(directive, 'decline'), disabled: isDisabled, style: {
2003
+ } }, processingId === directive.directiveId
2004
+ ? "Processing..."
2005
+ : "Execute"),
2006
+ React.createElement("button", { onClick: () => handleDirectiveAction(directive, "decline"), disabled: isDisabled, style: {
1865
2007
  flex: 1,
1866
2008
  padding: theme.spacing.sm,
1867
2009
  backgroundColor: isDisabled
1868
2010
  ? theme.colors.textSecondary
1869
2011
  : theme.colors.error,
1870
- color: '#fff',
1871
- border: 'none',
2012
+ color: "#fff",
2013
+ border: "none",
1872
2014
  borderRadius: theme.borderRadius,
1873
- cursor: isDisabled ? 'not-allowed' : 'pointer',
2015
+ cursor: isDisabled ? "not-allowed" : "pointer",
1874
2016
  fontSize: theme.fontSizes.sm,
1875
- fontWeight: 'bold',
2017
+ fontWeight: "bold",
1876
2018
  opacity: isDisabled ? 0.6 : 1,
1877
2019
  } }, "Decline")))));
1878
2020
  }))));
@@ -1898,53 +2040,57 @@ const AnalyticsReport = ({ analyticsType, theme: customTheme, onDirectiveAction,
1898
2040
  // Use a default theme if none provided
1899
2041
  const theme = customTheme || {
1900
2042
  colors: {
1901
- background: '#ffffff',
1902
- surface: '#f5f5f5',
1903
- text: '#333333',
1904
- textSecondary: '#666666',
1905
- border: '#e0e0e0',
1906
- primary: '#007bff',
1907
- success: '#28a745',
1908
- error: '#dc3545',
1909
- secondary: '#6c757d',
2043
+ background: "#ffffff",
2044
+ surface: "#f5f5f5",
2045
+ text: "#333333",
2046
+ textSecondary: "#666666",
2047
+ border: "#e0e0e0",
2048
+ primary: "#007bff",
2049
+ success: "#28a745",
2050
+ error: "#dc3545",
2051
+ secondary: "#6c757d",
1910
2052
  },
1911
2053
  spacing: {
1912
- xs: '4px',
1913
- sm: '8px',
1914
- md: '16px',
1915
- lg: '24px',
1916
- xl: '32px',
2054
+ xs: "4px",
2055
+ sm: "8px",
2056
+ md: "16px",
2057
+ lg: "24px",
2058
+ xl: "32px",
1917
2059
  },
1918
2060
  fontSizes: {
1919
- xs: '12px',
1920
- sm: '14px',
1921
- md: '16px',
1922
- lg: '20px',
1923
- xl: '24px',
2061
+ xs: "12px",
2062
+ sm: "14px",
2063
+ md: "16px",
2064
+ lg: "20px",
2065
+ xl: "24px",
1924
2066
  },
1925
- borderRadius: '8px',
1926
- boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
1927
- name: 'default',
2067
+ borderRadius: "8px",
2068
+ boxShadow: "0 2px 8px rgba(0,0,0,0.1)",
2069
+ name: "default",
1928
2070
  };
1929
2071
  return (React.createElement("div", { style: {
1930
- height: '100%',
1931
- display: 'flex',
1932
- flexDirection: 'column',
2072
+ height: "100%",
2073
+ display: "flex",
2074
+ flexDirection: "column",
1933
2075
  backgroundColor: theme.colors.background,
1934
2076
  } },
1935
2077
  React.createElement("div", { style: {
1936
2078
  padding: theme.spacing.lg,
1937
2079
  borderBottom: `1px solid ${theme.colors.border}`,
1938
- display: 'flex',
1939
- justifyContent: 'space-between',
1940
- alignItems: 'center',
2080
+ display: "flex",
2081
+ justifyContent: "space-between",
2082
+ alignItems: "center",
1941
2083
  } },
1942
- React.createElement("div", { style: { display: 'flex', alignItems: 'center', gap: theme.spacing.sm } },
2084
+ React.createElement("div", { style: {
2085
+ display: "flex",
2086
+ alignItems: "center",
2087
+ gap: theme.spacing.sm,
2088
+ } },
1943
2089
  onBack && (React.createElement("button", { onClick: onBack, style: {
1944
- background: 'none',
1945
- border: 'none',
1946
- cursor: 'pointer',
1947
- fontSize: '24px',
2090
+ background: "none",
2091
+ border: "none",
2092
+ cursor: "pointer",
2093
+ fontSize: "24px",
1948
2094
  color: theme.colors.text,
1949
2095
  padding: 0,
1950
2096
  } }, BACK_ICON_SVG)),
@@ -1957,33 +2103,33 @@ const AnalyticsReport = ({ analyticsType, theme: customTheme, onDirectiveAction,
1957
2103
  result && (React.createElement("div", { style: {
1958
2104
  fontSize: theme.fontSizes.xs,
1959
2105
  color: theme.colors.textSecondary,
1960
- marginTop: '4px',
2106
+ marginTop: "4px",
1961
2107
  } },
1962
2108
  "Last updated: ",
1963
2109
  new Date(result.createdAt).toLocaleString())))),
1964
- React.createElement("div", { style: { display: 'flex', gap: theme.spacing.sm } },
2110
+ React.createElement("div", { style: { display: "flex", gap: theme.spacing.sm } },
1965
2111
  React.createElement("button", { onClick: handleRefresh, disabled: isLoading, style: {
1966
- background: 'none',
1967
- border: 'none',
1968
- cursor: isLoading ? 'not-allowed' : 'pointer',
1969
- fontSize: '24px',
2112
+ background: "none",
2113
+ border: "none",
2114
+ cursor: isLoading ? "not-allowed" : "pointer",
2115
+ fontSize: "24px",
1970
2116
  color: theme.colors.text,
1971
2117
  padding: 0,
1972
2118
  opacity: isLoading ? 0.5 : 1,
1973
2119
  } }, REFRESH_ICON_SVG),
1974
2120
  onClose && (React.createElement("button", { onClick: onClose, style: {
1975
- background: 'none',
1976
- border: 'none',
1977
- cursor: 'pointer',
1978
- fontSize: '24px',
2121
+ background: "none",
2122
+ border: "none",
2123
+ cursor: "pointer",
2124
+ fontSize: "24px",
1979
2125
  color: theme.colors.text,
1980
2126
  padding: 0,
1981
2127
  } }, CLOSE_ICON_SVG$1)))),
1982
2128
  React.createElement("div", { style: {
1983
2129
  flex: 1,
1984
- overflowY: 'auto',
2130
+ overflowY: "auto",
1985
2131
  padding: theme.spacing.lg,
1986
- } }, isLoading ? (React.createElement("div", { style: { textAlign: 'center', color: theme.colors.textSecondary } }, "Loading analytics result...")) : error ? (React.createElement("div", { style: {
2132
+ } }, isLoading ? (React.createElement("div", { style: { textAlign: "center", color: theme.colors.textSecondary } }, "Loading analytics result...")) : error ? (React.createElement("div", { style: {
1987
2133
  padding: theme.spacing.md,
1988
2134
  backgroundColor: theme.colors.surface,
1989
2135
  borderRadius: theme.borderRadius,
@@ -1991,10 +2137,14 @@ const AnalyticsReport = ({ analyticsType, theme: customTheme, onDirectiveAction,
1991
2137
  color: theme.colors.error,
1992
2138
  } },
1993
2139
  "Error: ",
1994
- error.message)) : result ? (React.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: theme.spacing.xl } },
2140
+ error.message)) : result ? (React.createElement("div", { style: {
2141
+ display: "flex",
2142
+ flexDirection: "column",
2143
+ gap: theme.spacing.xl,
2144
+ } },
1995
2145
  result.metrics.length > 0 && (React.createElement(MetricsPanel, { metrics: result.metrics, theme: theme })),
1996
2146
  result.observations.length > 0 && (React.createElement(ObservationsPanel, { observations: result.observations, theme: theme })),
1997
- result.directives.length > 0 && (React.createElement(DirectivesPanel, { directives: result.directives, theme: theme, onDirectiveAction: onDirectiveAction, onUpdate: refetch })))) : (React.createElement("div", { style: { textAlign: 'center', color: theme.colors.textSecondary } }, "No results available")))));
2147
+ result.directives.length > 0 && (React.createElement(DirectivesPanel, { directives: result.directives, theme: theme, onDirectiveAction: onDirectiveAction, onUpdate: refetch })))) : (React.createElement("div", { style: { textAlign: "center", color: theme.colors.textSecondary } }, "No results available")))));
1998
2148
  };
1999
2149
 
2000
2150
  // Close Icon SVG
@@ -2003,32 +2153,32 @@ const CLOSE_ICON_SVG = (React.createElement("svg", { xmlns: "http://www.w3.org/2
2003
2153
  const AnalyticsDrawer = ({ isOpen, onClose, configs, isLoading, theme, onDirectiveAction, }) => {
2004
2154
  const [selectedAnalytics, setSelectedAnalytics] = React.useState(null);
2005
2155
  // Check if mobile
2006
- const isMobile = typeof window !== 'undefined' && window.innerWidth < 768;
2156
+ const isMobile = typeof window !== "undefined" && window.innerWidth < 768;
2007
2157
  const drawerStyles = {
2008
- position: 'fixed',
2158
+ position: "fixed",
2009
2159
  top: 0,
2010
2160
  right: 0,
2011
- width: isMobile ? '100%' : '400px',
2012
- height: '100%',
2161
+ width: isMobile ? "100%" : "400px",
2162
+ height: "100%",
2013
2163
  backgroundColor: theme.colors.background,
2014
2164
  boxShadow: theme.boxShadow,
2015
2165
  zIndex: 1001,
2016
- display: 'flex',
2017
- flexDirection: 'column',
2018
- transform: isOpen ? 'translateX(0)' : 'translateX(100%)',
2019
- transition: 'transform 0.3s ease',
2166
+ display: "flex",
2167
+ flexDirection: "column",
2168
+ transform: isOpen ? "translateX(0)" : "translateX(100%)",
2169
+ transition: "transform 0.3s ease",
2020
2170
  };
2021
2171
  const overlayStyles = {
2022
- position: 'fixed',
2172
+ position: "fixed",
2023
2173
  top: 0,
2024
2174
  left: 0,
2025
- width: '100%',
2026
- height: '100%',
2027
- backgroundColor: 'rgba(0, 0, 0, 0.5)',
2175
+ width: "100%",
2176
+ height: "100%",
2177
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
2028
2178
  zIndex: 1000,
2029
2179
  opacity: isOpen ? 1 : 0,
2030
- pointerEvents: isOpen ? 'auto' : 'none',
2031
- transition: 'opacity 0.3s ease',
2180
+ pointerEvents: isOpen ? "auto" : "none",
2181
+ transition: "opacity 0.3s ease",
2032
2182
  };
2033
2183
  if (selectedAnalytics) {
2034
2184
  return (React.createElement(React.Fragment, null,
@@ -2042,9 +2192,9 @@ const AnalyticsDrawer = ({ isOpen, onClose, configs, isLoading, theme, onDirecti
2042
2192
  React.createElement("div", { style: {
2043
2193
  padding: theme.spacing.lg,
2044
2194
  borderBottom: `1px solid ${theme.colors.border}`,
2045
- display: 'flex',
2046
- justifyContent: 'space-between',
2047
- alignItems: 'center',
2195
+ display: "flex",
2196
+ justifyContent: "space-between",
2197
+ alignItems: "center",
2048
2198
  } },
2049
2199
  React.createElement("h2", { style: {
2050
2200
  margin: 0,
@@ -2052,36 +2202,41 @@ const AnalyticsDrawer = ({ isOpen, onClose, configs, isLoading, theme, onDirecti
2052
2202
  color: theme.colors.text,
2053
2203
  } }, "Analytics"),
2054
2204
  React.createElement("button", { onClick: onClose, style: {
2055
- background: 'none',
2056
- border: 'none',
2057
- cursor: 'pointer',
2058
- fontSize: '24px',
2205
+ background: "none",
2206
+ border: "none",
2207
+ cursor: "pointer",
2208
+ fontSize: "24px",
2059
2209
  color: theme.colors.text,
2060
2210
  padding: 0,
2061
2211
  } }, CLOSE_ICON_SVG)),
2062
2212
  React.createElement("div", { style: {
2063
2213
  flex: 1,
2064
- overflowY: 'auto',
2214
+ overflowY: "auto",
2065
2215
  padding: theme.spacing.lg,
2066
- } }, isLoading ? (React.createElement("div", { style: { textAlign: 'center', color: theme.colors.textSecondary } }, "Loading analytics...")) : configs.length === 0 ? (React.createElement("div", { style: { textAlign: 'center', color: theme.colors.textSecondary } }, "No analytics configured")) : (React.createElement("div", { style: { display: 'flex', flexDirection: 'column', gap: theme.spacing.md } }, configs.map((config) => (React.createElement("div", { key: config.configId, onClick: () => config.isEnabled && setSelectedAnalytics(config.analyticsType), style: {
2216
+ } }, isLoading ? (React.createElement("div", { style: { textAlign: "center", color: theme.colors.textSecondary } }, "Loading analytics...")) : configs.length === 0 ? (React.createElement("div", { style: { textAlign: "center", color: theme.colors.textSecondary } }, "No analytics configured")) : (React.createElement("div", { style: {
2217
+ display: "flex",
2218
+ flexDirection: "column",
2219
+ gap: theme.spacing.md,
2220
+ } }, configs.map((config) => (React.createElement("div", { key: config.configId, onClick: () => config.isEnabled &&
2221
+ setSelectedAnalytics(config.analyticsType), style: {
2067
2222
  padding: theme.spacing.md,
2068
2223
  backgroundColor: theme.colors.surface,
2069
2224
  borderRadius: theme.borderRadius,
2070
2225
  border: `1px solid ${theme.colors.border}`,
2071
- cursor: config.isEnabled ? 'pointer' : 'not-allowed',
2226
+ cursor: config.isEnabled ? "pointer" : "not-allowed",
2072
2227
  opacity: config.isEnabled ? 1 : 0.6,
2073
- transition: 'transform 0.2s ease',
2228
+ transition: "transform 0.2s ease",
2074
2229
  }, onMouseEnter: (e) => {
2075
2230
  if (config.isEnabled) {
2076
- e.currentTarget.style.transform = 'translateX(5px)';
2231
+ e.currentTarget.style.transform = "translateX(5px)";
2077
2232
  }
2078
2233
  }, onMouseLeave: (e) => {
2079
- e.currentTarget.style.transform = 'translateX(0)';
2234
+ e.currentTarget.style.transform = "translateX(0)";
2080
2235
  } },
2081
2236
  React.createElement("div", { style: {
2082
- display: 'flex',
2083
- justifyContent: 'space-between',
2084
- alignItems: 'center',
2237
+ display: "flex",
2238
+ justifyContent: "space-between",
2239
+ alignItems: "center",
2085
2240
  marginBottom: theme.spacing.xs,
2086
2241
  } },
2087
2242
  React.createElement("h3", { style: {
@@ -2091,13 +2246,13 @@ const AnalyticsDrawer = ({ isOpen, onClose, configs, isLoading, theme, onDirecti
2091
2246
  } }, config.analyticsType),
2092
2247
  React.createElement("span", { style: {
2093
2248
  fontSize: theme.fontSizes.xs,
2094
- padding: '2px 8px',
2095
- borderRadius: '12px',
2249
+ padding: "2px 8px",
2250
+ borderRadius: "12px",
2096
2251
  backgroundColor: config.isEnabled
2097
2252
  ? theme.colors.success
2098
2253
  : theme.colors.textSecondary,
2099
- color: '#fff',
2100
- } }, config.isEnabled ? 'Enabled' : 'Disabled')),
2254
+ color: "#fff",
2255
+ } }, config.isEnabled ? "Enabled" : "Disabled")),
2101
2256
  React.createElement("p", { style: {
2102
2257
  margin: 0,
2103
2258
  fontSize: theme.fontSizes.sm,
@@ -2112,43 +2267,44 @@ const AnalyticsDrawer = ({ isOpen, onClose, configs, isLoading, theme, onDirecti
2112
2267
  "Frequency: ",
2113
2268
  config.frequency),
2114
2269
  config.lastExecutedAt && (React.createElement("div", null,
2115
- "Last run: ",
2270
+ "Last run:",
2271
+ " ",
2116
2272
  new Date(config.lastExecutedAt).toLocaleString()))))))))))));
2117
2273
  };
2118
2274
 
2119
2275
  // Analytics Icon SVG
2120
2276
  const ANALYTICS_ICON_SVG = (React.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", width: "1em", height: "1em", fill: "currentColor" },
2121
2277
  React.createElement("path", { d: "M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z" })));
2122
- const AnalyticsWidget = ({ position = 'bottom-right', theme: customTheme, onDirectiveAction, }) => {
2278
+ const AnalyticsWidget = ({ position = "bottom-right", theme: customTheme, onDirectiveAction, }) => {
2123
2279
  const { theme: contextTheme } = useReactBridgeContext();
2124
2280
  const theme = customTheme || contextTheme;
2125
2281
  const { configs, isLoading } = useAnalyticsConfigs();
2126
2282
  const [isOpen, setIsOpen] = React.useState(false);
2127
2283
  const enabledCount = configs.filter((c) => c.isEnabled).length;
2128
- const positionStyles = position === 'bottom-right'
2284
+ const positionStyles = position === "bottom-right"
2129
2285
  ? { right: theme.spacing.lg, bottom: theme.spacing.lg }
2130
2286
  : { left: theme.spacing.lg, bottom: theme.spacing.lg };
2131
2287
  return (React.createElement(React.Fragment, null,
2132
- React.createElement("button", { onClick: () => setIsOpen(!isOpen), style: Object.assign(Object.assign({ position: 'fixed' }, positionStyles), { width: '60px', height: '60px', borderRadius: '50%', backgroundColor: theme.colors.primary, color: '#fff', border: 'none', boxShadow: theme.boxShadow, cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '24px', zIndex: 1000, transition: 'transform 0.2s ease' }), onMouseEnter: (e) => {
2133
- e.currentTarget.style.transform = 'scale(1.1)';
2288
+ React.createElement("button", { onClick: () => setIsOpen(!isOpen), style: Object.assign(Object.assign({ position: "fixed" }, positionStyles), { width: "60px", height: "60px", borderRadius: "50%", backgroundColor: theme.colors.primary, color: "#fff", border: "none", boxShadow: theme.boxShadow, cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", fontSize: "24px", zIndex: 1000, transition: "transform 0.2s ease" }), onMouseEnter: (e) => {
2289
+ e.currentTarget.style.transform = "scale(1.1)";
2134
2290
  }, onMouseLeave: (e) => {
2135
- e.currentTarget.style.transform = 'scale(1)';
2291
+ e.currentTarget.style.transform = "scale(1)";
2136
2292
  } },
2137
2293
  ANALYTICS_ICON_SVG,
2138
2294
  !isLoading && enabledCount > 0 && (React.createElement("span", { style: {
2139
- position: 'absolute',
2140
- top: '-5px',
2141
- right: '-5px',
2295
+ position: "absolute",
2296
+ top: "-5px",
2297
+ right: "-5px",
2142
2298
  backgroundColor: theme.colors.error,
2143
- color: '#fff',
2144
- borderRadius: '50%',
2145
- width: '24px',
2146
- height: '24px',
2147
- display: 'flex',
2148
- alignItems: 'center',
2149
- justifyContent: 'center',
2150
- fontSize: '12px',
2151
- fontWeight: 'bold',
2299
+ color: "#fff",
2300
+ borderRadius: "50%",
2301
+ width: "24px",
2302
+ height: "24px",
2303
+ display: "flex",
2304
+ alignItems: "center",
2305
+ justifyContent: "center",
2306
+ fontSize: "12px",
2307
+ fontWeight: "bold",
2152
2308
  } }, enabledCount))),
2153
2309
  isOpen && (React.createElement(AnalyticsDrawer, { isOpen: isOpen, onClose: () => setIsOpen(false), configs: configs, isLoading: isLoading, theme: theme, onDirectiveAction: onDirectiveAction }))));
2154
2310
  };
@@ -2518,7 +2674,7 @@ function AnalyticsDashboard({ onDirectiveAction, className = "", showRefresh = t
2518
2674
  "Declined (",
2519
2675
  declinedCount,
2520
2676
  ")")),
2521
- directiveTypes.length > 1 && (React.createElement("select", { value: directiveType, onChange: e => setDirectiveType(e.target.value), style: {
2677
+ directiveTypes.length > 1 && (React.createElement("select", { value: directiveType, onChange: (e) => setDirectiveType(e.target.value), style: {
2522
2678
  padding: `${theme.spacing.xs} ${theme.spacing.sm}`,
2523
2679
  borderRadius: theme.borderRadius,
2524
2680
  border: `1px solid ${theme.colors.border}`,
@@ -2532,7 +2688,7 @@ function AnalyticsDashboard({ onDirectiveAction, className = "", showRefresh = t
2532
2688
  cursor: "pointer",
2533
2689
  } },
2534
2690
  React.createElement("option", { value: "all" }, "All types"),
2535
- directiveTypes.map(type => (React.createElement("option", { key: type, value: type }, type)))))),
2691
+ directiveTypes.map((type) => (React.createElement("option", { key: type, value: type }, type)))))),
2536
2692
  filteredDirectives.length === 0 && (React.createElement("div", { style: placeholderStyle }, "No directives match the selected filter.")),
2537
2693
  React.createElement("div", { style: {
2538
2694
  display: "flex",
@@ -2577,29 +2733,1839 @@ function AnalyticsDashboard({ onDirectiveAction, className = "", showRefresh = t
2577
2733
  ": ",
2578
2734
  param.value)))))),
2579
2735
  directive.status === "proposed" && (React.createElement("div", { style: { display: "flex", gap: theme.spacing.sm } },
2580
- 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
2736
+ React.createElement("button", { type: "button", onClick: () => handleDirectiveAction(directive, "execute"), disabled: isProcessing &&
2737
+ processingId === directive.directiveId, style: Object.assign(Object.assign({}, pillStyle(theme.colors.success)), { border: "none", cursor: isProcessing &&
2738
+ processingId === directive.directiveId
2581
2739
  ? "not-allowed"
2582
- : "pointer" }) }, isProcessing && processingId === directive.directiveId
2740
+ : "pointer" }) }, isProcessing &&
2741
+ processingId === directive.directiveId
2583
2742
  ? "Processing..."
2584
2743
  : "Execute"),
2585
- 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
2744
+ React.createElement("button", { type: "button", onClick: () => handleDirectiveAction(directive, "decline"), disabled: isProcessing &&
2745
+ processingId === directive.directiveId, style: Object.assign(Object.assign({}, pillStyle(theme.colors.error)), { border: "none", cursor: isProcessing &&
2746
+ processingId === directive.directiveId
2586
2747
  ? "not-allowed"
2587
- : "pointer" }) }, isProcessing && processingId === directive.directiveId
2748
+ : "pointer" }) }, isProcessing &&
2749
+ processingId === directive.directiveId
2588
2750
  ? "Processing..."
2589
2751
  : "Decline"))))))))))))));
2590
2752
  }
2591
2753
 
2754
+ /**
2755
+ * Request Cache Manager
2756
+ * Implements a simple caching mechanism similar to react-query
2757
+ * Prevents duplicate concurrent requests and caches results
2758
+ */
2759
+ const DEFAULT_TTL = 5 * 60 * 1000; // 5 minutes
2760
+ class RequestCache {
2761
+ constructor() {
2762
+ this.cache = new Map();
2763
+ this.pendingRequests = new Map();
2764
+ }
2765
+ /**
2766
+ * Generate a cache key from function and parameters
2767
+ */
2768
+ getCacheKey(fetchFn, params) {
2769
+ const fnString = fetchFn.toString();
2770
+ const paramString = params ? JSON.stringify(params) : '';
2771
+ return `${fnString}::${paramString}`;
2772
+ }
2773
+ /**
2774
+ * Check if cache entry is still valid
2775
+ */
2776
+ isCacheValid(entry) {
2777
+ return Date.now() - entry.timestamp < entry.ttl;
2778
+ }
2779
+ /**
2780
+ * Fetch or return cached data
2781
+ */
2782
+ get(fetchFn_1, params_1) {
2783
+ return __awaiter(this, arguments, void 0, function* (fetchFn, params, ttl = DEFAULT_TTL) {
2784
+ const key = this.getCacheKey(fetchFn, params);
2785
+ // Return valid cached data
2786
+ const cached = this.cache.get(key);
2787
+ if (cached && this.isCacheValid(cached)) {
2788
+ return cached.data;
2789
+ }
2790
+ // Return pending request if already in flight
2791
+ const pending = this.pendingRequests.get(key);
2792
+ if (pending) {
2793
+ return pending.promise;
2794
+ }
2795
+ // Create new request
2796
+ const promise = fetchFn().then((data) => {
2797
+ this.cache.set(key, {
2798
+ data,
2799
+ timestamp: Date.now(),
2800
+ ttl,
2801
+ });
2802
+ this.pendingRequests.delete(key);
2803
+ return data;
2804
+ }).catch((error) => {
2805
+ this.pendingRequests.delete(key);
2806
+ throw error;
2807
+ });
2808
+ this.pendingRequests.set(key, { promise });
2809
+ return promise;
2810
+ });
2811
+ }
2812
+ /**
2813
+ * Invalidate cache entry
2814
+ */
2815
+ invalidate(fetchFn, params) {
2816
+ const key = this.getCacheKey(fetchFn, params);
2817
+ this.cache.delete(key);
2818
+ }
2819
+ /**
2820
+ * Clear all cache
2821
+ */
2822
+ clear() {
2823
+ this.cache.clear();
2824
+ this.pendingRequests.clear();
2825
+ }
2826
+ }
2827
+ // Singleton instance
2828
+ const requestCache = new RequestCache();
2829
+
2830
+ /**
2831
+ * useReportData Hook
2832
+ * Fetches and manages report data with error handling
2833
+ * Implements caching to prevent duplicate requests
2834
+ */
2835
+ /**
2836
+ * Generic hook for fetching report data
2837
+ * Implements caching and deduplication to prevent infinite requests
2838
+ * @param fetchFn - Async function to fetch report data
2839
+ * @param dependencies - Dependencies that trigger refetch when changed
2840
+ * @param options - Hook options (enabled flag, cache TTL)
2841
+ */
2842
+ function useReportData(fetchFn, dependencies = [], options = {}) {
2843
+ const [data, setData] = React.useState(null);
2844
+ const [loading, setLoading] = React.useState(true);
2845
+ const [error, setError] = React.useState(null);
2846
+ const isMountedRef = React.useRef(true);
2847
+ const { enabled = true, ttl = 5 * 60 * 1000 } = options;
2848
+ // Create a stable string representation of dependencies for comparison
2849
+ const depsString = JSON.stringify(dependencies);
2850
+ React.useEffect(() => {
2851
+ isMountedRef.current = true;
2852
+ if (!enabled) {
2853
+ setLoading(false);
2854
+ return;
2855
+ }
2856
+ let cancelled = false;
2857
+ const fetchData = () => __awaiter(this, void 0, void 0, function* () {
2858
+ try {
2859
+ setLoading(true);
2860
+ setError(null);
2861
+ // Use cache to avoid duplicate requests
2862
+ const result = yield requestCache.get(fetchFn, depsString, ttl);
2863
+ if (!cancelled && isMountedRef.current) {
2864
+ setData(result);
2865
+ }
2866
+ }
2867
+ catch (err) {
2868
+ if (!cancelled && isMountedRef.current) {
2869
+ const error = err instanceof Error ? err : new Error("Unknown error occurred");
2870
+ setError(error);
2871
+ setData(null);
2872
+ }
2873
+ }
2874
+ finally {
2875
+ if (!cancelled && isMountedRef.current) {
2876
+ setLoading(false);
2877
+ }
2878
+ }
2879
+ });
2880
+ fetchData();
2881
+ return () => {
2882
+ cancelled = true;
2883
+ };
2884
+ }, [depsString, enabled, ttl, fetchFn]);
2885
+ React.useEffect(() => {
2886
+ return () => {
2887
+ isMountedRef.current = false;
2888
+ };
2889
+ }, []);
2890
+ const refetch = () => __awaiter(this, void 0, void 0, function* () {
2891
+ // Invalidate cache and refetch
2892
+ requestCache.invalidate(fetchFn, depsString);
2893
+ try {
2894
+ setLoading(true);
2895
+ setError(null);
2896
+ const result = yield requestCache.get(fetchFn, depsString, ttl);
2897
+ if (isMountedRef.current) {
2898
+ setData(result);
2899
+ }
2900
+ }
2901
+ catch (err) {
2902
+ if (isMountedRef.current) {
2903
+ const error = err instanceof Error ? err : new Error("Unknown error occurred");
2904
+ setError(error);
2905
+ setData(null);
2906
+ }
2907
+ }
2908
+ finally {
2909
+ if (isMountedRef.current) {
2910
+ setLoading(false);
2911
+ }
2912
+ }
2913
+ });
2914
+ return { data, loading, error, refetch };
2915
+ }
2916
+
2917
+ /**
2918
+ * Date Range Service
2919
+ * Handles date range calculations and options
2920
+ */
2921
+ class DateRangeService {
2922
+ /**
2923
+ * Calculate date range based on predefined options
2924
+ */
2925
+ static getDateRange(option) {
2926
+ const today = new Date();
2927
+ const endDate = today.toISOString().split("T")[0]; // YYYY-MM-DD format
2928
+ let startDate;
2929
+ switch (option) {
2930
+ case "past-week":
2931
+ startDate = new Date(today);
2932
+ startDate.setDate(today.getDate() - 7);
2933
+ break;
2934
+ case "past-month":
2935
+ startDate = new Date(today);
2936
+ startDate.setMonth(today.getMonth() - 1);
2937
+ break;
2938
+ case "past-3-months":
2939
+ startDate = new Date(today);
2940
+ startDate.setMonth(today.getMonth() - 3);
2941
+ break;
2942
+ case "past-6-months":
2943
+ startDate = new Date(today);
2944
+ startDate.setMonth(today.getMonth() - 6);
2945
+ break;
2946
+ case "past-year":
2947
+ startDate = new Date(today);
2948
+ startDate.setFullYear(today.getFullYear() - 1);
2949
+ break;
2950
+ default:
2951
+ startDate = new Date(today);
2952
+ startDate.setMonth(today.getMonth() - 1);
2953
+ }
2954
+ return {
2955
+ label: this.getLabel(option),
2956
+ startDate: startDate.toISOString().split("T")[0],
2957
+ endDate,
2958
+ };
2959
+ }
2960
+ /**
2961
+ * Get human-readable label for date range option
2962
+ */
2963
+ static getLabel(option) {
2964
+ const labels = {
2965
+ "past-week": "Past Week",
2966
+ "past-month": "Past Month",
2967
+ "past-3-months": "Past 3 Months",
2968
+ "past-6-months": "Past 6 Months",
2969
+ "past-year": "Past Year",
2970
+ };
2971
+ return labels[option];
2972
+ }
2973
+ /**
2974
+ * Get all available date range options
2975
+ */
2976
+ static getAllOptions() {
2977
+ return [
2978
+ { value: "past-week", label: "Past Week" },
2979
+ { value: "past-month", label: "Past Month" },
2980
+ { value: "past-3-months", label: "Past 3 Months" },
2981
+ { value: "past-6-months", label: "Past 6 Months" },
2982
+ { value: "past-year", label: "Past Year" },
2983
+ ];
2984
+ }
2985
+ /**
2986
+ * Format date for display (e.g., "Jan 6 - Feb 5")
2987
+ */
2988
+ static formatDateRangeForDisplay(startDate, endDate) {
2989
+ try {
2990
+ const start = new Date(startDate);
2991
+ const end = new Date(endDate);
2992
+ const formatPart = (date) => {
2993
+ const month = date.toLocaleString("default", { month: "short" });
2994
+ const day = date.getDate();
2995
+ return `${month} ${day}`;
2996
+ };
2997
+ return `${formatPart(start)} - ${formatPart(end)}`;
2998
+ }
2999
+ catch (_a) {
3000
+ return `${startDate} - ${endDate}`;
3001
+ }
3002
+ }
3003
+ }
3004
+
3005
+ /**
3006
+ * useDateRange Hook
3007
+ * Manages date range state with predefined options
3008
+ */
3009
+ /**
3010
+ * Hook to manage date range selection for reports
3011
+ * @param defaultOption - Default date range option (default: 'past-month')
3012
+ */
3013
+ function useDateRange(defaultOption = "past-month") {
3014
+ const [selectedOption, setSelectedOption] = React.useState(defaultOption);
3015
+ const dateRange = DateRangeService.getDateRange(selectedOption);
3016
+ return {
3017
+ selectedOption,
3018
+ setSelectedOption,
3019
+ startDate: dateRange.startDate,
3020
+ endDate: dateRange.endDate,
3021
+ label: dateRange.label,
3022
+ };
3023
+ }
3024
+
3025
+ /**
3026
+ * DateRangeSelector Component
3027
+ * Select dropdown for date range selection
3028
+ */
3029
+ const DateRangeSelector = ({ selectedOption, onSelect, theme, }) => {
3030
+ const options = DateRangeService.getAllOptions();
3031
+ return (React.createElement("select", { value: selectedOption, onChange: (e) => onSelect(e.target.value), style: {
3032
+ padding: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "6px"} ${(theme === null || theme === void 0 ? void 0 : theme.spacing.sm) || "10px"}`,
3033
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.sm) || "13px",
3034
+ fontWeight: "500",
3035
+ borderRadius: (theme === null || theme === void 0 ? void 0 : theme.borderRadius) || "6px",
3036
+ border: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#d0d0d0"}`,
3037
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.surface) || "#f9f9f9",
3038
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.text) || "#000",
3039
+ cursor: "pointer",
3040
+ transition: "border-color 0.2s ease, box-shadow 0.2s ease",
3041
+ }, onFocus: (e) => {
3042
+ e.currentTarget.style.borderColor =
3043
+ (theme === null || theme === void 0 ? void 0 : theme.colors.primary) || "#1976d2";
3044
+ e.currentTarget.style.boxShadow = `0 0 0 2px ${((theme === null || theme === void 0 ? void 0 : theme.colors.primary) || "#1976d2") + "20"}`;
3045
+ }, onBlur: (e) => {
3046
+ e.currentTarget.style.borderColor =
3047
+ (theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#d0d0d0";
3048
+ e.currentTarget.style.boxShadow = "none";
3049
+ } }, options.map((option) => (React.createElement("option", { key: option.value, value: option.value }, option.label)))));
3050
+ };
3051
+
3052
+ /**
3053
+ * LoadingState Component
3054
+ * Skeleton loader for reports
3055
+ */
3056
+ const Skeleton = ({ theme }) => (React.createElement("div", { style: {
3057
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0",
3058
+ borderRadius: (theme === null || theme === void 0 ? void 0 : theme.borderRadius) || "8px",
3059
+ height: "16px",
3060
+ marginBottom: (theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px",
3061
+ animation: "pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite",
3062
+ } }));
3063
+ const LoadingState = ({ theme, variant = "minimal", }) => {
3064
+ if (variant === "minimal") {
3065
+ return (React.createElement("div", { style: {
3066
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.lg) || "24px",
3067
+ textAlign: "center",
3068
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666",
3069
+ } },
3070
+ React.createElement("div", { style: {
3071
+ display: "inline-block",
3072
+ width: "40px",
3073
+ height: "40px",
3074
+ border: `3px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
3075
+ borderTop: `3px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.primary) || "#1976d2"}`,
3076
+ borderRadius: "50%",
3077
+ animation: "spin 0.6s linear infinite",
3078
+ } }),
3079
+ React.createElement("p", { style: { marginTop: (theme === null || theme === void 0 ? void 0 : theme.spacing.sm) || "8px" } }, "Loading report...")));
3080
+ }
3081
+ if (variant === "cards") {
3082
+ return (React.createElement("div", { style: {
3083
+ display: "grid",
3084
+ gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))",
3085
+ gap: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px",
3086
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px",
3087
+ } }, [1, 2, 3, 4].map((i) => (React.createElement("div", { key: i, style: {
3088
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px",
3089
+ border: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
3090
+ borderRadius: (theme === null || theme === void 0 ? void 0 : theme.borderRadius) || "8px",
3091
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.surface) || "#f5f5f5",
3092
+ } },
3093
+ React.createElement(Skeleton, { theme: theme }),
3094
+ React.createElement(Skeleton, { theme: theme }),
3095
+ React.createElement(Skeleton, { theme: theme }))))));
3096
+ }
3097
+ return (React.createElement("div", { style: {
3098
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px",
3099
+ border: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
3100
+ borderRadius: (theme === null || theme === void 0 ? void 0 : theme.borderRadius) || "8px",
3101
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.surface) || "#f5f5f5",
3102
+ } }, [1, 2, 3, 4, 5].map((i) => (React.createElement("div", { key: i, style: { marginBottom: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px" } },
3103
+ React.createElement(Skeleton, { theme: theme }),
3104
+ React.createElement(Skeleton, { theme: theme }))))));
3105
+ };
3106
+
3107
+ /**
3108
+ * ReportLayout Component
3109
+ * Wrapper for report pages with header and date range selector
3110
+ */
3111
+ const ReportLayout = ({ title, description, selectedDateRange, onDateRangeChange, loading, error, children, theme: themeProp, }) => {
3112
+ const { theme: contextTheme } = useReactBridgeContext();
3113
+ const theme = themeProp || contextTheme;
3114
+ return (React.createElement("div", { style: {
3115
+ display: "flex",
3116
+ flexDirection: "column",
3117
+ gap: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "12px",
3118
+ } },
3119
+ React.createElement("div", { style: {
3120
+ display: "flex",
3121
+ alignItems: "flex-start",
3122
+ justifyContent: "space-between",
3123
+ gap: (theme === null || theme === void 0 ? void 0 : theme.spacing.sm) || "12px",
3124
+ flexWrap: "wrap",
3125
+ } },
3126
+ React.createElement("div", { style: { flex: 1, minWidth: "200px" } },
3127
+ React.createElement("h1", { style: {
3128
+ margin: 0,
3129
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.lg) || "20px",
3130
+ fontWeight: "700",
3131
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.text) || "#000",
3132
+ } }, title),
3133
+ description && (React.createElement("p", { style: {
3134
+ margin: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px"} 0 0 0`,
3135
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.sm) || "12px",
3136
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666",
3137
+ } }, description))),
3138
+ React.createElement(DateRangeSelector, { selectedOption: selectedDateRange, onSelect: onDateRangeChange, theme: theme })),
3139
+ loading ? (React.createElement(LoadingState, { theme: theme })) : error ? (React.createElement("div", { style: {
3140
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.sm) || "12px",
3141
+ borderRadius: (theme === null || theme === void 0 ? void 0 : theme.borderRadius) || "6px",
3142
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.error)
3143
+ ? `${theme.colors.error}15`
3144
+ : "#FEE2E2",
3145
+ border: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.error) || "#f44336"}`,
3146
+ } },
3147
+ React.createElement("p", { style: {
3148
+ margin: 0,
3149
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.sm) || "12px",
3150
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.error) || "#f44336",
3151
+ fontWeight: "500",
3152
+ } },
3153
+ "Error loading report: ",
3154
+ error.message))) : (children)));
3155
+ };
3156
+
3157
+ /**
3158
+ * MetricCard Component
3159
+ * Displays a single KPI metric with optional trend indicator
3160
+ */
3161
+ const MetricCard = ({ label, value, unit, trend, trendValue, icon, onClick, theme, }) => {
3162
+ const getTrendColor = () => {
3163
+ if (!theme)
3164
+ return "inherit";
3165
+ if (trend === "up")
3166
+ return theme.colors.success;
3167
+ if (trend === "down")
3168
+ return theme.colors.error;
3169
+ return theme.colors.textSecondary;
3170
+ };
3171
+ const getTrendIcon = () => {
3172
+ if (trend === "up")
3173
+ return "↑";
3174
+ if (trend === "down")
3175
+ return "↓";
3176
+ return "→";
3177
+ };
3178
+ const containerStyles = {
3179
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.sm) || "10px",
3180
+ borderRadius: (theme === null || theme === void 0 ? void 0 : theme.borderRadius) || "6px",
3181
+ border: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
3182
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.surface) || "#f5f5f5",
3183
+ cursor: onClick ? "pointer" : "default",
3184
+ transition: "all 0.2s ease",
3185
+ };
3186
+ return (React.createElement("div", { style: containerStyles, onClick: onClick, onMouseEnter: (e) => {
3187
+ if (onClick) {
3188
+ e.currentTarget.style.boxShadow =
3189
+ (theme === null || theme === void 0 ? void 0 : theme.boxShadow) || "0 2px 8px rgba(0, 0, 0, 0.1)";
3190
+ }
3191
+ }, onMouseLeave: (e) => {
3192
+ if (onClick) {
3193
+ e.currentTarget.style.boxShadow = "none";
3194
+ }
3195
+ } },
3196
+ React.createElement("div", { style: {
3197
+ display: "flex",
3198
+ alignItems: "flex-start",
3199
+ justifyContent: "space-between",
3200
+ } },
3201
+ React.createElement("div", { style: { flex: 1 } },
3202
+ React.createElement("p", { style: {
3203
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.xs) || "11px",
3204
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666",
3205
+ margin: "0 0 6px 0",
3206
+ } }, label),
3207
+ React.createElement("div", { style: {
3208
+ display: "flex",
3209
+ alignItems: "baseline",
3210
+ gap: (theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px",
3211
+ } },
3212
+ React.createElement("p", { style: {
3213
+ fontSize: "18px",
3214
+ fontWeight: "bold",
3215
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.text) || "#000",
3216
+ margin: 0,
3217
+ } }, value),
3218
+ unit && (React.createElement("p", { style: {
3219
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.xs) || "11px",
3220
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666",
3221
+ margin: 0,
3222
+ } }, unit))),
3223
+ trend && trendValue !== undefined && (React.createElement("div", { style: {
3224
+ fontSize: "10px",
3225
+ color: getTrendColor(),
3226
+ marginTop: "4px",
3227
+ } },
3228
+ getTrendIcon(),
3229
+ " ",
3230
+ trendValue,
3231
+ "%"))),
3232
+ icon && (React.createElement("div", { style: {
3233
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#999",
3234
+ fontSize: "18px",
3235
+ } }, icon)))));
3236
+ };
3237
+
3238
+ /**
3239
+ * TrendChart Component
3240
+ * Renders a simple line/area chart for trend data
3241
+ */
3242
+ const TrendChart = ({ data, title, height = 200, theme, showArea = true, }) => {
3243
+ if (!data || data.length === 0) {
3244
+ return (React.createElement("div", { style: {
3245
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.lg) || "24px",
3246
+ textAlign: "center",
3247
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666",
3248
+ } }, "No data available"));
3249
+ }
3250
+ const padding = 40;
3251
+ const width = 600;
3252
+ const innerHeight = height - padding * 2;
3253
+ const innerWidth = width - padding * 2;
3254
+ const maxValue = Math.max(...data.map((d) => d.value));
3255
+ const minValue = Math.min(...data.map((d) => d.value));
3256
+ const range = maxValue - minValue || 1;
3257
+ const points = data.map((d, i) => {
3258
+ const x = padding + (i / (data.length - 1 || 1)) * innerWidth;
3259
+ const y = padding + innerHeight - ((d.value - minValue) / range) * innerHeight;
3260
+ return Object.assign({ x, y }, d);
3261
+ });
3262
+ const pathD = points
3263
+ .map((p, i) => `${i === 0 ? "M" : "L"} ${p.x} ${p.y}`)
3264
+ .join(" ");
3265
+ const areaPathD = `${pathD} L ${points[points.length - 1].x} ${padding + innerHeight} L ${points[0].x} ${padding + innerHeight} Z`;
3266
+ const lineColor = (theme === null || theme === void 0 ? void 0 : theme.colors.primary) || "#1976d2";
3267
+ const areaColor = (theme === null || theme === void 0 ? void 0 : theme.colors.primary) || "#1976d2";
3268
+ return (React.createElement("div", null,
3269
+ title && (React.createElement("h3", { style: {
3270
+ margin: `0 0 ${(theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px"} 0`,
3271
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.md) || "16px",
3272
+ fontWeight: "600",
3273
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.text) || "#000",
3274
+ } }, title)),
3275
+ React.createElement("svg", { width: "100%", height: height, viewBox: `0 0 ${width} ${height}`, preserveAspectRatio: "xMidYMid meet", style: { overflow: "visible" } },
3276
+ [0, 0.25, 0.5, 0.75, 1].map((factor) => {
3277
+ const y = padding + innerHeight - factor * innerHeight;
3278
+ return (React.createElement("line", { key: `grid-${factor}`, x1: padding, y1: y, x2: width - padding, y2: y, stroke: (theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0", strokeWidth: "1", strokeDasharray: "4", opacity: "0.5" }));
3279
+ }),
3280
+ showArea && React.createElement("path", { d: areaPathD, fill: areaColor, fillOpacity: "0.1" }),
3281
+ React.createElement("path", { d: pathD, fill: "none", stroke: lineColor, strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
3282
+ points.map((p, i) => (React.createElement("circle", { key: `point-${i}`, cx: p.x, cy: p.y, r: "3", fill: lineColor, opacity: "0.8" }))),
3283
+ points.map((p, i) => {
3284
+ if (data.length <= 6 || i % Math.ceil(data.length / 6) === 0) {
3285
+ return (React.createElement("text", { key: `label-${i}`, x: p.x, y: height - padding + 20, textAnchor: "middle", fontSize: "12", fill: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666" }, p.label));
3286
+ }
3287
+ }))));
3288
+ };
3289
+
3290
+ /**
3291
+ * Executive Dashboard Report
3292
+ * High-level directive execution metrics, trends, and cost impact
3293
+ */
3294
+ const ExecutiveDashboard = ({ theme: themeProp, defaultDateRange = "past-month", }) => {
3295
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
3296
+ const { api, theme: contextTheme } = useReactBridgeContext();
3297
+ const theme = themeProp || contextTheme;
3298
+ const dateRange = useDateRange(defaultDateRange);
3299
+ const { data, loading, error } = useReportData(() => api.getExecutiveDashboard({
3300
+ startDate: dateRange.startDate,
3301
+ endDate: dateRange.endDate,
3302
+ }), [dateRange.startDate, dateRange.endDate]);
3303
+ const trendData = ((_a = data === null || data === void 0 ? void 0 : data.monthlyTrends) === null || _a === void 0 ? void 0 : _a.map((m) => ({
3304
+ label: m.month,
3305
+ value: m.successPercentage,
3306
+ }))) || [];
3307
+ return (React.createElement(ReportLayout, { title: "Executive Dashboard", description: "High-level directive execution metrics and trends", selectedDateRange: dateRange.selectedOption, onDateRangeChange: dateRange.setSelectedOption, loading: loading, error: error, theme: theme },
3308
+ React.createElement("div", { style: {
3309
+ display: "grid",
3310
+ gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))",
3311
+ gap: (theme === null || theme === void 0 ? void 0 : theme.spacing.sm) || "10px",
3312
+ } },
3313
+ React.createElement(MetricCard, { label: "Total Directives", value: (_b = data === null || data === void 0 ? void 0 : data.totalDirectives) !== null && _b !== void 0 ? _b : 0, theme: theme }),
3314
+ React.createElement(MetricCard, { label: "Success Rate", value: (_d = (_c = data === null || data === void 0 ? void 0 : data.successRate) === null || _c === void 0 ? void 0 : _c.toFixed(2)) !== null && _d !== void 0 ? _d : 0, unit: "%", trend: ((_e = data === null || data === void 0 ? void 0 : data.successRate) !== null && _e !== void 0 ? _e : 0 > 80) ? "up" : "neutral", theme: theme }),
3315
+ React.createElement(MetricCard, { label: "Auto-Executed", value: (_f = data === null || data === void 0 ? void 0 : data.autoExecutedDirectives) !== null && _f !== void 0 ? _f : 0, theme: theme }),
3316
+ React.createElement(MetricCard, { label: "Cost Impact", value: (_h = (_g = data === null || data === void 0 ? void 0 : data.totalCostImpact) === null || _g === void 0 ? void 0 : _g.toFixed(2)) !== null && _h !== void 0 ? _h : 0, unit: "$", theme: theme })),
3317
+ trendData.length > 0 && (React.createElement("div", { style: {
3318
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.sm) || "10px",
3319
+ border: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
3320
+ borderRadius: (theme === null || theme === void 0 ? void 0 : theme.borderRadius) || "6px",
3321
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.surface) || "#f5f5f5",
3322
+ } },
3323
+ React.createElement(TrendChart, { data: trendData, title: "Success Rate Trend", theme: theme, showArea: true }))),
3324
+ React.createElement("div", { style: {
3325
+ display: "grid",
3326
+ gridTemplateColumns: "repeat(auto-fit, minmax(220px, 1fr))",
3327
+ gap: (theme === null || theme === void 0 ? void 0 : theme.spacing.sm) || "10px",
3328
+ } },
3329
+ React.createElement("div", { style: {
3330
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.sm) || "10px",
3331
+ border: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
3332
+ borderRadius: (theme === null || theme === void 0 ? void 0 : theme.borderRadius) || "6px",
3333
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.surface) || "#f5f5f5",
3334
+ } },
3335
+ React.createElement("h3", { style: {
3336
+ margin: `0 0 ${(theme === null || theme === void 0 ? void 0 : theme.spacing.sm) || "8px"} 0`,
3337
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.sm) || "13px",
3338
+ fontWeight: "600",
3339
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.text) || "#000",
3340
+ } }, "Execution Summary"),
3341
+ React.createElement("div", { style: {
3342
+ display: "flex",
3343
+ flexDirection: "column",
3344
+ gap: (theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px",
3345
+ } },
3346
+ React.createElement("div", { style: {
3347
+ display: "flex",
3348
+ justifyContent: "space-between",
3349
+ padding: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "3px"} 0`,
3350
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.xs) || "11px",
3351
+ } },
3352
+ React.createElement("span", { style: { color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666" } }, "Successful:"),
3353
+ React.createElement("span", { style: {
3354
+ fontWeight: "600",
3355
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.success) || "#4caf50",
3356
+ } }, (_j = data === null || data === void 0 ? void 0 : data.successfulExecutions) !== null && _j !== void 0 ? _j : 0)),
3357
+ React.createElement("div", { style: {
3358
+ display: "flex",
3359
+ justifyContent: "space-between",
3360
+ padding: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "3px"} 0`,
3361
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.xs) || "11px",
3362
+ } },
3363
+ React.createElement("span", { style: { color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666" } }, "Failed:"),
3364
+ React.createElement("span", { style: {
3365
+ fontWeight: "600",
3366
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.error) || "#f44336",
3367
+ } }, (_k = data === null || data === void 0 ? void 0 : data.failedExecutions) !== null && _k !== void 0 ? _k : 0)),
3368
+ React.createElement("div", { style: {
3369
+ display: "flex",
3370
+ justifyContent: "space-between",
3371
+ padding: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "3px"} 0`,
3372
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.xs) || "11px",
3373
+ } },
3374
+ React.createElement("span", { style: { color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666" } }, "Avg Cost:"),
3375
+ React.createElement("span", { style: {
3376
+ fontWeight: "600",
3377
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.text) || "#000",
3378
+ } },
3379
+ "$", (_m = (_l = data === null || data === void 0 ? void 0 : data.averageCostPerDirective) === null || _l === void 0 ? void 0 : _l.toFixed(2)) !== null && _m !== void 0 ? _m : 0)))))));
3380
+ };
3381
+
3382
+ /**
3383
+ * ProgressBar Component
3384
+ * Displays percentage with visual bar
3385
+ */
3386
+ const ProgressBar = ({ percentage, label, showPercentage = true, height = "medium", theme, }) => {
3387
+ const normalizedPercentage = Math.min(Math.max(percentage, 0), 100);
3388
+ const getBarColor = () => {
3389
+ if (!theme) {
3390
+ if (normalizedPercentage >= 80)
3391
+ return "#10B981";
3392
+ if (normalizedPercentage >= 60)
3393
+ return "#F59E0B";
3394
+ return "#EF4444";
3395
+ }
3396
+ if (normalizedPercentage >= 80)
3397
+ return theme.colors.success;
3398
+ if (normalizedPercentage >= 60)
3399
+ return "#F59E0B"; // warning
3400
+ return theme.colors.error;
3401
+ };
3402
+ const heightConfig = {
3403
+ small: "4px",
3404
+ medium: "8px",
3405
+ large: "12px",
3406
+ };
3407
+ return (React.createElement("div", null,
3408
+ (label || showPercentage) && (React.createElement("div", { style: {
3409
+ display: "flex",
3410
+ justifyContent: "space-between",
3411
+ alignItems: "center",
3412
+ marginBottom: (theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px",
3413
+ } },
3414
+ label && (React.createElement("span", { style: {
3415
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.sm) || "14px",
3416
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.text) || "#000",
3417
+ fontWeight: "500",
3418
+ } }, label)),
3419
+ showPercentage && (React.createElement("span", { style: {
3420
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.xs) || "12px",
3421
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666",
3422
+ } },
3423
+ normalizedPercentage.toFixed(1),
3424
+ "%")))),
3425
+ React.createElement("div", { style: {
3426
+ width: "100%",
3427
+ height: heightConfig[height],
3428
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0",
3429
+ borderRadius: "4px",
3430
+ overflow: "hidden",
3431
+ } },
3432
+ React.createElement("div", { style: {
3433
+ height: "100%",
3434
+ width: `${normalizedPercentage}%`,
3435
+ backgroundColor: getBarColor(),
3436
+ transition: "width 0.3s ease",
3437
+ } }))));
3438
+ };
3439
+
3440
+ /**
3441
+ * DataTable Component
3442
+ * Generic sortable/paginated table for report data
3443
+ */
3444
+ const DataTable = React.forwardRef(({ columns, data, title, pageSize = 10, theme }, ref) => {
3445
+ const [sortKey, setSortKey] = React.useState(null);
3446
+ const [sortOrder, setSortOrder] = React.useState("asc");
3447
+ const [currentPage, setCurrentPage] = React.useState(0);
3448
+ const sortedData = React.useMemo(() => {
3449
+ if (!sortKey)
3450
+ return data;
3451
+ const sorted = [...data].sort((a, b) => {
3452
+ const aVal = a[sortKey];
3453
+ const bVal = b[sortKey];
3454
+ if (aVal < bVal)
3455
+ return sortOrder === "asc" ? -1 : 1;
3456
+ if (aVal > bVal)
3457
+ return sortOrder === "asc" ? 1 : -1;
3458
+ return 0;
3459
+ });
3460
+ return sorted;
3461
+ }, [data, sortKey, sortOrder]);
3462
+ const paginatedData = React.useMemo(() => {
3463
+ const start = currentPage * pageSize;
3464
+ return sortedData.slice(start, start + pageSize);
3465
+ }, [sortedData, currentPage, pageSize]);
3466
+ const totalPages = Math.ceil(sortedData.length / pageSize);
3467
+ const handleSort = (key) => {
3468
+ if (sortKey === key) {
3469
+ setSortOrder(sortOrder === "asc" ? "desc" : "asc");
3470
+ }
3471
+ else {
3472
+ setSortKey(key);
3473
+ setSortOrder("asc");
3474
+ }
3475
+ setCurrentPage(0);
3476
+ };
3477
+ return (React.createElement("div", { ref: ref },
3478
+ title && (React.createElement("h3", { style: {
3479
+ margin: `0 0 ${(theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px"} 0`,
3480
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.md) || "16px",
3481
+ fontWeight: "600",
3482
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.text) || "#000",
3483
+ } }, title)),
3484
+ data.length === 0 ? (React.createElement("div", { style: {
3485
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.lg) || "24px",
3486
+ textAlign: "center",
3487
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666",
3488
+ border: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
3489
+ borderRadius: (theme === null || theme === void 0 ? void 0 : theme.borderRadius) || "8px",
3490
+ } }, "No data available")) : (React.createElement(React.Fragment, null,
3491
+ React.createElement("div", { style: {
3492
+ overflowX: "auto",
3493
+ border: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
3494
+ borderRadius: (theme === null || theme === void 0 ? void 0 : theme.borderRadius) || "8px",
3495
+ } },
3496
+ React.createElement("table", { style: {
3497
+ width: "100%",
3498
+ borderCollapse: "collapse",
3499
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.sm) || "14px",
3500
+ } },
3501
+ React.createElement("thead", null,
3502
+ React.createElement("tr", { style: {
3503
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.surface) || "#f5f5f5",
3504
+ borderBottom: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
3505
+ } }, columns.map((col) => (React.createElement("th", { key: String(col.key), onClick: () => col.sortable && handleSort(String(col.key)), style: {
3506
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.sm) || "8px",
3507
+ textAlign: "left",
3508
+ fontWeight: "600",
3509
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.text) || "#000",
3510
+ cursor: col.sortable ? "pointer" : "default",
3511
+ userSelect: "none",
3512
+ width: col.width,
3513
+ whiteSpace: "nowrap",
3514
+ }, onMouseEnter: (e) => {
3515
+ if (col.sortable) {
3516
+ e.currentTarget.style.backgroundColor =
3517
+ (theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0";
3518
+ }
3519
+ }, onMouseLeave: (e) => {
3520
+ e.currentTarget.style.backgroundColor =
3521
+ (theme === null || theme === void 0 ? void 0 : theme.colors.surface) || "#f5f5f5";
3522
+ } },
3523
+ React.createElement("div", { style: {
3524
+ display: "flex",
3525
+ alignItems: "center",
3526
+ gap: "4px",
3527
+ } },
3528
+ col.label,
3529
+ col.sortable && sortKey === String(col.key) && (React.createElement("span", null, sortOrder === "asc" ? "↑" : "↓")))))))),
3530
+ React.createElement("tbody", null, paginatedData.map((row, idx) => (React.createElement("tr", { key: row.id || idx, style: {
3531
+ borderBottom: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
3532
+ backgroundColor: idx % 2 === 0
3533
+ ? "transparent"
3534
+ : (theme === null || theme === void 0 ? void 0 : theme.colors.surface) || "#f5f5f5",
3535
+ }, onMouseEnter: (e) => {
3536
+ e.currentTarget.style.backgroundColor =
3537
+ (theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0";
3538
+ }, onMouseLeave: (e) => {
3539
+ e.currentTarget.style.backgroundColor =
3540
+ idx % 2 === 0
3541
+ ? "transparent"
3542
+ : (theme === null || theme === void 0 ? void 0 : theme.colors.surface) || "#f5f5f5";
3543
+ } }, columns.map((col) => (React.createElement("td", { key: String(col.key), style: {
3544
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.sm) || "8px",
3545
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.text) || "#000",
3546
+ } }, col.render
3547
+ ? col.render(row[col.key], row)
3548
+ : String(row[col.key])))))))))),
3549
+ totalPages > 1 && (React.createElement("div", { style: {
3550
+ marginTop: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px",
3551
+ display: "flex",
3552
+ justifyContent: "space-between",
3553
+ alignItems: "center",
3554
+ } },
3555
+ React.createElement("span", { style: {
3556
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.sm) || "14px",
3557
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666",
3558
+ } },
3559
+ "Page ",
3560
+ currentPage + 1,
3561
+ " of ",
3562
+ totalPages),
3563
+ React.createElement("div", { style: { display: "flex", gap: (theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px" } },
3564
+ React.createElement("button", { onClick: () => setCurrentPage(0), disabled: currentPage === 0, style: {
3565
+ padding: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px"} ${(theme === null || theme === void 0 ? void 0 : theme.spacing.sm) || "8px"}`,
3566
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.sm) || "14px",
3567
+ borderRadius: "4px",
3568
+ border: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
3569
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.surface) || "#f5f5f5",
3570
+ cursor: currentPage === 0 ? "not-allowed" : "pointer",
3571
+ opacity: currentPage === 0 ? 0.5 : 1,
3572
+ } }, "First"),
3573
+ React.createElement("button", { onClick: () => setCurrentPage(Math.max(0, currentPage - 1)), disabled: currentPage === 0, style: {
3574
+ padding: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px"} ${(theme === null || theme === void 0 ? void 0 : theme.spacing.sm) || "8px"}`,
3575
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.sm) || "14px",
3576
+ borderRadius: "4px",
3577
+ border: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
3578
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.surface) || "#f5f5f5",
3579
+ cursor: currentPage === 0 ? "not-allowed" : "pointer",
3580
+ opacity: currentPage === 0 ? 0.5 : 1,
3581
+ } }, "Previous"),
3582
+ React.createElement("button", { onClick: () => setCurrentPage(Math.min(totalPages - 1, currentPage + 1)), disabled: currentPage === totalPages - 1, style: {
3583
+ padding: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px"} ${(theme === null || theme === void 0 ? void 0 : theme.spacing.sm) || "8px"}`,
3584
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.sm) || "14px",
3585
+ borderRadius: "4px",
3586
+ border: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
3587
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.surface) || "#f5f5f5",
3588
+ cursor: currentPage === totalPages - 1
3589
+ ? "not-allowed"
3590
+ : "pointer",
3591
+ opacity: currentPage === totalPages - 1 ? 0.5 : 1,
3592
+ } }, "Next"),
3593
+ React.createElement("button", { onClick: () => setCurrentPage(totalPages - 1), disabled: currentPage === totalPages - 1, style: {
3594
+ padding: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px"} ${(theme === null || theme === void 0 ? void 0 : theme.spacing.sm) || "8px"}`,
3595
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.sm) || "14px",
3596
+ borderRadius: "4px",
3597
+ border: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
3598
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.surface) || "#f5f5f5",
3599
+ cursor: currentPage === totalPages - 1
3600
+ ? "not-allowed"
3601
+ : "pointer",
3602
+ opacity: currentPage === totalPages - 1 ? 0.5 : 1,
3603
+ } }, "Last"))))))));
3604
+ });
3605
+ DataTable.displayName = "DataTable";
3606
+
3607
+ /**
3608
+ * Supply Chain Risk Report
3609
+ * Supply chain risks including inventory, supplier, and cost analysis
3610
+ */
3611
+ const SupplyChainRisk = ({ theme: themeProp, defaultDateRange = "past-month", }) => {
3612
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3;
3613
+ const { api, theme: contextTheme } = useReactBridgeContext();
3614
+ const theme = themeProp || contextTheme;
3615
+ const dateRange = useDateRange(defaultDateRange);
3616
+ const { data, loading, error } = useReportData(() => api.getSupplyChainRisk({
3617
+ startDate: dateRange.startDate,
3618
+ endDate: dateRange.endDate,
3619
+ }), [dateRange.startDate, dateRange.endDate]);
3620
+ const riskPercentage = (_a = data === null || data === void 0 ? void 0 : data.overallRiskScore) !== null && _a !== void 0 ? _a : 0;
3621
+ ((_b = data === null || data === void 0 ? void 0 : data.highRiskCount) !== null && _b !== void 0 ? _b : 0) +
3622
+ ((_c = data === null || data === void 0 ? void 0 : data.mediumRiskCount) !== null && _c !== void 0 ? _c : 0) +
3623
+ ((_d = data === null || data === void 0 ? void 0 : data.lowRiskCount) !== null && _d !== void 0 ? _d : 0);
3624
+ const tableColumns = [
3625
+ {
3626
+ key: "issueType",
3627
+ label: "Issue Type",
3628
+ sortable: true,
3629
+ },
3630
+ {
3631
+ key: "description",
3632
+ label: "Description",
3633
+ sortable: true,
3634
+ },
3635
+ {
3636
+ key: "affectedRecords",
3637
+ label: "Affected Records",
3638
+ sortable: true,
3639
+ },
3640
+ {
3641
+ key: "severity",
3642
+ label: "Severity",
3643
+ sortable: true,
3644
+ render: (value) => {
3645
+ const color = value === "high"
3646
+ ? theme === null || theme === void 0 ? void 0 : theme.colors.error
3647
+ : value === "medium"
3648
+ ? "#F59E0B"
3649
+ : theme === null || theme === void 0 ? void 0 : theme.colors.success;
3650
+ return (React.createElement("span", { style: { color, fontWeight: "600" } }, value.toUpperCase()));
3651
+ },
3652
+ },
3653
+ ];
3654
+ return (React.createElement(ReportLayout, { title: "Supply Chain Risk", description: "Inventory, supplier, and cost risk analysis", selectedDateRange: dateRange.selectedOption, onDateRangeChange: dateRange.setSelectedOption, loading: loading, error: error, theme: theme },
3655
+ React.createElement("div", { style: {
3656
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px",
3657
+ border: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
3658
+ borderRadius: (theme === null || theme === void 0 ? void 0 : theme.borderRadius) || "8px",
3659
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.surface) || "#f5f5f5",
3660
+ } },
3661
+ React.createElement("h3", { style: {
3662
+ margin: `0 0 ${(theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px"} 0`,
3663
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.lg) || "18px",
3664
+ fontWeight: "600",
3665
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.text) || "#000",
3666
+ } }, "Overall Risk Assessment"),
3667
+ React.createElement(ProgressBar, { percentage: riskPercentage, label: "Risk Score", theme: theme, height: "large" })),
3668
+ React.createElement("div", { style: {
3669
+ display: "grid",
3670
+ gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))",
3671
+ gap: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px",
3672
+ } },
3673
+ React.createElement(MetricCard, { label: "High Risk Items", value: (_e = data === null || data === void 0 ? void 0 : data.highRiskCount) !== null && _e !== void 0 ? _e : 0, theme: theme }),
3674
+ React.createElement(MetricCard, { label: "Medium Risk Items", value: (_f = data === null || data === void 0 ? void 0 : data.mediumRiskCount) !== null && _f !== void 0 ? _f : 0, theme: theme }),
3675
+ React.createElement(MetricCard, { label: "Low Risk Items", value: (_g = data === null || data === void 0 ? void 0 : data.lowRiskCount) !== null && _g !== void 0 ? _g : 0, theme: theme })),
3676
+ React.createElement("div", { style: {
3677
+ display: "grid",
3678
+ gridTemplateColumns: "repeat(auto-fit, minmax(250px, 1fr))",
3679
+ gap: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px",
3680
+ } },
3681
+ React.createElement("div", { style: {
3682
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px",
3683
+ border: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
3684
+ borderRadius: (theme === null || theme === void 0 ? void 0 : theme.borderRadius) || "8px",
3685
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.surface) || "#f5f5f5",
3686
+ } },
3687
+ React.createElement("h4", { style: {
3688
+ margin: `0 0 ${(theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px"} 0`,
3689
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.md) || "16px",
3690
+ fontWeight: "600",
3691
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.text) || "#000",
3692
+ } }, "Inventory Risk"),
3693
+ React.createElement("div", { style: {
3694
+ display: "flex",
3695
+ flexDirection: "column",
3696
+ gap: (theme === null || theme === void 0 ? void 0 : theme.spacing.sm) || "8px",
3697
+ } },
3698
+ React.createElement("div", { style: {
3699
+ display: "flex",
3700
+ justifyContent: "space-between",
3701
+ padding: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px"} 0`,
3702
+ } },
3703
+ React.createElement("span", { style: { color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666" } }, "Low Stock Items:"),
3704
+ React.createElement("span", { style: { fontWeight: "600" } }, (_j = (_h = data === null || data === void 0 ? void 0 : data.inventoryRisk) === null || _h === void 0 ? void 0 : _h.lowStockItems) !== null && _j !== void 0 ? _j : 0)),
3705
+ React.createElement("div", { style: {
3706
+ display: "flex",
3707
+ justifyContent: "space-between",
3708
+ padding: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px"} 0`,
3709
+ } },
3710
+ React.createElement("span", { style: { color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666" } }, "Overstocked Items:"),
3711
+ React.createElement("span", { style: { fontWeight: "600" } }, (_l = (_k = data === null || data === void 0 ? void 0 : data.inventoryRisk) === null || _k === void 0 ? void 0 : _k.overstockedItems) !== null && _l !== void 0 ? _l : 0)),
3712
+ React.createElement(ProgressBar, { percentage: (_o = (_m = data === null || data === void 0 ? void 0 : data.inventoryRisk) === null || _m === void 0 ? void 0 : _m.averageStockHealth) !== null && _o !== void 0 ? _o : 0, label: "Stock Health", theme: theme }))),
3713
+ React.createElement("div", { style: {
3714
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px",
3715
+ border: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
3716
+ borderRadius: (theme === null || theme === void 0 ? void 0 : theme.borderRadius) || "8px",
3717
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.surface) || "#f5f5f5",
3718
+ } },
3719
+ React.createElement("h4", { style: {
3720
+ margin: `0 0 ${(theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px"} 0`,
3721
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.md) || "16px",
3722
+ fontWeight: "600",
3723
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.text) || "#000",
3724
+ } }, "Supplier Risk"),
3725
+ React.createElement("div", { style: {
3726
+ display: "flex",
3727
+ flexDirection: "column",
3728
+ gap: (theme === null || theme === void 0 ? void 0 : theme.spacing.sm) || "8px",
3729
+ } },
3730
+ React.createElement("div", { style: {
3731
+ display: "flex",
3732
+ justifyContent: "space-between",
3733
+ padding: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px"} 0`,
3734
+ } },
3735
+ React.createElement("span", { style: { color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666" } }, "Unreliable Suppliers:"),
3736
+ React.createElement("span", { style: { fontWeight: "600" } }, (_q = (_p = data === null || data === void 0 ? void 0 : data.supplierRisk) === null || _p === void 0 ? void 0 : _p.unreliableSuppliers) !== null && _q !== void 0 ? _q : 0)),
3737
+ React.createElement("div", { style: {
3738
+ display: "flex",
3739
+ justifyContent: "space-between",
3740
+ padding: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px"} 0`,
3741
+ } },
3742
+ React.createElement("span", { style: { color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666" } }, "High Defect Rate:"),
3743
+ React.createElement("span", { style: { fontWeight: "600" } }, (_s = (_r = data === null || data === void 0 ? void 0 : data.supplierRisk) === null || _r === void 0 ? void 0 : _r.highDefectRateSuppliers) !== null && _s !== void 0 ? _s : 0)),
3744
+ React.createElement(ProgressBar, { percentage: (_u = (_t = data === null || data === void 0 ? void 0 : data.supplierRisk) === null || _t === void 0 ? void 0 : _t.averageSupplierScore) !== null && _u !== void 0 ? _u : 0, label: "Supplier Score", theme: theme }))),
3745
+ React.createElement("div", { style: {
3746
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px",
3747
+ border: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
3748
+ borderRadius: (theme === null || theme === void 0 ? void 0 : theme.borderRadius) || "8px",
3749
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.surface) || "#f5f5f5",
3750
+ } },
3751
+ React.createElement("h4", { style: {
3752
+ margin: `0 0 ${(theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px"} 0`,
3753
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.md) || "16px",
3754
+ fontWeight: "600",
3755
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.text) || "#000",
3756
+ } }, "Cost Risk"),
3757
+ React.createElement("div", { style: {
3758
+ display: "flex",
3759
+ flexDirection: "column",
3760
+ gap: (theme === null || theme === void 0 ? void 0 : theme.spacing.sm) || "8px",
3761
+ } },
3762
+ React.createElement("div", { style: {
3763
+ display: "flex",
3764
+ justifyContent: "space-between",
3765
+ padding: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px"} 0`,
3766
+ } },
3767
+ React.createElement("span", { style: { color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666" } }, "Cost Variance:"),
3768
+ React.createElement("span", { style: {
3769
+ fontWeight: "600",
3770
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.error) || "#f44336",
3771
+ } },
3772
+ "$", (_x = (_w = (_v = data === null || data === void 0 ? void 0 : data.costRisk) === null || _v === void 0 ? void 0 : _v.unexpectedCostVariance) === null || _w === void 0 ? void 0 : _w.toFixed(2)) !== null && _x !== void 0 ? _x : 0)),
3773
+ React.createElement("div", { style: {
3774
+ display: "flex",
3775
+ justifyContent: "space-between",
3776
+ padding: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px"} 0`,
3777
+ } },
3778
+ React.createElement("span", { style: { color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666" } }, "Potential Savings:"),
3779
+ React.createElement("span", { style: {
3780
+ fontWeight: "600",
3781
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.success) || "#4caf50",
3782
+ } },
3783
+ "$", (_0 = (_z = (_y = data === null || data === void 0 ? void 0 : data.costRisk) === null || _y === void 0 ? void 0 : _y.potentialSavings) === null || _z === void 0 ? void 0 : _z.toFixed(2)) !== null && _0 !== void 0 ? _0 : 0)),
3784
+ React.createElement("div", { style: {
3785
+ display: "flex",
3786
+ justifyContent: "space-between",
3787
+ padding: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px"} 0`,
3788
+ } },
3789
+ React.createElement("span", { style: { color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666" } }, "Volatility Index:"),
3790
+ React.createElement("span", { style: { fontWeight: "600" } }, (_3 = (_2 = (_1 = data === null || data === void 0 ? void 0 : data.costRisk) === null || _1 === void 0 ? void 0 : _1.costVolatilityIndex) === null || _2 === void 0 ? void 0 : _2.toFixed(2)) !== null && _3 !== void 0 ? _3 : 0,
3791
+ "%"))))),
3792
+ (data === null || data === void 0 ? void 0 : data.dataQualityIssues) && data.dataQualityIssues.length > 0 && (React.createElement("div", null,
3793
+ React.createElement(DataTable, { title: "Data Quality Issues", columns: tableColumns, data: data.dataQualityIssues.map((issue, idx) => (Object.assign({ id: idx }, issue))), pageSize: 5, theme: theme })))));
3794
+ };
3795
+
3796
+ /**
3797
+ * StatusBadge Component
3798
+ * Displays status with color-coded background
3799
+ */
3800
+ const getStatusConfig = (status, theme) => {
3801
+ const baseConfig = {
3802
+ ok: { label: "OK" },
3803
+ warning: { label: "Warning" },
3804
+ critical: { label: "Critical" },
3805
+ proposed: { label: "Proposed" },
3806
+ executed: { label: "Executed" },
3807
+ declined: { label: "Declined" },
3808
+ failed: { label: "Failed" },
3809
+ "auto-executed": { label: "Auto Executed" },
3810
+ };
3811
+ const config = baseConfig[status];
3812
+ if (theme) {
3813
+ const statusColors = {
3814
+ ok: { bg: "rgba(16, 185, 129, 0.15)", text: theme.colors.success },
3815
+ warning: { bg: "rgba(245, 158, 11, 0.15)", text: "#F59E0B" },
3816
+ critical: { bg: "rgba(239, 68, 68, 0.15)", text: theme.colors.error },
3817
+ proposed: { bg: "rgba(59, 130, 246, 0.15)", text: theme.colors.primary },
3818
+ executed: { bg: "rgba(16, 185, 129, 0.15)", text: theme.colors.success },
3819
+ declined: {
3820
+ bg: "rgba(156, 163, 175, 0.15)",
3821
+ text: theme.colors.textSecondary,
3822
+ },
3823
+ failed: { bg: "rgba(239, 68, 68, 0.15)", text: theme.colors.error },
3824
+ "auto-executed": {
3825
+ bg: "rgba(16, 185, 129, 0.15)",
3826
+ text: theme.colors.success,
3827
+ },
3828
+ };
3829
+ return {
3830
+ bg: statusColors[status].bg,
3831
+ text: statusColors[status].text,
3832
+ label: config.label,
3833
+ };
3834
+ }
3835
+ const defaultColors = {
3836
+ ok: { bg: "#D1FAE5", text: "#059669" },
3837
+ warning: { bg: "#FEF3C7", text: "#D97706" },
3838
+ critical: { bg: "#FEE2E2", text: "#DC2626" },
3839
+ proposed: { bg: "#DBEAFE", text: "#1D4ED8" },
3840
+ executed: { bg: "#D1FAE5", text: "#059669" },
3841
+ declined: { bg: "#E5E7EB", text: "#4B5563" },
3842
+ failed: { bg: "#FEE2E2", text: "#DC2626" },
3843
+ "auto-executed": { bg: "#D1FAE5", text: "#059669" },
3844
+ };
3845
+ return {
3846
+ bg: defaultColors[status].bg,
3847
+ text: defaultColors[status].text,
3848
+ label: config.label,
3849
+ };
3850
+ };
3851
+ const StatusBadge = ({ status, label, theme, }) => {
3852
+ const config = getStatusConfig(status, theme);
3853
+ return (React.createElement("span", { style: {
3854
+ display: "inline-flex",
3855
+ alignItems: "center",
3856
+ paddingLeft: "10px",
3857
+ paddingRight: "10px",
3858
+ paddingTop: "4px",
3859
+ paddingBottom: "4px",
3860
+ borderRadius: "4px",
3861
+ fontSize: "12px",
3862
+ fontWeight: "500",
3863
+ backgroundColor: config.bg,
3864
+ color: config.text,
3865
+ whiteSpace: "nowrap",
3866
+ } }, label || config.label));
3867
+ };
3868
+
3869
+ /**
3870
+ * Execution Audit Trail Report
3871
+ * Complete execution history and audit information
3872
+ */
3873
+ const ExecutionAuditTrail = ({ theme: themeProp, defaultDateRange = "past-month", }) => {
3874
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
3875
+ const { api, theme: contextTheme } = useReactBridgeContext();
3876
+ const theme = themeProp || contextTheme;
3877
+ const dateRange = useDateRange(defaultDateRange);
3878
+ const [directiveTypeFilter, setDirectiveTypeFilter] = React.useState("");
3879
+ const { data, loading, error } = useReportData(() => api.getExecutionAuditTrail({
3880
+ startDate: dateRange.startDate,
3881
+ endDate: dateRange.endDate,
3882
+ directiveType: directiveTypeFilter || undefined,
3883
+ }), [dateRange.startDate, dateRange.endDate, directiveTypeFilter]);
3884
+ const tableColumns = [
3885
+ {
3886
+ key: "directiveAction",
3887
+ label: "Directive Action",
3888
+ sortable: true,
3889
+ width: "200px",
3890
+ },
3891
+ {
3892
+ key: "status",
3893
+ label: "Status",
3894
+ sortable: true,
3895
+ render: (value) => React.createElement(StatusBadge, { status: value, theme: theme }),
3896
+ },
3897
+ {
3898
+ key: "executedAt",
3899
+ label: "Executed At",
3900
+ sortable: true,
3901
+ render: (value) => {
3902
+ try {
3903
+ return new Date(value).toLocaleString();
3904
+ }
3905
+ catch (_a) {
3906
+ return value;
3907
+ }
3908
+ },
3909
+ },
3910
+ {
3911
+ key: "executionDurationMinutes",
3912
+ label: "Duration (min)",
3913
+ sortable: true,
3914
+ },
3915
+ {
3916
+ key: "executedBy",
3917
+ label: "Executed By",
3918
+ sortable: true,
3919
+ },
3920
+ {
3921
+ key: "outcome",
3922
+ label: "Outcome",
3923
+ sortable: false,
3924
+ },
3925
+ ];
3926
+ return (React.createElement(ReportLayout, { title: "Execution Audit Trail", description: "Directive execution history and audit information", selectedDateRange: dateRange.selectedOption, onDateRangeChange: dateRange.setSelectedOption, loading: loading, error: error, theme: theme },
3927
+ React.createElement("div", { style: {
3928
+ display: "grid",
3929
+ gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))",
3930
+ gap: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px",
3931
+ } },
3932
+ React.createElement(MetricCard, { label: "Total Directives", value: (_a = data === null || data === void 0 ? void 0 : data.totalDirectives) !== null && _a !== void 0 ? _a : 0, theme: theme }),
3933
+ React.createElement(MetricCard, { label: "Executed", value: (_b = data === null || data === void 0 ? void 0 : data.executedCount) !== null && _b !== void 0 ? _b : 0, theme: theme }),
3934
+ React.createElement(MetricCard, { label: "Declined", value: (_c = data === null || data === void 0 ? void 0 : data.declinedCount) !== null && _c !== void 0 ? _c : 0, theme: theme }),
3935
+ React.createElement(MetricCard, { label: "Failed", value: (_d = data === null || data === void 0 ? void 0 : data.failedCount) !== null && _d !== void 0 ? _d : 0, theme: theme }),
3936
+ React.createElement(MetricCard, { label: "Auto-Executed", value: (_e = data === null || data === void 0 ? void 0 : data.autoExecutedCount) !== null && _e !== void 0 ? _e : 0, theme: theme })),
3937
+ React.createElement("div", { style: {
3938
+ display: "grid",
3939
+ gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))",
3940
+ gap: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px",
3941
+ } },
3942
+ React.createElement("div", { style: {
3943
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px",
3944
+ border: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
3945
+ borderRadius: (theme === null || theme === void 0 ? void 0 : theme.borderRadius) || "8px",
3946
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.surface) || "#f5f5f5",
3947
+ } },
3948
+ React.createElement("h4", { style: {
3949
+ margin: `0 0 ${(theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px"} 0`,
3950
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.md) || "16px",
3951
+ fontWeight: "600",
3952
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.text) || "#000",
3953
+ } }, "Execution Statistics"),
3954
+ React.createElement("div", { style: {
3955
+ display: "flex",
3956
+ flexDirection: "column",
3957
+ gap: (theme === null || theme === void 0 ? void 0 : theme.spacing.sm) || "8px",
3958
+ } },
3959
+ React.createElement("div", { style: {
3960
+ display: "flex",
3961
+ justifyContent: "space-between",
3962
+ padding: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px"} 0`,
3963
+ } },
3964
+ React.createElement("span", { style: { color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666" } }, "Avg. Duration:"),
3965
+ React.createElement("span", { style: { fontWeight: "600" } }, (_h = (_g = (_f = data === null || data === void 0 ? void 0 : data.stats) === null || _f === void 0 ? void 0 : _f.averageExecutionTimeMinutes) === null || _g === void 0 ? void 0 : _g.toFixed(1)) !== null && _h !== void 0 ? _h : 0,
3966
+ " min")),
3967
+ React.createElement("div", { style: {
3968
+ display: "flex",
3969
+ justifyContent: "space-between",
3970
+ padding: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px"} 0`,
3971
+ } },
3972
+ React.createElement("span", { style: { color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666" } }, "Success Rate:"),
3973
+ React.createElement("span", { style: {
3974
+ fontWeight: "600",
3975
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.success) || "#4caf50",
3976
+ } }, (_l = (_k = (_j = data === null || data === void 0 ? void 0 : data.stats) === null || _j === void 0 ? void 0 : _j.successRate) === null || _k === void 0 ? void 0 : _k.toFixed(2)) !== null && _l !== void 0 ? _l : 0,
3977
+ "%")),
3978
+ React.createElement("div", { style: {
3979
+ display: "flex",
3980
+ justifyContent: "space-between",
3981
+ padding: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px"} 0`,
3982
+ } },
3983
+ React.createElement("span", { style: { color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666" } }, "Fastest Execution:"),
3984
+ React.createElement("span", { style: { fontWeight: "600" } }, (_o = (_m = data === null || data === void 0 ? void 0 : data.stats) === null || _m === void 0 ? void 0 : _m.fastestExecutionMinutes) !== null && _o !== void 0 ? _o : 0,
3985
+ " min")),
3986
+ React.createElement("div", { style: {
3987
+ display: "flex",
3988
+ justifyContent: "space-between",
3989
+ padding: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px"} 0`,
3990
+ } },
3991
+ React.createElement("span", { style: { color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666" } }, "Slowest Execution:"),
3992
+ React.createElement("span", { style: { fontWeight: "600" } }, (_q = (_p = data === null || data === void 0 ? void 0 : data.stats) === null || _p === void 0 ? void 0 : _p.slowestExecutionMinutes) !== null && _q !== void 0 ? _q : 0,
3993
+ " min"))))),
3994
+ (data === null || data === void 0 ? void 0 : data.executionHistory) && data.executionHistory.length > 0 && (React.createElement("div", null,
3995
+ React.createElement(DataTable, { title: "Execution History", columns: tableColumns, data: data.executionHistory.map((record, idx) => (Object.assign({ id: idx }, record))), pageSize: 10, theme: theme })))));
3996
+ };
3997
+
3998
+ /**
3999
+ * HealthGauge Component
4000
+ * Displays health/score on a 0-10 scale with color-coded circle
4001
+ */
4002
+ const HealthGauge = ({ score, label, size = "medium", theme, }) => {
4003
+ const getColor = () => {
4004
+ if (!theme) {
4005
+ if (score >= 8)
4006
+ return "#10B981";
4007
+ if (score >= 6)
4008
+ return "#F59E0B";
4009
+ return "#EF4444";
4010
+ }
4011
+ if (score >= 8)
4012
+ return theme.colors.success;
4013
+ if (score >= 6)
4014
+ return "#F59E0B"; // warning
4015
+ return theme.colors.error;
4016
+ };
4017
+ const getBackgroundColor = () => {
4018
+ if (!theme) {
4019
+ if (score >= 8)
4020
+ return "rgba(16, 185, 129, 0.1)";
4021
+ if (score >= 6)
4022
+ return "rgba(245, 158, 11, 0.1)";
4023
+ return "rgba(239, 68, 68, 0.1)";
4024
+ }
4025
+ if (score >= 8)
4026
+ return "rgba(16, 185, 129, 0.15)";
4027
+ if (score >= 6)
4028
+ return "rgba(245, 158, 11, 0.15)";
4029
+ return "rgba(239, 68, 68, 0.15)";
4030
+ };
4031
+ const sizeConfig = {
4032
+ small: { width: 64, height: 64, fontSize: "14px", labelSize: "11px" },
4033
+ medium: { width: 96, height: 96, fontSize: "24px", labelSize: "12px" },
4034
+ large: { width: 128, height: 128, fontSize: "32px", labelSize: "13px" },
4035
+ };
4036
+ const config = sizeConfig[size];
4037
+ return (React.createElement("div", { style: {
4038
+ display: "flex",
4039
+ flexDirection: "column",
4040
+ alignItems: "center",
4041
+ gap: (theme === null || theme === void 0 ? void 0 : theme.spacing.sm) || "8px",
4042
+ } },
4043
+ React.createElement("div", { style: {
4044
+ width: `${config.width}px`,
4045
+ height: `${config.height}px`,
4046
+ borderRadius: "50%",
4047
+ backgroundColor: getBackgroundColor(),
4048
+ display: "flex",
4049
+ alignItems: "center",
4050
+ justifyContent: "center",
4051
+ flex: "none",
4052
+ } },
4053
+ React.createElement("span", { style: {
4054
+ fontSize: config.fontSize,
4055
+ fontWeight: "bold",
4056
+ color: getColor(),
4057
+ } }, score.toFixed(1))),
4058
+ React.createElement("p", { style: {
4059
+ fontSize: config.labelSize,
4060
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666",
4061
+ textAlign: "center",
4062
+ margin: 0,
4063
+ maxWidth: `${config.width + 20}px`,
4064
+ } }, label)));
4065
+ };
4066
+
4067
+ /**
4068
+ * Portfolio Health Report
4069
+ * Aggregated metric health across the entire portfolio
4070
+ */
4071
+ const PortfolioHealth = ({ theme: themeProp, defaultDateRange = "past-month", }) => {
4072
+ var _a, _b, _c, _d;
4073
+ const { api, theme: contextTheme } = useReactBridgeContext();
4074
+ const theme = themeProp || contextTheme;
4075
+ const dateRange = useDateRange(defaultDateRange);
4076
+ const { data, loading, error } = useReportData(() => api.getPortfolioHealth({
4077
+ startDate: dateRange.startDate,
4078
+ endDate: dateRange.endDate,
4079
+ }), [dateRange.startDate, dateRange.endDate]);
4080
+ const metricTableColumns = [
4081
+ {
4082
+ key: "metricName",
4083
+ label: "Metric Name",
4084
+ sortable: true,
4085
+ },
4086
+ {
4087
+ key: "score",
4088
+ label: "Score (0-10)",
4089
+ sortable: true,
4090
+ render: (value) => value.toFixed(2),
4091
+ },
4092
+ {
4093
+ key: "status",
4094
+ label: "Status",
4095
+ sortable: true,
4096
+ render: (value) => {
4097
+ const color = value === "ok"
4098
+ ? theme === null || theme === void 0 ? void 0 : theme.colors.success
4099
+ : value === "warning"
4100
+ ? "#F59E0B"
4101
+ : theme === null || theme === void 0 ? void 0 : theme.colors.error;
4102
+ return (React.createElement("span", { style: { color, fontWeight: "600" } }, value.toUpperCase()));
4103
+ },
4104
+ },
4105
+ {
4106
+ key: "currentValue",
4107
+ label: "Current Value",
4108
+ sortable: true,
4109
+ render: (value) => value.toFixed(2),
4110
+ },
4111
+ {
4112
+ key: "targetValue",
4113
+ label: "Target Value",
4114
+ sortable: true,
4115
+ render: (value) => value.toFixed(2),
4116
+ },
4117
+ {
4118
+ key: "variance",
4119
+ label: "Variance",
4120
+ sortable: true,
4121
+ render: (value) => {
4122
+ const color = value > 0 ? theme === null || theme === void 0 ? void 0 : theme.colors.success : theme === null || theme === void 0 ? void 0 : theme.colors.error;
4123
+ return (React.createElement("span", { style: { color, fontWeight: "600" } }, value.toFixed(2)));
4124
+ },
4125
+ },
4126
+ ];
4127
+ const criticalTableColumns = [
4128
+ {
4129
+ key: "metricName",
4130
+ label: "Metric Name",
4131
+ sortable: true,
4132
+ },
4133
+ {
4134
+ key: "description",
4135
+ label: "Description",
4136
+ sortable: true,
4137
+ },
4138
+ {
4139
+ key: "recommendedAction",
4140
+ label: "Recommended Action",
4141
+ sortable: false,
4142
+ },
4143
+ ];
4144
+ return (React.createElement(ReportLayout, { title: "Portfolio Health", description: "Aggregated metric health and critical alerts", selectedDateRange: dateRange.selectedOption, onDateRangeChange: dateRange.setSelectedOption, loading: loading, error: error, theme: theme },
4145
+ React.createElement("div", { style: {
4146
+ display: "flex",
4147
+ justifyContent: "center",
4148
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.lg) || "24px",
4149
+ border: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
4150
+ borderRadius: (theme === null || theme === void 0 ? void 0 : theme.borderRadius) || "8px",
4151
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.surface) || "#f5f5f5",
4152
+ } },
4153
+ React.createElement(HealthGauge, { score: (_a = data === null || data === void 0 ? void 0 : data.overallHealthScore) !== null && _a !== void 0 ? _a : 0, label: "Overall Portfolio Health", size: "large", theme: theme })),
4154
+ React.createElement("div", { style: {
4155
+ display: "grid",
4156
+ gridTemplateColumns: "repeat(auto-fit, minmax(150px, 1fr))",
4157
+ gap: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px",
4158
+ } },
4159
+ React.createElement("div", { style: {
4160
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px",
4161
+ border: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
4162
+ borderRadius: (theme === null || theme === void 0 ? void 0 : theme.borderRadius) || "8px",
4163
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.surface) || "#f5f5f5",
4164
+ textAlign: "center",
4165
+ } },
4166
+ React.createElement("p", { style: {
4167
+ margin: 0,
4168
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.sm) || "14px",
4169
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666",
4170
+ marginBottom: (theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px",
4171
+ } }, "Healthy Metrics"),
4172
+ React.createElement("p", { style: {
4173
+ margin: 0,
4174
+ fontSize: "24px",
4175
+ fontWeight: "bold",
4176
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.success) || "#4caf50",
4177
+ } }, (_b = data === null || data === void 0 ? void 0 : data.healthyMetricsCount) !== null && _b !== void 0 ? _b : 0)),
4178
+ React.createElement("div", { style: {
4179
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px",
4180
+ border: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
4181
+ borderRadius: (theme === null || theme === void 0 ? void 0 : theme.borderRadius) || "8px",
4182
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.surface) || "#f5f5f5",
4183
+ textAlign: "center",
4184
+ } },
4185
+ React.createElement("p", { style: {
4186
+ margin: 0,
4187
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.sm) || "14px",
4188
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666",
4189
+ marginBottom: (theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px",
4190
+ } }, "Warning Metrics"),
4191
+ React.createElement("p", { style: {
4192
+ margin: 0,
4193
+ fontSize: "24px",
4194
+ fontWeight: "bold",
4195
+ color: "#F59E0B",
4196
+ } }, (_c = data === null || data === void 0 ? void 0 : data.warningMetricsCount) !== null && _c !== void 0 ? _c : 0)),
4197
+ React.createElement("div", { style: {
4198
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px",
4199
+ border: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
4200
+ borderRadius: (theme === null || theme === void 0 ? void 0 : theme.borderRadius) || "8px",
4201
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.surface) || "#f5f5f5",
4202
+ textAlign: "center",
4203
+ } },
4204
+ React.createElement("p", { style: {
4205
+ margin: 0,
4206
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.sm) || "14px",
4207
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666",
4208
+ marginBottom: (theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px",
4209
+ } }, "Critical Metrics"),
4210
+ React.createElement("p", { style: {
4211
+ margin: 0,
4212
+ fontSize: "24px",
4213
+ fontWeight: "bold",
4214
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.error) || "#f44336",
4215
+ } }, (_d = data === null || data === void 0 ? void 0 : data.criticalMetricsCount) !== null && _d !== void 0 ? _d : 0))),
4216
+ (data === null || data === void 0 ? void 0 : data.metricHealthScores) && data.metricHealthScores.length > 0 && (React.createElement("div", null,
4217
+ React.createElement(DataTable, { title: "Metric Health Scores", columns: metricTableColumns, data: data.metricHealthScores.map((metric, idx) => (Object.assign({ id: idx }, metric))), pageSize: 10, theme: theme }))),
4218
+ (data === null || data === void 0 ? void 0 : data.criticalMetrics) && data.criticalMetrics.length > 0 && (React.createElement("div", null,
4219
+ React.createElement(DataTable, { title: "Critical Metrics Requiring Attention", columns: criticalTableColumns, data: data.criticalMetrics.map((metric, idx) => (Object.assign({ id: idx }, metric))), pageSize: 5, theme: theme })))));
4220
+ };
4221
+
4222
+ /**
4223
+ * Data Quality & Automation Report
4224
+ * Data gaps, automation opportunities, and actionable recommendations
4225
+ */
4226
+ const DataQualityAutomation = ({ theme: themeProp, defaultDateRange = "past-month", }) => {
4227
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
4228
+ const { api, theme: contextTheme } = useReactBridgeContext();
4229
+ const theme = themeProp || contextTheme;
4230
+ const dateRange = useDateRange(defaultDateRange);
4231
+ const { data, loading, error } = useReportData(() => api.getDataQualityAutomation({
4232
+ startDate: dateRange.startDate,
4233
+ endDate: dateRange.endDate,
4234
+ }), [dateRange.startDate, dateRange.endDate]);
4235
+ const dataGapColumns = [
4236
+ {
4237
+ key: "fieldName",
4238
+ label: "Field Name",
4239
+ sortable: true,
4240
+ },
4241
+ {
4242
+ key: "missingRecords",
4243
+ label: "Missing Records",
4244
+ sortable: true,
4245
+ },
4246
+ {
4247
+ key: "missingPercentage",
4248
+ label: "Missing %",
4249
+ sortable: true,
4250
+ render: (value) => `${value.toFixed(2)}%`,
4251
+ },
4252
+ {
4253
+ key: "impact",
4254
+ label: "Impact",
4255
+ sortable: false,
4256
+ },
4257
+ ];
4258
+ const recommendationColumns = [
4259
+ {
4260
+ key: "category",
4261
+ label: "Category",
4262
+ sortable: true,
4263
+ },
4264
+ {
4265
+ key: "recommendation",
4266
+ label: "Recommendation",
4267
+ sortable: true,
4268
+ },
4269
+ {
4270
+ key: "priority",
4271
+ label: "Priority",
4272
+ sortable: true,
4273
+ render: (value) => {
4274
+ const color = value === "High"
4275
+ ? theme === null || theme === void 0 ? void 0 : theme.colors.error
4276
+ : value === "Medium"
4277
+ ? "#F59E0B"
4278
+ : theme === null || theme === void 0 ? void 0 : theme.colors.success;
4279
+ return React.createElement("span", { style: { color, fontWeight: "600" } }, value);
4280
+ },
4281
+ },
4282
+ {
4283
+ key: "expectedBenefit",
4284
+ label: "Expected Benefit",
4285
+ sortable: false,
4286
+ },
4287
+ ];
4288
+ return (React.createElement(ReportLayout, { title: "Data Quality & Automation", description: "Data quality assessment and automation opportunities", selectedDateRange: dateRange.selectedOption, onDateRangeChange: dateRange.setSelectedOption, loading: loading, error: error, theme: theme },
4289
+ React.createElement("div", { style: {
4290
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px",
4291
+ border: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
4292
+ borderRadius: (theme === null || theme === void 0 ? void 0 : theme.borderRadius) || "8px",
4293
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.surface) || "#f5f5f5",
4294
+ } },
4295
+ React.createElement("h3", { style: {
4296
+ margin: `0 0 ${(theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px"} 0`,
4297
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.lg) || "18px",
4298
+ fontWeight: "600",
4299
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.text) || "#000",
4300
+ } }, "Data Quality Assessment"),
4301
+ React.createElement("div", { style: {
4302
+ display: "flex",
4303
+ flexDirection: "column",
4304
+ gap: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px",
4305
+ } },
4306
+ React.createElement(ProgressBar, { percentage: (_a = data === null || data === void 0 ? void 0 : data.overallDataQualityScore) !== null && _a !== void 0 ? _a : 0, label: "Overall Quality Score", theme: theme, height: "large" }),
4307
+ React.createElement(ProgressBar, { percentage: (_b = data === null || data === void 0 ? void 0 : data.completenessScore) !== null && _b !== void 0 ? _b : 0, label: "Completeness", theme: theme }),
4308
+ React.createElement(ProgressBar, { percentage: (_c = data === null || data === void 0 ? void 0 : data.accuracyScore) !== null && _c !== void 0 ? _c : 0, label: "Accuracy", theme: theme }),
4309
+ React.createElement(ProgressBar, { percentage: (_d = data === null || data === void 0 ? void 0 : data.consistencyScore) !== null && _d !== void 0 ? _d : 0, label: "Consistency", theme: theme })),
4310
+ React.createElement("div", { style: {
4311
+ display: "grid",
4312
+ gridTemplateColumns: "repeat(auto-fit, minmax(150px, 1fr))",
4313
+ gap: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px",
4314
+ marginTop: (theme === null || theme === void 0 ? void 0 : theme.spacing.lg) || "24px",
4315
+ } },
4316
+ React.createElement("div", { style: {
4317
+ textAlign: "center",
4318
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.sm) || "8px",
4319
+ } },
4320
+ React.createElement("p", { style: {
4321
+ margin: 0,
4322
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.sm) || "14px",
4323
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666",
4324
+ } }, "Total Records Analyzed"),
4325
+ React.createElement("p", { style: {
4326
+ margin: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px"} 0 0 0`,
4327
+ fontSize: "20px",
4328
+ fontWeight: "600",
4329
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.text) || "#000",
4330
+ } }, (_e = data === null || data === void 0 ? void 0 : data.totalRecordsAnalyzed) !== null && _e !== void 0 ? _e : 0)),
4331
+ React.createElement("div", { style: {
4332
+ textAlign: "center",
4333
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.sm) || "8px",
4334
+ } },
4335
+ React.createElement("p", { style: {
4336
+ margin: 0,
4337
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.sm) || "14px",
4338
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666",
4339
+ } }, "Records with Issues"),
4340
+ React.createElement("p", { style: {
4341
+ margin: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px"} 0 0 0`,
4342
+ fontSize: "20px",
4343
+ fontWeight: "600",
4344
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.error) || "#f44336",
4345
+ } }, (_f = data === null || data === void 0 ? void 0 : data.recordsWithIssues) !== null && _f !== void 0 ? _f : 0)))),
4346
+ React.createElement("div", { style: {
4347
+ display: "grid",
4348
+ gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))",
4349
+ gap: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px",
4350
+ } },
4351
+ React.createElement("div", { style: {
4352
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px",
4353
+ border: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
4354
+ borderRadius: (theme === null || theme === void 0 ? void 0 : theme.borderRadius) || "8px",
4355
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.surface) || "#f5f5f5",
4356
+ } },
4357
+ React.createElement("h4", { style: {
4358
+ margin: `0 0 ${(theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px"} 0`,
4359
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.md) || "16px",
4360
+ fontWeight: "600",
4361
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.text) || "#000",
4362
+ } }, "Automation Readiness"),
4363
+ React.createElement("div", { style: {
4364
+ marginBottom: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px",
4365
+ } },
4366
+ React.createElement(ProgressBar, { percentage: (_h = (_g = data === null || data === void 0 ? void 0 : data.automationOpportunities) === null || _g === void 0 ? void 0 : _g.automationReadinessScore) !== null && _h !== void 0 ? _h : 0, label: "Readiness Score", theme: theme, height: "large" })),
4367
+ React.createElement("div", { style: {
4368
+ display: "flex",
4369
+ flexDirection: "column",
4370
+ gap: (theme === null || theme === void 0 ? void 0 : theme.spacing.sm) || "8px",
4371
+ } },
4372
+ React.createElement("div", { style: {
4373
+ display: "flex",
4374
+ justifyContent: "space-between",
4375
+ padding: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px"} 0`,
4376
+ } },
4377
+ React.createElement("span", { style: { color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666" } }, "Fully Automatable:"),
4378
+ React.createElement("span", { style: { fontWeight: "600" } }, (_k = (_j = data === null || data === void 0 ? void 0 : data.automationOpportunities) === null || _j === void 0 ? void 0 : _j.fullyAutomatable) !== null && _k !== void 0 ? _k : 0)),
4379
+ React.createElement("div", { style: {
4380
+ display: "flex",
4381
+ justifyContent: "space-between",
4382
+ padding: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px"} 0`,
4383
+ } },
4384
+ React.createElement("span", { style: { color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666" } }, "Partially Automatable:"),
4385
+ React.createElement("span", { style: { fontWeight: "600" } }, (_m = (_l = data === null || data === void 0 ? void 0 : data.automationOpportunities) === null || _l === void 0 ? void 0 : _l.partiallyAutomatable) !== null && _m !== void 0 ? _m : 0)),
4386
+ React.createElement("div", { style: {
4387
+ display: "flex",
4388
+ justifyContent: "space-between",
4389
+ padding: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px"} 0`,
4390
+ } },
4391
+ React.createElement("span", { style: { color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666" } }, "Manual Only:"),
4392
+ React.createElement("span", { style: { fontWeight: "600" } }, (_p = (_o = data === null || data === void 0 ? void 0 : data.automationOpportunities) === null || _o === void 0 ? void 0 : _o.manualOnly) !== null && _p !== void 0 ? _p : 0))))),
4393
+ (data === null || data === void 0 ? void 0 : data.identifiedDataGaps) && data.identifiedDataGaps.length > 0 && (React.createElement("div", null,
4394
+ React.createElement(DataTable, { title: "Identified Data Gaps", columns: dataGapColumns, data: data.identifiedDataGaps.map((gap, idx) => (Object.assign({ id: idx }, gap))), pageSize: 10, theme: theme }))),
4395
+ (data === null || data === void 0 ? void 0 : data.recommendations) && data.recommendations.length > 0 && (React.createElement("div", null,
4396
+ React.createElement(DataTable, { title: "Recommendations", columns: recommendationColumns, data: data.recommendations.map((rec, idx) => (Object.assign({ id: idx }, rec))), pageSize: 10, theme: theme })))));
4397
+ };
4398
+
4399
+ /**
4400
+ * Reports Dashboard
4401
+ * Main container that displays all 5 reports with navigation
4402
+ */
4403
+ const REPORTS = [
4404
+ {
4405
+ id: "executive",
4406
+ label: "Executive Dashboard",
4407
+ icon: "📊",
4408
+ description: "High-level directive execution metrics",
4409
+ },
4410
+ {
4411
+ id: "risk",
4412
+ label: "Supply Chain Risk",
4413
+ icon: "⚠️",
4414
+ description: "Risk analysis and supply chain health",
4415
+ },
4416
+ {
4417
+ id: "audit",
4418
+ label: "Execution Audit",
4419
+ icon: "✓",
4420
+ description: "Directive execution history and audit trail",
4421
+ },
4422
+ {
4423
+ id: "health",
4424
+ label: "Portfolio Health",
4425
+ icon: "❤️",
4426
+ description: "Portfolio metric health and critical alerts",
4427
+ },
4428
+ {
4429
+ id: "quality",
4430
+ label: "Data Quality",
4431
+ icon: "📈",
4432
+ description: "Data quality and automation assessment",
4433
+ },
4434
+ ];
4435
+ const ReportsDashboard = ({ theme, initialReport = "executive", }) => {
4436
+ const [activeReport, setActiveReport] = React.useState(initialReport);
4437
+ const containerStyle = {
4438
+ minHeight: "100vh",
4439
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.background) || "#fff",
4440
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.text) || "#000",
4441
+ };
4442
+ const navContainerStyle = {
4443
+ borderBottom: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
4444
+ backgroundColor: (theme === null || theme === void 0 ? void 0 : theme.colors.surface) || "#f5f5f5",
4445
+ };
4446
+ const navWrapperStyle = {
4447
+ maxWidth: "1400px",
4448
+ margin: "0 auto",
4449
+ padding: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px"} ${(theme === null || theme === void 0 ? void 0 : theme.spacing.lg) || "24px"}`,
4450
+ display: "flex",
4451
+ gap: (theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px",
4452
+ overflowX: "auto",
4453
+ scrollBehavior: "smooth",
4454
+ };
4455
+ const navButtonStyle = (isActive) => ({
4456
+ padding: `${(theme === null || theme === void 0 ? void 0 : theme.spacing.sm) || "8px"} ${(theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px"}`,
4457
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.sm) || "14px",
4458
+ fontWeight: "500",
4459
+ borderRadius: (theme === null || theme === void 0 ? void 0 : theme.borderRadius) || "8px",
4460
+ border: "none",
4461
+ cursor: "pointer",
4462
+ transition: "all 0.2s ease",
4463
+ backgroundColor: isActive
4464
+ ? (theme === null || theme === void 0 ? void 0 : theme.colors.primary) || "#1976d2"
4465
+ : (theme === null || theme === void 0 ? void 0 : theme.colors.background) || "#fff",
4466
+ color: isActive ? "#fff" : (theme === null || theme === void 0 ? void 0 : theme.colors.text) || "#000",
4467
+ whiteSpace: "nowrap",
4468
+ display: "flex",
4469
+ alignItems: "center",
4470
+ gap: (theme === null || theme === void 0 ? void 0 : theme.spacing.xs) || "4px",
4471
+ });
4472
+ const contentStyle = {
4473
+ maxWidth: "1400px",
4474
+ margin: "0 auto",
4475
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.lg) || "24px",
4476
+ };
4477
+ return (React.createElement("div", { style: containerStyle },
4478
+ React.createElement("div", { style: navContainerStyle },
4479
+ React.createElement("div", { style: navWrapperStyle }, REPORTS.map((report) => (React.createElement("button", { key: report.id, onClick: () => setActiveReport(report.id), style: navButtonStyle(activeReport === report.id), title: report.description },
4480
+ React.createElement("span", null, report.icon),
4481
+ React.createElement("span", null, report.label)))))),
4482
+ React.createElement("div", { style: contentStyle },
4483
+ activeReport === "executive" && React.createElement(ExecutiveDashboard, { theme: theme }),
4484
+ activeReport === "risk" && React.createElement(SupplyChainRisk, { theme: theme }),
4485
+ activeReport === "audit" && React.createElement(ExecutionAuditTrail, { theme: theme }),
4486
+ activeReport === "health" && React.createElement(PortfolioHealth, { theme: theme }),
4487
+ activeReport === "quality" && React.createElement(DataQualityAutomation, { theme: theme }))));
4488
+ };
4489
+
4490
+ /**
4491
+ * RiskMatrix Component
4492
+ * 2D visualization of risk items (probability vs impact)
4493
+ */
4494
+ const RiskMatrix = ({ items, title, height = 300, theme, }) => {
4495
+ if (!items || items.length === 0) {
4496
+ return (React.createElement("div", { style: {
4497
+ padding: (theme === null || theme === void 0 ? void 0 : theme.spacing.lg) || "24px",
4498
+ textAlign: "center",
4499
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666",
4500
+ } }, "No risk data available"));
4501
+ }
4502
+ const padding = 50;
4503
+ const width = 500;
4504
+ const innerWidth = width - padding * 2;
4505
+ const innerHeight = height - padding * 2;
4506
+ const getRiskColor = (severity) => {
4507
+ if (severity === "high")
4508
+ return (theme === null || theme === void 0 ? void 0 : theme.colors.error) || "#ef4444";
4509
+ if (severity === "medium")
4510
+ return "#F59E0B";
4511
+ return (theme === null || theme === void 0 ? void 0 : theme.colors.success) || "#10B981";
4512
+ };
4513
+ return (React.createElement("div", null,
4514
+ title && (React.createElement("h3", { style: {
4515
+ margin: `0 0 ${(theme === null || theme === void 0 ? void 0 : theme.spacing.md) || "16px"} 0`,
4516
+ fontSize: (theme === null || theme === void 0 ? void 0 : theme.fontSizes.md) || "16px",
4517
+ fontWeight: "600",
4518
+ color: (theme === null || theme === void 0 ? void 0 : theme.colors.text) || "#000",
4519
+ } }, title)),
4520
+ React.createElement("svg", { width: "100%", height: height, viewBox: `0 0 ${width} ${height}`, preserveAspectRatio: "xMidYMid meet", style: {
4521
+ border: `1px solid ${(theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0"}`,
4522
+ borderRadius: "8px",
4523
+ } },
4524
+ React.createElement("rect", { x: padding + innerWidth / 2, y: padding, width: innerWidth / 2, height: innerHeight / 2, fill: "#ef4444", opacity: "0.05" }),
4525
+ React.createElement("rect", { x: padding, y: padding, width: innerWidth / 2, height: innerHeight / 2, fill: "#F59E0B", opacity: "0.05" }),
4526
+ React.createElement("rect", { x: padding + innerWidth / 2, y: padding + innerHeight / 2, width: innerWidth / 2, height: innerHeight / 2, fill: "#F59E0B", opacity: "0.05" }),
4527
+ React.createElement("rect", { x: padding, y: padding + innerHeight / 2, width: innerWidth / 2, height: innerHeight / 2, fill: "#10B981", opacity: "0.05" }),
4528
+ React.createElement("line", { x1: padding, y1: padding + innerHeight / 2, x2: width - padding, y2: padding + innerHeight / 2, stroke: (theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0", strokeWidth: "2" }),
4529
+ React.createElement("line", { x1: padding + innerWidth / 2, y1: padding, x2: padding + innerWidth / 2, y2: height - padding, stroke: (theme === null || theme === void 0 ? void 0 : theme.colors.border) || "#e0e0e0", strokeWidth: "2" }),
4530
+ React.createElement("text", { x: width / 2, y: height - 5, textAnchor: "middle", fontSize: "12", fill: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666", fontWeight: "500" }, "Probability"),
4531
+ React.createElement("text", { x: 15, y: height / 2, textAnchor: "middle", fontSize: "12", fill: (theme === null || theme === void 0 ? void 0 : theme.colors.textSecondary) || "#666", fontWeight: "500", transform: `rotate(-90 15 ${height / 2})` }, "Impact"),
4532
+ items.map((item) => {
4533
+ const x = padding + (item.probability / 100) * innerWidth;
4534
+ const y = padding + innerHeight - (item.impact / 100) * innerHeight;
4535
+ return (React.createElement("g", { key: item.id },
4536
+ React.createElement("circle", { cx: x, cy: y, r: "6", fill: getRiskColor(item.severity), opacity: "0.7", style: { cursor: "pointer" } }),
4537
+ React.createElement("circle", { cx: x, cy: y, r: "6", fill: "none", stroke: getRiskColor(item.severity), strokeWidth: "2", opacity: "0.4" })));
4538
+ }))));
4539
+ };
4540
+
2592
4541
  exports.AnalyticsAPI = AnalyticsAPI;
2593
4542
  exports.AnalyticsDashboard = AnalyticsDashboard;
2594
4543
  exports.AnalyticsReport = AnalyticsReport;
2595
4544
  exports.AnalyticsWidget = AnalyticsWidget;
4545
+ exports.DataQualityAutomation = DataQualityAutomation;
4546
+ exports.DataTable = DataTable;
4547
+ exports.DateRangeSelector = DateRangeSelector;
4548
+ exports.DateRangeService = DateRangeService;
2596
4549
  exports.DirectivesPanel = DirectivesPanel;
4550
+ exports.ExecutionAuditTrail = ExecutionAuditTrail;
4551
+ exports.ExecutiveDashboard = ExecutiveDashboard;
4552
+ exports.HealthGauge = HealthGauge;
4553
+ exports.LoadingState = LoadingState;
4554
+ exports.MetricCard = MetricCard;
2597
4555
  exports.MetricsPanel = MetricsPanel;
2598
4556
  exports.ObservationsPanel = ObservationsPanel;
4557
+ exports.PortfolioHealth = PortfolioHealth;
4558
+ exports.ProgressBar = ProgressBar;
2599
4559
  exports.ReactBridgeAPI = ReactBridgeAPI;
2600
4560
  exports.ReactBridgeChatbox = ReactBridgeChatbox;
2601
4561
  exports.ReactBridgeProvider = ReactBridgeProvider;
2602
4562
  exports.ReactBridgeSearch = ReactBridgeSearch;
4563
+ exports.ReportLayout = ReportLayout;
4564
+ exports.ReportsDashboard = ReportsDashboard;
4565
+ exports.RiskMatrix = RiskMatrix;
4566
+ exports.StatusBadge = StatusBadge;
4567
+ exports.SupplyChainRisk = SupplyChainRisk;
4568
+ exports.TrendChart = TrendChart;
2603
4569
  exports.WebSpeechSTTProvider = WebSpeechSTTProvider;
2604
4570
  exports.WebSpeechTTSProvider = WebSpeechTTSProvider;
2605
4571
  exports.createCustomTheme = createCustomTheme;
@@ -2608,7 +4574,9 @@ exports.getTheme = getTheme;
2608
4574
  exports.lightTheme = lightTheme;
2609
4575
  exports.useAnalyticsConfigs = useAnalyticsConfigs;
2610
4576
  exports.useAnalyticsResult = useAnalyticsResult;
4577
+ exports.useDateRange = useDateRange;
2611
4578
  exports.useDirectiveAction = useDirectiveAction;
2612
4579
  exports.useReactBridge = useReactBridge;
2613
4580
  exports.useReactBridgeContext = useReactBridgeContext;
4581
+ exports.useReportData = useReportData;
2614
4582
  //# sourceMappingURL=index.js.map