// ── Dashboard Page ── registerPage('dashboard', { async init() { // Einstellungen-Link document.getElementById('dashboardSettingsLink').addEventListener('click', (e) => { e.preventDefault(); navigateTo('settings'); }); // Profil-Link document.getElementById('dashboardProfileLink').addEventListener('click', (e) => { e.preventDefault(); navigateTo('profile'); }); // Admin-Links (nur für Admins sichtbar) var adminLink = document.getElementById('dashboardAdminLink'); var serverSettingsLink = document.getElementById('dashboardServerSettingsLink'); if (currentUser && currentUser.isAdmin) { adminLink.hidden = false; adminLink.addEventListener('click', (e) => { e.preventDefault(); navigateTo('admin'); }); serverSettingsLink.hidden = false; serverSettingsLink.addEventListener('click', (e) => { e.preventDefault(); navigateTo('server-settings'); }); } // Globaler Click-Handler zum Schließen aller Card-Menüs document.addEventListener('click', this._closeCardMenus = () => closeAllCardMenus()); // Telegram-Config parallel pro Session laden (sessions werden gleich geladen) const [agents, sessions, cronjobs, shares, telegramBots] = await Promise.all([ apiGetAgents(), apiGetSessions(), apiGetCronjobs(), apiListShares(), apiGetTelegramBots() ]); const agentMap = {}; for (const a of agents) agentMap[a.agentId] = a; // Sessions const grid = document.getElementById('sessionCards'); grid.innerHTML = ''; for (const s of sessions) { const agent = s.agentId ? agentMap[s.agentId] : null; const card = buildSessionCard(s, agent); // Git-Status aus der Session-Response rendern (inline vom Backend) if (s.gitStatus) { const gs = s.gitStatus; const metaEl = card.querySelector('.card-meta'); if (metaEl) { const parts = []; if (gs.add > 0) { const tip = `${gs.add} ${gs.add === 1 ? 'Datei' : 'Dateien'} hinzugefügt`; parts.push(`+${gs.add}`); } if (gs.edit > 0) { const tip = `${gs.edit} ${gs.edit === 1 ? 'Datei' : 'Dateien'} geändert`; parts.push(`~${gs.edit}`); } if (gs.delete > 0) { const tip = `${gs.delete} ${gs.delete === 1 ? 'Datei' : 'Dateien'} gelöscht`; parts.push(`-${gs.delete}`); } if (gs.outgoing > 0) { const tip = `${gs.outgoing} ${gs.outgoing === 1 ? 'Commit muss' : 'Commits müssen'} noch gepusht werden`; parts.push(` ${gs.outgoing}`); } if (parts.length) { const gitEl = document.createElement('span'); gitEl.className = 'card-meta-item card-git-status'; gitEl.innerHTML = parts.join(' '); metaEl.appendChild(gitEl); } } } // Menü zum title-row hinzufügen const titleRow = card.querySelector('.card-title-row'); titleRow.insertAdjacentHTML('beforeend', `
`); // Chat deaktivieren wenn kein Agent gesetzt const chatBtn = card.querySelector('[data-action="chat"]'); if (!agent) { chatBtn.disabled = true; chatBtn.title = 'Kein Agent zugewiesen'; } // Card selbst klickbar wenn Agent zugewiesen if (agent) { card.classList.add('clickable'); card.addEventListener('click', () => navigateTo('chat', { id: s.sessionId })); } const menuTrigger = card.querySelector('.card-menu-trigger'); const menuDropdown = card.querySelector('.card-menu-dropdown'); menuTrigger.addEventListener('click', (e) => { e.stopPropagation(); _openCardMenu(menuTrigger, menuDropdown); }); chatBtn.addEventListener('click', (e) => { e.stopPropagation(); if (chatBtn.disabled) return; menuDropdown.hidden = true; navigateTo('chat', { id: s.sessionId }); }); menuDropdown.querySelector('[data-action="edit"]').addEventListener('click', (e) => { e.stopPropagation(); menuDropdown.hidden = true; navigateTo('session', { id: s.sessionId }); }); menuDropdown.querySelector('[data-action="openclaw-import"]').addEventListener('click', (e) => { e.stopPropagation(); menuDropdown.hidden = true; showOpenClawImportModal(s.sessionId); }); grid.appendChild(card); } // Neue Session Button document.getElementById('newSessionBtn').addEventListener('click', () => navigateTo('session')); // Agents const agentGrid = document.getElementById('agentCards'); agentGrid.innerHTML = ''; for (const a of agents) { const skills = a.skills || []; const card = buildAgentCard(a, skills); // Menü zum title-row hinzufügen const titleRow = card.querySelector('.card-title-row'); const menuHtml = ``; titleRow.insertAdjacentHTML('beforeend', menuHtml); const menuTrigger = card.querySelector('.card-menu-trigger'); const menuDropdown = card.querySelector('.card-menu-dropdown'); menuTrigger.addEventListener('click', (e) => { e.stopPropagation(); _openCardMenu(menuTrigger, menuDropdown); }); menuDropdown.querySelector('[data-action="files"]').addEventListener('click', (e) => { e.stopPropagation(); menuDropdown.hidden = true; openFileExplorer({ agentId: a.agentId }); }); menuDropdown.querySelector('[data-action="edit"]').addEventListener('click', (e) => { e.stopPropagation(); menuDropdown.hidden = true; navigateTo('agent', { id: a.agentId }); }); agentGrid.appendChild(card); } // Neuer Agent Button document.getElementById('newAgentBtn').addEventListener('click', () => navigateTo('agent')); // Cronjobs const cronjobGrid = document.getElementById('cronjobCards'); cronjobGrid.innerHTML = ''; for (const cj of cronjobs) { const card = document.createElement('div'); card.className = 'card card-compact'; const statusBadge = cj.isEnabled ? ' Aktiv' : ' Pausiert'; const lastRunIcon = cj.lastRunStatus === 'success' ? '✅' : cj.lastRunStatus === 'error' ? '❌' : ''; const cronDesc = describeCron(cj.cronExpression) || cj.cronExpression; card.innerHTML = `