claude-code-kanban 4.8.0 → 4.10.0
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/package.json +1 -1
- package/public/app.js +87 -213
- package/public/index.html +16 -54
- package/public/style.css +116 -88
- package/public/themes.css +823 -0
- package/server.js +25 -42
package/package.json
CHANGED
package/public/app.js
CHANGED
|
@@ -14,7 +14,6 @@ const collapsedProjectGroups = new Set();
|
|
|
14
14
|
let stableGroupOrder = []; // cached project path order to prevent jumping
|
|
15
15
|
let searchQuery = ''; // Search query for fuzzy search
|
|
16
16
|
let allTasksCache = []; // Cache all tasks for search
|
|
17
|
-
let bulkDeleteSessionId = null; // Track session for bulk delete
|
|
18
17
|
let ownerFilter = '';
|
|
19
18
|
let currentAgents = [];
|
|
20
19
|
let currentWaiting = null;
|
|
@@ -226,172 +225,9 @@ function clearSearch() {
|
|
|
226
225
|
renderSessions();
|
|
227
226
|
}
|
|
228
227
|
|
|
229
|
-
// biome-ignore lint/correctness/noUnusedVariables: used in HTML
|
|
230
|
-
function deleteAllSessionTasks(sessionId) {
|
|
231
|
-
const session = sessions.find((s) => s.id === sessionId);
|
|
232
|
-
if (!session) return;
|
|
233
|
-
|
|
234
|
-
// When viewing a single session, currentTasks already contains only that session's tasks
|
|
235
|
-
// When viewing "All Tasks", tasks have sessionId property, so we filter
|
|
236
|
-
const sessionTasks =
|
|
237
|
-
currentSessionId === sessionId ? currentTasks : currentTasks.filter((t) => t.sessionId === sessionId);
|
|
238
|
-
|
|
239
|
-
if (sessionTasks.length === 0) {
|
|
240
|
-
alert('No tasks to delete in this session');
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
bulkDeleteSessionId = sessionId;
|
|
245
|
-
|
|
246
|
-
const displayName = session.name || sessionId;
|
|
247
|
-
const message = `Delete all ${sessionTasks.length} task(s) from session "${displayName}"?`;
|
|
248
|
-
|
|
249
|
-
document.getElementById('delete-session-tasks-message').textContent = message;
|
|
250
|
-
|
|
251
|
-
const modal = document.getElementById('delete-session-tasks-modal');
|
|
252
|
-
modal.classList.add('visible');
|
|
253
|
-
|
|
254
|
-
// Handle ESC key
|
|
255
|
-
const keyHandler = (e) => {
|
|
256
|
-
if (e.key === 'Escape') {
|
|
257
|
-
e.preventDefault();
|
|
258
|
-
closeDeleteSessionTasksModal();
|
|
259
|
-
document.removeEventListener('keydown', keyHandler);
|
|
260
|
-
}
|
|
261
|
-
};
|
|
262
|
-
document.addEventListener('keydown', keyHandler);
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
function closeDeleteSessionTasksModal() {
|
|
266
|
-
const modal = document.getElementById('delete-session-tasks-modal');
|
|
267
|
-
modal.classList.remove('visible');
|
|
268
|
-
bulkDeleteSessionId = null;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// biome-ignore lint/correctness/noUnusedVariables: used in HTML
|
|
272
|
-
async function confirmDeleteSessionTasks() {
|
|
273
|
-
if (!bulkDeleteSessionId) return;
|
|
274
|
-
|
|
275
|
-
const sessionId = bulkDeleteSessionId;
|
|
276
|
-
closeDeleteSessionTasksModal();
|
|
277
|
-
|
|
278
|
-
// Get tasks to delete
|
|
279
|
-
const sessionTasks =
|
|
280
|
-
currentSessionId === sessionId ? currentTasks : currentTasks.filter((t) => t.sessionId === sessionId);
|
|
281
|
-
|
|
282
|
-
// Sort tasks by dependency order (blocked tasks first, then blockers)
|
|
283
|
-
const sortedTasks = topologicalSort(sessionTasks);
|
|
284
|
-
|
|
285
|
-
let successCount = 0;
|
|
286
|
-
let failedCount = 0;
|
|
287
|
-
const failedTasks = [];
|
|
288
|
-
|
|
289
|
-
for (const task of sortedTasks) {
|
|
290
|
-
try {
|
|
291
|
-
const res = await fetch(`/api/tasks/${sessionId}/${task.id}`, {
|
|
292
|
-
method: 'DELETE',
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
if (res.ok) {
|
|
296
|
-
successCount++;
|
|
297
|
-
} else {
|
|
298
|
-
failedCount++;
|
|
299
|
-
const error = await res.json();
|
|
300
|
-
failedTasks.push({ id: task.id, subject: task.subject, error: error.error });
|
|
301
|
-
console.error(`Failed to delete task ${task.id}:`, error);
|
|
302
|
-
}
|
|
303
|
-
} catch (error) {
|
|
304
|
-
failedCount++;
|
|
305
|
-
failedTasks.push({ id: task.id, subject: task.subject, error: 'Network error' });
|
|
306
|
-
console.error(`Error deleting task ${task.id}:`, error);
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
// Show result modal
|
|
311
|
-
showDeleteResultModal(successCount, failedCount, failedTasks);
|
|
312
|
-
|
|
313
|
-
// Close detail panel if open
|
|
314
|
-
closeDetailPanel();
|
|
315
|
-
|
|
316
|
-
// Refresh the view
|
|
317
|
-
await refreshCurrentView();
|
|
318
|
-
}
|
|
319
|
-
|
|
320
228
|
//#endregion
|
|
321
229
|
|
|
322
|
-
//#region
|
|
323
|
-
// Topological sort for task deletion order
|
|
324
|
-
function topologicalSort(tasks) {
|
|
325
|
-
const result = [];
|
|
326
|
-
const visited = new Set();
|
|
327
|
-
const visiting = new Set();
|
|
328
|
-
const taskMap = new Map(tasks.map((t) => [t.id, t]));
|
|
329
|
-
|
|
330
|
-
function visit(taskId) {
|
|
331
|
-
if (visited.has(taskId)) return;
|
|
332
|
-
if (visiting.has(taskId)) return; // Cycle - skip
|
|
333
|
-
|
|
334
|
-
visiting.add(taskId);
|
|
335
|
-
const task = taskMap.get(taskId);
|
|
336
|
-
|
|
337
|
-
if (task?.blocks && task.blocks.length > 0) {
|
|
338
|
-
// Visit all tasks that this task blocks (dependencies first)
|
|
339
|
-
for (const blockedId of task.blocks) {
|
|
340
|
-
if (taskMap.has(blockedId)) {
|
|
341
|
-
visit(blockedId);
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
visiting.delete(taskId);
|
|
347
|
-
visited.add(taskId);
|
|
348
|
-
if (task) result.push(task);
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// Visit all tasks
|
|
352
|
-
for (const task of tasks) {
|
|
353
|
-
visit(task.id);
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
return result;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
function showDeleteResultModal(successCount, failedCount, failedTasks) {
|
|
360
|
-
const modal = document.getElementById('delete-result-modal');
|
|
361
|
-
const messageEl = document.getElementById('delete-result-message');
|
|
362
|
-
const detailsEl = document.getElementById('delete-result-details');
|
|
363
|
-
|
|
364
|
-
if (failedCount === 0) {
|
|
365
|
-
messageEl.textContent = `Successfully deleted all ${successCount} task(s).`;
|
|
366
|
-
detailsEl.style.display = 'none';
|
|
367
|
-
} else {
|
|
368
|
-
messageEl.textContent = `Deleted ${successCount} task(s). Failed to delete ${failedCount} task(s).`;
|
|
369
|
-
|
|
370
|
-
const failedList = failedTasks
|
|
371
|
-
.map((t) => `<li><strong>${escapeHtml(t.subject)}</strong> (#${escapeHtml(t.id)}): ${escapeHtml(t.error)}</li>`)
|
|
372
|
-
.join('');
|
|
373
|
-
detailsEl.innerHTML = `<ul style="margin: 8px 0 0 0; padding-left: 20px;">${failedList}</ul>`;
|
|
374
|
-
detailsEl.style.display = 'block';
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
modal.classList.add('visible');
|
|
378
|
-
|
|
379
|
-
// Handle ESC key
|
|
380
|
-
const keyHandler = (e) => {
|
|
381
|
-
if (e.key === 'Escape') {
|
|
382
|
-
e.preventDefault();
|
|
383
|
-
closeDeleteResultModal();
|
|
384
|
-
document.removeEventListener('keydown', keyHandler);
|
|
385
|
-
}
|
|
386
|
-
};
|
|
387
|
-
document.addEventListener('keydown', keyHandler);
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
function closeDeleteResultModal() {
|
|
391
|
-
const modal = document.getElementById('delete-result-modal');
|
|
392
|
-
modal.classList.remove('visible');
|
|
393
|
-
}
|
|
394
|
-
|
|
230
|
+
//#region SEARCH
|
|
395
231
|
function fuzzyMatch(text, query) {
|
|
396
232
|
if (!query) return true;
|
|
397
233
|
if (!text) return false;
|
|
@@ -1833,6 +1669,8 @@ function _renderPinToDetail(pin) {
|
|
|
1833
1669
|
}
|
|
1834
1670
|
|
|
1835
1671
|
const SESSION_PIN_SVG = PIN_SVG.replace('width="14" height="14"', 'width="12" height="12"');
|
|
1672
|
+
const SESSION_STAR_SVG =
|
|
1673
|
+
'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="12" height="12"><path d="M12 2 L15 9 L22 9 L17 14 L19 22 L12 18 L5 22 L7 14 L2 9 L9 9 Z"/></svg>';
|
|
1836
1674
|
const LINK_SVG_PATHS =
|
|
1837
1675
|
'<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>';
|
|
1838
1676
|
const linkSvg = (size) =>
|
|
@@ -2993,7 +2831,7 @@ function renderSessions() {
|
|
|
2993
2831
|
const tempClass = session.hasRecentLog || session.inProgress || session.hasWaitingForUser ? 'warm' : 'stale';
|
|
2994
2832
|
return `
|
|
2995
2833
|
<button onclick="fetchTasks('${session.id}')" data-session-id="${session.id}" class="session-item ${isActive ? 'active' : ''} ${session.hasWaitingForUser ? 'permission-pending' : ''} ${tempClass} ${showCtx ? 'has-context' : ''}" title="${tooltip}">
|
|
2996
|
-
<span class="session-pin-btn${pinClass}" onclick="event.stopPropagation();toggleSessionPin('${escapeHtml(session.id)}')" title="${pinTitle} session">${SESSION_PIN_SVG}</span>
|
|
2834
|
+
<span class="session-pin-btn${pinClass}" onclick="event.stopPropagation();toggleSessionPin('${escapeHtml(session.id)}')" title="${pinTitle} session">${pinState === 'sticky' ? SESSION_STAR_SVG : SESSION_PIN_SVG}</span>
|
|
2997
2835
|
<div class="session-name">${escapeHtml(primaryName)}</div>
|
|
2998
2836
|
${secondaryName ? `<div class="session-secondary">${escapeHtml(secondaryName)}</div>` : ''}
|
|
2999
2837
|
${gitBranch ? `<div class="session-branch">${gitBranch}</div>` : ''}
|
|
@@ -3829,14 +3667,6 @@ async function showTaskDetail(taskId, sessionId = null) {
|
|
|
3829
3667
|
</div>`
|
|
3830
3668
|
: ''
|
|
3831
3669
|
}
|
|
3832
|
-
|
|
3833
|
-
<div class="detail-section note-section">
|
|
3834
|
-
<label for="note-input" class="detail-label">Add Note</label>
|
|
3835
|
-
<form class="note-form" onsubmit="addNote(event, '${task.id}', '${actualSessionId}')">
|
|
3836
|
-
<textarea id="note-input" class="note-input" placeholder="Add a note for Claude..." rows="3"></textarea>
|
|
3837
|
-
<button type="submit" class="note-submit">Add Note</button>
|
|
3838
|
-
</form>
|
|
3839
|
-
</div>
|
|
3840
3670
|
`;
|
|
3841
3671
|
|
|
3842
3672
|
// Setup button handlers (read-only in project view)
|
|
@@ -3845,9 +3675,6 @@ async function showTaskDetail(taskId, sessionId = null) {
|
|
|
3845
3675
|
deleteBtn.style.display = isProjectView ? 'none' : '';
|
|
3846
3676
|
if (!isProjectView) deleteBtn.onclick = () => deleteTask(task.id, actualSessionId);
|
|
3847
3677
|
|
|
3848
|
-
const noteSection = detailContent.querySelector('.note-section');
|
|
3849
|
-
if (noteSection && isProjectView) noteSection.style.display = 'none';
|
|
3850
|
-
|
|
3851
3678
|
if (!isProjectView) {
|
|
3852
3679
|
const titleEl = detailContent.querySelector('.detail-title');
|
|
3853
3680
|
if (titleEl) {
|
|
@@ -3955,36 +3782,6 @@ async function saveTaskField(taskId, sessionId, field, value) {
|
|
|
3955
3782
|
}
|
|
3956
3783
|
}
|
|
3957
3784
|
|
|
3958
|
-
// biome-ignore lint/correctness/noUnusedVariables: used in HTML
|
|
3959
|
-
async function addNote(event, taskId, sessionId) {
|
|
3960
|
-
event.preventDefault();
|
|
3961
|
-
const input = document.getElementById('note-input');
|
|
3962
|
-
const note = input.value.trim();
|
|
3963
|
-
if (!note) return;
|
|
3964
|
-
|
|
3965
|
-
try {
|
|
3966
|
-
const res = await fetch(`/api/tasks/${sessionId}/${taskId}/note`, {
|
|
3967
|
-
method: 'POST',
|
|
3968
|
-
headers: { 'Content-Type': 'application/json' },
|
|
3969
|
-
body: JSON.stringify({ note }),
|
|
3970
|
-
});
|
|
3971
|
-
|
|
3972
|
-
if (res.ok) {
|
|
3973
|
-
input.value = '';
|
|
3974
|
-
// Refresh to show updated description
|
|
3975
|
-
if (viewMode === 'all') {
|
|
3976
|
-
const tasksRes = await fetch('/api/tasks/all');
|
|
3977
|
-
currentTasks = await tasksRes.json();
|
|
3978
|
-
} else {
|
|
3979
|
-
await fetchTasks(sessionId);
|
|
3980
|
-
}
|
|
3981
|
-
showTaskDetail(taskId, sessionId);
|
|
3982
|
-
}
|
|
3983
|
-
} catch (error) {
|
|
3984
|
-
console.error('Failed to add note:', error);
|
|
3985
|
-
}
|
|
3986
|
-
}
|
|
3987
|
-
|
|
3988
3785
|
function closeDetailPanel() {
|
|
3989
3786
|
detailPanel.classList.remove('visible');
|
|
3990
3787
|
document.getElementById('delete-task-btn').style.display = 'none';
|
|
@@ -5986,6 +5783,69 @@ function loadTheme() {
|
|
|
5986
5783
|
updateThemeIcon();
|
|
5987
5784
|
updateThemeColor(document.body.classList.contains('light'));
|
|
5988
5785
|
syncHljsTheme();
|
|
5786
|
+
buildThemeMenu();
|
|
5787
|
+
const colorTheme = localStorage.getItem('color-theme');
|
|
5788
|
+
if (colorTheme) document.body.dataset.colorTheme = colorTheme;
|
|
5789
|
+
syncColorThemeSelect(colorTheme || 'ember');
|
|
5790
|
+
}
|
|
5791
|
+
|
|
5792
|
+
const COLOR_THEMES = [
|
|
5793
|
+
['ember', 'Ember'],
|
|
5794
|
+
['gruvbox', 'Gruvbox'],
|
|
5795
|
+
['catppuccin', 'Catppuccin'],
|
|
5796
|
+
['tokyo-night', 'Tokyo Night'],
|
|
5797
|
+
['solarized', 'Solarized'],
|
|
5798
|
+
['dracula', 'Dracula'],
|
|
5799
|
+
['nord', 'Nord'],
|
|
5800
|
+
['rose-pine', 'Rosé Pine'],
|
|
5801
|
+
['everforest', 'Everforest'],
|
|
5802
|
+
['kanagawa', 'Kanagawa'],
|
|
5803
|
+
['one-dark', 'One Dark'],
|
|
5804
|
+
['night-owl', 'Night Owl'],
|
|
5805
|
+
['monokai', 'Monokai Pro'],
|
|
5806
|
+
['github', 'GitHub'],
|
|
5807
|
+
['ayu', 'Ayu'],
|
|
5808
|
+
['vitesse', 'Vitesse'],
|
|
5809
|
+
['synthwave', "Synthwave '84"],
|
|
5810
|
+
];
|
|
5811
|
+
|
|
5812
|
+
function buildThemeMenu() {
|
|
5813
|
+
const menu = document.getElementById('themeMenu');
|
|
5814
|
+
menu.innerHTML = COLOR_THEMES.map(
|
|
5815
|
+
([id, label]) =>
|
|
5816
|
+
`<button type="button" class="theme-menu-item" data-theme-id="${id}"
|
|
5817
|
+
onclick="event.stopPropagation(); setColorTheme('${id}'); toggleThemeMenu()">
|
|
5818
|
+
<span class="theme-swatch theme-swatch-${id}"><i class="sw-bg"></i><i class="sw-accent"></i><i class="sw-ink"></i></span>${label}
|
|
5819
|
+
</button>`,
|
|
5820
|
+
).join('');
|
|
5821
|
+
}
|
|
5822
|
+
|
|
5823
|
+
// biome-ignore lint/correctness/noUnusedVariables: used in HTML
|
|
5824
|
+
function toggleThemeMenu(e) {
|
|
5825
|
+
e?.stopPropagation();
|
|
5826
|
+
const menu = document.getElementById('themeMenu');
|
|
5827
|
+
const open = menu.classList.toggle('open');
|
|
5828
|
+
if (open) {
|
|
5829
|
+
document.addEventListener('click', () => menu.classList.remove('open'), { once: true });
|
|
5830
|
+
}
|
|
5831
|
+
}
|
|
5832
|
+
|
|
5833
|
+
function syncColorThemeSelect(id) {
|
|
5834
|
+
document.querySelectorAll('.theme-menu-item').forEach((el) => {
|
|
5835
|
+
el.classList.toggle('on', el.dataset.themeId === (id || 'ember'));
|
|
5836
|
+
});
|
|
5837
|
+
}
|
|
5838
|
+
|
|
5839
|
+
// 'ember' (the :root default) has no override block — selecting it clears the attribute.
|
|
5840
|
+
function setColorTheme(id) {
|
|
5841
|
+
if (!id || id === 'ember') {
|
|
5842
|
+
delete document.body.dataset.colorTheme;
|
|
5843
|
+
localStorage.removeItem('color-theme');
|
|
5844
|
+
} else {
|
|
5845
|
+
document.body.dataset.colorTheme = id;
|
|
5846
|
+
localStorage.setItem('color-theme', id);
|
|
5847
|
+
}
|
|
5848
|
+
syncColorThemeSelect(id);
|
|
5989
5849
|
}
|
|
5990
5850
|
|
|
5991
5851
|
//#endregion
|
|
@@ -7065,21 +6925,35 @@ window.hubNavigate = function hubNavigate(app, url) {
|
|
|
7065
6925
|
|
|
7066
6926
|
(function initHubTheme() {
|
|
7067
6927
|
const getTheme = () => (document.body.classList.contains('light') ? 'light' : 'dark');
|
|
6928
|
+
const getColorTheme = () => document.body.dataset.colorTheme || 'ember';
|
|
7068
6929
|
const hubOrigin = () => (window.__HUB__?.url ? new URL(window.__HUB__.url).origin : null);
|
|
6930
|
+
// lastTheme/lastColorTheme are updated synchronously when applying a hub
|
|
6931
|
+
// message, so the (async) observer sees no diff and doesn't echo it back.
|
|
7069
6932
|
let lastTheme = getTheme();
|
|
6933
|
+
let lastColorTheme = getColorTheme();
|
|
7070
6934
|
window.addEventListener('message', (e) => {
|
|
7071
6935
|
if (e.source !== window.parent || e.origin !== hubOrigin()) return;
|
|
7072
6936
|
if (e.data?.type !== 'hub:theme') return;
|
|
7073
|
-
if (
|
|
7074
|
-
|
|
7075
|
-
|
|
6937
|
+
if (typeof e.data.colorTheme === 'string' && e.data.colorTheme !== getColorTheme()) {
|
|
6938
|
+
setColorTheme(e.data.colorTheme);
|
|
6939
|
+
lastColorTheme = getColorTheme();
|
|
6940
|
+
}
|
|
6941
|
+
if (getTheme() !== e.data.theme) {
|
|
6942
|
+
window.toggleTheme();
|
|
6943
|
+
lastTheme = getTheme();
|
|
6944
|
+
}
|
|
7076
6945
|
});
|
|
7077
6946
|
new MutationObserver(() => {
|
|
7078
6947
|
const t = getTheme();
|
|
7079
|
-
|
|
6948
|
+
const ct = getColorTheme();
|
|
6949
|
+
if (t === lastTheme && ct === lastColorTheme) return;
|
|
7080
6950
|
lastTheme = t;
|
|
6951
|
+
lastColorTheme = ct;
|
|
7081
6952
|
const origin = hubOrigin();
|
|
7082
|
-
if (origin) window.parent.postMessage({ type: 'hub:theme', theme: t }, origin);
|
|
7083
|
-
}).observe(document.body, {
|
|
6953
|
+
if (origin) window.parent.postMessage({ type: 'hub:theme', theme: t, colorTheme: ct }, origin);
|
|
6954
|
+
}).observe(document.body, {
|
|
6955
|
+
attributes: true,
|
|
6956
|
+
attributeFilter: ['class', 'data-color-theme'],
|
|
6957
|
+
});
|
|
7084
6958
|
})();
|
|
7085
6959
|
// #endregion HUB_INTEGRATION
|
package/public/index.html
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
16
16
|
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&family=Playfair+Display:wght@400;500;600&display=swap" rel="stylesheet">
|
|
17
17
|
<link rel="stylesheet" href="/style.css">
|
|
18
|
+
<link rel="stylesheet" href="/themes.css">
|
|
18
19
|
<script defer src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
19
20
|
<script defer src="https://cdn.jsdelivr.net/npm/dompurify@3/dist/purify.min.js"></script>
|
|
20
21
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/styles/github-dark.min.css" id="hljs-theme-dark">
|
|
@@ -143,6 +144,10 @@
|
|
|
143
144
|
<ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/>
|
|
144
145
|
</svg>
|
|
145
146
|
</button>
|
|
147
|
+
<span class="icon-btn theme-picker" id="themePickerBtn" title="Color theme" onclick="toggleThemeMenu(event)">
|
|
148
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="13.5" cy="6.5" r=".5" fill="currentColor"/><circle cx="17.5" cy="10.5" r=".5" fill="currentColor"/><circle cx="8.5" cy="7.5" r=".5" fill="currentColor"/><circle cx="6.5" cy="12.5" r=".5" fill="currentColor"/><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z"/></svg>
|
|
149
|
+
<div class="theme-menu" id="themeMenu"></div>
|
|
150
|
+
</span>
|
|
146
151
|
<button id="theme-toggle" class="icon-btn" onclick="toggleTheme()" title="Toggle theme" aria-label="Toggle theme">
|
|
147
152
|
<svg id="theme-icon-dark" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
148
153
|
<path d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"/>
|
|
@@ -216,7 +221,7 @@
|
|
|
216
221
|
<header class="detail-header">
|
|
217
222
|
<h3>Task Details</h3>
|
|
218
223
|
<div style="display: flex; gap: 8px; align-items: center;">
|
|
219
|
-
<button id="delete-task-btn" class="icon-btn" title="Delete task (D)" aria-label="Delete task" style="
|
|
224
|
+
<button id="delete-task-btn" class="icon-btn icon-btn-danger" title="Delete task (D)" aria-label="Delete task" style="display: none;">
|
|
220
225
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
221
226
|
<path d="M3 6h18M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/>
|
|
222
227
|
</svg>
|
|
@@ -467,50 +472,7 @@
|
|
|
467
472
|
</div>
|
|
468
473
|
<div class="modal-footer">
|
|
469
474
|
<button id="delete-cancel-btn" class="btn btn-secondary" onclick="closeDeleteConfirmModal()">Cancel</button>
|
|
470
|
-
<button id="delete-confirm-btn" class="btn btn-
|
|
471
|
-
</div>
|
|
472
|
-
</div>
|
|
473
|
-
</div>
|
|
474
|
-
|
|
475
|
-
<!-- Delete All Session Tasks Confirmation Modal -->
|
|
476
|
-
<div id="delete-session-tasks-modal" class="modal-overlay" onclick="closeDeleteSessionTasksModal()">
|
|
477
|
-
<div class="modal" onclick="event.stopPropagation()">
|
|
478
|
-
<div class="modal-header">
|
|
479
|
-
<h3 class="modal-title">Delete All Tasks</h3>
|
|
480
|
-
<button class="modal-close" aria-label="Close dialog" onclick="closeDeleteSessionTasksModal()">
|
|
481
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
482
|
-
<path d="M18 6L6 18M6 6l12 12"/>
|
|
483
|
-
</svg>
|
|
484
|
-
</button>
|
|
485
|
-
</div>
|
|
486
|
-
<div class="modal-body">
|
|
487
|
-
<p id="delete-session-tasks-message" style="margin: 0 0 12px 0; color: var(--text-primary);"></p>
|
|
488
|
-
<p style="margin: 0; font-size: 13px; color: var(--text-secondary);">This action cannot be undone.</p>
|
|
489
|
-
</div>
|
|
490
|
-
<div class="modal-footer">
|
|
491
|
-
<button class="btn btn-secondary" onclick="closeDeleteSessionTasksModal()">Cancel</button>
|
|
492
|
-
<button class="btn btn-primary" onclick="confirmDeleteSessionTasks()" style="background: #ef4444; border-color: #ef4444;">Delete All</button>
|
|
493
|
-
</div>
|
|
494
|
-
</div>
|
|
495
|
-
</div>
|
|
496
|
-
|
|
497
|
-
<!-- Delete Result Modal -->
|
|
498
|
-
<div id="delete-result-modal" class="modal-overlay" onclick="closeDeleteResultModal()">
|
|
499
|
-
<div class="modal" onclick="event.stopPropagation()">
|
|
500
|
-
<div class="modal-header">
|
|
501
|
-
<h3 class="modal-title">Deletion Result</h3>
|
|
502
|
-
<button class="modal-close" aria-label="Close dialog" onclick="closeDeleteResultModal()">
|
|
503
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
504
|
-
<path d="M18 6L6 18M6 6l12 12"/>
|
|
505
|
-
</svg>
|
|
506
|
-
</button>
|
|
507
|
-
</div>
|
|
508
|
-
<div class="modal-body">
|
|
509
|
-
<p id="delete-result-message" style="margin: 0; color: var(--text-primary);"></p>
|
|
510
|
-
<div id="delete-result-details" style="margin-top: 12px; font-size: 13px; color: var(--text-secondary);"></div>
|
|
511
|
-
</div>
|
|
512
|
-
<div class="modal-footer">
|
|
513
|
-
<button class="btn btn-primary" onclick="closeDeleteResultModal()">Close</button>
|
|
475
|
+
<button id="delete-confirm-btn" class="btn btn-danger" onclick="confirmDelete()">Delete</button>
|
|
514
476
|
</div>
|
|
515
477
|
</div>
|
|
516
478
|
</div>
|
|
@@ -544,7 +506,7 @@
|
|
|
544
506
|
<div class="modal-footer">
|
|
545
507
|
<button id="session-info-dismiss-btn" class="btn btn-secondary" onclick="toggleDismissSession(_infoModalSessionId); closeTeamModal()">Dismiss</button>
|
|
546
508
|
<button class="btn btn-secondary" onclick="showToolStatsModal(_infoModalSessionId)" title="Tool invocation statistics">Tool Stats</button>
|
|
547
|
-
<button class="btn btn-
|
|
509
|
+
<button class="btn btn-secondary" onclick="closeTeamModal()">Close</button>
|
|
548
510
|
</div>
|
|
549
511
|
</div>
|
|
550
512
|
</div>
|
|
@@ -562,7 +524,7 @@
|
|
|
562
524
|
</div>
|
|
563
525
|
<div id="tool-stats-modal-body" class="modal-body" style="overflow-y:auto;flex:1 1 auto;min-height:0;"></div>
|
|
564
526
|
<div class="modal-footer">
|
|
565
|
-
<button class="btn btn-
|
|
527
|
+
<button class="btn btn-secondary" onclick="closeToolStatsModal()">Close</button>
|
|
566
528
|
</div>
|
|
567
529
|
</div>
|
|
568
530
|
</div>
|
|
@@ -591,7 +553,7 @@
|
|
|
591
553
|
</div>
|
|
592
554
|
<div id="plan-modal-body" class="modal-body detail-desc rendered-md" style="overflow-y: auto; flex: 0 1 auto; min-height: 0;"></div>
|
|
593
555
|
<div class="modal-footer">
|
|
594
|
-
<button class="btn btn-
|
|
556
|
+
<button class="btn btn-secondary" onclick="closePlanModal()">Close</button>
|
|
595
557
|
</div>
|
|
596
558
|
</div>
|
|
597
559
|
</div>
|
|
@@ -601,7 +563,7 @@
|
|
|
601
563
|
<div class="modal modal-sm" onclick="event.stopPropagation()">
|
|
602
564
|
<div class="modal-header">
|
|
603
565
|
<h3 class="modal-title" style="display: flex; align-items: center; gap: 8px;">
|
|
604
|
-
<svg viewBox="0 0 24 24" fill="none" stroke="
|
|
566
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="var(--danger)" stroke-width="2" style="width: 20px; height: 20px;">
|
|
605
567
|
<circle cx="12" cy="12" r="10"/>
|
|
606
568
|
<line x1="15" y1="9" x2="9" y2="15"/>
|
|
607
569
|
<line x1="9" y1="9" x2="15" y2="15"/>
|
|
@@ -618,7 +580,7 @@
|
|
|
618
580
|
<div id="blocked-task-message" style="color: var(--text-primary); line-height: 1.6;"></div>
|
|
619
581
|
</div>
|
|
620
582
|
<div class="modal-footer">
|
|
621
|
-
<button class="btn btn-
|
|
583
|
+
<button class="btn btn-secondary" onclick="closeBlockedTaskModal()">OK</button>
|
|
622
584
|
</div>
|
|
623
585
|
</div>
|
|
624
586
|
</div>
|
|
@@ -637,7 +599,7 @@
|
|
|
637
599
|
</div>
|
|
638
600
|
<div id="loop-modal-body" class="modal-body" style="overflow-y:auto;flex:0 1 auto;min-height:0;"></div>
|
|
639
601
|
<div class="modal-footer">
|
|
640
|
-
<button class="btn btn-
|
|
602
|
+
<button class="btn btn-secondary" onclick="closeLoopModal()">Close</button>
|
|
641
603
|
</div>
|
|
642
604
|
</div>
|
|
643
605
|
</div>
|
|
@@ -669,7 +631,7 @@
|
|
|
669
631
|
<div id="agent-modal-body" class="modal-body" style="overflow-y: auto; overflow-x: hidden; flex: 0 1 auto; min-height: 0;"></div>
|
|
670
632
|
<div class="modal-footer">
|
|
671
633
|
<button id="agent-modal-dismiss-btn" class="btn agent-dismiss-btn" style="display:none" onclick="dismissAgent(currentAgentModalId);closeAgentModal()">Dismiss</button>
|
|
672
|
-
<button class="btn btn-
|
|
634
|
+
<button class="btn btn-secondary" onclick="closeAgentModal()">Close</button>
|
|
673
635
|
</div>
|
|
674
636
|
</div>
|
|
675
637
|
</div>
|
|
@@ -688,7 +650,7 @@
|
|
|
688
650
|
</div>
|
|
689
651
|
<div class="modal-footer scratchpad-footer">
|
|
690
652
|
<span id="scratchpad-charcount" class="scratchpad-charcount">0 chars</span>
|
|
691
|
-
<button class="btn btn-
|
|
653
|
+
<button class="btn btn-secondary" onclick="closeScratchpad()">Close</button>
|
|
692
654
|
</div>
|
|
693
655
|
</div>
|
|
694
656
|
</div>
|
|
@@ -712,7 +674,7 @@
|
|
|
712
674
|
<div class="modal-body" id="storage-modal-body" style="overflow-y:auto;min-height:200px;max-height:60vh;padding-top:16px;padding-right:8px;"></div>
|
|
713
675
|
<div class="modal-footer">
|
|
714
676
|
<button id="storage-cleanup-btn" class="btn btn-secondary" onclick="cleanupOrphanedStorage()">Clean Orphaned</button>
|
|
715
|
-
<button class="btn btn-
|
|
677
|
+
<button class="btn btn-secondary" onclick="closeStorageManager()">Close</button>
|
|
716
678
|
</div>
|
|
717
679
|
</div>
|
|
718
680
|
</div>
|