summaryrefslogtreecommitdiff
path: root/web/app.js
diff options
context:
space:
mode:
authorClaude <noreply@anthropic.com>2026-05-25 05:09:10 +0000
committerClaude <noreply@anthropic.com>2026-05-25 05:09:10 +0000
commit42bb6432d3e53042723b43330c22eafbf553e10f (patch)
tree7e95d5d70570cd34d21f35fa39f9141956b8755a /web/app.js
parentb44c8277465c3b4e03fe4de4dd93850413023b69 (diff)
refactor(web): remove the create-task modal from the UI (Phase 3)
The observability UI no longer creates tasks; chatbots do that via the chatbot MCP server. Removes the New Task button, the #task-modal (manual form + the now-defunct AI-elaborate textbox + validate panel), their handlers (elaborateTask/validateTask/buildValidatePayload/renderValidationResult/ openTaskModal/closeTaskModal/createTask) and the orphaned newTaskButtonShouldShowOnTab helper plus its test. Verified with node --test (267 JS tests pass) and a JS syntax check. Not browser-verified in this environment. https://claude.ai/code/session_01SESwn7kQ7oP62trWw6pc39
Diffstat (limited to 'web/app.js')
-rw-r--r--web/app.js274
1 files changed, 0 insertions, 274 deletions
diff --git a/web/app.js b/web/app.js
index 09b545b..0a66a11 100644
--- a/web/app.js
+++ b/web/app.js
@@ -465,9 +465,6 @@ export function filterActiveTasks(tasks) {
return tasks.filter(t => _PANEL_ACTIVE_STATES.has(t.state));
}
-// The New Task button is always visible regardless of active tab.
-export function newTaskButtonShouldShowOnTab(_tab) { return true; }
-
export function filterTasksByTab(tasks, tab) {
if (tab === 'active') return tasks.filter(t => ACTIVE_STATES.has(t.state));
if (tab === 'interrupted') return tasks.filter(t => INTERRUPTED_STATES.has(t.state));
@@ -1642,152 +1639,6 @@ async function submitAnswer(taskId, questionId, answer, banner) {
// ── Elaborate (Draft with AI) ─────────────────────────────────────────────────
-async function elaborateTask(prompt, workingDir) {
- const res = await fetch(`${API_BASE}/api/tasks/elaborate`, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ prompt, project_dir: workingDir }),
- });
- if (!res.ok) {
- let msg = `HTTP ${res.status}`;
- try { const body = await res.json(); msg = body.error || msg; } catch {}
- throw new Error(msg);
- }
- return res.json();
-}
-
-// ── Validate ──────────────────────────────────────────────────────────────────
-
-async function validateTask(payload) {
- const res = await fetch(`${API_BASE}/api/tasks/validate`, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify(payload),
- });
- if (!res.ok) {
- let msg = res.statusText;
- try { const body = await res.json(); msg = body.error || body.message || msg; } catch {}
- throw new Error(msg);
- }
- return res.json();
-}
-
-function buildValidatePayload() {
- const f = document.getElementById('task-form');
- const name = f.querySelector('[name="name"]').value;
- const instructions = f.querySelector('[name="instructions"]').value;
- const repository_url = document.getElementById('repository-url').value;
- const container_image = document.getElementById('container-image').value;
- const allowedToolsEl = f.querySelector('[name="allowed_tools"]');
- const allowed_tools = allowedToolsEl
- ? allowedToolsEl.value.split(',').map(s => s.trim()).filter(Boolean)
- : [];
- return { name, repository_url, agent: { instructions, container_image, allowed_tools } };
-}
-
-function renderValidationResult(result) {
- const container = document.getElementById('validate-result');
- container.removeAttribute('hidden');
- container.dataset.clarity = result.clarity;
-
- let icon;
- if (result.ready === true) {
- icon = '✓';
- } else if (result.clarity === 'ambiguous') {
- icon = '⚠';
- } else {
- icon = '✗';
- }
-
- container.innerHTML = '';
-
- const header = document.createElement('div');
- header.className = 'validate-header';
- const iconSpan = document.createElement('span');
- iconSpan.className = 'validate-icon';
- iconSpan.textContent = icon;
- const summarySpan = document.createElement('span');
- summarySpan.textContent = ' ' + (result.summary || '');
- header.append(iconSpan, summarySpan);
- container.appendChild(header);
-
- if (result.questions && result.questions.length > 0) {
- const ul = document.createElement('ul');
- ul.className = 'validate-questions';
- for (const q of result.questions) {
- const li = document.createElement('li');
- li.className = q.severity === 'blocking' ? 'validate-blocking' : 'validate-minor';
- li.textContent = q.text;
- ul.appendChild(li);
- }
- container.appendChild(ul);
- }
-
- if (result.suggestions && result.suggestions.length > 0) {
- const ul = document.createElement('ul');
- ul.className = 'validate-suggestions';
- for (const s of result.suggestions) {
- const li = document.createElement('li');
- li.className = 'validate-suggestion';
- li.textContent = s;
- ul.appendChild(li);
- }
- container.appendChild(ul);
- }
-}
-
-// ── Task modal ────────────────────────────────────────────────────────────────
-
-async function openTaskModal() {
- document.getElementById('task-modal').showModal();
-}
-
-function closeTaskModal() {
- document.getElementById('task-modal').close();
- document.getElementById('task-form').reset();
- document.getElementById('elaborate-prompt').value = '';
- const validateResult = document.getElementById('validate-result');
- validateResult.setAttribute('hidden', '');
- validateResult.innerHTML = '';
- validateResult.removeAttribute('data-clarity');
-}
-
-async function createTask(formData) {
- const repository_url = formData.get('repository_url');
- const container_image = formData.get('container_image');
- const elaboratePromptEl = document.getElementById('elaborate-prompt');
- const elaborationInput = elaboratePromptEl ? elaboratePromptEl.value.trim() : '';
- const body = {
- name: formData.get('name'),
- description: '',
- elaboration_input: elaborationInput || undefined,
- repository_url: repository_url,
- agent: {
- instructions: formData.get('instructions'),
- container_image: container_image,
- max_budget_usd: parseFloat(formData.get('max_budget_usd')),
- type: 'container',
- },
- timeout: formData.get('timeout'),
- priority: formData.get('priority'),
- tags: [],
- };
-
- const res = await fetch(`${API_BASE}/api/tasks`, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify(body),
- });
-
- if (!res.ok) {
- const text = await res.text();
- throw new Error(text || `HTTP ${res.status}`);
- }
-
- closeTaskModal();
- await poll();
-}
-
// ── Task side panel ───────────────────────────────────────────────────────────
// Format Go's task.Duration JSON value {"Duration": <nanoseconds>} to human string.
@@ -3545,9 +3396,6 @@ if (typeof document !== 'undefined') {
btn.addEventListener('click', () => switchTab(btn.dataset.tab));
});
- // Task modal
- document.getElementById('btn-new-task').addEventListener('click', openTaskModal);
- document.getElementById('btn-cancel-task').addEventListener('click', closeTaskModal);
// Push notifications button
const btnNotify = document.getElementById('btn-notifications');
@@ -3555,128 +3403,6 @@ if (typeof document !== 'undefined') {
btnNotify.addEventListener('click', () => enableNotifications(btnNotify));
}
- // Validate button
- document.getElementById('btn-validate').addEventListener('click', async () => {
- const btn = document.getElementById('btn-validate');
- const resultDiv = document.getElementById('validate-result');
- btn.disabled = true;
- btn.textContent = 'Checking…';
- try {
- const payload = buildValidatePayload();
- const result = await validateTask(payload);
- renderValidationResult(result);
- } catch (err) {
- resultDiv.removeAttribute('hidden');
- resultDiv.textContent = 'Validation failed: ' + err.message;
- } finally {
- btn.disabled = false;
- btn.textContent = 'Validate Instructions';
- }
- });
-
- // Draft with AI button
- const btnElaborate = document.getElementById('btn-elaborate');
- btnElaborate.addEventListener('click', async () => {
- const prompt = document.getElementById('elaborate-prompt').value.trim();
- if (!prompt) {
- const form = document.getElementById('task-form');
- // Remove previous error
- const prev = form.querySelector('.form-error');
- if (prev) prev.remove();
- const errEl = document.createElement('p');
- errEl.className = 'form-error';
- errEl.textContent = 'Please enter a description before drafting.';
- form.querySelector('.elaborate-section').appendChild(errEl);
- return;
- }
-
- btnElaborate.disabled = true;
- btnElaborate.textContent = 'Drafting…';
-
- // Remove any previous errors or banners
- const form = document.getElementById('task-form');
- form.querySelectorAll('.form-error, .elaborate-banner').forEach(el => el.remove());
-
- try {
- const repoUrl = document.getElementById('repository-url').value.trim();
- const result = await elaborateTask(prompt, repoUrl);
-
- // Populate form fields
- const f = document.getElementById('task-form');
- if (result.name)
- f.querySelector('[name="name"]').value = result.name;
- if (result.agent && result.agent.instructions)
- f.querySelector('[name="instructions"]').value = result.agent.instructions;
- if (result.repository_url || result.agent?.repository_url) {
- document.getElementById('repository-url').value = result.repository_url || result.agent.repository_url;
- }
- if (result.agent && result.agent.container_image) {
- document.getElementById('container-image').value = result.agent.container_image;
- }
- if (result.agent && result.agent.max_budget_usd != null)
- f.querySelector('[name="max_budget_usd"]').value = result.agent.max_budget_usd;
- if (result.timeout)
- f.querySelector('[name="timeout"]').value = result.timeout;
- if (result.priority) {
- const sel = f.querySelector('[name="priority"]');
- if ([...sel.options].some(o => o.value === result.priority)) {
- sel.value = result.priority;
- }
- }
-
- // Show success banner
- const banner = document.createElement('p');
- banner.className = 'elaborate-banner';
- banner.textContent = 'AI draft ready — review and submit.';
- document.getElementById('task-form').querySelector('.elaborate-section').appendChild(banner);
-
- // Auto-validate after elaboration
- try {
- const result = await validateTask(buildValidatePayload());
- renderValidationResult(result);
- } catch (_) {
- // silent - elaboration already succeeded, validation is bonus
- }
- } catch (err) {
- const errEl = document.createElement('p');
- errEl.className = 'form-error';
- errEl.textContent = `Elaboration failed: ${err.message}`;
- document.getElementById('task-form').querySelector('.elaborate-section').appendChild(errEl);
- } finally {
- btnElaborate.disabled = false;
- btnElaborate.textContent = 'Draft with AI ✦';
- }
- });
-
- document.getElementById('task-form').addEventListener('submit', async e => {
- e.preventDefault();
-
- // Remove any previous error
- const prev = e.target.querySelector('.form-error');
- if (prev) prev.remove();
-
- const btn = e.submitter;
- btn.disabled = true;
- btn.textContent = 'Creating…';
-
- try {
- const validateResult = document.getElementById('validate-result');
- if (!validateResult.hasAttribute('hidden') && validateResult.dataset.clarity && validateResult.dataset.clarity !== 'clear') {
- if (!window.confirm('The validator flagged issues. Create task anyway?')) {
- return;
- }
- }
- await createTask(new FormData(e.target));
- } catch (err) {
- const errEl = document.createElement('p');
- errEl.className = 'form-error';
- errEl.textContent = err.message;
- e.target.appendChild(errEl);
- } finally {
- btn.disabled = false;
- btn.textContent = 'Create & Queue';
- }
- });
// Story modal
const storyModal = document.getElementById('story-modal');