@bpmnkit/plugins 0.0.8
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 +153 -0
- package/dist/ai-bridge/css.d.ts +2 -0
- package/dist/ai-bridge/css.js +366 -0
- package/dist/ai-bridge/index.d.ts +44 -0
- package/dist/ai-bridge/index.js +132 -0
- package/dist/ai-bridge/panel.d.ts +27 -0
- package/dist/ai-bridge/panel.js +715 -0
- package/dist/ascii-view/css.d.ts +4 -0
- package/dist/ascii-view/css.js +83 -0
- package/dist/ascii-view/index.d.ts +25 -0
- package/dist/ascii-view/index.js +92 -0
- package/dist/command-palette/css.d.ts +4 -0
- package/dist/command-palette/css.js +157 -0
- package/dist/command-palette/index.d.ts +53 -0
- package/dist/command-palette/index.js +378 -0
- package/dist/command-palette-editor/index.d.ts +35 -0
- package/dist/command-palette-editor/index.js +60 -0
- package/dist/config-panel/css.d.ts +4 -0
- package/dist/config-panel/css.js +719 -0
- package/dist/config-panel/index.d.ts +36 -0
- package/dist/config-panel/index.js +73 -0
- package/dist/config-panel/renderer.d.ts +127 -0
- package/dist/config-panel/renderer.js +1162 -0
- package/dist/config-panel/types.d.ts +118 -0
- package/dist/config-panel/types.js +2 -0
- package/dist/config-panel-bpmn/index.d.ts +58 -0
- package/dist/config-panel-bpmn/index.js +1320 -0
- package/dist/config-panel-bpmn/template-engine.d.ts +17 -0
- package/dist/config-panel-bpmn/template-engine.js +307 -0
- package/dist/config-panel-bpmn/template-to-service-task.d.ts +30 -0
- package/dist/config-panel-bpmn/template-to-service-task.js +92 -0
- package/dist/config-panel-bpmn/template-types.d.ts +126 -0
- package/dist/config-panel-bpmn/template-types.js +6 -0
- package/dist/config-panel-bpmn/templates/generated.d.ts +3 -0
- package/dist/config-panel-bpmn/templates/generated.js +57865 -0
- package/dist/config-panel-bpmn/util.d.ts +46 -0
- package/dist/config-panel-bpmn/util.js +195 -0
- package/dist/dmn-editor/css.d.ts +3 -0
- package/dist/dmn-editor/css.js +667 -0
- package/dist/dmn-editor/dmn-editor.d.ts +34 -0
- package/dist/dmn-editor/dmn-editor.js +646 -0
- package/dist/dmn-editor/drd-canvas.d.ts +85 -0
- package/dist/dmn-editor/drd-canvas.js +1087 -0
- package/dist/dmn-editor/index.d.ts +3 -0
- package/dist/dmn-editor/index.js +2 -0
- package/dist/dmn-viewer/css.d.ts +3 -0
- package/dist/dmn-viewer/css.js +151 -0
- package/dist/dmn-viewer/dmn-viewer.d.ts +30 -0
- package/dist/dmn-viewer/dmn-viewer.js +160 -0
- package/dist/dmn-viewer/feel.d.ts +3 -0
- package/dist/dmn-viewer/feel.js +2 -0
- package/dist/dmn-viewer/index.d.ts +14 -0
- package/dist/dmn-viewer/index.js +12 -0
- package/dist/element-docs/content.d.ts +20 -0
- package/dist/element-docs/content.js +1032 -0
- package/dist/element-docs/index.d.ts +7 -0
- package/dist/element-docs/index.js +643 -0
- package/dist/feel-playground/css.d.ts +4 -0
- package/dist/feel-playground/css.js +292 -0
- package/dist/feel-playground/index.d.ts +4 -0
- package/dist/feel-playground/index.js +3 -0
- package/dist/feel-playground/playground-plugin.d.ts +14 -0
- package/dist/feel-playground/playground-plugin.js +292 -0
- package/dist/form-editor/css.d.ts +3 -0
- package/dist/form-editor/css.js +703 -0
- package/dist/form-editor/form-editor.d.ts +48 -0
- package/dist/form-editor/form-editor.js +1039 -0
- package/dist/form-editor/index.d.ts +3 -0
- package/dist/form-editor/index.js +2 -0
- package/dist/form-viewer/css.d.ts +3 -0
- package/dist/form-viewer/css.js +303 -0
- package/dist/form-viewer/form-viewer.d.ts +29 -0
- package/dist/form-viewer/form-viewer.js +376 -0
- package/dist/form-viewer/index.d.ts +12 -0
- package/dist/form-viewer/index.js +11 -0
- package/dist/history/checkpoint.d.ts +10 -0
- package/dist/history/checkpoint.js +92 -0
- package/dist/history/css.d.ts +2 -0
- package/dist/history/css.js +130 -0
- package/dist/history/history-panel.d.ts +12 -0
- package/dist/history/history-panel.js +142 -0
- package/dist/history/index.d.ts +5 -0
- package/dist/history/index.js +3 -0
- package/dist/main-menu/css.d.ts +4 -0
- package/dist/main-menu/css.js +272 -0
- package/dist/main-menu/index.d.ts +59 -0
- package/dist/main-menu/index.js +285 -0
- package/dist/minimap/css.d.ts +10 -0
- package/dist/minimap/css.js +54 -0
- package/dist/minimap/index.d.ts +38 -0
- package/dist/minimap/index.js +69 -0
- package/dist/minimap/minimap.d.ts +35 -0
- package/dist/minimap/minimap.js +166 -0
- package/dist/optimize/index.d.ts +21 -0
- package/dist/optimize/index.js +304 -0
- package/dist/process-runner/css.d.ts +2 -0
- package/dist/process-runner/css.js +467 -0
- package/dist/process-runner/index.d.ts +56 -0
- package/dist/process-runner/index.js +549 -0
- package/dist/storage/auto-save.d.ts +11 -0
- package/dist/storage/auto-save.js +44 -0
- package/dist/storage/css.d.ts +2 -0
- package/dist/storage/css.js +2 -0
- package/dist/storage/db.d.ts +99 -0
- package/dist/storage/db.js +116 -0
- package/dist/storage/dialog.d.ts +15 -0
- package/dist/storage/dialog.js +201 -0
- package/dist/storage/export.d.ts +3 -0
- package/dist/storage/export.js +137 -0
- package/dist/storage/index.d.ts +44 -0
- package/dist/storage/index.js +201 -0
- package/dist/storage/sidebar.d.ts +2 -0
- package/dist/storage/sidebar.js +2 -0
- package/dist/storage/storage-api.d.ts +76 -0
- package/dist/storage/storage-api.js +342 -0
- package/dist/storage/types.d.ts +44 -0
- package/dist/storage/types.js +2 -0
- package/dist/storage-tabs-bridge/index.d.ts +96 -0
- package/dist/storage-tabs-bridge/index.js +502 -0
- package/dist/tabs/css.d.ts +3 -0
- package/dist/tabs/css.js +642 -0
- package/dist/tabs/file-resolver.d.ts +71 -0
- package/dist/tabs/file-resolver.js +46 -0
- package/dist/tabs/index.d.ts +15 -0
- package/dist/tabs/index.js +13 -0
- package/dist/tabs/tabs-plugin.d.ts +250 -0
- package/dist/tabs/tabs-plugin.js +1119 -0
- package/dist/token-highlight/css.d.ts +2 -0
- package/dist/token-highlight/css.js +81 -0
- package/dist/token-highlight/index.d.ts +44 -0
- package/dist/token-highlight/index.js +164 -0
- package/dist/watermark/css.d.ts +10 -0
- package/dist/watermark/css.js +54 -0
- package/dist/watermark/index.d.ts +48 -0
- package/dist/watermark/index.js +64 -0
- package/dist/zoom-controls/css.d.ts +4 -0
- package/dist/zoom-controls/css.js +48 -0
- package/dist/zoom-controls/index.d.ts +36 -0
- package/dist/zoom-controls/index.js +111 -0
- package/package.json +121 -0
|
@@ -0,0 +1,549 @@
|
|
|
1
|
+
import { injectProcessRunnerStyles } from "./css.js";
|
|
2
|
+
// ── IndexedDB persistence for input variables ───────────────────────────────
|
|
3
|
+
function openRunnerDb() {
|
|
4
|
+
return new Promise((resolve, reject) => {
|
|
5
|
+
const req = indexedDB.open("bpmnkit-process-runner-v1", 1);
|
|
6
|
+
req.onupgradeneeded = () => {
|
|
7
|
+
req.result.createObjectStore("data");
|
|
8
|
+
};
|
|
9
|
+
req.onsuccess = () => resolve(req.result);
|
|
10
|
+
req.onerror = () => reject(req.error);
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
function inputVarsKey(projectId) {
|
|
14
|
+
return projectId !== null ? `input-vars:${projectId}` : "input-vars";
|
|
15
|
+
}
|
|
16
|
+
async function loadInputVars(projectId) {
|
|
17
|
+
try {
|
|
18
|
+
const db = await openRunnerDb();
|
|
19
|
+
return new Promise((resolve) => {
|
|
20
|
+
const req = db
|
|
21
|
+
.transaction("data", "readonly")
|
|
22
|
+
.objectStore("data")
|
|
23
|
+
.get(inputVarsKey(projectId));
|
|
24
|
+
req.onsuccess = () => {
|
|
25
|
+
const raw = req.result;
|
|
26
|
+
resolve(Array.isArray(raw) ? raw : []);
|
|
27
|
+
};
|
|
28
|
+
req.onerror = () => resolve([]);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async function saveInputVars(projectId, vars) {
|
|
36
|
+
try {
|
|
37
|
+
const db = await openRunnerDb();
|
|
38
|
+
await new Promise((resolve) => {
|
|
39
|
+
const tx = db.transaction("data", "readwrite");
|
|
40
|
+
tx.objectStore("data").put(vars, inputVarsKey(projectId));
|
|
41
|
+
tx.oncomplete = () => resolve();
|
|
42
|
+
tx.onerror = () => resolve();
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// ignore — IndexedDB unavailable
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// ── Internal state ──────────────────────────────────────────────────────────
|
|
50
|
+
const AUTO_PLAY_DELAY_MS = 600;
|
|
51
|
+
// ── Plugin factory ──────────────────────────────────────────────────────────
|
|
52
|
+
const PLAY_ICON = '<svg viewBox="0 0 16 16" fill="currentColor"><path d="M4 2.5l10 5.5-10 5.5V2.5z"/></svg>';
|
|
53
|
+
export function createProcessRunnerPlugin(options) {
|
|
54
|
+
const { engine } = options;
|
|
55
|
+
let canvasApi = null;
|
|
56
|
+
let currentInstance = null;
|
|
57
|
+
let stopTrackHighlight;
|
|
58
|
+
let mode = "idle";
|
|
59
|
+
let playModeActive = false;
|
|
60
|
+
/** The process ID of the currently displayed diagram. */
|
|
61
|
+
let currentProcessId;
|
|
62
|
+
/** The project ID used to scope input variable persistence. */
|
|
63
|
+
let currentProjectId = null;
|
|
64
|
+
/** Pending step resolvers — each represents a paused beforeComplete call. */
|
|
65
|
+
const stepQueue = [];
|
|
66
|
+
/** Accumulated FEEL expression evaluations for the current run. */
|
|
67
|
+
const feelEvals = [];
|
|
68
|
+
/** Current variable state, updated from variable:set events. */
|
|
69
|
+
const variables = new Map();
|
|
70
|
+
/** Errors emitted during the current run. */
|
|
71
|
+
const errors = [];
|
|
72
|
+
/** Input variables configured by the user (persisted in IndexedDB). */
|
|
73
|
+
const inputVars = [];
|
|
74
|
+
const toolbarEl = document.createElement("div");
|
|
75
|
+
toolbarEl.className = "bpmnkit-runner-toolbar";
|
|
76
|
+
/** Entry button placed in the HUD action bar (styled by initEditorHud). */
|
|
77
|
+
const playButtonEl = document.createElement("button");
|
|
78
|
+
playButtonEl.title = "Play mode";
|
|
79
|
+
playButtonEl.innerHTML = PLAY_ICON;
|
|
80
|
+
const unsubs = [];
|
|
81
|
+
// ── Play panel DOM ──────────────────────────────────────────────────────
|
|
82
|
+
const playPanelEl = document.createElement("div");
|
|
83
|
+
playPanelEl.className = "bpmnkit-runner-play-panel";
|
|
84
|
+
const playTabBarEl = document.createElement("div");
|
|
85
|
+
playTabBarEl.className = "bpmnkit-runner-play-tabs";
|
|
86
|
+
function makeTabBtn(label, active) {
|
|
87
|
+
const b = document.createElement("button");
|
|
88
|
+
b.className = active
|
|
89
|
+
? "bpmnkit-runner-play-tab bpmnkit-runner-play-tab--active"
|
|
90
|
+
: "bpmnkit-runner-play-tab";
|
|
91
|
+
b.textContent = label;
|
|
92
|
+
return b;
|
|
93
|
+
}
|
|
94
|
+
const varTabBtn = makeTabBtn("Variables", true);
|
|
95
|
+
const feelTabBtn = makeTabBtn("FEEL", false);
|
|
96
|
+
const errorsTabBtn = makeTabBtn("Errors", false);
|
|
97
|
+
const inputTabBtn = makeTabBtn("Input", false);
|
|
98
|
+
playTabBarEl.appendChild(varTabBtn);
|
|
99
|
+
playTabBarEl.appendChild(feelTabBtn);
|
|
100
|
+
playTabBarEl.appendChild(errorsTabBtn);
|
|
101
|
+
playTabBarEl.appendChild(inputTabBtn);
|
|
102
|
+
function makePaneEl(hidden) {
|
|
103
|
+
const d = document.createElement("div");
|
|
104
|
+
d.className = hidden
|
|
105
|
+
? "bpmnkit-runner-play-pane bpmnkit-runner-play-pane--hidden"
|
|
106
|
+
: "bpmnkit-runner-play-pane";
|
|
107
|
+
return d;
|
|
108
|
+
}
|
|
109
|
+
const varsPaneEl = makePaneEl(false);
|
|
110
|
+
const feelPaneEl = makePaneEl(true);
|
|
111
|
+
const errorsPaneEl = makePaneEl(true);
|
|
112
|
+
const ivarsPaneEl = makePaneEl(true);
|
|
113
|
+
playPanelEl.appendChild(playTabBarEl);
|
|
114
|
+
playPanelEl.appendChild(varsPaneEl);
|
|
115
|
+
playPanelEl.appendChild(feelPaneEl);
|
|
116
|
+
playPanelEl.appendChild(errorsPaneEl);
|
|
117
|
+
playPanelEl.appendChild(ivarsPaneEl);
|
|
118
|
+
function switchPlayTab(tab) {
|
|
119
|
+
varTabBtn.classList.toggle("bpmnkit-runner-play-tab--active", tab === "variables");
|
|
120
|
+
feelTabBtn.classList.toggle("bpmnkit-runner-play-tab--active", tab === "feel");
|
|
121
|
+
errorsTabBtn.classList.toggle("bpmnkit-runner-play-tab--active", tab === "errors");
|
|
122
|
+
inputTabBtn.classList.toggle("bpmnkit-runner-play-tab--active", tab === "input");
|
|
123
|
+
varsPaneEl.classList.toggle("bpmnkit-runner-play-pane--hidden", tab !== "variables");
|
|
124
|
+
feelPaneEl.classList.toggle("bpmnkit-runner-play-pane--hidden", tab !== "feel");
|
|
125
|
+
errorsPaneEl.classList.toggle("bpmnkit-runner-play-pane--hidden", tab !== "errors");
|
|
126
|
+
ivarsPaneEl.classList.toggle("bpmnkit-runner-play-pane--hidden", tab !== "input");
|
|
127
|
+
}
|
|
128
|
+
varTabBtn.addEventListener("click", () => switchPlayTab("variables"));
|
|
129
|
+
feelTabBtn.addEventListener("click", () => switchPlayTab("feel"));
|
|
130
|
+
errorsTabBtn.addEventListener("click", () => switchPlayTab("errors"));
|
|
131
|
+
inputTabBtn.addEventListener("click", () => switchPlayTab("input"));
|
|
132
|
+
// ── Render functions ────────────────────────────────────────────────────
|
|
133
|
+
function emptyEl(text) {
|
|
134
|
+
const d = document.createElement("div");
|
|
135
|
+
d.className = "bpmnkit-runner-play-empty";
|
|
136
|
+
d.textContent = text;
|
|
137
|
+
return d;
|
|
138
|
+
}
|
|
139
|
+
function clearEl(el) {
|
|
140
|
+
while (el.firstChild !== null)
|
|
141
|
+
el.removeChild(el.firstChild);
|
|
142
|
+
}
|
|
143
|
+
function renderVariables() {
|
|
144
|
+
clearEl(varsPaneEl);
|
|
145
|
+
if (variables.size === 0) {
|
|
146
|
+
varsPaneEl.appendChild(emptyEl("No variables yet."));
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
for (const [name, value] of variables) {
|
|
150
|
+
const row = document.createElement("div");
|
|
151
|
+
row.className = "bpmnkit-runner-play-var-row";
|
|
152
|
+
const nameEl = document.createElement("span");
|
|
153
|
+
nameEl.className = "bpmnkit-runner-play-var-name";
|
|
154
|
+
nameEl.textContent = name;
|
|
155
|
+
const valueEl = document.createElement("span");
|
|
156
|
+
valueEl.className = "bpmnkit-runner-play-var-value";
|
|
157
|
+
valueEl.textContent = JSON.stringify(value);
|
|
158
|
+
row.appendChild(nameEl);
|
|
159
|
+
row.appendChild(valueEl);
|
|
160
|
+
varsPaneEl.appendChild(row);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
function renderFeelEvals() {
|
|
164
|
+
clearEl(feelPaneEl);
|
|
165
|
+
if (feelEvals.length === 0) {
|
|
166
|
+
feelPaneEl.appendChild(emptyEl("No FEEL expressions evaluated yet."));
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const groups = new Map();
|
|
170
|
+
for (const ev of feelEvals) {
|
|
171
|
+
let arr = groups.get(ev.elementId);
|
|
172
|
+
if (arr === undefined) {
|
|
173
|
+
arr = [];
|
|
174
|
+
groups.set(ev.elementId, arr);
|
|
175
|
+
}
|
|
176
|
+
arr.push({ property: ev.property, expression: ev.expression, result: ev.result });
|
|
177
|
+
}
|
|
178
|
+
for (const [elementId, evals] of groups) {
|
|
179
|
+
const groupEl = document.createElement("div");
|
|
180
|
+
groupEl.className = "bpmnkit-runner-play-feel-group";
|
|
181
|
+
const headerEl = document.createElement("div");
|
|
182
|
+
headerEl.className = "bpmnkit-runner-play-feel-header";
|
|
183
|
+
headerEl.textContent = elementId;
|
|
184
|
+
groupEl.appendChild(headerEl);
|
|
185
|
+
for (const ev of evals) {
|
|
186
|
+
const rowEl = document.createElement("div");
|
|
187
|
+
rowEl.className = "bpmnkit-runner-play-feel-row";
|
|
188
|
+
const propEl = document.createElement("div");
|
|
189
|
+
propEl.className = "bpmnkit-runner-play-feel-prop";
|
|
190
|
+
propEl.textContent = ev.property;
|
|
191
|
+
const exprEl = document.createElement("code");
|
|
192
|
+
exprEl.className = "bpmnkit-runner-play-feel-expr";
|
|
193
|
+
exprEl.textContent = ev.expression;
|
|
194
|
+
const resultRowEl = document.createElement("div");
|
|
195
|
+
resultRowEl.className = "bpmnkit-runner-play-feel-result-row";
|
|
196
|
+
const arrowEl = document.createElement("span");
|
|
197
|
+
arrowEl.className = "bpmnkit-runner-play-feel-arrow";
|
|
198
|
+
arrowEl.textContent = "\u2192";
|
|
199
|
+
const resultEl = document.createElement("span");
|
|
200
|
+
resultEl.className = "bpmnkit-runner-play-feel-result";
|
|
201
|
+
resultEl.textContent = JSON.stringify(ev.result);
|
|
202
|
+
resultRowEl.appendChild(arrowEl);
|
|
203
|
+
resultRowEl.appendChild(resultEl);
|
|
204
|
+
rowEl.appendChild(propEl);
|
|
205
|
+
rowEl.appendChild(exprEl);
|
|
206
|
+
rowEl.appendChild(resultRowEl);
|
|
207
|
+
groupEl.appendChild(rowEl);
|
|
208
|
+
}
|
|
209
|
+
feelPaneEl.appendChild(groupEl);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
function renderErrors() {
|
|
213
|
+
clearEl(errorsPaneEl);
|
|
214
|
+
if (errors.length === 0) {
|
|
215
|
+
errorsPaneEl.appendChild(emptyEl("No errors."));
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
for (const err of errors) {
|
|
219
|
+
const rowEl = document.createElement("div");
|
|
220
|
+
rowEl.className = "bpmnkit-runner-play-error-row";
|
|
221
|
+
if (err.elementId !== undefined) {
|
|
222
|
+
const idEl = document.createElement("div");
|
|
223
|
+
idEl.className = "bpmnkit-runner-play-error-id";
|
|
224
|
+
idEl.textContent = err.elementId;
|
|
225
|
+
rowEl.appendChild(idEl);
|
|
226
|
+
}
|
|
227
|
+
const msgEl = document.createElement("div");
|
|
228
|
+
msgEl.className = "bpmnkit-runner-play-error-msg";
|
|
229
|
+
msgEl.textContent = err.message;
|
|
230
|
+
rowEl.appendChild(msgEl);
|
|
231
|
+
errorsPaneEl.appendChild(rowEl);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function buildInputVars() {
|
|
235
|
+
const result = {};
|
|
236
|
+
for (const { name, value } of inputVars) {
|
|
237
|
+
const trimmed = name.trim();
|
|
238
|
+
if (trimmed === "")
|
|
239
|
+
continue;
|
|
240
|
+
try {
|
|
241
|
+
result[trimmed] = JSON.parse(value);
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
result[trimmed] = value;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return result;
|
|
248
|
+
}
|
|
249
|
+
function renderInputVars() {
|
|
250
|
+
clearEl(ivarsPaneEl);
|
|
251
|
+
for (let i = 0; i < inputVars.length; i++) {
|
|
252
|
+
const entry = inputVars[i];
|
|
253
|
+
if (entry === undefined)
|
|
254
|
+
continue;
|
|
255
|
+
const row = document.createElement("div");
|
|
256
|
+
row.className = "bpmnkit-runner-play-ivar-row";
|
|
257
|
+
const nameInput = document.createElement("input");
|
|
258
|
+
nameInput.className = "bpmnkit-runner-play-ivar-name";
|
|
259
|
+
nameInput.placeholder = "name";
|
|
260
|
+
nameInput.value = entry.name;
|
|
261
|
+
nameInput.addEventListener("input", () => {
|
|
262
|
+
const v = inputVars[i];
|
|
263
|
+
if (v !== undefined) {
|
|
264
|
+
v.name = nameInput.value;
|
|
265
|
+
void saveInputVars(currentProjectId, inputVars);
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
const eqEl = document.createElement("span");
|
|
269
|
+
eqEl.className = "bpmnkit-runner-play-ivar-eq";
|
|
270
|
+
eqEl.textContent = "=";
|
|
271
|
+
const valueInput = document.createElement("input");
|
|
272
|
+
valueInput.className = "bpmnkit-runner-play-ivar-value";
|
|
273
|
+
valueInput.placeholder = "value (JSON or string)";
|
|
274
|
+
valueInput.value = entry.value;
|
|
275
|
+
valueInput.addEventListener("input", () => {
|
|
276
|
+
const v = inputVars[i];
|
|
277
|
+
if (v !== undefined) {
|
|
278
|
+
v.value = valueInput.value;
|
|
279
|
+
void saveInputVars(currentProjectId, inputVars);
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
const delBtn = document.createElement("button");
|
|
283
|
+
delBtn.className = "bpmnkit-runner-play-ivar-del";
|
|
284
|
+
delBtn.textContent = "\u00D7";
|
|
285
|
+
delBtn.addEventListener("click", () => {
|
|
286
|
+
inputVars.splice(i, 1);
|
|
287
|
+
renderInputVars();
|
|
288
|
+
void saveInputVars(currentProjectId, inputVars);
|
|
289
|
+
});
|
|
290
|
+
row.appendChild(nameInput);
|
|
291
|
+
row.appendChild(eqEl);
|
|
292
|
+
row.appendChild(valueInput);
|
|
293
|
+
row.appendChild(delBtn);
|
|
294
|
+
ivarsPaneEl.appendChild(row);
|
|
295
|
+
}
|
|
296
|
+
const addBtn = document.createElement("button");
|
|
297
|
+
addBtn.className = "bpmnkit-runner-play-ivar-add";
|
|
298
|
+
addBtn.textContent = "+ Add variable";
|
|
299
|
+
addBtn.addEventListener("click", () => {
|
|
300
|
+
inputVars.push({ name: "", value: "" });
|
|
301
|
+
renderInputVars();
|
|
302
|
+
void saveInputVars(currentProjectId, inputVars);
|
|
303
|
+
// Focus the name field of the new row
|
|
304
|
+
const rows = ivarsPaneEl.querySelectorAll(".bpmnkit-runner-play-ivar-name");
|
|
305
|
+
rows[rows.length - 1]?.focus();
|
|
306
|
+
});
|
|
307
|
+
ivarsPaneEl.appendChild(addBtn);
|
|
308
|
+
}
|
|
309
|
+
// ── Helpers ────────────────────────────────────────────────────────────
|
|
310
|
+
function getPrimaryProcessId() {
|
|
311
|
+
return currentProcessId;
|
|
312
|
+
}
|
|
313
|
+
function clearRunState() {
|
|
314
|
+
feelEvals.length = 0;
|
|
315
|
+
variables.clear();
|
|
316
|
+
errors.length = 0;
|
|
317
|
+
renderVariables();
|
|
318
|
+
renderFeelEvals();
|
|
319
|
+
renderErrors();
|
|
320
|
+
}
|
|
321
|
+
/** Cancel running instance and reset run state. Stays in play mode. */
|
|
322
|
+
function cleanup() {
|
|
323
|
+
currentInstance?.cancel();
|
|
324
|
+
currentInstance = null;
|
|
325
|
+
stopTrackHighlight?.();
|
|
326
|
+
stopTrackHighlight = undefined;
|
|
327
|
+
stepQueue.length = 0;
|
|
328
|
+
options.tokenHighlight?.api.clear();
|
|
329
|
+
clearRunState();
|
|
330
|
+
mode = "idle";
|
|
331
|
+
updateToolbar();
|
|
332
|
+
}
|
|
333
|
+
/** Exit play mode entirely (also cancels any running instance). */
|
|
334
|
+
function exitPlayMode() {
|
|
335
|
+
currentInstance?.cancel();
|
|
336
|
+
currentInstance = null;
|
|
337
|
+
stopTrackHighlight?.();
|
|
338
|
+
stopTrackHighlight = undefined;
|
|
339
|
+
stepQueue.length = 0;
|
|
340
|
+
options.tokenHighlight?.api.clear();
|
|
341
|
+
clearRunState();
|
|
342
|
+
mode = "idle";
|
|
343
|
+
playModeActive = false;
|
|
344
|
+
updateToolbar();
|
|
345
|
+
options.onExitPlayMode?.();
|
|
346
|
+
options.onHidePlayTab?.();
|
|
347
|
+
}
|
|
348
|
+
function startInstance(vars, stepMode = false) {
|
|
349
|
+
if (currentInstance !== null)
|
|
350
|
+
cleanup();
|
|
351
|
+
const processId = getPrimaryProcessId();
|
|
352
|
+
if (processId === undefined)
|
|
353
|
+
return;
|
|
354
|
+
mode = stepMode ? "running-step" : "running-auto";
|
|
355
|
+
updateToolbar();
|
|
356
|
+
const beforeComplete = stepMode
|
|
357
|
+
? (_elementId) => new Promise((resolve) => {
|
|
358
|
+
stepQueue.push(resolve);
|
|
359
|
+
updateToolbar();
|
|
360
|
+
})
|
|
361
|
+
: (_elementId) => new Promise((resolve) => {
|
|
362
|
+
setTimeout(resolve, AUTO_PLAY_DELAY_MS);
|
|
363
|
+
});
|
|
364
|
+
const instance = engine.start(processId, vars, { beforeComplete });
|
|
365
|
+
currentInstance = instance;
|
|
366
|
+
if (options.tokenHighlight !== undefined) {
|
|
367
|
+
stopTrackHighlight = options.tokenHighlight.api.trackInstance(instance);
|
|
368
|
+
}
|
|
369
|
+
instance.onChange((evt) => {
|
|
370
|
+
const type = evt.type;
|
|
371
|
+
if (type === "process:completed" || type === "process:failed") {
|
|
372
|
+
if (type === "process:failed") {
|
|
373
|
+
const error = evt.error;
|
|
374
|
+
if (typeof error === "string") {
|
|
375
|
+
// Avoid duplicating if element:failed already logged this message
|
|
376
|
+
const alreadyRecorded = errors.some((e) => e.message === error);
|
|
377
|
+
if (!alreadyRecorded) {
|
|
378
|
+
errors.push({ message: error });
|
|
379
|
+
renderErrors();
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
stopTrackHighlight?.();
|
|
384
|
+
stopTrackHighlight = undefined;
|
|
385
|
+
currentInstance = null;
|
|
386
|
+
stepQueue.length = 0;
|
|
387
|
+
mode = "idle";
|
|
388
|
+
updateToolbar();
|
|
389
|
+
}
|
|
390
|
+
else if (type === "feel:evaluated") {
|
|
391
|
+
const elementId = evt.elementId;
|
|
392
|
+
const property = evt.property;
|
|
393
|
+
const expression = evt.expression;
|
|
394
|
+
if (typeof elementId === "string" &&
|
|
395
|
+
typeof property === "string" &&
|
|
396
|
+
typeof expression === "string") {
|
|
397
|
+
feelEvals.push({ elementId, property, expression, result: evt.result });
|
|
398
|
+
renderFeelEvals();
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
else if (type === "variable:set") {
|
|
402
|
+
const name = evt.name;
|
|
403
|
+
if (typeof name === "string") {
|
|
404
|
+
variables.set(name, evt.value);
|
|
405
|
+
renderVariables();
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
else if (type === "element:failed") {
|
|
409
|
+
const elementId = evt.elementId;
|
|
410
|
+
const error = evt.error;
|
|
411
|
+
if (typeof elementId === "string" && typeof error === "string") {
|
|
412
|
+
errors.push({ elementId, message: error });
|
|
413
|
+
renderErrors();
|
|
414
|
+
options.tokenHighlight?.api.setError(elementId);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
// ── Toolbar rendering ──────────────────────────────────────────────────
|
|
420
|
+
function btn(label, extraClass) {
|
|
421
|
+
const b = document.createElement("button");
|
|
422
|
+
b.className =
|
|
423
|
+
extraClass !== undefined ? `bpmnkit-runner-btn ${extraClass}` : "bpmnkit-runner-btn";
|
|
424
|
+
b.textContent = label;
|
|
425
|
+
return b;
|
|
426
|
+
}
|
|
427
|
+
playButtonEl.addEventListener("click", () => {
|
|
428
|
+
playModeActive = true;
|
|
429
|
+
updateToolbar();
|
|
430
|
+
options.onEnterPlayMode?.();
|
|
431
|
+
options.onShowPlayTab?.();
|
|
432
|
+
});
|
|
433
|
+
function updateToolbar() {
|
|
434
|
+
while (toolbarEl.firstChild !== null) {
|
|
435
|
+
toolbarEl.removeChild(toolbarEl.firstChild);
|
|
436
|
+
}
|
|
437
|
+
// Hide the HUD entry button while in play mode
|
|
438
|
+
playButtonEl.style.display = playModeActive ? "none" : "";
|
|
439
|
+
if (!playModeActive)
|
|
440
|
+
return;
|
|
441
|
+
const isRunning = mode !== "idle";
|
|
442
|
+
const hasPendingStep = mode === "running-step" && stepQueue.length > 0;
|
|
443
|
+
// Run button
|
|
444
|
+
const runBtn = btn("\u25B6 Run");
|
|
445
|
+
runBtn.disabled = isRunning;
|
|
446
|
+
runBtn.addEventListener("click", () => {
|
|
447
|
+
if (mode === "idle")
|
|
448
|
+
startInstance(buildInputVars());
|
|
449
|
+
});
|
|
450
|
+
toolbarEl.appendChild(runBtn);
|
|
451
|
+
// One Step button — enabled in idle (start step run) or when paused (advance)
|
|
452
|
+
const oneStepBtn = btn("\u21A6 One Step", "bpmnkit-runner-btn--step");
|
|
453
|
+
oneStepBtn.disabled = isRunning && !hasPendingStep;
|
|
454
|
+
oneStepBtn.addEventListener("click", () => {
|
|
455
|
+
if (mode === "running-step" && stepQueue.length > 0) {
|
|
456
|
+
const next = stepQueue.shift();
|
|
457
|
+
if (next !== undefined) {
|
|
458
|
+
next();
|
|
459
|
+
updateToolbar();
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
else if (mode === "idle") {
|
|
463
|
+
startInstance(buildInputVars(), true);
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
toolbarEl.appendChild(oneStepBtn);
|
|
467
|
+
// Cancel button
|
|
468
|
+
const cancelBtn = btn("\u25A0 Cancel", "bpmnkit-runner-btn--stop");
|
|
469
|
+
cancelBtn.disabled = !isRunning;
|
|
470
|
+
cancelBtn.addEventListener("click", () => {
|
|
471
|
+
if (mode !== "idle")
|
|
472
|
+
cleanup();
|
|
473
|
+
});
|
|
474
|
+
toolbarEl.appendChild(cancelBtn);
|
|
475
|
+
// Exit button
|
|
476
|
+
const exitBtn = btn("Exit", "bpmnkit-runner-btn--exit");
|
|
477
|
+
exitBtn.addEventListener("click", () => exitPlayMode());
|
|
478
|
+
toolbarEl.appendChild(exitBtn);
|
|
479
|
+
}
|
|
480
|
+
// ── CanvasPlugin ───────────────────────────────────────────────────────
|
|
481
|
+
return {
|
|
482
|
+
name: "process-runner",
|
|
483
|
+
/** The toolbar element. Place this in the tabs bar center slot; shows running controls during play mode. */
|
|
484
|
+
toolbar: toolbarEl,
|
|
485
|
+
/** Icon button for the HUD action bar. Pass to `initEditorHud` as `playButton`. */
|
|
486
|
+
playButton: playButtonEl,
|
|
487
|
+
/** Exits play mode and cancels any running instance. */
|
|
488
|
+
exitPlayMode,
|
|
489
|
+
install(api) {
|
|
490
|
+
canvasApi = api;
|
|
491
|
+
injectProcessRunnerStyles();
|
|
492
|
+
updateToolbar();
|
|
493
|
+
renderVariables();
|
|
494
|
+
renderFeelEvals();
|
|
495
|
+
renderErrors();
|
|
496
|
+
renderInputVars();
|
|
497
|
+
if (options.playContainer !== undefined) {
|
|
498
|
+
options.playContainer.appendChild(playPanelEl);
|
|
499
|
+
}
|
|
500
|
+
// Load persisted input variables for the initial project
|
|
501
|
+
currentProjectId = options.getProjectId?.() ?? null;
|
|
502
|
+
void loadInputVars(currentProjectId).then((loaded) => {
|
|
503
|
+
inputVars.length = 0;
|
|
504
|
+
for (const v of loaded)
|
|
505
|
+
inputVars.push(v);
|
|
506
|
+
renderInputVars();
|
|
507
|
+
});
|
|
508
|
+
const onAny = api.on;
|
|
509
|
+
unsubs.push(api.on("diagram:load", (defs) => {
|
|
510
|
+
currentProcessId = defs.processes[0]?.id;
|
|
511
|
+
engine.deploy({ bpmn: defs });
|
|
512
|
+
if (currentInstance !== null)
|
|
513
|
+
cleanup();
|
|
514
|
+
// Reload input vars if the project changed
|
|
515
|
+
const pid = options.getProjectId?.() ?? null;
|
|
516
|
+
if (pid !== currentProjectId) {
|
|
517
|
+
currentProjectId = pid;
|
|
518
|
+
void loadInputVars(pid).then((loaded) => {
|
|
519
|
+
inputVars.length = 0;
|
|
520
|
+
for (const v of loaded)
|
|
521
|
+
inputVars.push(v);
|
|
522
|
+
renderInputVars();
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
updateToolbar();
|
|
526
|
+
}), api.on("diagram:clear", () => {
|
|
527
|
+
currentProcessId = undefined;
|
|
528
|
+
if (currentInstance !== null)
|
|
529
|
+
cleanup();
|
|
530
|
+
updateToolbar();
|
|
531
|
+
}), onAny("diagram:change", (defs) => {
|
|
532
|
+
const typed = defs;
|
|
533
|
+
currentProcessId = typed.processes?.[0]?.id;
|
|
534
|
+
engine.deploy({ bpmn: defs });
|
|
535
|
+
if (currentInstance !== null)
|
|
536
|
+
cleanup();
|
|
537
|
+
}));
|
|
538
|
+
},
|
|
539
|
+
uninstall() {
|
|
540
|
+
for (const off of unsubs)
|
|
541
|
+
off();
|
|
542
|
+
cleanup();
|
|
543
|
+
toolbarEl.remove();
|
|
544
|
+
playPanelEl.remove();
|
|
545
|
+
canvasApi = null;
|
|
546
|
+
},
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare class AutoSave {
|
|
2
|
+
private readonly _timers;
|
|
3
|
+
private readonly _latest;
|
|
4
|
+
private readonly _delay;
|
|
5
|
+
private readonly _onSave;
|
|
6
|
+
constructor(onSave: (fileId: string, content: string) => Promise<void>, delay?: number);
|
|
7
|
+
schedule(fileId: string, content: string): void;
|
|
8
|
+
flush(): Promise<void>;
|
|
9
|
+
private _save;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=auto-save.d.ts.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export class AutoSave {
|
|
2
|
+
_timers = new Map();
|
|
3
|
+
_latest = new Map();
|
|
4
|
+
_delay;
|
|
5
|
+
_onSave;
|
|
6
|
+
constructor(onSave, delay = 500) {
|
|
7
|
+
this._onSave = onSave;
|
|
8
|
+
this._delay = delay;
|
|
9
|
+
document.addEventListener("visibilitychange", () => {
|
|
10
|
+
if (document.visibilityState === "hidden")
|
|
11
|
+
void this.flush();
|
|
12
|
+
});
|
|
13
|
+
window.addEventListener("beforeunload", () => void this.flush());
|
|
14
|
+
}
|
|
15
|
+
schedule(fileId, content) {
|
|
16
|
+
this._latest.set(fileId, content);
|
|
17
|
+
const existing = this._timers.get(fileId);
|
|
18
|
+
if (existing !== undefined)
|
|
19
|
+
clearTimeout(existing);
|
|
20
|
+
this._timers.set(fileId, setTimeout(() => {
|
|
21
|
+
void this._save(fileId);
|
|
22
|
+
}, this._delay));
|
|
23
|
+
}
|
|
24
|
+
async flush() {
|
|
25
|
+
const entries = [...this._latest.entries()];
|
|
26
|
+
for (const [fileId] of entries) {
|
|
27
|
+
const timer = this._timers.get(fileId);
|
|
28
|
+
if (timer !== undefined)
|
|
29
|
+
clearTimeout(timer);
|
|
30
|
+
this._timers.delete(fileId);
|
|
31
|
+
}
|
|
32
|
+
this._latest.clear();
|
|
33
|
+
await Promise.all(entries.map(([id, content]) => this._onSave(id, content)));
|
|
34
|
+
}
|
|
35
|
+
async _save(fileId) {
|
|
36
|
+
const content = this._latest.get(fileId);
|
|
37
|
+
if (content === undefined)
|
|
38
|
+
return;
|
|
39
|
+
this._latest.delete(fileId);
|
|
40
|
+
this._timers.delete(fileId);
|
|
41
|
+
await this._onSave(fileId, content);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=auto-save.js.map
|