@elabs-ai/components-process 4.2.0 → 5.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.
- package/README.md +8 -1
- package/dist/core/index.d.ts +801 -3
- package/dist/core/index.js +1334 -0
- package/dist/core/index.js.map +1 -1
- package/dist/index.d.ts +1889 -34
- package/dist/index.js +5512 -196
- package/dist/index.js.map +1 -1
- package/dist/test/index.d.ts +223 -5
- package/dist/test/index.js +346 -191
- package/dist/test/index.js.map +1 -1
- package/package.json +14 -13
- package/src/__contract__/case-table.contract.test.tsx +49 -0
- package/src/__contract__/compare-kpi-strip.contract.test.tsx +49 -0
- package/src/__contract__/conformance-overlay.contract.test.tsx +49 -0
- package/src/__contract__/happy-path-editor.contract.test.tsx +49 -0
- package/src/__contract__/violation-list.contract.test.tsx +49 -0
- package/src/abstraction-controls/abstraction-controls-per-type.test.tsx +80 -0
- package/src/abstraction-controls/abstraction-controls.stories.tsx +43 -1
- package/src/abstraction-controls/abstraction-controls.tsx +198 -5
- package/src/case-table/case-table.stories.tsx +89 -0
- package/src/case-table/case-table.test.tsx +148 -0
- package/src/case-table/case-table.tsx +144 -0
- package/src/case-table/columns.ts +116 -0
- package/src/case-table/index.ts +11 -0
- package/src/case-timeline/case-timeline-model.test.ts +72 -0
- package/src/case-timeline/case-timeline-model.ts +112 -0
- package/src/case-timeline/case-timeline.stories.tsx +94 -0
- package/src/case-timeline/case-timeline.test.tsx +51 -0
- package/src/case-timeline/case-timeline.tsx +109 -0
- package/src/case-timeline/index.ts +9 -0
- package/src/conformance-overlay/conformance-fixture.ts +59 -0
- package/src/conformance-overlay/conformance-legend.tsx +109 -0
- package/src/conformance-overlay/conformance-overlay.stories.tsx +116 -0
- package/src/conformance-overlay/conformance-overlay.test.tsx +88 -0
- package/src/conformance-overlay/conformance-overlay.tsx +107 -0
- package/src/conformance-overlay/conformance-state.test.ts +79 -0
- package/src/conformance-overlay/conformance-state.ts +220 -0
- package/src/conformance-overlay/index.ts +4 -0
- package/src/core/activity-color-scale.test.ts +107 -0
- package/src/core/activity-color-scale.ts +133 -0
- package/src/core/adapters/ocel.test.ts +112 -0
- package/src/core/adapters/ocel.ts +359 -0
- package/src/core/adapters/xes.test.ts +293 -0
- package/src/core/adapters/xes.ts +384 -0
- package/src/core/cases-from-log.test.ts +72 -0
- package/src/core/cases-from-log.ts +85 -0
- package/src/core/conformance.test.ts +80 -0
- package/src/core/conformance.ts +91 -0
- package/src/core/diff-graphs.test.ts +151 -0
- package/src/core/diff-graphs.ts +118 -0
- package/src/core/discover-object-centric-graph.test.ts +94 -0
- package/src/core/discover-object-centric-graph.ts +296 -0
- package/src/core/fixtures/ocel-sample.ts +82 -0
- package/src/core/fixtures/sample.xes +68 -0
- package/src/core/index.ts +113 -0
- package/src/core/reference-model.test.ts +43 -0
- package/src/core/reference-model.ts +116 -0
- package/src/core/replay-timeline.test.ts +161 -0
- package/src/core/replay-timeline.ts +260 -0
- package/src/core/segments.test.ts +185 -0
- package/src/core/segments.ts +153 -0
- package/src/core/token-replay.test.ts +218 -0
- package/src/core/token-replay.ts +456 -0
- package/src/core/types.ts +2 -2
- package/src/dotted-chart/compute-dots.test.ts +176 -0
- package/src/dotted-chart/compute-dots.ts +241 -0
- package/src/dotted-chart/dotted-chart-labels.ts +93 -0
- package/src/dotted-chart/dotted-chart.stories.tsx +182 -0
- package/src/dotted-chart/dotted-chart.test.tsx +135 -0
- package/src/dotted-chart/dotted-chart.tsx +841 -0
- package/src/dotted-chart/index.ts +23 -0
- package/src/dotted-chart/use-element-size.ts +33 -0
- package/src/happy-path-editor/happy-path-editor-context.ts +81 -0
- package/src/happy-path-editor/happy-path-editor.stories.tsx +116 -0
- package/src/happy-path-editor/happy-path-editor.test.tsx +142 -0
- package/src/happy-path-editor/happy-path-editor.tsx +239 -0
- package/src/happy-path-editor/happy-path-step-node.tsx +175 -0
- package/src/happy-path-editor/index.ts +4 -0
- package/src/index.ts +51 -1
- package/src/performance-spectrum/aggregate-segments.test.ts +107 -0
- package/src/performance-spectrum/aggregate-segments.ts +174 -0
- package/src/performance-spectrum/index.ts +25 -0
- package/src/performance-spectrum/performance-spectrum-context.tsx +116 -0
- package/src/performance-spectrum/performance-spectrum.stories.tsx +128 -0
- package/src/performance-spectrum/performance-spectrum.test.tsx +190 -0
- package/src/performance-spectrum/performance-spectrum.tsx +870 -0
- package/src/process-compare/compare-kpi-strip.stories.tsx +48 -0
- package/src/process-compare/compare-kpi-strip.tsx +94 -0
- package/src/process-compare/compare-model.ts +83 -0
- package/src/process-compare/compare-side.tsx +42 -0
- package/src/process-compare/diff-to-graph.ts +104 -0
- package/src/process-compare/index.ts +23 -0
- package/src/process-compare/process-compare.stories.tsx +184 -0
- package/src/process-compare/process-compare.test.tsx +224 -0
- package/src/process-compare/process-compare.tsx +251 -0
- package/src/process-explorer.stories.tsx +1 -1
- package/src/process-filter-bar/index.ts +2 -0
- package/src/process-filter-bar/process-filter-bar.stories.tsx +156 -0
- package/src/process-filter-bar/process-filter-bar.test.tsx +201 -0
- package/src/process-filter-bar/process-filter-bar.tsx +167 -0
- package/src/process-kpi-strip/process-kpi-strip.stories.tsx +47 -0
- package/src/process-kpi-strip/process-kpi-strip.test.tsx +67 -0
- package/src/process-kpi-strip/process-kpi-strip.tsx +148 -8
- package/src/process-map/activity-accent.ts +25 -0
- package/src/process-map/index.ts +1 -0
- package/src/process-map/map-model.test.ts +16 -0
- package/src/process-map/map-model.ts +323 -1
- package/src/process-map/object-centric-map.test.tsx +132 -0
- package/src/process-map/process-activity-node.tsx +152 -14
- package/src/process-map/process-map-object-centric.stories.tsx +219 -0
- package/src/process-map/process-map.stories.tsx +64 -0
- package/src/process-map/process-map.tsx +240 -16
- package/src/process-map/process-transition-edge.test.tsx +47 -0
- package/src/process-map/process-transition-edge.tsx +134 -7
- package/src/process-map/use-process-layout.ts +30 -9
- package/src/process-replay/congestion-heat.tsx +107 -0
- package/src/process-replay/index.ts +14 -0
- package/src/process-replay/process-replay.stories.tsx +168 -0
- package/src/process-replay/process-replay.test.tsx +170 -0
- package/src/process-replay/process-replay.tsx +285 -0
- package/src/process-replay/replay-controls.tsx +147 -0
- package/src/process-replay/replay-format.ts +83 -0
- package/src/process-replay/replay-tokens-context.ts +30 -0
- package/src/process-replay/use-controllable-value.ts +30 -0
- package/src/templates-process-explorer.stories.tsx +1304 -0
- package/src/test/contract.test.ts +66 -0
- package/src/test/contract.ts +107 -6
- package/src/test/doubles.test.tsx +87 -1
- package/src/test/doubles.tsx +174 -3
- package/src/test/index.ts +25 -1
- package/src/use-process-explorer/use-process-explorer.test.ts +44 -0
- package/src/use-process-explorer/use-process-explorer.ts +34 -2
- package/src/variant-explorer/coverage-bar.tsx +36 -0
- package/src/variant-explorer/index.ts +16 -0
- package/src/variant-explorer/sequence-chips.tsx +103 -0
- package/src/variant-explorer/variant-explorer-model.ts +42 -0
- package/src/variant-explorer/variant-explorer.stories.tsx +226 -0
- package/src/variant-explorer/variant-explorer.test.tsx +302 -0
- package/src/variant-explorer/variant-explorer.tsx +567 -0
- package/src/variant-explorer/variant-row.tsx +137 -0
- package/src/violation-list/index.ts +2 -0
- package/src/violation-list/violation-list.stories.tsx +73 -0
- package/src/violation-list/violation-list.test.tsx +84 -0
- package/src/violation-list/violation-list.tsx +259 -0
package/dist/test/index.js
CHANGED
|
@@ -1,88 +1,121 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
// src/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
super(`${componentName}: ${message}`);
|
|
7
|
-
this.name = "ProcessContractError";
|
|
8
|
-
}
|
|
9
|
-
};
|
|
10
|
-
function isProcessGraph(value) {
|
|
11
|
-
return !!value && typeof value === "object" && Array.isArray(value.activities) && Array.isArray(value.transitions);
|
|
3
|
+
// src/core/event-log.ts
|
|
4
|
+
function isNormalizedLog(log) {
|
|
5
|
+
return Array.isArray(log.cases);
|
|
12
6
|
}
|
|
13
|
-
function
|
|
14
|
-
return
|
|
7
|
+
function asNormalizedLog(log) {
|
|
8
|
+
return isNormalizedLog(log) ? log : normalizeLog(log);
|
|
15
9
|
}
|
|
16
|
-
function
|
|
17
|
-
|
|
18
|
-
if (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
10
|
+
function toEpochMs(value) {
|
|
11
|
+
if (value === void 0 || value === null) return Number.NaN;
|
|
12
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : Number.NaN;
|
|
13
|
+
if (value instanceof Date) return value.getTime();
|
|
14
|
+
const parsed = Date.parse(value);
|
|
15
|
+
if (!Number.isNaN(parsed)) return parsed;
|
|
16
|
+
const asNumber = Number(value);
|
|
17
|
+
return Number.isFinite(asNumber) && value.trim() !== "" ? asNumber : Number.NaN;
|
|
18
|
+
}
|
|
19
|
+
function byTimestamp(a, b) {
|
|
20
|
+
if (Number.isNaN(a.at) || Number.isNaN(b.at)) return 0;
|
|
21
|
+
return a.at - b.at;
|
|
22
|
+
}
|
|
23
|
+
function normalizeLog(log) {
|
|
24
|
+
const staged = /* @__PURE__ */ new Map();
|
|
25
|
+
const order = [];
|
|
26
|
+
for (const row of log.events) {
|
|
27
|
+
if (!row || typeof row.caseId !== "string" || row.caseId === "") continue;
|
|
28
|
+
if (typeof row.activity !== "string" || row.activity === "") continue;
|
|
29
|
+
let bucket = staged.get(row.caseId);
|
|
30
|
+
if (bucket === void 0) {
|
|
31
|
+
bucket = [];
|
|
32
|
+
staged.set(row.caseId, bucket);
|
|
33
|
+
order.push(row.caseId);
|
|
34
|
+
}
|
|
35
|
+
bucket.push({ at: toEpochMs(row.timestamp), row });
|
|
29
36
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
37
|
+
const cases = [];
|
|
38
|
+
let events = 0;
|
|
39
|
+
for (const caseId of order) {
|
|
40
|
+
const bucket = staged.get(caseId);
|
|
41
|
+
bucket.sort(byTimestamp);
|
|
42
|
+
const instances = [];
|
|
43
|
+
const open = /* @__PURE__ */ new Map();
|
|
44
|
+
for (const { at, row } of bucket) {
|
|
45
|
+
if (row.lifecycle === "start") {
|
|
46
|
+
const index = instances.length;
|
|
47
|
+
instances.push(makeInstance(row, at, at, true));
|
|
48
|
+
const queue = open.get(row.activity);
|
|
49
|
+
if (queue === void 0) open.set(row.activity, [index]);
|
|
50
|
+
else queue.push(index);
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (row.lifecycle === "complete") {
|
|
54
|
+
const queue = open.get(row.activity);
|
|
55
|
+
const index = queue?.shift();
|
|
56
|
+
if (index !== void 0) {
|
|
57
|
+
const instance = instances[index];
|
|
58
|
+
instance.end = at;
|
|
59
|
+
instance.duration = durationOf(instance.start, at);
|
|
60
|
+
instance.isOpen = false;
|
|
61
|
+
if (instance.resource === void 0 && row.resource !== void 0) {
|
|
62
|
+
instance.resource = row.resource;
|
|
63
|
+
}
|
|
64
|
+
if (instance.attributes === void 0 && row.attributes !== void 0) {
|
|
65
|
+
instance.attributes = row.attributes;
|
|
66
|
+
}
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const end = at;
|
|
71
|
+
const explicitStart = toEpochMs(row.startTimestamp);
|
|
72
|
+
const start = Number.isNaN(explicitStart) ? end : explicitStart;
|
|
73
|
+
instances.push(makeInstance(row, start, end, false));
|
|
33
74
|
}
|
|
75
|
+
if (instances.length === 0) continue;
|
|
76
|
+
instances.sort(byStart);
|
|
77
|
+
let caseStart = Number.POSITIVE_INFINITY;
|
|
78
|
+
let caseEnd = Number.NEGATIVE_INFINITY;
|
|
79
|
+
for (const instance of instances) {
|
|
80
|
+
if (Number.isFinite(instance.start) && instance.start < caseStart) caseStart = instance.start;
|
|
81
|
+
if (Number.isFinite(instance.end) && instance.end > caseEnd) caseEnd = instance.end;
|
|
82
|
+
}
|
|
83
|
+
const hasExtent = caseStart !== Number.POSITIVE_INFINITY && caseEnd !== Number.NEGATIVE_INFINITY;
|
|
84
|
+
const normalizedCase = {
|
|
85
|
+
caseId,
|
|
86
|
+
events: instances,
|
|
87
|
+
start: hasExtent ? caseStart : Number.NaN,
|
|
88
|
+
end: hasExtent ? caseEnd : Number.NaN,
|
|
89
|
+
duration: hasExtent ? durationOf(caseStart, caseEnd) : Number.NaN
|
|
90
|
+
};
|
|
91
|
+
const caseAttributes = log.caseAttributes?.[caseId];
|
|
92
|
+
if (caseAttributes !== void 0) normalizedCase.attributes = caseAttributes;
|
|
93
|
+
cases.push(normalizedCase);
|
|
94
|
+
events += instances.length;
|
|
34
95
|
}
|
|
96
|
+
return { cases, totals: { cases: cases.length, events } };
|
|
35
97
|
}
|
|
36
|
-
function
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const payload = { component: componentName, dataLength };
|
|
40
|
-
if ("selection" in props) payload.selection = props.selection;
|
|
41
|
-
return payload;
|
|
98
|
+
function byStart(a, b) {
|
|
99
|
+
if (Number.isNaN(a.start) || Number.isNaN(b.start)) return 0;
|
|
100
|
+
return a.start - b.start;
|
|
42
101
|
}
|
|
43
|
-
function
|
|
44
|
-
const
|
|
45
|
-
|
|
102
|
+
function durationOf(start, end) {
|
|
103
|
+
const delta = end - start;
|
|
104
|
+
if (!Number.isFinite(delta)) return Number.NaN;
|
|
105
|
+
return delta < 0 ? 0 : delta;
|
|
46
106
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const payload = buildProcessDoublePayload(name, record, spec);
|
|
59
|
-
return /* @__PURE__ */ jsx(
|
|
60
|
-
"div",
|
|
61
|
-
{
|
|
62
|
-
ref,
|
|
63
|
-
"data-slot": "process-test-double",
|
|
64
|
-
"data-process-double": name,
|
|
65
|
-
"data-process-props": JSON.stringify(payload),
|
|
66
|
-
className: props.className,
|
|
67
|
-
style: props.style
|
|
68
|
-
}
|
|
69
|
-
);
|
|
70
|
-
});
|
|
71
|
-
Double.displayName = name;
|
|
72
|
-
return Double;
|
|
107
|
+
function makeInstance(row, start, end, isOpen) {
|
|
108
|
+
const instance = {
|
|
109
|
+
activity: row.activity,
|
|
110
|
+
start,
|
|
111
|
+
end,
|
|
112
|
+
duration: durationOf(start, end),
|
|
113
|
+
isOpen
|
|
114
|
+
};
|
|
115
|
+
if (row.resource !== void 0) instance.resource = row.resource;
|
|
116
|
+
if (row.attributes !== void 0) instance.attributes = row.attributes;
|
|
117
|
+
return instance;
|
|
73
118
|
}
|
|
74
|
-
var ProcessMapDouble = createProcessDouble(
|
|
75
|
-
"ProcessMapDouble",
|
|
76
|
-
PROCESS_MAP_SPEC
|
|
77
|
-
);
|
|
78
|
-
var VariantExplorerDouble = createProcessDouble(
|
|
79
|
-
"VariantExplorerDouble",
|
|
80
|
-
VARIANT_EXPLORER_SPEC
|
|
81
|
-
);
|
|
82
|
-
var ProcessKpiStripDouble = createProcessDouble(
|
|
83
|
-
"ProcessKpiStripDouble",
|
|
84
|
-
PROCESS_KPI_STRIP_SPEC
|
|
85
|
-
);
|
|
86
119
|
|
|
87
120
|
// src/core/scale.ts
|
|
88
121
|
function ascending(a, b) {
|
|
@@ -205,123 +238,6 @@ var DurationSampler = class {
|
|
|
205
238
|
}
|
|
206
239
|
};
|
|
207
240
|
|
|
208
|
-
// src/core/event-log.ts
|
|
209
|
-
function isNormalizedLog(log) {
|
|
210
|
-
return Array.isArray(log.cases);
|
|
211
|
-
}
|
|
212
|
-
function asNormalizedLog(log) {
|
|
213
|
-
return isNormalizedLog(log) ? log : normalizeLog(log);
|
|
214
|
-
}
|
|
215
|
-
function toEpochMs(value) {
|
|
216
|
-
if (value === void 0 || value === null) return Number.NaN;
|
|
217
|
-
if (typeof value === "number") return Number.isFinite(value) ? value : Number.NaN;
|
|
218
|
-
if (value instanceof Date) return value.getTime();
|
|
219
|
-
const parsed = Date.parse(value);
|
|
220
|
-
if (!Number.isNaN(parsed)) return parsed;
|
|
221
|
-
const asNumber = Number(value);
|
|
222
|
-
return Number.isFinite(asNumber) && value.trim() !== "" ? asNumber : Number.NaN;
|
|
223
|
-
}
|
|
224
|
-
function byTimestamp(a, b) {
|
|
225
|
-
if (Number.isNaN(a.at) || Number.isNaN(b.at)) return 0;
|
|
226
|
-
return a.at - b.at;
|
|
227
|
-
}
|
|
228
|
-
function normalizeLog(log) {
|
|
229
|
-
const staged = /* @__PURE__ */ new Map();
|
|
230
|
-
const order = [];
|
|
231
|
-
for (const row of log.events) {
|
|
232
|
-
if (!row || typeof row.caseId !== "string" || row.caseId === "") continue;
|
|
233
|
-
if (typeof row.activity !== "string" || row.activity === "") continue;
|
|
234
|
-
let bucket = staged.get(row.caseId);
|
|
235
|
-
if (bucket === void 0) {
|
|
236
|
-
bucket = [];
|
|
237
|
-
staged.set(row.caseId, bucket);
|
|
238
|
-
order.push(row.caseId);
|
|
239
|
-
}
|
|
240
|
-
bucket.push({ at: toEpochMs(row.timestamp), row });
|
|
241
|
-
}
|
|
242
|
-
const cases = [];
|
|
243
|
-
let events = 0;
|
|
244
|
-
for (const caseId of order) {
|
|
245
|
-
const bucket = staged.get(caseId);
|
|
246
|
-
bucket.sort(byTimestamp);
|
|
247
|
-
const instances = [];
|
|
248
|
-
const open = /* @__PURE__ */ new Map();
|
|
249
|
-
for (const { at, row } of bucket) {
|
|
250
|
-
if (row.lifecycle === "start") {
|
|
251
|
-
const index = instances.length;
|
|
252
|
-
instances.push(makeInstance(row, at, at, true));
|
|
253
|
-
const queue = open.get(row.activity);
|
|
254
|
-
if (queue === void 0) open.set(row.activity, [index]);
|
|
255
|
-
else queue.push(index);
|
|
256
|
-
continue;
|
|
257
|
-
}
|
|
258
|
-
if (row.lifecycle === "complete") {
|
|
259
|
-
const queue = open.get(row.activity);
|
|
260
|
-
const index = queue?.shift();
|
|
261
|
-
if (index !== void 0) {
|
|
262
|
-
const instance = instances[index];
|
|
263
|
-
instance.end = at;
|
|
264
|
-
instance.duration = durationOf(instance.start, at);
|
|
265
|
-
instance.isOpen = false;
|
|
266
|
-
if (instance.resource === void 0 && row.resource !== void 0) {
|
|
267
|
-
instance.resource = row.resource;
|
|
268
|
-
}
|
|
269
|
-
if (instance.attributes === void 0 && row.attributes !== void 0) {
|
|
270
|
-
instance.attributes = row.attributes;
|
|
271
|
-
}
|
|
272
|
-
continue;
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
const end = at;
|
|
276
|
-
const explicitStart = toEpochMs(row.startTimestamp);
|
|
277
|
-
const start = Number.isNaN(explicitStart) ? end : explicitStart;
|
|
278
|
-
instances.push(makeInstance(row, start, end, false));
|
|
279
|
-
}
|
|
280
|
-
if (instances.length === 0) continue;
|
|
281
|
-
instances.sort(byStart);
|
|
282
|
-
let caseStart = Number.POSITIVE_INFINITY;
|
|
283
|
-
let caseEnd = Number.NEGATIVE_INFINITY;
|
|
284
|
-
for (const instance of instances) {
|
|
285
|
-
if (Number.isFinite(instance.start) && instance.start < caseStart) caseStart = instance.start;
|
|
286
|
-
if (Number.isFinite(instance.end) && instance.end > caseEnd) caseEnd = instance.end;
|
|
287
|
-
}
|
|
288
|
-
const hasExtent = caseStart !== Number.POSITIVE_INFINITY && caseEnd !== Number.NEGATIVE_INFINITY;
|
|
289
|
-
const normalizedCase = {
|
|
290
|
-
caseId,
|
|
291
|
-
events: instances,
|
|
292
|
-
start: hasExtent ? caseStart : Number.NaN,
|
|
293
|
-
end: hasExtent ? caseEnd : Number.NaN,
|
|
294
|
-
duration: hasExtent ? durationOf(caseStart, caseEnd) : Number.NaN
|
|
295
|
-
};
|
|
296
|
-
const caseAttributes = log.caseAttributes?.[caseId];
|
|
297
|
-
if (caseAttributes !== void 0) normalizedCase.attributes = caseAttributes;
|
|
298
|
-
cases.push(normalizedCase);
|
|
299
|
-
events += instances.length;
|
|
300
|
-
}
|
|
301
|
-
return { cases, totals: { cases: cases.length, events } };
|
|
302
|
-
}
|
|
303
|
-
function byStart(a, b) {
|
|
304
|
-
if (Number.isNaN(a.start) || Number.isNaN(b.start)) return 0;
|
|
305
|
-
return a.start - b.start;
|
|
306
|
-
}
|
|
307
|
-
function durationOf(start, end) {
|
|
308
|
-
const delta = end - start;
|
|
309
|
-
if (!Number.isFinite(delta)) return Number.NaN;
|
|
310
|
-
return delta < 0 ? 0 : delta;
|
|
311
|
-
}
|
|
312
|
-
function makeInstance(row, start, end, isOpen) {
|
|
313
|
-
const instance = {
|
|
314
|
-
activity: row.activity,
|
|
315
|
-
start,
|
|
316
|
-
end,
|
|
317
|
-
duration: durationOf(start, end),
|
|
318
|
-
isOpen
|
|
319
|
-
};
|
|
320
|
-
if (row.resource !== void 0) instance.resource = row.resource;
|
|
321
|
-
if (row.attributes !== void 0) instance.attributes = row.attributes;
|
|
322
|
-
return instance;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
241
|
// src/core/extract-variants.ts
|
|
326
242
|
var VARIANT_KEY_SEPARATOR = "";
|
|
327
243
|
function variantKey(sequence) {
|
|
@@ -510,15 +426,254 @@ function toSortedRecord(counts) {
|
|
|
510
426
|
return out;
|
|
511
427
|
}
|
|
512
428
|
|
|
429
|
+
// src/core/segments.ts
|
|
430
|
+
function segmentKey(from, to) {
|
|
431
|
+
return `${from}${EDGE_KEY_SEPARATOR}${to}`;
|
|
432
|
+
}
|
|
433
|
+
function segmentsFor(log, order) {
|
|
434
|
+
const wanted = /* @__PURE__ */ new Set();
|
|
435
|
+
for (const def of order) wanted.add(segmentKey(def.from, def.to));
|
|
436
|
+
const out = [];
|
|
437
|
+
if (wanted.size === 0) return out;
|
|
438
|
+
for (const kase of asNormalizedLog(log).cases) {
|
|
439
|
+
const trace = kase.events;
|
|
440
|
+
for (let i = 1; i < trace.length; i += 1) {
|
|
441
|
+
const previous = trace[i - 1];
|
|
442
|
+
const event = trace[i];
|
|
443
|
+
const key = segmentKey(previous.activity, event.activity);
|
|
444
|
+
if (!wanted.has(key)) continue;
|
|
445
|
+
const start = previous.end;
|
|
446
|
+
if (!Number.isFinite(start) || !Number.isFinite(event.start)) continue;
|
|
447
|
+
const end = Math.max(start, event.start);
|
|
448
|
+
out.push({ segment: key, caseId: kase.caseId, start, end, duration: end - start });
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
return out;
|
|
452
|
+
}
|
|
453
|
+
function segmentOrderByFrequency(graph, limit = Number.POSITIVE_INFINITY) {
|
|
454
|
+
const n = Math.max(0, Math.floor(limit));
|
|
455
|
+
return graph.transitions.slice(0, n).map((t) => ({ from: t.source, to: t.target }));
|
|
456
|
+
}
|
|
457
|
+
function segmentOrderForVariant(variant) {
|
|
458
|
+
const seen = /* @__PURE__ */ new Set();
|
|
459
|
+
const out = [];
|
|
460
|
+
for (let i = 1; i < variant.sequence.length; i += 1) {
|
|
461
|
+
const from = variant.sequence[i - 1];
|
|
462
|
+
const to = variant.sequence[i];
|
|
463
|
+
const key = segmentKey(from, to);
|
|
464
|
+
if (seen.has(key)) continue;
|
|
465
|
+
seen.add(key);
|
|
466
|
+
out.push({ from, to });
|
|
467
|
+
}
|
|
468
|
+
return out;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// src/test/contract.ts
|
|
472
|
+
var ProcessContractError = class extends Error {
|
|
473
|
+
constructor(componentName, message) {
|
|
474
|
+
super(`${componentName}: ${message}`);
|
|
475
|
+
this.name = "ProcessContractError";
|
|
476
|
+
}
|
|
477
|
+
};
|
|
478
|
+
function isProcessGraph(value) {
|
|
479
|
+
return !!value && typeof value === "object" && Array.isArray(value.activities) && Array.isArray(value.transitions);
|
|
480
|
+
}
|
|
481
|
+
function isEventLog(value) {
|
|
482
|
+
return !!value && typeof value === "object" && Array.isArray(value.events);
|
|
483
|
+
}
|
|
484
|
+
function countSpectrumOccurrences(log, order, limit) {
|
|
485
|
+
const cap = typeof limit === "number" ? Math.max(0, Math.floor(limit)) : 12;
|
|
486
|
+
let definitions = [];
|
|
487
|
+
if (order === void 0 || order === "frequency") {
|
|
488
|
+
definitions = segmentOrderByFrequency(discoverGraph(log), cap);
|
|
489
|
+
} else if (Array.isArray(order)) {
|
|
490
|
+
definitions = order.slice(0, cap);
|
|
491
|
+
} else if (order && typeof order === "object" && "variantId" in order) {
|
|
492
|
+
const id = order.variantId;
|
|
493
|
+
const variant = extractVariants(log).find((v) => v.id === id);
|
|
494
|
+
definitions = variant ? segmentOrderForVariant(variant).slice(0, cap) : [];
|
|
495
|
+
}
|
|
496
|
+
return segmentsFor(log, definitions).length;
|
|
497
|
+
}
|
|
498
|
+
function isVariantArray(value) {
|
|
499
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === "object" && entry !== null && "sequence" in entry);
|
|
500
|
+
}
|
|
501
|
+
function isTimedEventLog(value) {
|
|
502
|
+
const events = value?.events;
|
|
503
|
+
return Array.isArray(events) && events.length > 0 && events.every(
|
|
504
|
+
(row) => !!row && typeof row === "object" && Number.isFinite(toEpochMs(row.timestamp))
|
|
505
|
+
);
|
|
506
|
+
}
|
|
507
|
+
function isConformanceResult(value) {
|
|
508
|
+
return !!value && typeof value === "object" && Array.isArray(value.traces) && typeof value.deviationCounts === "object";
|
|
509
|
+
}
|
|
510
|
+
function isHappyPath(value) {
|
|
511
|
+
return !!value && typeof value === "object" && Array.isArray(value.steps);
|
|
512
|
+
}
|
|
513
|
+
function assertProcessContract(componentName, props, spec) {
|
|
514
|
+
const data = props[spec.dataProp];
|
|
515
|
+
if (spec.dataProp === "graph" && !isProcessGraph(data)) {
|
|
516
|
+
throw new ProcessContractError(
|
|
517
|
+
componentName,
|
|
518
|
+
`"graph" prop must be a ProcessGraph, got ${typeof data}`
|
|
519
|
+
);
|
|
520
|
+
}
|
|
521
|
+
if (spec.dataProp === "variants" && !isVariantArray(data)) {
|
|
522
|
+
throw new ProcessContractError(
|
|
523
|
+
componentName,
|
|
524
|
+
`"variants" prop must be a Variant[], got ${typeof data}`
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
if (spec.dataProp === "log" && !isTimedEventLog(data)) {
|
|
528
|
+
throw new ProcessContractError(
|
|
529
|
+
componentName,
|
|
530
|
+
`"log" prop must be an EventLog with non-empty events and parsable timestamps`
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
if (spec.segmentOrder && isEventLog(data) && data.events.length > 0 && countSpectrumOccurrences(data, props.order, props.segmentLimit) === 0) {
|
|
534
|
+
throw new ProcessContractError(
|
|
535
|
+
componentName,
|
|
536
|
+
`"order" resolves to no segment that occurs in "log"`
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
if (spec.dataProp === "conformance" && !isConformanceResult(data)) {
|
|
540
|
+
throw new ProcessContractError(
|
|
541
|
+
componentName,
|
|
542
|
+
`"conformance" prop must be a ConformanceResult, got ${typeof data}`
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
if (spec.dataProp === "value" && !isHappyPath(data)) {
|
|
546
|
+
throw new ProcessContractError(
|
|
547
|
+
componentName,
|
|
548
|
+
`"value" prop must be a HappyPath, got ${typeof data}`
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
for (const key of spec.requiredProps ?? []) {
|
|
552
|
+
if (props[key] === void 0) {
|
|
553
|
+
throw new ProcessContractError(componentName, `missing required prop "${key}"`);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
function buildProcessDoublePayload(componentName, props, spec) {
|
|
558
|
+
const data = props[spec.dataProp];
|
|
559
|
+
const dataLength = spec.dataProp === "graph" && isProcessGraph(data) ? data.activities.length : spec.dataProp === "log" && isTimedEventLog(data) ? data.events.length : spec.dataProp === "conformance" && isConformanceResult(data) ? data.traces.length : spec.dataProp === "value" && isHappyPath(data) ? data.steps.length : Array.isArray(data) ? data.length : 0;
|
|
560
|
+
const payload = { component: componentName, dataLength };
|
|
561
|
+
if ("selection" in props) payload.selection = props.selection;
|
|
562
|
+
return payload;
|
|
563
|
+
}
|
|
564
|
+
function readProcessDoubleProps(el) {
|
|
565
|
+
const raw = el.getAttribute("data-process-props");
|
|
566
|
+
return raw ? JSON.parse(raw) : null;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
// src/test/doubles.tsx
|
|
570
|
+
import { forwardRef } from "react";
|
|
571
|
+
import { jsx } from "react/jsx-runtime";
|
|
572
|
+
var PROCESS_MAP_SPEC = { dataProp: "graph" };
|
|
573
|
+
var VARIANT_EXPLORER_SPEC = { dataProp: "variants" };
|
|
574
|
+
var PROCESS_KPI_STRIP_SPEC = { dataProp: "graph" };
|
|
575
|
+
function createProcessDouble(name, spec) {
|
|
576
|
+
const Double = forwardRef(function ProcessTestDouble(props, ref) {
|
|
577
|
+
const record = props;
|
|
578
|
+
assertProcessContract(name, record, spec);
|
|
579
|
+
const payload = buildProcessDoublePayload(name, record, spec);
|
|
580
|
+
return /* @__PURE__ */ jsx(
|
|
581
|
+
"div",
|
|
582
|
+
{
|
|
583
|
+
ref,
|
|
584
|
+
"data-slot": "process-test-double",
|
|
585
|
+
"data-process-double": name,
|
|
586
|
+
"data-process-props": JSON.stringify(payload),
|
|
587
|
+
className: props.className,
|
|
588
|
+
style: props.style
|
|
589
|
+
}
|
|
590
|
+
);
|
|
591
|
+
});
|
|
592
|
+
Double.displayName = name;
|
|
593
|
+
return Double;
|
|
594
|
+
}
|
|
595
|
+
var ProcessMapDouble = createProcessDouble(
|
|
596
|
+
"ProcessMapDouble",
|
|
597
|
+
PROCESS_MAP_SPEC
|
|
598
|
+
);
|
|
599
|
+
var VariantExplorerDouble = createProcessDouble(
|
|
600
|
+
"VariantExplorerDouble",
|
|
601
|
+
VARIANT_EXPLORER_SPEC
|
|
602
|
+
);
|
|
603
|
+
var ProcessKpiStripDouble = createProcessDouble(
|
|
604
|
+
"ProcessKpiStripDouble",
|
|
605
|
+
PROCESS_KPI_STRIP_SPEC
|
|
606
|
+
);
|
|
607
|
+
var DottedChartDouble = createProcessDouble("DottedChartDouble", {
|
|
608
|
+
dataProp: "log"
|
|
609
|
+
});
|
|
610
|
+
var PERFORMANCE_SPECTRUM_SPEC = { dataProp: "log", segmentOrder: true };
|
|
611
|
+
var PerformanceSpectrumDouble = createProcessDouble(
|
|
612
|
+
"PerformanceSpectrumDouble",
|
|
613
|
+
PERFORMANCE_SPECTRUM_SPEC
|
|
614
|
+
);
|
|
615
|
+
var ConformanceOverlayDouble = createProcessDouble(
|
|
616
|
+
"ConformanceOverlayDouble",
|
|
617
|
+
{ dataProp: "conformance", requiredProps: ["graph"] }
|
|
618
|
+
);
|
|
619
|
+
var ViolationListDouble = createProcessDouble(
|
|
620
|
+
"ViolationListDouble",
|
|
621
|
+
{ dataProp: "conformance" }
|
|
622
|
+
);
|
|
623
|
+
var HappyPathEditorDouble = createProcessDouble(
|
|
624
|
+
"HappyPathEditorDouble",
|
|
625
|
+
{ dataProp: "value", requiredProps: ["onChange"] }
|
|
626
|
+
);
|
|
627
|
+
var ProcessReplayDouble = createProcessDouble(
|
|
628
|
+
"ProcessReplayDouble",
|
|
629
|
+
{ dataProp: "log", requiredProps: ["graph"] }
|
|
630
|
+
);
|
|
631
|
+
var ProcessCompareDouble = forwardRef(
|
|
632
|
+
function ProcessCompareDouble2({ a, b, mode = "side-by-side", className, style }, ref) {
|
|
633
|
+
if (!a || typeof a.label !== "string") {
|
|
634
|
+
throw new ProcessContractError("ProcessCompareDouble", 'missing required prop "a.label"');
|
|
635
|
+
}
|
|
636
|
+
if (!b || typeof b.label !== "string") {
|
|
637
|
+
throw new ProcessContractError("ProcessCompareDouble", 'missing required prop "b.label"');
|
|
638
|
+
}
|
|
639
|
+
const payload = {
|
|
640
|
+
component: "ProcessCompareDouble",
|
|
641
|
+
mode,
|
|
642
|
+
aLabel: a.label,
|
|
643
|
+
bLabel: b.label,
|
|
644
|
+
aActivityCount: a.graph?.activities.length ?? 0,
|
|
645
|
+
bActivityCount: b.graph?.activities.length ?? 0
|
|
646
|
+
};
|
|
647
|
+
return /* @__PURE__ */ jsx(
|
|
648
|
+
"div",
|
|
649
|
+
{
|
|
650
|
+
ref,
|
|
651
|
+
"data-slot": "process-test-double",
|
|
652
|
+
"data-process-double": "ProcessCompareDouble",
|
|
653
|
+
"data-process-props": JSON.stringify(payload),
|
|
654
|
+
className,
|
|
655
|
+
style
|
|
656
|
+
}
|
|
657
|
+
);
|
|
658
|
+
}
|
|
659
|
+
);
|
|
660
|
+
|
|
513
661
|
// src/test/primitives.tsx
|
|
514
662
|
function withProcessFixture(log) {
|
|
515
663
|
return { log, graph: discoverGraph(log), variants: extractVariants(log) };
|
|
516
664
|
}
|
|
517
665
|
export {
|
|
666
|
+
ConformanceOverlayDouble,
|
|
667
|
+
DottedChartDouble,
|
|
668
|
+
HappyPathEditorDouble,
|
|
669
|
+
PerformanceSpectrumDouble,
|
|
670
|
+
ProcessCompareDouble,
|
|
518
671
|
ProcessContractError,
|
|
519
672
|
ProcessKpiStripDouble,
|
|
520
673
|
ProcessMapDouble,
|
|
674
|
+
ProcessReplayDouble,
|
|
521
675
|
VariantExplorerDouble,
|
|
676
|
+
ViolationListDouble,
|
|
522
677
|
assertProcessContract,
|
|
523
678
|
buildProcessDoublePayload,
|
|
524
679
|
readProcessDoubleProps,
|