@miragon/pulse-analytics-connector 0.0.0-bootstrap.0 → 0.21.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 (357) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +86 -3
  3. package/dist/bpmn-name-lookup.d.ts +72 -0
  4. package/dist/bpmn-name-lookup.d.ts.map +1 -0
  5. package/dist/bpmn-name-lookup.js +123 -0
  6. package/dist/bpmn-name-lookup.js.map +1 -0
  7. package/dist/bpmn-name-lookup.test.d.ts +2 -0
  8. package/dist/bpmn-name-lookup.test.d.ts.map +1 -0
  9. package/dist/bpmn-name-lookup.test.js +287 -0
  10. package/dist/bpmn-name-lookup.test.js.map +1 -0
  11. package/dist/bpmn-names.d.ts +38 -0
  12. package/dist/bpmn-names.d.ts.map +1 -0
  13. package/dist/bpmn-names.js +22 -0
  14. package/dist/bpmn-names.js.map +1 -0
  15. package/dist/brand-gates.test.d.ts +2 -0
  16. package/dist/brand-gates.test.d.ts.map +1 -0
  17. package/dist/brand-gates.test.js +58 -0
  18. package/dist/brand-gates.test.js.map +1 -0
  19. package/dist/builder-texts.d.ts +4 -0
  20. package/dist/builder-texts.d.ts.map +1 -0
  21. package/dist/builder-texts.js +14 -0
  22. package/dist/builder-texts.js.map +1 -0
  23. package/dist/builder-texts.test.d.ts +2 -0
  24. package/dist/builder-texts.test.d.ts.map +1 -0
  25. package/dist/builder-texts.test.js +32 -0
  26. package/dist/builder-texts.test.js.map +1 -0
  27. package/dist/definition.d.ts +3 -0
  28. package/dist/definition.d.ts.map +1 -0
  29. package/dist/definition.js +151 -0
  30. package/dist/definition.js.map +1 -0
  31. package/dist/engine-ids.d.ts +42 -0
  32. package/dist/engine-ids.d.ts.map +1 -0
  33. package/dist/engine-ids.js +50 -0
  34. package/dist/engine-ids.js.map +1 -0
  35. package/dist/engine-scope.test.d.ts +2 -0
  36. package/dist/engine-scope.test.d.ts.map +1 -0
  37. package/dist/engine-scope.test.js +260 -0
  38. package/dist/engine-scope.test.js.map +1 -0
  39. package/dist/heatmap-data.d.ts +15 -0
  40. package/dist/heatmap-data.d.ts.map +1 -0
  41. package/dist/heatmap-data.js +2 -0
  42. package/dist/heatmap-data.js.map +1 -0
  43. package/dist/index.d.ts +5 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +3 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/instructions.d.ts +8 -0
  48. package/dist/instructions.d.ts.map +1 -0
  49. package/dist/instructions.js +33 -0
  50. package/dist/instructions.js.map +1 -0
  51. package/dist/messages/de.ask-ai.d.ts +9 -0
  52. package/dist/messages/de.ask-ai.d.ts.map +1 -0
  53. package/dist/messages/de.ask-ai.js +18 -0
  54. package/dist/messages/de.ask-ai.js.map +1 -0
  55. package/dist/messages/de.builder.d.ts +12 -0
  56. package/dist/messages/de.builder.d.ts.map +1 -0
  57. package/dist/messages/de.builder.js +53 -0
  58. package/dist/messages/de.builder.js.map +1 -0
  59. package/dist/messages/de.server.d.ts +8 -0
  60. package/dist/messages/de.server.d.ts.map +1 -0
  61. package/dist/messages/de.server.js +26 -0
  62. package/dist/messages/de.server.js.map +1 -0
  63. package/dist/messages/de.sweep.d.ts +10 -0
  64. package/dist/messages/de.sweep.d.ts.map +1 -0
  65. package/dist/messages/de.sweep.js +203 -0
  66. package/dist/messages/de.sweep.js.map +1 -0
  67. package/dist/messages/en.ask-ai.d.ts +25 -0
  68. package/dist/messages/en.ask-ai.d.ts.map +1 -0
  69. package/dist/messages/en.ask-ai.js +24 -0
  70. package/dist/messages/en.ask-ai.js.map +1 -0
  71. package/dist/messages/en.builder.d.ts +12 -0
  72. package/dist/messages/en.builder.d.ts.map +1 -0
  73. package/dist/messages/en.builder.js +53 -0
  74. package/dist/messages/en.builder.js.map +1 -0
  75. package/dist/messages/en.server.d.ts +8 -0
  76. package/dist/messages/en.server.d.ts.map +1 -0
  77. package/dist/messages/en.server.js +26 -0
  78. package/dist/messages/en.server.js.map +1 -0
  79. package/dist/messages/en.sweep.d.ts +11 -0
  80. package/dist/messages/en.sweep.d.ts.map +1 -0
  81. package/dist/messages/en.sweep.js +204 -0
  82. package/dist/messages/en.sweep.js.map +1 -0
  83. package/dist/messages/glossary.d.ts +26 -0
  84. package/dist/messages/glossary.d.ts.map +1 -0
  85. package/dist/messages/glossary.js +37 -0
  86. package/dist/messages/glossary.js.map +1 -0
  87. package/dist/messages/glossary.test.d.ts +2 -0
  88. package/dist/messages/glossary.test.d.ts.map +1 -0
  89. package/dist/messages/glossary.test.js +109 -0
  90. package/dist/messages/glossary.test.js.map +1 -0
  91. package/dist/messages/index.d.ts +12 -0
  92. package/dist/messages/index.d.ts.map +1 -0
  93. package/dist/messages/index.js +23 -0
  94. package/dist/messages/index.js.map +1 -0
  95. package/dist/messages/plural.d.ts +10 -0
  96. package/dist/messages/plural.d.ts.map +1 -0
  97. package/dist/messages/plural.js +17 -0
  98. package/dist/messages/plural.js.map +1 -0
  99. package/dist/messages/use-t.d.ts +10 -0
  100. package/dist/messages/use-t.d.ts.map +1 -0
  101. package/dist/messages/use-t.js +10 -0
  102. package/dist/messages/use-t.js.map +1 -0
  103. package/dist/module.d.ts +48 -0
  104. package/dist/module.d.ts.map +1 -0
  105. package/dist/module.js +174 -0
  106. package/dist/module.js.map +1 -0
  107. package/dist/module.test.d.ts +2 -0
  108. package/dist/module.test.d.ts.map +1 -0
  109. package/dist/module.test.js +230 -0
  110. package/dist/module.test.js.map +1 -0
  111. package/dist/named-views.d.ts +27 -0
  112. package/dist/named-views.d.ts.map +1 -0
  113. package/dist/named-views.js +73 -0
  114. package/dist/named-views.js.map +1 -0
  115. package/dist/named-views.test.d.ts +2 -0
  116. package/dist/named-views.test.d.ts.map +1 -0
  117. package/dist/named-views.test.js +110 -0
  118. package/dist/named-views.test.js.map +1 -0
  119. package/dist/plugin.d.ts +44 -0
  120. package/dist/plugin.d.ts.map +1 -0
  121. package/dist/plugin.js +52 -0
  122. package/dist/plugin.js.map +1 -0
  123. package/dist/prometheus-wiring.test.d.ts +2 -0
  124. package/dist/prometheus-wiring.test.d.ts.map +1 -0
  125. package/dist/prometheus-wiring.test.js +142 -0
  126. package/dist/prometheus-wiring.test.js.map +1 -0
  127. package/dist/server-locale.d.ts +48 -0
  128. package/dist/server-locale.d.ts.map +1 -0
  129. package/dist/server-locale.js +33 -0
  130. package/dist/server-locale.js.map +1 -0
  131. package/dist/settings-tools.d.ts +23 -0
  132. package/dist/settings-tools.d.ts.map +1 -0
  133. package/dist/settings-tools.js +100 -0
  134. package/dist/settings-tools.js.map +1 -0
  135. package/dist/settings.d.ts +77 -0
  136. package/dist/settings.d.ts.map +1 -0
  137. package/dist/settings.js +99 -0
  138. package/dist/settings.js.map +1 -0
  139. package/dist/settings.test.d.ts +2 -0
  140. package/dist/settings.test.d.ts.map +1 -0
  141. package/dist/settings.test.js +299 -0
  142. package/dist/settings.test.js.map +1 -0
  143. package/dist/steps/app-config.d.ts +30 -0
  144. package/dist/steps/app-config.d.ts.map +1 -0
  145. package/dist/steps/app-config.js +46 -0
  146. package/dist/steps/app-config.js.map +1 -0
  147. package/dist/steps/dashboard.d.ts +12 -0
  148. package/dist/steps/dashboard.d.ts.map +1 -0
  149. package/dist/steps/dashboard.js +58 -0
  150. package/dist/steps/dashboard.js.map +1 -0
  151. package/dist/steps/failure-dashboard.d.ts +10 -0
  152. package/dist/steps/failure-dashboard.d.ts.map +1 -0
  153. package/dist/steps/failure-dashboard.js +32 -0
  154. package/dist/steps/failure-dashboard.js.map +1 -0
  155. package/dist/steps/index.d.ts +3 -0
  156. package/dist/steps/index.d.ts.map +1 -0
  157. package/dist/steps/index.js +3 -0
  158. package/dist/steps/index.js.map +1 -0
  159. package/dist/steps/steps.test.d.ts +2 -0
  160. package/dist/steps/steps.test.d.ts.map +1 -0
  161. package/dist/steps/steps.test.js +153 -0
  162. package/dist/steps/steps.test.js.map +1 -0
  163. package/dist/tool-names.d.ts +13 -0
  164. package/dist/tool-names.d.ts.map +1 -0
  165. package/dist/tool-names.js +27 -0
  166. package/dist/tool-names.js.map +1 -0
  167. package/dist/tools/cluster-compare.d.ts +8 -0
  168. package/dist/tools/cluster-compare.d.ts.map +1 -0
  169. package/dist/tools/cluster-compare.js +17 -0
  170. package/dist/tools/cluster-compare.js.map +1 -0
  171. package/dist/tools/element.d.ts +8 -0
  172. package/dist/tools/element.d.ts.map +1 -0
  173. package/dist/tools/element.js +25 -0
  174. package/dist/tools/element.js.map +1 -0
  175. package/dist/tools/engine-compare.d.ts +8 -0
  176. package/dist/tools/engine-compare.d.ts.map +1 -0
  177. package/dist/tools/engine-compare.js +18 -0
  178. package/dist/tools/engine-compare.js.map +1 -0
  179. package/dist/tools/engine-compare.test.d.ts +2 -0
  180. package/dist/tools/engine-compare.test.d.ts.map +1 -0
  181. package/dist/tools/engine-compare.test.js +166 -0
  182. package/dist/tools/engine-compare.test.js.map +1 -0
  183. package/dist/tools/engine-landscape.d.ts +7 -0
  184. package/dist/tools/engine-landscape.d.ts.map +1 -0
  185. package/dist/tools/engine-landscape.js +13 -0
  186. package/dist/tools/engine-landscape.js.map +1 -0
  187. package/dist/tools/engine-landscape.test.d.ts +2 -0
  188. package/dist/tools/engine-landscape.test.d.ts.map +1 -0
  189. package/dist/tools/engine-landscape.test.js +110 -0
  190. package/dist/tools/engine-landscape.test.js.map +1 -0
  191. package/dist/tools/failures.d.ts +7 -0
  192. package/dist/tools/failures.d.ts.map +1 -0
  193. package/dist/tools/failures.js +13 -0
  194. package/dist/tools/failures.js.map +1 -0
  195. package/dist/tools/health.d.ts +7 -0
  196. package/dist/tools/health.d.ts.map +1 -0
  197. package/dist/tools/health.js +23 -0
  198. package/dist/tools/health.js.map +1 -0
  199. package/dist/tools/health.test.d.ts +2 -0
  200. package/dist/tools/health.test.d.ts.map +1 -0
  201. package/dist/tools/health.test.js +119 -0
  202. package/dist/tools/health.test.js.map +1 -0
  203. package/dist/tools/index.d.ts +18 -0
  204. package/dist/tools/index.d.ts.map +1 -0
  205. package/dist/tools/index.js +35 -0
  206. package/dist/tools/index.js.map +1 -0
  207. package/dist/tools/performance.d.ts +8 -0
  208. package/dist/tools/performance.d.ts.map +1 -0
  209. package/dist/tools/performance.js +25 -0
  210. package/dist/tools/performance.js.map +1 -0
  211. package/dist/tools/performance.test.d.ts +2 -0
  212. package/dist/tools/performance.test.d.ts.map +1 -0
  213. package/dist/tools/performance.test.js +176 -0
  214. package/dist/tools/performance.test.js.map +1 -0
  215. package/dist/tools/version-compare.d.ts +8 -0
  216. package/dist/tools/version-compare.d.ts.map +1 -0
  217. package/dist/tools/version-compare.js +17 -0
  218. package/dist/tools/version-compare.js.map +1 -0
  219. package/dist/tools/version-compare.test.d.ts +2 -0
  220. package/dist/tools/version-compare.test.d.ts.map +1 -0
  221. package/dist/tools/version-compare.test.js +82 -0
  222. package/dist/tools/version-compare.test.js.map +1 -0
  223. package/dist/toolsets.d.ts +17 -0
  224. package/dist/toolsets.d.ts.map +1 -0
  225. package/dist/toolsets.js +47 -0
  226. package/dist/toolsets.js.map +1 -0
  227. package/dist/toolsets.test.d.ts +2 -0
  228. package/dist/toolsets.test.d.ts.map +1 -0
  229. package/dist/toolsets.test.js +91 -0
  230. package/dist/toolsets.test.js.map +1 -0
  231. package/dist/view-title.test.d.ts +2 -0
  232. package/dist/view-title.test.d.ts.map +1 -0
  233. package/dist/view-title.test.js +91 -0
  234. package/dist/view-title.test.js.map +1 -0
  235. package/dist/widget-tools/comparisons.d.ts +13 -0
  236. package/dist/widget-tools/comparisons.d.ts.map +1 -0
  237. package/dist/widget-tools/comparisons.js +177 -0
  238. package/dist/widget-tools/comparisons.js.map +1 -0
  239. package/dist/widget-tools/comparisons.test.d.ts +2 -0
  240. package/dist/widget-tools/comparisons.test.d.ts.map +1 -0
  241. package/dist/widget-tools/comparisons.test.js +123 -0
  242. package/dist/widget-tools/comparisons.test.js.map +1 -0
  243. package/dist/widget-tools/shared.d.ts +36 -0
  244. package/dist/widget-tools/shared.d.ts.map +1 -0
  245. package/dist/widget-tools/shared.js +39 -0
  246. package/dist/widget-tools/shared.js.map +1 -0
  247. package/dist/widget-tools.d.ts +25 -0
  248. package/dist/widget-tools.d.ts.map +1 -0
  249. package/dist/widget-tools.js +269 -0
  250. package/dist/widget-tools.js.map +1 -0
  251. package/dist/widget-tools.test.d.ts +2 -0
  252. package/dist/widget-tools.test.d.ts.map +1 -0
  253. package/dist/widget-tools.test.js +272 -0
  254. package/dist/widget-tools.test.js.map +1 -0
  255. package/package.json +91 -5
  256. package/src/bpmn-name-lookup.test.ts +333 -0
  257. package/src/bpmn-name-lookup.ts +197 -0
  258. package/src/bpmn-names.ts +51 -0
  259. package/src/brand-gates.test.ts +69 -0
  260. package/src/builder-texts.test.ts +40 -0
  261. package/src/builder-texts.ts +15 -0
  262. package/src/definition.ts +181 -0
  263. package/src/engine-ids.ts +85 -0
  264. package/src/engine-scope.test.ts +324 -0
  265. package/src/heatmap-data.ts +14 -0
  266. package/src/index.ts +4 -0
  267. package/src/instructions.ts +33 -0
  268. package/src/messages/GLOSSARY.md +88 -0
  269. package/src/messages/de.ask-ai.ts +28 -0
  270. package/src/messages/de.builder.ts +77 -0
  271. package/src/messages/de.server.ts +39 -0
  272. package/src/messages/de.sweep.ts +244 -0
  273. package/src/messages/en.ask-ai.ts +34 -0
  274. package/src/messages/en.builder.ts +76 -0
  275. package/src/messages/en.server.ts +39 -0
  276. package/src/messages/en.sweep.ts +240 -0
  277. package/src/messages/glossary.test.ts +122 -0
  278. package/src/messages/glossary.ts +62 -0
  279. package/src/messages/index.ts +24 -0
  280. package/src/messages/plural.ts +18 -0
  281. package/src/messages/use-t.ts +12 -0
  282. package/src/module.test.ts +319 -0
  283. package/src/module.ts +211 -0
  284. package/src/named-views.test.ts +141 -0
  285. package/src/named-views.ts +97 -0
  286. package/src/plugin.ts +94 -0
  287. package/src/prometheus-wiring.test.ts +174 -0
  288. package/src/server-locale.ts +59 -0
  289. package/src/settings-tools.ts +170 -0
  290. package/src/settings.test.ts +402 -0
  291. package/src/settings.ts +114 -0
  292. package/src/steps/app-config.ts +75 -0
  293. package/src/steps/dashboard.ts +73 -0
  294. package/src/steps/failure-dashboard.ts +38 -0
  295. package/src/steps/index.ts +2 -0
  296. package/src/steps/steps.test.ts +216 -0
  297. package/src/tool-names.ts +26 -0
  298. package/src/tools/cluster-compare.ts +28 -0
  299. package/src/tools/element.ts +35 -0
  300. package/src/tools/engine-compare.test.ts +210 -0
  301. package/src/tools/engine-compare.ts +30 -0
  302. package/src/tools/engine-landscape.test.ts +138 -0
  303. package/src/tools/engine-landscape.ts +21 -0
  304. package/src/tools/failures.ts +19 -0
  305. package/src/tools/health.test.ts +156 -0
  306. package/src/tools/health.ts +29 -0
  307. package/src/tools/index.ts +44 -0
  308. package/src/tools/performance.test.ts +210 -0
  309. package/src/tools/performance.ts +38 -0
  310. package/src/tools/version-compare.test.ts +97 -0
  311. package/src/tools/version-compare.ts +28 -0
  312. package/src/toolsets.test.ts +107 -0
  313. package/src/toolsets.ts +56 -0
  314. package/src/view-title.test.ts +123 -0
  315. package/src/widget-tools/comparisons.test.ts +170 -0
  316. package/src/widget-tools/comparisons.ts +229 -0
  317. package/src/widget-tools/shared.ts +67 -0
  318. package/src/widget-tools.test.ts +306 -0
  319. package/src/widget-tools.ts +375 -0
  320. package/src/widgets/analytics-dashboard/activity-bottleneck-table.tsx +179 -0
  321. package/src/widgets/analytics-dashboard/definition-breakdown.tsx +108 -0
  322. package/src/widgets/analytics-dashboard/execution-performance-kpi.tsx +94 -0
  323. package/src/widgets/analytics-dashboard/execution-summary-kpi.tsx +122 -0
  324. package/src/widgets/analytics-dashboard/lib.ts +43 -0
  325. package/src/widgets/bpmn-heatmap.test.tsx +75 -0
  326. package/src/widgets/bpmn-heatmap.tsx +127 -0
  327. package/src/widgets/catalogue-sync.test.ts +16 -0
  328. package/src/widgets/cluster-compare.tsx +148 -0
  329. package/src/widgets/comparison-shared.test.ts +237 -0
  330. package/src/widgets/comparison-shared.tsx +371 -0
  331. package/src/widgets/comparison-widgets.test.tsx +307 -0
  332. package/src/widgets/dashboard-widgets.test.tsx +397 -0
  333. package/src/widgets/engine-compare.tsx +87 -0
  334. package/src/widgets/engine-landscape.tsx +352 -0
  335. package/src/widgets/failure-dashboard/error-patterns-table.tsx +122 -0
  336. package/src/widgets/failure-dashboard/failure-rate-table.test.ts +80 -0
  337. package/src/widgets/failure-dashboard/failure-rate-table.tsx +170 -0
  338. package/src/widgets/failure-dashboard/lib.ts +32 -0
  339. package/src/widgets/failure-dashboard/summary-kpi.tsx +122 -0
  340. package/src/widgets/failure-landscape-widgets.test.tsx +393 -0
  341. package/src/widgets/figure.tsx +79 -0
  342. package/src/widgets/hand-off.test.ts +126 -0
  343. package/src/widgets/hand-off.ts +102 -0
  344. package/src/widgets/index.ts +124 -0
  345. package/src/widgets/model-descriptions.dashboard.test.ts +280 -0
  346. package/src/widgets/model-descriptions.test.ts +251 -0
  347. package/src/widgets/model-descriptions.ts +428 -0
  348. package/src/widgets/names.test.ts +32 -0
  349. package/src/widgets/names.ts +39 -0
  350. package/src/widgets/query-gate.test.tsx +57 -0
  351. package/src/widgets/query-gate.tsx +50 -0
  352. package/src/widgets/settings-section.test.tsx +174 -0
  353. package/src/widgets/settings-section.tsx +244 -0
  354. package/src/widgets/version-compare.test.ts +68 -0
  355. package/src/widgets/version-compare.tsx +96 -0
  356. package/src/widgets/view-meta.ts +18 -0
  357. package/src/widgets/widget-render.test-support.tsx +103 -0
@@ -0,0 +1,170 @@
1
+ import { TONE_DOT, cn } from "@miragon/mcp-toolkit-ui"
2
+ import {
3
+ HandOffButton,
4
+ ListTable,
5
+ NamedId,
6
+ Section,
7
+ TableEmptyState,
8
+ TableSkeleton,
9
+ Td,
10
+ WidgetShell,
11
+ formatNumber,
12
+ type ListTableColumn,
13
+ } from "@miragon/pulse-widget-shell/widgets"
14
+ import type { FailureDashboardData, ProcessFailureItem } from "@miragon/pulse-analytics-client"
15
+ import { useFailureDashboardSelfFetch, type FailureScopeProps, type FailureView } from "./lib.js"
16
+ import { QueryGate } from "../query-gate.js"
17
+ import { useT, type T } from "../../messages/use-t.js"
18
+ import { engineIdsOf, useHandOff, type HandOff } from "../hand-off.js"
19
+ import { processNameOf } from "../../bpmn-names.js"
20
+ import { Figure, FigureLegend, StateCount } from "../figure.js"
21
+
22
+ /**
23
+ * What drives ONE process's open incidents right now (live gauges: open
24
+ * incidents per 100 running instances, dead jobs — #336). The regression
25
+ * check goes to the tools that measure incident rates over time —
26
+ * analytics_version_compare cannot split incidents by version, so its
27
+ * incident rates are null (#327).
28
+ */
29
+ export function failureRateHandOff(
30
+ proc: ProcessFailureItem,
31
+ data: Pick<FailureDashboardData, "engines">,
32
+ ): HandOff {
33
+ return {
34
+ intent: "askAi.failureRate",
35
+ ids: { engine: engineIdsOf(data.engines), processDefinitionKey: proc.processDefinitionKey },
36
+ // A rate over no running instance is null — left out, never a 0.
37
+ facts: {
38
+ openIncidentsNow: proc.openIncidents,
39
+ runningNow: proc.runningNow,
40
+ incidentRatePct: proc.incidentRatePct,
41
+ deadJobs: proc.deadJobs,
42
+ },
43
+ tools: [
44
+ "analytics_compare_execution_periods",
45
+ "analytics_cluster_compare",
46
+ "analytics_element_bottleneck",
47
+ ],
48
+ }
49
+ }
50
+
51
+ /**
52
+ * The bar's length: the rate against the largest rate in the table, so
53
+ * every bar is comparable and none is cut off. A rate of incidents per 100
54
+ * running instances may pass 100 (one instance can carry several), which a
55
+ * scale capped at 100 would hide.
56
+ */
57
+ export function rateBarWidth(rate: number, max: number): number {
58
+ if (!(max > 0) || !(rate > 0)) return 0
59
+ return Math.min(100, (rate / max) * 100)
60
+ }
61
+
62
+ function columns(t: T): ListTableColumn[] {
63
+ return [
64
+ { label: t("aFailureRate.colProcess") },
65
+ { label: t("aFailureRate.colRunningNow"), align: "right" },
66
+ { label: t("aFailureRate.colOpenIncidents"), align: "right" },
67
+ { label: t("aFailureRate.colDeadJobs"), align: "right" },
68
+ { label: t("aFailureRate.colIncidentRate"), align: "right" },
69
+ {
70
+ label: <span className="sr-only">{t("aFailureRate.colAi")}</span>,
71
+ plain: true,
72
+ sticky: true,
73
+ },
74
+ ]
75
+ }
76
+
77
+ /**
78
+ * The rate as a number over a bar. The bar is a magnitude, not a state: it
79
+ * takes the data-viz blue (decision j), not the danger red. A rate is judged
80
+ * only against a threshold or the period before (U17), and this live ratio
81
+ * has neither; the open incidents beside it already carry the danger.
82
+ */
83
+ function RateCell({ rate, max, t }: { rate: number | null; max: number; t: T }) {
84
+ if (rate === null) return <Figure value={null} why={t("aFigure.noRate")} />
85
+ return (
86
+ <span className="ml-auto flex w-24 flex-col items-end gap-1">
87
+ <span className="tabular-nums">{formatNumber(rate, { maximumFractionDigits: 1 })}</span>
88
+ <span aria-hidden="true" className="bg-muted block h-1.5 w-full overflow-hidden rounded-full">
89
+ <span
90
+ className={cn("block h-full rounded-full", TONE_DOT.info)}
91
+ style={{ width: `${rateBarWidth(rate, max)}%` }}
92
+ />
93
+ </span>
94
+ </span>
95
+ )
96
+ }
97
+
98
+ export function FailureRateTable({
99
+ data: initialData,
100
+ engine,
101
+ }: { data: FailureView | null } & FailureScopeProps) {
102
+ const fallbackQuery = useFailureDashboardSelfFetch(initialData, { engine })
103
+ const t = useT()
104
+ const { ask } = useHandOff()
105
+ return (
106
+ <QueryGate initialData={initialData} query={fallbackQuery} skeleton={<TableSkeleton />}>
107
+ {(data) => {
108
+ if (data.processBreakdown.length === 0) {
109
+ return (
110
+ <WidgetShell>
111
+ <TableEmptyState variant="done">{t("aFailureRate.emptyState")}</TableEmptyState>
112
+ </WidgetShell>
113
+ )
114
+ }
115
+ const max = Math.max(0, ...data.processBreakdown.map((p) => p.incidentRatePct ?? 0))
116
+ return (
117
+ <WidgetShell>
118
+ <Section
119
+ title={t("aFailureRate.heading")}
120
+ count={data.processBreakdown.length}
121
+ defaultOpen
122
+ >
123
+ <ListTable ariaLabel={t("aFailureRate.tableLabel")} columns={columns(t)}>
124
+ {data.processBreakdown.map((proc) => (
125
+ <tr key={proc.processDefinitionKey}>
126
+ <Td>
127
+ <NamedId
128
+ name={processNameOf(data.names, proc.processDefinitionKey)}
129
+ id={proc.processDefinitionKey}
130
+ />
131
+ </Td>
132
+ <Td align="right" className="tabular-nums">
133
+ {formatNumber(proc.runningNow)}
134
+ </Td>
135
+ {/* The states of a process (decision f), on the kit's one
136
+ ladder: open incidents and dead jobs (no retries left)
137
+ edged in danger while there are any, as camunda7 and
138
+ the landscape show them; none is a plain count. */}
139
+ <Td align="right" className="tabular-nums">
140
+ <StateCount value={proc.openIncidents} />
141
+ </Td>
142
+ <Td align="right" className="tabular-nums">
143
+ <StateCount value={proc.deadJobs} />
144
+ </Td>
145
+ <Td align="right">
146
+ <RateCell rate={proc.incidentRatePct} max={max} t={t} />
147
+ </Td>
148
+ <Td align="right">
149
+ <HandOffButton
150
+ action="findCause"
151
+ variant="icon"
152
+ prompt={ask(failureRateHandOff(proc, data))}
153
+ />
154
+ </Td>
155
+ </tr>
156
+ ))}
157
+ </ListTable>
158
+ <FigureLegend
159
+ reasons={[
160
+ data.processBreakdown.some((p) => p.incidentRatePct === null) &&
161
+ t("aFigure.noRate"),
162
+ ]}
163
+ />
164
+ </Section>
165
+ </WidgetShell>
166
+ )
167
+ }}
168
+ </QueryGate>
169
+ )
170
+ }
@@ -0,0 +1,32 @@
1
+ import { useToolQuery } from "@miragon/mcp-toolkit-ui"
2
+ import type { EngineFilterInput, FailureDashboardData } from "@miragon/pulse-analytics-client"
3
+ import type { Named } from "../../bpmn-names.js"
4
+ import { ANALYTICS_FAILURE_DASHBOARD_DATA } from "../../tool-names.js"
5
+
6
+ /** The failure payload the widgets read: the figures plus the process names behind their keys. */
7
+ export type FailureView = Named<FailureDashboardData>
8
+
9
+ /** The cell props every failure widget takes — the engine scope its self-fetch reads. */
10
+ export interface FailureScopeProps {
11
+ /** Configured engine id(s); omitted = every configured engine (the feed resolves it). */
12
+ engine?: EngineFilterInput
13
+ }
14
+
15
+ // Centralised so the three failure widgets share one self-fetch contract. The
16
+ // failure dashboard is point-in-time (live state gauges), so there is no period
17
+ // scope — only the engine scope, carried in the args AND the cache key so an
18
+ // engine-scoped cell never reads a fleet-wide entry. Self-fetches the app-only
19
+ // *_data feed — calling the show_* tool from inside the iframe is host-defined
20
+ // behavior (hosts honoring resultCanProduceWidget may render a second widget
21
+ // per refresh).
22
+ export function useFailureDashboardSelfFetch(
23
+ initialData: FailureView | null,
24
+ { engine }: FailureScopeProps,
25
+ ) {
26
+ return useToolQuery<FailureView>(
27
+ ["analytics:failure-dashboard", engine ?? null],
28
+ ANALYTICS_FAILURE_DASHBOARD_DATA,
29
+ engine === undefined ? {} : { engine },
30
+ { enabled: !initialData },
31
+ )
32
+ }
@@ -0,0 +1,122 @@
1
+ import {
2
+ HandOffButton,
3
+ ViewMeta,
4
+ WidgetShell,
5
+ formatNumber,
6
+ } from "@miragon/pulse-widget-shell/widgets"
7
+ import type { FailureDashboardData } from "@miragon/pulse-analytics-client"
8
+ import { KpiGrid, KpiGridSkeleton, WidgetHeader, cn, type KpiCell } from "@miragon/mcp-toolkit-ui"
9
+ import { useFailureDashboardSelfFetch, type FailureScopeProps, type FailureView } from "./lib.js"
10
+ import { QueryGate } from "../query-gate.js"
11
+ import { useT, type T } from "../../messages/use-t.js"
12
+ import { processNameOf } from "../../bpmn-names.js"
13
+ import { engineIdsOf, useHandOff, type HandOff } from "../hand-off.js"
14
+ import { enginesMeta } from "../view-meta.js"
15
+
16
+ /**
17
+ * Triage of the open-incident snapshot. Only the headline numbers travel —
18
+ * the patterns themselves are read through the tools (bounded, and their
19
+ * messages stay tool output instead of the user's own words).
20
+ */
21
+ export function failureSummaryHandOff(data: FailureDashboardData): HandOff {
22
+ return {
23
+ intent: "askAi.failureSummary",
24
+ ids: { engine: engineIdsOf(data.engines) },
25
+ facts: {
26
+ openIncidentsNow: data.totalIncidents,
27
+ incidentGroups: data.uniqueErrorPatterns,
28
+ mostAffectedProcess: data.mostAffectedProcess,
29
+ },
30
+ tools: [
31
+ "analytics_find_failed_instances",
32
+ "analytics_show_failure_dashboard",
33
+ "camunda7_list_incidents",
34
+ "camunda7_query_historic_incidents",
35
+ ],
36
+ }
37
+ }
38
+
39
+ /**
40
+ * The most affected process as a figure: its name (the key below it, quiet),
41
+ * or the key alone in mono when the model's name is unknown. With no open
42
+ * incident no process is affected, and the cell says so in quiet words: "—"
43
+ * means a figure nobody measured (U17), and this one is known.
44
+ */
45
+ function mostAffectedCell(t: T, data: FailureView): KpiCell {
46
+ const label = t("aFailureSummary.mostAffected")
47
+ const key = data.mostAffectedProcess
48
+ if (!key) {
49
+ return {
50
+ label,
51
+ value: (
52
+ <span className="text-section text-muted-foreground block">
53
+ {t("aFailureSummary.mostAffectedNone")}
54
+ </span>
55
+ ),
56
+ }
57
+ }
58
+ const name = processNameOf(data.names, key)
59
+ return {
60
+ label,
61
+ value: (
62
+ <span className={cn("text-section block break-words", !name && "font-mono")}>
63
+ {name ?? key}
64
+ </span>
65
+ ),
66
+ trend: name ? <span className="font-mono break-all">{key}</span> : undefined,
67
+ }
68
+ }
69
+
70
+ export function FailureSummaryKpi({
71
+ data: initialData,
72
+ engine,
73
+ }: { data: FailureView | null } & FailureScopeProps) {
74
+ const fallbackQuery = useFailureDashboardSelfFetch(initialData, { engine })
75
+ const t = useT()
76
+ const { ask } = useHandOff()
77
+
78
+ return (
79
+ <QueryGate
80
+ initialData={initialData}
81
+ query={fallbackQuery}
82
+ header={<WidgetHeader title={t("aFailureSummary.title")} />}
83
+ skeleton={<KpiGridSkeleton cells={3} boxed />}
84
+ >
85
+ {(data) => (
86
+ <WidgetShell>
87
+ <WidgetHeader
88
+ title={t("aFailureSummary.title")}
89
+ // A live snapshot: no period, the engines and when it was read.
90
+ sub={<ViewMeta engines={enginesMeta(data.engines)} asOf={data.asOf} />}
91
+ actions={
92
+ <HandOffButton
93
+ action="prioritize"
94
+ variant="primary"
95
+ prompt={ask(failureSummaryHandOff(data))}
96
+ />
97
+ }
98
+ />
99
+ {/* The dashboards' one KPI pattern (U14): a neutral strip, the state
100
+ as a dot. Only an open incident is a state (danger); how many
101
+ groups they form and which process has the most are neutral. */}
102
+ <KpiGrid
103
+ boxed
104
+ ariaLabel={t("aFailureSummary.summaryAriaLabel")}
105
+ cells={[
106
+ {
107
+ label: t("aFailureSummary.totalIncidents"),
108
+ value: formatNumber(data.totalIncidents),
109
+ tone: data.totalIncidents > 0 ? "danger" : undefined,
110
+ },
111
+ {
112
+ label: t("aFailureSummary.uniqueErrorPatterns"),
113
+ value: formatNumber(data.uniqueErrorPatterns),
114
+ },
115
+ mostAffectedCell(t, data),
116
+ ]}
117
+ />
118
+ </WidgetShell>
119
+ )}
120
+ </QueryGate>
121
+ )
122
+ }