@bpmnkit/operate 0.0.5
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 +131 -0
- package/dist/components/badge.d.ts +2 -0
- package/dist/components/badge.js +2 -0
- package/dist/components/card.d.ts +2 -0
- package/dist/components/card.js +2 -0
- package/dist/components/chart.d.ts +6 -0
- package/dist/components/chart.js +161 -0
- package/dist/components/filter-table.d.ts +20 -0
- package/dist/components/filter-table.js +215 -0
- package/dist/components/table.d.ts +2 -0
- package/dist/components/table.js +2 -0
- package/dist/css.d.ts +2 -0
- package/dist/css.js +1071 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/mock-data.d.ts +18 -0
- package/dist/mock-data.js +509 -0
- package/dist/operate.d.ts +3 -0
- package/dist/operate.js +308 -0
- package/dist/router.d.ts +9 -0
- package/dist/router.js +49 -0
- package/dist/stores/base.d.ts +20 -0
- package/dist/stores/base.js +32 -0
- package/dist/stores/dashboard.d.ts +6 -0
- package/dist/stores/dashboard.js +19 -0
- package/dist/stores/decisions.d.ts +9 -0
- package/dist/stores/decisions.js +19 -0
- package/dist/stores/definitions.d.ts +9 -0
- package/dist/stores/definitions.js +19 -0
- package/dist/stores/incidents.d.ts +10 -0
- package/dist/stores/incidents.js +27 -0
- package/dist/stores/instances.d.ts +15 -0
- package/dist/stores/instances.js +33 -0
- package/dist/stores/jobs.d.ts +10 -0
- package/dist/stores/jobs.js +19 -0
- package/dist/stores/tasks.d.ts +10 -0
- package/dist/stores/tasks.js +19 -0
- package/dist/stream.d.ts +12 -0
- package/dist/stream.js +42 -0
- package/dist/types.d.ts +48 -0
- package/dist/types.js +2 -0
- package/dist/views/dashboard.d.ts +6 -0
- package/dist/views/dashboard.js +98 -0
- package/dist/views/decision-detail.d.ts +15 -0
- package/dist/views/decision-detail.js +167 -0
- package/dist/views/decisions.d.ts +7 -0
- package/dist/views/decisions.js +78 -0
- package/dist/views/definition-detail.d.ts +15 -0
- package/dist/views/definition-detail.js +339 -0
- package/dist/views/definitions.d.ts +7 -0
- package/dist/views/definitions.js +70 -0
- package/dist/views/header.d.ts +9 -0
- package/dist/views/header.js +49 -0
- package/dist/views/incident-detail.d.ts +14 -0
- package/dist/views/incident-detail.js +540 -0
- package/dist/views/incidents.d.ts +7 -0
- package/dist/views/incidents.js +108 -0
- package/dist/views/instance-detail.d.ts +16 -0
- package/dist/views/instance-detail.js +728 -0
- package/dist/views/instances.d.ts +7 -0
- package/dist/views/instances.js +249 -0
- package/dist/views/jobs.d.ts +6 -0
- package/dist/views/jobs.js +60 -0
- package/dist/views/messages.d.ts +11 -0
- package/dist/views/messages.js +431 -0
- package/dist/views/nav.d.ts +10 -0
- package/dist/views/nav.js +60 -0
- package/dist/views/task-detail.d.ts +13 -0
- package/dist/views/task-detail.js +187 -0
- package/dist/views/tasks.d.ts +7 -0
- package/dist/views/tasks.js +72 -0
- package/package.json +46 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { InstancesStore } from "../stores/instances.js";
|
|
2
|
+
import type { ProcessInstanceResult } from "../types.js";
|
|
3
|
+
export declare function createInstancesView(store: InstancesStore, onSelect: (inst: ProcessInstanceResult) => void, onFilterChange?: (state: string) => void): {
|
|
4
|
+
el: HTMLElement;
|
|
5
|
+
destroy(): void;
|
|
6
|
+
};
|
|
7
|
+
//# sourceMappingURL=instances.d.ts.map
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import { badge } from "../components/badge.js";
|
|
2
|
+
import { createFilterTable } from "../components/filter-table.js";
|
|
3
|
+
function relTime(iso) {
|
|
4
|
+
if (!iso)
|
|
5
|
+
return "—";
|
|
6
|
+
const diff = Date.now() - new Date(iso).getTime();
|
|
7
|
+
const m = Math.floor(diff / 60_000);
|
|
8
|
+
if (m < 1)
|
|
9
|
+
return "just now";
|
|
10
|
+
if (m < 60)
|
|
11
|
+
return `${m}m ago`;
|
|
12
|
+
const h = Math.floor(m / 60);
|
|
13
|
+
if (h < 24)
|
|
14
|
+
return `${h}h ago`;
|
|
15
|
+
return `${Math.floor(h / 24)}d ago`;
|
|
16
|
+
}
|
|
17
|
+
function buildInstMap(items) {
|
|
18
|
+
const m = new Map();
|
|
19
|
+
for (const inst of items)
|
|
20
|
+
m.set(inst.processInstanceKey, inst);
|
|
21
|
+
return m;
|
|
22
|
+
}
|
|
23
|
+
/** Walk up the parent chain and return an ordered array of process definition names. */
|
|
24
|
+
function getChain(inst, map) {
|
|
25
|
+
const chain = [];
|
|
26
|
+
let cur = inst;
|
|
27
|
+
const visited = new Set();
|
|
28
|
+
while (cur && !visited.has(cur.processInstanceKey)) {
|
|
29
|
+
visited.add(cur.processInstanceKey);
|
|
30
|
+
chain.unshift(cur.processDefinitionName ?? cur.processDefinitionId ?? "?");
|
|
31
|
+
if (!cur.parentProcessInstanceKey)
|
|
32
|
+
break;
|
|
33
|
+
const parent = map.get(cur.parentProcessInstanceKey);
|
|
34
|
+
if (!parent) {
|
|
35
|
+
// Parent exists but not loaded — prefix with ellipsis
|
|
36
|
+
chain.unshift("…");
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
cur = parent;
|
|
40
|
+
}
|
|
41
|
+
return chain;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Returns the processDefinitionId of the root (top-level) process for this instance.
|
|
45
|
+
* Uses rootProcessInstanceKey (8.9+) as a shortcut; falls back to walking the chain.
|
|
46
|
+
*/
|
|
47
|
+
function getRootDefId(inst, map) {
|
|
48
|
+
// 8.9+ shortcut
|
|
49
|
+
if (inst.rootProcessInstanceKey && inst.rootProcessInstanceKey !== inst.processInstanceKey) {
|
|
50
|
+
const root = map.get(inst.rootProcessInstanceKey);
|
|
51
|
+
if (root)
|
|
52
|
+
return root.processDefinitionId;
|
|
53
|
+
}
|
|
54
|
+
// Walk up
|
|
55
|
+
let cur = inst;
|
|
56
|
+
const visited = new Set();
|
|
57
|
+
while (cur && !visited.has(cur.processInstanceKey)) {
|
|
58
|
+
visited.add(cur.processInstanceKey);
|
|
59
|
+
if (!cur.parentProcessInstanceKey)
|
|
60
|
+
return cur.processDefinitionId;
|
|
61
|
+
const parent = map.get(cur.parentProcessInstanceKey);
|
|
62
|
+
if (!parent)
|
|
63
|
+
return cur.processDefinitionId;
|
|
64
|
+
cur = parent;
|
|
65
|
+
}
|
|
66
|
+
return inst.processDefinitionId;
|
|
67
|
+
}
|
|
68
|
+
/** Collect unique {id, name} pairs for all root-level process definitions. */
|
|
69
|
+
function getRootDefs(items) {
|
|
70
|
+
const seen = new Set();
|
|
71
|
+
const result = [];
|
|
72
|
+
for (const inst of items) {
|
|
73
|
+
if (inst.parentProcessInstanceKey)
|
|
74
|
+
continue; // skip sub-processes
|
|
75
|
+
const id = inst.processDefinitionId;
|
|
76
|
+
if (!id || seen.has(id))
|
|
77
|
+
continue;
|
|
78
|
+
seen.add(id);
|
|
79
|
+
result.push({ id, name: inst.processDefinitionName ?? id });
|
|
80
|
+
}
|
|
81
|
+
return result.sort((a, b) => a.name.localeCompare(b.name));
|
|
82
|
+
}
|
|
83
|
+
/** Render a breadcrumb element for the Process column. */
|
|
84
|
+
function renderBreadcrumb(chain) {
|
|
85
|
+
const el = document.createElement("span");
|
|
86
|
+
el.className = "op-proc-breadcrumb";
|
|
87
|
+
if (chain.length === 0) {
|
|
88
|
+
el.textContent = "—";
|
|
89
|
+
return el;
|
|
90
|
+
}
|
|
91
|
+
for (let i = 0; i < chain.length; i++) {
|
|
92
|
+
if (i > 0) {
|
|
93
|
+
const sep = document.createElement("span");
|
|
94
|
+
sep.className = "op-proc-sep";
|
|
95
|
+
sep.textContent = " / ";
|
|
96
|
+
el.appendChild(sep);
|
|
97
|
+
}
|
|
98
|
+
const part = document.createElement("span");
|
|
99
|
+
part.className = i === chain.length - 1 ? "op-proc-leaf" : "op-proc-root";
|
|
100
|
+
part.textContent = chain[i] ?? "";
|
|
101
|
+
el.appendChild(part);
|
|
102
|
+
}
|
|
103
|
+
return el;
|
|
104
|
+
}
|
|
105
|
+
export function createInstancesView(store, onSelect, onFilterChange) {
|
|
106
|
+
const el = document.createElement("div");
|
|
107
|
+
el.className = "op-view";
|
|
108
|
+
// ── State filter bar ────────────────────────────────────────────────────
|
|
109
|
+
const filterBar = document.createElement("div");
|
|
110
|
+
filterBar.className = "op-filter-bar";
|
|
111
|
+
const stateFilters = [
|
|
112
|
+
{ label: "All", value: "" },
|
|
113
|
+
{ label: "Active", value: "ACTIVE" },
|
|
114
|
+
{ label: "Completed", value: "COMPLETED" },
|
|
115
|
+
{ label: "Terminated", value: "TERMINATED" },
|
|
116
|
+
];
|
|
117
|
+
let activeStateFilter = "";
|
|
118
|
+
for (const f of stateFilters) {
|
|
119
|
+
const btn = document.createElement("button");
|
|
120
|
+
btn.className = `op-filter-btn${f.value === activeStateFilter ? " op-filter-btn--active" : ""}`;
|
|
121
|
+
btn.textContent = f.label;
|
|
122
|
+
btn.addEventListener("click", () => {
|
|
123
|
+
activeStateFilter = f.value;
|
|
124
|
+
for (const b of Array.from(filterBar.querySelectorAll(".op-filter-btn"))) {
|
|
125
|
+
b.classList.remove("op-filter-btn--active");
|
|
126
|
+
}
|
|
127
|
+
btn.classList.add("op-filter-btn--active");
|
|
128
|
+
onFilterChange?.(f.value);
|
|
129
|
+
});
|
|
130
|
+
filterBar.appendChild(btn);
|
|
131
|
+
}
|
|
132
|
+
// ── Main process filter ─────────────────────────────────────────────────
|
|
133
|
+
const procFilterWrap = document.createElement("div");
|
|
134
|
+
procFilterWrap.className = "op-proc-filter-wrap";
|
|
135
|
+
const procFilterLabel = document.createElement("span");
|
|
136
|
+
procFilterLabel.className = "op-proc-filter-label";
|
|
137
|
+
procFilterLabel.textContent = "Process:";
|
|
138
|
+
procFilterWrap.appendChild(procFilterLabel);
|
|
139
|
+
const procSelect = document.createElement("select");
|
|
140
|
+
procSelect.className = "op-proc-filter-select";
|
|
141
|
+
// "All" option is always first
|
|
142
|
+
const allOpt = document.createElement("option");
|
|
143
|
+
allOpt.value = "";
|
|
144
|
+
allOpt.textContent = "All";
|
|
145
|
+
procSelect.appendChild(allOpt);
|
|
146
|
+
procFilterWrap.appendChild(procSelect);
|
|
147
|
+
filterBar.appendChild(procFilterWrap);
|
|
148
|
+
el.appendChild(filterBar);
|
|
149
|
+
let mainProcessFilter = "";
|
|
150
|
+
procSelect.addEventListener("change", () => {
|
|
151
|
+
mainProcessFilter = procSelect.value;
|
|
152
|
+
render();
|
|
153
|
+
});
|
|
154
|
+
// ── Table ───────────────────────────────────────────────────────────────
|
|
155
|
+
let instMap = new Map();
|
|
156
|
+
const { el: tableEl, setRows } = createFilterTable({
|
|
157
|
+
columns: [
|
|
158
|
+
{
|
|
159
|
+
label: "Key",
|
|
160
|
+
width: "140px",
|
|
161
|
+
render: (row) => row.processInstanceKey,
|
|
162
|
+
sortValue: (row) => row.processInstanceKey,
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
label: "Process",
|
|
166
|
+
render: (row) => renderBreadcrumb(getChain(row, instMap)),
|
|
167
|
+
sortValue: (row) => {
|
|
168
|
+
const chain = getChain(row, instMap);
|
|
169
|
+
return chain.join(" / ");
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
label: "Business ID",
|
|
174
|
+
width: "140px",
|
|
175
|
+
render: (row) => row.businessId || "—",
|
|
176
|
+
sortValue: (row) => row.businessId ?? "",
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
label: "State",
|
|
180
|
+
width: "120px",
|
|
181
|
+
render: (row) => {
|
|
182
|
+
const wrap = document.createElement("div");
|
|
183
|
+
wrap.className = "bpmnkit-badge-wrap";
|
|
184
|
+
wrap.appendChild(badge(row.state));
|
|
185
|
+
if (row.hasIncident) {
|
|
186
|
+
const inc = document.createElement("span");
|
|
187
|
+
inc.className = "bpmnkit-badge bpmnkit-badge--incident-dot";
|
|
188
|
+
inc.title = "Has incident";
|
|
189
|
+
inc.textContent = "⚠";
|
|
190
|
+
wrap.appendChild(inc);
|
|
191
|
+
}
|
|
192
|
+
return wrap;
|
|
193
|
+
},
|
|
194
|
+
sortValue: (row) => row.state,
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
label: "Started",
|
|
198
|
+
width: "100px",
|
|
199
|
+
render: (row) => relTime(row.startDate),
|
|
200
|
+
sortValue: (row) => row.startDate ?? "",
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
label: "Ended",
|
|
204
|
+
width: "100px",
|
|
205
|
+
render: (row) => relTime(row.endDate),
|
|
206
|
+
sortValue: (row) => row.endDate ?? "",
|
|
207
|
+
},
|
|
208
|
+
],
|
|
209
|
+
searchFn: (row) => {
|
|
210
|
+
const chain = getChain(row, instMap);
|
|
211
|
+
return [row.processInstanceKey, ...chain, row.businessId, row.state].filter(Boolean).join(" ");
|
|
212
|
+
},
|
|
213
|
+
onRowClick: onSelect,
|
|
214
|
+
emptyText: "No process instances found",
|
|
215
|
+
});
|
|
216
|
+
el.appendChild(tableEl);
|
|
217
|
+
function updateProcFilter(items) {
|
|
218
|
+
const defs = getRootDefs(items);
|
|
219
|
+
// Rebuild options after the "All" entry, preserving current selection
|
|
220
|
+
while (procSelect.options.length > 1)
|
|
221
|
+
procSelect.remove(1);
|
|
222
|
+
for (const def of defs) {
|
|
223
|
+
const opt = document.createElement("option");
|
|
224
|
+
opt.value = def.id;
|
|
225
|
+
opt.textContent = def.name;
|
|
226
|
+
procSelect.appendChild(opt);
|
|
227
|
+
}
|
|
228
|
+
// Restore selection if still valid
|
|
229
|
+
procSelect.value = mainProcessFilter;
|
|
230
|
+
if (!procSelect.value) {
|
|
231
|
+
mainProcessFilter = "";
|
|
232
|
+
procSelect.value = "";
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
function render() {
|
|
236
|
+
const items = store.state.data?.items ?? [];
|
|
237
|
+
instMap = buildInstMap(items);
|
|
238
|
+
updateProcFilter(items);
|
|
239
|
+
let rows = items;
|
|
240
|
+
if (mainProcessFilter) {
|
|
241
|
+
rows = rows.filter((inst) => getRootDefId(inst, instMap) === mainProcessFilter);
|
|
242
|
+
}
|
|
243
|
+
setRows(rows);
|
|
244
|
+
}
|
|
245
|
+
const unsub = store.subscribe(render);
|
|
246
|
+
render();
|
|
247
|
+
return { el, destroy: unsub };
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=instances.js.map
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { badge } from "../components/badge.js";
|
|
2
|
+
import { createFilterTable } from "../components/filter-table.js";
|
|
3
|
+
export function createJobsView(store) {
|
|
4
|
+
const el = document.createElement("div");
|
|
5
|
+
el.className = "op-view";
|
|
6
|
+
const { el: tableEl, setRows } = createFilterTable({
|
|
7
|
+
columns: [
|
|
8
|
+
{
|
|
9
|
+
label: "Key",
|
|
10
|
+
width: "120px",
|
|
11
|
+
render: (row) => row.jobKey,
|
|
12
|
+
sortValue: (row) => row.jobKey,
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
label: "Type",
|
|
16
|
+
render: (row) => row.type,
|
|
17
|
+
sortValue: (row) => row.type,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
label: "Worker",
|
|
21
|
+
width: "160px",
|
|
22
|
+
render: (row) => row.worker || "—",
|
|
23
|
+
sortValue: (row) => row.worker ?? "",
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
label: "Retries",
|
|
27
|
+
width: "70px",
|
|
28
|
+
render: (row) => String(row.retries),
|
|
29
|
+
sortValue: (row) => row.retries,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
label: "State",
|
|
33
|
+
width: "120px",
|
|
34
|
+
render: (row) => badge(row.state),
|
|
35
|
+
sortValue: (row) => row.state,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
label: "Error",
|
|
39
|
+
width: "200px",
|
|
40
|
+
render: (row) => {
|
|
41
|
+
const span = document.createElement("span");
|
|
42
|
+
span.className = "op-cell-error";
|
|
43
|
+
span.title = row.errorMessage ?? "";
|
|
44
|
+
span.textContent = row.errorMessage ?? "—";
|
|
45
|
+
return span;
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
searchFn: (row) => [row.jobKey, row.type, row.worker, row.state, row.errorMessage].filter(Boolean).join(" "),
|
|
50
|
+
emptyText: "No jobs found",
|
|
51
|
+
});
|
|
52
|
+
el.appendChild(tableEl);
|
|
53
|
+
function render() {
|
|
54
|
+
setRows(store.state.data?.items ?? []);
|
|
55
|
+
}
|
|
56
|
+
const unsub = store.subscribe(render);
|
|
57
|
+
render();
|
|
58
|
+
return { el, destroy: unsub };
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=jobs.js.map
|