@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,431 @@
1
+ import { badge } from "../components/badge.js";
2
+ import { createFilterTable } from "../components/filter-table.js";
3
+ import { MOCK_MESSAGE_SUBSCRIPTIONS } from "../mock-data.js";
4
+ function relTime(iso) {
5
+ if (!iso)
6
+ return "—";
7
+ const diff = Date.now() - new Date(iso).getTime();
8
+ const m = Math.floor(diff / 60_000);
9
+ if (m < 1)
10
+ return "just now";
11
+ if (m < 60)
12
+ return `${m}m ago`;
13
+ const h = Math.floor(m / 60);
14
+ if (h < 24)
15
+ return `${h}h ago`;
16
+ return `${Math.floor(h / 24)}d ago`;
17
+ }
18
+ function parseVariables(raw) {
19
+ const trimmed = raw.trim();
20
+ if (!trimmed)
21
+ return null;
22
+ try {
23
+ const parsed = JSON.parse(trimmed);
24
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
25
+ return parsed;
26
+ }
27
+ return null;
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ }
33
+ function showFormModal(container, title, fields, submitLabel, onSubmit) {
34
+ const overlay = document.createElement("div");
35
+ overlay.className = "op-modal-overlay";
36
+ const dialog = document.createElement("div");
37
+ dialog.className = "op-modal op-modal--form";
38
+ const header = document.createElement("div");
39
+ header.className = "op-modal-header";
40
+ const titleEl = document.createElement("span");
41
+ titleEl.className = "op-modal-title";
42
+ titleEl.textContent = title;
43
+ header.appendChild(titleEl);
44
+ const closeBtn = document.createElement("button");
45
+ closeBtn.className = "op-modal-close";
46
+ closeBtn.textContent = "✕";
47
+ closeBtn.addEventListener("click", () => overlay.remove());
48
+ header.appendChild(closeBtn);
49
+ const body = document.createElement("div");
50
+ body.className = "op-modal-form-body";
51
+ const inputMap = new Map();
52
+ for (const field of fields) {
53
+ const group = document.createElement("div");
54
+ group.className = "op-form-group";
55
+ const label = document.createElement("label");
56
+ label.className = "op-form-label";
57
+ label.textContent = field.required ? `${field.label} *` : field.label;
58
+ let input;
59
+ if (field.type === "textarea") {
60
+ const ta = document.createElement("textarea");
61
+ ta.className = "op-form-textarea";
62
+ ta.placeholder = field.placeholder ?? "";
63
+ ta.rows = 4;
64
+ input = ta;
65
+ }
66
+ else {
67
+ const inp = document.createElement("input");
68
+ inp.type = field.type === "number" ? "number" : "text";
69
+ inp.className = "op-form-input";
70
+ inp.placeholder = field.placeholder ?? "";
71
+ input = inp;
72
+ }
73
+ inputMap.set(field.key, input);
74
+ group.appendChild(label);
75
+ group.appendChild(input);
76
+ if (field.hint) {
77
+ const hint = document.createElement("span");
78
+ hint.className = "op-form-hint";
79
+ hint.textContent = field.hint;
80
+ group.appendChild(hint);
81
+ }
82
+ body.appendChild(group);
83
+ }
84
+ const footer = document.createElement("div");
85
+ footer.className = "op-modal-form-footer";
86
+ const errorEl = document.createElement("div");
87
+ errorEl.className = "op-form-error";
88
+ errorEl.style.display = "none";
89
+ footer.appendChild(errorEl);
90
+ const feedbackEl = document.createElement("div");
91
+ feedbackEl.className = "op-action-feedback";
92
+ feedbackEl.style.display = "none";
93
+ footer.appendChild(feedbackEl);
94
+ const cancelBtn = document.createElement("button");
95
+ cancelBtn.className = "op-action-btn";
96
+ cancelBtn.textContent = "Cancel";
97
+ cancelBtn.style.marginLeft = "auto";
98
+ cancelBtn.addEventListener("click", () => overlay.remove());
99
+ footer.appendChild(cancelBtn);
100
+ const submitBtn = document.createElement("button");
101
+ submitBtn.className = "op-action-btn op-action-btn--primary";
102
+ submitBtn.textContent = submitLabel;
103
+ footer.appendChild(submitBtn);
104
+ submitBtn.addEventListener("click", () => {
105
+ errorEl.style.display = "none";
106
+ // Validate required fields
107
+ const values = {};
108
+ for (const field of fields) {
109
+ const input = inputMap.get(field.key);
110
+ const value = input?.value.trim() ?? "";
111
+ if (field.required && !value) {
112
+ errorEl.textContent = `${field.label} is required.`;
113
+ errorEl.style.display = "";
114
+ input?.focus();
115
+ return;
116
+ }
117
+ values[field.key] = value;
118
+ }
119
+ submitBtn.disabled = true;
120
+ cancelBtn.disabled = true;
121
+ submitBtn.textContent = "Submitting…";
122
+ onSubmit(values)
123
+ .then((successMsg) => {
124
+ feedbackEl.textContent = successMsg;
125
+ feedbackEl.className = "op-action-feedback op-action-feedback--ok";
126
+ feedbackEl.style.display = "";
127
+ submitBtn.style.display = "none";
128
+ cancelBtn.disabled = false;
129
+ cancelBtn.textContent = "Close";
130
+ })
131
+ .catch((err) => {
132
+ errorEl.textContent = String(err);
133
+ errorEl.style.display = "";
134
+ submitBtn.disabled = false;
135
+ cancelBtn.disabled = false;
136
+ submitBtn.textContent = submitLabel;
137
+ });
138
+ });
139
+ dialog.appendChild(header);
140
+ dialog.appendChild(body);
141
+ dialog.appendChild(footer);
142
+ overlay.appendChild(dialog);
143
+ overlay.addEventListener("click", (e) => {
144
+ if (e.target === overlay)
145
+ overlay.remove();
146
+ });
147
+ container.appendChild(overlay);
148
+ const firstInput = fields[0] ? inputMap.get(fields[0].key) : null;
149
+ if (firstInput)
150
+ setTimeout(() => firstInput.focus(), 0);
151
+ }
152
+ function showSubDetailModal(container, sub) {
153
+ const overlay = document.createElement("div");
154
+ overlay.className = "op-modal-overlay";
155
+ const dialog = document.createElement("div");
156
+ dialog.className = "op-modal op-modal--form";
157
+ const header = document.createElement("div");
158
+ header.className = "op-modal-header";
159
+ const titleEl = document.createElement("span");
160
+ titleEl.className = "op-modal-title";
161
+ titleEl.textContent = sub.messageName ?? "Message Subscription";
162
+ header.appendChild(titleEl);
163
+ const closeBtn = document.createElement("button");
164
+ closeBtn.className = "op-modal-close";
165
+ closeBtn.textContent = "✕";
166
+ closeBtn.addEventListener("click", () => overlay.remove());
167
+ header.appendChild(closeBtn);
168
+ const body = document.createElement("div");
169
+ body.className = "op-kv-body";
170
+ const fields = [
171
+ ["State", sub.messageSubscriptionState],
172
+ ["Correlation Key", sub.correlationKey],
173
+ ["Process", sub.processDefinitionId],
174
+ ["Instance Key", sub.processInstanceKey],
175
+ ["Element ID", sub.elementId],
176
+ ["Last Updated", sub.lastUpdatedDate],
177
+ ["Tenant", sub.tenantId],
178
+ ];
179
+ for (const [key, value] of fields) {
180
+ const row = document.createElement("div");
181
+ row.className = "op-kv-row";
182
+ const keyEl = document.createElement("span");
183
+ keyEl.className = "op-kv-key";
184
+ keyEl.textContent = key;
185
+ row.appendChild(keyEl);
186
+ const valEl = document.createElement("span");
187
+ valEl.className = "op-kv-value";
188
+ valEl.textContent = value ?? "—";
189
+ row.appendChild(valEl);
190
+ body.appendChild(row);
191
+ }
192
+ dialog.appendChild(header);
193
+ dialog.appendChild(body);
194
+ overlay.appendChild(dialog);
195
+ overlay.addEventListener("click", (e) => {
196
+ if (e.target === overlay)
197
+ overlay.remove();
198
+ });
199
+ container.appendChild(overlay);
200
+ }
201
+ export function createMessagesView(cfg) {
202
+ const el = document.createElement("div");
203
+ el.className = "op-view op-msg-view";
204
+ // ── Action cards ──────────────────────────────────────────────────────────
205
+ const actionsGrid = document.createElement("div");
206
+ actionsGrid.className = "op-msg-actions";
207
+ el.appendChild(actionsGrid);
208
+ const actions = [
209
+ {
210
+ title: "✉ Correlate Message",
211
+ desc: "Send a message to a waiting catch event by correlation key.",
212
+ submitLabel: "Correlate",
213
+ endpoint: "/api/messages/correlation",
214
+ fields: [
215
+ {
216
+ key: "name",
217
+ label: "Message Name",
218
+ placeholder: "e.g. PaymentConfirmed",
219
+ required: true,
220
+ },
221
+ {
222
+ key: "correlationKey",
223
+ label: "Correlation Key",
224
+ placeholder: "e.g. ORD-10042",
225
+ required: true,
226
+ },
227
+ {
228
+ key: "variables",
229
+ label: "Variables",
230
+ placeholder: '{"amount": 99.99}',
231
+ type: "textarea",
232
+ hint: "Optional JSON object to pass as message variables.",
233
+ },
234
+ ],
235
+ buildBody: (v) => {
236
+ const body = {
237
+ name: v.name,
238
+ correlationKey: v.correlationKey,
239
+ };
240
+ if (v.variables) {
241
+ const vars = parseVariables(v.variables ?? "");
242
+ if (vars)
243
+ body.variables = vars;
244
+ }
245
+ return body;
246
+ },
247
+ },
248
+ {
249
+ title: "📨 Publish Message",
250
+ desc: "Publish a buffered message. Correlation is optional.",
251
+ submitLabel: "Publish",
252
+ endpoint: "/api/messages/publication",
253
+ fields: [
254
+ { key: "name", label: "Message Name", placeholder: "e.g. OrderShipped", required: true },
255
+ { key: "correlationKey", label: "Correlation Key", placeholder: "e.g. ORD-10042" },
256
+ {
257
+ key: "timeToLive",
258
+ label: "Time to Live (ms)",
259
+ placeholder: "e.g. 60000",
260
+ type: "number",
261
+ hint: "How long the message is buffered. Leave empty for default.",
262
+ },
263
+ {
264
+ key: "messageId",
265
+ label: "Message ID",
266
+ placeholder: "Unique deduplication ID (optional)",
267
+ },
268
+ {
269
+ key: "variables",
270
+ label: "Variables",
271
+ placeholder: '{"trackingCode": "XYZ-001"}',
272
+ type: "textarea",
273
+ hint: "Optional JSON object to pass as message variables.",
274
+ },
275
+ ],
276
+ buildBody: (v) => {
277
+ const body = { name: v.name };
278
+ if (v.correlationKey)
279
+ body.correlationKey = v.correlationKey;
280
+ if (v.messageId)
281
+ body.messageId = v.messageId;
282
+ if (v.timeToLive)
283
+ body.timeToLive = Number(v.timeToLive);
284
+ if (v.variables) {
285
+ const vars = parseVariables(v.variables ?? "");
286
+ if (vars)
287
+ body.variables = vars;
288
+ }
289
+ return body;
290
+ },
291
+ },
292
+ {
293
+ title: "⚡ Broadcast Signal",
294
+ desc: "Broadcast a signal to all matching catch events.",
295
+ submitLabel: "Broadcast",
296
+ endpoint: "/api/signals/broadcast",
297
+ fields: [
298
+ {
299
+ key: "signalName",
300
+ label: "Signal Name",
301
+ placeholder: "e.g. StockReplenished",
302
+ required: true,
303
+ },
304
+ {
305
+ key: "variables",
306
+ label: "Variables",
307
+ placeholder: '{"sku": "ITEM-001"}',
308
+ type: "textarea",
309
+ hint: "Optional JSON object to pass as signal variables.",
310
+ },
311
+ ],
312
+ buildBody: (v) => {
313
+ const body = { signalName: v.signalName };
314
+ if (v.variables) {
315
+ const vars = parseVariables(v.variables ?? "");
316
+ if (vars)
317
+ body.variables = vars;
318
+ }
319
+ return body;
320
+ },
321
+ },
322
+ ];
323
+ for (const action of actions) {
324
+ const card = document.createElement("button");
325
+ card.className = "op-msg-action-card";
326
+ const cardTitle = document.createElement("div");
327
+ cardTitle.className = "op-msg-action-card-title";
328
+ cardTitle.textContent = action.title;
329
+ card.appendChild(cardTitle);
330
+ const cardDesc = document.createElement("div");
331
+ cardDesc.className = "op-msg-action-card-desc";
332
+ cardDesc.textContent = action.desc;
333
+ card.appendChild(cardDesc);
334
+ const capturedAction = action;
335
+ card.addEventListener("click", () => {
336
+ showFormModal(el, capturedAction.title, capturedAction.fields, capturedAction.submitLabel, (values) => {
337
+ if (cfg.mock) {
338
+ return Promise.resolve("Mock mode — action not sent to server.");
339
+ }
340
+ const body = capturedAction.buildBody(values);
341
+ const headers = { "Content-Type": "application/json" };
342
+ if (cfg.profile)
343
+ headers["x-profile"] = cfg.profile;
344
+ return fetch(`${cfg.proxyUrl}${capturedAction.endpoint}`, {
345
+ method: "POST",
346
+ headers,
347
+ body: JSON.stringify(body),
348
+ }).then((r) => {
349
+ if (r.ok)
350
+ return r.json().then((data) => {
351
+ const result = data;
352
+ const key = result.processInstanceKey ?? result.messageKey ?? result.signalKey;
353
+ return key ? `Success. Key: ${String(key)}` : "Success.";
354
+ });
355
+ return r.text().then((msg) => {
356
+ throw new Error(`${r.status}: ${msg}`);
357
+ });
358
+ });
359
+ });
360
+ });
361
+ actionsGrid.appendChild(card);
362
+ }
363
+ // ── Message subscriptions ─────────────────────────────────────────────────
364
+ const subSection = document.createElement("div");
365
+ el.appendChild(subSection);
366
+ const subTitle = document.createElement("div");
367
+ subTitle.className = "op-msg-section-title";
368
+ subTitle.textContent = "Active Message Subscriptions";
369
+ subSection.appendChild(subTitle);
370
+ const { el: subTableEl, setRows: setSubRows } = createFilterTable({
371
+ columns: [
372
+ {
373
+ label: "Message Name",
374
+ render: (row) => row.messageName ?? "—",
375
+ sortValue: (row) => row.messageName ?? "",
376
+ },
377
+ {
378
+ label: "Process",
379
+ width: "160px",
380
+ render: (row) => row.processDefinitionId ?? "—",
381
+ sortValue: (row) => row.processDefinitionId ?? "",
382
+ },
383
+ {
384
+ label: "Correlation Key",
385
+ width: "160px",
386
+ render: (row) => row.correlationKey ?? "—",
387
+ sortValue: (row) => row.correlationKey ?? "",
388
+ },
389
+ {
390
+ label: "State",
391
+ width: "100px",
392
+ render: (row) => badge(row.messageSubscriptionState ?? "UNKNOWN"),
393
+ sortValue: (row) => row.messageSubscriptionState ?? "",
394
+ },
395
+ {
396
+ label: "Updated",
397
+ width: "90px",
398
+ render: (row) => relTime(row.lastUpdatedDate),
399
+ sortValue: (row) => row.lastUpdatedDate ?? "",
400
+ },
401
+ ],
402
+ searchFn: (row) => [row.messageName, row.processDefinitionId, row.correlationKey, row.messageSubscriptionState]
403
+ .filter(Boolean)
404
+ .join(" "),
405
+ onRowClick: (sub) => showSubDetailModal(el, sub),
406
+ emptyText: "No active message subscriptions",
407
+ });
408
+ subSection.appendChild(subTableEl);
409
+ function loadSubscriptions() {
410
+ if (cfg.mock) {
411
+ setSubRows(MOCK_MESSAGE_SUBSCRIPTIONS);
412
+ return;
413
+ }
414
+ const headers = { "Content-Type": "application/json" };
415
+ if (cfg.profile)
416
+ headers["x-profile"] = cfg.profile;
417
+ fetch(`${cfg.proxyUrl}/api/message-subscriptions/search`, {
418
+ method: "POST",
419
+ headers,
420
+ body: JSON.stringify({ filter: { messageSubscriptionState: "CREATED" } }),
421
+ })
422
+ .then((r) => r.json())
423
+ .then((result) => {
424
+ setSubRows(result.items ?? []);
425
+ })
426
+ .catch(() => setSubRows([]));
427
+ }
428
+ loadSubscriptions();
429
+ return { el, destroy() { } };
430
+ }
431
+ //# sourceMappingURL=messages.js.map
@@ -0,0 +1,10 @@
1
+ export interface NavItem {
2
+ id: string;
3
+ label: string;
4
+ icon: string;
5
+ }
6
+ export declare function createNav(onNavigate: (path: string) => void): {
7
+ el: HTMLElement;
8
+ setActive(path: string): void;
9
+ };
10
+ //# sourceMappingURL=nav.d.ts.map
@@ -0,0 +1,60 @@
1
+ import { IC_UI } from "@bpmnkit/ui";
2
+ const NAV_ITEMS = [
3
+ { id: "/", label: "Dashboard", icon: IC_UI.dashboard },
4
+ { id: "/definitions", label: "Processes", icon: IC_UI.processes },
5
+ { id: "/decisions", label: "Decisions", icon: IC_UI.decisions },
6
+ { id: "/instances", label: "Instances", icon: IC_UI.instances },
7
+ { id: "/incidents", label: "Incidents", icon: IC_UI.incidents },
8
+ { id: "/jobs", label: "Jobs", icon: IC_UI.jobs },
9
+ { id: "/tasks", label: "Tasks", icon: IC_UI.tasks },
10
+ { id: "/messages", label: "Messages", icon: IC_UI.messages },
11
+ ];
12
+ export function createNav(onNavigate) {
13
+ const el = document.createElement("nav");
14
+ el.className = "op-nav";
15
+ const logo = document.createElement("div");
16
+ logo.className = "op-nav-logo";
17
+ logo.innerHTML = `<svg width="20" height="20" viewBox="0 0 100 100" aria-hidden="true">
18
+ <polygon points="50,8 92,50 50,92 8,50" fill="currentColor"/>
19
+ <line x1="50" y1="28" x2="50" y2="72" stroke="var(--bpmnkit-nav-bg)" stroke-width="12" stroke-linecap="round"/>
20
+ <line x1="28" y1="50" x2="72" y2="50" stroke="var(--bpmnkit-nav-bg)" stroke-width="12" stroke-linecap="round"/>
21
+ </svg>
22
+ <span>Operate</span>`;
23
+ el.appendChild(logo);
24
+ const list = document.createElement("ul");
25
+ list.className = "op-nav-list";
26
+ const itemEls = new Map();
27
+ for (const item of NAV_ITEMS) {
28
+ const li = document.createElement("li");
29
+ const btn = document.createElement("button");
30
+ btn.className = "op-nav-item";
31
+ btn.dataset.path = item.id;
32
+ const iconSpan = document.createElement("span");
33
+ iconSpan.className = "op-nav-icon";
34
+ iconSpan.innerHTML = item.icon;
35
+ const labelSpan = document.createElement("span");
36
+ labelSpan.className = "op-nav-label";
37
+ labelSpan.textContent = item.label;
38
+ btn.appendChild(iconSpan);
39
+ btn.appendChild(labelSpan);
40
+ btn.addEventListener("click", () => onNavigate(item.id));
41
+ li.appendChild(btn);
42
+ list.appendChild(li);
43
+ itemEls.set(item.id, btn);
44
+ }
45
+ el.appendChild(list);
46
+ function setActive(path) {
47
+ // Normalize: strip trailing detail segments for highlighting
48
+ const base = path === "/" ? "/" : `/${path.split("/")[1] ?? ""}`;
49
+ for (const [id, btn] of itemEls) {
50
+ if (id === base) {
51
+ btn.classList.add("op-nav-item--active");
52
+ }
53
+ else {
54
+ btn.classList.remove("op-nav-item--active");
55
+ }
56
+ }
57
+ }
58
+ return { el, setActive };
59
+ }
60
+ //# sourceMappingURL=nav.js.map
@@ -0,0 +1,13 @@
1
+ import type { TasksStore } from "../stores/tasks.js";
2
+ interface Config {
3
+ proxyUrl: string;
4
+ profile: string | null;
5
+ mock: boolean;
6
+ theme: "light" | "dark";
7
+ }
8
+ export declare function createTaskDetailView(taskKey: string, store: TasksStore, cfg: Config, onBack: () => void): {
9
+ el: HTMLElement;
10
+ destroy(): void;
11
+ };
12
+ export {};
13
+ //# sourceMappingURL=task-detail.d.ts.map