@echothink-ui/admin 0.1.0

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 (48) hide show
  1. package/README.md +5 -0
  2. package/dist/components/AdminHealthTemplate.d.ts +5 -0
  3. package/dist/components/AdminShell.d.ts +8 -0
  4. package/dist/components/AuditLogViewer.d.ts +9 -0
  5. package/dist/components/BillingUsagePanel.d.ts +7 -0
  6. package/dist/components/FeatureFlagPanel.d.ts +8 -0
  7. package/dist/components/IntegrationHealthTable.d.ts +6 -0
  8. package/dist/components/JobQueuePanel.d.ts +7 -0
  9. package/dist/components/PolicyConfigPanel.d.ts +9 -0
  10. package/dist/components/QueueDepthChart.d.ts +6 -0
  11. package/dist/components/RateLimitPanel.d.ts +7 -0
  12. package/dist/components/RuntimeLogViewer.d.ts +10 -0
  13. package/dist/components/ServiceStatusCard.d.ts +7 -0
  14. package/dist/components/SystemHealthDashboard.d.ts +8 -0
  15. package/dist/components/TenantSettingsPanel.d.ts +11 -0
  16. package/dist/components/WorkerPoolPanel.d.ts +7 -0
  17. package/dist/components/types.d.ts +114 -0
  18. package/dist/index.cjs +1835 -0
  19. package/dist/index.cjs.map +1 -0
  20. package/dist/index.css +1711 -0
  21. package/dist/index.css.map +1 -0
  22. package/dist/index.d.ts +19 -0
  23. package/dist/index.js +1812 -0
  24. package/dist/index.js.map +1 -0
  25. package/package.json +46 -0
  26. package/src/components/AdminHealthTemplate.tsx +25 -0
  27. package/src/components/AdminShell.tsx +48 -0
  28. package/src/components/AuditLogViewer.tsx +96 -0
  29. package/src/components/BillingUsagePanel.tsx +171 -0
  30. package/src/components/FeatureFlagPanel.tsx +178 -0
  31. package/src/components/IntegrationHealthTable.tsx +196 -0
  32. package/src/components/JobQueuePanel.tsx +171 -0
  33. package/src/components/PolicyConfigPanel.test.tsx +45 -0
  34. package/src/components/PolicyConfigPanel.tsx +131 -0
  35. package/src/components/QueueDepthChart.tsx +70 -0
  36. package/src/components/RateLimitPanel.test.tsx +29 -0
  37. package/src/components/RateLimitPanel.tsx +249 -0
  38. package/src/components/RuntimeLogViewer.test.tsx +60 -0
  39. package/src/components/RuntimeLogViewer.tsx +185 -0
  40. package/src/components/ServiceStatusCard.tsx +91 -0
  41. package/src/components/SystemHealthDashboard.tsx +214 -0
  42. package/src/components/TenantSettingsPanel.test.tsx +38 -0
  43. package/src/components/TenantSettingsPanel.tsx +44 -0
  44. package/src/components/WorkerPoolPanel.test.tsx +32 -0
  45. package/src/components/WorkerPoolPanel.tsx +281 -0
  46. package/src/components/types.ts +131 -0
  47. package/src/index.tsx +37 -0
  48. package/src/styles.css +2024 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,1835 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.tsx
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ AdminComponentNames: () => AdminComponentNames,
34
+ AdminHealthTemplate: () => AdminHealthTemplate,
35
+ AdminShell: () => AdminShell,
36
+ AuditLogViewer: () => AuditLogViewer,
37
+ BillingUsagePanel: () => BillingUsagePanel,
38
+ FeatureFlagPanel: () => FeatureFlagPanel,
39
+ IntegrationHealthTable: () => IntegrationHealthTable,
40
+ JobQueuePanel: () => JobQueuePanel,
41
+ PolicyConfigPanel: () => PolicyConfigPanel,
42
+ QueueDepthChart: () => QueueDepthChart,
43
+ RateLimitPanel: () => RateLimitPanel,
44
+ RuntimeLogViewer: () => RuntimeLogViewer,
45
+ ServiceStatusCard: () => ServiceStatusCard,
46
+ SystemHealthDashboard: () => SystemHealthDashboard,
47
+ TenantSettingsPanel: () => TenantSettingsPanel,
48
+ WorkerPoolPanel: () => WorkerPoolPanel,
49
+ severityForStatus: () => severityForStatus
50
+ });
51
+ module.exports = __toCommonJS(index_exports);
52
+
53
+ // src/components/AdminShell.tsx
54
+ var import_layouts = require("@echothink-ui/layouts");
55
+ var import_jsx_runtime = require("react/jsx-runtime");
56
+ function AdminShell({
57
+ sideNav,
58
+ header,
59
+ children,
60
+ className,
61
+ title: _title,
62
+ subtitle: _subtitle,
63
+ description: _description,
64
+ eyebrow: _eyebrow,
65
+ density: _density,
66
+ status: _status,
67
+ severity: _severity,
68
+ loading: _loading,
69
+ empty: _empty,
70
+ error: _error,
71
+ items: _items,
72
+ actions: _actions,
73
+ metadata: _metadata,
74
+ footer: _footer,
75
+ ...props
76
+ }) {
77
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
78
+ import_layouts.TemplateShell,
79
+ {
80
+ ...props,
81
+ className: ["eth-admin-shell", className].filter(Boolean).join(" "),
82
+ "data-eth-component": "AdminShell",
83
+ canvas: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "eth-admin-shell__layout", children: [
84
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("aside", { className: "eth-admin-shell__side-nav", children: sideNav }),
85
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "eth-admin-shell__workspace", children: [
86
+ header ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("header", { className: "eth-admin-shell__header", children: header }) : null,
87
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("main", { className: "eth-admin-shell__main", children })
88
+ ] })
89
+ ] })
90
+ }
91
+ );
92
+ }
93
+
94
+ // src/components/SystemHealthDashboard.tsx
95
+ var import_core2 = require("@echothink-ui/core");
96
+ var import_charts = require("@echothink-ui/charts");
97
+
98
+ // src/components/ServiceStatusCard.tsx
99
+ var import_core = require("@echothink-ui/core");
100
+ var import_jsx_runtime2 = require("react/jsx-runtime");
101
+ var percentFormatter = new Intl.NumberFormat("en", { maximumFractionDigits: 2 });
102
+ function ServiceStatusCard({ service, className, ...props }) {
103
+ const statusSeverity2 = severityForStatus(service.status);
104
+ const statusText = statusLabel(service.status);
105
+ const metrics = [
106
+ {
107
+ label: "Latency",
108
+ value: service.latencyMs !== void 0 ? `${service.latencyMs} ms` : "Unavailable",
109
+ muted: service.latencyMs === void 0
110
+ },
111
+ {
112
+ label: "Uptime",
113
+ value: service.uptimePercent !== void 0 ? formatPercent(service.uptimePercent) : "Not reported",
114
+ muted: service.uptimePercent === void 0
115
+ },
116
+ {
117
+ label: service.incidentsCount !== void 0 ? "Open incidents" : "Last incident",
118
+ value: service.incidentsCount !== void 0 ? service.incidentsCount : service.lastIncidentAt ?? "None reported",
119
+ muted: service.incidentsCount !== void 0 ? service.incidentsCount === 0 : !service.lastIncidentAt
120
+ }
121
+ ];
122
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
123
+ import_core.Surface,
124
+ {
125
+ ...props,
126
+ title: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "eth-admin-service-status-card__title", children: [
127
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: service.name }),
128
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_core.Badge, { "aria-label": `Service status: ${statusText}`, severity: statusSeverity2, children: statusText })
129
+ ] }),
130
+ description: statusDescription(service.status),
131
+ className: [
132
+ "eth-admin-service-status-card",
133
+ `eth-admin-service-status-card--${service.status}`,
134
+ className
135
+ ].filter(Boolean).join(" "),
136
+ "data-eth-component": "ServiceStatusCard",
137
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("dl", { className: "eth-admin-service-status-card__metrics", children: metrics.map((metric) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
138
+ "div",
139
+ {
140
+ className: metric.muted ? "eth-admin-service-status-card__metric--muted" : void 0,
141
+ children: [
142
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("dt", { children: metric.label }),
143
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("dd", { children: metric.value })
144
+ ]
145
+ },
146
+ metric.label
147
+ )) })
148
+ }
149
+ );
150
+ }
151
+ function severityForStatus(status) {
152
+ if (status === "healthy") return "success";
153
+ if (status === "degraded") return "warning";
154
+ return "danger";
155
+ }
156
+ function statusLabel(status) {
157
+ if (status === "healthy") return "Healthy";
158
+ if (status === "degraded") return "Degraded";
159
+ return "Down";
160
+ }
161
+ function statusDescription(status) {
162
+ if (status === "healthy") return "Operational within expected thresholds";
163
+ if (status === "degraded") return "Elevated latency or partial failures detected";
164
+ return "Service unavailable or actively failing";
165
+ }
166
+ function formatPercent(value) {
167
+ return `${percentFormatter.format(value)}%`;
168
+ }
169
+
170
+ // src/components/SystemHealthDashboard.tsx
171
+ var import_jsx_runtime3 = require("react/jsx-runtime");
172
+ function SystemHealthDashboard({
173
+ services,
174
+ incidents = [],
175
+ metrics = [],
176
+ title,
177
+ description,
178
+ severity,
179
+ status,
180
+ className,
181
+ ...props
182
+ }) {
183
+ const serviceCount = services.length;
184
+ const healthyCount = services.filter((service) => service.status === "healthy").length;
185
+ const degradedCount = services.filter((service) => service.status === "degraded").length;
186
+ const downCount = services.filter((service) => service.status === "down").length;
187
+ const criticalIncidentCount = incidents.filter(
188
+ (incident) => incident.severity === "critical" || incident.severity === "error"
189
+ ).length;
190
+ const openIncidentCount = incidents.length;
191
+ const defaultSeverity = severityForHealth(
192
+ downCount,
193
+ degradedCount,
194
+ criticalIncidentCount,
195
+ openIncidentCount
196
+ );
197
+ const defaultStatus = statusForHealth(serviceCount, downCount, degradedCount);
198
+ const computedMetrics = metrics.length ? metrics : [
199
+ {
200
+ label: "Healthy services",
201
+ value: serviceCount ? `${healthyCount} / ${serviceCount}` : "0",
202
+ trend: serviceHealthTrend(healthyCount, degradedCount, downCount)
203
+ },
204
+ {
205
+ label: "Open incidents",
206
+ value: openIncidentCount,
207
+ trend: incidentTrend(criticalIncidentCount, openIncidentCount)
208
+ },
209
+ {
210
+ label: "Avg latency",
211
+ value: average(
212
+ services.map((service) => service.latencyMs).filter((value) => value !== void 0)
213
+ ),
214
+ trend: serviceCount ? `${serviceCount} monitored` : void 0
215
+ }
216
+ ];
217
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
218
+ import_core2.Surface,
219
+ {
220
+ ...props,
221
+ title: title ?? "System health",
222
+ description: description ?? healthSummary(serviceCount, healthyCount, degradedCount, downCount, openIncidentCount),
223
+ severity: severity ?? defaultSeverity,
224
+ status: status ?? defaultStatus,
225
+ className: ["eth-admin-system-health", className].filter(Boolean).join(" "),
226
+ "data-eth-component": "SystemHealthDashboard",
227
+ children: [
228
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "eth-admin-system-health__metrics", children: computedMetrics.map((metric) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
229
+ import_charts.KPIBlock,
230
+ {
231
+ title: metric.label,
232
+ value: metric.value,
233
+ status: metric.trend
234
+ },
235
+ String(metric.label)
236
+ )) }),
237
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "eth-admin-system-health__services", children: services.length ? services.map((service) => {
238
+ const serviceIncidents = incidents.filter(
239
+ (incident) => incident.title.toLowerCase().includes(service.name.toLowerCase())
240
+ );
241
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
242
+ ServiceStatusCard,
243
+ {
244
+ service: {
245
+ name: service.name,
246
+ status: service.status,
247
+ latencyMs: service.latencyMs,
248
+ uptimePercent: service.status === "healthy" ? 99.9 : void 0,
249
+ incidentsCount: service.incidentsCount ?? serviceIncidents.length,
250
+ lastIncidentAt: serviceIncidents[0]?.startedAt
251
+ }
252
+ },
253
+ service.id
254
+ );
255
+ }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "eth-admin-system-health__empty", children: "No services are currently registered." }) }),
256
+ incidents.length ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { className: "eth-admin-system-health__incidents", children: [
257
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { children: "Incidents" }),
258
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ul", { children: incidents.map((incident) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("li", { children: [
259
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_core2.Badge, { severity: severityForIncident(incident.severity), children: incident.severity }),
260
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: incident.title }),
261
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("time", { children: incident.startedAt })
262
+ ] }, incident.id)) })
263
+ ] }) : null
264
+ ]
265
+ }
266
+ );
267
+ }
268
+ function average(values) {
269
+ if (!values.length) return "0 ms";
270
+ return `${Math.round(values.reduce((sum, value) => sum + value, 0) / values.length)} ms`;
271
+ }
272
+ function healthSummary(serviceCount, healthyCount, degradedCount, downCount, openIncidentCount) {
273
+ if (!serviceCount) return "No services registered for this tenant.";
274
+ const exceptions = [];
275
+ if (degradedCount) exceptions.push(`${degradedCount} degraded`);
276
+ if (downCount) exceptions.push(`${downCount} down`);
277
+ if (openIncidentCount) {
278
+ exceptions.push(`${openIncidentCount} open ${pluralize(openIncidentCount, "incident")}`);
279
+ }
280
+ const serviceSummary = `${healthyCount} of ${serviceCount} ${pluralize(serviceCount, "service")} healthy`;
281
+ return exceptions.length ? `${serviceSummary}; ${exceptions.join(", ")}.` : `${serviceSummary}; no open incidents.`;
282
+ }
283
+ function serviceHealthTrend(healthyCount, degradedCount, downCount) {
284
+ if (downCount) {
285
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_core2.Badge, { severity: "danger", children: `${downCount} down` });
286
+ }
287
+ if (degradedCount) {
288
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_core2.Badge, { severity: "warning", children: `${degradedCount} degraded` });
289
+ }
290
+ if (healthyCount) {
291
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_core2.Badge, { severity: "success", children: "Nominal" });
292
+ }
293
+ return void 0;
294
+ }
295
+ function incidentTrend(criticalIncidentCount, openIncidentCount) {
296
+ if (criticalIncidentCount) {
297
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_core2.Badge, { severity: "danger", children: `${criticalIncidentCount} critical` });
298
+ }
299
+ if (openIncidentCount) {
300
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_core2.Badge, { severity: "warning", children: "Investigating" });
301
+ }
302
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_core2.Badge, { severity: "success", children: "Clear" });
303
+ }
304
+ function severityForHealth(downCount, degradedCount, criticalIncidentCount, openIncidentCount) {
305
+ if (downCount || criticalIncidentCount) return "danger";
306
+ if (degradedCount || openIncidentCount) return "warning";
307
+ return void 0;
308
+ }
309
+ function statusForHealth(serviceCount, downCount, degradedCount) {
310
+ if (!serviceCount) return "inactive";
311
+ if (downCount) return "failed";
312
+ if (degradedCount) return "warning";
313
+ return "active";
314
+ }
315
+ function pluralize(count, singular) {
316
+ return count === 1 ? singular : `${singular}s`;
317
+ }
318
+ function severityForIncident(severity) {
319
+ if (severity === "critical" || severity === "error") return "danger";
320
+ if (severity === "warning") return "warning";
321
+ return "info";
322
+ }
323
+
324
+ // src/components/WorkerPoolPanel.tsx
325
+ var React = __toESM(require("react"), 1);
326
+ var import_core3 = require("@echothink-ui/core");
327
+ var import_data = require("@echothink-ui/data");
328
+ var import_jsx_runtime4 = require("react/jsx-runtime");
329
+ function WorkerPoolPanel({
330
+ pools,
331
+ onScale,
332
+ title = "Worker pools",
333
+ subtitle,
334
+ description,
335
+ actions,
336
+ density = "compact",
337
+ className,
338
+ "aria-label": ariaLabel,
339
+ "aria-labelledby": ariaLabelledBy,
340
+ eyebrow: _eyebrow,
341
+ status: _status,
342
+ severity: _severity,
343
+ loading: _loading,
344
+ empty: _empty,
345
+ error: _error,
346
+ items: _items,
347
+ metadata: _metadata,
348
+ footer: _footer,
349
+ ...sectionProps
350
+ }) {
351
+ const headingId = React.useId();
352
+ const rows = pools.map((pool) => {
353
+ const percent = pool.total > 0 ? pool.active / pool.total * 100 : 0;
354
+ const cappedPercent = Math.min(100, Math.max(0, percent));
355
+ return {
356
+ ...pool,
357
+ cappedPercent,
358
+ capacityLabel: pool.total > 0 ? `${formatNumber(pool.active)} / ${formatNumber(pool.total)} active` : `${formatNumber(pool.active)} active`,
359
+ percent,
360
+ percentLabel: pool.total > 0 ? formatPercent2(percent) : "No capacity",
361
+ state: workerPoolState(pool, percent)
362
+ };
363
+ });
364
+ const totals = pools.reduce(
365
+ (summary, pool) => ({
366
+ active: summary.active + pool.active,
367
+ failed: summary.failed + pool.failed,
368
+ idle: summary.idle + pool.idle,
369
+ total: summary.total + pool.total
370
+ }),
371
+ { active: 0, failed: 0, idle: 0, total: 0 }
372
+ );
373
+ const utilization = totals.total > 0 ? totals.active / totals.total * 100 : 0;
374
+ const statusSummary = workerPoolStatusSummary(pools.length, totals.failed, utilization);
375
+ const supportingText = subtitle ?? description;
376
+ const columns = [
377
+ {
378
+ key: "name",
379
+ header: "Pool",
380
+ width: "26%",
381
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "eth-admin-worker-pool__pool", children: [
382
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: row.name }),
383
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: row.state.label })
384
+ ] })
385
+ },
386
+ {
387
+ key: "active",
388
+ header: "Capacity",
389
+ width: "34%",
390
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "eth-admin-worker-pool__capacity", children: [
391
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "eth-admin-worker-pool__capacity-copy", children: [
392
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: row.capacityLabel }),
393
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: row.percentLabel })
394
+ ] }),
395
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
396
+ "span",
397
+ {
398
+ className: "eth-admin-worker-pool__meter",
399
+ role: "progressbar",
400
+ "aria-label": `${row.name} capacity`,
401
+ "aria-valuemin": 0,
402
+ "aria-valuemax": 100,
403
+ "aria-valuenow": Math.round(row.cappedPercent),
404
+ "aria-valuetext": `${formatNumber(row.active)} of ${formatNumber(
405
+ row.total
406
+ )} workers active`,
407
+ style: {
408
+ "--eth-admin-worker-pool-capacity": `${row.cappedPercent}%`
409
+ },
410
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
411
+ "span",
412
+ {
413
+ className: [
414
+ "eth-admin-worker-pool__meter-fill",
415
+ `eth-admin-worker-pool__meter-fill--${row.state.tone}`
416
+ ].join(" ")
417
+ }
418
+ )
419
+ }
420
+ )
421
+ ] })
422
+ },
423
+ {
424
+ key: "idle",
425
+ header: "Idle",
426
+ align: "end",
427
+ width: "12%",
428
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "eth-admin-worker-pool__number", children: formatNumber(row.idle) })
429
+ },
430
+ {
431
+ key: "failed",
432
+ header: "Failed",
433
+ align: "end",
434
+ width: "12%",
435
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core3.Badge, { severity: row.failed > 0 ? "danger" : "success", children: formatNumber(row.failed) })
436
+ },
437
+ {
438
+ key: "scale",
439
+ header: "Scale",
440
+ align: "end",
441
+ width: "10rem",
442
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
443
+ "div",
444
+ {
445
+ className: "eth-admin-worker-pool__scale",
446
+ role: "group",
447
+ "aria-label": `${row.name} scale controls`,
448
+ children: [
449
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
450
+ import_core3.Button,
451
+ {
452
+ type: "button",
453
+ intent: "ghost",
454
+ density: "compact",
455
+ className: "eth-admin-worker-pool__scale-button",
456
+ disabled: !onScale,
457
+ "aria-label": `Scale ${row.name} down by 1`,
458
+ onClick: () => onScale?.(row.id, -1),
459
+ children: "-1"
460
+ }
461
+ ),
462
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
463
+ import_core3.Button,
464
+ {
465
+ type: "button",
466
+ intent: "ghost",
467
+ density: "compact",
468
+ className: "eth-admin-worker-pool__scale-button",
469
+ disabled: !onScale,
470
+ "aria-label": `Scale ${row.name} up by 1`,
471
+ onClick: () => onScale?.(row.id, 1),
472
+ children: "+1"
473
+ }
474
+ )
475
+ ]
476
+ }
477
+ )
478
+ }
479
+ ];
480
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
481
+ "section",
482
+ {
483
+ ...sectionProps,
484
+ "aria-label": ariaLabel,
485
+ "aria-labelledby": ariaLabelledBy ?? (ariaLabel ? void 0 : headingId),
486
+ className: ["eth-admin-worker-pool", className].filter(Boolean).join(" "),
487
+ "data-eth-component": "WorkerPoolPanel",
488
+ children: [
489
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("header", { children: [
490
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "eth-admin-worker-pool__heading", children: [
491
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { id: headingId, children: title }),
492
+ supportingText ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: supportingText }) : null
493
+ ] }),
494
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "eth-admin-worker-pool__header-actions", children: [
495
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core3.Badge, { severity: statusSummary.severity, children: statusSummary.label }),
496
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_core3.ActionGroup, { actions })
497
+ ] })
498
+ ] }),
499
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("dl", { className: "eth-admin-worker-pool__summary", "aria-label": "Worker pool totals", children: [
500
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
501
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("dt", { children: "Tracked pools" }),
502
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("dd", { children: formatPoolCount(pools.length) })
503
+ ] }),
504
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
505
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("dt", { children: "Active capacity" }),
506
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("dd", { children: [
507
+ formatNumber(totals.active),
508
+ " / ",
509
+ formatNumber(totals.total)
510
+ ] })
511
+ ] }),
512
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { children: [
513
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("dt", { children: "Failures" }),
514
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("dd", { children: formatFailureCount(totals.failed) })
515
+ ] })
516
+ ] }),
517
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
518
+ import_data.DataTable,
519
+ {
520
+ rows,
521
+ columns,
522
+ rowKey: "id",
523
+ density,
524
+ className: "eth-admin-worker-pool__table",
525
+ emptyState: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "eth-admin-worker-pool__empty", children: "No worker pools are configured." })
526
+ }
527
+ )
528
+ ]
529
+ }
530
+ );
531
+ }
532
+ function workerPoolState(pool, percent) {
533
+ if (pool.failed > 0) return { label: "Failure requires review", tone: "danger" };
534
+ if (pool.total <= 0) return { label: "No capacity", tone: "neutral" };
535
+ if (percent >= 100) return { label: "At capacity", tone: "warning" };
536
+ if (pool.idle > 0) return { label: "Capacity available", tone: "normal" };
537
+ return { label: "Active", tone: "normal" };
538
+ }
539
+ function workerPoolStatusSummary(poolCount, failedCount, utilization) {
540
+ if (poolCount === 0) return { label: "No pools", severity: "neutral" };
541
+ if (failedCount === 1) return { label: "Failure in pool", severity: "danger" };
542
+ if (failedCount > 1) {
543
+ return { label: `${formatNumber(failedCount)} failures`, severity: "danger" };
544
+ }
545
+ if (utilization >= 90) return { label: "Capacity tight", severity: "warning" };
546
+ return { label: "Operational", severity: "success" };
547
+ }
548
+ function formatNumber(value) {
549
+ return new Intl.NumberFormat("en-US").format(value);
550
+ }
551
+ function formatPercent2(value) {
552
+ return `${value.toLocaleString("en-US", { maximumFractionDigits: 0 })}%`;
553
+ }
554
+ function formatPoolCount(value) {
555
+ return `${formatNumber(value)} ${value === 1 ? "pool" : "pools"}`;
556
+ }
557
+ function formatFailureCount(value) {
558
+ return `${formatNumber(value)} failed`;
559
+ }
560
+
561
+ // src/components/JobQueuePanel.tsx
562
+ var React2 = __toESM(require("react"), 1);
563
+ var import_core4 = require("@echothink-ui/core");
564
+ var import_data2 = require("@echothink-ui/data");
565
+ var import_jsx_runtime5 = require("react/jsx-runtime");
566
+ function JobQueuePanel({
567
+ queues,
568
+ actions,
569
+ title = "Job queues",
570
+ subtitle,
571
+ description,
572
+ density = "compact",
573
+ className,
574
+ "aria-labelledby": ariaLabelledBy,
575
+ eyebrow: _eyebrow,
576
+ status: _status,
577
+ severity: _severity,
578
+ loading: _loading,
579
+ empty: _empty,
580
+ error: _error,
581
+ items: _items,
582
+ metadata: _metadata,
583
+ footer: _footer,
584
+ ...props
585
+ }) {
586
+ const headingId = React2.useId();
587
+ const rows = queues.map((queue) => ({ ...queue }));
588
+ const subtitleContent = subtitle ?? description;
589
+ const totals = queues.reduce(
590
+ (summary, queue) => ({
591
+ depth: summary.depth + queue.depth,
592
+ processing: summary.processing + queue.processing,
593
+ failed: summary.failed + queue.failed
594
+ }),
595
+ { depth: 0, processing: 0, failed: 0 }
596
+ );
597
+ const columns = [
598
+ {
599
+ key: "name",
600
+ header: "Queue",
601
+ width: "34%",
602
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "eth-admin-job-queue__queue", children: [
603
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("strong", { children: row.name }),
604
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: queueStateLabel(row) })
605
+ ] })
606
+ },
607
+ {
608
+ key: "depth",
609
+ header: "Depth",
610
+ align: "end",
611
+ width: "16%",
612
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "eth-admin-job-queue__number", children: formatCount(row.depth) })
613
+ },
614
+ {
615
+ key: "processing",
616
+ header: "Processing",
617
+ align: "end",
618
+ width: "18%",
619
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "eth-admin-job-queue__number", children: formatCount(row.processing) })
620
+ },
621
+ {
622
+ key: "failed",
623
+ header: "Failed",
624
+ align: "end",
625
+ width: "14%",
626
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_core4.Badge, { severity: row.failed > 0 ? "danger" : "success", children: formatCount(row.failed) })
627
+ },
628
+ {
629
+ key: "retryRate",
630
+ header: "Retry rate",
631
+ align: "end",
632
+ width: "18%",
633
+ render: (row) => row.retryRate === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "eth-admin-job-queue__muted", children: "n/a" }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_core4.Badge, { severity: retryRateSeverity(row.retryRate), children: formatRetryRate(row.retryRate) })
634
+ }
635
+ ];
636
+ const statusSeverity2 = queues.length === 0 ? "neutral" : totals.failed > 0 ? "danger" : totals.processing > 0 ? "info" : "success";
637
+ const statusLabel3 = queues.length === 0 ? "No queues" : totals.failed > 0 ? "Action needed" : "Operational";
638
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
639
+ "section",
640
+ {
641
+ ...props,
642
+ className: ["eth-admin-job-queue", className].filter(Boolean).join(" "),
643
+ "data-eth-component": "JobQueuePanel",
644
+ "aria-labelledby": ariaLabelledBy ?? headingId,
645
+ children: [
646
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("header", { children: [
647
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "eth-admin-job-queue__heading", children: [
648
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { id: headingId, children: title }),
649
+ subtitleContent ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "eth-admin-job-queue__subtitle", children: subtitleContent }) : null
650
+ ] }),
651
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "eth-admin-job-queue__header-actions", children: [
652
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_core4.Badge, { severity: statusSeverity2, children: statusLabel3 }),
653
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_core4.ActionGroup, { actions })
654
+ ] })
655
+ ] }),
656
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("dl", { className: "eth-admin-job-queue__summary", "aria-label": "Queue totals", children: [
657
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
658
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Total depth" }),
659
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: formatCount(totals.depth) })
660
+ ] }),
661
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
662
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Processing" }),
663
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: formatCount(totals.processing) })
664
+ ] }),
665
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
666
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Failed" }),
667
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: formatCount(totals.failed) })
668
+ ] })
669
+ ] }),
670
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_data2.DataTable, { rows, columns, density })
671
+ ]
672
+ }
673
+ );
674
+ }
675
+ function queueStateLabel(queue) {
676
+ if (queue.failed > 0) return "Failure requires review";
677
+ if (queue.processing > 0) return "Workers active";
678
+ if (queue.depth > 0) return "Waiting for capacity";
679
+ return "Idle";
680
+ }
681
+ function retryRateSeverity(retryRate) {
682
+ if (retryRate >= 1) return "danger";
683
+ if (retryRate > 0.1) return "warning";
684
+ if (retryRate > 0) return "info";
685
+ return "success";
686
+ }
687
+ function formatCount(value) {
688
+ return new Intl.NumberFormat("en-US").format(value);
689
+ }
690
+ function formatRetryRate(value) {
691
+ return `${value.toLocaleString("en-US", { maximumFractionDigits: 2 })}%`;
692
+ }
693
+
694
+ // src/components/QueueDepthChart.tsx
695
+ var import_charts2 = require("@echothink-ui/charts");
696
+ var import_jsx_runtime6 = require("react/jsx-runtime");
697
+ var depthFormatter = new Intl.NumberFormat("en-US", { maximumFractionDigits: 1 });
698
+ var queueDepthSeries = [{ key: "depth", label: "Queue depth", color: "#0f62fe" }];
699
+ function QueueDepthChart({
700
+ points,
701
+ title,
702
+ metadata,
703
+ className,
704
+ ...props
705
+ }) {
706
+ const data = points.map((point, index) => {
707
+ const row = {
708
+ label: point.label ?? point.timestamp ?? String(index + 1),
709
+ depth: point.depth
710
+ };
711
+ return point.timestamp ? { ...row, timestamp: point.timestamp } : row;
712
+ });
713
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
714
+ import_charts2.ChartBlock,
715
+ {
716
+ ...props,
717
+ className: ["eth-admin-queue-depth-chart", className].filter(Boolean).join(" "),
718
+ title: title ?? "Queue depth",
719
+ metadata: metadata ?? queueDepthMetadata(points),
720
+ chartType: "line",
721
+ data,
722
+ valueKey: "depth",
723
+ series: queueDepthSeries,
724
+ "data-eth-component": "QueueDepthChart"
725
+ }
726
+ );
727
+ }
728
+ function queueDepthMetadata(points) {
729
+ const depths = points.map((point) => point.depth).filter(Number.isFinite);
730
+ if (!depths.length) return [];
731
+ const current = depths.at(-1) ?? 0;
732
+ const previous = depths.at(-2);
733
+ const peak = Math.max(...depths);
734
+ const average2 = depths.reduce((total, depth) => total + depth, 0) / depths.length;
735
+ return [
736
+ { label: "Current depth", value: formatDepth(current) },
737
+ { label: "Peak", value: formatDepth(peak) },
738
+ { label: "Average", value: formatDepth(average2) },
739
+ {
740
+ label: "Latest change",
741
+ value: previous === void 0 ? "n/a" : formatDelta(current - previous)
742
+ }
743
+ ];
744
+ }
745
+ function formatDepth(value) {
746
+ return depthFormatter.format(value);
747
+ }
748
+ function formatDelta(value) {
749
+ if (value === 0) return "No change";
750
+ return `${value > 0 ? "+" : ""}${formatDepth(value)}`;
751
+ }
752
+
753
+ // src/components/RuntimeLogViewer.tsx
754
+ var React3 = __toESM(require("react"), 1);
755
+ var import_icons_react = require("@carbon/icons-react");
756
+ var import_core5 = require("@echothink-ui/core");
757
+ var import_data3 = require("@echothink-ui/data");
758
+ var import_jsx_runtime7 = require("react/jsx-runtime");
759
+ function RuntimeLogViewer({
760
+ entries,
761
+ filters,
762
+ onPause,
763
+ streaming = false,
764
+ className,
765
+ title = "Runtime logs",
766
+ subtitle,
767
+ description,
768
+ density = "compact",
769
+ "aria-label": ariaLabel,
770
+ "aria-labelledby": ariaLabelledBy
771
+ }) {
772
+ const headingId = React3.useId();
773
+ const warningCount = countLevel(entries, "warning");
774
+ const errorCount = countLevel(entries, "error");
775
+ const latestTimestamp = entries[entries.length - 1]?.timestamp ?? "No activity";
776
+ const supportingText = subtitle ?? description ?? `${formatEntryCount(entries.length)} buffered from runtime stream.`;
777
+ const hasToolbar = Boolean(filters || streaming && onPause);
778
+ const rows = entries.map((entry) => ({ ...entry }));
779
+ const columns = [
780
+ {
781
+ key: "timestamp",
782
+ header: "Time",
783
+ width: "7rem",
784
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("time", { className: "eth-admin-runtime-log__timestamp", dateTime: row.timestamp, children: row.timestamp })
785
+ },
786
+ {
787
+ key: "level",
788
+ header: "Level",
789
+ width: "7rem",
790
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_core5.Badge, { severity: levelSeverity(row.level), children: formatLevel(row.level) })
791
+ },
792
+ {
793
+ key: "source",
794
+ header: "Source",
795
+ width: "11rem",
796
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "eth-admin-runtime-log__source", children: row.source ?? "system" })
797
+ },
798
+ {
799
+ key: "message",
800
+ header: "Message",
801
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
802
+ "span",
803
+ {
804
+ className: [
805
+ "eth-admin-runtime-log__message",
806
+ `eth-admin-runtime-log__message--${row.level ?? "info"}`
807
+ ].join(" "),
808
+ children: row.message
809
+ }
810
+ )
811
+ }
812
+ ];
813
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
814
+ "section",
815
+ {
816
+ role: "region",
817
+ "aria-label": ariaLabel,
818
+ "aria-labelledby": ariaLabelledBy ?? (ariaLabel ? void 0 : headingId),
819
+ className: [
820
+ "eth-admin-runtime-log",
821
+ streaming ? "eth-admin-runtime-log--streaming" : "eth-admin-runtime-log--paused",
822
+ className
823
+ ].filter(Boolean).join(" "),
824
+ "data-eth-component": "RuntimeLogViewer",
825
+ children: [
826
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("header", { className: "eth-admin-runtime-log__header", children: [
827
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "eth-admin-runtime-log__heading", children: [
828
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h3", { id: headingId, children: title }),
829
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { children: supportingText })
830
+ ] }),
831
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "eth-admin-runtime-log__status", "aria-live": "polite", children: [
832
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_core5.Badge, { severity: streaming ? "success" : "neutral", children: streaming ? "Streaming" : "Paused" }),
833
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: errorCount ? formatLevelCount(errorCount, "error") : "No errors" })
834
+ ] })
835
+ ] }),
836
+ hasToolbar ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
837
+ "div",
838
+ {
839
+ className: "eth-admin-runtime-log__toolbar",
840
+ role: "toolbar",
841
+ "aria-label": "Runtime log controls",
842
+ children: [
843
+ filters ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "eth-admin-runtime-log__filters", children: filters }) : null,
844
+ streaming && onPause ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
845
+ import_core5.Button,
846
+ {
847
+ type: "button",
848
+ intent: "secondary",
849
+ density: "compact",
850
+ icon: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_icons_react.Pause, { size: 16 }),
851
+ "aria-label": "Pause runtime stream",
852
+ onClick: onPause,
853
+ children: "Pause stream"
854
+ }
855
+ ) : null
856
+ ]
857
+ }
858
+ ) : null,
859
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("dl", { className: "eth-admin-runtime-log__summary", "aria-label": "Runtime log summary", children: [
860
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { children: [
861
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("dt", { children: "Entries" }),
862
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("dd", { children: formatEntryCount(entries.length) })
863
+ ] }),
864
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { children: [
865
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("dt", { children: "Warnings" }),
866
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("dd", { children: formatLevelCount(warningCount, "warning") })
867
+ ] }),
868
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { children: [
869
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("dt", { children: "Errors" }),
870
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("dd", { children: formatLevelCount(errorCount, "error") })
871
+ ] }),
872
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { children: [
873
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("dt", { children: "Latest" }),
874
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("dd", { children: latestTimestamp })
875
+ ] })
876
+ ] }),
877
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "eth-admin-runtime-log__table-shell", "aria-live": streaming ? "polite" : "off", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
878
+ import_data3.DataTable,
879
+ {
880
+ rows,
881
+ columns,
882
+ density,
883
+ rowKey: "id",
884
+ className: "eth-admin-runtime-log__table",
885
+ emptyState: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "eth-admin-runtime-log__empty", role: "status", children: [
886
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h4", { children: "No runtime logs" }),
887
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { children: "Events will appear here when the stream receives output." })
888
+ ] })
889
+ }
890
+ ) })
891
+ ]
892
+ }
893
+ );
894
+ }
895
+ function countLevel(entries, level) {
896
+ return entries.filter((entry) => entry.level === level).length;
897
+ }
898
+ function formatEntryCount(count) {
899
+ return `${count} ${count === 1 ? "entry" : "entries"}`;
900
+ }
901
+ function formatLevelCount(count, label) {
902
+ return `${count} ${count === 1 ? label : `${label}s`}`;
903
+ }
904
+ function formatLevel(level) {
905
+ return (level ?? "info").toUpperCase();
906
+ }
907
+ function levelSeverity(level) {
908
+ if (level === "error") return "danger";
909
+ if (level === "warning") return "warning";
910
+ if (level === "debug") return "neutral";
911
+ return "info";
912
+ }
913
+
914
+ // src/components/AuditLogViewer.tsx
915
+ var React4 = __toESM(require("react"), 1);
916
+ var import_core6 = require("@echothink-ui/core");
917
+ var import_data4 = require("@echothink-ui/data");
918
+ var import_jsx_runtime8 = require("react/jsx-runtime");
919
+ var exportFormats = [
920
+ { format: "csv", label: "CSV" },
921
+ { format: "json", label: "JSON" },
922
+ { format: "xlsx", label: "XLSX" }
923
+ ];
924
+ function AuditLogViewer({
925
+ entries,
926
+ filters,
927
+ onExport,
928
+ className,
929
+ "aria-label": ariaLabel,
930
+ "aria-labelledby": ariaLabelledBy
931
+ }) {
932
+ const headingId = React4.useId();
933
+ const rows = entries.map((entry) => ({ ...entry }));
934
+ const columns = [
935
+ { key: "timestamp", header: "Time", width: "7rem" },
936
+ {
937
+ key: "actor",
938
+ header: "Actor",
939
+ width: "9rem",
940
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "eth-admin-audit-log__actor", children: row.actor })
941
+ },
942
+ { key: "action", header: "Action", width: "12rem" },
943
+ { key: "resource", header: "Resource", width: "12rem" },
944
+ {
945
+ key: "ip",
946
+ header: "IP",
947
+ width: "9rem",
948
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "eth-admin-audit-log__mono", children: row.ip ?? "n/a" })
949
+ },
950
+ {
951
+ key: "outcome",
952
+ header: "Outcome",
953
+ width: "8rem",
954
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_core6.Badge, { severity: outcomeSeverity(row.outcome), children: row.outcome })
955
+ }
956
+ ];
957
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
958
+ "section",
959
+ {
960
+ "aria-label": ariaLabel,
961
+ "aria-labelledby": ariaLabelledBy ?? (ariaLabel ? void 0 : headingId),
962
+ className: ["eth-admin-audit-log", className].filter(Boolean).join(" "),
963
+ "data-eth-component": "AuditLogViewer",
964
+ children: [
965
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("header", { children: [
966
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "eth-admin-audit-log__heading", children: [
967
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h3", { id: headingId, children: "Audit log" }),
968
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: formatEntryCount2(entries.length) })
969
+ ] }),
970
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "eth-admin-audit-log__toolbar", children: [
971
+ filters ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "eth-admin-audit-log__filters", children: filters }) : null,
972
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "eth-admin-audit-log__exports", "aria-label": "Export audit log", children: exportFormats.map(({ format, label }) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
973
+ import_core6.Button,
974
+ {
975
+ type: "button",
976
+ intent: "tertiary",
977
+ density: "compact",
978
+ disabled: !onExport,
979
+ onClick: () => onExport?.(format),
980
+ children: label
981
+ },
982
+ format
983
+ )) })
984
+ ] })
985
+ ] }),
986
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_data4.DataTable, { rows, columns, density: "compact", rowKey: "id" })
987
+ ]
988
+ }
989
+ );
990
+ }
991
+ function formatEntryCount2(count) {
992
+ return `${count} ${count === 1 ? "event" : "events"}`;
993
+ }
994
+ function outcomeSeverity(outcome) {
995
+ return outcome === "success" ? "success" : outcome === "failure" ? "danger" : "neutral";
996
+ }
997
+
998
+ // src/components/PolicyConfigPanel.tsx
999
+ var import_react = require("react");
1000
+ var import_core7 = require("@echothink-ui/core");
1001
+ var import_forms = require("@echothink-ui/forms");
1002
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1003
+ function PolicyConfigPanel({
1004
+ policy,
1005
+ schema,
1006
+ onChange,
1007
+ onSave,
1008
+ title,
1009
+ description,
1010
+ density = "default",
1011
+ className,
1012
+ ...props
1013
+ }) {
1014
+ const generatedId = (0, import_react.useId)().replace(/[^a-zA-Z0-9_-]/g, "");
1015
+ const policyDomId = `eth-admin-policy-${String(policy.id ?? generatedId).replace(
1016
+ /[^a-zA-Z0-9_-]/g,
1017
+ "-"
1018
+ )}`;
1019
+ const update = (patch) => onChange?.({ ...policy, ...patch });
1020
+ const schemaFields = Object.keys(schema.properties ?? {});
1021
+ const variables = policy.variables?.length ? policy.variables : schemaFields;
1022
+ const rules = policy.rules ?? [];
1023
+ const visibleVariables = variables.slice(0, 5);
1024
+ const hiddenVariableCount = Math.max(0, variables.length - visibleVariables.length);
1025
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1026
+ import_core7.Surface,
1027
+ {
1028
+ ...props,
1029
+ title: title ?? "Policy configuration",
1030
+ description: description ?? schema.description ?? "Configure policy metadata and conditional rules for governed operations.",
1031
+ density,
1032
+ className: ["eth-admin-policy-config", className].filter(Boolean).join(" "),
1033
+ "data-eth-component": "PolicyConfigPanel",
1034
+ children: [
1035
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "eth-admin-policy-config__layout", children: [
1036
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "eth-admin-policy-config__fields", children: [
1037
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_core7.FormField, { id: `${policyDomId}-name`, label: "Policy name", required: true, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1038
+ import_core7.TextInput,
1039
+ {
1040
+ id: `${policyDomId}-name`,
1041
+ density,
1042
+ value: policy.name ?? "",
1043
+ onChange: (event) => update({ name: event.currentTarget.value })
1044
+ }
1045
+ ) }),
1046
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_core7.FormField, { id: `${policyDomId}-description`, label: "Description", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1047
+ import_core7.Textarea,
1048
+ {
1049
+ id: `${policyDomId}-description`,
1050
+ rows: 4,
1051
+ value: policy.description ?? "",
1052
+ onChange: (event) => update({ description: event.currentTarget.value })
1053
+ }
1054
+ ) })
1055
+ ] }),
1056
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("aside", { className: "eth-admin-policy-config__summary", "aria-label": "Policy summary", children: [
1057
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "eth-admin-policy-config__summary-header", children: [
1058
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h3", { children: "Policy scope" }),
1059
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_core7.Badge, { severity: rules.length ? "success" : "warning", children: rules.length ? "Configured" : "Needs rules" })
1060
+ ] }),
1061
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("dl", { className: "eth-admin-policy-config__summary-grid", children: [
1062
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
1063
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("dt", { children: "Rules" }),
1064
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("dd", { children: rules.length })
1065
+ ] }),
1066
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
1067
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("dt", { children: "Variables" }),
1068
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("dd", { children: variables.length })
1069
+ ] }),
1070
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { children: [
1071
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("dt", { children: "Schema fields" }),
1072
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("dd", { children: schemaFields.length })
1073
+ ] })
1074
+ ] }),
1075
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "eth-admin-policy-config__variables", children: [
1076
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: "Rule variables" }),
1077
+ variables.length ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "eth-admin-policy-config__variable-list", children: [
1078
+ visibleVariables.map((variable) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_core7.Tag, { children: variable }, variable)),
1079
+ hiddenVariableCount ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_core7.Badge, { severity: "neutral", children: [
1080
+ "+",
1081
+ hiddenVariableCount,
1082
+ " more"
1083
+ ] }) : null
1084
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { children: "No variables available." })
1085
+ ] })
1086
+ ] })
1087
+ ] }),
1088
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1089
+ import_forms.RuleBuilder,
1090
+ {
1091
+ className: "eth-admin-policy-config__rules",
1092
+ rules,
1093
+ variables,
1094
+ onChange: (nextRules) => update({ rules: nextRules })
1095
+ }
1096
+ ),
1097
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "eth-admin-policy-config__actions", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_core7.Button, { type: "button", disabled: !onSave, onClick: () => onSave?.(policy), children: "Save policy" }) })
1098
+ ]
1099
+ }
1100
+ );
1101
+ }
1102
+
1103
+ // src/components/BillingUsagePanel.tsx
1104
+ var import_core8 = require("@echothink-ui/core");
1105
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1106
+ function BillingUsagePanel({ metrics, period, title, className, ...props }) {
1107
+ const entries = metrics.map((metric) => {
1108
+ const percent = metric.limit > 0 ? metric.current / metric.limit * 100 : 0;
1109
+ const roundedPercent = Math.round(percent);
1110
+ const cappedPercent = Math.min(100, Math.max(0, percent));
1111
+ const state = usageState(percent, metric.limit);
1112
+ return {
1113
+ metric,
1114
+ percent,
1115
+ roundedPercent,
1116
+ cappedPercent,
1117
+ state,
1118
+ trendLabel: formatTrend(metric.trend),
1119
+ usageLabel: metric.limit > 0 ? `${formatNumber2(metric.current)} / ${formatNumber2(metric.limit)} ${formatUnit(metric.unit, metric.limit)}` : `${formatNumber2(metric.current)} ${formatUnit(metric.unit, metric.current)}`
1120
+ };
1121
+ });
1122
+ const highestUsage = entries.reduce((highest, entry) => {
1123
+ if (!highest || entry.percent > highest.percent) return entry;
1124
+ return highest;
1125
+ }, void 0);
1126
+ const overLimitCount = entries.filter((entry) => entry.percent >= 100).length;
1127
+ const watchedCount = entries.filter((entry) => entry.percent >= 80 && entry.percent < 100).length;
1128
+ const quotaStatus = getQuotaStatus(overLimitCount, watchedCount);
1129
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1130
+ import_core8.Surface,
1131
+ {
1132
+ ...props,
1133
+ title: title ?? "Billing usage",
1134
+ subtitle: period,
1135
+ className: ["eth-admin-billing-usage", className].filter(Boolean).join(" "),
1136
+ "data-eth-component": "BillingUsagePanel",
1137
+ children: entries.length ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
1138
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("dl", { className: "eth-admin-billing-usage__summary", "aria-label": "Billing usage summary", children: [
1139
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
1140
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("dt", { children: "Tracked quotas" }),
1141
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("dd", { children: entries.length })
1142
+ ] }),
1143
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
1144
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("dt", { children: "Highest usage" }),
1145
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("dd", { children: highestUsage ? `${highestUsage.metric.label} ${highestUsage.roundedPercent}%` : "n/a" })
1146
+ ] }),
1147
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
1148
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("dt", { children: "Quota status" }),
1149
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("dd", { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_core8.Badge, { severity: quotaStatus.severity, children: quotaStatus.label }) })
1150
+ ] })
1151
+ ] }),
1152
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "eth-admin-billing-usage__metrics", children: entries.map(({ metric, roundedPercent, cappedPercent, state, trendLabel, usageLabel }) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("section", { className: "eth-admin-billing-usage__metric", children: [
1153
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "eth-admin-billing-usage__metric-header", children: [
1154
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
1155
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h3", { children: metric.label }),
1156
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { children: usageLabel })
1157
+ ] }),
1158
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_core8.Badge, { severity: state.severity, children: state.label })
1159
+ ] }),
1160
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1161
+ "div",
1162
+ {
1163
+ className: "eth-admin-billing-usage__meter",
1164
+ role: "progressbar",
1165
+ "aria-label": `${metric.label} quota usage`,
1166
+ "aria-valuemin": 0,
1167
+ "aria-valuemax": 100,
1168
+ "aria-valuenow": Math.round(cappedPercent),
1169
+ "aria-valuetext": metric.limit > 0 ? `${roundedPercent}% of quota used` : "No quota limit configured",
1170
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1171
+ "span",
1172
+ {
1173
+ className: `eth-admin-billing-usage__meter-fill eth-admin-billing-usage__meter-fill--${state.tone}`,
1174
+ style: {
1175
+ "--eth-admin-billing-usage-percent": `${cappedPercent}%`
1176
+ }
1177
+ }
1178
+ )
1179
+ }
1180
+ ),
1181
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("dl", { className: "eth-admin-billing-usage__metric-details", children: [
1182
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
1183
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("dt", { children: "Utilization" }),
1184
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("dd", { children: metric.limit > 0 ? `${roundedPercent}%` : "No limit" })
1185
+ ] }),
1186
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
1187
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("dt", { children: "Limit" }),
1188
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("dd", { children: metric.limit > 0 ? `${formatNumber2(metric.limit)} ${formatUnit(metric.unit, metric.limit)}` : "Unlimited" })
1189
+ ] }),
1190
+ trendLabel ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
1191
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("dt", { children: "Change" }),
1192
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("dd", { children: trendLabel })
1193
+ ] }) : null
1194
+ ] })
1195
+ ] }, `${metric.label}-${metric.unit}`)) })
1196
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "eth-admin-billing-usage__empty", children: "No usage metrics are available for this period." })
1197
+ }
1198
+ );
1199
+ }
1200
+ function usageState(percent, limit) {
1201
+ if (limit <= 0) return { label: "No limit", severity: "neutral", tone: "neutral" };
1202
+ if (percent >= 100) return { label: "Over limit", severity: "danger", tone: "danger" };
1203
+ if (percent >= 80) return { label: "Watch", severity: "warning", tone: "warning" };
1204
+ return { label: "Within limit", severity: "success", tone: "normal" };
1205
+ }
1206
+ function getQuotaStatus(overLimitCount, watchedCount) {
1207
+ if (overLimitCount > 0) return { label: `${overLimitCount} over limit`, severity: "danger" };
1208
+ if (watchedCount > 0) return { label: `${watchedCount} nearing limit`, severity: "warning" };
1209
+ return { label: "Within limits", severity: "success" };
1210
+ }
1211
+ function formatNumber2(value) {
1212
+ return new Intl.NumberFormat("en-US", {
1213
+ maximumFractionDigits: value % 1 === 0 ? 0 : 2
1214
+ }).format(value);
1215
+ }
1216
+ function formatUnit(unit, value) {
1217
+ if (unit.toLowerCase() === "user") return value === 1 ? "user" : "users";
1218
+ return unit;
1219
+ }
1220
+ function formatTrend(trend) {
1221
+ if (trend === void 0) return void 0;
1222
+ if (trend === 0) return "Unchanged";
1223
+ return `${trend > 0 ? "+" : ""}${trend}% vs previous period`;
1224
+ }
1225
+
1226
+ // src/components/TenantSettingsPanel.tsx
1227
+ var import_forms2 = require("@echothink-ui/forms");
1228
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1229
+ function TenantSettingsPanel({
1230
+ sections,
1231
+ values,
1232
+ onChange,
1233
+ onSubmit,
1234
+ submitLabel = "Save settings",
1235
+ title,
1236
+ description,
1237
+ className,
1238
+ ...props
1239
+ }) {
1240
+ const effectiveDescription = description === void 0 ? "Manage tenant identity, regional placement, and governance defaults." : description;
1241
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1242
+ import_forms2.ConfigForm,
1243
+ {
1244
+ ...props,
1245
+ title: title ?? "Tenant settings",
1246
+ description: effectiveDescription,
1247
+ className: ["eth-admin-tenant-settings", className].filter(Boolean).join(" "),
1248
+ sections,
1249
+ values,
1250
+ onChange,
1251
+ onSubmit,
1252
+ submitLabel,
1253
+ "data-eth-component": "TenantSettingsPanel"
1254
+ }
1255
+ );
1256
+ }
1257
+
1258
+ // src/components/FeatureFlagPanel.tsx
1259
+ var React5 = __toESM(require("react"), 1);
1260
+ var import_core9 = require("@echothink-ui/core");
1261
+ var import_data5 = require("@echothink-ui/data");
1262
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1263
+ function FeatureFlagPanel({
1264
+ flags,
1265
+ onToggle,
1266
+ onUpdate,
1267
+ className,
1268
+ title = "Feature flags",
1269
+ subtitle,
1270
+ description,
1271
+ actions,
1272
+ density = "compact",
1273
+ "aria-label": ariaLabel,
1274
+ "aria-labelledby": ariaLabelledBy,
1275
+ eyebrow: _eyebrow,
1276
+ status: _status,
1277
+ severity: _severity,
1278
+ loading: _loading,
1279
+ empty: _empty,
1280
+ error: _error,
1281
+ items: _items,
1282
+ metadata: _metadata,
1283
+ footer: _footer,
1284
+ ...sectionProps
1285
+ }) {
1286
+ const headingId = React5.useId();
1287
+ const enabledCount = flags.filter((flag) => flag.enabled).length;
1288
+ const disabledCount = flags.length - enabledCount;
1289
+ const rows = flags.map((flag) => ({ ...flag }));
1290
+ const columns = [
1291
+ {
1292
+ key: "name",
1293
+ header: "Flag",
1294
+ width: "34%",
1295
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "eth-admin-feature-flag__name", children: row.name })
1296
+ },
1297
+ {
1298
+ key: "enabled",
1299
+ header: "Status",
1300
+ width: "13rem",
1301
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "eth-admin-feature-flag__status", children: [
1302
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1303
+ import_core9.Toggle,
1304
+ {
1305
+ label: `${row.name} is ${row.enabled ? "enabled" : "disabled"}`,
1306
+ hideLabel: true,
1307
+ onLabel: "",
1308
+ offLabel: "",
1309
+ checked: row.enabled,
1310
+ readOnly: !onToggle,
1311
+ density,
1312
+ onChange: () => onToggle?.(row.id)
1313
+ }
1314
+ ),
1315
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_core9.Badge, { severity: row.enabled ? "success" : "neutral", children: row.enabled ? "Enabled" : "Disabled" })
1316
+ ] })
1317
+ },
1318
+ {
1319
+ key: "rolloutPercent",
1320
+ header: "Rollout",
1321
+ width: "18rem",
1322
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "eth-admin-feature-flag__rollout", children: [
1323
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1324
+ import_core9.NumberInput,
1325
+ {
1326
+ "aria-label": `${row.name} rollout percent`,
1327
+ className: "eth-admin-feature-flag__rollout-input",
1328
+ density,
1329
+ hideLabel: true,
1330
+ min: 0,
1331
+ max: 100,
1332
+ step: 1,
1333
+ readOnly: !onUpdate,
1334
+ value: normalizeRolloutPercent(row.rolloutPercent),
1335
+ onChange: (event) => onUpdate?.(row.id, {
1336
+ rolloutPercent: normalizeRolloutPercent(Number(event.currentTarget.value))
1337
+ })
1338
+ }
1339
+ ),
1340
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "eth-admin-feature-flag__rollout-unit", "aria-hidden": "true", children: "%" }),
1341
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "eth-admin-feature-flag__meter", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1342
+ "span",
1343
+ {
1344
+ style: {
1345
+ "--eth-admin-feature-flag-rollout": `${normalizeRolloutPercent(row.rolloutPercent)}%`
1346
+ }
1347
+ }
1348
+ ) })
1349
+ ] })
1350
+ },
1351
+ {
1352
+ key: "environments",
1353
+ header: "Environments",
1354
+ render: (row) => row.environments?.length ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "eth-admin-feature-flag__environments", children: row.environments.map((environment) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_core9.Badge, { severity: "neutral", children: environment }, environment)) }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_core9.Badge, { severity: "neutral", children: "All environments" })
1355
+ }
1356
+ ];
1357
+ const supportingText = subtitle ?? description;
1358
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1359
+ "section",
1360
+ {
1361
+ ...sectionProps,
1362
+ "aria-label": ariaLabel,
1363
+ "aria-labelledby": ariaLabelledBy ?? (ariaLabel ? void 0 : headingId),
1364
+ className: ["eth-admin-feature-flag", className].filter(Boolean).join(" "),
1365
+ "data-eth-component": "FeatureFlagPanel",
1366
+ children: [
1367
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("header", { children: [
1368
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "eth-admin-feature-flag__heading", children: [
1369
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("h3", { id: headingId, children: title }),
1370
+ supportingText ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { children: supportingText }) : null
1371
+ ] }),
1372
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "eth-admin-feature-flag__header-actions", children: [
1373
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1374
+ "div",
1375
+ {
1376
+ className: "eth-admin-feature-flag__summary",
1377
+ "aria-label": `${flags.length} feature flags`,
1378
+ children: [
1379
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_core9.Badge, { severity: "success", children: [
1380
+ enabledCount,
1381
+ " enabled"
1382
+ ] }),
1383
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_core9.Badge, { severity: "neutral", children: [
1384
+ disabledCount,
1385
+ " disabled"
1386
+ ] })
1387
+ ]
1388
+ }
1389
+ ),
1390
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_core9.ActionGroup, { actions })
1391
+ ] })
1392
+ ] }),
1393
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1394
+ import_data5.DataTable,
1395
+ {
1396
+ rows,
1397
+ columns,
1398
+ density,
1399
+ rowKey: "id",
1400
+ className: "eth-admin-feature-flag__table",
1401
+ emptyState: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "eth-admin-feature-flag__empty", children: "No feature flags configured." })
1402
+ }
1403
+ )
1404
+ ]
1405
+ }
1406
+ );
1407
+ }
1408
+ function normalizeRolloutPercent(value) {
1409
+ const numericValue = value ?? 0;
1410
+ if (!Number.isFinite(numericValue)) return 0;
1411
+ return Math.min(100, Math.max(0, Math.round(numericValue)));
1412
+ }
1413
+
1414
+ // src/components/RateLimitPanel.tsx
1415
+ var React6 = __toESM(require("react"), 1);
1416
+ var import_core10 = require("@echothink-ui/core");
1417
+ var import_data6 = require("@echothink-ui/data");
1418
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1419
+ function RateLimitPanel({
1420
+ limits,
1421
+ onUpdate,
1422
+ title = "Rate limits",
1423
+ subtitle,
1424
+ description,
1425
+ actions,
1426
+ density = "compact",
1427
+ className,
1428
+ "aria-label": ariaLabel,
1429
+ "aria-labelledby": ariaLabelledBy,
1430
+ eyebrow: _eyebrow,
1431
+ status: _status,
1432
+ severity: _severity,
1433
+ loading: _loading,
1434
+ empty: _empty,
1435
+ error: _error,
1436
+ items: _items,
1437
+ metadata: _metadata,
1438
+ footer: _footer,
1439
+ ...sectionProps
1440
+ }) {
1441
+ const headingId = React6.useId();
1442
+ const rows = limits.map((limit) => {
1443
+ const percent = limit.limit > 0 ? limit.current / limit.limit * 100 : 0;
1444
+ const cappedPercent = Math.min(100, Math.max(0, percent));
1445
+ return {
1446
+ ...limit,
1447
+ cappedPercent,
1448
+ percent,
1449
+ percentLabel: limit.limit > 0 ? formatPercent3(percent) : "No limit",
1450
+ state: rateLimitState(percent, limit.limit),
1451
+ usageLabel: limit.limit > 0 ? `${formatNumber3(limit.current)} / ${formatNumber3(limit.limit)}` : `${formatNumber3(limit.current)} requests`
1452
+ };
1453
+ });
1454
+ const highestUsage = rows.reduce((highest, row) => {
1455
+ if (row.limit <= 0) return highest;
1456
+ if (!highest || row.percent > highest.percent) return row;
1457
+ return highest;
1458
+ }, void 0);
1459
+ const exceededCount = rows.filter((row) => row.limit > 0 && row.percent >= 100).length;
1460
+ const nearLimitCount = rows.filter(
1461
+ (row) => row.limit > 0 && row.percent >= 80 && row.percent < 100
1462
+ ).length;
1463
+ const statusSummary = rateLimitStatusSummary(limits.length, exceededCount, nearLimitCount);
1464
+ const supportingText = subtitle ?? description;
1465
+ const columns = [
1466
+ {
1467
+ key: "name",
1468
+ header: "Limit",
1469
+ width: "28%",
1470
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "eth-admin-rate-limit__limit", children: [
1471
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("strong", { children: row.name }),
1472
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: row.state.label })
1473
+ ] })
1474
+ },
1475
+ {
1476
+ key: "current",
1477
+ header: "Usage",
1478
+ width: "34%",
1479
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "eth-admin-rate-limit__usage", children: [
1480
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "eth-admin-rate-limit__usage-copy", children: [
1481
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { children: row.usageLabel }),
1482
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("strong", { children: row.percentLabel })
1483
+ ] }),
1484
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1485
+ "span",
1486
+ {
1487
+ className: "eth-admin-rate-limit__meter",
1488
+ role: "progressbar",
1489
+ "aria-label": `${row.name} usage`,
1490
+ "aria-valuemin": 0,
1491
+ "aria-valuemax": 100,
1492
+ "aria-valuenow": Math.round(row.cappedPercent),
1493
+ "aria-valuetext": row.limit > 0 ? `${formatPercent3(row.percent)} used, ${formatNumber3(row.current)} of ${formatNumber3(
1494
+ row.limit
1495
+ )} requests` : "No configured limit",
1496
+ style: {
1497
+ "--eth-admin-rate-limit-usage": `${row.cappedPercent}%`
1498
+ },
1499
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1500
+ "span",
1501
+ {
1502
+ className: [
1503
+ "eth-admin-rate-limit__meter-fill",
1504
+ `eth-admin-rate-limit__meter-fill--${row.state.tone}`
1505
+ ].join(" ")
1506
+ }
1507
+ )
1508
+ }
1509
+ )
1510
+ ] })
1511
+ },
1512
+ {
1513
+ key: "windowSeconds",
1514
+ header: "Window",
1515
+ width: "8rem",
1516
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { className: "eth-admin-rate-limit__number", children: formatWindow(row.windowSeconds) })
1517
+ },
1518
+ {
1519
+ key: "limit",
1520
+ header: "Configured limit",
1521
+ width: "13rem",
1522
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1523
+ import_core10.NumberInput,
1524
+ {
1525
+ "aria-label": `${row.name} configured limit`,
1526
+ className: "eth-admin-rate-limit__limit-input",
1527
+ density,
1528
+ hideLabel: true,
1529
+ min: 0,
1530
+ step: 1,
1531
+ readOnly: !onUpdate,
1532
+ value: row.limit,
1533
+ onChange: (event) => {
1534
+ const nextLimit = Number(event.currentTarget.value);
1535
+ if (Number.isFinite(nextLimit)) onUpdate?.(row.id, { limit: nextLimit });
1536
+ }
1537
+ }
1538
+ )
1539
+ }
1540
+ ];
1541
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1542
+ "section",
1543
+ {
1544
+ ...sectionProps,
1545
+ "aria-label": ariaLabel,
1546
+ "aria-labelledby": ariaLabelledBy ?? (ariaLabel ? void 0 : headingId),
1547
+ className: ["eth-admin-rate-limit", className].filter(Boolean).join(" "),
1548
+ "data-eth-component": "RateLimitPanel",
1549
+ children: [
1550
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("header", { children: [
1551
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "eth-admin-rate-limit__heading", children: [
1552
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h3", { id: headingId, children: title }),
1553
+ supportingText ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { children: supportingText }) : null
1554
+ ] }),
1555
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "eth-admin-rate-limit__header-actions", children: [
1556
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_core10.Badge, { severity: statusSummary.severity, children: statusSummary.label }),
1557
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_core10.ActionGroup, { actions })
1558
+ ] })
1559
+ ] }),
1560
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("dl", { className: "eth-admin-rate-limit__summary", "aria-label": "Rate limit totals", children: [
1561
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
1562
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dt", { children: "Tracked limits" }),
1563
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dd", { children: formatNumber3(limits.length) })
1564
+ ] }),
1565
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
1566
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dt", { children: "Highest usage" }),
1567
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dd", { children: highestUsage ? `${highestUsage.name} ${formatPercent3(highestUsage.percent)}` : "n/a" })
1568
+ ] }),
1569
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { children: [
1570
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dt", { children: "Needs review" }),
1571
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("dd", { children: formatNumber3(exceededCount + nearLimitCount) })
1572
+ ] })
1573
+ ] }),
1574
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1575
+ import_data6.DataTable,
1576
+ {
1577
+ rows,
1578
+ columns,
1579
+ rowKey: "id",
1580
+ density,
1581
+ className: "eth-admin-rate-limit__table",
1582
+ emptyState: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "eth-admin-rate-limit__empty", children: "No rate limits configured." })
1583
+ }
1584
+ )
1585
+ ]
1586
+ }
1587
+ );
1588
+ }
1589
+ function rateLimitState(percent, limit) {
1590
+ if (limit <= 0) return { label: "No limit", severity: "neutral", tone: "neutral" };
1591
+ if (percent >= 100) return { label: "Exceeded", severity: "danger", tone: "danger" };
1592
+ if (percent >= 80) return { label: "Near limit", severity: "warning", tone: "warning" };
1593
+ return { label: "Within limit", severity: "success", tone: "normal" };
1594
+ }
1595
+ function rateLimitStatusSummary(totalCount, exceededCount, nearLimitCount) {
1596
+ if (totalCount === 0) return { label: "No limits", severity: "neutral" };
1597
+ if (exceededCount > 0) {
1598
+ return { label: `${formatNumber3(exceededCount)} exceeded`, severity: "danger" };
1599
+ }
1600
+ if (nearLimitCount > 0) {
1601
+ return { label: `${formatNumber3(nearLimitCount)} near limit`, severity: "warning" };
1602
+ }
1603
+ return { label: "Within limits", severity: "success" };
1604
+ }
1605
+ function formatWindow(seconds) {
1606
+ return `${formatNumber3(seconds)}s`;
1607
+ }
1608
+ function formatPercent3(value) {
1609
+ return `${Math.round(value).toLocaleString("en-US")}%`;
1610
+ }
1611
+ function formatNumber3(value) {
1612
+ return new Intl.NumberFormat("en-US").format(value);
1613
+ }
1614
+
1615
+ // src/components/IntegrationHealthTable.tsx
1616
+ var React7 = __toESM(require("react"), 1);
1617
+ var import_core11 = require("@echothink-ui/core");
1618
+ var import_data7 = require("@echothink-ui/data");
1619
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1620
+ function IntegrationHealthTable({
1621
+ integrations,
1622
+ className,
1623
+ title = "Integration health",
1624
+ subtitle,
1625
+ description,
1626
+ actions,
1627
+ density = "compact",
1628
+ "aria-label": ariaLabel,
1629
+ "aria-labelledby": ariaLabelledBy,
1630
+ eyebrow: _eyebrow,
1631
+ status: _status,
1632
+ severity: _severity,
1633
+ loading: _loading,
1634
+ empty: _empty,
1635
+ error: _error,
1636
+ items: _items,
1637
+ metadata: _metadata,
1638
+ footer: _footer,
1639
+ ...sectionProps
1640
+ }) {
1641
+ const headingId = React7.useId();
1642
+ const incidentCount = integrations.reduce(
1643
+ (sum, integration) => sum + (integration.incidentsCount ?? 0),
1644
+ 0
1645
+ );
1646
+ const impairedCount = integrations.filter(
1647
+ (integration) => integration.status !== "healthy"
1648
+ ).length;
1649
+ const healthyCount = integrations.length - impairedCount;
1650
+ const rows = integrations.map((integration) => ({ ...integration }));
1651
+ const columns = [
1652
+ {
1653
+ key: "name",
1654
+ header: "Integration",
1655
+ width: "32%",
1656
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { className: "eth-admin-integration-health__name", children: [
1657
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("strong", { children: row.name }),
1658
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: row.id })
1659
+ ] })
1660
+ },
1661
+ {
1662
+ key: "status",
1663
+ header: "Status",
1664
+ width: "9rem",
1665
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_core11.Badge, { severity: statusSeverity(row.status), children: statusLabel2(row.status) })
1666
+ },
1667
+ {
1668
+ key: "latencyMs",
1669
+ header: "Latency",
1670
+ width: "8rem",
1671
+ align: "end",
1672
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: latencyMetricClassName(row.latencyMs), children: formatLatency(row.latencyMs) })
1673
+ },
1674
+ {
1675
+ key: "incidentsCount",
1676
+ header: "Incidents",
1677
+ width: "8rem",
1678
+ align: "end",
1679
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_core11.Badge, { severity: incidentSeverity(row.incidentsCount), children: formatIncidentCount(row.incidentsCount) })
1680
+ },
1681
+ {
1682
+ key: "lastCheckedAt",
1683
+ header: "Last checked",
1684
+ width: "10rem",
1685
+ render: (row) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { className: "eth-admin-integration-health__checked", children: row.lastCheckedAt ?? "Not checked" })
1686
+ }
1687
+ ];
1688
+ const supportingText = subtitle ?? description;
1689
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1690
+ "section",
1691
+ {
1692
+ ...sectionProps,
1693
+ "aria-label": ariaLabel,
1694
+ "aria-labelledby": ariaLabelledBy ?? (ariaLabel ? void 0 : headingId),
1695
+ className: ["eth-admin-integration-health", className].filter(Boolean).join(" "),
1696
+ "data-eth-component": "IntegrationHealthTable",
1697
+ children: [
1698
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("header", { children: [
1699
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "eth-admin-integration-health__heading", children: [
1700
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("h3", { id: headingId, children: title }),
1701
+ supportingText ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { children: supportingText }) : null
1702
+ ] }),
1703
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "eth-admin-integration-health__header-actions", children: [
1704
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1705
+ "div",
1706
+ {
1707
+ className: "eth-admin-integration-health__summary",
1708
+ "aria-label": summaryLabel(rows.length, incidentCount, healthyCount),
1709
+ children: [
1710
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_core11.Badge, { severity: !rows.length ? "neutral" : impairedCount ? "warning" : "success", children: formatHealthySummary(rows.length, healthyCount) }),
1711
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_core11.Badge, { severity: incidentCount ? "danger" : "neutral", children: [
1712
+ incidentCount,
1713
+ " ",
1714
+ incidentCount === 1 ? "incident" : "incidents"
1715
+ ] })
1716
+ ]
1717
+ }
1718
+ ),
1719
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_core11.ActionGroup, { actions })
1720
+ ] })
1721
+ ] }),
1722
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1723
+ import_data7.DataTable,
1724
+ {
1725
+ rows,
1726
+ columns,
1727
+ density,
1728
+ rowKey: "id",
1729
+ className: "eth-admin-integration-health__table",
1730
+ emptyState: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "eth-admin-integration-health__empty", children: "No integrations are reporting." })
1731
+ }
1732
+ )
1733
+ ]
1734
+ }
1735
+ );
1736
+ }
1737
+ function statusSeverity(status) {
1738
+ if (status === "healthy") return "success";
1739
+ if (status === "degraded") return "warning";
1740
+ return "danger";
1741
+ }
1742
+ function statusLabel2(status) {
1743
+ if (status === "down") return "Down";
1744
+ if (status === "degraded") return "Degraded";
1745
+ return "Healthy";
1746
+ }
1747
+ function latencySeverity(latencyMs) {
1748
+ if (latencyMs === void 0) return null;
1749
+ if (latencyMs >= 1e3) return "danger";
1750
+ if (latencyMs >= 500) return "warning";
1751
+ return null;
1752
+ }
1753
+ function latencyMetricClassName(latencyMs) {
1754
+ const severity = latencySeverity(latencyMs);
1755
+ return [
1756
+ "eth-admin-integration-health__metric",
1757
+ severity ? `eth-admin-integration-health__metric--${severity}` : void 0
1758
+ ].filter(Boolean).join(" ");
1759
+ }
1760
+ function incidentSeverity(count) {
1761
+ if (!count) return "success";
1762
+ return count > 1 ? "danger" : "warning";
1763
+ }
1764
+ function formatLatency(latencyMs) {
1765
+ return latencyMs === void 0 ? "n/a" : `${latencyMs} ms`;
1766
+ }
1767
+ function formatIncidentCount(count) {
1768
+ return String(count ?? 0);
1769
+ }
1770
+ function formatHealthySummary(total, healthyCount) {
1771
+ return total ? `${healthyCount}/${total} healthy` : "0 integrations";
1772
+ }
1773
+ function summaryLabel(total, incidentCount, healthyCount) {
1774
+ if (!total) return `No integrations reporting, ${incidentCount} open incidents`;
1775
+ return `${healthyCount} of ${total} integrations healthy, ${incidentCount} open ${incidentCount === 1 ? "incident" : "incidents"}`;
1776
+ }
1777
+
1778
+ // src/components/AdminHealthTemplate.tsx
1779
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1780
+ function AdminHealthTemplate({ services, incidents, metrics, ...props }) {
1781
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1782
+ SystemHealthDashboard,
1783
+ {
1784
+ ...props,
1785
+ services: services ?? [
1786
+ { id: "api", name: "API Gateway", status: "healthy", latencyMs: 42 },
1787
+ { id: "workers", name: "Worker fleet", status: "degraded", latencyMs: 110, incidentsCount: 1 },
1788
+ { id: "storage", name: "Storage", status: "healthy", latencyMs: 24 }
1789
+ ],
1790
+ incidents,
1791
+ metrics,
1792
+ "data-eth-component": "AdminHealthTemplate"
1793
+ }
1794
+ );
1795
+ }
1796
+
1797
+ // src/index.tsx
1798
+ var AdminComponentNames = [
1799
+ "AdminShell",
1800
+ "SystemHealthDashboard",
1801
+ "ServiceStatusCard",
1802
+ "WorkerPoolPanel",
1803
+ "JobQueuePanel",
1804
+ "QueueDepthChart",
1805
+ "RuntimeLogViewer",
1806
+ "AuditLogViewer",
1807
+ "PolicyConfigPanel",
1808
+ "BillingUsagePanel",
1809
+ "TenantSettingsPanel",
1810
+ "FeatureFlagPanel",
1811
+ "RateLimitPanel",
1812
+ "IntegrationHealthTable",
1813
+ "AdminHealthTemplate"
1814
+ ];
1815
+ // Annotate the CommonJS export names for ESM import in node:
1816
+ 0 && (module.exports = {
1817
+ AdminComponentNames,
1818
+ AdminHealthTemplate,
1819
+ AdminShell,
1820
+ AuditLogViewer,
1821
+ BillingUsagePanel,
1822
+ FeatureFlagPanel,
1823
+ IntegrationHealthTable,
1824
+ JobQueuePanel,
1825
+ PolicyConfigPanel,
1826
+ QueueDepthChart,
1827
+ RateLimitPanel,
1828
+ RuntimeLogViewer,
1829
+ ServiceStatusCard,
1830
+ SystemHealthDashboard,
1831
+ TenantSettingsPanel,
1832
+ WorkerPoolPanel,
1833
+ severityForStatus
1834
+ });
1835
+ //# sourceMappingURL=index.cjs.map