let _currentPanel = 'chat';
let _skillsData = null; // cached skills list
async function switchPanel(name) {
_currentPanel = name;
// Update nav tabs
document.querySelectorAll('.nav-tab').forEach(t => t.classList.toggle('active', t.dataset.panel === name));
// Update panel views
document.querySelectorAll('.panel-view').forEach(p => p.classList.remove('active'));
const panelEl = $('panel' + name.charAt(0).toUpperCase() + name.slice(1));
if (panelEl) panelEl.classList.add('active');
// Lazy-load panel data
if (name === 'tasks') await loadCrons();
if (name === 'skills') await loadSkills();
if (name === 'memory') await loadMemory();
if (name === 'workspaces') await loadWorkspacesPanel();
if (name === 'profiles') await loadProfilesPanel();
if (name === 'todos') loadTodos();
if (name === 'missioncontrol') await loadMissionControl();
}
// ── Cron panel ──
async function loadCrons() {
const box = $('cronList');
try {
const data = await api('/api/crons');
if (!data.jobs || !data.jobs.length) {
box.innerHTML = `
${li('clock',12)} ${esc(job.schedule_display || job.schedule?.expression || '')} | ${esc(t('cron_next'))}: ${esc(nextRun)} | ${esc(t('cron_last'))}: ${esc(lastRun)}
${esc((job.prompt||'').slice(0,300))}${(job.prompt||'').length>300?'…':''}
${job.state==='paused'
? ``
: ``}
`;
box.appendChild(item);
// Eagerly load last output for visible items
loadCronOutput(job.id);
}
} catch(e) { box.innerHTML = `
${li('lightbulb',12)} Tipp
Frag im Chat nach einer Todo-Liste, z.B.:
"Plane mein Wochenende: Freitags einkaufen, samtags Sport, sonntags relaxen"
`;
return;
}
const statusIcon = {pending:li('square',14), in_progress:li('loader',14), completed:li('check',14), cancelled:li('x',14)};
const statusColor = {pending:'var(--muted)', in_progress:'var(--blue)', completed:'rgba(100,200,100,.8)', cancelled:'rgba(200,100,100,.5)'};
panel.innerHTML = todos.map(t => `
No tasks yet.
Add one above ↑
';
} else {
const statusMeta = {
backlog: { icon: '○', color: 'var(--muted)', label: 'Backlog' },
progress: { icon: '◐', color: '#ff9800', label: 'In Progress' },
done: { icon: '●', color: '#4caf50', label: 'Done' }
};
listEl.innerHTML = filteredTasks.map(t => {
const meta = statusMeta[t.status] || statusMeta.backlog;
const p = priorityMap[t.priority] || { name: 'Unknown', color: '#808080' };
const emoji = priorityEmoji[t.priority] || '•';
return `