@bpmnkit/operate 0.0.12 → 0.0.14

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 CHANGED
@@ -116,6 +116,8 @@ interface OperateApi {
116
116
  | [`@bpmnkit/cli-sdk`](https://www.npmjs.com/package/@bpmnkit/cli-sdk) | Plugin authoring SDK for the casen CLI |
117
117
  | [`@bpmnkit/create-casen-plugin`](https://www.npmjs.com/package/@bpmnkit/create-casen-plugin) | Scaffold a new casen CLI plugin in seconds |
118
118
  | [`@bpmnkit/casen-report`](https://www.npmjs.com/package/@bpmnkit/casen-report) | HTML reports from Camunda 8 incident and SLA data |
119
+ | [`@bpmnkit/casen-worker-http`](https://www.npmjs.com/package/@bpmnkit/casen-worker-http) | Example HTTP worker plugin — completes jobs with live JSONPlaceholder API data |
120
+ | [`@bpmnkit/casen-worker-ai`](https://www.npmjs.com/package/@bpmnkit/casen-worker-ai) | AI task worker — classify, summarize, extract, and decide using Claude |
119
121
 
120
122
  ## License
121
123
 
package/dist/operate.js CHANGED
@@ -27,7 +27,7 @@ import { createTasksView } from "./views/tasks.js";
27
27
  export function createOperate(options) {
28
28
  injectUiStyles();
29
29
  injectOperateStyles();
30
- const { container, proxyUrl = "http://localhost:3033", pollInterval = 30_000, mock = false, } = options;
30
+ const { container, proxyUrl = "http://localhost:3033", pollInterval = 30_000, mock = false, onOpenInEditor, } = options;
31
31
  let profile = options.profile ?? null;
32
32
  const initialTheme = loadPersistedTheme() ?? options.theme ?? "neon";
33
33
  // ── Root element ──────────────────────────────────────────────────────────
@@ -147,7 +147,14 @@ export function createOperate(options) {
147
147
  };
148
148
  header.setTitle("Process Definition");
149
149
  nav.setActive("/definitions");
150
- const { el: vEl, destroy, setTheme, } = createDefinitionDetailView(params.key ?? "", defStore, { proxyUrl, profile, mock, theme: getTheme(), navigate: (path) => router.navigate(path) }, () => router.navigate("/definitions"));
150
+ const { el: vEl, destroy, setTheme, } = createDefinitionDetailView(params.key ?? "", defStore, {
151
+ proxyUrl,
152
+ profile,
153
+ mock,
154
+ theme: getTheme(),
155
+ navigate: (path) => router.navigate(path),
156
+ onOpenInEditor,
157
+ }, () => router.navigate("/definitions"));
151
158
  showView(vEl, destroy, setTheme);
152
159
  });
153
160
  router.on("/decisions", () => {
@@ -204,6 +211,7 @@ export function createOperate(options) {
204
211
  mock,
205
212
  theme: getTheme(),
206
213
  navigate: (path) => router.navigate(path),
214
+ onOpenInEditor,
207
215
  }, () => router.navigate("/instances"));
208
216
  showView(vEl, destroy, setTheme);
209
217
  });
@@ -229,7 +237,14 @@ export function createOperate(options) {
229
237
  const incidentKey = params.key ?? "";
230
238
  header.setTitle(`Incident ${incidentKey}`);
231
239
  nav.setActive("/incidents");
232
- const { el: vEl, destroy } = createIncidentDetailView(incidentKey, incStore, { proxyUrl, profile, mock, theme: getTheme(), navigate: (path) => router.navigate(path) }, () => router.navigate("/incidents"));
240
+ const { el: vEl, destroy } = createIncidentDetailView(incidentKey, incStore, {
241
+ proxyUrl,
242
+ profile,
243
+ mock,
244
+ theme: getTheme(),
245
+ navigate: (path) => router.navigate(path),
246
+ onOpenInEditor,
247
+ }, () => router.navigate("/incidents"));
233
248
  showView(vEl, destroy);
234
249
  });
235
250
  router.on("/jobs", () => {
package/dist/types.d.ts CHANGED
@@ -12,6 +12,11 @@ export interface OperateOptions {
12
12
  pollInterval?: number;
13
13
  /** Use mock/demo data instead of connecting to proxy. */
14
14
  mock?: boolean;
15
+ /**
16
+ * Called when the user clicks "Open in Editor" on a diagram view.
17
+ * Receives the raw BPMN XML and a suggested file name.
18
+ */
19
+ onOpenInEditor?: (xml: string, name: string) => void;
15
20
  }
16
21
  export interface OperateApi {
17
22
  readonly el: HTMLElement;
@@ -5,6 +5,7 @@ interface Config {
5
5
  mock: boolean;
6
6
  theme: "light" | "dark" | "neon";
7
7
  navigate?: (path: string) => void;
8
+ onOpenInEditor?: (xml: string, name: string) => void;
8
9
  }
9
10
  export declare function createDefinitionDetailView(definitionKey: string, store: DefinitionsStore, cfg: Config, onBack: () => void): {
10
11
  el: HTMLElement;
@@ -28,6 +28,19 @@ export function createDefinitionDetailView(definitionKey, store, cfg, onBack) {
28
28
  backBtn.textContent = "← Processes";
29
29
  backBtn.addEventListener("click", onBack);
30
30
  breadcrumb.appendChild(backBtn);
31
+ let _openInEditorXml = null;
32
+ let _openInEditorName = "";
33
+ const openInEditorBtn = document.createElement("button");
34
+ openInEditorBtn.className = "op-action-btn";
35
+ openInEditorBtn.textContent = "Open in Editor ↗";
36
+ openInEditorBtn.style.marginLeft = "auto";
37
+ openInEditorBtn.style.display = "none";
38
+ openInEditorBtn.addEventListener("click", () => {
39
+ if (_openInEditorXml)
40
+ cfg.onOpenInEditor?.(_openInEditorXml, _openInEditorName);
41
+ });
42
+ if (cfg.onOpenInEditor)
43
+ breadcrumb.appendChild(openInEditorBtn);
31
44
  el.appendChild(breadcrumb);
32
45
  // Metadata row
33
46
  const meta = document.createElement("div");
@@ -292,7 +305,10 @@ export function createDefinitionDetailView(definitionKey, store, cfg, onBack) {
292
305
  el.appendChild(overlay);
293
306
  setTimeout(() => bizInput.focus(), 0);
294
307
  }
295
- function loadCanvas(xml) {
308
+ function loadCanvas(xml, name) {
309
+ _openInEditorXml = xml;
310
+ _openInEditorName = name;
311
+ openInEditorBtn.style.display = "";
296
312
  canvas?.destroy();
297
313
  canvasWrap.innerHTML = "";
298
314
  canvas = new BpmnCanvas({
@@ -303,12 +319,15 @@ export function createDefinitionDetailView(definitionKey, store, cfg, onBack) {
303
319
  });
304
320
  }
305
321
  if (cfg.mock) {
306
- renderMeta(getDef());
307
- loadCanvas(MOCK_BPMN_XML);
322
+ const def = getDef();
323
+ renderMeta(def);
324
+ const mockName = def?.name ?? def?.processDefinitionId ?? "Process";
325
+ loadCanvas(MOCK_BPMN_XML, mockName);
308
326
  }
309
327
  else {
310
328
  const def = getDef();
311
329
  renderMeta(def);
330
+ const defName = def?.name ?? def?.processDefinitionId ?? "Process";
312
331
  fetch(`${cfg.proxyUrl}/api/process-definitions/${definitionKey}/xml`, {
313
332
  headers: {
314
333
  accept: "text/xml",
@@ -316,7 +335,7 @@ export function createDefinitionDetailView(definitionKey, store, cfg, onBack) {
316
335
  },
317
336
  })
318
337
  .then((r) => r.text())
319
- .then((xml) => loadCanvas(xml))
338
+ .then((xml) => loadCanvas(xml, defName))
320
339
  .catch(() => {
321
340
  canvasWrap.innerHTML = `<div style="padding:24px;color:var(--bpmnkit-fg-muted)">Failed to load diagram</div>`;
322
341
  });
@@ -5,6 +5,7 @@ interface Config {
5
5
  mock: boolean;
6
6
  theme: "light" | "dark" | "neon";
7
7
  navigate?: (path: string) => void;
8
+ onOpenInEditor?: (xml: string, name: string) => void;
8
9
  }
9
10
  export declare function createIncidentDetailView(incidentKey: string, store: IncidentsStore, cfg: Config, onBack: () => void): {
10
11
  el: HTMLElement;
@@ -44,6 +44,19 @@ export function createIncidentDetailView(incidentKey, store, cfg, onBack) {
44
44
  backBtn.textContent = "← Incidents";
45
45
  backBtn.addEventListener("click", onBack);
46
46
  breadcrumb.appendChild(backBtn);
47
+ let _openInEditorXml = null;
48
+ let _openInEditorName = "";
49
+ const openInEditorBtn = document.createElement("button");
50
+ openInEditorBtn.className = "op-action-btn";
51
+ openInEditorBtn.textContent = "Open in Editor ↗";
52
+ openInEditorBtn.style.marginLeft = "auto";
53
+ openInEditorBtn.style.display = "none";
54
+ openInEditorBtn.addEventListener("click", () => {
55
+ if (_openInEditorXml)
56
+ cfg.onOpenInEditor?.(_openInEditorXml, _openInEditorName);
57
+ });
58
+ if (cfg.onOpenInEditor)
59
+ breadcrumb.appendChild(openInEditorBtn);
47
60
  el.appendChild(breadcrumb);
48
61
  // Process chain (shows Root / Parent / Current)
49
62
  const processChainEl = document.createElement("div");
@@ -221,7 +234,10 @@ export function createIncidentDetailView(incidentKey, store, cfg, onBack) {
221
234
  // Canvas
222
235
  const tokenHighlight = createTokenHighlightPlugin();
223
236
  let canvas = null;
224
- function loadCanvas(xml) {
237
+ function loadCanvas(xml, name) {
238
+ _openInEditorXml = xml;
239
+ _openInEditorName = name;
240
+ openInEditorBtn.style.display = "";
225
241
  canvas?.destroy();
226
242
  canvasWrap.innerHTML = "";
227
243
  canvas = new BpmnCanvas({
@@ -459,7 +475,7 @@ export function createIncidentDetailView(incidentKey, store, cfg, onBack) {
459
475
  let storeUnsub;
460
476
  if (cfg.mock) {
461
477
  const mockInc = MOCK_INCIDENTS.find((i) => i.incidentKey === incidentKey) ?? null;
462
- loadCanvas(MOCK_BPMN_XML);
478
+ loadCanvas(MOCK_BPMN_XML, mockInc?.processDefinitionId ?? "Process");
463
479
  if (mockInc) {
464
480
  renderMeta(mockInc);
465
481
  renderDetails(mockInc);
@@ -488,6 +504,7 @@ export function createIncidentDetailView(incidentKey, store, cfg, onBack) {
488
504
  renderDetails(inc);
489
505
  fetchProcessChain(inc).catch(() => { });
490
506
  const pdKey = inc.processDefinitionKey;
507
+ const incName = inc.processDefinitionId ?? "Process";
491
508
  if (pdKey) {
492
509
  fetch(`${cfg.proxyUrl}/api/process-definitions/${pdKey}/xml`, {
493
510
  headers: {
@@ -497,7 +514,7 @@ export function createIncidentDetailView(incidentKey, store, cfg, onBack) {
497
514
  })
498
515
  .then((r) => r.text())
499
516
  .then((xml) => {
500
- loadCanvas(xml);
517
+ loadCanvas(xml, incName);
501
518
  if (inc.elementId) {
502
519
  tokenHighlight.api.setActive([inc.elementId]);
503
520
  }
@@ -6,6 +6,7 @@ interface Config {
6
6
  mock: boolean;
7
7
  theme: "light" | "dark" | "neon";
8
8
  navigate?: (path: string) => void;
9
+ onOpenInEditor?: (xml: string, name: string) => void;
9
10
  }
10
11
  export declare function createInstanceDetailView(instanceKey: string, instancesStore: InstancesStore, cfg: Config, onBack: () => void): {
11
12
  el: HTMLElement;
@@ -139,6 +139,19 @@ export function createInstanceDetailView(instanceKey, instancesStore, cfg, onBac
139
139
  backBtn.textContent = "← Instances";
140
140
  backBtn.addEventListener("click", onBack);
141
141
  breadcrumb.appendChild(backBtn);
142
+ let _openInEditorXml = null;
143
+ let _openInEditorName = "";
144
+ const openInEditorBtn = document.createElement("button");
145
+ openInEditorBtn.className = "op-action-btn";
146
+ openInEditorBtn.textContent = "Open in Editor ↗";
147
+ openInEditorBtn.style.marginLeft = "auto";
148
+ openInEditorBtn.style.display = "none";
149
+ openInEditorBtn.addEventListener("click", () => {
150
+ if (_openInEditorXml)
151
+ cfg.onOpenInEditor?.(_openInEditorXml, _openInEditorName);
152
+ });
153
+ if (cfg.onOpenInEditor)
154
+ breadcrumb.appendChild(openInEditorBtn);
142
155
  el.appendChild(breadcrumb);
143
156
  // Process hierarchy chain (shown for sub-process instances)
144
157
  const processChainEl = document.createElement("div");
@@ -241,7 +254,10 @@ export function createInstanceDetailView(instanceKey, instancesStore, cfg, onBac
241
254
  // Token-highlight plugin + canvas
242
255
  const tokenHighlight = createTokenHighlightPlugin();
243
256
  let canvas = null;
244
- function loadCanvas(xml) {
257
+ function loadCanvas(xml, name) {
258
+ _openInEditorXml = xml;
259
+ _openInEditorName = name;
260
+ openInEditorBtn.style.display = "";
245
261
  canvas?.destroy();
246
262
  canvasWrap.innerHTML = "";
247
263
  canvas = new BpmnCanvas({
@@ -618,7 +634,7 @@ export function createInstanceDetailView(instanceKey, instancesStore, cfg, onBac
618
634
  // ── Instance data loading ────────────────────────────────────────────────
619
635
  let instUnsub;
620
636
  if (cfg.mock) {
621
- loadCanvas(MOCK_BPMN_XML);
637
+ loadCanvas(MOCK_BPMN_XML, "Order Processing");
622
638
  applyTokens(MOCK_ACTIVE_ELEMENTS, MOCK_VISITED_ELEMENTS);
623
639
  renderVariables(MOCK_VARIABLES.filter((v) => v.processInstanceKey === instanceKey));
624
640
  setTimeout(() => applyTokens(MOCK_ACTIVE_ELEMENTS, MOCK_VISITED_ELEMENTS), 100);
@@ -645,6 +661,7 @@ export function createInstanceDetailView(instanceKey, instancesStore, cfg, onBac
645
661
  renderMeta(inst);
646
662
  fetchProcessChain(inst.processInstanceKey).catch(() => { });
647
663
  const pdKey = inst.processDefinitionKey;
664
+ const instName = inst.processDefinitionName ?? inst.processDefinitionId ?? "Process";
648
665
  fetch(`${cfg.proxyUrl}/api/process-definitions/${pdKey}/xml`, {
649
666
  headers: {
650
667
  accept: "text/xml",
@@ -653,7 +670,7 @@ export function createInstanceDetailView(instanceKey, instancesStore, cfg, onBac
653
670
  })
654
671
  .then((r) => r.text())
655
672
  .then((xml) => {
656
- loadCanvas(xml);
673
+ loadCanvas(xml, instName);
657
674
  return fetch(`${cfg.proxyUrl}/api/element-instances/search`, {
658
675
  method: "POST",
659
676
  headers: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bpmnkit/operate",
3
- "version": "0.0.12",
3
+ "version": "0.0.14",
4
4
  "description": "Monitoring and operations frontend for Camunda 8 clusters — real-time SSE, zero dependencies",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -19,9 +19,9 @@
19
19
  ],
20
20
  "dependencies": {
21
21
  "@bpmnkit/api": "0.0.13",
22
- "@bpmnkit/canvas": "0.0.14",
23
- "@bpmnkit/core": "0.0.14",
24
- "@bpmnkit/plugins": "0.0.15",
22
+ "@bpmnkit/canvas": "0.0.15",
23
+ "@bpmnkit/core": "0.0.15",
24
+ "@bpmnkit/plugins": "0.0.17",
25
25
  "@bpmnkit/ui": "0.0.9"
26
26
  },
27
27
  "keywords": [