Skip to main content
Glama
dashboard_overview.html12.9 kB
<!-- Template pour la page principale du dashboard --> <div class="dashboard-overview"> <!-- Métriques principales --> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-6"> <div class="card"> <div class="card-body"> <div class="flex items-center justify-between"> <div> <p class="text-secondary text-sm">Connexions actives</p> <p class="text-2xl font-bold" id="active-connections">0</p> </div> <div class="text-primary text-3xl">🌐</div> </div> </div> </div> <div class="card"> <div class="card-body"> <div class="flex items-center justify-between"> <div> <p class="text-secondary text-sm">Outils MCP</p> <p class="text-2xl font-bold" id="total-tools">0</p> </div> <div class="text-primary text-3xl">🔧</div> </div> </div> </div> <div class="card"> <div class="card-body"> <div class="flex items-center justify-between"> <div> <p class="text-secondary text-sm">Requêtes/h</p> <p class="text-2xl font-bold" id="requests-per-hour">0</p> </div> <div class="text-primary text-3xl">📊</div> </div> </div> </div> <div class="card"> <div class="card-body"> <div class="flex items-center justify-between"> <div> <p class="text-secondary text-sm">Uptime</p> <p class="text-2xl font-bold" id="uptime">--</p> </div> <div class="text-primary text-3xl">⏱️</div> </div> </div> </div> </div> <!-- Graphiques et activité récente --> <div class="grid grid-cols-1 lg:grid-cols-2 gap-6"> <!-- Graphique d'activité --> <div class="card"> <div class="card-header"> <h3 class="card-title">Activité des 24 dernières heures</h3> </div> <div class="card-body"> <div class="activity-chart"> <canvas id="activity-chart" width="400" height="200"></canvas> </div> </div> </div> <!-- Connexions récentes --> <div class="card"> <div class="card-header"> <h3 class="card-title">Connexions récentes</h3> </div> <div class="card-body"> <div class="recent-connections"> <div id="connections-list" class="space-y-3"> <!-- Les connexions seront ajoutées dynamiquement --> </div> </div> </div> </div> </div> <!-- Outils MCP disponibles --> <div class="card mt-6"> <div class="card-header"> <h3 class="card-title">Outils MCP disponibles</h3> <button class="btn btn-primary btn-sm" id="refresh-tools">🔄 Actualiser</button> </div> <div class="card-body"> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4" id="tools-grid"> <!-- Les outils seront ajoutés dynamiquement --> </div> </div> </div> </div> <script> class DashboardOverview { constructor() { this.init(); } init() { // Attendre que les éléments DOM soient disponibles const checkElements = () => { const requiredElements = [ 'active-connections', 'total-tools', 'requests-per-hour', 'uptime', 'connections-list', 'tools-grid' ]; const allElementsExist = requiredElements.every(id => document.getElementById(id) !== null ); if (allElementsExist) { this.loadMetrics(); this.loadRecentConnections(); this.loadAvailableTools(); this.setupEventListeners(); // Actualiser les métriques toutes les 30 secondes setInterval(() => { this.loadMetrics(); this.loadRecentConnections(); }, 30000); } else { // Réessayer dans 100ms si les éléments ne sont pas encore disponibles setTimeout(checkElements, 100); } }; checkElements(); } setupEventListeners() { const refreshButton = document.getElementById('refresh-tools'); if (refreshButton) { refreshButton.addEventListener('click', () => { this.loadAvailableTools(); }); } } async loadMetrics() { try { const response = await fetch('/api/metrics'); const metrics = await response.json(); // Vérifier que les éléments existent avant de les modifier const activeConnections = document.getElementById('active-connections'); const totalTools = document.getElementById('total-tools'); const requestsPerHour = document.getElementById('requests-per-hour'); const uptime = document.getElementById('uptime'); if (activeConnections) activeConnections.textContent = metrics.active_connections || 0; if (totalTools) totalTools.textContent = metrics.total_tools || 0; if (requestsPerHour) requestsPerHour.textContent = metrics.requests_per_hour || 0; if (uptime) uptime.textContent = this.formatUptime(metrics.uptime || 0); this.updateActivityChart(metrics.activity_data); } catch (error) { console.error('Erreur lors du chargement des métriques:', error); } } async loadRecentConnections() { try { const response = await fetch('/api/connections/recent'); const connections = await response.json(); const container = document.getElementById('connections-list'); if (!container) { // Élément pas trouvé - probablement sur une autre page return; } container.innerHTML = ''; if (connections.length === 0) { container.innerHTML = '<p class="text-secondary">Aucune connexion récente</p>'; return; } connections.forEach(conn => { const item = document.createElement('div'); item.className = 'flex items-center justify-between p-3 bg-gray-50 rounded-lg'; item.innerHTML = ` <div class="flex items-center gap-3"> <div class="status-dot ${conn.active ? 'status-online' : 'status-offline'}"></div> <div> <p class="font-medium">${conn.client_ip}</p> <p class="text-sm text-secondary">${this.formatDate(conn.connected_at)}</p> </div> </div> <div class="text-sm text-secondary"> ${conn.requests_count} requêtes </div> `; container.appendChild(item); }); } catch (error) { console.error('Erreur lors du chargement des connexions:', error); } } async loadAvailableTools() { try { const response = await fetch('/api/tools'); const tools = await response.json(); const container = document.getElementById('tools-grid'); if (!container) { console.log('Élément tools-grid non trouvé dans le DOM, probablement sur une autre page'); return; } container.innerHTML = ''; if (tools.length === 0) { container.innerHTML = '<p class="text-secondary col-span-full">Aucun outil MCP disponible</p>'; return; } tools.forEach(tool => { const item = document.createElement('div'); item.className = 'card'; item.innerHTML = ` <div class="card-body"> <div class="flex items-start justify-between mb-2"> <h4 class="font-semibold">${tool.name}</h4> <span class="badge ${tool.enabled ? 'badge-success' : 'badge-warning'}"> ${tool.enabled ? 'Actif' : 'Inactif'} </span> </div> <p class="text-sm text-secondary mb-3">${tool.description || 'Aucune description'}</p> <div class="flex items-center justify-between text-xs text-secondary"> <span>${tool.category || 'Général'}</span> <span>${tool.usage_count || 0} utilisations</span> </div> </div> `; container.appendChild(item); }); } catch (error) { console.error('Erreur lors du chargement des outils:', error); } } updateActivityChart(data) { // Ici, on pourrait utiliser Chart.js ou une autre bibliothèque // Pour l'instant, on crée un graphique simple const canvas = document.getElementById('activity-chart'); if (!canvas) return; // Vérifier que l'élément existe const ctx = canvas.getContext('2d'); // Nettoyer le canvas ctx.clearRect(0, 0, canvas.width, canvas.height); if (!data || data.length === 0) { ctx.fillStyle = '#6b7280'; ctx.font = '14px sans-serif'; ctx.textAlign = 'center'; ctx.fillText('Aucune donnée disponible', canvas.width / 2, canvas.height / 2); return; } // Dessiner un graphique en barres simple const maxValue = Math.max(...data.map(d => d.requests)); const barWidth = canvas.width / data.length; data.forEach((point, index) => { const barHeight = (point.requests / maxValue) * (canvas.height - 40); const x = index * barWidth; const y = canvas.height - barHeight - 20; ctx.fillStyle = '#3b82f6'; ctx.fillRect(x + 2, y, barWidth - 4, barHeight); // Étiquette de l'heure ctx.fillStyle = '#6b7280'; ctx.font = '10px sans-serif'; ctx.textAlign = 'center'; ctx.fillText(point.hour, x + barWidth / 2, canvas.height - 5); }); } formatUptime(seconds) { const days = Math.floor(seconds / 86400); const hours = Math.floor((seconds % 86400) / 3600); const minutes = Math.floor((seconds % 3600) / 60); if (days > 0) return `${days}j ${hours}h`; if (hours > 0) return `${hours}h ${minutes}m`; return `${minutes}m`; } formatDate(dateString) { const date = new Date(dateString); const now = new Date(); const diff = now - date; if (diff < 60000) return 'À l\'instant'; if (diff < 3600000) return `Il y a ${Math.floor(diff / 60000)} min`; if (diff < 86400000) return `Il y a ${Math.floor(diff / 3600000)} h`; return date.toLocaleDateString('fr-FR', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' }); } } // Initialiser le dashboard overview quand la page est chargée // Attendre un délai supplémentaire pour s'assurer que le DOM est complètement rendu const initDashboardOverview = () => { // Vérifier si les éléments existent avant d'initialiser if (document.getElementById('active-connections')) { new DashboardOverview(); } else { // Réessayer après un court délai setTimeout(initDashboardOverview, 200); } }; if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { setTimeout(initDashboardOverview, 100); }); } else { setTimeout(initDashboardOverview, 100); } </script>

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Jonathan97480/McpHomeAssistant'

If you have feedback or need assistance with the MCP directory API, please join our Discord server