// ── 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'); var apiKeysLink = document.getElementById('dashboardApiKeysLink'); if (currentUser && currentUser.isAdmin) { adminLink.hidden = false; adminLink.addEventListener('click', (e) => { e.preventDefault(); navigateTo('admin'); }); apiKeysLink.hidden = false; apiKeysLink.addEventListener('click', (e) => { e.preventDefault(); navigateTo('api-keys'); }); 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, availableAgents, sessions, cronjobs, shares, telegramBots] = await Promise.all([ apiGetAgents(), apiGetAvailableAgents(), apiGetSessions(), apiGetCronjobs(), apiListShares(), apiGetTelegramBots() ]); const agentMap = {}; for (const a of availableAgents) 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 { dropdown: sessionMenu } = _initCardMenu(card); chatBtn.addEventListener('click', (e) => { e.stopPropagation(); if (chatBtn.disabled) return; sessionMenu.hidden = true; navigateTo('chat', { id: s.sessionId }); }); _onCardMenuAction(sessionMenu, 'edit', () => navigateTo('session', { id: s.sessionId })); _onCardMenuAction(sessionMenu, 'openclaw-import', () => 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 { dropdown: agentMenu } = _initCardMenu(card); _onCardMenuAction(agentMenu, 'files', () => openFileExplorer({ agentId: a.agentId })); _onCardMenuAction(agentMenu, 'edit', () => 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 = `