@nestos/kanban 0.5.1 → 0.5.2
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/LICENSE +674 -0
- package/README.md +73 -29
- package/dist/{activity-C6xDM-cg.d.cts → activity-BbC4sgKL.d.cts} +28 -2
- package/dist/{activity-Dw8DOw0L.d.ts → activity-Czlan5xW.d.ts} +28 -2
- package/dist/activity-module-DaO1Rry0.d.cts +22 -0
- package/dist/activity-module-T22wliZu.d.ts +22 -0
- package/dist/activity-ports-Dqxa86zT.d.cts +12 -0
- package/dist/activity-ports-cxfrelaL.d.ts +12 -0
- package/dist/activity.cjs +10 -282
- package/dist/activity.cjs.map +1 -1
- package/dist/activity.d.cts +8 -30
- package/dist/activity.d.ts +8 -30
- package/dist/activity.js +9 -281
- package/dist/activity.js.map +1 -1
- package/dist/{chunk-O4OGAAV4.js → chunk-3JYLJPE5.js} +29 -5
- package/dist/chunk-3JYLJPE5.js.map +1 -0
- package/dist/{chunk-ATUFFNLV.js → chunk-3LEIHB7Y.js} +5 -5
- package/dist/chunk-4XF6LQSU.cjs.map +1 -1
- package/dist/chunk-5Q7WB63A.cjs +282 -0
- package/dist/chunk-5Q7WB63A.cjs.map +1 -0
- package/dist/{chunk-PSKQAFDF.cjs → chunk-7KDOTBRX.cjs} +1 -1
- package/dist/chunk-7KDOTBRX.cjs.map +1 -0
- package/dist/{chunk-5DLZWW5Y.js → chunk-AHHEGTUA.js} +3 -3
- package/dist/chunk-AOHQCX7K.cjs +95 -0
- package/dist/chunk-AOHQCX7K.cjs.map +1 -0
- package/dist/{chunk-IUI5CI2S.cjs → chunk-DINLR6E6.cjs} +96 -92
- package/dist/chunk-DINLR6E6.cjs.map +1 -0
- package/dist/{chunk-L44TM4EE.cjs → chunk-EYTVC2H5.cjs} +568 -454
- package/dist/chunk-EYTVC2H5.cjs.map +1 -0
- package/dist/chunk-FEE2YBZ7.js +1972 -0
- package/dist/chunk-FEE2YBZ7.js.map +1 -0
- package/dist/chunk-FNO5K3A7.js +282 -0
- package/dist/chunk-FNO5K3A7.js.map +1 -0
- package/dist/chunk-IHHDXZPZ.js +382 -0
- package/dist/chunk-IHHDXZPZ.js.map +1 -0
- package/dist/chunk-J3EAIVA3.js +280 -0
- package/dist/chunk-J3EAIVA3.js.map +1 -0
- package/dist/{chunk-DFTOTBGF.js → chunk-KH3WF3K4.js} +20 -16
- package/dist/chunk-KH3WF3K4.js.map +1 -0
- package/dist/{chunk-TB2RZGDV.js → chunk-M35X5PHO.js} +14 -1
- package/dist/chunk-M35X5PHO.js.map +1 -0
- package/dist/chunk-QRGZD2JU.cjs +1972 -0
- package/dist/chunk-QRGZD2JU.cjs.map +1 -0
- package/dist/{chunk-4KF7KUAI.cjs → chunk-RBOER6EW.cjs} +6 -6
- package/dist/chunk-RBOER6EW.cjs.map +1 -0
- package/dist/{chunk-6MN3H3YF.cjs → chunk-RSH6QSEC.cjs} +16 -3
- package/dist/chunk-RSH6QSEC.cjs.map +1 -0
- package/dist/{chunk-T7P5EIC4.cjs → chunk-VMRDXOLX.cjs} +33 -33
- package/dist/chunk-VMRDXOLX.cjs.map +1 -0
- package/dist/{chunk-5XKOCKY2.js → chunk-X4UHZX6F.js} +1 -1
- package/dist/chunk-XBSGUVCY.cjs +382 -0
- package/dist/chunk-XBSGUVCY.cjs.map +1 -0
- package/dist/{chunk-OHQTKGQN.js → chunk-XKDZHAUE.js} +242 -128
- package/dist/chunk-XKDZHAUE.js.map +1 -0
- package/dist/chunk-ZUZGAO6G.cjs +280 -0
- package/dist/chunk-ZUZGAO6G.cjs.map +1 -0
- package/dist/{content-CAIp1njn.d.cts → content-C5aJZFlw.d.cts} +1 -1
- package/dist/{content-CGMJdyH_.d.ts → content-hLH5BNud.d.ts} +1 -1
- package/dist/contracts/index.cjs +13 -3
- package/dist/contracts/index.cjs.map +1 -1
- package/dist/contracts/index.d.cts +5 -4
- package/dist/contracts/index.d.ts +5 -4
- package/dist/contracts/index.js +14 -4
- package/dist/{discovery-DxpirOz3.d.cts → discovery-9E-LfwIw.d.cts} +1 -1
- package/dist/{discovery-gSqWpuRm.d.ts → discovery-D60yrjej.d.ts} +1 -1
- package/dist/discovery.cjs +63 -65
- package/dist/discovery.cjs.map +1 -1
- package/dist/discovery.d.cts +4 -4
- package/dist/discovery.d.ts +4 -4
- package/dist/discovery.js +5 -7
- package/dist/discovery.js.map +1 -1
- package/dist/execution-bridge-fpCnH6z5.d.cts +52 -0
- package/dist/execution-bridge-rk0uVy_n.d.ts +52 -0
- package/dist/execution.cjs +6 -356
- package/dist/execution.cjs.map +1 -1
- package/dist/execution.d.cts +4 -51
- package/dist/execution.d.ts +4 -51
- package/dist/execution.js +9 -359
- package/dist/execution.js.map +1 -1
- package/dist/index.cjs +10 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -16
- package/dist/index.d.ts +9 -16
- package/dist/index.js +10 -12
- package/dist/index.js.map +1 -1
- package/dist/{module-CWNK2BMj.d.ts → module-CYfE7YhM.d.ts} +2 -2
- package/dist/{module-BbvwdCDF.d.cts → module-Ca9L3qCn.d.cts} +2 -2
- package/dist/{planning-CcFZYdIL.d.cts → planning-CHrOqQ6b.d.cts} +45 -10
- package/dist/{planning-CcFZYdIL.d.ts → planning-CHrOqQ6b.d.ts} +45 -10
- package/dist/{ports-Bn6ro2FB.d.ts → ports-B0McVg7B.d.ts} +4 -3
- package/dist/ports-BeGO1VRI.d.cts +49 -0
- package/dist/{ports-CaL6geqR.d.cts → ports-GQy0x-RI.d.cts} +4 -3
- package/dist/ports-ykGiNUSx.d.ts +49 -0
- package/dist/runtime/index.cjs +205 -0
- package/dist/runtime/index.cjs.map +1 -0
- package/dist/runtime/index.d.cts +75 -0
- package/dist/runtime/index.d.ts +75 -0
- package/dist/runtime/index.js +205 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/integration.cjs +423 -0
- package/dist/runtime/integration.cjs.map +1 -0
- package/dist/runtime/integration.d.cts +658 -0
- package/dist/runtime/integration.d.ts +658 -0
- package/dist/runtime/integration.js +423 -0
- package/dist/runtime/integration.js.map +1 -0
- package/dist/storage.cjs +9 -277
- package/dist/storage.cjs.map +1 -1
- package/dist/storage.d.cts +6 -6
- package/dist/storage.d.ts +6 -6
- package/dist/storage.js +11 -279
- package/dist/storage.js.map +1 -1
- package/dist/{store-q63eSMoT.d.cts → store-DPwHzGiz.d.cts} +2 -2
- package/dist/{store-Ct0gOAAg.d.ts → store-DgdrPCV9.d.ts} +2 -2
- package/dist/task-projection-CSorlMws.d.ts +11 -0
- package/dist/task-projection-DKKB_ueb.d.cts +11 -0
- package/examples/standalone.ts +22 -0
- package/package.json +117 -87
- package/dist/chunk-2YFPV5GF.cjs +0 -16
- package/dist/chunk-2YFPV5GF.cjs.map +0 -1
- package/dist/chunk-4KF7KUAI.cjs.map +0 -1
- package/dist/chunk-6MN3H3YF.cjs.map +0 -1
- package/dist/chunk-DFTOTBGF.js.map +0 -1
- package/dist/chunk-G6FCDLDF.js +0 -16
- package/dist/chunk-G6FCDLDF.js.map +0 -1
- package/dist/chunk-IUI5CI2S.cjs.map +0 -1
- package/dist/chunk-KYNYPKKH.cjs +0 -71
- package/dist/chunk-KYNYPKKH.cjs.map +0 -1
- package/dist/chunk-L44TM4EE.cjs.map +0 -1
- package/dist/chunk-LSE6JG5I.cjs +0 -20
- package/dist/chunk-LSE6JG5I.cjs.map +0 -1
- package/dist/chunk-O4OGAAV4.js.map +0 -1
- package/dist/chunk-OHQTKGQN.js.map +0 -1
- package/dist/chunk-PSKQAFDF.cjs.map +0 -1
- package/dist/chunk-QTMTBEBA.js +0 -20
- package/dist/chunk-QTMTBEBA.js.map +0 -1
- package/dist/chunk-T7P5EIC4.cjs.map +0 -1
- package/dist/chunk-TB2RZGDV.js.map +0 -1
- package/dist/ui/index.cjs +0 -1961
- package/dist/ui/index.cjs.map +0 -1
- package/dist/ui/index.d.cts +0 -209
- package/dist/ui/index.d.ts +0 -209
- package/dist/ui/index.js +0 -1961
- package/dist/ui/index.js.map +0 -1
- package/dist/ui/kanban.css +0 -194
- /package/dist/{chunk-ATUFFNLV.js.map → chunk-3LEIHB7Y.js.map} +0 -0
- /package/dist/{chunk-5DLZWW5Y.js.map → chunk-AHHEGTUA.js.map} +0 -0
- /package/dist/{chunk-5XKOCKY2.js.map → chunk-X4UHZX6F.js.map} +0 -0
package/dist/ui/index.cjs
DELETED
|
@@ -1,1961 +0,0 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } async function _asyncNullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return await rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4;
|
|
2
|
-
|
|
3
|
-
var _chunkKYNYPKKHcjs = require('../chunk-KYNYPKKH.cjs');
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
var _chunkPSKQAFDFcjs = require('../chunk-PSKQAFDF.cjs');
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
var _chunk6MN3H3YFcjs = require('../chunk-6MN3H3YF.cjs');
|
|
12
|
-
require('../chunk-LSE6JG5I.cjs');
|
|
13
|
-
|
|
14
|
-
// src/ui/html.ts
|
|
15
|
-
function escapeHTML(value2) {
|
|
16
|
-
return String(_nullishCoalesce(value2, () => ( ""))).replace(/[&<>"']/g, (character) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[character]);
|
|
17
|
-
}
|
|
18
|
-
var escapeAttr = escapeHTML;
|
|
19
|
-
|
|
20
|
-
// src/ui/task-state.ts
|
|
21
|
-
function taskStatus(ui, task) {
|
|
22
|
-
if (!task) return "";
|
|
23
|
-
return `<span class="kanban__task-state" data-task-phase="${escapeAttr(task.phase)}">${escapeHTML(ui.text("taskPhase." + task.phase))}${task.reason ? `<small>${escapeHTML(taskReason(ui, task.reason))}</small>` : ""}${task.phase === "waiting-start" && task.reason !== "MANUAL_START_REQUIRED" && task.startAt !== void 0 ? `<time data-task-start-at="${task.startAt}" datetime="${new Date(task.startAt).toISOString()}">${escapeHTML(startTimeText(ui, task.startAt))}</time>` : ""}</span>`;
|
|
24
|
-
}
|
|
25
|
-
function taskControls(ui, task, fixAvailable = false) {
|
|
26
|
-
return task.actions.filter((action) => ["run", "pause", "resume", "edit", "cancel"].includes(action) || action === "fix" && fixAvailable).map((action) => {
|
|
27
|
-
const label = ui.text("taskAction." + action), icon = action === "cancel" ? ui.icons.close : ui.icons[action];
|
|
28
|
-
return `<button type="button" data-action="task-${action}" title="${escapeAttr(label)}" aria-label="${escapeAttr(label)}">${_nullishCoalesce(icon, () => ( escapeHTML(label)))}</button>`;
|
|
29
|
-
}).join("");
|
|
30
|
-
}
|
|
31
|
-
function phaseFilter(ui, selected) {
|
|
32
|
-
const phases = ["waiting-start", "analyzing", "queued", "waiting-dependency", "preparing", "running", "pausing", "paused", "resuming", "waiting-input", "error", "review", "completed", "cancelled", "unknown"];
|
|
33
|
-
return `<label>${escapeHTML(ui.text("taskState"))}<select name="phase"><option value="">${escapeHTML(ui.text("all"))}</option>${phases.map((phase) => `<option value="${phase}" ${phase === selected ? "selected" : ""}>${escapeHTML(ui.text("taskPhase." + phase))}</option>`).join("")}</select></label>`;
|
|
34
|
-
}
|
|
35
|
-
function startTimeText(ui, startAt) {
|
|
36
|
-
return ui.text("taskStartAt") + " " + new Date(startAt).toLocaleString() + " \xB7 " + Math.max(0, Math.ceil((startAt - Date.now()) / 1e3)) + "s";
|
|
37
|
-
}
|
|
38
|
-
function updateTaskCountdowns(editor, ui) {
|
|
39
|
-
for (const node of editor.querySelectorAll("[data-task-start-at]")) {
|
|
40
|
-
const at = Number(node.dataset.taskStartAt);
|
|
41
|
-
if (Number.isFinite(at)) node.textContent = startTimeText(ui, at);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
function taskReason(ui, reason) {
|
|
45
|
-
const key = "taskReason." + reason, value2 = ui.text(key);
|
|
46
|
-
return value2 === key || value2 === "kanban." + key ? reason : value2;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// src/ui/session-links.ts
|
|
50
|
-
function sessionLink(ui, id, label = id, url) {
|
|
51
|
-
if (!url) return `<button type="button" data-session="${escapeAttr(id)}">${escapeHTML(label)}</button>`;
|
|
52
|
-
return linkPair(ui, url, label, id);
|
|
53
|
-
}
|
|
54
|
-
function linkPair(ui, href, label, sessionId) {
|
|
55
|
-
return `<span class="kanban__session-links"><a href="${escapeAttr(href)}"${sessionId ? ` data-session="${escapeAttr(sessionId)}" title="${escapeAttr(ui.text("openSessionInTab"))}"` : ""}>${escapeHTML(label)}</a></span>`;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// src/ui/references.ts
|
|
59
|
-
function referenceMenu(ui, board, entity, actions = "") {
|
|
60
|
-
const reference = _chunkPSKQAFDFcjs.kanbanReference.call(void 0, board, entity);
|
|
61
|
-
const path = `/board/${encodeURIComponent(board.id)}${entity ? entity.kind ? "/@record/" + encodeURIComponent(entity.id) : "/" + encodeURIComponent(entity.id) : ""}`;
|
|
62
|
-
return `<details class="kanban__menu" data-popover><summary aria-label="${escapeAttr(ui.text("referenceActions"))}" title="${escapeAttr(ui.text("referenceActions"))}">${ui.icons.more}</summary>
|
|
63
|
-
<div class="kanban__menu-content"><code class="kanban__menu-reference">${escapeHTML(reference)}</code>${actions}<button type="button" data-action="copy-reference" data-copy="${escapeAttr(reference)}">${escapeHTML(ui.text("copyReference"))}</button>
|
|
64
|
-
<button type="button" data-action="copy-link" data-copy="${escapeAttr(path)}">${escapeHTML(ui.text("copyLink"))}</button></div></details>`;
|
|
65
|
-
}
|
|
66
|
-
async function copyReference(ui, button2) {
|
|
67
|
-
const value2 = _nullishCoalesce(button2.dataset.copy, () => ( ""));
|
|
68
|
-
const text = button2.dataset.action === "copy-link" ? _nullishCoalesce(_optionalChain([ui, 'access', _ => _.referenceUrl, 'optionalCall', _2 => _2(value2)]), () => ( value2)) : value2;
|
|
69
|
-
try {
|
|
70
|
-
await navigator.clipboard.writeText(text);
|
|
71
|
-
if (button2.dataset.action === "copy-resource") {
|
|
72
|
-
button2.title = ui.text("copied");
|
|
73
|
-
button2.setAttribute("aria-label", ui.text("copied"));
|
|
74
|
-
} else button2.textContent = ui.text("copied");
|
|
75
|
-
} catch (e) {
|
|
76
|
-
throw Object.assign(new Error(ui.text("copyFailed")), { code: "COPY_FAILED" });
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// src/ui/suggestion-field.ts
|
|
81
|
-
function suggestionField(options) {
|
|
82
|
-
return `<div class="kanban__suggest" data-kanban-suggest="${escapeAttr(JSON.stringify(options))}"></div>`;
|
|
83
|
-
}
|
|
84
|
-
function selectedItems(board, ids) {
|
|
85
|
-
return ids.map((id) => ({ id, label: _nullishCoalesce(_optionalChain([board, 'access', _3 => _3.items, 'access', _4 => _4.find, 'call', _5 => _5((item) => item.id === id), 'optionalAccess', _6 => _6.title]), () => ( id)) }));
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// src/ui/session-view.ts
|
|
89
|
-
function executionBadge(ui, session, sessionUrl) {
|
|
90
|
-
if (!session) return "";
|
|
91
|
-
const resource = _nullishCoalesce(session.resourceId, () => ( session.sessionId));
|
|
92
|
-
return `<span class="kanban__execution" data-execution-state="${escapeAttr(session.state)}" data-stale="${session.stale}"><span>${sessionUrl ? sessionLink(ui, resource, ui.text("executionSession"), sessionUrl(resource)) : escapeHTML(ui.text("executionSession"))} \xB7 ${escapeHTML(ui.text("sessionState." + session.state))}${session.stale ? " \xB7 " + escapeHTML(ui.text("activityStale")) : ""}</span><small>${escapeHTML(activityTime(ui, session))}</small></span>`;
|
|
93
|
-
}
|
|
94
|
-
function activityTime(ui, session) {
|
|
95
|
-
if (session.lastActivityAt === void 0) return ui.text("activityUnknown");
|
|
96
|
-
const minutes = Math.max(0, Math.floor((Date.now() - session.lastActivityAt) / 6e4));
|
|
97
|
-
return ui.text("lastActivity") + " \xB7 " + (minutes < 1 ? ui.text("justNow") : minutes < 60 ? ui.text("minutesAgo").replace("{count}", String(minutes)) : new Date(session.lastActivityAt).toLocaleString());
|
|
98
|
-
}
|
|
99
|
-
function executionSessionView(ui, detail, editable, sessionUrl) {
|
|
100
|
-
const session = detail.current, resource = _nullishCoalesce(_optionalChain([session, 'optionalAccess', _7 => _7.resourceId]), () => ( _optionalChain([session, 'optionalAccess', _8 => _8.sessionId])));
|
|
101
|
-
return `<section class="kanban__execution-detail"><h4>${escapeHTML(ui.text("executionSession"))}</h4><p>${escapeHTML(ui.text("executionSessionHelp"))}</p>
|
|
102
|
-
${detail.continuation ? `<button type="button" data-action="continue-execution" data-dispatch="${escapeAttr(detail.continuation.previousDispatchId)}">${escapeHTML(ui.text("continueExecution"))}</button>` : ""}
|
|
103
|
-
${session ? `${executionBadge(ui, session)}${sessionLink(ui, resource, _nullishCoalesce(session.title, () => ( session.sessionId)), _optionalChain([sessionUrl, 'optionalCall', _9 => _9(resource)]))}<small>${escapeHTML(session.sessionId)}</small>${session.observedAt ? `<small>${escapeHTML(ui.text("observedAt"))} \xB7 ${escapeHTML(new Date(session.observedAt).toLocaleString())}</small>` : ""}${session.code ? `<p>${escapeHTML(ui.text("activityReadFailed"))} (${escapeHTML(session.code)})</p>` : ""}` : `<p>${escapeHTML(ui.text("noExecutionSession"))}</p>`}
|
|
104
|
-
${editable ? `<details><summary>${escapeHTML(ui.text(session ? "changeExecutionSession" : "bindExecutionSession"))}</summary><form data-form="execution-session">${suggestionField({ name: "executionSession", label: "executionSession", kind: "session", manual: true, required: true })}<button>${escapeHTML(ui.text("bindExecutionSession"))}</button><p data-execution-error role="alert" hidden></p></form></details>` : ""}
|
|
105
|
-
</section>`;
|
|
106
|
-
}
|
|
107
|
-
function relatedSessionsView(ui, detail, sessionUrl) {
|
|
108
|
-
const sessions = _nullishCoalesce(detail.sessions, () => ( legacySessions(detail)));
|
|
109
|
-
return `${detail.sessionsCode ? `<p role="alert">${escapeHTML(ui.text("sessionRelationsIncomplete"))} (${escapeHTML(detail.sessionsCode)})</p>` : ""}
|
|
110
|
-
${sessions.length ? `<ul class="kanban__session-list">${sessions.map((session) => relatedSession(ui, session, sessionUrl)).join("")}</ul>` : `<p>${escapeHTML(ui.text("noRelatedSessions"))}</p>`}`;
|
|
111
|
-
}
|
|
112
|
-
function relatedSession(ui, session, sessionUrl) {
|
|
113
|
-
const resource = _nullishCoalesce(session.resourceId, () => ( session.sessionId)), title = _nullishCoalesce(session.title, () => ( session.sessionId));
|
|
114
|
-
return `<li class="kanban__related-session" data-related-session="${escapeAttr(session.sessionId)}"><div class="kanban__session-heading" title="${escapeAttr(title)}">${sessionLink(ui, resource, title, _optionalChain([sessionUrl, 'optionalCall', _10 => _10(resource)]))}</div>
|
|
115
|
-
<small>${escapeHTML(session.sessionId)}</small>${session.createdAt !== void 0 ? `<small>${escapeHTML(ui.text("sessionCreatedAt"))} \xB7 ${escapeHTML(date(session.createdAt))}</small>` : ""}<p>${session.current ? `<strong>${escapeHTML(ui.text("currentExecution"))}</strong> \xB7 ` : ""}${session.purposes.map((purpose) => escapeHTML(ui.text("sessionPurpose." + purpose))).join(" \xB7 ")} \xB7 ${escapeHTML(ui.text("sessionState." + session.state))}${session.stale ? " \xB7 " + escapeHTML(ui.text("activityStale")) : ""}</p>
|
|
116
|
-
${session.code ? `<p role="alert">${escapeHTML(ui.text("activityReadFailed"))} (${escapeHTML(session.code)})</p>` : ""}
|
|
117
|
-
${session.executions.length ? `<details><summary>${escapeHTML(ui.text("sessionExecutions"))} (${session.executions.length})</summary><ol>${session.executions.map((run) => executionView(ui, run)).join("")}</ol></details>` : ""}</li>`;
|
|
118
|
-
}
|
|
119
|
-
function executionView(ui, run) {
|
|
120
|
-
const label = run.previousDispatchId ? ui.text("sessionContinuation") : ui.text("sessionPurpose." + run.purpose);
|
|
121
|
-
const showState = run.state && run.state !== run.outcome && !(run.state === "completed" && ["succeeded", "accepted", "rejected"].includes(_nullishCoalesce(run.outcome, () => ( ""))));
|
|
122
|
-
const fields = [
|
|
123
|
-
[ui.text("sessionExecutionId"), run.id],
|
|
124
|
-
[ui.text("sessionRoundId"), run.roundId],
|
|
125
|
-
[ui.text("sessionTurnId"), run.turnId],
|
|
126
|
-
[ui.text("sessionPreviousExecution"), run.previousDispatchId],
|
|
127
|
-
[ui.text(run.roundId ? "sessionExecutionStarted" : "sessionExecutionPrepared"), date(run.createdAt)],
|
|
128
|
-
[ui.text("sessionExecutionEnded"), date(run.completedAt)],
|
|
129
|
-
..._nullishCoalesce(_optionalChain([run, 'access', _11 => _11.resources, 'optionalAccess', _12 => _12.map, 'call', _13 => _13((resource) => [resource.label, resource.value])]), () => ( []))
|
|
130
|
-
];
|
|
131
|
-
return `<li class="kanban__session-run"><p>${escapeHTML(label)}${run.attempt ? " \xB7 #" + run.attempt : ""}${run.outcome ? " \xB7 " + escapeHTML(ui.text("sessionRunOutcome." + run.outcome)) : ""}${showState ? " \xB7 " + escapeHTML(ui.text("sessionState." + run.state)) : ""}</p>
|
|
132
|
-
<dl>${fields.filter((field2) => field2[1] !== void 0).map(([key, value2]) => `<dt>${escapeHTML(key)}</dt><dd>${escapeHTML(value2)}</dd>`).join("")}</dl>${run.code ? `<p role="alert">${escapeHTML(run.code)}</p>` : ""}</li>`;
|
|
133
|
-
}
|
|
134
|
-
function date(value2) {
|
|
135
|
-
return value2 === void 0 ? void 0 : new Date(value2).toLocaleString();
|
|
136
|
-
}
|
|
137
|
-
function legacySessions(detail) {
|
|
138
|
-
return [...new Map(detail.history.map((row) => [row.sessionId, row])).values()].map((row) => ({
|
|
139
|
-
..._optionalChain([detail, 'access', _14 => _14.current, 'optionalAccess', _15 => _15.sessionId]) === row.sessionId ? detail.current : { sessionId: row.sessionId, state: "unknown", stale: true, recent: false },
|
|
140
|
-
current: _optionalChain([detail, 'access', _16 => _16.current, 'optionalAccess', _17 => _17.sessionId]) === row.sessionId,
|
|
141
|
-
purposes: ["execution"],
|
|
142
|
-
executions: []
|
|
143
|
-
}));
|
|
144
|
-
}
|
|
145
|
-
function executionFilter(ui, value2 = "all") {
|
|
146
|
-
return `<select name="execution" aria-label="${escapeAttr(ui.text("executionFilter"))}">${["all", "running", "recent", "active"].map((filter) => `<option value="${filter}" ${filter === value2 ? "selected" : ""}>${escapeHTML(ui.text("executionFilter." + filter))}</option>`).join("")}</select>`;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// src/ui/view.ts
|
|
150
|
-
var states = ["proposed", "backlog", "open", "claimed", "review", "completed", "cancelled"];
|
|
151
|
-
var button = (ui, action, key, primary = false) => `<button type="button"${primary ? ' class="kanban__primary"' : ""} data-action="${escapeAttr(action)}">${escapeHTML(ui.text(key))}</button>`;
|
|
152
|
-
function contextTabs(ui, active = "board") {
|
|
153
|
-
return `<nav class="kanban__context-tabs" aria-label="${escapeAttr(ui.text("recordContext"))}">${[["board", "tabBoard"], ["log", "tabLog"], ["decision", "tabDecision"]].map(([value2, key]) => `<button type="button" data-context="${value2}" ${active === value2 ? 'aria-current="page"' : ""}>${escapeHTML(ui.text(key))}</button>`).join("")}</nav>`;
|
|
154
|
-
}
|
|
155
|
-
function field(ui, name, key, value2 = "", required = true, type = "text") {
|
|
156
|
-
return `<label>${escapeHTML(ui.text(key))}<input name="${name}" type="${type}" value="${escapeAttr(value2)}" ${required ? "required" : ""}></label>`;
|
|
157
|
-
}
|
|
158
|
-
function textarea(ui, name, key, value2 = "") {
|
|
159
|
-
return `<label>${escapeHTML(ui.text(key))}<textarea name="${name}" required>${escapeHTML(value2)}</textarea></label>`;
|
|
160
|
-
}
|
|
161
|
-
function owns(item, actor) {
|
|
162
|
-
return !!actor && !!item.owner && (_nullishCoalesce(item.owner.kind, () => ( "agent"))) === actor.kind && (_nullishCoalesce(item.owner.id, () => ( item.owner.agentId))) === actor.id;
|
|
163
|
-
}
|
|
164
|
-
function navigation(ui, boards, selected) {
|
|
165
|
-
return `<header class="kanban__sidebar-header"><h2>${escapeHTML(ui.text("title"))}</h2>${button(ui, "new-board", "createShort")}</header>
|
|
166
|
-
<section class="kanban__board-list"><p class="kanban__caption">${escapeHTML(ui.text("scope"))}</p><nav aria-label="${escapeAttr(ui.text("title"))}">${boards.map((board) => `<button type="button" data-board="${escapeAttr(board.id)}" ${board.id === selected ? 'aria-current="page"' : ""}><small>${escapeHTML(_chunkPSKQAFDFcjs.kanbanReference.call(void 0, board))}</small><span>${escapeHTML(board.title)}</span></button>`).join("")}</nav></section>
|
|
167
|
-
<footer class="kanban__sidebar-tools"><details class="kanban__reference-lookup"><summary>${escapeHTML(ui.text("openReference"))}</summary>${referenceLookup(ui)}</details>
|
|
168
|
-
<details class="kanban__scope-note"><summary>${escapeHTML(ui.text("scopeInfo"))}</summary><p>${escapeHTML(ui.text("scopeHelp"))}</p></details></footer>`;
|
|
169
|
-
}
|
|
170
|
-
function referenceLookup(ui) {
|
|
171
|
-
return `<form data-form="reference"><input name="reference" aria-label="${escapeAttr(ui.text("reference"))}" placeholder="${escapeAttr(ui.text("referencePlaceholder"))}" required><button>${escapeHTML(ui.text("openShort"))}</button></form>`;
|
|
172
|
-
}
|
|
173
|
-
function boardHeader(ui, board, active = "board", automation = false) {
|
|
174
|
-
const [action, key] = active === "log" ? ["new-log", "newLog"] : active === "decision" ? ["new-decision", "newDecision"] : ["new-item", "newItem"];
|
|
175
|
-
const actions = `<div class="kanban__mobile-create">${button(ui, action, key)}</div>${button(ui, "refresh", "refresh")}${automation ? button(ui, "automation", "automationTitle") : ""}`;
|
|
176
|
-
return `<header class="kanban__page-header" data-titlebar><span class="kanban__navigation" data-navigation></span><div class="kanban__board-heading"><h2 data-titlebar-title title="${escapeAttr(board.title)}">${escapeHTML(board.title)}</h2></div>
|
|
177
|
-
<div class="kanban__header-actions"><span class="kanban__desktop-create">${button(ui, action, key, true)}</span><span class="kanban__window-navigation" data-window-navigation></span>${referenceMenu(ui, board, void 0, actions)}</div></header>`;
|
|
178
|
-
}
|
|
179
|
-
function catalogView(ui, boards) {
|
|
180
|
-
return `<header class="kanban__page-header" data-titlebar><span class="kanban__navigation" data-navigation></span><div class="kanban__board-heading"><h2 data-titlebar-title>${escapeHTML(ui.text("title"))}</h2></div><span class="kanban__window-navigation" data-window-navigation></span>${button(ui, "new-board", "createShort")}</header>
|
|
181
|
-
<div class="kanban__record-list">${boards.map((board) => `<button type="button" class="kanban__card" data-board="${escapeAttr(board.id)}"><strong>${escapeHTML(board.title)}</strong><small>${escapeHTML(_chunkPSKQAFDFcjs.kanbanReference.call(void 0, board))}</small></button>`).join("") || `<p>${escapeHTML(ui.text("emptyBoards"))}</p>`}</div>`;
|
|
182
|
-
}
|
|
183
|
-
function boardView(ui, board, page, query, activity = false, automation = false, sessionUrl) {
|
|
184
|
-
const columns = query.view === "archive" ? [{ id: "archive", label: ui.text("archive"), states }] : _nullishCoalesce(board.columns, () => ( states.map((state) => ({ id: state, label: ui.text(state), states: [state] }))));
|
|
185
|
-
return `${boardHeader(ui, board, "board", automation)}${contextTabs(ui)}<form data-form="filter" class="kanban__filters"><input name="search" aria-label="${escapeAttr(ui.text("search"))}" placeholder="${escapeAttr(ui.text("search"))}" value="${escapeAttr(_nullishCoalesce(query.search, () => ( "")))}">
|
|
186
|
-
<details class="kanban__filter-more" data-popover><summary>${escapeHTML(ui.text("moreFilters"))}${query.area || query.milestone || query.view !== "all" || query.execution && query.execution !== "all" ? '<span class="kanban__filter-dot" aria-hidden="true"></span>' : ""}</summary><div class="kanban__filter-fields"><label>${escapeHTML(ui.text("filter"))}<select name="view" aria-label="${escapeAttr(ui.text("filter"))}">${["all", "backlog", "ready", "in-progress", "review", "closed", "proposed", "archive"].map((view) => `<option value="${view}" ${view === query.view ? "selected" : ""}>${escapeHTML(ui.text(view === "ready" ? "open" : view === "in-progress" ? "claimed" : view === "closed" ? "completed" : view))}</option>`).join("")}</select></label>${phaseFilter(ui, query.phase)}${activity ? executionFilter(ui, query.execution) : ""}${suggestionField({ name: "area", label: "area", kind: "area", free: true, selected: query.area ? [{ id: query.area, label: query.area }] : [] })}
|
|
187
|
-
${suggestionField({ name: "milestone", label: "milestone", kind: "milestone", free: true, selected: query.milestone ? [{ id: query.milestone, label: query.milestone }] : [] })}</div></details><button>${escapeHTML(ui.text("filter"))}</button></form>
|
|
188
|
-
<p class="kanban__count" role="status">${escapeHTML(ui.text("total", { count: page.total }))}</p><div class="kanban__columns" data-has-items="${page.items.length > 0}">${columns.map((column) => {
|
|
189
|
-
const items = page.items.filter((item) => column.states.includes(item.status));
|
|
190
|
-
return `<section class="kanban__column" data-empty="${items.length === 0}"><h3>${escapeHTML(column.label)} <small>${items.length}</small></h3><div class="kanban__column-items" data-column="${escapeAttr(column.id)}" tabindex="0" aria-label="${escapeAttr(column.label + " \xB7 " + ui.text("columnItems"))}">${items.map((item) => itemCard(ui, board, item, sessionUrl)).join("") || `<p>${escapeHTML(ui.text("emptyItems"))}</p>`}</div></section>`;
|
|
191
|
-
}).join("")}</div><footer class="kanban__toolbar"><small>${escapeHTML(ui.text("scrollHint"))}</small>${button(ui, "scroll-left", "previousColumns")}${button(ui, "scroll-right", "nextColumns")}${query.cursor ? button(ui, "first", "first") : ""}${page.nextCursor ? button(ui, "next", "next") : ""}</footer>`;
|
|
192
|
-
}
|
|
193
|
-
function itemCard(ui, board, item, sessionUrl) {
|
|
194
|
-
const content = `<strong>${escapeHTML(item.title)}</strong><small>${escapeHTML(_chunkPSKQAFDFcjs.kanbanReference.call(void 0, board, item))}</small><small>P${item.planning.priority} \xB7 ${escapeHTML(_nullishCoalesce(item.planning.area, () => ( "")))} \xB7 ${escapeHTML(_nullishCoalesce(item.planning.milestone, () => ( "")))}</small>${taskStatus(ui, item.task)}${item.pendingAmendments ? `<small class="kanban__badge">${escapeHTML(ui.text("pendingAmendments"))} (${item.pendingAmendments})</small>` : ""}${item.progress ? `<small>${item.progress.completed}/${item.progress.total}</small>` : ""}`;
|
|
195
|
-
const identity = _optionalChain([item, 'access', _18 => _18.task, 'optionalAccess', _19 => _19.sessionId]) ? `data-session="${escapeAttr(item.task.sessionId)}"` : `data-item="${escapeAttr(item.id)}"`;
|
|
196
|
-
return `<article class="kanban__card"><button type="button" class="kanban__item-open" ${identity}>${content}</button>${_optionalChain([item, 'access', _20 => _20.task, 'optionalAccess', _21 => _21.sessionId]) ? `<button type="button" data-item="${escapeAttr(item.id)}" title="${escapeAttr(ui.text("details"))}" aria-label="${escapeAttr(ui.text("details"))}">${escapeHTML(ui.text("details"))}</button>` : ""}<span data-item-execution="${escapeAttr(item.id)}">${executionBadge(ui, item.execution, sessionUrl)}</span></article>`;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// src/ui/children.ts
|
|
200
|
-
function childType(board, parent) {
|
|
201
|
-
const types = _nullishCoalesce(board.workTypes, () => ( _chunkPSKQAFDFcjs.DEFAULT_KANBAN_WORK_TYPES));
|
|
202
|
-
const rank = _optionalChain([types, 'access', _22 => _22.find, 'call', _23 => _23((type) => type.id === (_nullishCoalesce(_nullishCoalesce(_optionalChain([parent, 'access', _24 => _24.planning, 'optionalAccess', _25 => _25.kind]), () => ( board.defaultWorkType)), () => ( "task")))), 'optionalAccess', _26 => _26.rank]);
|
|
203
|
-
const candidates = types.filter((type) => rank !== void 0 && type.rank > rank);
|
|
204
|
-
return _optionalChain([(_nullishCoalesce(candidates.find((type) => type.id === (_nullishCoalesce(board.defaultWorkType, () => ( "task")))), () => ( candidates.sort((a, b) => a.rank - b.rank)[0]))), 'optionalAccess', _27 => _27.id]);
|
|
205
|
-
}
|
|
206
|
-
function childrenView(ui, page, cursor, canCreate, sessionUrl) {
|
|
207
|
-
return `<h4>${escapeHTML(ui.text("children"))} (${page.total})</h4><div class="kanban__actions">${canCreate ? button(ui, "new-child", "newChild") : ""}</div>
|
|
208
|
-
<div class="kanban__record-list">${page.items.map((item) => `<article class="kanban__card"><button type="button" data-item="${escapeAttr(item.id)}"><strong>${escapeHTML(item.title)}</strong></button>${taskStatus(ui, item.task)}${_optionalChain([item, 'access', _28 => _28.task, 'optionalAccess', _29 => _29.sessionId]) ? sessionLink(ui, item.task.sessionId, ui.text("executionSession"), _optionalChain([sessionUrl, 'optionalCall', _30 => _30(item.task.sessionId)])) : ""}${item.execution ? sessionLink(ui, _nullishCoalesce(item.execution.resourceId, () => ( item.execution.sessionId)), ui.text("executionSession"), _optionalChain([sessionUrl, 'optionalCall', _31 => _31(_nullishCoalesce(item.execution.resourceId, () => ( item.execution.sessionId)))])) : ""}</article>`).join("")}</div>
|
|
209
|
-
<div class="kanban__actions">${cursor ? button(ui, "children-first", "first") : ""}${page.nextCursor ? `<button type="button" data-action="children-next" data-cursor="${escapeAttr(page.nextCursor)}">${escapeHTML(ui.text("next"))}</button>` : ""}</div>`;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// src/ui/panel-header.ts
|
|
213
|
-
function panelHeader(ui, title, board, entity) {
|
|
214
|
-
const label = escapeAttr(ui.text("close"));
|
|
215
|
-
return `<header class="kanban__panel-header" data-titlebar><button type="button" class="kanban__panel-back" data-titlebar-back data-action="close-panel" aria-label="${label}" title="${label}">${_nullishCoalesce(ui.icons.back, () => ( ui.icons.close))}</button>
|
|
216
|
-
<h3 data-titlebar-title title="${escapeAttr(title)}">${escapeHTML(title)}</h3><span class="kanban__window-navigation" data-window-navigation></span>${board ? referenceMenu(ui, board, entity, `<p class="kanban__menu-title">${escapeHTML(title)}</p>`) : ""}</header>`;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// src/ui/context-view.ts
|
|
220
|
-
function recordsView(ui, page, kind, hasPrevious, board) {
|
|
221
|
-
return `${board ? boardHeader(ui, board, kind) : `<header class="kanban__toolbar"><h2>${escapeHTML(ui.text(kind))}</h2></header>`}
|
|
222
|
-
${contextTabs(ui, kind)}<p>${escapeHTML(ui.text("recordHelp"))}</p><div class="kanban__record-list" tabindex="0" aria-label="${escapeAttr(ui.text(kind))}">${recordLinks(ui, page, board)}${!page.total ? `<p>${escapeHTML(ui.text("emptyRecords"))}</p>` : ""}</div>
|
|
223
|
-
<footer class="kanban__toolbar">${hasPrevious ? button(ui, "records-first", "first") : ""}${page.nextCursor ? button(ui, "records-next", "next") : ""}</footer>`;
|
|
224
|
-
}
|
|
225
|
-
function recordLinks(ui, page, board) {
|
|
226
|
-
return page.items.map((record) => `<button type="button" class="kanban__card" data-record="${escapeAttr(record.id)}"><strong>${escapeHTML(record.title)}</strong>${board && !record.activity ? `<small>${escapeHTML(_chunkPSKQAFDFcjs.kanbanReference.call(void 0, board, record))}</small>` : ""}<small>${escapeHTML(ui.text(record.activity ? "automaticLog" : record.kind))} \xB7 ${escapeHTML(ui.text(record.status))} \xB7 ${escapeHTML(new Date(record.createdAt).toLocaleString())}</small></button>`).join("");
|
|
227
|
-
}
|
|
228
|
-
function sourcesView(ui, sources) {
|
|
229
|
-
return sources.length ? `<ul>${sources.map((source) => `<li><button type="button" data-session="${escapeAttr(source.sessionId)}">${escapeHTML(source.sessionId)}</button><small>${escapeHTML(source.messageId)} \xB7 ${escapeHTML(source.revision)} \xB7 ${escapeHTML(source.role)}</small></li>`).join("")}</ul>` : `<p>${escapeHTML(ui.text("noSources"))}</p>`;
|
|
230
|
-
}
|
|
231
|
-
function recordForm(ui, kind, board, itemId = "", resources = []) {
|
|
232
|
-
return `${panelHeader(ui, ui.text(kind === "log" ? "newLog" : "newDecision"))}<form data-form="record">
|
|
233
|
-
<input type="hidden" name="kind" value="${kind}">${field(ui, "title", "name")}${textarea(ui, "content", "content")}${kind === "decision" ? textarea(ui, "rationale", "rationale") + suggestionField({ name: "supersedes", label: "supersedes", kind: "decision" }) : ""}
|
|
234
|
-
${kind === "decision" && resources.length ? `<label>${escapeHTML(ui.text("recordResources"))}<select name="recordResources" multiple>${resources.map((resource) => `<option value="${escapeAttr(JSON.stringify(resource.reference))}">${escapeHTML(resource.label)}</option>`).join("")}</select></label>` : ""}
|
|
235
|
-
${itemChoices(board, itemId)}<details><summary>${escapeHTML(ui.text("sources"))}</summary>${suggestionField({ name: "sourceSession", label: "sourceSession", kind: "session", manual: true })}${field(ui, "sourceMessage", "sourceMessage", "", false)}${field(ui, "sourceRevision", "sourceRevision", "", false)}</details><button>${escapeHTML(ui.text("save"))}</button></form>`;
|
|
236
|
-
}
|
|
237
|
-
function recordDetail(ui, record, board, executions) {
|
|
238
|
-
return `${panelHeader(ui, record.title, board, record)}
|
|
239
|
-
<p>${escapeHTML(ui.text(record.kind))} \xB7 ${escapeHTML(ui.text(record.status))} \xB7 ${escapeHTML(ui.text(record.origin))}</p>${record.activity ? "" : `<small>${escapeHTML(ui.text("recordId"))}: ${escapeHTML(record.id)}</small>`}<p>${escapeHTML(ui.text("author"))}: ${escapeHTML(record.author.id)} \xB7 ${escapeHTML(new Date(record.createdAt).toLocaleString())}</p>
|
|
240
|
-
<section data-reference-links></section><section class="kanban__prose"><h4>${escapeHTML(ui.text("content"))}</h4><p>${escapeHTML(record.content)}</p>${record.rationale ? `<h4>${escapeHTML(ui.text("rationale"))}</h4><p>${escapeHTML(record.rationale)}</p>` : ""}</section>
|
|
241
|
-
${record.status === "draft" ? `<div class="kanban__actions">${button(ui, "confirm-record", "confirmRecord")}${button(ui, "reject-record", "rejectRecord")}</div>` : ""}
|
|
242
|
-
${record.kind === "decision" && record.status === "confirmed" && executions ? recordExecutionView(ui, board, executions) : ""}
|
|
243
|
-
${(_nullishCoalesce(record.externalRefs, () => ( []))).map((ref) => `<p>${escapeHTML(ref.system)}: ${escapeHTML(ref.id)}</p>`).join("")}
|
|
244
|
-
${record.supersedes ? recordLink(ui, record.supersedes, "supersedes") : ""}${record.supersededBy ? recordLink(ui, record.supersededBy, "superseded") : ""}
|
|
245
|
-
<h4>${escapeHTML(ui.text("itemIds"))}</h4>${record.itemIds.map((id) => `<button type="button" data-item="${escapeAttr(id)}">${escapeHTML(_nullishCoalesce(_optionalChain([board, 'access', _32 => _32.items, 'access', _33 => _33.find, 'call', _34 => _34((item) => item.id === id), 'optionalAccess', _35 => _35.title]), () => ( id)))}</button>`).join("")}
|
|
246
|
-
${record.activity ? "" : `<form data-form="record-link">${suggestionField({ name: "itemId", label: "itemIds", kind: "item", required: true })}<button>${escapeHTML(ui.text("linkRecord"))}</button></form>`}<h4>${escapeHTML(ui.text("sources"))}</h4>${sourcesView(ui, record.sources)}`;
|
|
247
|
-
}
|
|
248
|
-
function recordExecutionView(ui, board, executions) {
|
|
249
|
-
const completed = executions.some((run) => run.state === "completed");
|
|
250
|
-
const actions = completed ? `<p>${escapeHTML(ui.text("completedFollowup"))}</p>` : `${button(ui, "run-record", "runRecord")}<details><summary>${escapeHTML(ui.text("referenceActions"))}</summary>${button(ui, "run-record-separate", "runRecordSeparate")}</details>`;
|
|
251
|
-
return `<div class="kanban__actions">${actions}</div>${completed ? "" : `<p>${escapeHTML(ui.text("runRecordHelp"))}</p>`}
|
|
252
|
-
${executions.map((run) => `<p><button type="button" ${run.rootItemId && run.boardId === board.id ? `data-item="${escapeAttr(run.rootItemId)}"` : `data-board="${escapeAttr(run.boardId)}"`}>${escapeHTML(ui.text(run.rootItemId && run.boardId === board.id ? "executionWork" : "executionBoard"))}</button> \xB7 ${escapeHTML(ui.text(run.state))}${run.code ? ` \xB7 ${escapeHTML(run.code)}` : ""}</p>`).join("")}`;
|
|
253
|
-
}
|
|
254
|
-
function recordLink(ui, id, key) {
|
|
255
|
-
return `<p>${escapeHTML(ui.text(key))}: <button type="button" data-record="${escapeAttr(id)}">${escapeHTML(id)}</button></p>`;
|
|
256
|
-
}
|
|
257
|
-
function amendmentsView(ui, item) {
|
|
258
|
-
const pending = _nullishCoalesce(_optionalChain([item, 'access', _36 => _36.amendments, 'optionalAccess', _37 => _37.filter, 'call', _38 => _38((proposal) => proposal.status === "pending")]), () => ( []));
|
|
259
|
-
if (!pending.length) return "";
|
|
260
|
-
return `<section class="kanban__amendments"><h4>${escapeHTML(ui.text("amendments"))}</h4><p>${escapeHTML(ui.text("amendmentHint"))}</p>${pending.map((proposal) => `<article><strong>${escapeHTML(proposal.proposedBy.id)}</strong><small> v${proposal.baseRevision}</small>
|
|
261
|
-
<details><summary>${escapeHTML(ui.text("currentText"))}</summary><p>${escapeHTML(item.title)}</p><p>${escapeHTML(item.responsibility)}</p><p>${escapeHTML(item.acceptance)}</p></details>
|
|
262
|
-
<h5>${escapeHTML(ui.text("proposedText"))}</h5><p>${escapeHTML(proposal.proposed.title)}</p><p>${escapeHTML(proposal.proposed.responsibility)}</p><p>${escapeHTML(proposal.proposed.acceptance)}</p>
|
|
263
|
-
${sourcesView(ui, proposal.sources)}<form data-form="amendment" data-amendment="${escapeAttr(proposal.id)}"><select name="decision" aria-label="${escapeAttr(ui.text("amendments"))}"><option value="accept">${escapeHTML(ui.text("applyAmendment"))}</option><option value="reject">${escapeHTML(ui.text("rejectAmendment"))}</option></select>${field(ui, "reason", "reason", "", false)}<button>${escapeHTML(ui.text("save"))}</button></form></article>`).join("")}</section>`;
|
|
264
|
-
}
|
|
265
|
-
function itemChoices(board, itemId) {
|
|
266
|
-
return suggestionField({ name: "itemIds", label: "itemIds", kind: "item", multiple: true, selected: selectedItems(board, itemId ? [itemId] : []) });
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// src/ui/event-history.ts
|
|
270
|
-
function meaningfulItemEvents(events) {
|
|
271
|
-
const last = /* @__PURE__ */ new Map(), hidden = /* @__PURE__ */ new Set();
|
|
272
|
-
for (const event of [...events].sort((a, b) => a.sequence - b.sequence)) {
|
|
273
|
-
if (event.kind === "renew") {
|
|
274
|
-
hidden.add(event);
|
|
275
|
-
continue;
|
|
276
|
-
}
|
|
277
|
-
if (event.kind !== "observe-execution" || !event.data.dispatchId || !event.data.reason) continue;
|
|
278
|
-
const key = JSON.stringify([event.boardId, event.itemId, event.data.dispatchId]);
|
|
279
|
-
const state = JSON.stringify([event.data.reason, event.data.code, event.data.status]);
|
|
280
|
-
if (last.get(key) === state) hidden.add(event);
|
|
281
|
-
last.set(key, state);
|
|
282
|
-
}
|
|
283
|
-
return events.filter((event) => !hidden.has(event));
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// src/ui/forms.ts
|
|
287
|
-
function newBoardForm(ui) {
|
|
288
|
-
return `${panelHeader(ui, ui.text("newBoard"))}<form data-form="board">${field(ui, "title", "boardName")}
|
|
289
|
-
<label><input name="requireEstimate" type="checkbox">${escapeHTML(ui.text("requireEstimate"))}</label>
|
|
290
|
-
${save(ui)}</form>`;
|
|
291
|
-
}
|
|
292
|
-
function newItemForm(ui, board, parent, resources) {
|
|
293
|
-
const preset = parent ? { kind: childType(board, parent), parentId: parent.id, priority: _nullishCoalesce(_optionalChain([parent, 'access', _39 => _39.planning, 'optionalAccess', _40 => _40.priority]), () => ( 2)), dependencies: [], references: [] } : void 0;
|
|
294
|
-
return `${panelHeader(ui, ui.text("newItem"))}<form data-form="item">${field(ui, "title", "name")}
|
|
295
|
-
${textarea(ui, "responsibility", "responsibility")}${textarea(ui, "acceptance", "acceptance")}${launchModeField(ui)}${planningFields(ui, board, void 0, preset)}${itemResourceField(ui, resources, (_nullishCoalesce(board.workTypes, () => ( _chunkPSKQAFDFcjs.DEFAULT_KANBAN_WORK_TYPES))).some((type) => type.id === (_nullishCoalesce(_nullishCoalesce(_optionalChain([preset, 'optionalAccess', _41 => _41.kind]), () => ( board.defaultWorkType)), () => ( "task"))) && type.executable))}${save(ui)}</form>`;
|
|
296
|
-
}
|
|
297
|
-
function planningFields(ui, board, item, preset) {
|
|
298
|
-
const plan = _nullishCoalesce(preset, () => ( _optionalChain([item, 'optionalAccess', _42 => _42.planning]))), types = _nullishCoalesce(board.workTypes, () => ( _chunkPSKQAFDFcjs.DEFAULT_KANBAN_WORK_TYPES));
|
|
299
|
-
return `<label>${escapeHTML(ui.text("type"))}<select name="kind">${types.map((type) => `<option data-executable="${type.executable}" value="${escapeAttr(type.id)}" ${type.id === (_nullishCoalesce(_nullishCoalesce(_optionalChain([plan, 'optionalAccess', _43 => _43.kind]), () => ( board.defaultWorkType)), () => ( "task"))) ? "selected" : ""}>${escapeHTML(type.label)}</option>`).join("")}</select></label>
|
|
300
|
-
${field(ui, "priority", "priority", String(_nullishCoalesce(_optionalChain([plan, 'optionalAccess', _44 => _44.priority]), () => ( 2))), true, "number")}
|
|
301
|
-
${suggestionField({ name: "area", label: "area", kind: "area", free: true, selected: _optionalChain([plan, 'optionalAccess', _45 => _45.area]) ? [{ id: plan.area, label: plan.area }] : [] })}${suggestionField({ name: "milestone", label: "milestone", kind: "milestone", free: true, selected: _optionalChain([plan, 'optionalAccess', _46 => _46.milestone]) ? [{ id: plan.milestone, label: plan.milestone }] : [] })}
|
|
302
|
-
${suggestionField({ name: "parentId", label: "parent", kind: "parent", excludeItemId: _optionalChain([item, 'optionalAccess', _47 => _47.id]), selected: selectedItems(board, _optionalChain([plan, 'optionalAccess', _48 => _48.parentId]) ? [plan.parentId] : []) })}${suggestionField({ name: "dependencies", label: "dependencies", kind: "dependency", multiple: true, excludeItemId: _optionalChain([item, 'optionalAccess', _49 => _49.id]), selected: selectedItems(board, _nullishCoalesce(_optionalChain([plan, 'optionalAccess', _50 => _50.dependencies]), () => ( []))) })}
|
|
303
|
-
${field(ui, "dueAt", "dueAt", dateInput(_optionalChain([plan, 'optionalAccess', _51 => _51.dueAt])), false, "datetime-local")}`;
|
|
304
|
-
}
|
|
305
|
-
function dateInput(at) {
|
|
306
|
-
if (at === void 0) return "";
|
|
307
|
-
const date2 = new Date(at);
|
|
308
|
-
return new Date(at - date2.getTimezoneOffset() * 6e4).toISOString().slice(0, 16);
|
|
309
|
-
}
|
|
310
|
-
var save = (ui) => `<div class="kanban__actions"><button>${escapeHTML(ui.text("save"))}</button>${button(ui, "close-panel", "close")}</div>`;
|
|
311
|
-
function detailView(ui, board, item, actor, archived, events, relatedSessions = false, guidance, interactive = false, task = _chunkKYNYPKKHcjs.projectKanbanTask.call(void 0, item), fixAvailable = false) {
|
|
312
|
-
return `${panelHeader(ui, item.title, board, item)}${taskStatus(ui, task)}${archived ? "" : `<div class="kanban__actions">${taskControls(ui, task, fixAvailable)}</div>`}
|
|
313
|
-
<p>${escapeHTML(ui.text("origin"))}: ${escapeHTML(item.origin ? ui.text(item.origin.kind === "discovery" ? "flow" : "manual") + " \xB7 " + item.origin.principal.id : ui.text("unknownOrigin"))}</p>
|
|
314
|
-
<dl><dt>${escapeHTML(ui.text("itemId"))}</dt><dd>${escapeHTML(item.id)}</dd><dt>${escapeHTML(ui.text("responsibility"))}</dt><dd>${escapeHTML(item.responsibility)}</dd>
|
|
315
|
-
<dt>${escapeHTML(ui.text("acceptance"))}</dt><dd>${escapeHTML(item.acceptance)}</dd><dt>${escapeHTML(ui.text("owner"))}</dt><dd>${escapeHTML(_nullishCoalesce(_nullishCoalesce(_optionalChain([item, 'access', _52 => _52.owner, 'optionalAccess', _53 => _53.id]), () => ( _optionalChain([item, 'access', _54 => _54.owner, 'optionalAccess', _55 => _55.agentId]))), () => ( ui.text("none"))))}</dd></dl>
|
|
316
|
-
<p>${escapeHTML(ui.text(item.status))}${item.blocked ? " \xB7 " + escapeHTML(ui.text("blocked") + ": " + item.blocked.reason) : ""}</p>
|
|
317
|
-
${interactive ? "<section data-item-operations></section>" : ""}
|
|
318
|
-
${item.status === "review" ? interactive ? `<details><summary>${escapeHTML(ui.text("reviewFlow"))}</summary>${reviewGuidance(ui, guidance)}</details>` : reviewGuidance(ui, guidance) : ""}
|
|
319
|
-
<div class="kanban__actions">${controls(ui, board, item, actor, archived, interactive)}</div>
|
|
320
|
-
${_nullishCoalesce(_optionalChain([item, 'access', _56 => _56.issues, 'optionalAccess', _57 => _57.filter, 'call', _58 => _58((issue) => !issue.resolvedBy), 'access', _59 => _59.map, 'call', _60 => _60((issue) => `<form data-form="task-reply"><input type="hidden" name="attemptId" value="${escapeAttr(issue.attemptId)}"><input type="hidden" name="replyTo" value="${escapeAttr(issue.id)}">${textarea(ui, "content", "message")}<button>${escapeHTML(ui.text("send"))}</button></form>`), 'access', _61 => _61.join, 'call', _62 => _62("")]), () => ( ""))}
|
|
321
|
-
${amendmentsView(ui, item)}
|
|
322
|
-
${archived ? "" : detailForms(ui, board, item, actor)}
|
|
323
|
-
${(_nullishCoalesce(_optionalChain([item, 'access', _63 => _63.planning, 'optionalAccess', _64 => _64.dependencies]), () => ( []))).length ? `<p>${escapeHTML(ui.text("dependencies"))}: ${(_nullishCoalesce(_optionalChain([item, 'access', _65 => _65.planning, 'optionalAccess', _66 => _66.dependencies]), () => ( []))).map((id) => `<button type="button" data-item="${escapeAttr(id)}">${escapeHTML(_nullishCoalesce(_optionalChain([board, 'access', _67 => _67.items, 'access', _68 => _68.find, 'call', _69 => _69((i) => i.id === id), 'optionalAccess', _70 => _70.title]), () => ( id)))}</button>`).join(" ")}</p>` : ""}
|
|
324
|
-
${_optionalChain([item, 'access', _71 => _71.planning, 'optionalAccess', _72 => _72.parentId]) ? `<p>${escapeHTML(ui.text("parent"))}: <button type="button" data-item="${escapeAttr(item.planning.parentId)}">${escapeHTML(_nullishCoalesce(_optionalChain([board, 'access', _73 => _73.items, 'access', _74 => _74.find, 'call', _75 => _75((parent) => parent.id === _optionalChain([item, 'access', _76 => _76.planning, 'optionalAccess', _77 => _77.parentId])), 'optionalAccess', _78 => _78.title]), () => ( item.planning.parentId)))}</button></p>` : ""}
|
|
325
|
-
<section data-children></section><section data-related-records></section><h4>${escapeHTML(ui.text("sources"))}</h4>${sourcesView(ui, _nullishCoalesce(item.sources, () => ( [])))}
|
|
326
|
-
<div data-analysis></div><div data-execution-session></div><section data-related-sessions-section></section><section data-reference-links></section><section data-work-resource-section></section>
|
|
327
|
-
${relatedSessions ? "" : `<h4>${escapeHTML(ui.text("sessions"))}</h4>${item.participants.map((p) => `<button type="button" data-session="${escapeAttr(p.sessionId)}">${escapeHTML(p.sessionId)} \xB7 ${escapeHTML(p.roles.join(", "))}</button>`).join("") || `<p>${escapeHTML(ui.text("none"))}</p>`}`}
|
|
328
|
-
${archived ? "" : `<details><summary>${escapeHTML(ui.text("registerSession"))}</summary><p>${escapeHTML(ui.text("registerSessionHelp"))}</p><form data-form="session">${suggestionField({ name: "sessionId", label: "session", kind: "session", manual: true, required: true })}<button>${escapeHTML(ui.text("registerSession"))}</button></form></details>`}
|
|
329
|
-
<section data-item-events>${itemEventsView(ui, events)}</section>`;
|
|
330
|
-
}
|
|
331
|
-
function reviewGuidance(ui, guidance) {
|
|
332
|
-
const [summary, ...steps] = _nullishCoalesce(_optionalChain([guidance, 'optionalAccess', _79 => _79.paragraphs]), () => ( [ui.text("reviewHelp")]));
|
|
333
|
-
return `<section class="kanban__review-guide"><strong>${escapeHTML(_nullishCoalesce(_optionalChain([guidance, 'optionalAccess', _80 => _80.title]), () => ( ui.text("reviewHelpTitle"))))}</strong><p>${escapeHTML(summary)}</p>
|
|
334
|
-
${steps.length ? `<details><summary>${escapeHTML(ui.text("reviewFlow"))}</summary><ol>${steps.map((text) => `<li>${escapeHTML(text)}</li>`).join("")}</ol></details>` : ""}</section>`;
|
|
335
|
-
}
|
|
336
|
-
function itemEventsView(ui, events) {
|
|
337
|
-
return `<details><summary>${escapeHTML(ui.text("eventsHelp"))}</summary><ol>${meaningfulItemEvents(events).map((event) => `<li>${escapeHTML(event.kind)} \xB7 ${escapeHTML(_nullishCoalesce(_nullishCoalesce(event.actor.id, () => ( event.actor.agentId)), () => ( "")))} \xB7 ${escapeHTML(new Date(event.at).toLocaleString())}${event.data.message ? `<p>${escapeHTML(event.data.message)}</p>` : ""}</li>`).join("")}</ol></details>`;
|
|
338
|
-
}
|
|
339
|
-
function controls(ui, board, item, actor, archived, interactive = false) {
|
|
340
|
-
if (archived) return button(ui, "restore", "restore");
|
|
341
|
-
if (["completed", "cancelled"].includes(item.status)) return button(ui, "archive", "archiveItem");
|
|
342
|
-
const executable = _chunkPSKQAFDFcjs.executableWorkItem.call(void 0, board, item);
|
|
343
|
-
let result = item.status === "proposed" ? button(ui, "publish", "publish") : item.status === "backlog" && executable ? button(ui, "ready", "ready") : item.status === "open" ? button(ui, "defer", "defer") : "";
|
|
344
|
-
if (owns(item, actor) && item.status === "claimed") result += button(ui, "renew", "renew");
|
|
345
|
-
if (item.status === "review" && !owns(item, actor)) result += interactive ? "" : button(ui, "accept", "accept") + button(ui, "reject", "reject");
|
|
346
|
-
if (item.blocked) result += button(ui, "unblock", "unblock");
|
|
347
|
-
if (item.status === "review" && owns(item, actor) && board.policy.review !== "assignee") result += `<p>${escapeHTML(ui.text("noReview"))}</p>`;
|
|
348
|
-
return result;
|
|
349
|
-
}
|
|
350
|
-
function detailForms(ui, board, item, actor) {
|
|
351
|
-
if (["completed", "cancelled"].includes(item.status)) return "";
|
|
352
|
-
let forms = "";
|
|
353
|
-
const executable = _chunkPSKQAFDFcjs.executableWorkItem.call(void 0, board, item);
|
|
354
|
-
if (!executable && ["backlog", "proposed", "open"].includes(item.status)) forms += `<form data-form="close-plan">${field(ui, "resultRef", "result")}<button>${escapeHTML(ui.text("closePlan"))}</button></form>`;
|
|
355
|
-
if (!board.automation && executable && item.status === "open" && !item.blocked) forms += `<form data-form="claim">${board.policy.requireEstimate !== false ? estimates(ui) : ""}<button>${escapeHTML(ui.text("claim"))}</button></form>`;
|
|
356
|
-
if (item.status === "claimed" && owns(item, actor)) forms += `<form data-form="submit">${field(ui, "resultRef", "result")}<button>${escapeHTML(ui.text("submit"))}</button></form>`;
|
|
357
|
-
const automatic = _optionalChain([item, 'access', _81 => _81.eligiblePrincipals, 'optionalAccess', _82 => _82.some, 'call', _83 => _83((principal) => principal.kind === _optionalChain([board, 'access', _84 => _84.automation, 'optionalAccess', _85 => _85.worker, 'access', _86 => _86.kind]) && principal.id === board.automation.worker.id)]);
|
|
358
|
-
let secondary = "";
|
|
359
|
-
if (["proposed", "backlog", "open"].includes(item.status) && !automatic && !board.automation) secondary += `<details><summary>${escapeHTML(ui.text("editItem"))}</summary><form data-form="edit-item">${field(ui, "title", "name", item.title)}${textarea(ui, "responsibility", "responsibility", item.responsibility)}${textarea(ui, "acceptance", "acceptance", item.acceptance)}<button>${escapeHTML(ui.text("save"))}</button></form></details>`;
|
|
360
|
-
if (!board.automation && _optionalChain([item, 'access', _87 => _87.launch, 'optionalAccess', _88 => _88.admittedAt]) === void 0 && ["proposed", "backlog", "open"].includes(item.status)) secondary += `<details><summary>${escapeHTML(ui.text("plan"))}</summary><form data-form="plan">${planningFields(ui, board, item)}<button>${escapeHTML(ui.text("save"))}</button></form></details><form data-form="cancel">${field(ui, "reason", "reason")}<button>${escapeHTML(ui.text("cancel"))}</button></form>`;
|
|
361
|
-
if (owns(item, actor)) secondary += `<form data-form="release">${field(ui, "reason", "reason")}<button>${escapeHTML(ui.text("release"))}</button></form>`;
|
|
362
|
-
if (!item.blocked && (!item.owner || owns(item, actor))) secondary += `<form data-form="block">${field(ui, "reason", "reason")}<button>${escapeHTML(ui.text("block"))}</button></form>`;
|
|
363
|
-
return forms + `<details><summary>${escapeHTML(ui.text("moreActions"))}</summary>` + secondary + `<form data-form="message">${textarea(ui, "message", "message")}<button>${escapeHTML(ui.text("send"))}</button></form></details>`;
|
|
364
|
-
}
|
|
365
|
-
function estimates(ui) {
|
|
366
|
-
return `${field(ui, "complexity", "complexity", "1", true, "number")}${field(ui, "workUnits", "workUnits", "1", true, "number")}
|
|
367
|
-
${field(ui, "duration", "duration", "30", true, "number")}<label>${escapeHTML(ui.text("confidence"))}<select name="confidence">${["low", "medium", "high"].map((value2) => `<option value="${value2}">${escapeHTML(ui.text(value2))}</option>`).join("")}</select></label>`;
|
|
368
|
-
}
|
|
369
|
-
function itemResourceField(ui, catalog, executable) {
|
|
370
|
-
if (!catalog || !catalog.resources.length && !catalog.selected) return "";
|
|
371
|
-
const options = [...catalog.resources], selected = catalog.selected ? JSON.stringify(catalog.selected) : "";
|
|
372
|
-
if (catalog.selected && !options.some((option) => option.reference.system === catalog.selected.system && option.reference.id === catalog.selected.id)) options.push({ reference: catalog.selected, label: catalog.selected.id });
|
|
373
|
-
return `<label>${escapeHTML(ui.text("itemResource"))}<select name="itemResource" data-resource-required="${catalog.required === true}" ${catalog.required && executable ? "required" : ""} ${catalog.readonly ? "disabled" : ""}>
|
|
374
|
-
<option value="">${escapeHTML(ui.text("none"))}</option>${options.map((option) => `<option value="${escapeAttr(JSON.stringify(option.reference))}" ${JSON.stringify(option.reference) === selected ? "selected" : ""}>${escapeHTML(option.label)}</option>`).join("")}</select>
|
|
375
|
-
${catalog.readonly ? `<input type="hidden" name="itemResource" value="${escapeAttr(selected)}">` : ""}</label>`;
|
|
376
|
-
}
|
|
377
|
-
function editTaskForm(ui, board, item, editId, resources) {
|
|
378
|
-
return `${panelHeader(ui, item.title, board, item)}<p>${escapeHTML(ui.text("editLeaseHelp"))}</p><form data-form="save-edit"><input type="hidden" name="editId" value="${escapeAttr(editId)}">${field(ui, "title", "name", item.title)}${textarea(ui, "responsibility", "responsibility", item.responsibility)}${textarea(ui, "acceptance", "acceptance", item.acceptance)}${launchModeField(ui, _optionalChain([item, 'access', _89 => _89.launch, 'optionalAccess', _90 => _90.mode]))}${planningFields(ui, board, item)}${itemResourceField(ui, resources, true)}${save(ui)}</form>`;
|
|
379
|
-
}
|
|
380
|
-
function launchModeField(ui, mode = "automatic") {
|
|
381
|
-
return `<label>${escapeHTML(ui.text("taskStartMode"))}<select name="launchMode">${["automatic", "manual"].map((value2) => `<option value="${value2}" ${mode === value2 ? "selected" : ""}>${escapeHTML(ui.text("taskMode." + value2))}</option>`).join("")}</select></label>`;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
// src/ui/automation.ts
|
|
385
|
-
function automationForm(ui, board, catalog) {
|
|
386
|
-
const settings = board.automation;
|
|
387
|
-
const select = (name, label) => {
|
|
388
|
-
const selected = _optionalChain([settings, 'optionalAccess', _91 => _91[name]]), targets = [...name === "preparation" ? _nullishCoalesce(catalog.preparations, () => ( [])) : catalog.targets];
|
|
389
|
-
if (_optionalChain([settings, 'optionalAccess', _92 => _92[name]]) && !targets.some((entry) => sameReference(entry.reference, selected)))
|
|
390
|
-
targets.push({ reference: settings[name], label: ui.text("automationTargetUnavailable") });
|
|
391
|
-
return `<label>${escapeHTML(ui.text(label))}<select name="${name}" ${name === "preparation" ? "" : "required"}><option value="">${escapeHTML(ui.text("automationChoose"))}</option>${targets.map((entry) => {
|
|
392
|
-
const value2 = JSON.stringify(entry.reference);
|
|
393
|
-
return `<option value="${escapeAttr(value2)}" ${sameReference(entry.reference, selected) ? "selected" : ""}>${escapeHTML(entry.label)}</option>`;
|
|
394
|
-
}).join("")}</select></label>`;
|
|
395
|
-
};
|
|
396
|
-
return `${panelHeader(ui, ui.text("automationTitle"))}<form data-form="automation">
|
|
397
|
-
<p>${escapeHTML(ui.text("automationHelp"))}</p>
|
|
398
|
-
<label><input type="checkbox" name="enabled" ${_optionalChain([settings, 'optionalAccess', _93 => _93.enabled]) ? "checked" : ""}>${escapeHTML(ui.text("automationEnabled"))}</label>
|
|
399
|
-
${select("planner", "automationPlanner")}${select("executor", "automationExecutor")}${select("preparation", "automationPreparation")}<div data-preparation-options>${preparationFields(board, catalog)}</div>
|
|
400
|
-
<label><input type="checkbox" name="autoAccept" ${_optionalChain([settings, 'optionalAccess', _94 => _94.autoAccept]) ? "checked" : ""}>${escapeHTML(ui.text("automationAutoAccept"))}</label>
|
|
401
|
-
<p>${escapeHTML(ui.text("automationReviewHelp"))}</p>
|
|
402
|
-
<div class="kanban__actions"><button>${escapeHTML(ui.text("save"))}</button>${button(ui, "close-panel", "close")}</div></form>`;
|
|
403
|
-
}
|
|
404
|
-
function analysisView(ui, status) {
|
|
405
|
-
if (!status) return `<p>${escapeHTML(ui.text("automationPending"))}</p>`;
|
|
406
|
-
return `<section><h4>${escapeHTML(ui.text("automationAnalysis"))}</h4><p>${escapeHTML(ui.text("automationState." + status.state))}</p>
|
|
407
|
-
${status.reason ? `<p>${escapeHTML(status.reason)}</p>` : ""}${status.code ? `<p>${escapeHTML(ui.text("errors." + status.code))}</p>` : ""}
|
|
408
|
-
${["failed", "clarification"].includes(status.state) ? button(ui, "reanalyze", "automationReanalyze") : ""}</section>`;
|
|
409
|
-
}
|
|
410
|
-
function preparationFields(board, catalog, reference = _optionalChain([board, 'access', _95 => _95.automation, 'optionalAccess', _96 => _96.preparation])) {
|
|
411
|
-
const selected = reference;
|
|
412
|
-
const entries = _nullishCoalesce(_optionalChain([catalog, 'access', _97 => _97.preparations, 'optionalAccess', _98 => _98.filter, 'call', _99 => _99((entry) => sameReference(entry.reference, selected))]), () => ( []));
|
|
413
|
-
return entries.flatMap((entry) => (_nullishCoalesce(entry.options, () => ( []))).map((option) => {
|
|
414
|
-
const value2 = _nullishCoalesce(_nullishCoalesce(_optionalChain([board, 'access', _100 => _100.automation, 'optionalAccess', _101 => _101.preparationOptions, 'optionalAccess', _102 => _102[option.name]]), () => ( option.defaultValue)), () => ( ""));
|
|
415
|
-
const name = "preparation-option-" + option.name;
|
|
416
|
-
const control = option.choices ? `<select name="${escapeAttr(name)}">${option.choices.map((choice) => `<option value="${escapeAttr(choice.value)}" ${choice.value === value2 ? "selected" : ""}>${escapeHTML(choice.label)}</option>`).join("")}</select>` : `<input name="${escapeAttr(name)}" value="${escapeAttr(value2)}" maxlength="4096">`;
|
|
417
|
-
return `<label>${escapeHTML(option.label)}${control}</label>`;
|
|
418
|
-
})).join("");
|
|
419
|
-
}
|
|
420
|
-
function sameReference(left, right) {
|
|
421
|
-
const a = left;
|
|
422
|
-
const b = right;
|
|
423
|
-
return !!a && !!b && a.system === b.system && a.id === b.id && a.revision === b.revision;
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
// src/ui/suggestion-picker.ts
|
|
427
|
-
var KanbanSuggestionPicker = (_class = class {
|
|
428
|
-
constructor(root, config, fetch, presentation) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);_class.prototype.__init4.call(this);_class.prototype.__init5.call(this);_class.prototype.__init6.call(this);_class.prototype.__init7.call(this);_class.prototype.__init8.call(this);_class.prototype.__init9.call(this);_class.prototype.__init10.call(this);
|
|
429
|
-
this.root = root;
|
|
430
|
-
this.config = config;
|
|
431
|
-
this.fetch = fetch;
|
|
432
|
-
this.presentation = presentation;
|
|
433
|
-
this.selected = [..._nullishCoalesce(config.selected, () => ( []))];
|
|
434
|
-
this.mount();
|
|
435
|
-
this.bind();
|
|
436
|
-
this.renderValues();
|
|
437
|
-
this.close();
|
|
438
|
-
}
|
|
439
|
-
__init() {this.input = document.createElement("input")}
|
|
440
|
-
__init2() {this.list = document.createElement("div")}
|
|
441
|
-
__init3() {this.chips = document.createElement("div")}
|
|
442
|
-
__init4() {this.values = document.createElement("div")}
|
|
443
|
-
__init5() {this.hint = document.createElement("small")}
|
|
444
|
-
|
|
445
|
-
__init6() {this.rows = []}
|
|
446
|
-
__init7() {this.active = -1}
|
|
447
|
-
__init8() {this.loading = false}
|
|
448
|
-
__init9() {this.generation = 0}
|
|
449
|
-
|
|
450
|
-
__init10() {this.abort = new AbortController()}
|
|
451
|
-
mount() {
|
|
452
|
-
const caption = document.createElement("label"), id = "kanban-suggest-" + _chunk6MN3H3YFcjs.randomUUID.call(void 0, );
|
|
453
|
-
caption.textContent = this.presentation.text(this.config.label);
|
|
454
|
-
caption.htmlFor = this.input.id = id;
|
|
455
|
-
this.input.type = "text";
|
|
456
|
-
this.input.autocomplete = "off";
|
|
457
|
-
this.input.maxLength = 256;
|
|
458
|
-
this.input.required = !!this.config.required;
|
|
459
|
-
this.input.setAttribute("role", "combobox");
|
|
460
|
-
this.input.setAttribute("aria-autocomplete", "list");
|
|
461
|
-
this.input.setAttribute("aria-controls", this.list.id = id + "-list");
|
|
462
|
-
this.input.setAttribute("aria-describedby", this.hint.id = id + "-hint");
|
|
463
|
-
this.input.placeholder = this.config.free ? this.presentation.text(this.config.label) + " \xB7 " + this.presentation.text("suggestFreePlaceholder") : this.presentation.text("suggestPlaceholder");
|
|
464
|
-
if (this.config.free) this.input.name = this.config.name;
|
|
465
|
-
this.input.value = this.config.multiple ? "" : _nullishCoalesce(_optionalChain([this, 'access', _103 => _103.selected, 'access', _104 => _104[0], 'optionalAccess', _105 => _105.label]), () => ( ""));
|
|
466
|
-
this.list.className = "kanban__suggest-list";
|
|
467
|
-
this.list.setAttribute("role", "listbox");
|
|
468
|
-
this.list.setAttribute("aria-label", caption.textContent);
|
|
469
|
-
this.chips.className = "kanban__suggest-chips";
|
|
470
|
-
this.hint.setAttribute("aria-live", "polite");
|
|
471
|
-
this.hint.textContent = this.presentation.text(this.config.free ? "suggestFreeHint" : "suggestHint");
|
|
472
|
-
this.root.replaceChildren(caption, this.chips, this.input, this.values, this.list, this.hint);
|
|
473
|
-
}
|
|
474
|
-
bind() {
|
|
475
|
-
const signal = this.abort.signal;
|
|
476
|
-
this.input.addEventListener("focus", () => {
|
|
477
|
-
if (!this.config.multiple && this.selected.length) this.input.select();
|
|
478
|
-
if (!this.loading) void this.search();
|
|
479
|
-
}, { signal });
|
|
480
|
-
this.input.addEventListener("click", () => {
|
|
481
|
-
if (this.list.hidden && !this.loading) void this.search();
|
|
482
|
-
}, { signal });
|
|
483
|
-
this.input.addEventListener("input", () => {
|
|
484
|
-
if (!this.config.multiple && !this.config.free) {
|
|
485
|
-
this.selected = [];
|
|
486
|
-
this.renderValues();
|
|
487
|
-
}
|
|
488
|
-
this.validate();
|
|
489
|
-
clearTimeout(this.timer);
|
|
490
|
-
this.generation++;
|
|
491
|
-
this.rows = [];
|
|
492
|
-
this.active = -1;
|
|
493
|
-
this.list.replaceChildren();
|
|
494
|
-
this.hint.textContent = this.presentation.text("loading");
|
|
495
|
-
this.open();
|
|
496
|
-
this.timer = setTimeout(() => {
|
|
497
|
-
void this.search();
|
|
498
|
-
}, 150);
|
|
499
|
-
}, { signal });
|
|
500
|
-
this.input.addEventListener("keydown", (event) => this.keydown(event), { signal });
|
|
501
|
-
this.list.addEventListener("pointerdown", (event) => event.preventDefault(), { signal });
|
|
502
|
-
this.root.addEventListener("click", (event) => this.click(event), { signal });
|
|
503
|
-
document.addEventListener("scroll", () => this.position(), { signal, capture: true });
|
|
504
|
-
window.addEventListener("resize", () => this.position(), { signal });
|
|
505
|
-
this.root.addEventListener("focusout", (event) => {
|
|
506
|
-
if (!this.root.contains(event.relatedTarget)) this.close();
|
|
507
|
-
}, { signal });
|
|
508
|
-
}
|
|
509
|
-
async search() {
|
|
510
|
-
const generation = ++this.generation, operationId = _chunk6MN3H3YFcjs.randomUUID.call(void 0, ), started = Date.now();
|
|
511
|
-
const search = !this.config.multiple && _optionalChain([this, 'access', _106 => _106.selected, 'access', _107 => _107[0], 'optionalAccess', _108 => _108.label]) === this.input.value ? "" : this.input.value.trim();
|
|
512
|
-
const kind = _optionalChain([this, 'access', _109 => _109.root, 'access', _110 => _110.closest, 'call', _111 => _111("form"), 'optionalAccess', _112 => _112.querySelector, 'call', _113 => _113("[name=kind]"), 'optionalAccess', _114 => _114.value]);
|
|
513
|
-
this.revealInput();
|
|
514
|
-
this.loading = true;
|
|
515
|
-
this.hint.textContent = this.presentation.text("loading");
|
|
516
|
-
try {
|
|
517
|
-
const page = await this.fetch({
|
|
518
|
-
kind: this.config.kind,
|
|
519
|
-
search,
|
|
520
|
-
limit: 12,
|
|
521
|
-
...this.config.multiple ? { excludeIds: this.selected.map((row) => row.id) } : {},
|
|
522
|
-
...this.config.excludeItemId ? { excludeItemId: this.config.excludeItemId } : {},
|
|
523
|
-
...this.config.kind === "parent" && kind ? { childKind: kind } : {}
|
|
524
|
-
});
|
|
525
|
-
if (generation !== this.generation || this.abort.signal.aborted || !this.root.isConnected) return;
|
|
526
|
-
this.rows = page.items.filter((row) => !this.config.multiple || !this.selected.some((value2) => value2.id === row.id));
|
|
527
|
-
if (this.config.manual && search && !this.rows.some((row) => row.id === search)) this.rows.push({ id: search, label: search, detail: this.presentation.text("suggestManualId") });
|
|
528
|
-
this.active = this.rows.length ? 0 : -1;
|
|
529
|
-
this.renderOptions();
|
|
530
|
-
this.hint.textContent = this.presentation.text(page.hasMore ? "suggestRefine" : this.rows.length ? this.config.free ? "suggestFreeHint" : "suggestHint" : "suggestEmpty");
|
|
531
|
-
this.log({ operationId, stage: this.config.kind, result: "success", count: page.items.length, durationMs: Date.now() - started });
|
|
532
|
-
} catch (error) {
|
|
533
|
-
if (generation !== this.generation || this.abort.signal.aborted) return;
|
|
534
|
-
this.rows = [];
|
|
535
|
-
this.list.replaceChildren();
|
|
536
|
-
this.hint.textContent = this.presentation.text("suggestFailed");
|
|
537
|
-
const retry = document.createElement("button");
|
|
538
|
-
retry.type = "button";
|
|
539
|
-
retry.textContent = this.presentation.text("retry");
|
|
540
|
-
retry.dataset.suggestRetry = "";
|
|
541
|
-
this.list.append(retry);
|
|
542
|
-
this.open();
|
|
543
|
-
const raw = _optionalChain([error, 'optionalAccess', _115 => _115.code]), code = typeof raw === "string" && /^[A-Z_0-9]{1,80}$/.test(raw) ? raw : "KANBAN_SUGGEST_FAILED";
|
|
544
|
-
this.log({ operationId, stage: this.config.kind, result: "failure", code, durationMs: Date.now() - started });
|
|
545
|
-
} finally {
|
|
546
|
-
if (generation === this.generation) this.loading = false;
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
|
-
log(event) {
|
|
550
|
-
try {
|
|
551
|
-
_optionalChain([this, 'access', _116 => _116.presentation, 'access', _117 => _117.log, 'optionalCall', _118 => _118(event)]);
|
|
552
|
-
} catch (e2) {
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
renderOptions() {
|
|
556
|
-
this.list.replaceChildren();
|
|
557
|
-
this.rows.forEach((row, index) => {
|
|
558
|
-
const button2 = document.createElement("button");
|
|
559
|
-
button2.type = "button";
|
|
560
|
-
button2.tabIndex = -1;
|
|
561
|
-
button2.dataset.suggestIndex = String(index);
|
|
562
|
-
button2.id = this.list.id + "-" + index;
|
|
563
|
-
button2.setAttribute("role", "option");
|
|
564
|
-
const title = document.createElement("strong"), detail = document.createElement("small");
|
|
565
|
-
title.textContent = row.label;
|
|
566
|
-
detail.textContent = [row.status ? this.presentation.text(row.status) : "", row.archived ? this.presentation.text("archive") : "", row.detail, this.config.free ? "" : row.id].filter(Boolean).join(" \xB7 ");
|
|
567
|
-
button2.append(title, detail);
|
|
568
|
-
this.list.append(button2);
|
|
569
|
-
});
|
|
570
|
-
this.open();
|
|
571
|
-
this.markActive();
|
|
572
|
-
}
|
|
573
|
-
click(event) {
|
|
574
|
-
const button2 = event.target.closest("button");
|
|
575
|
-
if (!button2) return;
|
|
576
|
-
if (button2.dataset.suggestIndex !== void 0) this.choose(this.rows[Number(button2.dataset.suggestIndex)]);
|
|
577
|
-
else if (button2.dataset.suggestRemove !== void 0) {
|
|
578
|
-
this.selected = this.selected.filter((row) => row.id !== button2.dataset.suggestRemove);
|
|
579
|
-
this.renderValues();
|
|
580
|
-
this.changed();
|
|
581
|
-
this.input.focus();
|
|
582
|
-
} else if (button2.hasAttribute("data-suggest-retry")) {
|
|
583
|
-
void this.search();
|
|
584
|
-
this.input.focus();
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
choose(row) {
|
|
588
|
-
if (!row) return;
|
|
589
|
-
this.selected = this.config.multiple ? [...this.selected, row] : [row];
|
|
590
|
-
this.input.value = this.config.multiple ? "" : row.label;
|
|
591
|
-
this.renderValues();
|
|
592
|
-
this.input.setCustomValidity("");
|
|
593
|
-
this.hint.textContent = this.presentation.text(this.config.free ? "suggestFreeHint" : "suggestHint");
|
|
594
|
-
this.changed();
|
|
595
|
-
this.close();
|
|
596
|
-
this.input.focus();
|
|
597
|
-
}
|
|
598
|
-
renderValues() {
|
|
599
|
-
this.values.replaceChildren();
|
|
600
|
-
this.chips.replaceChildren();
|
|
601
|
-
if (!this.config.free) for (const row of this.selected.length ? this.selected : this.config.multiple ? [] : [{ id: "", label: "" }]) {
|
|
602
|
-
const input = document.createElement("input");
|
|
603
|
-
input.type = "hidden";
|
|
604
|
-
input.name = this.config.name;
|
|
605
|
-
input.value = row.id;
|
|
606
|
-
this.values.append(input);
|
|
607
|
-
}
|
|
608
|
-
if (this.config.multiple) for (const row of this.selected) {
|
|
609
|
-
const chip = document.createElement("button");
|
|
610
|
-
chip.type = "button";
|
|
611
|
-
chip.dataset.suggestRemove = row.id;
|
|
612
|
-
const name = document.createElement("span"), remove = document.createElement("span");
|
|
613
|
-
name.textContent = row.label;
|
|
614
|
-
remove.innerHTML = this.presentation.icons.close;
|
|
615
|
-
remove.setAttribute("aria-hidden", "true");
|
|
616
|
-
chip.append(name, remove);
|
|
617
|
-
chip.setAttribute("aria-label", this.presentation.text("suggestRemove") + ": " + row.label);
|
|
618
|
-
this.chips.append(chip);
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
validate() {
|
|
622
|
-
const unselected = !this.config.free && !!this.input.value.trim() && (this.config.multiple || !this.selected.length);
|
|
623
|
-
this.input.setCustomValidity(unselected ? this.presentation.text("suggestPickRequired") : "");
|
|
624
|
-
}
|
|
625
|
-
changed() {
|
|
626
|
-
this.validate();
|
|
627
|
-
this.root.dispatchEvent(new Event("input", { bubbles: true }));
|
|
628
|
-
}
|
|
629
|
-
keydown(event) {
|
|
630
|
-
if (event.key === "Escape" && !this.list.hidden) {
|
|
631
|
-
event.preventDefault();
|
|
632
|
-
event.stopPropagation();
|
|
633
|
-
this.close();
|
|
634
|
-
return;
|
|
635
|
-
}
|
|
636
|
-
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
637
|
-
event.preventDefault();
|
|
638
|
-
event.stopPropagation();
|
|
639
|
-
if (this.list.hidden) {
|
|
640
|
-
void this.search();
|
|
641
|
-
return;
|
|
642
|
-
}
|
|
643
|
-
this.active = this.rows.length ? (this.active + (event.key === "ArrowDown" ? 1 : -1) + this.rows.length) % this.rows.length : -1;
|
|
644
|
-
this.markActive();
|
|
645
|
-
} else if (event.key === "Enter" && !this.list.hidden) {
|
|
646
|
-
event.preventDefault();
|
|
647
|
-
event.stopPropagation();
|
|
648
|
-
this.choose(this.rows[this.active]);
|
|
649
|
-
} else if (event.key === "Tab" && !this.list.querySelector("[data-suggest-retry]")) this.close();
|
|
650
|
-
else if (event.key === "Backspace" && this.config.multiple && !this.input.value && this.selected.length) {
|
|
651
|
-
this.selected.pop();
|
|
652
|
-
this.renderValues();
|
|
653
|
-
this.changed();
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
markActive() {
|
|
657
|
-
[...this.list.children].forEach((node, index) => node.setAttribute("aria-selected", String(index === this.active)));
|
|
658
|
-
if (this.active >= 0) {
|
|
659
|
-
this.input.setAttribute("aria-activedescendant", this.list.id + "-" + this.active);
|
|
660
|
-
const row = this.list.children[this.active];
|
|
661
|
-
if (row && row.offsetTop < this.list.scrollTop) this.list.scrollTop = row.offsetTop;
|
|
662
|
-
else if (row && row.offsetTop + row.offsetHeight > this.list.scrollTop + this.list.clientHeight) this.list.scrollTop = row.offsetTop + row.offsetHeight - this.list.clientHeight;
|
|
663
|
-
} else this.input.removeAttribute("aria-activedescendant");
|
|
664
|
-
}
|
|
665
|
-
open() {
|
|
666
|
-
this.list.hidden = false;
|
|
667
|
-
this.input.setAttribute("aria-expanded", "true");
|
|
668
|
-
this.position();
|
|
669
|
-
}
|
|
670
|
-
revealInput() {
|
|
671
|
-
const panel = this.root.closest("[data-panel]");
|
|
672
|
-
if (!panel) return;
|
|
673
|
-
const input = this.input.getBoundingClientRect(), bounds = panel.getBoundingClientRect();
|
|
674
|
-
const top = (_nullishCoalesce(_optionalChain([panel, 'access', _119 => _119.querySelector, 'call', _120 => _120(".kanban__panel-header"), 'optionalAccess', _121 => _121.getBoundingClientRect, 'call', _122 => _122(), 'access', _123 => _123.bottom]), () => ( bounds.top))) + 8, bottom = bounds.bottom - 12;
|
|
675
|
-
if (input.bottom > bottom) panel.scrollTop += input.bottom - bottom;
|
|
676
|
-
else if (input.top < top) panel.scrollTop -= top - input.top;
|
|
677
|
-
}
|
|
678
|
-
position() {
|
|
679
|
-
if (this.list.hidden || !this.root.isConnected) return;
|
|
680
|
-
const input = this.input.getBoundingClientRect(), scope = (_nullishCoalesce(_nullishCoalesce(this.root.closest("[data-panel]"), () => ( this.root.closest(".kanban"))), () => ( document.documentElement))).getBoundingClientRect();
|
|
681
|
-
const below = Math.max(0, scope.bottom - input.bottom - 8), above = Math.max(0, input.top - scope.top - 8), up = above > below && below < 160;
|
|
682
|
-
const height = Math.min(210, up ? above : below), width = Math.min(Math.max(input.width, 220), Math.max(0, scope.width - 16));
|
|
683
|
-
const left = Math.max(scope.left + 8, Math.min(input.left, scope.right - width - 8));
|
|
684
|
-
Object.assign(this.list.style, {
|
|
685
|
-
position: "fixed",
|
|
686
|
-
zIndex: "30",
|
|
687
|
-
left: `${left}px`,
|
|
688
|
-
width: `${width}px`,
|
|
689
|
-
maxHeight: `${height}px`,
|
|
690
|
-
top: up ? "auto" : `${input.bottom + 4}px`,
|
|
691
|
-
bottom: up ? `${innerHeight - input.top + 4}px` : "auto"
|
|
692
|
-
});
|
|
693
|
-
}
|
|
694
|
-
close() {
|
|
695
|
-
this.loading = false;
|
|
696
|
-
if (this.hint.textContent === this.presentation.text("loading")) this.hint.textContent = this.presentation.text(this.config.free ? "suggestFreeHint" : "suggestHint");
|
|
697
|
-
clearTimeout(this.timer);
|
|
698
|
-
this.generation++;
|
|
699
|
-
this.list.hidden = true;
|
|
700
|
-
this.input.setAttribute("aria-expanded", "false");
|
|
701
|
-
this.input.removeAttribute("aria-activedescendant");
|
|
702
|
-
}
|
|
703
|
-
destroy() {
|
|
704
|
-
clearTimeout(this.timer);
|
|
705
|
-
this.generation++;
|
|
706
|
-
this.abort.abort();
|
|
707
|
-
}
|
|
708
|
-
}, _class);
|
|
709
|
-
|
|
710
|
-
// src/ui/suggestions.ts
|
|
711
|
-
var KanbanSuggestions = (_class2 = class {
|
|
712
|
-
constructor(root, service, boardId, presentation) {;_class2.prototype.__init11.call(this);
|
|
713
|
-
this.root = root;
|
|
714
|
-
this.service = service;
|
|
715
|
-
this.boardId = boardId;
|
|
716
|
-
this.presentation = presentation;
|
|
717
|
-
this.observer = new MutationObserver(() => this.sync());
|
|
718
|
-
this.observer.observe(root, { childList: true, subtree: true });
|
|
719
|
-
this.sync();
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
__init11() {this.fields = /* @__PURE__ */ new Map()}
|
|
723
|
-
sync() {
|
|
724
|
-
for (const [node, field2] of this.fields) if (!this.root.contains(node)) {
|
|
725
|
-
field2.destroy();
|
|
726
|
-
this.fields.delete(node);
|
|
727
|
-
}
|
|
728
|
-
if (!this.service) return;
|
|
729
|
-
for (const node of this.root.querySelectorAll("[data-kanban-suggest]")) {
|
|
730
|
-
if (this.fields.has(node)) continue;
|
|
731
|
-
const options = JSON.parse(node.dataset.kanbanSuggest);
|
|
732
|
-
const picker = new KanbanSuggestionPicker(node, options, (query) => this.service.suggest(this.boardId(), query), this.presentation);
|
|
733
|
-
this.fields.set(node, picker);
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
destroy() {
|
|
737
|
-
this.observer.disconnect();
|
|
738
|
-
for (const field2 of this.fields.values()) field2.destroy();
|
|
739
|
-
this.fields.clear();
|
|
740
|
-
}
|
|
741
|
-
}, _class2);
|
|
742
|
-
|
|
743
|
-
// src/ui/index.ts
|
|
744
|
-
var _uicommon = require('@nestos/ui-common');
|
|
745
|
-
|
|
746
|
-
// src/ui/drawer.ts
|
|
747
|
-
var KanbanDrawer = (_class3 = class {
|
|
748
|
-
constructor(editor, sidebar) {;_class3.prototype.__init12.call(this);_class3.prototype.__init13.call(this);_class3.prototype.__init14.call(this);
|
|
749
|
-
this.editor = editor;
|
|
750
|
-
this.sidebar = sidebar;
|
|
751
|
-
}
|
|
752
|
-
__init12() {this.key = ""}
|
|
753
|
-
__init13() {this.focusRequested = false}
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
__init14() {this.restoreRequested = false}
|
|
758
|
-
get element() {
|
|
759
|
-
return this.editor.querySelector("[data-panel]");
|
|
760
|
-
}
|
|
761
|
-
get open() {
|
|
762
|
-
return !this.element.hidden;
|
|
763
|
-
}
|
|
764
|
-
show(html, key) {
|
|
765
|
-
const panel = this.element, same = this.open && this.key === key, top = same ? panel.scrollTop : 0;
|
|
766
|
-
if (!this.open) {
|
|
767
|
-
const active = document.activeElement;
|
|
768
|
-
this.restoreTarget = _nullishCoalesce(active, () => ( void 0));
|
|
769
|
-
this.restoreItem = _optionalChain([active, 'optionalAccess', _124 => _124.dataset, 'access', _125 => _125.item]);
|
|
770
|
-
this.restoreRecord = _optionalChain([active, 'optionalAccess', _126 => _126.dataset, 'access', _127 => _127.record]);
|
|
771
|
-
}
|
|
772
|
-
this.focusRequested ||= same && panel.contains(document.activeElement);
|
|
773
|
-
const retained = same ? ["[data-work-resource-section]", "[data-related-sessions-section]"].map((selector) => ({ selector, node: panel.querySelector(selector) })) : [];
|
|
774
|
-
panel.innerHTML = html;
|
|
775
|
-
for (const { selector, node } of retained) if (_optionalChain([node, 'optionalAccess', _128 => _128.hasChildNodes, 'call', _129 => _129()])) _optionalChain([panel, 'access', _130 => _130.querySelector, 'call', _131 => _131(selector), 'optionalAccess', _132 => _132.replaceWith, 'call', _133 => _133(node)]);
|
|
776
|
-
const error = document.createElement("p");
|
|
777
|
-
error.dataset.panelError = "";
|
|
778
|
-
error.setAttribute("role", "alert");
|
|
779
|
-
const header = panel.querySelector(".kanban__panel-header");
|
|
780
|
-
if (header) header.after(error);
|
|
781
|
-
else panel.prepend(error);
|
|
782
|
-
panel.hidden = false;
|
|
783
|
-
panel.scrollTop = top;
|
|
784
|
-
this.key = key;
|
|
785
|
-
this.focusRequested ||= !same;
|
|
786
|
-
this.editor.querySelector("[data-content]").inert = true;
|
|
787
|
-
if (this.sidebar) this.sidebar.inert = true;
|
|
788
|
-
this.editor.querySelector("[data-backdrop]").hidden = false;
|
|
789
|
-
this.editor.classList.add("kanban--detail");
|
|
790
|
-
}
|
|
791
|
-
close() {
|
|
792
|
-
this.element.hidden = true;
|
|
793
|
-
this.element.replaceChildren();
|
|
794
|
-
this.key = "";
|
|
795
|
-
this.focusRequested = false;
|
|
796
|
-
this.restoreRequested = true;
|
|
797
|
-
this.editor.querySelector("[data-content]").inert = false;
|
|
798
|
-
if (this.sidebar) this.sidebar.inert = false;
|
|
799
|
-
this.editor.querySelector("[data-backdrop]").hidden = true;
|
|
800
|
-
this.editor.classList.remove("kanban--detail");
|
|
801
|
-
}
|
|
802
|
-
flushFocus() {
|
|
803
|
-
if (this.focusRequested && this.open) {
|
|
804
|
-
this.focusRequested = false;
|
|
805
|
-
this.element.focus({ preventScroll: true });
|
|
806
|
-
} else if (this.restoreRequested) {
|
|
807
|
-
this.restoreRequested = false;
|
|
808
|
-
const matches = [...this.editor.querySelectorAll("[data-item], [data-record]")];
|
|
809
|
-
const target = _optionalChain([this, 'access', _134 => _134.restoreTarget, 'optionalAccess', _135 => _135.isConnected]) ? this.restoreTarget : matches.find((node) => this.restoreItem ? node.dataset.item === this.restoreItem : this.restoreRecord ? node.dataset.record === this.restoreRecord : false);
|
|
810
|
-
_optionalChain([(_nullishCoalesce(target, () => ( this.editor.querySelector("button")))), 'optionalAccess', _136 => _136.focus, 'call', _137 => _137({ preventScroll: true })]);
|
|
811
|
-
}
|
|
812
|
-
}
|
|
813
|
-
keydown(event) {
|
|
814
|
-
if (!this.open || event.key !== "Tab") return;
|
|
815
|
-
const nodes = [...this.element.querySelectorAll('button, input:not([type=hidden]), select, textarea, a[href], summary, [tabindex="0"]')].filter((node) => !node.matches(":disabled") && node.tabIndex >= 0 && !node.closest("[hidden], [inert]") && !node.hidden && !node.closest("details:not([open]) :not(summary)"));
|
|
816
|
-
const first = nodes[0], last = nodes[nodes.length - 1], active = document.activeElement;
|
|
817
|
-
if (!first) {
|
|
818
|
-
event.preventDefault();
|
|
819
|
-
this.element.focus();
|
|
820
|
-
return;
|
|
821
|
-
}
|
|
822
|
-
if (event.shiftKey && (active === first || active === this.element)) {
|
|
823
|
-
event.preventDefault();
|
|
824
|
-
last.focus();
|
|
825
|
-
} else if (!event.shiftKey && (active === last || !this.element.contains(active))) {
|
|
826
|
-
event.preventDefault();
|
|
827
|
-
first.focus();
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
destroy() {
|
|
831
|
-
if (this.sidebar) this.sidebar.inert = false;
|
|
832
|
-
this.editor.classList.remove("kanban--detail");
|
|
833
|
-
}
|
|
834
|
-
}, _class3);
|
|
835
|
-
function drawerMarkup(ui) {
|
|
836
|
-
return `<button type="button" class="kanban__backdrop" data-backdrop data-action="dismiss-panel" aria-label="${escapeAttr(ui.text("closeDetail"))}" tabindex="-1" hidden></button>
|
|
837
|
-
<section data-panel class="kanban__panel" role="dialog" aria-modal="true" aria-label="${escapeAttr(ui.text("details"))}" tabindex="-1" hidden></section>`;
|
|
838
|
-
}
|
|
839
|
-
function preserveBoardScroll(container, render) {
|
|
840
|
-
const columns = [...container.querySelectorAll("[data-column]")].map((node) => ({ id: node.dataset.column, top: node.scrollTop }));
|
|
841
|
-
const left = _nullishCoalesce(_optionalChain([container, 'access', _138 => _138.querySelector, 'call', _139 => _139(".kanban__columns"), 'optionalAccess', _140 => _140.scrollLeft]), () => ( 0));
|
|
842
|
-
render();
|
|
843
|
-
for (const node of container.querySelectorAll("[data-column]")) node.scrollTop = _nullishCoalesce(_optionalChain([columns, 'access', _141 => _141.find, 'call', _142 => _142((column) => column.id === node.dataset.column), 'optionalAccess', _143 => _143.top]), () => ( 0));
|
|
844
|
-
const board = container.querySelector(".kanban__columns");
|
|
845
|
-
if (board) board.scrollLeft = left;
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
// src/ui/diagnostics.ts
|
|
849
|
-
function failureDetails(error) {
|
|
850
|
-
if (!error || typeof error !== "object") return {};
|
|
851
|
-
const value2 = error;
|
|
852
|
-
const known = /^(?:Error|TypeError|ReferenceError|SyntaxError|RangeError|SecurityError|QuotaExceededError|NotSupportedError|InvalidStateError|DataCloneError|AbortError|NetworkError)$/;
|
|
853
|
-
const errorName = typeof value2.name === "string" && known.test(value2.name) ? value2.name : void 0;
|
|
854
|
-
const frame = typeof value2.stack === "string" ? value2.stack.match(/(?:^|\/)([A-Za-z0-9_.-]+\.m?js):(\d+):(\d+)/m) : null;
|
|
855
|
-
return { ...errorName ? { errorName } : {}, ...frame ? { source: `${frame[1]}:${frame[2]}:${frame[3]}` } : {} };
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
// src/ui/operations.ts
|
|
859
|
-
function itemOperationsView(ui, view, sessionUrl) {
|
|
860
|
-
return `<button type="button" data-action="refresh-item-operations">${escapeHTML(ui.text("operationRefresh"))}</button><h4>${escapeHTML(ui.text("operationsTitle"))}</h4>
|
|
861
|
-
<ol class="kanban__operations">${view.operations.map((operation) => operationCard(ui, view, operation, sessionUrl)).join("")}</ol>`;
|
|
862
|
-
}
|
|
863
|
-
function operationCard(ui, view, operation, url) {
|
|
864
|
-
const reason = operation.code ? ui.text("errors." + operation.code) : "";
|
|
865
|
-
return `<li data-operation-id="${escapeAttr(operation.id)}"><strong>${escapeHTML(operation.label)}</strong> \xB7 ${escapeHTML(ui.text("operationState." + operation.state))}
|
|
866
|
-
${operation.reason ? `<p>${escapeHTML(operation.reason)}</p>` : ""}${operation.code ? `<p role="alert">${escapeHTML(reason.endsWith("errors." + operation.code) ? operation.code : reason)}</p>` : ""}
|
|
867
|
-
${operation.summary ? `<pre class="kanban__operation-summary">${escapeHTML(operation.summary)}</pre>` : ""}
|
|
868
|
-
${operation.sessionId ? sessionLink(ui, operation.sessionId, ui.text("operationSession"), _optionalChain([url, 'optionalCall', _144 => _144(operation.sessionId)])) : ""}
|
|
869
|
-
<form data-form="item-operation" data-operation="${escapeAttr(operation.id)}" data-revision="${escapeAttr(view.revision)}">
|
|
870
|
-
${choices(ui, operation)}${operation.confirmation ? `<label><input type="checkbox" name="confirmed" required>${escapeHTML(operation.confirmation)}</label>` : ""}
|
|
871
|
-
<button type="submit"${operation.enabled ? "" : " disabled"}>${escapeHTML(operation.label)}</button></form>${configuration(ui, view, operation)}</li>`;
|
|
872
|
-
}
|
|
873
|
-
function choices(ui, operation) {
|
|
874
|
-
return (_nullishCoalesce(operation.fields, () => ( []))).map((field2) => `<label>${escapeHTML(field2.label)}<select name="choice-${escapeAttr(field2.id)}" required>
|
|
875
|
-
<option value="">${escapeHTML(ui.text("operationChoose"))}</option>${field2.choices.map((choice) => `<option value="${escapeAttr(choice.id)}"${field2.selected === choice.id ? " selected" : ""}>${escapeHTML(choice.label + (choice.detail ? " \xB7 " + choice.detail : ""))}</option>`).join("")}</select></label>`).join("");
|
|
876
|
-
}
|
|
877
|
-
function configuration(ui, view, operation) {
|
|
878
|
-
if (!operation.configurable) return "";
|
|
879
|
-
return `<details><summary>${escapeHTML(ui.text("operationConfigure"))}</summary><form data-form="operation-binding" data-operation="${escapeAttr(operation.id)}" data-revision="${escapeAttr(view.revision)}">
|
|
880
|
-
<label>${escapeHTML(ui.text("operationFlow"))}<select name="target" required><option value="">${escapeHTML(ui.text("operationChoose"))}</option>
|
|
881
|
-
${(_nullishCoalesce(view.targets, () => ( []))).map((target) => `<option value="${escapeAttr(JSON.stringify(target.reference))}"${JSON.stringify(target.reference) === JSON.stringify(operation.binding) ? " selected" : ""}>${escapeHTML(target.label)}</option>`).join("")}</select></label>
|
|
882
|
-
<button type="submit">${escapeHTML(ui.text("save"))}</button>${_optionalChain([view, 'access', _145 => _145.targets, 'optionalAccess', _146 => _146.length]) ? "" : `<p>${escapeHTML(ui.text("operationNoFlows"))}</p>`}</form></details>`;
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
// src/ui/work-resources.ts
|
|
886
|
-
function workResourcesView(ui, resources) {
|
|
887
|
-
if (!resources.length) return `<p>${escapeHTML(ui.text("none"))}</p>`;
|
|
888
|
-
return resources.map((resource) => `<article class="kanban__work-resource" data-work-resource="${escapeAttr(resource.id)}">
|
|
889
|
-
<strong>${escapeHTML(resource.title)}</strong>${copy(ui, resource.title, ui.text("copyWorkResourceName"))} \xB7 ${escapeHTML(ui.text("workResourceState." + resource.state))}
|
|
890
|
-
<p><code>${escapeHTML(resource.location)}</code>${copy(ui, resource.location, ui.text("copyWorkResourcePath"))}</p>
|
|
891
|
-
<dl>${resource.properties.map((row) => `<dt>${escapeHTML(row.label)}</dt><dd>${escapeHTML(row.value)}${copy(ui, row.value, ui.text("copyValue") + " \xB7 " + row.label)}</dd>`).join("")}</dl>
|
|
892
|
-
${resource.reasons.map((reason) => `<p>${escapeHTML(reasonLabel(ui, reason))}</p>`).join("")}
|
|
893
|
-
<button type="button" data-action="cleanup-work-resource" data-resource="${escapeAttr(resource.id)}" data-version="${escapeAttr(resource.version)}" ${resource.canCleanup ? "" : "disabled"}>${escapeHTML(ui.text("cleanupWorkResource"))}</button>
|
|
894
|
-
</article>`).join("");
|
|
895
|
-
}
|
|
896
|
-
function copy(ui, value2, label) {
|
|
897
|
-
return `<button type="button" class="kanban__copy-button" data-action="copy-resource" data-copy="${escapeAttr(value2)}" title="${escapeAttr(label)}" aria-label="${escapeAttr(label)}">${_nullishCoalesce(ui.icons.copy, () => ( escapeHTML(ui.text("copyValue"))))}</button>`;
|
|
898
|
-
}
|
|
899
|
-
function reasonLabel(ui, reason) {
|
|
900
|
-
const key = "workResourceReason." + reason, label = ui.text(key);
|
|
901
|
-
return label.includes(key) ? reason : label;
|
|
902
|
-
}
|
|
903
|
-
|
|
904
|
-
// src/ui/renderer.ts
|
|
905
|
-
function createRenderer(ui) {
|
|
906
|
-
const bind = (fn) => (...args) => fn(ui, ...args);
|
|
907
|
-
return {
|
|
908
|
-
label: ui.text.bind(ui),
|
|
909
|
-
boardView: bind(boardView),
|
|
910
|
-
catalogView: bind(catalogView),
|
|
911
|
-
navigation: bind(navigation),
|
|
912
|
-
button: bind(button),
|
|
913
|
-
detailView: bind(detailView),
|
|
914
|
-
itemEventsView: bind(itemEventsView),
|
|
915
|
-
newBoardForm: bind(newBoardForm),
|
|
916
|
-
newItemForm: bind(newItemForm),
|
|
917
|
-
recordLinks: bind(recordLinks),
|
|
918
|
-
recordsView: bind(recordsView),
|
|
919
|
-
recordDetail: bind(recordDetail),
|
|
920
|
-
recordForm: bind(recordForm),
|
|
921
|
-
executionSessionView: bind(executionSessionView),
|
|
922
|
-
executionBadge: bind(executionBadge),
|
|
923
|
-
copyReference: bind(copyReference)
|
|
924
|
-
};
|
|
925
|
-
}
|
|
926
|
-
|
|
927
|
-
// src/ui/commands.ts
|
|
928
|
-
var value = (data, key) => String(_nullishCoalesce(data.get(key), () => ( ""))).trim();
|
|
929
|
-
function readPlan(data, previous) {
|
|
930
|
-
const area = value(data, "area"), milestone = value(data, "milestone"), parentId = value(data, "parentId"), dueAt = value(data, "dueAt");
|
|
931
|
-
return {
|
|
932
|
-
kind: value(data, "kind"),
|
|
933
|
-
..._optionalChain([previous, 'optionalAccess', _147 => _147.execution]) ? { execution: previous.execution } : {},
|
|
934
|
-
priority: Number(value(data, "priority")),
|
|
935
|
-
references: _nullishCoalesce(_optionalChain([previous, 'optionalAccess', _148 => _148.references]), () => ( [])),
|
|
936
|
-
dependencies: [...new Set(data.getAll("dependencies").flatMap((value2) => String(value2).split(",")).map((id) => id.trim()).filter(Boolean))],
|
|
937
|
-
...area ? { area } : {},
|
|
938
|
-
...milestone ? { milestone } : {},
|
|
939
|
-
...parentId ? { parentId } : {},
|
|
940
|
-
...dueAt ? { dueAt: new Date(dueAt).getTime() } : {}
|
|
941
|
-
};
|
|
942
|
-
}
|
|
943
|
-
function boardInput(data, actor, id) {
|
|
944
|
-
return {
|
|
945
|
-
id,
|
|
946
|
-
title: value(data, "title"),
|
|
947
|
-
scope: { kind: "system" },
|
|
948
|
-
members: [{ ...actor, responsibility: "Manage personal work", roles: ["worker", "reviewer", "coordinator"] }],
|
|
949
|
-
policy: { requireEstimate: data.has("requireEstimate"), review: "assignee" }
|
|
950
|
-
};
|
|
951
|
-
}
|
|
952
|
-
function formCommand(kind, data, board, item, id = _chunk6MN3H3YFcjs.randomUUID.call(void 0, )) {
|
|
953
|
-
if (kind === "item") return { type: "create-item", ...value(data, "launchMode") ? { launch: { mode: value(data, "launchMode") } } : {}, item: { id, title: value(data, "title"), responsibility: value(data, "responsibility"), acceptance: value(data, "acceptance"), ...value(data, "itemResource") ? { externalRefs: [JSON.parse(value(data, "itemResource"))] } : {} }, planning: readPlan(data) };
|
|
954
|
-
if (kind === "record") {
|
|
955
|
-
const sessionId = value(data, "sourceSession"), messageId = value(data, "sourceMessage"), revision = value(data, "sourceRevision");
|
|
956
|
-
if ([sessionId, messageId, revision].some(Boolean) && ![sessionId, messageId, revision].every(Boolean)) throw Object.assign(new Error("Missing source fields"), { code: "SOURCE_FIELDS_REQUIRED" });
|
|
957
|
-
return { type: "append-record", record: {
|
|
958
|
-
id,
|
|
959
|
-
kind: value(data, "kind"),
|
|
960
|
-
title: value(data, "title"),
|
|
961
|
-
content: value(data, "content"),
|
|
962
|
-
externalRefs: data.getAll("recordResources").map((value2) => JSON.parse(String(value2))),
|
|
963
|
-
itemIds: [...new Set(data.getAll("itemIds").flatMap((value2) => String(value2).split(",")).map((id2) => id2.trim()).filter(Boolean))],
|
|
964
|
-
sources: sessionId ? [{ sessionId, messageId, revision, role: "user" }] : [],
|
|
965
|
-
...value(data, "rationale") ? { rationale: value(data, "rationale") } : {},
|
|
966
|
-
...value(data, "supersedes") ? { supersedes: value(data, "supersedes") } : {}
|
|
967
|
-
} };
|
|
968
|
-
}
|
|
969
|
-
if (!item) throw new Error("ITEM_NOT_FOUND");
|
|
970
|
-
const itemId = item.id, token = _nullishCoalesce(_optionalChain([item, 'access', _149 => _149.owner, 'optionalAccess', _150 => _150.token]), () => ( ""));
|
|
971
|
-
if (kind === "edit-item") return { type: "edit-item", itemId, title: value(data, "title"), responsibility: value(data, "responsibility"), acceptance: value(data, "acceptance") };
|
|
972
|
-
if (kind === "amendment") return { type: "review-amendment", itemId, amendmentId: value(data, "amendmentId"), accept: value(data, "decision") === "accept", reason: value(data, "reason") || void 0 };
|
|
973
|
-
if (kind === "claim") return { type: "claim", itemId, ...board.policy.requireEstimate !== false ? { estimate: estimate(data) } : {} };
|
|
974
|
-
if (kind === "close-plan") return { type: "close-plan", itemId, resultRef: value(data, "resultRef") };
|
|
975
|
-
if (kind === "submit") return { type: "submit", itemId, token, resultRef: value(data, "resultRef") };
|
|
976
|
-
if (kind === "plan") return { type: "plan-item", itemId, planning: readPlan(data, item.planning) };
|
|
977
|
-
if (kind === "cancel") return { type: "cancel-item", itemId, reason: value(data, "reason") };
|
|
978
|
-
if (kind === "release") return { type: "release-item", itemId, token, next: "backlog", reason: value(data, "reason") };
|
|
979
|
-
if (kind === "block") return { type: "block-item", itemId, token, reason: value(data, "reason") };
|
|
980
|
-
if (kind === "session") return { type: "register-session", itemId, sessionId: value(data, "sessionId"), role: "observer", subscribed: true };
|
|
981
|
-
if (kind === "message") return { type: "message", itemId, message: value(data, "message"), recipientSessionIds: item.participants.filter((p) => p.subscribed).map((p) => p.sessionId) };
|
|
982
|
-
throw new Error("UNKNOWN_COMMAND");
|
|
983
|
-
}
|
|
984
|
-
function estimate(data) {
|
|
985
|
-
return { complexity: Number(value(data, "complexity")), workUnits: Number(value(data, "workUnits")), durationMs: Number(value(data, "duration")) * 6e4, confidence: value(data, "confidence") };
|
|
986
|
-
}
|
|
987
|
-
function actionCommand(action, item) {
|
|
988
|
-
const itemId = item.id, token = _nullishCoalesce(_optionalChain([item, 'access', _151 => _151.owner, 'optionalAccess', _152 => _152.token]), () => ( ""));
|
|
989
|
-
if (action === "ready" || action === "defer") return { type: "set-stage", itemId, stage: action === "ready" ? "open" : "backlog" };
|
|
990
|
-
if (action === "publish") return { type: "publish-proposal", itemId };
|
|
991
|
-
if (action === "renew") return { type: "renew", itemId, token };
|
|
992
|
-
if (action === "accept" || action === "reject") return { type: "review", itemId, accept: action === "accept" };
|
|
993
|
-
if (action === "archive") return { type: "archive-items", itemIds: [itemId], reason: "manual" };
|
|
994
|
-
if (action === "restore") return { type: "restore-item", itemId };
|
|
995
|
-
if (action === "unblock") return { type: "unblock-item", itemId, token };
|
|
996
|
-
throw new Error("UNKNOWN_COMMAND");
|
|
997
|
-
}
|
|
998
|
-
|
|
999
|
-
// src/ui/index.ts
|
|
1000
|
-
var KanbanWorkbench = (_class4 = class {
|
|
1001
|
-
constructor(options, container) {;_class4.prototype.__init15.call(this);_class4.prototype.__init16.call(this);_class4.prototype.__init17.call(this);_class4.prototype.__init18.call(this);_class4.prototype.__init19.call(this);_class4.prototype.__init20.call(this);_class4.prototype.__init21.call(this);_class4.prototype.__init22.call(this);_class4.prototype.__init23.call(this);_class4.prototype.__init24.call(this);_class4.prototype.__init25.call(this);_class4.prototype.__init26.call(this);_class4.prototype.__init27.call(this);_class4.prototype.__init28.call(this);
|
|
1002
|
-
this.options = options;
|
|
1003
|
-
this.container = container;
|
|
1004
|
-
this.ui = createRenderer(options.presentation);
|
|
1005
|
-
}
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
__init15() {this.itemArchived = false}
|
|
1013
|
-
|
|
1014
|
-
__init16() {this.boardId = ""}
|
|
1015
|
-
|
|
1016
|
-
__init17() {this.recordId = ""}
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
__init18() {this.itemId = ""}
|
|
1022
|
-
__init19() {this.query = { view: "all", limit: 50 }}
|
|
1023
|
-
|
|
1024
|
-
__init20() {this.generation = 0}
|
|
1025
|
-
__init21() {this.eventGeneration = 0}
|
|
1026
|
-
__init22() {this.abort = new AbortController()}
|
|
1027
|
-
__init23() {this.busy = false}
|
|
1028
|
-
|
|
1029
|
-
__init24() {this.operationStage = "ui.operation"}
|
|
1030
|
-
__init25() {this.dirty = false}
|
|
1031
|
-
__init26() {this.visible = true}
|
|
1032
|
-
__init27() {this.invalid = false}
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
__init28() {this.windowMounts = /* @__PURE__ */ new Map()}
|
|
1037
|
-
async start() {
|
|
1038
|
-
const { sidebar, editor } = this.options, signal = this.abort.signal;
|
|
1039
|
-
_optionalChain([sidebar, 'optionalAccess', _153 => _153.classList, 'access', _154 => _154.add, 'call', _155 => _155("kanban__sidebar")]);
|
|
1040
|
-
editor.classList.add("kanban");
|
|
1041
|
-
editor.innerHTML = `<p data-status role="status"></p><p data-error role="alert"></p><div data-retry hidden>${this.ui.button("refresh", "retry")}</div><div data-content class="kanban__content"></div>${drawerMarkup(this.options.presentation)}`;
|
|
1042
|
-
this.drawer = new KanbanDrawer(editor, sidebar);
|
|
1043
|
-
this.suggestions = new KanbanSuggestions(editor, this.options.service, () => this.boardId, this.options.presentation);
|
|
1044
|
-
document.addEventListener("pointerdown", (event) => {
|
|
1045
|
-
for (const menu of editor.querySelectorAll("[data-popover][open]")) if (!menu.contains(event.target)) menu.open = false;
|
|
1046
|
-
}, { signal });
|
|
1047
|
-
editor.addEventListener("toggle", (event) => {
|
|
1048
|
-
const opened = event.target;
|
|
1049
|
-
if (opened instanceof HTMLDetailsElement && opened.open && opened.hasAttribute("data-related-sessions")) {
|
|
1050
|
-
void this.loadRelatedSessions();
|
|
1051
|
-
return;
|
|
1052
|
-
}
|
|
1053
|
-
if (opened instanceof HTMLDetailsElement && opened.open && opened.hasAttribute("data-work-resources")) {
|
|
1054
|
-
void this.loadWorkResources();
|
|
1055
|
-
return;
|
|
1056
|
-
}
|
|
1057
|
-
if (!(opened instanceof HTMLDetailsElement) || !opened.open || !opened.hasAttribute("data-popover")) return;
|
|
1058
|
-
for (const menu of editor.querySelectorAll("[data-popover][open]")) if (menu !== opened) menu.open = false;
|
|
1059
|
-
}, { capture: true, signal });
|
|
1060
|
-
editor.addEventListener("change", (event) => {
|
|
1061
|
-
const target = event.target;
|
|
1062
|
-
if (!(target instanceof HTMLSelectElement) || target.name !== "kind") return;
|
|
1063
|
-
const resource = _optionalChain([target, 'access', _156 => _156.closest, 'call', _157 => _157("form"), 'optionalAccess', _158 => _158.querySelector, 'call', _159 => _159('select[name="itemResource"]')]);
|
|
1064
|
-
if (resource) resource.required = resource.dataset.resourceRequired === "true" && _optionalChain([target, 'access', _160 => _160.selectedOptions, 'access', _161 => _161[0], 'optionalAccess', _162 => _162.dataset, 'access', _163 => _163.executable]) === "true";
|
|
1065
|
-
}, { signal });
|
|
1066
|
-
editor.addEventListener("keydown", (event) => {
|
|
1067
|
-
const menu = editor.querySelector("[data-popover][open]");
|
|
1068
|
-
if (event.key === "Escape" && menu) {
|
|
1069
|
-
event.preventDefault();
|
|
1070
|
-
event.stopPropagation();
|
|
1071
|
-
menu.open = false;
|
|
1072
|
-
_optionalChain([menu, 'access', _164 => _164.querySelector, 'call', _165 => _165("summary"), 'optionalAccess', _166 => _166.focus, 'call', _167 => _167()]);
|
|
1073
|
-
return;
|
|
1074
|
-
}
|
|
1075
|
-
this.drawer.keydown(event);
|
|
1076
|
-
if (event.key === "Escape" && this.drawer.open) {
|
|
1077
|
-
event.preventDefault();
|
|
1078
|
-
void this.run(() => this.requestClose(false));
|
|
1079
|
-
}
|
|
1080
|
-
}, { signal });
|
|
1081
|
-
for (const element of sidebar ? [sidebar, editor] : [editor]) element.addEventListener("click", (event) => {
|
|
1082
|
-
if (event instanceof MouseEvent && (event.ctrlKey || event.metaKey || event.shiftKey || event.altKey || event.button !== 0)) return;
|
|
1083
|
-
if (!event.target.closest("[data-action], [data-board], [data-item], [data-session], [data-record], [data-context]")) return;
|
|
1084
|
-
void this.run(async () => {
|
|
1085
|
-
await this.click(event);
|
|
1086
|
-
if (element === sidebar) _optionalChain([this, 'access', _168 => _168.options, 'access', _169 => _169.activated, 'optionalCall', _170 => _170()]);
|
|
1087
|
-
});
|
|
1088
|
-
}, { signal });
|
|
1089
|
-
_optionalChain([sidebar, 'optionalAccess', _171 => _171.addEventListener, 'call', _172 => _172("submit", (event) => {
|
|
1090
|
-
event.preventDefault();
|
|
1091
|
-
void this.run(() => this.submit(event));
|
|
1092
|
-
}, { signal })]);
|
|
1093
|
-
editor.addEventListener("submit", (event) => {
|
|
1094
|
-
event.preventDefault();
|
|
1095
|
-
void this.run(() => this.submit(event));
|
|
1096
|
-
}, { signal });
|
|
1097
|
-
editor.addEventListener("change", (event) => {
|
|
1098
|
-
const target = event.target;
|
|
1099
|
-
if (target.name === "preparation" && this.board && this.automationCatalog) {
|
|
1100
|
-
const container = editor.querySelector("[data-preparation-options]");
|
|
1101
|
-
if (container) container.innerHTML = preparationFields(this.board, this.automationCatalog, target.value ? JSON.parse(target.value) : null);
|
|
1102
|
-
}
|
|
1103
|
-
}, { signal });
|
|
1104
|
-
editor.addEventListener("input", (event) => {
|
|
1105
|
-
const target = event.target;
|
|
1106
|
-
if (target.closest("[data-form=reference]")) return;
|
|
1107
|
-
if (target.closest("form")) this.generation++;
|
|
1108
|
-
if (target.closest("[data-panel]")) {
|
|
1109
|
-
this.dirty = true;
|
|
1110
|
-
_optionalChain([this, 'access', _173 => _173.options, 'access', _174 => _174.changed, 'optionalCall', _175 => _175()]);
|
|
1111
|
-
}
|
|
1112
|
-
}, { signal });
|
|
1113
|
-
this.activityTimer = setInterval(() => {
|
|
1114
|
-
if (!this.visible || document.hidden) return;
|
|
1115
|
-
updateTaskCountdowns(this.options.editor, this.options.presentation);
|
|
1116
|
-
if (_optionalChain([this, 'access', _176 => _176.options, 'access', _177 => _177.service, 'optionalAccess', _178 => _178.queryActivity]) && (_optionalChain([this, 'access', _179 => _179.board, 'optionalAccess', _180 => _180.automation, 'optionalAccess', _181 => _181.enabled]) || _optionalChain([this, 'access', _182 => _182.page, 'optionalAccess', _183 => _183.items, 'access', _184 => _184.some, 'call', _185 => _185((item) => item.execution)]) || this.query.execution && this.query.execution !== "all")) this.refreshInBackground(true);
|
|
1117
|
-
}, 15e3);
|
|
1118
|
-
if (this.options.initialResource !== void 0) await this.openResource(this.options.initialResource);
|
|
1119
|
-
else await this.run(() => this.refresh());
|
|
1120
|
-
}
|
|
1121
|
-
open(target) {
|
|
1122
|
-
const path = target.boardId ? `/board/${encodeURIComponent(target.boardId)}${target.recordId ? "/@record/" + encodeURIComponent(target.recordId) : target.itemId ? "/" + encodeURIComponent(target.itemId) : ""}` : "/";
|
|
1123
|
-
return this.openResource(path);
|
|
1124
|
-
}
|
|
1125
|
-
dispose() {
|
|
1126
|
-
return this.destroy();
|
|
1127
|
-
}
|
|
1128
|
-
async openResource(path) {
|
|
1129
|
-
if (this.busy || this.dirty) throw new Error(this.ui.label("unsaved"));
|
|
1130
|
-
this.closePanel();
|
|
1131
|
-
const parts = path.split("/");
|
|
1132
|
-
this.boardId = decodeURIComponent(_nullishCoalesce(parts[2], () => ( "")));
|
|
1133
|
-
this.itemId = decodeURIComponent(_nullishCoalesce(parts[3], () => ( "")));
|
|
1134
|
-
this.recordId = parts[3] === "@record" ? decodeURIComponent(_nullishCoalesce(parts[4], () => ( ""))) : "";
|
|
1135
|
-
if (this.recordId) this.itemId = "";
|
|
1136
|
-
this.recordKind = ["@log", "@decision"].includes(_nullishCoalesce(parts[3], () => ( ""))) ? parts[3].slice(1) : void 0;
|
|
1137
|
-
if (this.recordKind) this.itemId = "";
|
|
1138
|
-
this.recordCursor = void 0;
|
|
1139
|
-
this.query = { view: "all", limit: 50 };
|
|
1140
|
-
await this.run(() => this.refresh());
|
|
1141
|
-
}
|
|
1142
|
-
createBoard() {
|
|
1143
|
-
return this.run(async () => {
|
|
1144
|
-
if (this.dirty) throw new Error(this.ui.label("unsaved"));
|
|
1145
|
-
this.showBoardForm();
|
|
1146
|
-
});
|
|
1147
|
-
}
|
|
1148
|
-
showBoardForm() {
|
|
1149
|
-
this.itemId = "";
|
|
1150
|
-
this.drawer.show(this.ui.newBoardForm(), "new-board");
|
|
1151
|
-
this.dirty = true;
|
|
1152
|
-
}
|
|
1153
|
-
getActiveResourceId() {
|
|
1154
|
-
return this.boardId ? `/board/${encodeURIComponent(this.boardId)}${this.recordId ? "/@record/" + encodeURIComponent(this.recordId) : this.itemId ? "/" + encodeURIComponent(this.itemId) : this.recordKind ? "/@" + this.recordKind : ""}` : "/";
|
|
1155
|
-
}
|
|
1156
|
-
getViewState() {
|
|
1157
|
-
return {
|
|
1158
|
-
title: _optionalChain([this, 'access', _186 => _186.drawer, 'optionalAccess', _187 => _187.open]) ? _nullishCoalesce(_optionalChain([this, 'access', _188 => _188.panel, 'call', _189 => _189(), 'access', _190 => _190.querySelector, 'call', _191 => _191("h3"), 'optionalAccess', _192 => _192.textContent]), () => ( _optionalChain([this, 'access', _193 => _193.board, 'optionalAccess', _194 => _194.title]))) : _nullishCoalesce(_optionalChain([this, 'access', _195 => _195.board, 'optionalAccess', _196 => _196.title]), () => ( this.ui.label("title"))),
|
|
1159
|
-
context: _optionalChain([this, 'access', _197 => _197.board, 'optionalAccess', _198 => _198.title]),
|
|
1160
|
-
dirty: this.dirty,
|
|
1161
|
-
busy: this.busy
|
|
1162
|
-
};
|
|
1163
|
-
}
|
|
1164
|
-
captureRecovery() {
|
|
1165
|
-
if (this.busy || this.dirty) throw new Error(this.ui.label("unsaved"));
|
|
1166
|
-
return null;
|
|
1167
|
-
}
|
|
1168
|
-
restoreRecovery() {
|
|
1169
|
-
}
|
|
1170
|
-
suspendForRecovery() {
|
|
1171
|
-
this.generation++;
|
|
1172
|
-
this.abort.abort();
|
|
1173
|
-
_optionalChain([this, 'access', _199 => _199.suggestions, 'optionalAccess', _200 => _200.destroy, 'call', _201 => _201()]);
|
|
1174
|
-
if (this.activityTimer) clearInterval(this.activityTimer);
|
|
1175
|
-
}
|
|
1176
|
-
async destroy() {
|
|
1177
|
-
for (const release of this.windowMounts.values()) release();
|
|
1178
|
-
this.windowMounts.clear();
|
|
1179
|
-
this.suspendForRecovery();
|
|
1180
|
-
_optionalChain([this, 'access', _202 => _202.releaseNavigation, 'optionalCall', _203 => _203()]);
|
|
1181
|
-
this.releaseNavigation = void 0;
|
|
1182
|
-
_optionalChain([this, 'access', _204 => _204.suggestions, 'optionalAccess', _205 => _205.destroy, 'call', _206 => _206()]);
|
|
1183
|
-
_optionalChain([this, 'access', _207 => _207.drawer, 'optionalAccess', _208 => _208.destroy, 'call', _209 => _209()]);
|
|
1184
|
-
_optionalChain([this, 'access', _210 => _210.options, 'access', _211 => _211.sidebar, 'optionalAccess', _212 => _212.replaceChildren, 'call', _213 => _213()]);
|
|
1185
|
-
this.options.editor.replaceChildren();
|
|
1186
|
-
this.options.editor.inert = false;
|
|
1187
|
-
this.options.editor.classList.remove("kanban");
|
|
1188
|
-
_optionalChain([this, 'access', _214 => _214.options, 'access', _215 => _215.sidebar, 'optionalAccess', _216 => _216.classList, 'access', _217 => _217.remove, 'call', _218 => _218("kanban__sidebar")]);
|
|
1189
|
-
_optionalChain([this, 'access', _219 => _219.container, 'optionalAccess', _220 => _220.replaceChildren, 'call', _221 => _221()]);
|
|
1190
|
-
_optionalChain([this, 'access', _222 => _222.container, 'optionalAccess', _223 => _223.classList, 'access', _224 => _224.remove, 'call', _225 => _225("kanban-layout")]);
|
|
1191
|
-
}
|
|
1192
|
-
invalidateFromEvents() {
|
|
1193
|
-
this.invalid = true;
|
|
1194
|
-
this.eventGeneration++;
|
|
1195
|
-
this.refreshInBackground();
|
|
1196
|
-
}
|
|
1197
|
-
setVisible(visible) {
|
|
1198
|
-
this.visible = visible;
|
|
1199
|
-
if (visible && this.invalid) this.invalidateFromEvents();
|
|
1200
|
-
}
|
|
1201
|
-
refreshInBackground(activityOnly = false) {
|
|
1202
|
-
if (this.background || this.busy || this.dirty || !this.visible || this.abort.signal.aborted) return;
|
|
1203
|
-
if (_optionalChain([document, 'access', _226 => _226.activeElement, 'optionalAccess', _227 => _227.closest, 'call', _228 => _228("form")]) && this.options.editor.contains(document.activeElement)) return;
|
|
1204
|
-
const started = Date.now(), operationId = _chunk6MN3H3YFcjs.randomUUID.call(void 0, );
|
|
1205
|
-
const reading = activityOnly ? this.refreshActivity(this.generation) : this.refresh(), generation = this.generation;
|
|
1206
|
-
this.background = reading.catch((error) => {
|
|
1207
|
-
if (!this.alive(generation)) return;
|
|
1208
|
-
this.invalid = false;
|
|
1209
|
-
if (!this.abort.signal.aborted) {
|
|
1210
|
-
this.reportRead("ui.background", error, operationId, started);
|
|
1211
|
-
this.error(errorText(error, this.ui.label, "ui.background"));
|
|
1212
|
-
}
|
|
1213
|
-
}).finally(() => {
|
|
1214
|
-
this.background = void 0;
|
|
1215
|
-
if (this.invalid && !this.busy && !this.dirty && this.visible && !this.abort.signal.aborted) this.refreshInBackground();
|
|
1216
|
-
});
|
|
1217
|
-
}
|
|
1218
|
-
queryPage() {
|
|
1219
|
-
const service = this.options.service;
|
|
1220
|
-
return this.query.execution && this.query.execution !== "all" && service.queryActivity ? service.queryActivity(this.boardId, this.query) : service.query(this.boardId, this.query);
|
|
1221
|
-
}
|
|
1222
|
-
async refreshActivity(generation) {
|
|
1223
|
-
if (this.item && this.itemId) {
|
|
1224
|
-
await Promise.all([this.loadExecutionSections(generation, this.item, this.itemArchived), _optionalChain([this, 'access', _229 => _229.operations, 'optionalAccess', _230 => _230.operations, 'access', _231 => _231.some, 'call', _232 => _232((operation) => ["running", "unknown"].includes(operation.state))]) ? this.loadOperations(generation) : void 0]);
|
|
1225
|
-
return;
|
|
1226
|
-
}
|
|
1227
|
-
if (!this.board || this.recordId || this.recordKind || !_optionalChain([this, 'access', _233 => _233.options, 'access', _234 => _234.service, 'optionalAccess', _235 => _235.queryActivity])) return;
|
|
1228
|
-
await this.supplement("ui.activity", generation, () => this.options.service.queryActivity(this.boardId, this.query), (page) => {
|
|
1229
|
-
if (page.revision !== _optionalChain([this, 'access', _236 => _236.page, 'optionalAccess', _237 => _237.revision])) {
|
|
1230
|
-
this.invalid = true;
|
|
1231
|
-
this.refreshInBackground();
|
|
1232
|
-
return;
|
|
1233
|
-
}
|
|
1234
|
-
if (JSON.stringify(page) === JSON.stringify(this.page)) return;
|
|
1235
|
-
const sameItems = page.total === this.page.total && page.nextCursor === this.page.nextCursor && JSON.stringify(page.items.map((item) => item.id)) === JSON.stringify(this.page.items.map((item) => item.id));
|
|
1236
|
-
this.page = page;
|
|
1237
|
-
if (sameItems) {
|
|
1238
|
-
const sessions = new Map(page.items.map((item) => [item.id, item.execution]));
|
|
1239
|
-
for (const slot of this.content().querySelectorAll("[data-item-execution]")) {
|
|
1240
|
-
const html = this.ui.executionBadge(sessions.get(slot.dataset.itemExecution), this.options.sessionUrl);
|
|
1241
|
-
if (slot.innerHTML !== html) slot.innerHTML = html;
|
|
1242
|
-
}
|
|
1243
|
-
return;
|
|
1244
|
-
}
|
|
1245
|
-
preserveBoardScroll(this.content(), () => {
|
|
1246
|
-
this.content().innerHTML = this.ui.boardView(this.board, page, this.query, true, !!_optionalChain([this, 'access', _238 => _238.options, 'access', _239 => _239.service, 'optionalAccess', _240 => _240.automationCatalog]), this.options.sessionUrl);
|
|
1247
|
-
});
|
|
1248
|
-
this.mountHeaderActions();
|
|
1249
|
-
});
|
|
1250
|
-
}
|
|
1251
|
-
async refresh() {
|
|
1252
|
-
const service = this.options.service, generation = ++this.generation, events = this.eventGeneration;
|
|
1253
|
-
if (!service) {
|
|
1254
|
-
this.content().innerHTML = `<p>${escapeHTML(this.ui.label("unavailable"))}</p>`;
|
|
1255
|
-
return;
|
|
1256
|
-
}
|
|
1257
|
-
this.operationStage = "ui.snapshot";
|
|
1258
|
-
const pageRequest = this.boardId ? this.queryPage() : void 0;
|
|
1259
|
-
const itemRequest = this.boardId && this.itemId ? service.item(this.boardId, this.itemId) : void 0;
|
|
1260
|
-
const [boards, actor, initialPage, initialItem] = await Promise.all([_nullishCoalesce(_optionalChain([service, 'access', _241 => _241.catalog, 'optionalCall', _242 => _242()]), () => ( service.list())), service.currentPrincipal(), pageRequest, itemRequest]);
|
|
1261
|
-
if (!this.alive(generation)) return;
|
|
1262
|
-
this.actor = actor;
|
|
1263
|
-
if (!this.boardId && this.options.initialResource === void 0) this.boardId = _nullishCoalesce(_optionalChain([boards, 'access', _243 => _243[0], 'optionalAccess', _244 => _244.id]), () => ( ""));
|
|
1264
|
-
this.board = boards.find((board) => board.id === this.boardId);
|
|
1265
|
-
if (this.boardId && !this.board) throw Object.assign(new Error("Board unavailable"), { code: "BOARD_NOT_FOUND" });
|
|
1266
|
-
if (this.query.execution && this.query.execution !== "all" && !service.queryActivity) throw Object.assign(new Error("Execution Session projection unavailable"), { code: "EXECUTION_SESSION_UNAVAILABLE" });
|
|
1267
|
-
const page = this.board ? await _asyncNullishCoalesce(initialPage, async () => ( await this.queryPage())) : void 0;
|
|
1268
|
-
if (!this.alive(generation)) return;
|
|
1269
|
-
this.page = page;
|
|
1270
|
-
this.invalid = events !== this.eventGeneration;
|
|
1271
|
-
if (this.options.sidebar) this.options.sidebar.innerHTML = this.ui.navigation(boards, this.boardId);
|
|
1272
|
-
this.operationStage = "ui.render";
|
|
1273
|
-
preserveBoardScroll(this.content(), () => {
|
|
1274
|
-
this.content().innerHTML = this.board && page ? this.ui.boardView(this.board, page, this.query, !!service.queryActivity, !!service.automationCatalog, this.options.sessionUrl) : this.ui.catalogView(boards);
|
|
1275
|
-
});
|
|
1276
|
-
if (this.recordKind) await this.showRecords(generation);
|
|
1277
|
-
if (!this.alive(generation)) return;
|
|
1278
|
-
_optionalChain([this, 'access', _245 => _245.releaseNavigation, 'optionalCall', _246 => _246()]);
|
|
1279
|
-
this.releaseNavigation = void 0;
|
|
1280
|
-
const navigation2 = this.content().querySelector("[data-navigation]");
|
|
1281
|
-
if (navigation2 && !this.options.mountTitleBar) this.releaseNavigation = _optionalChain([this, 'access', _247 => _247.options, 'access', _248 => _248.mountNavigation, 'optionalCall', _249 => _249(navigation2)]);
|
|
1282
|
-
if (this.recordId) await this.showRecord(this.recordId, generation);
|
|
1283
|
-
else if (this.itemId) await this.showItem(generation, initialItem);
|
|
1284
|
-
else if (!this.recordKind) void this.refreshActivity(generation);
|
|
1285
|
-
this.mountHeaderActions();
|
|
1286
|
-
this.operationStage = "ui.selection";
|
|
1287
|
-
this.options.selected(this.getActiveResourceId());
|
|
1288
|
-
}
|
|
1289
|
-
async showItem(generation = this.generation, loaded) {
|
|
1290
|
-
const service = this.options.service;
|
|
1291
|
-
if (!service || !this.board || !this.itemId) return;
|
|
1292
|
-
this.operationStage = "ui.item.load";
|
|
1293
|
-
const { item, archive, task } = await _asyncNullishCoalesce(loaded, async () => ( await service.item(this.boardId, this.itemId)));
|
|
1294
|
-
if (!this.alive(generation)) return;
|
|
1295
|
-
this.operationStage = "ui.item.render";
|
|
1296
|
-
const referencesChanged = _optionalChain([this, 'access', _250 => _250.item, 'optionalAccess', _251 => _251.id]) === item.id && JSON.stringify(this.item.externalRefs) !== JSON.stringify(item.externalRefs);
|
|
1297
|
-
if (!this.drawer.open || this.itemArchived !== !!archive || JSON.stringify(this.item) !== JSON.stringify(item)) this.drawer.show(this.ui.detailView(this.board, item, this.actor, !!archive, [], !!service.executionSession, _optionalChain([this, 'access', _252 => _252.options, 'access', _253 => _253.reviewGuidance, 'optionalCall', _254 => _254(this.board, item)]), !!service.itemOperations && !archive && (_nullishCoalesce(_optionalChain([this, 'access', _255 => _255.options, 'access', _256 => _256.itemOperationsAvailable, 'optionalCall', _257 => _257(this.board, item)]), () => ( true))), _nullishCoalesce(task, () => ( _chunkKYNYPKKHcjs.projectKanbanTask.call(void 0, item))), !!service.fixTask), "item:" + item.id);
|
|
1298
|
-
this.item = item;
|
|
1299
|
-
this.itemArchived = !!archive;
|
|
1300
|
-
this.loadItemSections(generation, item, !!archive);
|
|
1301
|
-
const resources = this.panel().querySelector("[data-work-resources]");
|
|
1302
|
-
if (referencesChanged && resources) {
|
|
1303
|
-
resources.dataset.associationRevision = String(Number(_nullishCoalesce(resources.dataset.associationRevision, () => ( 0))) + 1);
|
|
1304
|
-
delete resources.dataset.loaded;
|
|
1305
|
-
if (resources.open) void this.loadWorkResources(false, true);
|
|
1306
|
-
}
|
|
1307
|
-
this.options.selected(this.getActiveResourceId());
|
|
1308
|
-
}
|
|
1309
|
-
loadItemSections(generation, item, archived) {
|
|
1310
|
-
const service = this.options.service, boardId = this.boardId;
|
|
1311
|
-
if (service.executionSession && !this.panel().querySelector("[data-related-sessions]"))
|
|
1312
|
-
this.setSection("[data-related-sessions-section]", `<details data-related-sessions><summary>${escapeHTML(this.ui.label("relatedSessions"))}</summary><button type="button" data-action="refresh-related-sessions">${escapeHTML(this.ui.label("refresh"))}</button><div data-related-sessions-body></div></details>`);
|
|
1313
|
-
if (service.workResources) {
|
|
1314
|
-
const resources = this.panel().querySelector("[data-work-resources]");
|
|
1315
|
-
if (!resources) this.setSection("[data-work-resource-section]", `<details data-work-resources><summary>${escapeHTML(this.ui.label("workResourceTitle"))}</summary><p>${escapeHTML(this.ui.label("workResourceHelp"))}</p><div class="kanban__actions"><button type="button" data-action="refresh-work-resources">${escapeHTML(this.ui.label("refresh"))}</button><button type="button" data-action="inspect-work-resources">${escapeHTML(this.ui.label("inspectWorkResources"))}</button></div><div data-work-resource-body></div></details>`);
|
|
1316
|
-
}
|
|
1317
|
-
void this.supplement("ui.item.events", generation, () => service.events(boardId, 0, 200), (events) => {
|
|
1318
|
-
this.setSection("[data-item-events]", this.ui.itemEventsView(events.filter((event) => event.itemId === item.id).reverse()));
|
|
1319
|
-
}, "[data-item-events]");
|
|
1320
|
-
void this.supplement("ui.item.records", generation, () => service.records(boardId, { itemId: item.id, limit: 10 }), (records) => {
|
|
1321
|
-
this.setSection("[data-related-records]", `<h4>${escapeHTML(this.ui.label("relatedRecords"))} (${records.total})</h4>${this.ui.recordLinks(records, this.board)}<div class="kanban__actions">${this.ui.button("new-log", "newLog")}${this.ui.button("new-decision", "newDecision")}</div>`);
|
|
1322
|
-
}, "[data-related-records]");
|
|
1323
|
-
void this.loadOperations(generation);
|
|
1324
|
-
void this.loadExecutionSections(generation, item, archived, true);
|
|
1325
|
-
if (!service.executionSession) this.loadReferenceSection(generation, item);
|
|
1326
|
-
void this.supplement("ui.item.children", generation, () => this.showChildren(generation), () => {
|
|
1327
|
-
}, "[data-children]");
|
|
1328
|
-
}
|
|
1329
|
-
async loadExecutionSections(generation, item, archived, references = false) {
|
|
1330
|
-
const service = this.options.service, boardId = this.boardId, reads = [];
|
|
1331
|
-
if (service.executionSession) reads.push(this.supplement("ui.item.session", generation, () => service.executionSession(boardId, item.id), (execution) => {
|
|
1332
|
-
this.setSection("[data-execution-session]", this.ui.executionSessionView(execution, !!this.options.executionReference && !archived && !["completed", "cancelled"].includes(item.status) && _optionalChain([item, 'access', _258 => _258.launch, 'optionalAccess', _259 => _259.admittedAt]) === void 0, this.options.sessionUrl));
|
|
1333
|
-
if (references) this.loadReferenceSection(generation, item, new Set(execution.history.map((binding) => binding.sessionId)));
|
|
1334
|
-
}, "[data-execution-session]"));
|
|
1335
|
-
if (_optionalChain([this, 'access', _260 => _260.board, 'optionalAccess', _261 => _261.automation]) && service.analysisStatus) reads.push(this.supplement("ui.item.analysis", generation, () => service.analysisStatus(boardId, item.id), (analysis) => {
|
|
1336
|
-
this.setSection("[data-analysis]", analysisView(this.options.presentation, _nullishCoalesce(analysis, () => ( null))));
|
|
1337
|
-
}, "[data-analysis]"));
|
|
1338
|
-
await Promise.all(reads);
|
|
1339
|
-
}
|
|
1340
|
-
async loadOperations(generation) {
|
|
1341
|
-
const service = this.options.service, item = this.item;
|
|
1342
|
-
if (!_optionalChain([service, 'optionalAccess', _262 => _262.itemOperations]) || !item || !this.panel().querySelector("[data-item-operations]")) return;
|
|
1343
|
-
await this.supplement("ui.item.operations", generation, () => service.itemOperations(this.boardId, item.id), (view) => {
|
|
1344
|
-
this.operations = view;
|
|
1345
|
-
this.setSection("[data-item-operations]", itemOperationsView(this.options.presentation, view, this.options.sessionUrl));
|
|
1346
|
-
}, "[data-item-operations]");
|
|
1347
|
-
}
|
|
1348
|
-
async submitOperation(form, data, binding) {
|
|
1349
|
-
const service = this.options.service, action = form.dataset.operation, itemId = this.item.id;
|
|
1350
|
-
const request = { operationId: form.dataset.resourceId, itemId, action, expectedRevision: form.dataset.revision };
|
|
1351
|
-
const entry = _optionalChain([this, 'access', _263 => _263.operations, 'optionalAccess', _264 => _264.operations, 'access', _265 => _265.find, 'call', _266 => _266((operation) => operation.id === action)]);
|
|
1352
|
-
this.operationStage = binding ? "ui.operation.bind" : "ui.operation.start";
|
|
1353
|
-
const view = binding ? await service.bindItemOperation(this.boardId, { ...request, target: JSON.parse(value(data, "target")) }) : await service.runItemOperation(this.boardId, {
|
|
1354
|
-
...request,
|
|
1355
|
-
confirmed: data.has("confirmed"),
|
|
1356
|
-
selections: Object.fromEntries((_nullishCoalesce(_optionalChain([entry, 'optionalAccess', _267 => _267.fields]), () => ( []))).map((field2) => [field2.id, value(data, "choice-" + field2.id)]))
|
|
1357
|
-
});
|
|
1358
|
-
this.dirty = false;
|
|
1359
|
-
this.operations = view;
|
|
1360
|
-
_optionalChain([this, 'access', _268 => _268.options, 'access', _269 => _269.committed, 'optionalCall', _270 => _270()]);
|
|
1361
|
-
this.setSection("[data-item-operations]", itemOperationsView(this.options.presentation, view, this.options.sessionUrl));
|
|
1362
|
-
_optionalChain([this, 'access', _271 => _271.options, 'access', _272 => _272.changed, 'optionalCall', _273 => _273()]);
|
|
1363
|
-
const result = view.operations.find((operation) => operation.id === action);
|
|
1364
|
-
if (!binding && _optionalChain([result, 'optionalAccess', _274 => _274.state]) === "succeeded") await this.refresh();
|
|
1365
|
-
if (!binding && _optionalChain([entry, 'optionalAccess', _275 => _275.openSessionOnRun]) && _optionalChain([result, 'optionalAccess', _276 => _276.sessionId])) await this.options.openSession(result.sessionId);
|
|
1366
|
-
}
|
|
1367
|
-
loadReferenceSection(generation, item, skip) {
|
|
1368
|
-
void this.supplement("ui.item.references", generation, () => this.showReferenceLinks(_nullishCoalesce(item.externalRefs, () => ( [])), generation, skip), () => {
|
|
1369
|
-
}, "[data-reference-links]");
|
|
1370
|
-
}
|
|
1371
|
-
async supplement(stage, generation, read, apply, selector) {
|
|
1372
|
-
const started = Date.now(), operationId = _chunk6MN3H3YFcjs.randomUUID.call(void 0, );
|
|
1373
|
-
try {
|
|
1374
|
-
const value2 = await read();
|
|
1375
|
-
if (!this.alive(generation) || this.dirty) return;
|
|
1376
|
-
apply(value2);
|
|
1377
|
-
try {
|
|
1378
|
-
_optionalChain([this, 'access', _277 => _277.options, 'access', _278 => _278.presentation, 'access', _279 => _279.log, 'optionalCall', _280 => _280({ operationId, stage, result: "success", durationMs: Date.now() - started })]);
|
|
1379
|
-
} catch (e3) {
|
|
1380
|
-
}
|
|
1381
|
-
} catch (error) {
|
|
1382
|
-
if (!this.alive(generation)) return;
|
|
1383
|
-
this.reportRead(stage, error, operationId, started);
|
|
1384
|
-
const slot = selector ? this.panel().querySelector(selector) : void 0;
|
|
1385
|
-
if (slot) {
|
|
1386
|
-
const notice = _nullishCoalesce(slot.querySelector("[data-read-error]"), () => ( document.createElement("p")));
|
|
1387
|
-
notice.setAttribute("role", "alert");
|
|
1388
|
-
notice.setAttribute("data-read-error", "");
|
|
1389
|
-
notice.textContent = errorText(error, this.ui.label, stage);
|
|
1390
|
-
if (!notice.parentElement) slot.append(notice);
|
|
1391
|
-
} else this.error(errorText(error, this.ui.label, stage));
|
|
1392
|
-
}
|
|
1393
|
-
}
|
|
1394
|
-
setSection(selector, html) {
|
|
1395
|
-
const slot = this.panel().querySelector(selector);
|
|
1396
|
-
if (slot && slot.innerHTML !== html) slot.innerHTML = html;
|
|
1397
|
-
}
|
|
1398
|
-
reportRead(stage, error, operationId = _chunk6MN3H3YFcjs.randomUUID.call(void 0, ), started = Date.now()) {
|
|
1399
|
-
const raw = _optionalChain([error, 'optionalAccess', _281 => _281.code]);
|
|
1400
|
-
try {
|
|
1401
|
-
_optionalChain([this, 'access', _282 => _282.options, 'access', _283 => _283.presentation, 'access', _284 => _284.log, 'optionalCall', _285 => _285({ operationId, stage, result: "failure", ...failureDetails(error), code: typeof raw === "string" && /^[A-Z][A-Z0-9_]{0,79}$/.test(raw) ? raw : "KANBAN_OPERATION_FAILED", durationMs: Date.now() - started })]);
|
|
1402
|
-
} catch (e4) {
|
|
1403
|
-
}
|
|
1404
|
-
}
|
|
1405
|
-
async showChildren(generation, cursor) {
|
|
1406
|
-
const { service } = this.options, item = this.item, board = this.board;
|
|
1407
|
-
if (!service || !item || !board || !childType(board, item)) return;
|
|
1408
|
-
const query = { parentId: item.id, view: "all", limit: 50, ...cursor ? { cursor } : {} };
|
|
1409
|
-
const page = await (_nullishCoalesce(_optionalChain([service, 'access', _286 => _286.queryActivity, 'optionalCall', _287 => _287(board.id, query)]), () => ( service.query(board.id, query))));
|
|
1410
|
-
if (!this.alive(generation)) return;
|
|
1411
|
-
this.panel().querySelector("[data-children]").innerHTML = childrenView(this.options.presentation, page, cursor, !["completed", "cancelled"].includes(item.status) && !item.closedAt, this.options.sessionUrl);
|
|
1412
|
-
}
|
|
1413
|
-
async showRecords(generation) {
|
|
1414
|
-
if (!this.recordKind || !this.options.service) return;
|
|
1415
|
-
let page;
|
|
1416
|
-
try {
|
|
1417
|
-
page = await this.options.service.records(this.boardId, { kind: this.recordKind, limit: 50, ...this.recordCursor ? { cursor: this.recordCursor } : {} });
|
|
1418
|
-
} catch (error) {
|
|
1419
|
-
if (_optionalChain([error, 'optionalAccess', _288 => _288.code]) !== "CURSOR_STALE" || !this.recordCursor) throw error;
|
|
1420
|
-
this.recordCursor = void 0;
|
|
1421
|
-
page = await this.options.service.records(this.boardId, { kind: this.recordKind, limit: 50 });
|
|
1422
|
-
}
|
|
1423
|
-
if (!this.alive(generation)) return;
|
|
1424
|
-
this.recordPage = page;
|
|
1425
|
-
this.content().innerHTML = this.ui.recordsView(page, this.recordKind, !!this.recordCursor, this.board);
|
|
1426
|
-
}
|
|
1427
|
-
async showRecord(id, generation = this.generation) {
|
|
1428
|
-
if (!this.options.service) return;
|
|
1429
|
-
const record = await this.options.service.record(this.boardId, id);
|
|
1430
|
-
const executions = record.kind === "decision" ? await _optionalChain([this, 'access', _289 => _289.options, 'access', _290 => _290.service, 'access', _291 => _291.recordExecutions, 'optionalCall', _292 => _292(this.boardId, id)]) : void 0;
|
|
1431
|
-
if (!this.alive(generation)) return;
|
|
1432
|
-
this.recordId = id;
|
|
1433
|
-
this.drawer.show(this.ui.recordDetail(record, this.board, executions), "record:" + id);
|
|
1434
|
-
await this.showReferenceLinks(_nullishCoalesce(record.externalRefs, () => ( [])), generation);
|
|
1435
|
-
this.options.selected(this.getActiveResourceId());
|
|
1436
|
-
}
|
|
1437
|
-
async showReferenceLinks(references, generation, skip = /* @__PURE__ */ new Set()) {
|
|
1438
|
-
if (!this.options.referenceLink) return;
|
|
1439
|
-
const started = Date.now();
|
|
1440
|
-
const results = await Promise.allSettled(references.filter((ref) => !skip.has(ref.id)).map((ref) => this.options.referenceLink(ref)));
|
|
1441
|
-
if (!this.alive(generation)) return;
|
|
1442
|
-
const resolved = results.flatMap((result) => result.status === "fulfilled" && result.value ? [result.value] : []);
|
|
1443
|
-
const links = [...new Map(resolved.map((link) => [link.href, link])).values()];
|
|
1444
|
-
const slot = this.panel().querySelector("[data-reference-links]");
|
|
1445
|
-
if (slot) slot.innerHTML = links.map((link) => linkPair(this.options.presentation, link.href, link.label, link.sessionId)).join("");
|
|
1446
|
-
const errors = results.filter((result) => result.status === "rejected");
|
|
1447
|
-
if (errors.length) {
|
|
1448
|
-
const raw = _optionalChain([errors, 'access', _293 => _293[0], 'access', _294 => _294.reason, 'optionalAccess', _295 => _295.code]), code = typeof raw === "string" && /^[A-Z][A-Z0-9_]{0,79}$/.test(raw) ? raw : "SESSION_LINK_UNAVAILABLE";
|
|
1449
|
-
if (slot) {
|
|
1450
|
-
const error = document.createElement("p");
|
|
1451
|
-
error.setAttribute("role", "alert");
|
|
1452
|
-
error.textContent = this.ui.label("sessionLinkUnavailable") + " (" + code + ")";
|
|
1453
|
-
slot.append(error);
|
|
1454
|
-
}
|
|
1455
|
-
_optionalChain([this, 'access', _296 => _296.options, 'access', _297 => _297.presentation, 'access', _298 => _298.log, 'optionalCall', _299 => _299({ operationId: _chunk6MN3H3YFcjs.randomUUID.call(void 0, ), stage: "ui.reference-links", result: "failure", code, ...failureDetails(errors[0].reason), durationMs: Date.now() - started })]);
|
|
1456
|
-
}
|
|
1457
|
-
}
|
|
1458
|
-
async loadWorkResources(inspect = false, refresh = false) {
|
|
1459
|
-
const service = this.options.service, boardId = this.boardId, itemId = _optionalChain([this, 'access', _300 => _300.item, 'optionalAccess', _301 => _301.id]);
|
|
1460
|
-
const section = this.panel().querySelector("[data-work-resources]");
|
|
1461
|
-
if (!_optionalChain([service, 'optionalAccess', _302 => _302.workResources]) || !itemId || !section || section.dataset.loading || !refresh && section.dataset.loaded) return;
|
|
1462
|
-
const operationId = _chunk6MN3H3YFcjs.randomUUID.call(void 0, ), started = Date.now(), revision = section.dataset.associationRevision;
|
|
1463
|
-
section.dataset.loading = "true";
|
|
1464
|
-
if (!section.dataset.loaded) this.setSection("[data-work-resource-body]", `<p role="status">${escapeHTML(this.ui.label("loading"))}</p>`);
|
|
1465
|
-
try {
|
|
1466
|
-
const resources = await service.workResources(boardId, itemId, { inspect });
|
|
1467
|
-
if (this.abort.signal.aborted || !section.isConnected || _optionalChain([this, 'access', _303 => _303.item, 'optionalAccess', _304 => _304.id]) !== itemId || this.boardId !== boardId || revision !== section.dataset.associationRevision) return;
|
|
1468
|
-
this.setSection("[data-work-resource-body]", workResourcesView(this.options.presentation, resources));
|
|
1469
|
-
section.dataset.loaded = "true";
|
|
1470
|
-
} catch (error) {
|
|
1471
|
-
if (!section.isConnected || this.abort.signal.aborted) return;
|
|
1472
|
-
this.reportRead("ui.item.work-resources", error, operationId, started);
|
|
1473
|
-
const body = section.querySelector("[data-work-resource-body]"), notice = document.createElement("p");
|
|
1474
|
-
notice.setAttribute("role", "alert");
|
|
1475
|
-
notice.textContent = errorText(error, this.ui.label, "ui.item.work-resources");
|
|
1476
|
-
_optionalChain([body, 'optionalAccess', _305 => _305.append, 'call', _306 => _306(notice)]);
|
|
1477
|
-
} finally {
|
|
1478
|
-
delete section.dataset.loading;
|
|
1479
|
-
if (!this.abort.signal.aborted && section.isConnected && section.open && revision !== section.dataset.associationRevision) void this.loadWorkResources(false, true);
|
|
1480
|
-
}
|
|
1481
|
-
}
|
|
1482
|
-
async loadRelatedSessions(refresh = false) {
|
|
1483
|
-
const service = this.options.service, boardId = this.boardId, itemId = _optionalChain([this, 'access', _307 => _307.item, 'optionalAccess', _308 => _308.id]);
|
|
1484
|
-
const details = this.panel().querySelector("[data-related-sessions]");
|
|
1485
|
-
if (!_optionalChain([service, 'optionalAccess', _309 => _309.executionSession]) || !itemId || !details || details.dataset.loading || !refresh && details.dataset.loaded) return;
|
|
1486
|
-
details.dataset.loading = "true";
|
|
1487
|
-
this.setSection("[data-related-sessions-body]", `<p role="status">${escapeHTML(this.ui.label("loading"))}</p>`);
|
|
1488
|
-
try {
|
|
1489
|
-
await this.supplement("ui.item.related-sessions", this.generation, () => service.executionSession(boardId, itemId, { includeRelated: true }), (detail) => {
|
|
1490
|
-
if (_optionalChain([this, 'access', _310 => _310.item, 'optionalAccess', _311 => _311.id]) !== itemId || this.boardId !== boardId) return;
|
|
1491
|
-
this.setSection("[data-related-sessions-body]", relatedSessionsView(this.options.presentation, detail, this.options.sessionUrl));
|
|
1492
|
-
details.dataset.loaded = "true";
|
|
1493
|
-
}, "[data-related-sessions-body]");
|
|
1494
|
-
} finally {
|
|
1495
|
-
delete details.dataset.loading;
|
|
1496
|
-
}
|
|
1497
|
-
}
|
|
1498
|
-
async click(event) {
|
|
1499
|
-
const target = event.target.closest("button, a");
|
|
1500
|
-
if (!target || target.matches(":disabled")) return;
|
|
1501
|
-
if (target.dataset.action === "refresh-related-sessions") {
|
|
1502
|
-
await this.loadRelatedSessions(true);
|
|
1503
|
-
return;
|
|
1504
|
-
}
|
|
1505
|
-
for (const menu of this.options.editor.querySelectorAll("[data-popover][open]")) if (!menu.contains(target)) menu.open = false;
|
|
1506
|
-
if (target.dataset.session) {
|
|
1507
|
-
event.preventDefault();
|
|
1508
|
-
await this.options.openSession(target.dataset.session);
|
|
1509
|
-
return;
|
|
1510
|
-
}
|
|
1511
|
-
if (this.dirty && !["close-panel", "copy-reference", "copy-link", "copy-resource"].includes(_nullishCoalesce(target.dataset.action, () => ( "")))) throw new Error(this.ui.label("unsaved"));
|
|
1512
|
-
const path = this.navigationTarget(target);
|
|
1513
|
-
if (path && this.options.navigate) {
|
|
1514
|
-
await this.options.navigate(path);
|
|
1515
|
-
return;
|
|
1516
|
-
}
|
|
1517
|
-
if (target.dataset.board) {
|
|
1518
|
-
await this.navigate(target.dataset.board);
|
|
1519
|
-
return;
|
|
1520
|
-
}
|
|
1521
|
-
if (target.dataset.context) {
|
|
1522
|
-
this.recordKind = target.dataset.context === "board" ? void 0 : target.dataset.context;
|
|
1523
|
-
this.recordCursor = void 0;
|
|
1524
|
-
this.closePanel();
|
|
1525
|
-
await this.refresh();
|
|
1526
|
-
return;
|
|
1527
|
-
}
|
|
1528
|
-
if (target.dataset.record) {
|
|
1529
|
-
this.itemId = "";
|
|
1530
|
-
this.item = void 0;
|
|
1531
|
-
await this.showRecord(target.dataset.record);
|
|
1532
|
-
return;
|
|
1533
|
-
}
|
|
1534
|
-
if (target.dataset.item) {
|
|
1535
|
-
this.recordId = "";
|
|
1536
|
-
this.itemId = target.dataset.item;
|
|
1537
|
-
await this.showItem();
|
|
1538
|
-
return;
|
|
1539
|
-
}
|
|
1540
|
-
const action = target.dataset.action;
|
|
1541
|
-
if (action === "continue-execution" && this.item && target.dataset.dispatch) {
|
|
1542
|
-
await this.execute({ type: "continue-execution", previousDispatchId: target.dataset.dispatch, dispatchId: _chunk6MN3H3YFcjs.randomUUID.call(void 0, ) });
|
|
1543
|
-
return;
|
|
1544
|
-
}
|
|
1545
|
-
if (action === "refresh-work-resources" || action === "inspect-work-resources") {
|
|
1546
|
-
await this.loadWorkResources(action === "inspect-work-resources", true);
|
|
1547
|
-
return;
|
|
1548
|
-
}
|
|
1549
|
-
if (action === "cleanup-work-resource" && this.item && _optionalChain([this, 'access', _312 => _312.options, 'access', _313 => _313.service, 'optionalAccess', _314 => _314.cleanupWorkResource])) {
|
|
1550
|
-
if (!globalThis.confirm(this.ui.label("cleanupWorkResourceConfirm"))) return;
|
|
1551
|
-
try {
|
|
1552
|
-
await this.options.service.cleanupWorkResource(this.boardId, { operationId: _chunk6MN3H3YFcjs.randomUUID.call(void 0, ), itemId: this.item.id, resourceId: target.dataset.resource, version: target.dataset.version });
|
|
1553
|
-
} finally {
|
|
1554
|
-
await this.loadWorkResources(false, true);
|
|
1555
|
-
}
|
|
1556
|
-
return;
|
|
1557
|
-
}
|
|
1558
|
-
if (action === "close-panel" || action === "dismiss-panel") {
|
|
1559
|
-
await this.requestClose(action === "close-panel");
|
|
1560
|
-
return;
|
|
1561
|
-
}
|
|
1562
|
-
if (action === "copy-reference" || action === "copy-link" || action === "copy-resource") {
|
|
1563
|
-
await this.ui.copyReference(target.closest("[data-action]"));
|
|
1564
|
-
return;
|
|
1565
|
-
}
|
|
1566
|
-
if (action === "automation" && this.board && _optionalChain([this, 'access', _315 => _315.options, 'access', _316 => _316.service, 'optionalAccess', _317 => _317.automationCatalog])) {
|
|
1567
|
-
this.automationCatalog = await this.options.service.automationCatalog();
|
|
1568
|
-
this.itemId = "";
|
|
1569
|
-
this.drawer.show(automationForm(this.options.presentation, this.board, this.automationCatalog), "automation");
|
|
1570
|
-
this.dirty = true;
|
|
1571
|
-
return;
|
|
1572
|
-
}
|
|
1573
|
-
if (action === "task-edit" && this.item && this.board) {
|
|
1574
|
-
const editId = _chunk6MN3H3YFcjs.randomUUID.call(void 0, ), itemId = this.item.id;
|
|
1575
|
-
await this.execute({ type: "begin-edit", itemId, editId, leaseMs: 3e5 });
|
|
1576
|
-
this.editing = { itemId, editId };
|
|
1577
|
-
const resources = await _optionalChain([this, 'access', _318 => _318.options, 'access', _319 => _319.service, 'optionalAccess', _320 => _320.itemResources, 'optionalCall', _321 => _321(this.boardId)]);
|
|
1578
|
-
if (resources) resources.selected = _optionalChain([this, 'access', _322 => _322.item, 'access', _323 => _323.externalRefs, 'optionalAccess', _324 => _324.find, 'call', _325 => _325((ref) => resources.resources.some((r) => r.reference.system === ref.system && r.reference.id === ref.id))]);
|
|
1579
|
-
this.drawer.show(editTaskForm(this.options.presentation, this.board, this.item, editId, resources), "edit:" + itemId);
|
|
1580
|
-
this.dirty = true;
|
|
1581
|
-
return;
|
|
1582
|
-
}
|
|
1583
|
-
if (action === "task-fix" && this.item && _optionalChain([this, 'access', _326 => _326.options, 'access', _327 => _327.service, 'optionalAccess', _328 => _328.fixTask])) {
|
|
1584
|
-
target.dataset.operationId ??= _chunk6MN3H3YFcjs.randomUUID.call(void 0, );
|
|
1585
|
-
const fix = await this.options.service.fixTask(this.boardId, { itemId: this.item.id, operationId: target.dataset.operationId });
|
|
1586
|
-
await this.options.openSession(fix.sessionId);
|
|
1587
|
-
return;
|
|
1588
|
-
}
|
|
1589
|
-
if (_optionalChain([action, 'optionalAccess', _329 => _329.startsWith, 'call', _330 => _330("task-")]) && this.item) {
|
|
1590
|
-
if (action === "task-cancel") await this.execute({ type: "cancel-item", itemId: this.item.id, reason: this.ui.label("taskAction.cancel") });
|
|
1591
|
-
else if (action === "task-run") await this.execute({ type: "request-run", itemId: this.item.id });
|
|
1592
|
-
else if (action === "task-pause" || action === "task-resume") await this.execute({ type: "request-control", itemId: this.item.id, controlId: _chunk6MN3H3YFcjs.randomUUID.call(void 0, ), action: action === "task-pause" ? "pause" : "resume" });
|
|
1593
|
-
return;
|
|
1594
|
-
}
|
|
1595
|
-
if (action === "reanalyze" && _optionalChain([this, 'access', _331 => _331.item, 'optionalAccess', _332 => _332.planning])) {
|
|
1596
|
-
await this.execute({ type: "retry-analysis", itemId: this.item.id, retryId: _chunk6MN3H3YFcjs.randomUUID.call(void 0, ) });
|
|
1597
|
-
return;
|
|
1598
|
-
}
|
|
1599
|
-
if (action === "new-board") {
|
|
1600
|
-
this.showBoardForm();
|
|
1601
|
-
return;
|
|
1602
|
-
}
|
|
1603
|
-
if (action === "children-next" || action === "children-first") {
|
|
1604
|
-
await this.showChildren(this.generation, action === "children-next" ? target.dataset.cursor : void 0);
|
|
1605
|
-
return;
|
|
1606
|
-
}
|
|
1607
|
-
if (action === "new-child" && this.board && this.item && childType(this.board, this.item)) {
|
|
1608
|
-
await this.showItemForm(this.item);
|
|
1609
|
-
return;
|
|
1610
|
-
}
|
|
1611
|
-
if (action === "new-item" && this.board) {
|
|
1612
|
-
await this.showItemForm();
|
|
1613
|
-
return;
|
|
1614
|
-
}
|
|
1615
|
-
if (action === "new-log" || action === "new-decision") {
|
|
1616
|
-
const resources = action === "new-decision" ? await _optionalChain([this, 'access', _333 => _333.options, 'access', _334 => _334.service, 'optionalAccess', _335 => _335.recordResources, 'optionalCall', _336 => _336()]) : [];
|
|
1617
|
-
this.recordId = "";
|
|
1618
|
-
this.drawer.show(this.ui.recordForm(action === "new-log" ? "log" : "decision", this.board, this.itemId, resources), action);
|
|
1619
|
-
this.dirty = true;
|
|
1620
|
-
return;
|
|
1621
|
-
}
|
|
1622
|
-
if ((action === "run-record" || action === "run-record-separate") && _optionalChain([this, 'access', _337 => _337.options, 'access', _338 => _338.service, 'optionalAccess', _339 => _339.runRecord])) {
|
|
1623
|
-
const record = await this.options.service.record(this.boardId, this.recordId);
|
|
1624
|
-
target.dataset.operationId ??= _chunk6MN3H3YFcjs.randomUUID.call(void 0, );
|
|
1625
|
-
await this.options.service.runRecord(this.boardId, { operationId: target.dataset.operationId, recordId: record.id, expectedRevision: record.revision, placement: action === "run-record-separate" ? "new-board" : "current-board" });
|
|
1626
|
-
_optionalChain([this, 'access', _340 => _340.options, 'access', _341 => _341.committed, 'optionalCall', _342 => _342()]);
|
|
1627
|
-
await this.refresh();
|
|
1628
|
-
return;
|
|
1629
|
-
}
|
|
1630
|
-
if (action === "scroll-left" || action === "scroll-right") {
|
|
1631
|
-
const board = this.content().querySelector(".kanban__columns");
|
|
1632
|
-
if (board) board.scrollLeft += board.clientWidth * (action === "scroll-left" ? -0.8 : 0.8);
|
|
1633
|
-
return;
|
|
1634
|
-
}
|
|
1635
|
-
if (action === "records-next" || action === "records-first") {
|
|
1636
|
-
this.recordCursor = action === "records-next" ? _optionalChain([this, 'access', _343 => _343.recordPage, 'optionalAccess', _344 => _344.nextCursor]) : void 0;
|
|
1637
|
-
await this.refresh();
|
|
1638
|
-
return;
|
|
1639
|
-
}
|
|
1640
|
-
if ((action === "confirm-record" || action === "reject-record") && this.recordId) {
|
|
1641
|
-
await this.execute({ type: "review-record", recordId: this.recordId, accept: action === "confirm-record" });
|
|
1642
|
-
return;
|
|
1643
|
-
}
|
|
1644
|
-
if (action === "next" || action === "first") {
|
|
1645
|
-
this.query.cursor = action === "next" ? _optionalChain([this, 'access', _345 => _345.page, 'optionalAccess', _346 => _346.nextCursor]) : void 0;
|
|
1646
|
-
await this.refresh();
|
|
1647
|
-
return;
|
|
1648
|
-
}
|
|
1649
|
-
if (action === "refresh-item-operations") {
|
|
1650
|
-
this.dirty = false;
|
|
1651
|
-
await this.loadOperations(this.generation);
|
|
1652
|
-
_optionalChain([this, 'access', _347 => _347.options, 'access', _348 => _348.changed, 'optionalCall', _349 => _349()]);
|
|
1653
|
-
return;
|
|
1654
|
-
}
|
|
1655
|
-
if (action === "refresh") {
|
|
1656
|
-
await this.refresh();
|
|
1657
|
-
return;
|
|
1658
|
-
}
|
|
1659
|
-
if (action && this.item) await this.execute(actionCommand(action, this.item));
|
|
1660
|
-
}
|
|
1661
|
-
async openReference(reference) {
|
|
1662
|
-
if (this.dirty) throw new Error(this.ui.label("unsaved"));
|
|
1663
|
-
const target = await this.options.service.resolve(reference);
|
|
1664
|
-
if (this.options.navigate) {
|
|
1665
|
-
const leaf = target.recordId ? "/@record/" + encodeURIComponent(target.recordId) : target.itemId ? "/" + encodeURIComponent(target.itemId) : "";
|
|
1666
|
-
await this.options.navigate(`/board/${encodeURIComponent(target.boardId)}${leaf}`);
|
|
1667
|
-
return;
|
|
1668
|
-
}
|
|
1669
|
-
this.closePanel();
|
|
1670
|
-
this.boardId = target.boardId;
|
|
1671
|
-
this.itemId = _nullishCoalesce(target.itemId, () => ( ""));
|
|
1672
|
-
this.recordId = _nullishCoalesce(target.recordId, () => ( ""));
|
|
1673
|
-
this.recordKind = void 0;
|
|
1674
|
-
this.recordCursor = void 0;
|
|
1675
|
-
this.query = { view: "all", limit: 50 };
|
|
1676
|
-
await this.refresh();
|
|
1677
|
-
_optionalChain([this, 'access', _350 => _350.options, 'access', _351 => _351.activated, 'optionalCall', _352 => _352()]);
|
|
1678
|
-
}
|
|
1679
|
-
async navigate(id) {
|
|
1680
|
-
this.boardId = id;
|
|
1681
|
-
this.itemId = "";
|
|
1682
|
-
this.recordKind = void 0;
|
|
1683
|
-
this.recordCursor = void 0;
|
|
1684
|
-
this.query = { view: "all", limit: 50 };
|
|
1685
|
-
this.closePanel();
|
|
1686
|
-
await this.refresh();
|
|
1687
|
-
}
|
|
1688
|
-
async submit(event) {
|
|
1689
|
-
const form = event.target, kind = form.dataset.form, data = new FormData(form);
|
|
1690
|
-
form.dataset.resourceId ??= _chunk6MN3H3YFcjs.randomUUID.call(void 0, );
|
|
1691
|
-
if (!form.reportValidity()) return;
|
|
1692
|
-
if (kind === "item-operation" || kind === "operation-binding") {
|
|
1693
|
-
await this.submitOperation(form, data, kind === "operation-binding");
|
|
1694
|
-
return;
|
|
1695
|
-
}
|
|
1696
|
-
if (kind === "reference") {
|
|
1697
|
-
await this.openReference(value(data, "reference"));
|
|
1698
|
-
return;
|
|
1699
|
-
}
|
|
1700
|
-
if (kind === "filter") {
|
|
1701
|
-
if (this.dirty) throw new Error(this.ui.label("unsaved"));
|
|
1702
|
-
this.query = { phase: value(data, "phase") || void 0, view: value(data, "view"), execution: value(data, "execution") || "all", search: value(data, "search"), area: value(data, "area") || void 0, milestone: value(data, "milestone") || void 0, limit: 50 };
|
|
1703
|
-
await this.refresh();
|
|
1704
|
-
return;
|
|
1705
|
-
}
|
|
1706
|
-
if (kind === "board" && this.actor && this.options.service) {
|
|
1707
|
-
const created = await this.options.service.create(boardInput(data, this.actor, form.dataset.resourceId));
|
|
1708
|
-
_optionalChain([this, 'access', _353 => _353.options, 'access', _354 => _354.committed, 'optionalCall', _355 => _355()]);
|
|
1709
|
-
this.dirty = false;
|
|
1710
|
-
await this.navigate(created.id);
|
|
1711
|
-
return;
|
|
1712
|
-
}
|
|
1713
|
-
if (kind === "automation" && this.automationCatalog) {
|
|
1714
|
-
await this.execute({ type: "configure-automation", settings: {
|
|
1715
|
-
enabled: data.has("enabled"),
|
|
1716
|
-
autoAccept: data.has("autoAccept"),
|
|
1717
|
-
...value(data, "preparation") ? {
|
|
1718
|
-
preparation: JSON.parse(value(data, "preparation")),
|
|
1719
|
-
preparationOptions: Object.fromEntries([...data.entries()].filter(([key]) => key.startsWith("preparation-option-")).map(([key, value2]) => [key.slice("preparation-option-".length), String(value2)]))
|
|
1720
|
-
} : {},
|
|
1721
|
-
planner: JSON.parse(value(data, "planner")),
|
|
1722
|
-
executor: JSON.parse(value(data, "executor")),
|
|
1723
|
-
coordinator: this.automationCatalog.coordinator,
|
|
1724
|
-
worker: this.automationCatalog.worker
|
|
1725
|
-
} });
|
|
1726
|
-
return;
|
|
1727
|
-
}
|
|
1728
|
-
if (kind === "task-reply" && this.item && _optionalChain([this, 'access', _356 => _356.options, 'access', _357 => _357.service, 'optionalAccess', _358 => _358.replyTask])) {
|
|
1729
|
-
await this.options.service.replyTask(this.boardId, { itemId: this.item.id, attemptId: value(data, "attemptId"), replyTo: value(data, "replyTo"), operationId: form.dataset.resourceId, content: value(data, "content") });
|
|
1730
|
-
this.dirty = false;
|
|
1731
|
-
await this.refresh();
|
|
1732
|
-
return;
|
|
1733
|
-
}
|
|
1734
|
-
if (kind === "save-edit" && this.item) {
|
|
1735
|
-
const planning = formCommand("plan", data, this.board, this.item);
|
|
1736
|
-
if (planning.type !== "plan-item") return;
|
|
1737
|
-
await this.execute({ type: "save-edit", launchMode: value(data, "launchMode"), itemId: this.item.id, editId: value(data, "editId"), title: value(data, "title"), responsibility: value(data, "responsibility"), acceptance: value(data, "acceptance"), planning: planning.planning, externalRefs: [...(_nullishCoalesce(this.item.externalRefs, () => ( []))).filter((ref) => !value(data, "itemResource") || ref.system !== JSON.parse(value(data, "itemResource")).system), ...value(data, "itemResource") ? [JSON.parse(value(data, "itemResource"))] : []] });
|
|
1738
|
-
this.editing = void 0;
|
|
1739
|
-
return;
|
|
1740
|
-
}
|
|
1741
|
-
if (kind === "amendment") data.set("amendmentId", _nullishCoalesce(form.dataset.amendment, () => ( "")));
|
|
1742
|
-
if (kind === "record-link" && this.recordId) {
|
|
1743
|
-
await this.execute({ type: "link-record", recordId: this.recordId, itemId: value(data, "itemId") });
|
|
1744
|
-
return;
|
|
1745
|
-
}
|
|
1746
|
-
if (kind && this.board) {
|
|
1747
|
-
if (kind === "execution-session" && this.item && this.options.executionReference) {
|
|
1748
|
-
await this.execute({ type: "link-reference", itemId: this.item.id, reference: this.options.executionReference(value(data, "executionSession"), form.dataset.resourceId) });
|
|
1749
|
-
return;
|
|
1750
|
-
}
|
|
1751
|
-
await this.execute(formCommand(kind, data, this.board, this.item, form.dataset.resourceId));
|
|
1752
|
-
}
|
|
1753
|
-
}
|
|
1754
|
-
async showItemForm(parent) {
|
|
1755
|
-
const board = this.board, generation = this.generation;
|
|
1756
|
-
if (!board) return;
|
|
1757
|
-
const resources = await _optionalChain([this, 'access', _359 => _359.options, 'access', _360 => _360.service, 'optionalAccess', _361 => _361.itemResources, 'optionalCall', _362 => _362(board.id, _optionalChain([parent, 'optionalAccess', _363 => _363.id]))]);
|
|
1758
|
-
if (this.abort.signal.aborted || generation !== this.generation) return;
|
|
1759
|
-
this.itemId = "";
|
|
1760
|
-
this.drawer.show(this.ui.newItemForm(board, parent, resources), parent ? "new-child" : "new-item");
|
|
1761
|
-
this.dirty = true;
|
|
1762
|
-
}
|
|
1763
|
-
async execute(command) {
|
|
1764
|
-
if (!this.board || !this.options.service) return;
|
|
1765
|
-
if (command.type === "review") {
|
|
1766
|
-
const workflow = await this.options.service.workflow(this.board.id);
|
|
1767
|
-
const dispatch = Object.values(workflow.dispatches).find((dispatch2) => dispatch2.itemId === ("itemId" in command ? command.itemId : "") && dispatch2.outcome === "succeeded");
|
|
1768
|
-
if (dispatch) command = { type: "accept-execution", dispatchId: dispatch.id, accept: command.accept };
|
|
1769
|
-
}
|
|
1770
|
-
const fingerprint = JSON.stringify(command);
|
|
1771
|
-
if (this.pending && (this.pending.boardId !== this.board.id || this.pending.fingerprint !== fingerprint)) throw Object.assign(new Error("Pending write"), { code: "WRITE_OUTCOME_UNKNOWN" });
|
|
1772
|
-
this.pending ??= { boardId: this.board.id, fingerprint, request: { operationId: _chunk6MN3H3YFcjs.randomUUID.call(void 0, ), expectedRevision: this.board.revision, command } };
|
|
1773
|
-
try {
|
|
1774
|
-
await this.options.service.execute(this.board.id, this.pending.request);
|
|
1775
|
-
} catch (error) {
|
|
1776
|
-
if (_optionalChain([error, 'optionalAccess', _364 => _364.name]) === "KanbanError" || _optionalChain([error, 'optionalAccess', _365 => _365.outcome]) === "not-committed") this.pending = void 0;
|
|
1777
|
-
throw error;
|
|
1778
|
-
}
|
|
1779
|
-
this.pending = void 0;
|
|
1780
|
-
_optionalChain([this, 'access', _366 => _366.options, 'access', _367 => _367.committed, 'optionalCall', _368 => _368()]);
|
|
1781
|
-
if (command.type === "configure-automation") this.closePanel();
|
|
1782
|
-
this.dirty = false;
|
|
1783
|
-
this.query.cursor = void 0;
|
|
1784
|
-
this.recordCursor = void 0;
|
|
1785
|
-
if (command.type === "create-item") this.itemId = command.item.id;
|
|
1786
|
-
if (command.type === "append-record") {
|
|
1787
|
-
this.recordId = command.record.id;
|
|
1788
|
-
this.itemId = "";
|
|
1789
|
-
this.item = void 0;
|
|
1790
|
-
}
|
|
1791
|
-
await this.refresh();
|
|
1792
|
-
}
|
|
1793
|
-
async run(action) {
|
|
1794
|
-
if (this.busy || this.abort.signal.aborted) return;
|
|
1795
|
-
const operationId = _chunk6MN3H3YFcjs.randomUUID.call(void 0, ), started = Date.now();
|
|
1796
|
-
this.operationStage = "ui.operation";
|
|
1797
|
-
this.generation++;
|
|
1798
|
-
this.busy = true;
|
|
1799
|
-
this.status(this.ui.label("loading"));
|
|
1800
|
-
this.error("");
|
|
1801
|
-
this.options.editor.setAttribute("aria-busy", "true");
|
|
1802
|
-
let succeeded = false;
|
|
1803
|
-
try {
|
|
1804
|
-
await action();
|
|
1805
|
-
succeeded = true;
|
|
1806
|
-
} catch (error) {
|
|
1807
|
-
const raw = _optionalChain([error, 'optionalAccess', _369 => _369.code]);
|
|
1808
|
-
try {
|
|
1809
|
-
_optionalChain([this, 'access', _370 => _370.options, 'access', _371 => _371.presentation, 'access', _372 => _372.log, 'optionalCall', _373 => _373({ operationId, stage: this.operationStage, result: "failure", ...failureDetails(error), code: typeof raw === "string" && /^[A-Z][A-Z0-9_]{0,79}$/.test(raw) ? raw : "KANBAN_OPERATION_FAILED", durationMs: Date.now() - started })]);
|
|
1810
|
-
} catch (e5) {
|
|
1811
|
-
}
|
|
1812
|
-
if (!this.abort.signal.aborted) this.error(errorText(error, this.ui.label, this.operationStage));
|
|
1813
|
-
} finally {
|
|
1814
|
-
this.busy = false;
|
|
1815
|
-
if (!this.abort.signal.aborted) {
|
|
1816
|
-
this.status("");
|
|
1817
|
-
this.options.editor.removeAttribute("aria-busy");
|
|
1818
|
-
this.options.editor.inert = false;
|
|
1819
|
-
this.mountHeaderActions();
|
|
1820
|
-
this.drawer.flushFocus();
|
|
1821
|
-
_optionalChain([this, 'access', _374 => _374.options, 'access', _375 => _375.changed, 'optionalCall', _376 => _376()]);
|
|
1822
|
-
if (succeeded && this.invalid && this.visible && !this.dirty) this.refreshInBackground();
|
|
1823
|
-
}
|
|
1824
|
-
}
|
|
1825
|
-
}
|
|
1826
|
-
navigationTarget(target) {
|
|
1827
|
-
if (target.dataset.board) return `/board/${encodeURIComponent(target.dataset.board)}`;
|
|
1828
|
-
const board = `/board/${encodeURIComponent(this.boardId)}`;
|
|
1829
|
-
if (target.dataset.item) return `${board}/${encodeURIComponent(target.dataset.item)}`;
|
|
1830
|
-
if (target.dataset.record) return `${board}/@record/${encodeURIComponent(target.dataset.record)}`;
|
|
1831
|
-
if (target.dataset.context) return board + (target.dataset.context === "board" ? "" : "/@" + target.dataset.context);
|
|
1832
|
-
}
|
|
1833
|
-
mountHeaderActions() {
|
|
1834
|
-
for (const [slot, release] of this.windowMounts) if (!this.options.editor.contains(slot)) {
|
|
1835
|
-
release();
|
|
1836
|
-
this.windowMounts.delete(slot);
|
|
1837
|
-
}
|
|
1838
|
-
if (this.options.mountTitleBar) {
|
|
1839
|
-
for (const header of this.options.editor.querySelectorAll("[data-titlebar]")) if (!this.windowMounts.has(header)) this.mountTitleBar(header);
|
|
1840
|
-
return;
|
|
1841
|
-
}
|
|
1842
|
-
for (const slot of this.options.editor.querySelectorAll("[data-window-navigation]")) {
|
|
1843
|
-
if (!this.windowMounts.has(slot) && this.options.mountWindowList) this.windowMounts.set(slot, this.options.mountWindowList(slot));
|
|
1844
|
-
}
|
|
1845
|
-
for (const header of this.options.editor.querySelectorAll("[data-titlebar]")) if (!this.windowMounts.has(header)) this.mountDefaultTitleBar(header);
|
|
1846
|
-
}
|
|
1847
|
-
mountDefaultTitleBar(header) {
|
|
1848
|
-
const back = _nullishCoalesce(header.querySelector("[data-titlebar-back]"), () => ( void 0));
|
|
1849
|
-
const title = _nullishCoalesce(header.querySelector("[data-titlebar-title]"), () => ( void 0));
|
|
1850
|
-
_optionalChain([back, 'optionalAccess', _377 => _377.classList, 'access', _378 => _378.add, 'call', _379 => _379("ui-nav-button")]);
|
|
1851
|
-
_optionalChain([header, 'access', _380 => _380.querySelector, 'call', _381 => _381(".kanban__menu > summary"), 'optionalAccess', _382 => _382.classList, 'access', _383 => _383.add, 'call', _384 => _384("ui-nav-button")]);
|
|
1852
|
-
const view = _uicommon.mountTitleBar.call(void 0, header, {
|
|
1853
|
-
title,
|
|
1854
|
-
back,
|
|
1855
|
-
leading: [...header.querySelectorAll("[data-navigation] > button")],
|
|
1856
|
-
trailing: [...header.querySelectorAll("[data-window-navigation]")],
|
|
1857
|
-
actions: [...header.querySelectorAll(".kanban__desktop-create, :scope > [data-action=new-board]")],
|
|
1858
|
-
menu: _nullishCoalesce(header.querySelector(".kanban__menu"), () => ( void 0))
|
|
1859
|
-
});
|
|
1860
|
-
view.element.dataset.titlebarSlot = "";
|
|
1861
|
-
header.dataset.titlebarHost = "true";
|
|
1862
|
-
view.update({ title: _nullishCoalesce(_optionalChain([title, 'optionalAccess', _385 => _385.textContent]), () => ( "")) });
|
|
1863
|
-
this.windowMounts.set(header, () => {
|
|
1864
|
-
view.destroy();
|
|
1865
|
-
delete header.dataset.titlebarHost;
|
|
1866
|
-
});
|
|
1867
|
-
}
|
|
1868
|
-
mountTitleBar(header) {
|
|
1869
|
-
const slot = document.createElement("div");
|
|
1870
|
-
slot.dataset.titlebarSlot = "";
|
|
1871
|
-
header.prepend(slot);
|
|
1872
|
-
header.dataset.titlebarHost = "true";
|
|
1873
|
-
const release = this.options.mountTitleBar(slot, {
|
|
1874
|
-
title: _nullishCoalesce(header.querySelector("[data-titlebar-title]"), () => ( void 0)),
|
|
1875
|
-
back: _nullishCoalesce(header.querySelector("[data-titlebar-back]"), () => ( void 0)),
|
|
1876
|
-
menu: _nullishCoalesce(header.querySelector(".kanban__menu"), () => ( void 0)),
|
|
1877
|
-
actions: [...header.querySelectorAll(".kanban__desktop-create, :scope > [data-action=new-board]")]
|
|
1878
|
-
});
|
|
1879
|
-
this.windowMounts.set(header, () => {
|
|
1880
|
-
release();
|
|
1881
|
-
slot.remove();
|
|
1882
|
-
delete header.dataset.titlebarHost;
|
|
1883
|
-
});
|
|
1884
|
-
}
|
|
1885
|
-
closePanel() {
|
|
1886
|
-
this.dirty = false;
|
|
1887
|
-
this.itemId = "";
|
|
1888
|
-
this.recordId = "";
|
|
1889
|
-
this.item = void 0;
|
|
1890
|
-
this.drawer.close();
|
|
1891
|
-
}
|
|
1892
|
-
async requestClose(explicit) {
|
|
1893
|
-
if (this.editing && explicit) {
|
|
1894
|
-
await this.execute({ type: "end-edit", ...this.editing });
|
|
1895
|
-
this.editing = void 0;
|
|
1896
|
-
}
|
|
1897
|
-
if (this.dirty && !explicit) throw new Error(this.ui.label("unsaved"));
|
|
1898
|
-
if (this.options.navigate && this.boardId) {
|
|
1899
|
-
if (this.dirty) this.closePanel();
|
|
1900
|
-
await this.options.navigate(`/board/${encodeURIComponent(this.boardId)}`);
|
|
1901
|
-
return;
|
|
1902
|
-
}
|
|
1903
|
-
this.closePanel();
|
|
1904
|
-
void this.refreshActivity(this.generation);
|
|
1905
|
-
this.options.selected(this.getActiveResourceId());
|
|
1906
|
-
}
|
|
1907
|
-
alive(generation) {
|
|
1908
|
-
return generation === this.generation && !this.abort.signal.aborted;
|
|
1909
|
-
}
|
|
1910
|
-
content() {
|
|
1911
|
-
return this.options.editor.querySelector("[data-content]");
|
|
1912
|
-
}
|
|
1913
|
-
panel() {
|
|
1914
|
-
return this.options.editor.querySelector("[data-panel]");
|
|
1915
|
-
}
|
|
1916
|
-
status(message) {
|
|
1917
|
-
this.options.editor.querySelector("[data-status]").textContent = message;
|
|
1918
|
-
}
|
|
1919
|
-
error(message) {
|
|
1920
|
-
const error = this.options.editor.querySelector("[data-error]");
|
|
1921
|
-
error.textContent = message;
|
|
1922
|
-
error.hidden = _nullishCoalesce(_optionalChain([this, 'access', _386 => _386.drawer, 'optionalAccess', _387 => _387.open]), () => ( false));
|
|
1923
|
-
const panelError = this.options.editor.querySelector("[data-panel-error]");
|
|
1924
|
-
if (panelError) panelError.textContent = message;
|
|
1925
|
-
const executionError = this.options.editor.querySelector("[data-execution-error]");
|
|
1926
|
-
if (executionError) {
|
|
1927
|
-
executionError.textContent = message;
|
|
1928
|
-
executionError.hidden = !message;
|
|
1929
|
-
if (message) {
|
|
1930
|
-
const panel = this.panel(), bottom = executionError.getBoundingClientRect().bottom, edge = panel.getBoundingClientRect().bottom;
|
|
1931
|
-
if (bottom > edge) panel.scrollTop += bottom - edge + 12;
|
|
1932
|
-
}
|
|
1933
|
-
}
|
|
1934
|
-
this.options.editor.querySelector("[data-retry]").hidden = !message || (_nullishCoalesce(_optionalChain([this, 'access', _388 => _388.drawer, 'optionalAccess', _389 => _389.open]), () => ( false)));
|
|
1935
|
-
}
|
|
1936
|
-
}, _class4);
|
|
1937
|
-
function errorText(error, label, stage) {
|
|
1938
|
-
const code = _optionalChain([error, 'optionalAccess', _390 => _390.outcome]) === "unknown" ? "WRITE_OUTCOME_UNKNOWN" : _optionalChain([error, 'optionalAccess', _391 => _391.code]);
|
|
1939
|
-
if (code === "REVISION_CONFLICT" || code === "CURSOR_STALE") return label("conflict");
|
|
1940
|
-
if (error instanceof Error && error.message === label("unsaved")) return error.message;
|
|
1941
|
-
const safe = typeof code === "string" && /^[A-Z_]{1,80}$/.test(code) ? code : "KANBAN_OPERATION_FAILED";
|
|
1942
|
-
const translated = label("errors." + safe);
|
|
1943
|
-
const details = safe === "KANBAN_OPERATION_FAILED" ? failureDetails(error) : {};
|
|
1944
|
-
const diagnostic = details.errorName ? `
|
|
1945
|
-
${label("diagnostic")}: ${stage} \xB7 ${details.errorName}${details.source ? " \xB7 " + details.source : ""}` : "";
|
|
1946
|
-
return (translated !== "kanban.errors." + safe && translated !== "errors." + safe ? `${translated} (${safe})` : `${label("failed")}: ${safe}`) + diagnostic;
|
|
1947
|
-
}
|
|
1948
|
-
async function mountKanban(container, options) {
|
|
1949
|
-
const sidebar = document.createElement("aside"), editor = document.createElement("main");
|
|
1950
|
-
container.classList.add("kanban-layout");
|
|
1951
|
-
container.replaceChildren(sidebar, editor);
|
|
1952
|
-
const view = new KanbanWorkbench({ ...options, sidebar, editor }, container);
|
|
1953
|
-
await view.start();
|
|
1954
|
-
return view;
|
|
1955
|
-
}
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
exports.KanbanSuggestionPicker = KanbanSuggestionPicker; exports.KanbanWorkbench = KanbanWorkbench; exports.mountKanban = mountKanban;
|
|
1961
|
-
//# sourceMappingURL=index.cjs.map
|