@miragon/pulse-analytics-connector 0.0.0-stage → 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.
- package/LICENSE +21 -0
- package/README.md +87 -2
- package/dist/bpmn-name-lookup.d.ts +72 -0
- package/dist/bpmn-name-lookup.d.ts.map +1 -0
- package/dist/bpmn-name-lookup.js +123 -0
- package/dist/bpmn-name-lookup.js.map +1 -0
- package/dist/bpmn-name-lookup.test.d.ts +2 -0
- package/dist/bpmn-name-lookup.test.d.ts.map +1 -0
- package/dist/bpmn-name-lookup.test.js +287 -0
- package/dist/bpmn-name-lookup.test.js.map +1 -0
- package/dist/bpmn-names.d.ts +38 -0
- package/dist/bpmn-names.d.ts.map +1 -0
- package/dist/bpmn-names.js +22 -0
- package/dist/bpmn-names.js.map +1 -0
- package/dist/brand-gates.test.d.ts +2 -0
- package/dist/brand-gates.test.d.ts.map +1 -0
- package/dist/brand-gates.test.js +58 -0
- package/dist/brand-gates.test.js.map +1 -0
- package/dist/builder-texts.d.ts +4 -0
- package/dist/builder-texts.d.ts.map +1 -0
- package/dist/builder-texts.js +14 -0
- package/dist/builder-texts.js.map +1 -0
- package/dist/builder-texts.test.d.ts +2 -0
- package/dist/builder-texts.test.d.ts.map +1 -0
- package/dist/builder-texts.test.js +32 -0
- package/dist/builder-texts.test.js.map +1 -0
- package/dist/definition.d.ts +3 -0
- package/dist/definition.d.ts.map +1 -0
- package/dist/definition.js +151 -0
- package/dist/definition.js.map +1 -0
- package/dist/engine-ids.d.ts +42 -0
- package/dist/engine-ids.d.ts.map +1 -0
- package/dist/engine-ids.js +50 -0
- package/dist/engine-ids.js.map +1 -0
- package/dist/engine-scope.test.d.ts +2 -0
- package/dist/engine-scope.test.d.ts.map +1 -0
- package/dist/engine-scope.test.js +260 -0
- package/dist/engine-scope.test.js.map +1 -0
- package/dist/heatmap-data.d.ts +15 -0
- package/dist/heatmap-data.d.ts.map +1 -0
- package/dist/heatmap-data.js +2 -0
- package/dist/heatmap-data.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/instructions.d.ts +8 -0
- package/dist/instructions.d.ts.map +1 -0
- package/dist/instructions.js +33 -0
- package/dist/instructions.js.map +1 -0
- package/dist/messages/de.ask-ai.d.ts +9 -0
- package/dist/messages/de.ask-ai.d.ts.map +1 -0
- package/dist/messages/de.ask-ai.js +18 -0
- package/dist/messages/de.ask-ai.js.map +1 -0
- package/dist/messages/de.builder.d.ts +12 -0
- package/dist/messages/de.builder.d.ts.map +1 -0
- package/dist/messages/de.builder.js +53 -0
- package/dist/messages/de.builder.js.map +1 -0
- package/dist/messages/de.server.d.ts +8 -0
- package/dist/messages/de.server.d.ts.map +1 -0
- package/dist/messages/de.server.js +26 -0
- package/dist/messages/de.server.js.map +1 -0
- package/dist/messages/de.sweep.d.ts +10 -0
- package/dist/messages/de.sweep.d.ts.map +1 -0
- package/dist/messages/de.sweep.js +203 -0
- package/dist/messages/de.sweep.js.map +1 -0
- package/dist/messages/en.ask-ai.d.ts +25 -0
- package/dist/messages/en.ask-ai.d.ts.map +1 -0
- package/dist/messages/en.ask-ai.js +24 -0
- package/dist/messages/en.ask-ai.js.map +1 -0
- package/dist/messages/en.builder.d.ts +12 -0
- package/dist/messages/en.builder.d.ts.map +1 -0
- package/dist/messages/en.builder.js +53 -0
- package/dist/messages/en.builder.js.map +1 -0
- package/dist/messages/en.server.d.ts +8 -0
- package/dist/messages/en.server.d.ts.map +1 -0
- package/dist/messages/en.server.js +26 -0
- package/dist/messages/en.server.js.map +1 -0
- package/dist/messages/en.sweep.d.ts +11 -0
- package/dist/messages/en.sweep.d.ts.map +1 -0
- package/dist/messages/en.sweep.js +204 -0
- package/dist/messages/en.sweep.js.map +1 -0
- package/dist/messages/glossary.d.ts +26 -0
- package/dist/messages/glossary.d.ts.map +1 -0
- package/dist/messages/glossary.js +37 -0
- package/dist/messages/glossary.js.map +1 -0
- package/dist/messages/glossary.test.d.ts +2 -0
- package/dist/messages/glossary.test.d.ts.map +1 -0
- package/dist/messages/glossary.test.js +109 -0
- package/dist/messages/glossary.test.js.map +1 -0
- package/dist/messages/index.d.ts +12 -0
- package/dist/messages/index.d.ts.map +1 -0
- package/dist/messages/index.js +23 -0
- package/dist/messages/index.js.map +1 -0
- package/dist/messages/plural.d.ts +10 -0
- package/dist/messages/plural.d.ts.map +1 -0
- package/dist/messages/plural.js +17 -0
- package/dist/messages/plural.js.map +1 -0
- package/dist/messages/use-t.d.ts +10 -0
- package/dist/messages/use-t.d.ts.map +1 -0
- package/dist/messages/use-t.js +10 -0
- package/dist/messages/use-t.js.map +1 -0
- package/dist/module.d.ts +48 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +174 -0
- package/dist/module.js.map +1 -0
- package/dist/module.test.d.ts +2 -0
- package/dist/module.test.d.ts.map +1 -0
- package/dist/module.test.js +230 -0
- package/dist/module.test.js.map +1 -0
- package/dist/named-views.d.ts +27 -0
- package/dist/named-views.d.ts.map +1 -0
- package/dist/named-views.js +73 -0
- package/dist/named-views.js.map +1 -0
- package/dist/named-views.test.d.ts +2 -0
- package/dist/named-views.test.d.ts.map +1 -0
- package/dist/named-views.test.js +110 -0
- package/dist/named-views.test.js.map +1 -0
- package/dist/plugin.d.ts +44 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +52 -0
- package/dist/plugin.js.map +1 -0
- package/dist/prometheus-wiring.test.d.ts +2 -0
- package/dist/prometheus-wiring.test.d.ts.map +1 -0
- package/dist/prometheus-wiring.test.js +142 -0
- package/dist/prometheus-wiring.test.js.map +1 -0
- package/dist/server-locale.d.ts +48 -0
- package/dist/server-locale.d.ts.map +1 -0
- package/dist/server-locale.js +33 -0
- package/dist/server-locale.js.map +1 -0
- package/dist/settings-tools.d.ts +23 -0
- package/dist/settings-tools.d.ts.map +1 -0
- package/dist/settings-tools.js +100 -0
- package/dist/settings-tools.js.map +1 -0
- package/dist/settings.d.ts +77 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +99 -0
- package/dist/settings.js.map +1 -0
- package/dist/settings.test.d.ts +2 -0
- package/dist/settings.test.d.ts.map +1 -0
- package/dist/settings.test.js +299 -0
- package/dist/settings.test.js.map +1 -0
- package/dist/steps/app-config.d.ts +30 -0
- package/dist/steps/app-config.d.ts.map +1 -0
- package/dist/steps/app-config.js +46 -0
- package/dist/steps/app-config.js.map +1 -0
- package/dist/steps/dashboard.d.ts +12 -0
- package/dist/steps/dashboard.d.ts.map +1 -0
- package/dist/steps/dashboard.js +58 -0
- package/dist/steps/dashboard.js.map +1 -0
- package/dist/steps/failure-dashboard.d.ts +10 -0
- package/dist/steps/failure-dashboard.d.ts.map +1 -0
- package/dist/steps/failure-dashboard.js +32 -0
- package/dist/steps/failure-dashboard.js.map +1 -0
- package/dist/steps/index.d.ts +3 -0
- package/dist/steps/index.d.ts.map +1 -0
- package/dist/steps/index.js +3 -0
- package/dist/steps/index.js.map +1 -0
- package/dist/steps/steps.test.d.ts +2 -0
- package/dist/steps/steps.test.d.ts.map +1 -0
- package/dist/steps/steps.test.js +153 -0
- package/dist/steps/steps.test.js.map +1 -0
- package/dist/tool-names.d.ts +13 -0
- package/dist/tool-names.d.ts.map +1 -0
- package/dist/tool-names.js +27 -0
- package/dist/tool-names.js.map +1 -0
- package/dist/tools/cluster-compare.d.ts +8 -0
- package/dist/tools/cluster-compare.d.ts.map +1 -0
- package/dist/tools/cluster-compare.js +17 -0
- package/dist/tools/cluster-compare.js.map +1 -0
- package/dist/tools/element.d.ts +8 -0
- package/dist/tools/element.d.ts.map +1 -0
- package/dist/tools/element.js +25 -0
- package/dist/tools/element.js.map +1 -0
- package/dist/tools/engine-compare.d.ts +8 -0
- package/dist/tools/engine-compare.d.ts.map +1 -0
- package/dist/tools/engine-compare.js +18 -0
- package/dist/tools/engine-compare.js.map +1 -0
- package/dist/tools/engine-compare.test.d.ts +2 -0
- package/dist/tools/engine-compare.test.d.ts.map +1 -0
- package/dist/tools/engine-compare.test.js +166 -0
- package/dist/tools/engine-compare.test.js.map +1 -0
- package/dist/tools/engine-landscape.d.ts +7 -0
- package/dist/tools/engine-landscape.d.ts.map +1 -0
- package/dist/tools/engine-landscape.js +13 -0
- package/dist/tools/engine-landscape.js.map +1 -0
- package/dist/tools/engine-landscape.test.d.ts +2 -0
- package/dist/tools/engine-landscape.test.d.ts.map +1 -0
- package/dist/tools/engine-landscape.test.js +110 -0
- package/dist/tools/engine-landscape.test.js.map +1 -0
- package/dist/tools/failures.d.ts +7 -0
- package/dist/tools/failures.d.ts.map +1 -0
- package/dist/tools/failures.js +13 -0
- package/dist/tools/failures.js.map +1 -0
- package/dist/tools/health.d.ts +7 -0
- package/dist/tools/health.d.ts.map +1 -0
- package/dist/tools/health.js +23 -0
- package/dist/tools/health.js.map +1 -0
- package/dist/tools/health.test.d.ts +2 -0
- package/dist/tools/health.test.d.ts.map +1 -0
- package/dist/tools/health.test.js +119 -0
- package/dist/tools/health.test.js.map +1 -0
- package/dist/tools/index.d.ts +18 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +35 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/performance.d.ts +8 -0
- package/dist/tools/performance.d.ts.map +1 -0
- package/dist/tools/performance.js +25 -0
- package/dist/tools/performance.js.map +1 -0
- package/dist/tools/performance.test.d.ts +2 -0
- package/dist/tools/performance.test.d.ts.map +1 -0
- package/dist/tools/performance.test.js +176 -0
- package/dist/tools/performance.test.js.map +1 -0
- package/dist/tools/version-compare.d.ts +8 -0
- package/dist/tools/version-compare.d.ts.map +1 -0
- package/dist/tools/version-compare.js +17 -0
- package/dist/tools/version-compare.js.map +1 -0
- package/dist/tools/version-compare.test.d.ts +2 -0
- package/dist/tools/version-compare.test.d.ts.map +1 -0
- package/dist/tools/version-compare.test.js +82 -0
- package/dist/tools/version-compare.test.js.map +1 -0
- package/dist/toolsets.d.ts +17 -0
- package/dist/toolsets.d.ts.map +1 -0
- package/dist/toolsets.js +47 -0
- package/dist/toolsets.js.map +1 -0
- package/dist/toolsets.test.d.ts +2 -0
- package/dist/toolsets.test.d.ts.map +1 -0
- package/dist/toolsets.test.js +91 -0
- package/dist/toolsets.test.js.map +1 -0
- package/dist/view-title.test.d.ts +2 -0
- package/dist/view-title.test.d.ts.map +1 -0
- package/dist/view-title.test.js +91 -0
- package/dist/view-title.test.js.map +1 -0
- package/dist/widget-tools/comparisons.d.ts +13 -0
- package/dist/widget-tools/comparisons.d.ts.map +1 -0
- package/dist/widget-tools/comparisons.js +177 -0
- package/dist/widget-tools/comparisons.js.map +1 -0
- package/dist/widget-tools/comparisons.test.d.ts +2 -0
- package/dist/widget-tools/comparisons.test.d.ts.map +1 -0
- package/dist/widget-tools/comparisons.test.js +123 -0
- package/dist/widget-tools/comparisons.test.js.map +1 -0
- package/dist/widget-tools/shared.d.ts +36 -0
- package/dist/widget-tools/shared.d.ts.map +1 -0
- package/dist/widget-tools/shared.js +39 -0
- package/dist/widget-tools/shared.js.map +1 -0
- package/dist/widget-tools.d.ts +25 -0
- package/dist/widget-tools.d.ts.map +1 -0
- package/dist/widget-tools.js +269 -0
- package/dist/widget-tools.js.map +1 -0
- package/dist/widget-tools.test.d.ts +2 -0
- package/dist/widget-tools.test.d.ts.map +1 -0
- package/dist/widget-tools.test.js +272 -0
- package/dist/widget-tools.test.js.map +1 -0
- package/package.json +91 -3
- package/src/bpmn-name-lookup.test.ts +333 -0
- package/src/bpmn-name-lookup.ts +197 -0
- package/src/bpmn-names.ts +51 -0
- package/src/brand-gates.test.ts +69 -0
- package/src/builder-texts.test.ts +40 -0
- package/src/builder-texts.ts +15 -0
- package/src/definition.ts +181 -0
- package/src/engine-ids.ts +85 -0
- package/src/engine-scope.test.ts +324 -0
- package/src/heatmap-data.ts +14 -0
- package/src/index.ts +4 -0
- package/src/instructions.ts +33 -0
- package/src/messages/GLOSSARY.md +88 -0
- package/src/messages/de.ask-ai.ts +28 -0
- package/src/messages/de.builder.ts +77 -0
- package/src/messages/de.server.ts +39 -0
- package/src/messages/de.sweep.ts +244 -0
- package/src/messages/en.ask-ai.ts +34 -0
- package/src/messages/en.builder.ts +76 -0
- package/src/messages/en.server.ts +39 -0
- package/src/messages/en.sweep.ts +240 -0
- package/src/messages/glossary.test.ts +122 -0
- package/src/messages/glossary.ts +62 -0
- package/src/messages/index.ts +24 -0
- package/src/messages/plural.ts +18 -0
- package/src/messages/use-t.ts +12 -0
- package/src/module.test.ts +319 -0
- package/src/module.ts +211 -0
- package/src/named-views.test.ts +141 -0
- package/src/named-views.ts +97 -0
- package/src/plugin.ts +94 -0
- package/src/prometheus-wiring.test.ts +174 -0
- package/src/server-locale.ts +59 -0
- package/src/settings-tools.ts +170 -0
- package/src/settings.test.ts +402 -0
- package/src/settings.ts +114 -0
- package/src/steps/app-config.ts +75 -0
- package/src/steps/dashboard.ts +73 -0
- package/src/steps/failure-dashboard.ts +38 -0
- package/src/steps/index.ts +2 -0
- package/src/steps/steps.test.ts +216 -0
- package/src/tool-names.ts +26 -0
- package/src/tools/cluster-compare.ts +28 -0
- package/src/tools/element.ts +35 -0
- package/src/tools/engine-compare.test.ts +210 -0
- package/src/tools/engine-compare.ts +30 -0
- package/src/tools/engine-landscape.test.ts +138 -0
- package/src/tools/engine-landscape.ts +21 -0
- package/src/tools/failures.ts +19 -0
- package/src/tools/health.test.ts +156 -0
- package/src/tools/health.ts +29 -0
- package/src/tools/index.ts +44 -0
- package/src/tools/performance.test.ts +210 -0
- package/src/tools/performance.ts +38 -0
- package/src/tools/version-compare.test.ts +97 -0
- package/src/tools/version-compare.ts +28 -0
- package/src/toolsets.test.ts +107 -0
- package/src/toolsets.ts +56 -0
- package/src/view-title.test.ts +123 -0
- package/src/widget-tools/comparisons.test.ts +170 -0
- package/src/widget-tools/comparisons.ts +229 -0
- package/src/widget-tools/shared.ts +67 -0
- package/src/widget-tools.test.ts +306 -0
- package/src/widget-tools.ts +375 -0
- package/src/widgets/analytics-dashboard/activity-bottleneck-table.tsx +179 -0
- package/src/widgets/analytics-dashboard/definition-breakdown.tsx +108 -0
- package/src/widgets/analytics-dashboard/execution-performance-kpi.tsx +94 -0
- package/src/widgets/analytics-dashboard/execution-summary-kpi.tsx +122 -0
- package/src/widgets/analytics-dashboard/lib.ts +43 -0
- package/src/widgets/bpmn-heatmap.test.tsx +75 -0
- package/src/widgets/bpmn-heatmap.tsx +127 -0
- package/src/widgets/catalogue-sync.test.ts +16 -0
- package/src/widgets/cluster-compare.tsx +148 -0
- package/src/widgets/comparison-shared.test.ts +237 -0
- package/src/widgets/comparison-shared.tsx +371 -0
- package/src/widgets/comparison-widgets.test.tsx +307 -0
- package/src/widgets/dashboard-widgets.test.tsx +397 -0
- package/src/widgets/engine-compare.tsx +87 -0
- package/src/widgets/engine-landscape.tsx +352 -0
- package/src/widgets/failure-dashboard/error-patterns-table.tsx +122 -0
- package/src/widgets/failure-dashboard/failure-rate-table.test.ts +80 -0
- package/src/widgets/failure-dashboard/failure-rate-table.tsx +170 -0
- package/src/widgets/failure-dashboard/lib.ts +32 -0
- package/src/widgets/failure-dashboard/summary-kpi.tsx +122 -0
- package/src/widgets/failure-landscape-widgets.test.tsx +393 -0
- package/src/widgets/figure.tsx +79 -0
- package/src/widgets/hand-off.test.ts +126 -0
- package/src/widgets/hand-off.ts +102 -0
- package/src/widgets/index.ts +124 -0
- package/src/widgets/model-descriptions.dashboard.test.ts +280 -0
- package/src/widgets/model-descriptions.test.ts +251 -0
- package/src/widgets/model-descriptions.ts +428 -0
- package/src/widgets/names.test.ts +32 -0
- package/src/widgets/names.ts +39 -0
- package/src/widgets/query-gate.test.tsx +57 -0
- package/src/widgets/query-gate.tsx +50 -0
- package/src/widgets/settings-section.test.tsx +174 -0
- package/src/widgets/settings-section.tsx +244 -0
- package/src/widgets/version-compare.test.ts +68 -0
- package/src/widgets/version-compare.tsx +96 -0
- package/src/widgets/view-meta.ts +18 -0
- package/src/widgets/widget-render.test-support.tsx +103 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { useMemo } from "react"
|
|
2
|
+
import { useLocale, useToolQuery } from "@miragon/mcp-toolkit-ui"
|
|
3
|
+
import {
|
|
4
|
+
askAiPrompt,
|
|
5
|
+
modelContextText,
|
|
6
|
+
type AskAiPrompt,
|
|
7
|
+
type HandOffParts,
|
|
8
|
+
type ModelContextSpec,
|
|
9
|
+
type ToolSurface,
|
|
10
|
+
} from "@miragon/pulse-widget-shell/widgets"
|
|
11
|
+
import type { AnalyticsAskAiKey } from "../messages/en.ask-ai.js"
|
|
12
|
+
import { translator } from "../messages/index.js"
|
|
13
|
+
|
|
14
|
+
/** An analytics hand-off: catalogue intent + the typed parts (the surface is added by the hook). */
|
|
15
|
+
export interface HandOff extends Omit<HandOffParts, "surface"> {
|
|
16
|
+
intent: AnalyticsAskAiKey
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** An analytics view context: static summary + the typed parts. */
|
|
20
|
+
export type ViewContext = Omit<ModelContextSpec, "surface">
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The camunda7 module's surface feed, by raw name — a tier-2 cross-module
|
|
24
|
+
* reference (string, not import; cf. camunda7's `analytics-probe.ts`). It
|
|
25
|
+
* reports the camunda7 tools the deployment registers for the model; when
|
|
26
|
+
* camunda7 is not active the call fails and no camunda7 tool is ever named.
|
|
27
|
+
*/
|
|
28
|
+
const CAMUNDA7_SURFACE_FEED = "camunda7_widget_actions_data"
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The tools an analytics widget may name for the model:
|
|
32
|
+
*
|
|
33
|
+
* - `analytics_*` — the module is active (its own widget is rendering), and
|
|
34
|
+
* every analytics tool a hand-off names is registered by its read-only
|
|
35
|
+
* floor (pinned by the app's hand-off surface test);
|
|
36
|
+
* - `camunda7_*` — exactly what `camunda7_widget_actions_data` reports, once
|
|
37
|
+
* it answered (fails closed before, and without the camunda7 module).
|
|
38
|
+
*/
|
|
39
|
+
export function analyticsSurface(camunda7ModelTools: readonly string[] | undefined): ToolSurface {
|
|
40
|
+
return {
|
|
41
|
+
has: (tool) => tool.startsWith("analytics_") || (camunda7ModelTools?.includes(tool) ?? false),
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The surface a model description can rely on WITHOUT a live query (the
|
|
47
|
+
* adapter's `describeForModel` is a pure function): analytics tools only.
|
|
48
|
+
*/
|
|
49
|
+
export const ANALYTICS_ONLY_SURFACE = analyticsSurface(undefined)
|
|
50
|
+
|
|
51
|
+
/** {@link analyticsSurface} over the live camunda7 feed. */
|
|
52
|
+
export function useAnalyticsSurface(): ToolSurface {
|
|
53
|
+
const modelTools = useToolQuery<{ modelTools?: string[] }>(
|
|
54
|
+
["camunda7-widget-actions"],
|
|
55
|
+
CAMUNDA7_SURFACE_FEED,
|
|
56
|
+
{},
|
|
57
|
+
).data?.modelTools
|
|
58
|
+
return useMemo(() => analyticsSurface(modelTools), [modelTools])
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Pure binding of the builders to a locale and surface (the hook's body; testable without React). */
|
|
62
|
+
export function bindHandOff(locale: string, surface: ToolSurface) {
|
|
63
|
+
return {
|
|
64
|
+
surface,
|
|
65
|
+
/** The Ask-AI prompt for `HandOffButton` — null when nothing in it is available here. */
|
|
66
|
+
ask: (handOff: HandOff): AskAiPrompt | null =>
|
|
67
|
+
askAiPrompt({ ...handOff, intent: translator(locale, handOff.intent), locale, surface }),
|
|
68
|
+
/** The `HostModelContext` text for a view. */
|
|
69
|
+
context: (view: ViewContext): string => modelContextText({ ...view, surface }),
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* The analytics widgets' ONE way to talk to the model: Ask-AI prompts and
|
|
75
|
+
* model contexts, localized to the active locale and filtered by the live
|
|
76
|
+
* tool surface (CLAUDE.md invariant 6).
|
|
77
|
+
*/
|
|
78
|
+
export function useHandOff() {
|
|
79
|
+
const surface = useAnalyticsSurface()
|
|
80
|
+
const locale = useLocale()
|
|
81
|
+
return useMemo(() => bindHandOff(locale, surface), [locale, surface])
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* The engine scope a hand-off or model context states: the result's `engines`
|
|
86
|
+
* echo — the ids the server resolved from its CONFIGURED set for the data on
|
|
87
|
+
* screen (#336) — as the `engine` id a follow-up call takes: the one id, the
|
|
88
|
+
* aggregated list, or nothing for an unscoped library result. Never a cell
|
|
89
|
+
* prop: the scope named must be the scope of the numbers shown, and an id the
|
|
90
|
+
* server did not resolve is one analytics would refuse.
|
|
91
|
+
*/
|
|
92
|
+
export function engineIdsOf(
|
|
93
|
+
engines: readonly string[] | null | undefined,
|
|
94
|
+
): string | string[] | undefined {
|
|
95
|
+
if (!engines || engines.length === 0) return undefined
|
|
96
|
+
return engines.length === 1 ? engines[0] : [...engines]
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** True when the figures add up several engines (the deliberate fleet aggregate). */
|
|
100
|
+
export function isAggregate(engines: readonly string[] | null | undefined): boolean {
|
|
101
|
+
return (engines?.length ?? 0) > 1
|
|
102
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { adaptDataWidget } from "@miragon/pulse-widget-shell/ui"
|
|
2
|
+
import type { WidgetComponent } from "@miragon/mcp-toolkit-ui/app"
|
|
3
|
+
import type { AnalyticsDashboardData, FailureDashboardData } from "@miragon/pulse-analytics-client"
|
|
4
|
+
import { ExecutionSummaryKpi } from "./analytics-dashboard/execution-summary-kpi.js"
|
|
5
|
+
import { ExecutionPerformanceKpi } from "./analytics-dashboard/execution-performance-kpi.js"
|
|
6
|
+
import { ProcessDefinitionBreakdown } from "./analytics-dashboard/definition-breakdown.js"
|
|
7
|
+
import { ActivityBottleneckTable } from "./analytics-dashboard/activity-bottleneck-table.js"
|
|
8
|
+
import { FailureSummaryKpi } from "./failure-dashboard/summary-kpi.js"
|
|
9
|
+
import { ErrorPatternsTable } from "./failure-dashboard/error-patterns-table.js"
|
|
10
|
+
import { FailureRateTable } from "./failure-dashboard/failure-rate-table.js"
|
|
11
|
+
import { ClusterCompareWidget, type ClusterCompareData } from "./cluster-compare.js"
|
|
12
|
+
import { VersionCompareWidget, type VersionCompareData } from "./version-compare.js"
|
|
13
|
+
import { EngineCompareWidget, type EngineCompareData } from "./engine-compare.js"
|
|
14
|
+
import { EngineLandscapeWidget, type EngineLandscapeData } from "./engine-landscape.js"
|
|
15
|
+
import { type BpmnHeatmapData } from "@miragon/pulse-widget-shell/widgets"
|
|
16
|
+
import { AnalyticsBpmnHeatmap, type AnalyticsBpmnHeatmapData } from "./bpmn-heatmap.js"
|
|
17
|
+
import { AnalyticsSettingsWidget, type AnalyticsSettingsViewData } from "./settings-section.js"
|
|
18
|
+
import {
|
|
19
|
+
describeActivityBottlenecks,
|
|
20
|
+
describeBpmnHeatmap,
|
|
21
|
+
describeClusterCompare,
|
|
22
|
+
describeDefinitionBreakdown,
|
|
23
|
+
describeEngineCompare,
|
|
24
|
+
describeEngineLandscape,
|
|
25
|
+
describeErrorPatterns,
|
|
26
|
+
describeExecutionPerformance,
|
|
27
|
+
describeExecutionSummary,
|
|
28
|
+
describeFailureRates,
|
|
29
|
+
describeFailureSummary,
|
|
30
|
+
describeVersionCompare,
|
|
31
|
+
} from "./model-descriptions.js"
|
|
32
|
+
|
|
33
|
+
export type {
|
|
34
|
+
AnalyticsDashboardData,
|
|
35
|
+
FailureDashboardData,
|
|
36
|
+
ClusterCompareData,
|
|
37
|
+
VersionCompareData,
|
|
38
|
+
EngineCompareData,
|
|
39
|
+
EngineLandscapeData,
|
|
40
|
+
BpmnHeatmapData,
|
|
41
|
+
AnalyticsBpmnHeatmapData,
|
|
42
|
+
AnalyticsSettingsViewData,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const ANALYTICS_DATA_TYPES = {
|
|
46
|
+
dashboard: "analytics:dashboard",
|
|
47
|
+
failureDashboard: "analytics:failureDashboard",
|
|
48
|
+
clusterCompare: "analytics:clusterCompare",
|
|
49
|
+
versionCompare: "analytics:versionCompare",
|
|
50
|
+
engineCompare: "analytics:engineCompare",
|
|
51
|
+
engineLandscape: "analytics:engineLandscape",
|
|
52
|
+
bpmnHeatmap: "analytics:bpmnHeatmap",
|
|
53
|
+
settings: "analytics:settings",
|
|
54
|
+
} as const
|
|
55
|
+
|
|
56
|
+
// Every widget passes a `describeForModel` so the model always knows the view,
|
|
57
|
+
// its active filters (period / engine scope) and the headline numbers — see
|
|
58
|
+
// `model-descriptions.ts` for the house pattern.
|
|
59
|
+
export const analyticsWidgets: Record<string, WidgetComponent> = {
|
|
60
|
+
"analytics:execution-summary-kpi": adaptDataWidget(
|
|
61
|
+
ExecutionSummaryKpi,
|
|
62
|
+
ANALYTICS_DATA_TYPES.dashboard,
|
|
63
|
+
describeExecutionSummary,
|
|
64
|
+
),
|
|
65
|
+
"analytics:execution-performance-kpi": adaptDataWidget(
|
|
66
|
+
ExecutionPerformanceKpi,
|
|
67
|
+
ANALYTICS_DATA_TYPES.dashboard,
|
|
68
|
+
describeExecutionPerformance,
|
|
69
|
+
),
|
|
70
|
+
"analytics:process-definition-breakdown": adaptDataWidget(
|
|
71
|
+
ProcessDefinitionBreakdown,
|
|
72
|
+
ANALYTICS_DATA_TYPES.dashboard,
|
|
73
|
+
describeDefinitionBreakdown,
|
|
74
|
+
),
|
|
75
|
+
"analytics:activity-bottleneck-table": adaptDataWidget(
|
|
76
|
+
ActivityBottleneckTable,
|
|
77
|
+
ANALYTICS_DATA_TYPES.dashboard,
|
|
78
|
+
describeActivityBottlenecks,
|
|
79
|
+
),
|
|
80
|
+
"analytics:failure-summary-kpi": adaptDataWidget(
|
|
81
|
+
FailureSummaryKpi,
|
|
82
|
+
ANALYTICS_DATA_TYPES.failureDashboard,
|
|
83
|
+
describeFailureSummary,
|
|
84
|
+
),
|
|
85
|
+
"analytics:error-patterns-table": adaptDataWidget(
|
|
86
|
+
ErrorPatternsTable,
|
|
87
|
+
ANALYTICS_DATA_TYPES.failureDashboard,
|
|
88
|
+
describeErrorPatterns,
|
|
89
|
+
),
|
|
90
|
+
"analytics:failure-rate-table": adaptDataWidget(
|
|
91
|
+
FailureRateTable,
|
|
92
|
+
ANALYTICS_DATA_TYPES.failureDashboard,
|
|
93
|
+
describeFailureRates,
|
|
94
|
+
),
|
|
95
|
+
"analytics:cluster-compare": adaptDataWidget(
|
|
96
|
+
ClusterCompareWidget,
|
|
97
|
+
ANALYTICS_DATA_TYPES.clusterCompare,
|
|
98
|
+
describeClusterCompare,
|
|
99
|
+
),
|
|
100
|
+
"analytics:version-compare": adaptDataWidget(
|
|
101
|
+
VersionCompareWidget,
|
|
102
|
+
ANALYTICS_DATA_TYPES.versionCompare,
|
|
103
|
+
describeVersionCompare,
|
|
104
|
+
),
|
|
105
|
+
"analytics:engine-compare": adaptDataWidget(
|
|
106
|
+
EngineCompareWidget,
|
|
107
|
+
ANALYTICS_DATA_TYPES.engineCompare,
|
|
108
|
+
describeEngineCompare,
|
|
109
|
+
),
|
|
110
|
+
"analytics:engine-landscape": adaptDataWidget(
|
|
111
|
+
EngineLandscapeWidget,
|
|
112
|
+
ANALYTICS_DATA_TYPES.engineLandscape,
|
|
113
|
+
describeEngineLandscape,
|
|
114
|
+
),
|
|
115
|
+
"analytics:bpmn-heatmap": adaptDataWidget(
|
|
116
|
+
AnalyticsBpmnHeatmap,
|
|
117
|
+
ANALYTICS_DATA_TYPES.bpmnHeatmap,
|
|
118
|
+
describeBpmnHeatmap,
|
|
119
|
+
),
|
|
120
|
+
// No describeForModel here: the widget renders its ModelContext inline (the
|
|
121
|
+
// settings tab mounts it without pipeline data, so only the component knows
|
|
122
|
+
// the self-fetched view).
|
|
123
|
+
"analytics:settings": adaptDataWidget(AnalyticsSettingsWidget, ANALYTICS_DATA_TYPES.settings),
|
|
124
|
+
}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest"
|
|
2
|
+
import type { AnalyticsDashboardData, CompareKpiDelta } from "@miragon/pulse-analytics-client"
|
|
3
|
+
import type { AnalyticsBpmnHeatmapData } from "./bpmn-heatmap.js"
|
|
4
|
+
import {
|
|
5
|
+
describeActivityBottlenecks,
|
|
6
|
+
describeBpmnHeatmap,
|
|
7
|
+
describeClusterCompare,
|
|
8
|
+
describeDefinitionBreakdown,
|
|
9
|
+
describeEngineCompare,
|
|
10
|
+
describeExecutionPerformance,
|
|
11
|
+
describeExecutionSummary,
|
|
12
|
+
} from "./model-descriptions.js"
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The analytics-dashboard, comparison and heatmap model descriptions (#336
|
|
16
|
+
* facts in #338's modelContextText): the scope is the data's echo, window
|
|
17
|
+
* flows stay apart from the live gauges, and an unmeasured figure is left out.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const dashboard = (over: Partial<AnalyticsDashboardData> = {}): AnalyticsDashboardData => ({
|
|
21
|
+
processDefinitionKey: null,
|
|
22
|
+
period: "7d",
|
|
23
|
+
engines: ["prod-a", "prod-b"],
|
|
24
|
+
totalCount: 40,
|
|
25
|
+
completedCount: 30,
|
|
26
|
+
incidentsCreated: 5,
|
|
27
|
+
incidentsResolved: 2,
|
|
28
|
+
incidentRatePct: 12.5,
|
|
29
|
+
avgDurationMs: 60_000,
|
|
30
|
+
medianDurationMs: 45_000,
|
|
31
|
+
p95DurationMs: 187_000,
|
|
32
|
+
runningNow: 156,
|
|
33
|
+
openIncidentsNow: 12,
|
|
34
|
+
previous: null,
|
|
35
|
+
activityBreakdown: [],
|
|
36
|
+
activityCount: 0,
|
|
37
|
+
definitionBreakdown: [
|
|
38
|
+
{
|
|
39
|
+
processDefinitionKey: "order",
|
|
40
|
+
totalInstances: 30,
|
|
41
|
+
completed: 25,
|
|
42
|
+
runningNow: 100,
|
|
43
|
+
incidentsCreated: 4,
|
|
44
|
+
avgDurationMs: 1,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
processDefinitionKey: "refund",
|
|
48
|
+
totalInstances: 10,
|
|
49
|
+
completed: 5,
|
|
50
|
+
runningNow: null,
|
|
51
|
+
incidentsCreated: 1,
|
|
52
|
+
avgDurationMs: 2,
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
...over,
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
describe("dashboard model descriptions", () => {
|
|
59
|
+
it("labels the fleet aggregate with its engines and the period it covers (K33)", () => {
|
|
60
|
+
const text = describeExecutionSummary(dashboard(), {})
|
|
61
|
+
expect(text).toContain('Ids: engine=["prod-a","prod-b"], period="7d"\n')
|
|
62
|
+
expect(text).toContain("(aggregated)")
|
|
63
|
+
expect(text).toContain(
|
|
64
|
+
"Tools: analytics_analyze_process_performance, analytics_find_failed_instances",
|
|
65
|
+
)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it("reads the scope from the data, never from the cell props", () => {
|
|
69
|
+
const text = describeExecutionSummary(
|
|
70
|
+
dashboard({ processDefinitionKey: "order", engines: ["prod-a"], period: "1d" }),
|
|
71
|
+
{ engine: "prod-b", period: "30d" },
|
|
72
|
+
)
|
|
73
|
+
expect(text).toContain('Ids: engine="prod-a", processDefinitionKey="order", period="1d"\n')
|
|
74
|
+
expect(text).not.toContain("prod-b")
|
|
75
|
+
// Scoped to one process: no definition count.
|
|
76
|
+
expect(text).not.toContain("processDefinitions=")
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
it("keeps window flows and the live gauges apart (N77)", () => {
|
|
80
|
+
const text = describeExecutionSummary(dashboard(), {})
|
|
81
|
+
expect(text).toContain(
|
|
82
|
+
"processDefinitions=2, startedInWindow=40, completedInWindow=30, incidentsCreatedInWindow=5, incidentsResolvedInWindow=2, runningNow=156, openIncidentsNow=12",
|
|
83
|
+
)
|
|
84
|
+
expect(text).toContain("incidents, not failed instances")
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
it("never reads an unreported gauge or an empty duration window as 0 (N78)", () => {
|
|
88
|
+
const text = describeExecutionSummary(
|
|
89
|
+
dashboard({ runningNow: null, openIncidentsNow: null }),
|
|
90
|
+
{},
|
|
91
|
+
)
|
|
92
|
+
expect(text).not.toMatch(/runningNow|openIncidentsNow/)
|
|
93
|
+
const perf = describeExecutionPerformance(
|
|
94
|
+
dashboard({
|
|
95
|
+
avgDurationMs: null,
|
|
96
|
+
medianDurationMs: null,
|
|
97
|
+
p95DurationMs: null,
|
|
98
|
+
incidentRatePct: null,
|
|
99
|
+
}),
|
|
100
|
+
{},
|
|
101
|
+
)
|
|
102
|
+
expect(perf).toContain("No instance ended in the period")
|
|
103
|
+
expect(perf).not.toMatch(/DurationMs|incidentRatePct/)
|
|
104
|
+
expect(describeExecutionPerformance(dashboard(), {})).toContain(
|
|
105
|
+
"avgDurationMs=60000, medianDurationMs=45000, p95DurationMs=187000, incidentRatePct=12.5",
|
|
106
|
+
)
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
it("states the previous period's rate the screen judges against, and when it is noise", () => {
|
|
110
|
+
const previous = {
|
|
111
|
+
totalCount: 30,
|
|
112
|
+
incidentsCreated: 2,
|
|
113
|
+
incidentRatePct: 6.7,
|
|
114
|
+
partial: false,
|
|
115
|
+
suppressed: false,
|
|
116
|
+
}
|
|
117
|
+
const scoped = { processDefinitionKey: "order" }
|
|
118
|
+
const text = describeExecutionPerformance(dashboard({ ...scoped, previous }), {})
|
|
119
|
+
expect(text).toContain("incidentRatePct=12.5, previousPeriodIncidentRatePct=6.7")
|
|
120
|
+
expect(text).not.toContain("NotReliable")
|
|
121
|
+
expect(text).not.toContain("mix")
|
|
122
|
+
const noisy = describeExecutionPerformance(
|
|
123
|
+
dashboard({ ...scoped, previous: { ...previous, suppressed: true } }),
|
|
124
|
+
{},
|
|
125
|
+
)
|
|
126
|
+
expect(noisy).toContain("previousPeriodComparisonNotReliable=true")
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
// Simpson's paradox: a rate over several processes moves with their mix.
|
|
130
|
+
it("says a rate over several processes is not judged against the previous period", () => {
|
|
131
|
+
const previous = {
|
|
132
|
+
totalCount: 30,
|
|
133
|
+
incidentsCreated: 2,
|
|
134
|
+
incidentRatePct: 6.7,
|
|
135
|
+
partial: false,
|
|
136
|
+
suppressed: true,
|
|
137
|
+
}
|
|
138
|
+
const text = describeExecutionPerformance(dashboard({ previous }), {})
|
|
139
|
+
expect(text).toContain("reflects their mix and is not judged")
|
|
140
|
+
expect(text).toContain("previousPeriodIncidentRatePct=6.7")
|
|
141
|
+
expect(text).not.toContain("NotReliable")
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
it("names the busiest definition with its window flows and live state", () => {
|
|
145
|
+
const text = describeDefinitionBreakdown(dashboard(), {})
|
|
146
|
+
expect(text).toContain(
|
|
147
|
+
'busiestProcessDefinitionKey="order", busiestStartedInWindow=30, busiestIncidentsCreatedInWindow=4, busiestRunningNow=100',
|
|
148
|
+
)
|
|
149
|
+
expect(text).toContain("Tools: analytics_show_dashboard")
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
it("names the process of the top activity — ids repeat across models (N84)", () => {
|
|
153
|
+
const text = describeActivityBottlenecks(
|
|
154
|
+
dashboard({
|
|
155
|
+
activityBreakdown: [
|
|
156
|
+
{
|
|
157
|
+
processDefinitionKey: "invoice",
|
|
158
|
+
activityId: "StartEvent_1",
|
|
159
|
+
activityType: "startEvent",
|
|
160
|
+
executionCount: 9,
|
|
161
|
+
avgDurationMs: 10,
|
|
162
|
+
p95DurationMs: 20,
|
|
163
|
+
totalTimeMs: 90,
|
|
164
|
+
},
|
|
165
|
+
],
|
|
166
|
+
}),
|
|
167
|
+
{},
|
|
168
|
+
)
|
|
169
|
+
expect(text).toContain('topProcessDefinitionKey="invoice", topActivityId="StartEvent_1"')
|
|
170
|
+
expect(text).toContain('Ids: engine=["prod-a","prod-b"], period="7d"')
|
|
171
|
+
// The whole breakdown is on screen: no "in all" count.
|
|
172
|
+
expect(text).not.toContain("activitiesInAll")
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
it("says a cut list is the top of more activities", () => {
|
|
176
|
+
const row = {
|
|
177
|
+
processDefinitionKey: "invoice",
|
|
178
|
+
activityId: "Task_A",
|
|
179
|
+
activityType: "userTask",
|
|
180
|
+
executionCount: 9,
|
|
181
|
+
avgDurationMs: 10,
|
|
182
|
+
p95DurationMs: 20,
|
|
183
|
+
totalTimeMs: 90,
|
|
184
|
+
}
|
|
185
|
+
const text = describeActivityBottlenecks(
|
|
186
|
+
dashboard({ activityBreakdown: [row], activityCount: 37 }),
|
|
187
|
+
{},
|
|
188
|
+
)
|
|
189
|
+
expect(text).toContain("rows=1, activitiesInAll=37")
|
|
190
|
+
})
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
const delta: CompareKpiDelta = {
|
|
194
|
+
started_per_day_delta_pct: 5,
|
|
195
|
+
incident_rate_delta_pp: -1.5,
|
|
196
|
+
element_incident_rate_delta_pp: null,
|
|
197
|
+
avg_duration_delta_pct: 0,
|
|
198
|
+
p95_duration_delta_pct: null,
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
describe("the comparison descriptions", () => {
|
|
202
|
+
it("cluster compare: re-runs as asked, states the windows as measured", () => {
|
|
203
|
+
const text = describeClusterCompare(
|
|
204
|
+
{
|
|
205
|
+
engines: ["prod-a"],
|
|
206
|
+
processDefinitionKey: null,
|
|
207
|
+
activityId: null,
|
|
208
|
+
deploymentTimestamp: "2026-07-01T12:00:00Z",
|
|
209
|
+
requestedWindowDays: { before: 7, after: 7 },
|
|
210
|
+
windowDays: { before: 7, after: 0.42 },
|
|
211
|
+
partial: true,
|
|
212
|
+
minBucketSize: 10,
|
|
213
|
+
suppressed: true,
|
|
214
|
+
kpis: [],
|
|
215
|
+
delta,
|
|
216
|
+
},
|
|
217
|
+
{},
|
|
218
|
+
)
|
|
219
|
+
// The tool takes whole days: the requested windows, never the measured 0.42.
|
|
220
|
+
expect(text).toContain(
|
|
221
|
+
'Ids: engine="prod-a", deploymentTimestamp="2026-07-01T12:00:00Z", windowBeforeDays=7, windowAfterDays=7\n',
|
|
222
|
+
)
|
|
223
|
+
expect(text).toContain("measuredBeforeDays=7, measuredAfterDays=0.42")
|
|
224
|
+
expect(text).toContain("starts compare per day")
|
|
225
|
+
expect(text).toContain('largestDelta="startedPerDayDeltaPct"')
|
|
226
|
+
expect(text).toContain("suppressed=true")
|
|
227
|
+
expect(text).toContain("treat the deltas as noise")
|
|
228
|
+
expect(text).not.toMatch(/failure/i)
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
it("engine compare: the process is held fixed", () => {
|
|
232
|
+
const text = describeEngineCompare(
|
|
233
|
+
{
|
|
234
|
+
engineA: "prod-a",
|
|
235
|
+
engineB: "prod-b",
|
|
236
|
+
processDefinitionKey: "order",
|
|
237
|
+
windowDays: 14,
|
|
238
|
+
activityId: null,
|
|
239
|
+
minBucketSize: 10,
|
|
240
|
+
suppressed: false,
|
|
241
|
+
kpis: [],
|
|
242
|
+
delta,
|
|
243
|
+
},
|
|
244
|
+
{},
|
|
245
|
+
)
|
|
246
|
+
expect(text).toContain(
|
|
247
|
+
'Ids: processDefinitionKey="order", engineA="prod-a", engineB="prod-b", windowDays=14',
|
|
248
|
+
)
|
|
249
|
+
expect(text).toContain("attributable to the engine")
|
|
250
|
+
expect(text).not.toContain("noise")
|
|
251
|
+
})
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
describe("describeBpmnHeatmap", () => {
|
|
255
|
+
const heatmap = (engines: string[]): AnalyticsBpmnHeatmapData => ({
|
|
256
|
+
processDefinitionKey: "order",
|
|
257
|
+
period: "7d",
|
|
258
|
+
engines,
|
|
259
|
+
frequency: { Task_A: 12, Task_B: 4 },
|
|
260
|
+
durationSec: { Task_A: 1.04, Task_B: 9.26 },
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
it("names the engines whose heat it adds up (K33)", () => {
|
|
264
|
+
const fleet = describeBpmnHeatmap(heatmap(["prod-a", "prod-b"]), {})
|
|
265
|
+
expect(fleet).toContain(
|
|
266
|
+
'Ids: engine=["prod-a","prod-b"], processDefinitionKey="order", period="7d"',
|
|
267
|
+
)
|
|
268
|
+
expect(fleet).toContain("(aggregated)")
|
|
269
|
+
expect(describeBpmnHeatmap(heatmap(["prod-b"]), {})).toContain(
|
|
270
|
+
'Ids: engine="prod-b", processDefinitionKey="order", period="7d"',
|
|
271
|
+
)
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
it("the hottest and slowest element as facts", () => {
|
|
275
|
+
const text = describeBpmnHeatmap(heatmap(["prod-a"]), {})
|
|
276
|
+
expect(text).toContain('hottestActivityId="Task_A", hottestExecutions=12')
|
|
277
|
+
expect(text).toContain('slowestActivityId="Task_B", slowestAvgSec=9.3')
|
|
278
|
+
expect(text).toContain("Tools: analytics_element_bottleneck")
|
|
279
|
+
})
|
|
280
|
+
})
|