diff options
| -rw-r--r-- | web/app.js | 255 |
1 files changed, 0 insertions, 255 deletions
@@ -821,43 +821,6 @@ function renderTasksIntoContainer(tasks, container, emptyMsg) { }); } -function renderQueuePanel(tasks) { - const container = document.querySelector('[data-panel="queue"] .panel-task-list'); - if (!container) return; - const visible = sortTasksByDate(filterQueueTasks(tasks)); - renderTasksIntoContainer(visible, container, 'No tasks queued.'); -} - -function renderInterruptedPanel(tasks) { - const container = document.querySelector('[data-panel="interrupted"] .panel-task-list'); - if (!container) return; - const visible = sortTasksByDate(tasks.filter(t => INTERRUPTED_STATES.has(t.state)), true); - renderTasksIntoContainer(visible, container, 'No interrupted tasks.'); -} - -function renderReadyPanel(tasks) { - const container = document.querySelector('[data-panel="ready"] .panel-task-list'); - if (!container) return; - const visible = sortTasksByDate(filterReadyTasks(tasks)); - renderTasksIntoContainer(visible, container, 'No tasks awaiting review.'); - - const completedContainer = document.querySelector('[data-panel="ready"] .ready-completed-history'); - if (!completedContainer) return; - const done = sortTasksByDate(filterAllDoneTasks(tasks), true); - if (!completedContainer.querySelector('.ready-completed-label')) { - const label = document.createElement('h2'); - label.className = 'ready-completed-label'; - label.textContent = 'Completed (24h)'; - completedContainer.prepend(label); - } - const list = completedContainer.querySelector('.ready-completed-list') || (() => { - const el = document.createElement('div'); - el.className = 'ready-completed-list'; - completedContainer.appendChild(el); - return el; - })(); - renderTasksIntoContainer(done, list, 'No completed tasks in the last 24h.'); -} // ── Run action ──────────────────────────────────────────────────────────────── @@ -2308,131 +2271,6 @@ function closeLogViewer() { activeLogSource = null; } -// ── Running view ─────────────────────────────────────────────────────────────── - -// Map of taskId → EventSource for live log streams in the Running tab. -const runningViewLogSources = {}; - -function renderRunningView(tasks) { - const currentEl = document.querySelector('.running-current'); - if (!currentEl) return; - - const running = filterRunningTasks(tasks); - - // Close SSE streams for tasks that are no longer RUNNING. - for (const [id, src] of Object.entries(runningViewLogSources)) { - if (!running.find(t => t.id === id)) { - src.close(); - delete runningViewLogSources[id]; - } - } - - // Update elapsed spans in place if the same tasks are still running. - const existingCards = currentEl.querySelectorAll('[data-task-id]'); - const existingIds = new Set([...existingCards].map(c => c.dataset.taskId)); - const unchanged = running.length > 0 && - running.length === existingCards.length && - running.every(t => existingIds.has(t.id)); - - if (unchanged) { - updateRunningElapsed(); - return; - } - - // Full re-render. - currentEl.innerHTML = ''; - - const h2 = document.createElement('h2'); - h2.textContent = 'Currently Running'; - currentEl.appendChild(h2); - - if (running.length === 0) { - const empty = document.createElement('p'); - empty.className = 'task-meta'; - empty.textContent = 'No tasks are currently running.'; - currentEl.appendChild(empty); - return; - } - - for (const task of running) { - const card = document.createElement('div'); - card.className = 'running-task-card task-card'; - card.dataset.taskId = task.id; - - const header = document.createElement('div'); - header.className = 'task-card-header'; - - const name = document.createElement('span'); - name.className = 'task-name'; - name.textContent = task.name; - - const badge = document.createElement('span'); - badge.className = 'state-badge'; - badge.dataset.state = task.state; - badge.textContent = task.state; - - const elapsed = document.createElement('span'); - elapsed.className = 'running-elapsed'; - elapsed.dataset.startedAt = task.updated_at ?? ''; - elapsed.textContent = formatElapsed(task.updated_at); - - header.append(name, badge, elapsed); - card.appendChild(header); - - // Parent context (async fetch) - if (task.parent_task_id) { - const parentEl = document.createElement('div'); - parentEl.className = 'task-meta'; - parentEl.textContent = 'Subtask of: …'; - card.appendChild(parentEl); - fetch(`${API_BASE}/api/tasks/${task.parent_task_id}`) - .then(r => r.ok ? r.json() : null) - .then(parent => { - if (parent) parentEl.textContent = `Subtask of: ${parent.name}`; - }) - .catch(() => { parentEl.textContent = ''; }); - } - - // Meta row: agent type + model + execution ID (exec ID filled in async) - const metaRow = document.createElement('div'); - metaRow.className = 'task-meta running-exec-meta'; - const agentType = (task.agent && task.agent.type) ? task.agent.type : 'claude'; - const agentModel = (task.agent && task.agent.model) ? task.agent.model : ''; - const agentSpan = document.createElement('span'); - agentSpan.textContent = agentModel ? `${agentType} (${agentModel})` : `Agent: ${agentType}`; - const execIdSpan = document.createElement('span'); - execIdSpan.className = 'execution-id running-exec-id'; - execIdSpan.textContent = 'exec: …'; - metaRow.append(agentSpan, execIdSpan); - card.appendChild(metaRow); - - // Log area - const logArea = document.createElement('div'); - logArea.className = 'running-log'; - logArea.dataset.logTarget = task.id; - card.appendChild(logArea); - - // Footer with Cancel button - const footer = document.createElement('div'); - footer.className = 'task-card-footer'; - const cancelBtn = document.createElement('button'); - cancelBtn.className = 'btn-cancel'; - cancelBtn.textContent = 'Cancel'; - cancelBtn.addEventListener('click', (e) => { - e.stopPropagation(); - handleCancel(task.id, cancelBtn, footer); - }); - footer.appendChild(cancelBtn); - card.appendChild(footer); - - currentEl.appendChild(card); - - // Open SSE stream if not already streaming for this task. - if (!runningViewLogSources[task.id]) { - startRunningLogStream(task.id, logArea); - } - } -} // taskId -> { source: EventSource, execId: string } — tracks which execution // each visible task's inline log-tail is currently attached to, so a poll- @@ -2532,99 +2370,6 @@ export async function ensureTaskLogStream(taskId, logAreaEl, { }; } -function startRunningLogStream(taskId, logArea) { - fetch(`${API_BASE}/api/executions?task_id=${taskId}&limit=1`) - .then(r => r.ok ? r.json() : []) - .then(execs => { - if (!execs || execs.length === 0) return; - const execId = execs[0].id; - - // Update the exec ID shown in the running card. - const card = document.querySelector(`[data-task-id="${taskId}"]`); - if (card) { - const execIdEl = card.querySelector('.running-exec-id'); - if (execIdEl) execIdEl.textContent = `exec: ${execId.slice(0, 8)}`; - } - - let userScrolled = false; - logArea.addEventListener('scroll', () => { - const nearBottom = logArea.scrollHeight - logArea.scrollTop - logArea.clientHeight < 50; - userScrolled = !nearBottom; - }); - - const src = new EventSource(`${API_BASE}/api/executions/${execId}/logs/stream`); - runningViewLogSources[taskId] = src; - - src.onmessage = (event) => { - let data; - try { data = JSON.parse(event.data); } catch { return; } - - const line = document.createElement('div'); - line.className = 'log-line'; - - switch (data.type) { - case 'text': { - line.classList.add('log-text'); - line.textContent = data.text ?? data.content ?? ''; - break; - } - case 'tool_use': { - line.classList.add('log-tool-use'); - const toolName = document.createElement('span'); - toolName.className = 'tool-name'; - toolName.textContent = `[${data.name ?? 'Tool'}]`; - line.appendChild(toolName); - const inputStr = data.input ? JSON.stringify(data.input) : ''; - const inputPreview = document.createElement('span'); - inputPreview.textContent = ' ' + inputStr.slice(0, 120); - line.appendChild(inputPreview); - break; - } - case 'cost': { - line.classList.add('log-cost'); - const cost = data.total_cost ?? data.cost ?? 0; - line.textContent = `Cost: $${Number(cost).toFixed(3)}`; - break; - } - default: - return; - } - - logArea.appendChild(line); - // Trim to last 500 lines. - while (logArea.childElementCount > 500) { - logArea.removeChild(logArea.firstElementChild); - } - if (!userScrolled) logArea.scrollTop = logArea.scrollHeight; - }; - - src.addEventListener('done', () => { - src.close(); - delete runningViewLogSources[taskId]; - }); - - src.onerror = () => { - src.close(); - delete runningViewLogSources[taskId]; - const errEl = document.createElement('div'); - errEl.className = 'log-line log-error'; - errEl.textContent = 'Stream closed.'; - logArea.appendChild(errEl); - }; - }) - .catch(() => {}); -} - -function updateRunningElapsed() { - document.querySelectorAll('.running-elapsed[data-started-at]').forEach(el => { - el.textContent = formatElapsed(el.dataset.startedAt || null); - }); -} - -function isRunningTabActive() { - const panel = document.querySelector('[data-panel="running"]'); - return panel && !panel.hasAttribute('hidden'); -} function sortExecutionsByDate(executions) { return sortExecutionsDesc(executions); |
