diff --git a/web/app.js b/web/app.js index 82fd420..72e04ef 100644 --- a/web/app.js +++ b/web/app.js @@ -50,9 +50,11 @@ const updateModalClose = document.getElementById("update-modal-close"); const updateModalInstall = document.getElementById("update-modal-install"); const updateModalReleases = document.getElementById("update-modal-releases"); const plansRefreshButton = document.getElementById("plans-refresh"); +const plansCloseButton = document.getElementById("plans-close"); const planForm = document.getElementById("plan-form"); const plansStatusEl = document.getElementById("plans-status"); const plansDashboardEl = document.getElementById("plans-dashboard"); +const plansRailListEl = document.getElementById("plans-rail-list"); let ollamaOnline = true; let latestUpdate = null; @@ -742,7 +744,6 @@ function toggleSidebarPanel(panelName) { const panels = { settings: { panel: settingsPanel, button: settingsToggle }, memory: { panel: memoryPanel, button: memoryToggle }, - plans: { panel: plansPanel, button: plansToggle }, ollama: { panel: ollamaPanel, button: ollamaToggle }, }; const target = panels[panelName]; @@ -763,7 +764,6 @@ function toggleSidebarPanel(panelName) { checkForUpdate(); } if (panelName === "memory") refreshMemory(); - if (panelName === "plans") refreshPlans(); if (panelName === "ollama") { refreshConfig(); refreshOllamaStatus(); @@ -971,6 +971,19 @@ function closeNegotiationPanel() { negotiationStatusEl.textContent = ""; } +function openPlansPanel(openPlanId = null) { + if (!plansPanel) return; + plansPanel.hidden = false; + plansToggle?.setAttribute("aria-expanded", "true"); + refreshPlans(openPlanId); +} + +function closePlansPanel() { + if (!plansPanel) return; + plansPanel.hidden = true; + plansToggle?.setAttribute("aria-expanded", "false"); +} + function renderNegotiationMessages(data) { negotiationMessagesEl.innerHTML = ""; const items = Array.isArray(data) ? data : [data].filter(Boolean); @@ -1062,13 +1075,47 @@ async function createPlan(event) { } async function refreshPlans(openPlanId = null) { - if (!plansDashboardEl) return; + if (!plansDashboardEl && !plansRailListEl) return; try { const response = await fetch("/api/plans"); const result = await response.json(); - await renderPlans(result.plans || [], openPlanId); + const plans = result.plans || []; + renderPlansRail(plans); + if (plansDashboardEl) await renderPlans(plans, openPlanId); } catch (error) { - plansDashboardEl.textContent = `Plans failed: ${fetchErrorMessage(error)}`; + if (plansDashboardEl) plansDashboardEl.textContent = `Plans failed: ${fetchErrorMessage(error)}`; + if (plansRailListEl) plansRailListEl.textContent = `Plans failed: ${fetchErrorMessage(error)}`; + } +} + +function renderPlansRail(plans) { + if (!plansRailListEl) return; + plansRailListEl.innerHTML = ""; + if (!plans.length) { + plansRailListEl.innerHTML = '