'use client'; import { useEffect, useState, useCallback } from 'react'; import { SidebarNav } from '@/components/sidebar-nav'; import { api } from '@/lib/api'; import type { Service, Deployment } from '@/lib/api'; import { useAuth } from '@/lib/auth'; import { Play, Activity, Clock, RefreshCw, Plus, Edit, Trash2, FileText } from 'lucide-react'; import { ServiceForm } from '@/components/service-form'; import { LogViewer } from '@/components/log-viewer'; export default function DashboardPage() { const { user } = useAuth(); const [services, setServices] = useState([]); const [recentDeployments, setRecentDeployments] = useState([]); const [loading, setLoading] = useState(true); const [refreshing, setRefreshing] = useState(false); const [error, setError] = useState(null); const [showServiceForm, setShowServiceForm] = useState(false); const [editingService, setEditingService] = useState(); const [viewingLogsDeployment, setViewingLogsDeployment] = useState(null); const loadData = useCallback(async () => { setError(null); try { // Add timeout to prevent hanging const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error('API request timeout')), 15000) ); const [servicesData, deploymentsData] = await Promise.race([ Promise.all([ api.getServices(), api.getDeployments(10), ]), timeoutPromise ]) as [Service[], Deployment[]]; setServices(servicesData); setRecentDeployments(deploymentsData); } catch (error) { console.error('Failed to load data:', error); const errorMessage = error instanceof Error ? error.message : 'Failed to load data'; setError(errorMessage); // Set empty arrays on error to prevent hanging setServices([]); setRecentDeployments([]); } finally { setLoading(false); setRefreshing(false); } }, []); const refreshHealth = useCallback(async () => { setRefreshing(true); try { await api.clearHealthCache(); const [servicesData, deploymentsData] = await Promise.all([ api.getServices(), api.getDeployments(10), ]); setServices(servicesData); setRecentDeployments(deploymentsData); } catch (error) { console.error('Failed to refresh health:', error); } finally { setRefreshing(false); } }, []); useEffect(() => { loadData(); // Auto-refresh every 60 seconds const interval = setInterval(() => { loadData(); }, 60000); return () => clearInterval(interval); }, [loadData]); async function handleDeploy(serviceId: string) { try { await api.triggerDeployment(serviceId); await loadData(); } catch (error) { console.error('Deploy failed:', error); alert('Deployment failed'); } } function handleCreateService() { setEditingService(undefined); setShowServiceForm(true); } function handleEditService(service: Service) { setEditingService(service); setShowServiceForm(true); } async function handleDeleteService(serviceId: string) { if (!confirm('Are you sure you want to delete this service?')) { return; } try { await api.deleteService(serviceId); await loadData(); } catch (error) { console.error('Delete failed:', error); alert('Failed to delete service'); } } function handleCloseServiceForm() { setShowServiceForm(false); setEditingService(undefined); } function handleViewLogs(deploymentId: string) { setViewingLogsDeployment(deploymentId); } function handleCloseLogs() { setViewingLogsDeployment(null); } function getStatusColor(status: string) { switch (status) { case 'up': case 'success': return 'text-green-600 bg-green-50 border-green-200'; case 'down': case 'failed': return 'text-red-600 bg-red-50 border-red-200'; case 'degraded': case 'running': return 'text-yellow-600 bg-yellow-50 border-yellow-200'; default: return 'text-gray-600 bg-gray-50 border-gray-200'; } } if (loading) { return (
Loading...
); } return (
{/* Header */}
{error && (
Error: {error}

Unable to connect to the DevOps API. Please check your connection and try again.

)}

Dashboard

Services and deployments overview

{/* Services Grid */}

Services

{services.length === 0 ? (

No services configured

{error ? 'Unable to load services due to API connection issues.' : 'Get started by creating your first service.'}

) : (
{services.map((service) => (

{service.name}

{service.repoPath}

{service.status}
Version: {service.version}
{service.lastDeployedAt && (
Last deploy: {new Date(service.lastDeployedAt).toLocaleString()}
)}
))}
)}
{/* Recent Deployments */}

Recent Deployments

{recentDeployments.length === 0 ? (

No recent deployments

{error ? 'Unable to load deployments due to API connection issues.' : 'Deployments will appear here once you start deploying services.'}

) : (
{recentDeployments.map((deployment) => { const service = services.find(s => s.id === deployment.serviceId); return ( ); })}
Service Version Status Triggered Time Actions
{service?.name || deployment.serviceId} {deployment.version} {deployment.status} {deployment.triggeredBy} {new Date(deployment.triggeredAt).toLocaleString()}
)}
{showServiceForm && ( )} {viewingLogsDeployment && ( )}
); }