@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.
Files changed (72) hide show
  1. package/README.md +131 -0
  2. package/dist/components/badge.d.ts +2 -0
  3. package/dist/components/badge.js +2 -0
  4. package/dist/components/card.d.ts +2 -0
  5. package/dist/components/card.js +2 -0
  6. package/dist/components/chart.d.ts +6 -0
  7. package/dist/components/chart.js +161 -0
  8. package/dist/components/filter-table.d.ts +20 -0
  9. package/dist/components/filter-table.js +215 -0
  10. package/dist/components/table.d.ts +2 -0
  11. package/dist/components/table.js +2 -0
  12. package/dist/css.d.ts +2 -0
  13. package/dist/css.js +1071 -0
  14. package/dist/index.d.ts +3 -0
  15. package/dist/index.js +2 -0
  16. package/dist/mock-data.d.ts +18 -0
  17. package/dist/mock-data.js +509 -0
  18. package/dist/operate.d.ts +3 -0
  19. package/dist/operate.js +308 -0
  20. package/dist/router.d.ts +9 -0
  21. package/dist/router.js +49 -0
  22. package/dist/stores/base.d.ts +20 -0
  23. package/dist/stores/base.js +32 -0
  24. package/dist/stores/dashboard.d.ts +6 -0
  25. package/dist/stores/dashboard.js +19 -0
  26. package/dist/stores/decisions.d.ts +9 -0
  27. package/dist/stores/decisions.js +19 -0
  28. package/dist/stores/definitions.d.ts +9 -0
  29. package/dist/stores/definitions.js +19 -0
  30. package/dist/stores/incidents.d.ts +10 -0
  31. package/dist/stores/incidents.js +27 -0
  32. package/dist/stores/instances.d.ts +15 -0
  33. package/dist/stores/instances.js +33 -0
  34. package/dist/stores/jobs.d.ts +10 -0
  35. package/dist/stores/jobs.js +19 -0
  36. package/dist/stores/tasks.d.ts +10 -0
  37. package/dist/stores/tasks.js +19 -0
  38. package/dist/stream.d.ts +12 -0
  39. package/dist/stream.js +42 -0
  40. package/dist/types.d.ts +48 -0
  41. package/dist/types.js +2 -0
  42. package/dist/views/dashboard.d.ts +6 -0
  43. package/dist/views/dashboard.js +98 -0
  44. package/dist/views/decision-detail.d.ts +15 -0
  45. package/dist/views/decision-detail.js +167 -0
  46. package/dist/views/decisions.d.ts +7 -0
  47. package/dist/views/decisions.js +78 -0
  48. package/dist/views/definition-detail.d.ts +15 -0
  49. package/dist/views/definition-detail.js +339 -0
  50. package/dist/views/definitions.d.ts +7 -0
  51. package/dist/views/definitions.js +70 -0
  52. package/dist/views/header.d.ts +9 -0
  53. package/dist/views/header.js +49 -0
  54. package/dist/views/incident-detail.d.ts +14 -0
  55. package/dist/views/incident-detail.js +540 -0
  56. package/dist/views/incidents.d.ts +7 -0
  57. package/dist/views/incidents.js +108 -0
  58. package/dist/views/instance-detail.d.ts +16 -0
  59. package/dist/views/instance-detail.js +728 -0
  60. package/dist/views/instances.d.ts +7 -0
  61. package/dist/views/instances.js +249 -0
  62. package/dist/views/jobs.d.ts +6 -0
  63. package/dist/views/jobs.js +60 -0
  64. package/dist/views/messages.d.ts +11 -0
  65. package/dist/views/messages.js +431 -0
  66. package/dist/views/nav.d.ts +10 -0
  67. package/dist/views/nav.js +60 -0
  68. package/dist/views/task-detail.d.ts +13 -0
  69. package/dist/views/task-detail.js +187 -0
  70. package/dist/views/tasks.d.ts +7 -0
  71. package/dist/views/tasks.js +72 -0
  72. package/package.json +46 -0
@@ -0,0 +1,187 @@
1
+ import { FormEditor } from "@bpmnkit/plugins/form-editor";
2
+ import { badge } from "../components/badge.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 metaRow(label, value) {
18
+ const row = document.createElement("div");
19
+ row.className = "op-task-meta-row";
20
+ const lbl = document.createElement("span");
21
+ lbl.className = "op-task-meta-label";
22
+ lbl.textContent = label;
23
+ const val = document.createElement("span");
24
+ val.className = "op-task-meta-value";
25
+ val.textContent = value;
26
+ row.appendChild(lbl);
27
+ row.appendChild(val);
28
+ return row;
29
+ }
30
+ export function createTaskDetailView(taskKey, store, cfg, onBack) {
31
+ const el = document.createElement("div");
32
+ el.className = "op-view op-def-detail";
33
+ // Breadcrumb
34
+ const breadcrumb = document.createElement("div");
35
+ breadcrumb.className = "op-breadcrumb";
36
+ const backBtn = document.createElement("button");
37
+ backBtn.className = "op-back-btn";
38
+ backBtn.textContent = "← Tasks";
39
+ backBtn.addEventListener("click", onBack);
40
+ breadcrumb.appendChild(backBtn);
41
+ el.appendChild(breadcrumb);
42
+ // Metadata row
43
+ const meta = document.createElement("div");
44
+ meta.className = "op-def-meta";
45
+ el.appendChild(meta);
46
+ // Body: split into meta panel + form panel
47
+ const body = document.createElement("div");
48
+ body.className = "op-task-detail-body";
49
+ el.appendChild(body);
50
+ // Left: task info
51
+ const infoPanel = document.createElement("div");
52
+ infoPanel.className = "op-task-info-panel";
53
+ body.appendChild(infoPanel);
54
+ // Right: form
55
+ const formWrap = document.createElement("div");
56
+ formWrap.className = "op-task-form-wrap";
57
+ body.appendChild(formWrap);
58
+ let editor = null;
59
+ function renderTaskInfo(task) {
60
+ meta.innerHTML = "";
61
+ const titleEl = document.createElement("span");
62
+ titleEl.className = "op-def-meta-name";
63
+ titleEl.textContent = task.name ?? "—";
64
+ meta.appendChild(titleEl);
65
+ meta.appendChild(badge(task.state ?? "UNKNOWN"));
66
+ infoPanel.innerHTML = "";
67
+ const heading = document.createElement("div");
68
+ heading.className = "op-task-info-heading";
69
+ heading.textContent = "Task Details";
70
+ infoPanel.appendChild(heading);
71
+ infoPanel.appendChild(metaRow("Key", task.userTaskKey ?? "—"));
72
+ infoPanel.appendChild(metaRow("Assignee", task.assignee ?? "unassigned"));
73
+ infoPanel.appendChild(metaRow("Process", task.processName ?? task.processDefinitionId ?? "—"));
74
+ infoPanel.appendChild(metaRow("Instance", task.processInstanceKey ?? "—"));
75
+ infoPanel.appendChild(metaRow("Created", relTime(task.creationDate)));
76
+ infoPanel.appendChild(metaRow("Due", relTime(task.dueDate)));
77
+ infoPanel.appendChild(metaRow("Priority", String(task.priority ?? "—")));
78
+ if (task.candidateGroups?.length) {
79
+ infoPanel.appendChild(metaRow("Groups", task.candidateGroups.join(", ")));
80
+ }
81
+ if (task.candidateUsers?.length) {
82
+ infoPanel.appendChild(metaRow("Candidates", task.candidateUsers.join(", ")));
83
+ }
84
+ }
85
+ function loadForm(schema) {
86
+ editor?.destroy();
87
+ formWrap.innerHTML = "";
88
+ const formHeading = document.createElement("div");
89
+ formHeading.className = "op-task-info-heading";
90
+ formHeading.textContent = "Form";
91
+ formWrap.appendChild(formHeading);
92
+ const formContainer = document.createElement("div");
93
+ formContainer.className = "op-task-form-container";
94
+ formWrap.appendChild(formContainer);
95
+ editor = new FormEditor({ container: formContainer, theme: cfg.theme, readonly: true });
96
+ editor.loadSchema(schema).catch(() => { });
97
+ }
98
+ function showNoForm() {
99
+ formWrap.innerHTML = "";
100
+ const msg = document.createElement("div");
101
+ msg.className = "op-panel-empty";
102
+ msg.textContent = "No form associated with this task.";
103
+ formWrap.appendChild(msg);
104
+ }
105
+ function fetchForm(task) {
106
+ if (cfg.mock) {
107
+ loadForm({
108
+ type: "default",
109
+ id: "mock-form",
110
+ components: [
111
+ { id: "f1", type: "textfield", label: "Order ID", key: "orderId" },
112
+ { id: "f2", type: "checkbox", label: "Approve", key: "approved" },
113
+ { id: "f3", type: "button", label: "Submit", action: "submit" },
114
+ ],
115
+ });
116
+ return;
117
+ }
118
+ if (!task.formKey && !task.externalFormReference) {
119
+ showNoForm();
120
+ return;
121
+ }
122
+ const headers = {};
123
+ if (cfg.profile)
124
+ headers["x-profile"] = cfg.profile;
125
+ fetch(`${cfg.proxyUrl}/api/user-tasks/${task.userTaskKey}/form`, { headers })
126
+ .then((r) => (r.ok ? r.json() : null))
127
+ .then((result) => {
128
+ let schema = result?.schema;
129
+ // The API returns schema as a JSON string, not an object
130
+ if (typeof schema === "string") {
131
+ try {
132
+ schema = JSON.parse(schema);
133
+ }
134
+ catch {
135
+ schema = undefined;
136
+ }
137
+ }
138
+ if (schema && typeof schema === "object") {
139
+ loadForm(schema);
140
+ }
141
+ else {
142
+ showNoForm();
143
+ }
144
+ })
145
+ .catch(() => showNoForm());
146
+ }
147
+ function initTask(task) {
148
+ renderTaskInfo(task);
149
+ fetchForm(task);
150
+ }
151
+ // Resolve from store or fetch directly
152
+ const fromStore = store.state.data?.items.find((t) => t.userTaskKey === taskKey);
153
+ if (fromStore) {
154
+ initTask(fromStore);
155
+ }
156
+ else if (!cfg.mock) {
157
+ const headers = {};
158
+ if (cfg.profile)
159
+ headers["x-profile"] = cfg.profile;
160
+ fetch(`${cfg.proxyUrl}/api/user-tasks/${taskKey}`, { headers })
161
+ .then((r) => (r.ok ? r.json() : null))
162
+ .then((task) => {
163
+ if (task)
164
+ initTask(task);
165
+ })
166
+ .catch(() => { });
167
+ }
168
+ else {
169
+ // Mock + not in store: show empty state
170
+ showNoForm();
171
+ }
172
+ const unsub = store.subscribe(() => {
173
+ if (editor || formWrap.children.length > 0)
174
+ return;
175
+ const found = store.state.data?.items.find((t) => t.userTaskKey === taskKey);
176
+ if (found)
177
+ initTask(found);
178
+ });
179
+ return {
180
+ el,
181
+ destroy() {
182
+ unsub();
183
+ editor?.destroy();
184
+ },
185
+ };
186
+ }
187
+ //# sourceMappingURL=task-detail.js.map
@@ -0,0 +1,7 @@
1
+ import type { TasksStore } from "../stores/tasks.js";
2
+ import type { UserTaskResult } from "../types.js";
3
+ export declare function createTasksView(store: TasksStore, onSelect?: (task: UserTaskResult) => void): {
4
+ el: HTMLElement;
5
+ destroy(): void;
6
+ };
7
+ //# sourceMappingURL=tasks.d.ts.map
@@ -0,0 +1,72 @@
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
+ export function createTasksView(store, onSelect) {
18
+ const el = document.createElement("div");
19
+ el.className = "op-view";
20
+ const { el: tableEl, setRows } = createFilterTable({
21
+ columns: [
22
+ {
23
+ label: "Name",
24
+ render: (row) => row.name ?? "—",
25
+ sortValue: (row) => row.name ?? "",
26
+ },
27
+ {
28
+ label: "Assignee",
29
+ width: "160px",
30
+ render: (row) => row.assignee ?? "unassigned",
31
+ sortValue: (row) => row.assignee ?? "",
32
+ },
33
+ {
34
+ label: "Process",
35
+ width: "180px",
36
+ render: (row) => row.processName ?? row.processDefinitionId ?? "—",
37
+ sortValue: (row) => row.processName ?? row.processDefinitionId ?? "",
38
+ },
39
+ {
40
+ label: "State",
41
+ width: "100px",
42
+ render: (row) => badge(row.state ?? "UNKNOWN"),
43
+ sortValue: (row) => row.state ?? "",
44
+ },
45
+ {
46
+ label: "Due",
47
+ width: "100px",
48
+ render: (row) => relTime(row.dueDate),
49
+ sortValue: (row) => row.dueDate ?? "",
50
+ },
51
+ {
52
+ label: "Priority",
53
+ width: "70px",
54
+ render: (row) => String(row.priority ?? "—"),
55
+ sortValue: (row) => row.priority ?? 0,
56
+ },
57
+ ],
58
+ searchFn: (row) => [row.name, row.assignee, row.processName, row.processDefinitionId, row.state]
59
+ .filter(Boolean)
60
+ .join(" "),
61
+ onRowClick: onSelect,
62
+ emptyText: "No user tasks found",
63
+ });
64
+ el.appendChild(tableEl);
65
+ function render() {
66
+ setRows(store.state.data?.items ?? []);
67
+ }
68
+ const unsub = store.subscribe(render);
69
+ render();
70
+ return { el, destroy: unsub };
71
+ }
72
+ //# sourceMappingURL=tasks.js.map
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@bpmnkit/operate",
3
+ "version": "0.0.5",
4
+ "description": "Monitoring and operations frontend for Camunda 8 clusters — real-time SSE, zero dependencies",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": ["dist/**/*.js", "dist/**/*.d.ts"],
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "typecheck": "tsc --noEmit",
18
+ "check": "biome check ."
19
+ },
20
+ "dependencies": {
21
+ "@bpmnkit/api": "workspace:*",
22
+ "@bpmnkit/canvas": "workspace:*",
23
+ "@bpmnkit/core": "workspace:*",
24
+ "@bpmnkit/plugins": "workspace:*",
25
+ "@bpmnkit/ui": "workspace:*"
26
+ },
27
+ "keywords": [
28
+ "bpmn",
29
+ "camunda",
30
+ "operate",
31
+ "monitoring",
32
+ "operations",
33
+ "workflow",
34
+ "process-instances",
35
+ "incidents",
36
+ "typescript"
37
+ ],
38
+ "license": "MIT",
39
+ "publishConfig": {
40
+ "access": "public"
41
+ },
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "https://github.com/bpmnkit/monorepo"
45
+ }
46
+ }