clay-server 5.3.0-beta.3 → 5.3.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/ask-user-request-identity.js +18 -1
- package/lib/project-delegated-follow-up.js +18 -9
- package/lib/public/css/right-workbench.css +26 -3
- package/lib/public/css/shared-browser.css +21 -0
- package/lib/public/css/sticky-notes.css +3 -2
- package/lib/public/index.html +2 -2
- package/lib/public/modules/app-header.js +24 -2
- package/lib/public/modules/app-messages.js +1 -1
- package/lib/public/modules/clay-session-links.js +1 -1
- package/lib/public/modules/filebrowser.js +2 -2
- package/lib/public/modules/pane-activation.js +3 -0
- package/lib/public/modules/pane-browser-bridge.js +15 -5
- package/lib/public/modules/pane-header-runtime.js +18 -0
- package/lib/public/modules/right-workbench.js +92 -62
- package/lib/public/modules/shared-browser.js +6 -0
- package/lib/public/modules/split-pane-renderer.js +6 -8
- package/lib/public/modules/split-pane-runtime.js +23 -0
- package/lib/public/modules/split-view-workers.js +58 -2
- package/lib/public/modules/split-view.js +8 -14
- package/lib/public/modules/sticky-notes.js +8 -10
- package/lib/public/modules/terminal.js +7 -2
- package/lib/public/modules/theme.js +5 -0
- package/lib/public/modules/worker-created-presentation.js +2 -0
- package/lib/public/modules/workspace-assignment-card.js +9 -6
- package/lib/public/pane-assets/{app-K4LGSKX5.js → app-6H5S2Y3Z.js} +1 -1
- package/lib/public/pane-assets/chunk-3QV5SDC4.js +1 -0
- package/lib/public/pane-assets/{chunk-AILOLDZA.js → chunk-4FM3U3DW.js} +1 -1
- package/lib/public/pane-assets/{chunk-6SM2WQJX.js → chunk-7GZH3FZY.js} +1 -1
- package/lib/public/pane-assets/chunk-AGJTF5WQ.js +1 -0
- package/lib/public/pane-assets/chunk-NPKRTUNG.js +2 -0
- package/lib/public/pane-assets/{chunk-BYSBUZDZ.js → chunk-VGA2Y3D2.js} +1 -1
- package/lib/public/pane-assets/{chunk-W34XSARI.js → chunk-WKO3T75E.js} +93 -93
- package/lib/public/pane-assets/manifest.json +347 -345
- package/lib/public/pane-assets/{style-JVCOCG3W.css → style-TSRDU54Z.css} +1 -1
- package/lib/server.js +1 -0
- package/lib/workspace-assignment-service.js +56 -11
- package/lib/workspace-follow-up-queue.js +92 -0
- package/lib/workspace-query-mcp-server.js +1 -1
- package/package.json +1 -1
- package/lib/public/pane-assets/chunk-6AJEGTWL.js +0 -1
- package/lib/public/pane-assets/chunk-7H36SUZA.js +0 -2
- package/lib/public/pane-assets/chunk-QJPBAN5H.js +0 -1
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { store } from './store.js';
|
|
2
|
+
import { getCachedSessions } from './sidebar-sessions.js';
|
|
3
|
+
import { livePaneBinding, samePaneBinding, samePaneTarget, paneTarget } from './pane-binding.js';
|
|
4
|
+
import { VENDOR_AVATARS, VENDOR_NAMES } from './app-rendering.js';
|
|
5
|
+
import { modelEntryValue } from './model-picker.js';
|
|
6
|
+
|
|
7
|
+
export function renderPaneRuntime(paneEl, session) {
|
|
8
|
+
var runtime = paneEl.querySelector('.split-view-runtime');
|
|
9
|
+
if (!runtime) return;
|
|
10
|
+
var vendor = session && session.vendor || 'unknown', model = modelEntryValue(session && session.model);
|
|
11
|
+
var frame = paneEl.querySelector('.split-pane-frame'), controller = frame && frame.clayPane;
|
|
12
|
+
var live = controller && controller.identity(), target = session && paneTarget(store.snap(), getCachedSessions(), session.id);
|
|
13
|
+
if (session && live && live.ready && live.sessionId === session.id && !frame.dataset.requestedSessionId &&
|
|
14
|
+
samePaneTarget(target, live.binding) && livePaneBinding(frame) && typeof controller.headerRuntime === 'function') {
|
|
15
|
+
var observed = controller.headerRuntime();
|
|
16
|
+
if (observed && observed.vendor === vendor && samePaneBinding(live.binding, observed.binding)) model = modelEntryValue(observed.model) || model;
|
|
17
|
+
}
|
|
18
|
+
var label = model || (vendor === 'unknown' ? 'Model unavailable' : 'Provider default');
|
|
19
|
+
var icon = runtime.querySelector('.split-view-runtime-icon'), text = runtime.querySelector('.split-view-model');
|
|
20
|
+
if (icon) { icon.hidden = !VENDOR_AVATARS[vendor]; if (!icon.hidden) icon.src = VENDOR_AVATARS[vendor]; icon.title = VENDOR_NAMES[vendor] || vendor; icon.alt = ''; }
|
|
21
|
+
if (text) { text.textContent = label; text.title = (VENDOR_NAMES[vendor] || vendor) + ' · ' + label; }
|
|
22
|
+
runtime.setAttribute('aria-label', (VENDOR_NAMES[vendor] || vendor) + ' · ' + label);
|
|
23
|
+
}
|
|
@@ -71,6 +71,54 @@ export function workerRemovalTarget(container, driverOrigin, workerOrigin, gener
|
|
|
71
71
|
bindingGeneration: source.binding.generation, bindingRequestId: source.binding.requestId,
|
|
72
72
|
viewRevision: store.get('projectSplitViewRevision'), socketGeneration: store.get('projectSplitViewSocketGeneration') };
|
|
73
73
|
}
|
|
74
|
+
// One introduction per Driver in this page, independent of transcript refreshes.
|
|
75
|
+
export function showCreatedWorkerViewer(group) {
|
|
76
|
+
var state = store.snap(), roles = splitGroupRoles(group);
|
|
77
|
+
if (!roles || state.paneMode || state.dmMode || state.replayingHistory || !state.connected ||
|
|
78
|
+
state.activeSessionId !== roles.driverId || document.hidden) return;
|
|
79
|
+
var workerId = roles.workerIds[roles.workerIds.length - 1];
|
|
80
|
+
var worker = sessions().find(function (item) { return item.id === workerId; });
|
|
81
|
+
var anchors = group.pairAnchors, anchor = anchors && (anchors.workers || [anchors.worker])[roles.workerIds.length - 1];
|
|
82
|
+
var origin = worker && worker.sessionOriginId || anchor && anchor.origin;
|
|
83
|
+
if (!origin) return;
|
|
84
|
+
var driverIdentity = sessions().find(function (item) { return item.id === roles.driverId; });
|
|
85
|
+
var driverOrigin = driverIdentity && driverIdentity.sessionOriginId || anchors && anchors.driver && anchors.driver.origin;
|
|
86
|
+
if (!driverOrigin) return;
|
|
87
|
+
var key = JSON.stringify([state.myUserId, state.currentSlug, driverOrigin]);
|
|
88
|
+
var seen = state.introducedWorkerDrivers || [];
|
|
89
|
+
if (seen.indexOf(key) >= 0) return;
|
|
90
|
+
store.set({ introducedWorkerDrivers: seen.concat(key).slice(-64) });
|
|
91
|
+
if (state.createdWorkerViewer || state.splitViewWorkerConversation) return;
|
|
92
|
+
store.set({ createdWorkerViewer: { driverId: roles.driverId, driverOrigin: driverOrigin, workerId: workerId, workerOrigin: origin,
|
|
93
|
+
generation: worker ? worker.workerGeneration : null,
|
|
94
|
+
ownerId: state.myUserId, slug: state.currentSlug, socketGeneration: state.projectSplitViewSocketGeneration } });
|
|
95
|
+
var driver = sessions().find(function (item) { return item.id === roles.driverId; });
|
|
96
|
+
var pane = driver && document.querySelector('.split-pane[data-session-origin="' + CSS.escape(driver.sessionOriginId) + '"]');
|
|
97
|
+
if (pane) renderPaneWorkers(pane, driver);
|
|
98
|
+
}
|
|
99
|
+
function introduceWorkerViewer(container, driver) {
|
|
100
|
+
var pending = store.get('createdWorkerViewer'), state = store.snap();
|
|
101
|
+
if (!pending || pending.driverId !== driver.id) return;
|
|
102
|
+
var worker = sessions().find(function (item) { return item.id === pending.workerId; });
|
|
103
|
+
if (!worker) return;
|
|
104
|
+
store.set({ createdWorkerViewer: null });
|
|
105
|
+
var group = (state.splitGroups || []).find(function (item) {
|
|
106
|
+
var roles = splitGroupRoles(item);
|
|
107
|
+
return roles && roles.driverId === driver.id && roles.workerIds.indexOf(worker.id) >= 0;
|
|
108
|
+
});
|
|
109
|
+
if (!group || driver.sessionOriginId !== pending.driverOrigin || worker.sessionOriginId !== pending.workerOrigin || pending.generation !== null && worker.workerGeneration !== pending.generation ||
|
|
110
|
+
state.splitViewWorkerConversation || document.hidden || !container.isConnected || container.hidden || container.inert ||
|
|
111
|
+
driver.hidden || worker.hidden || exactWorker(driver, worker.sessionOriginId, worker.workerGeneration) !== worker) return;
|
|
112
|
+
var chip = Array.from(container.querySelectorAll('.split-view-worker-chip')).find(function (item) { return item.dataset.workerOrigin === worker.sessionOriginId; });
|
|
113
|
+
if (chip) open(chip, driver, worker, false);
|
|
114
|
+
}
|
|
115
|
+
function syncWorkerSelection() {
|
|
116
|
+
var state = store.get('splitViewWorkerConversation');
|
|
117
|
+
document.querySelectorAll('.split-view-worker-chip').forEach(function (chip) {
|
|
118
|
+
chip.setAttribute('aria-expanded', String(!!state && chip.dataset.workerOrigin === state.workerOriginId &&
|
|
119
|
+
chip.dataset.workerGeneration === String(state.generation)));
|
|
120
|
+
});
|
|
121
|
+
}
|
|
74
122
|
function popover() { return document.getElementById("split-view-worker-popover"); }
|
|
75
123
|
function close(returnFocus) {
|
|
76
124
|
var state = store.get('splitViewWorkerConversation');
|
|
@@ -84,6 +132,7 @@ function close(returnFocus) {
|
|
|
84
132
|
if (state.fillTimer) clearTimeout(state.fillTimer);
|
|
85
133
|
if (state.requestTimer) clearTimeout(state.requestTimer);
|
|
86
134
|
store.set({ splitViewWorkerConversation: null });
|
|
135
|
+
syncWorkerSelection();
|
|
87
136
|
var element = popover(); if (element) element.remove();
|
|
88
137
|
if (returnFocus) {
|
|
89
138
|
var chip = document.querySelector('.split-pane[data-session-origin="' + CSS.escape(state.driverOriginId) + '"] [data-worker-origin="' + CSS.escape(state.workerOriginId) + '"]');
|
|
@@ -135,7 +184,7 @@ function requestPage(state, before, append, refresh) {
|
|
|
135
184
|
}
|
|
136
185
|
}
|
|
137
186
|
}
|
|
138
|
-
function open(chip, driver, worker) {
|
|
187
|
+
function open(chip, driver, worker, takeFocus) {
|
|
139
188
|
var existing = store.get('splitViewWorkerConversation');
|
|
140
189
|
if (existing && existing.driverOriginId === driver.sessionOriginId && existing.workerOriginId === worker.sessionOriginId && existing.generation === worker.workerGeneration) { close(true); return; }
|
|
141
190
|
if (existing) close(false);
|
|
@@ -146,7 +195,8 @@ function open(chip, driver, worker) {
|
|
|
146
195
|
store.set({ splitViewWorkerConversation: state }); ensurePopover(); renderContent();
|
|
147
196
|
var element = popover(); position(element, chip);
|
|
148
197
|
requestPage(state, undefined, false);
|
|
149
|
-
|
|
198
|
+
syncWorkerSelection();
|
|
199
|
+
var closeButton = element && element.querySelector('[aria-label="Close Worker conversation"]'); if (closeButton && takeFocus !== false) closeButton.focus();
|
|
150
200
|
}
|
|
151
201
|
function ensurePopover() {
|
|
152
202
|
var state = store.get('splitViewWorkerConversation');
|
|
@@ -368,6 +418,7 @@ export function renderPaneWorkers(container, driver) {
|
|
|
368
418
|
});
|
|
369
419
|
root.appendChild(controls);
|
|
370
420
|
}
|
|
421
|
+
introduceWorkerViewer(container, driver);
|
|
371
422
|
var conversation = store.get('splitViewWorkerConversation');
|
|
372
423
|
if (conversation) ensurePopover();
|
|
373
424
|
}
|
|
@@ -386,6 +437,11 @@ window.addEventListener("scroll", function (event) {
|
|
|
386
437
|
reanchorPopover();
|
|
387
438
|
}, true);
|
|
388
439
|
store.subscribe(function (state, previous) {
|
|
440
|
+
var introduction = state.createdWorkerViewer;
|
|
441
|
+
if (introduction && (!state.connected || introduction.slug !== state.currentSlug || introduction.ownerId !== state.myUserId ||
|
|
442
|
+
introduction.socketGeneration !== state.projectSplitViewSocketGeneration || introduction.driverId !== state.activeSessionId)) {
|
|
443
|
+
store.set({ createdWorkerViewer: null });
|
|
444
|
+
}
|
|
389
445
|
if (state.paneBindingSessions !== previous.paneBindingSessions || state.connected !== previous.connected) {
|
|
390
446
|
document.querySelectorAll('.split-view-worker-chip').forEach(function (chip) {
|
|
391
447
|
var worker = sessions().find(function (item) { return item.sessionOriginId === chip.dataset.workerOrigin; });
|
|
@@ -131,21 +131,15 @@ function closePane(sessionId) {
|
|
|
131
131
|
// Called on session_list so pane headers follow renames made elsewhere
|
|
132
132
|
// (sidebar, in-pane app). Panes being renamed inline are left alone.
|
|
133
133
|
export function syncPaneTitles() {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
var
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
var session = sessionById(
|
|
140
|
-
if (
|
|
141
|
-
if (titleEls[i].parentNode) titleEls[i].parentNode.title = session.title;
|
|
142
|
-
if (titleEls[i].style.display !== "none") titleEls[i].textContent = session.title;
|
|
143
|
-
}
|
|
144
|
-
var accessBtns = host.querySelectorAll(".split-pane-full-access");
|
|
145
|
-
for (var ai = 0; ai < split.panes.length && ai < accessBtns.length; ai++) {
|
|
146
|
-
updatePaneFullAccessButton(accessBtns[ai], sessionById(paneEls[ai] && Number(paneEls[ai].dataset.sessionId) || split.panes[ai].sessionId));
|
|
134
|
+
if (!host) return;
|
|
135
|
+
var panes = host.querySelectorAll('.split-pane:not(.split-pane-cached)');
|
|
136
|
+
for (var i = 0; i < panes.length; i++) {
|
|
137
|
+
var frame = panes[i].querySelector('.split-pane-frame');
|
|
138
|
+
if (frame && frame.dataset.requestedSessionId) continue;
|
|
139
|
+
var session = sessionById(Number(panes[i].dataset.sessionId));
|
|
140
|
+
if (session) updateSplitPaneMetadata(panes[i], { sessionId: session.id, slug: panes[i].dataset.projectSlug, title: session.title });
|
|
147
141
|
}
|
|
148
|
-
syncPairChrome(host,
|
|
142
|
+
syncPairChrome(host, store.get('splitPanes'));
|
|
149
143
|
}
|
|
150
144
|
|
|
151
145
|
function handlePaneMessage(event) {
|
|
@@ -104,11 +104,17 @@ function recomputeFlightGeometry() {
|
|
|
104
104
|
function syncFlightControls() {
|
|
105
105
|
var buttons = document.querySelectorAll("#sticky-notes-toggle-btn");
|
|
106
106
|
var hidden = !!store.get("notesTemporarilyHidden");
|
|
107
|
-
var
|
|
107
|
+
var count = openCount();
|
|
108
|
+
var label = hidden ? "Show sticky notes (" + count + ")" : "Hide sticky notes";
|
|
108
109
|
for (var i = 0; i < buttons.length; i++) {
|
|
109
110
|
buttons[i].setAttribute("aria-label", label);
|
|
110
111
|
buttons[i].setAttribute("aria-pressed", hidden ? "true" : "false");
|
|
111
112
|
buttons[i].title = label;
|
|
113
|
+
var badge = buttons[i].querySelector('.sticky-notes-count');
|
|
114
|
+
if (badge) {
|
|
115
|
+
badge.textContent = String(count);
|
|
116
|
+
badge.classList.toggle('hidden', !hidden || count === 0);
|
|
117
|
+
}
|
|
112
118
|
}
|
|
113
119
|
refreshIcons();
|
|
114
120
|
}
|
|
@@ -246,15 +252,7 @@ export function createNote() {
|
|
|
246
252
|
|
|
247
253
|
function updateBadge() {
|
|
248
254
|
syncToggleAvailability();
|
|
249
|
-
|
|
250
|
-
if (!badge) return;
|
|
251
|
-
var count = openCount();
|
|
252
|
-
if (count > 0) {
|
|
253
|
-
badge.textContent = count;
|
|
254
|
-
badge.classList.remove("hidden");
|
|
255
|
-
} else {
|
|
256
|
-
badge.classList.add("hidden");
|
|
257
|
-
}
|
|
255
|
+
syncFlightControls();
|
|
258
256
|
}
|
|
259
257
|
|
|
260
258
|
// --- WS message handlers ---
|
|
@@ -3,7 +3,7 @@ import { iconHtml, refreshIcons } from './icons.js';
|
|
|
3
3
|
import { closeSidebar } from './sidebar.js';
|
|
4
4
|
import { claimRightWorkbench, registerRightWorkbench, releaseRightWorkbench } from './right-workbench.js';
|
|
5
5
|
import { copyToClipboard } from './utils.js';
|
|
6
|
-
import { getTerminalTheme } from './theme.js';
|
|
6
|
+
import { getTerminalTheme, getDockedTerminalTheme } from './theme.js';
|
|
7
7
|
import { getTerminalFontFamily, getTerminalFontSize, onTerminalFontChange } from './terminal-prefs.js';
|
|
8
8
|
import { createKeyToolbar } from './terminal-toolbar.js';
|
|
9
9
|
|
|
@@ -358,7 +358,7 @@ function createXtermForTab(tab) {
|
|
|
358
358
|
cursorBlink: true,
|
|
359
359
|
fontSize: getTerminalFontSize(),
|
|
360
360
|
fontFamily: getTerminalFontFamily(),
|
|
361
|
-
theme: getTerminalTheme(),
|
|
361
|
+
theme: (store.get('rightWorkbenchDockedOwners') || []).indexOf('terminal') !== -1 ? getDockedTerminalTheme() : getTerminalTheme(),
|
|
362
362
|
});
|
|
363
363
|
|
|
364
364
|
var fitAddon = null;
|
|
@@ -843,6 +843,7 @@ export function sendTerminalCommand(command) {
|
|
|
843
843
|
}
|
|
844
844
|
|
|
845
845
|
export function setTerminalTheme(xtermTheme) {
|
|
846
|
+
if ((store.get('rightWorkbenchDockedOwners') || []).indexOf('terminal') !== -1) xtermTheme = getDockedTerminalTheme();
|
|
846
847
|
for (var tab of tabs.values()) {
|
|
847
848
|
if (tab.xterm) {
|
|
848
849
|
tab.xterm.options.theme = xtermTheme;
|
|
@@ -850,6 +851,10 @@ export function setTerminalTheme(xtermTheme) {
|
|
|
850
851
|
}
|
|
851
852
|
}
|
|
852
853
|
|
|
854
|
+
store.subscribe(function (state, previous) {
|
|
855
|
+
if ((state.rightWorkbenchDockedOwners || []).includes('terminal') !== (previous.rightWorkbenchDockedOwners || []).includes('terminal')) setTerminalTheme(getTerminalTheme());
|
|
856
|
+
});
|
|
857
|
+
|
|
853
858
|
// Live font update: applies family/size to every open shell terminal
|
|
854
859
|
// and refits each (cell dimensions change with font size, so cols/rows
|
|
855
860
|
// shift too). Hooked via onTerminalFontChange below.
|
|
@@ -267,6 +267,11 @@ export function getTerminalTheme() {
|
|
|
267
267
|
return computeTerminalTheme(getTheme(DEFAULT_DARK_THEME_ID) || defaultDarkFallback);
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
+
export function getDockedTerminalTheme() {
|
|
271
|
+
var theme = getCurrentTheme();
|
|
272
|
+
return Object.assign({}, computeTerminalTheme(theme), { background: '#' + theme.base00 });
|
|
273
|
+
}
|
|
274
|
+
|
|
270
275
|
export function getMermaidThemeVars() {
|
|
271
276
|
return computeMermaidVars(getCurrentTheme());
|
|
272
277
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// New execution pairs keep the Driver's current presentation; Workers live in pills.
|
|
2
|
+
import { showCreatedWorkerViewer } from './split-view-workers.js';
|
|
2
3
|
import { store } from './store.js';
|
|
3
4
|
import { getWs } from './ws-ref.js';
|
|
4
5
|
import { getCachedSessions } from './sidebar-sessions.js';
|
|
@@ -24,6 +25,7 @@ function reconcileCreatedWorkerPresentation() {
|
|
|
24
25
|
(session.ownerId || null) === (state.myUserId || null); });
|
|
25
26
|
if (state.sessionListProjectSlug !== state.currentSlug || !driver || !driver.sessionOriginId || !getWs() || getWs().readyState !== 1) return false;
|
|
26
27
|
store.set({ createdWorkerPresentation: null });
|
|
28
|
+
showCreatedWorkerViewer(pending.group);
|
|
27
29
|
if (state.activeSessionId === driver.id && !state.splitPanes) return true;
|
|
28
30
|
var view = (state.projectSplitViews || []).find(function (item) {
|
|
29
31
|
return item.sessions.some(function (ref) { return ref.id === driver.id && ref.sessionOriginId === driver.sessionOriginId; });
|
|
@@ -11,6 +11,7 @@ function textElement(tag, className, text) {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
function statusLabel(status) {
|
|
14
|
+
if (status === "queued") return "Queued for Driver";
|
|
14
15
|
if (status === "starting") return "Starting";
|
|
15
16
|
if (status === "running") return "In progress";
|
|
16
17
|
if (status === "completed") return "Completed";
|
|
@@ -22,7 +23,7 @@ function statusLabel(status) {
|
|
|
22
23
|
|
|
23
24
|
function sendDecision(assignment, action, surface, context, card, opener) {
|
|
24
25
|
var ws = getWs();
|
|
25
|
-
if (!ws || ws.readyState !== 1 || !assignment || assignment.status !== "proposed") return false;
|
|
26
|
+
if (!ws || ws.readyState !== 1 || !assignment || (assignment.status !== "proposed" && !(assignment.status === "queued" && action === "cancel"))) return false;
|
|
26
27
|
pendingFocus[assignment.assignmentId] = opener || null;
|
|
27
28
|
card.setAttribute("aria-busy", "true");
|
|
28
29
|
var buttons = card.querySelectorAll("button");
|
|
@@ -79,10 +80,12 @@ export function createWorkspaceAssignmentCard(assignment, options) {
|
|
|
79
80
|
card.appendChild(header);
|
|
80
81
|
|
|
81
82
|
var targetText = followUp
|
|
82
|
-
? "
|
|
83
|
+
? "Send instructions to “" + (assignment.targetSessionTitle || "Existing session") + "” in " + (assignment.projectTitle || assignment.projectSlug || "project")
|
|
83
84
|
: "New private session in " + (assignment.projectTitle || assignment.projectSlug || "project");
|
|
84
85
|
var target = textElement("p", "workspace-assignment-target", targetText);
|
|
85
86
|
card.appendChild(target);
|
|
87
|
+
if (assignment.status === 'queued' && assignment.deliveryState === 'queued') card.appendChild(textElement('p', 'workspace-assignment-result', 'Approved. Waiting for the Driver to finish its current turn.'));
|
|
88
|
+
else if (assignment.deliveryState === 'accepted' && assignment.status === 'running') card.appendChild(textElement('p', 'workspace-assignment-result', 'Accepted by the Driver runtime. Completion is still pending.'));
|
|
86
89
|
card.appendChild(textElement("p", "workspace-assignment-task", assignment.task || ""));
|
|
87
90
|
|
|
88
91
|
if (assignment.error) {
|
|
@@ -94,17 +97,17 @@ export function createWorkspaceAssignmentCard(assignment, options) {
|
|
|
94
97
|
|
|
95
98
|
var actions = document.createElement("div");
|
|
96
99
|
actions.className = "workspace-assignment-actions";
|
|
97
|
-
if (assignment.status === "proposed") {
|
|
98
|
-
var cancel = textElement("button", "workspace-assignment-action secondary", "Cancel");
|
|
100
|
+
if (assignment.status === "proposed" || assignment.status === "queued") {
|
|
101
|
+
var cancel = textElement("button", "workspace-assignment-action secondary", assignment.status === "queued" ? "Cancel queued update" : "Cancel");
|
|
99
102
|
cancel.type = "button";
|
|
100
|
-
cancel.setAttribute("aria-label", "Cancel project assignment");
|
|
103
|
+
cancel.setAttribute("aria-label", assignment.status === "queued" ? "Cancel queued update" : "Cancel project assignment");
|
|
101
104
|
cancel.addEventListener("click", function () { sendDecision(assignment, "cancel", config.home ? "home" : "project", config.context, card, cancel); });
|
|
102
105
|
var approve = textElement("button", "workspace-assignment-action primary", "Approve");
|
|
103
106
|
approve.type = "button";
|
|
104
107
|
approve.setAttribute("aria-label", followUp ? "Approve follow-up in " + (assignment.targetSessionTitle || "the target session") : "Approve new session in " + (assignment.projectTitle || assignment.projectSlug || "the target project"));
|
|
105
108
|
approve.addEventListener("click", function () { sendDecision(assignment, "approve", config.home ? "home" : "project", config.context, card, approve); });
|
|
106
109
|
actions.appendChild(cancel);
|
|
107
|
-
actions.appendChild(approve);
|
|
110
|
+
if (assignment.status === "proposed") actions.appendChild(approve);
|
|
108
111
|
} else {
|
|
109
112
|
var resolved = textElement("span", "workspace-assignment-resolved", statusLabel(assignment.status));
|
|
110
113
|
resolved.setAttribute("role", "status");
|