'use client'; import React, { useState, useEffect } from 'react'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Badge } from '@/components/ui/badge'; import { Github, Gitlab, FolderOpen, Search, RefreshCw, ExternalLink, GitBranch, Star, Eye, Code, Calendar, GitCompare, Brain, GitCommit, Server } from 'lucide-react'; import { authApiClient } from '@/components/apis/authApiClients'; import { useAuth } from '@/contexts/auth-context'; import Link from 'next/link'; import { useRouter } from 'next/navigation'; interface VcsRepoSummary { id: string; name: string; full_name: string; description?: string; language?: string; visibility: 'public' | 'private'; provider: 'github' | 'gitlab' | 'bitbucket' | 'gitea'; html_url: string; clone_url: string; default_branch: string; stargazers_count?: number; watchers_count?: number; forks_count?: number; updated_at: string; created_at: string; } const VcsReposPage: React.FC = () => { const { user, isLoading: authLoading } = useAuth(); const router = useRouter(); const [repositories, setRepositories] = useState([]); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const [searchQuery, setSearchQuery] = useState(''); const [filter, setFilter] = useState<'all' | 'public' | 'private'>('all'); const [providerFilter, setProviderFilter] = useState<'all' | 'github' | 'gitlab' | 'bitbucket' | 'gitea'>('all'); const [aiAnalysisLoading, setAiAnalysisLoading] = useState(null); const [aiAnalysisError, setAiAnalysisError] = useState(null); // Redirect to sign-in if not authenticated useEffect(() => { if (!authLoading && !user) { const returnUrl = encodeURIComponent(window.location.pathname + window.location.search); router.push(`/signin?returnUrl=${returnUrl}`); } }, [user, authLoading, router]); // Handle OAuth callback for all providers useEffect(() => { const handleVcsCallback = async () => { const urlParams = new URLSearchParams(window.location.search); const oauthSuccess = urlParams.get('oauth_success'); const provider = urlParams.get('provider'); const attachRepo = urlParams.get('attach_repo'); const repositoryUrl = urlParams.get('repository_url'); const branchName = urlParams.get('branch_name'); // Handle OAuth success redirect from backend if (oauthSuccess === 'true' && provider) { console.log(`🔐 [VCS OAuth] OAuth success for ${provider.toUpperCase()}`); if (attachRepo === 'true' && repositoryUrl) { console.log(`🔄 [VCS OAuth] Auto-attaching repository after OAuth: ${repositoryUrl}`); try { // Automatically attach the repository const response = await authApiClient.post(`/api/vcs/${provider}/attach-repository`, { repository_url: repositoryUrl, branch_name: branchName || undefined, user_id: user.id }, { headers: { 'x-user-id': user.id } }); if (response.data?.success) { alert(`✅ ${provider.toUpperCase()} account connected and repository attached successfully!`); // Clean up URL parameters const newUrl = window.location.pathname; window.history.replaceState({}, document.title, newUrl); // Refresh repositories to show the new one loadRepositories(); } else { alert(`${provider.toUpperCase()} account connected, but failed to attach repository. Please try again.`); } } catch (attachError) { console.error('Failed to attach repository after OAuth:', attachError); alert(`${provider.toUpperCase()} account connected, but failed to attach repository. Please try again.`); } } else { console.log(`🔐 [VCS OAuth] ${provider.toUpperCase()} account connected successfully`); alert(`${provider.toUpperCase()} account connected successfully!`); // Clean up URL parameters const newUrl = window.location.pathname; window.history.replaceState({}, document.title, newUrl); // Refresh repositories loadRepositories(); } } }; handleVcsCallback(); }, [user, loadRepositories]); // Show loading while checking authentication if (authLoading) { return (

Loading...

); } // Show sign-in prompt if not authenticated if (!user) { return (

Authentication Required

Please sign in to view your repositories from GitHub, GitLab, Bitbucket, and Gitea.

After signing in, you can connect your VCS accounts and view all your repositories in one place.
); } // Load repositories from all providers const loadRepositories = async () => { try { setIsLoading(true); setError(null); const allRepos: VcsRepoSummary[] = []; // Try to load from each provider const providers = ['github', 'gitlab', 'bitbucket', 'gitea']; for (const provider of providers) { try { const response = await authApiClient.get(`/api/vcs/${provider}/repositories`, { headers: { 'x-user-id': user.id } }); const repos = response.data?.data || []; // Add provider info to each repo const reposWithProvider = repos.map((repo: any) => ({ ...repo, provider: provider })); allRepos.push(...reposWithProvider); } catch (err) { console.log(`No ${provider} repositories or not connected:`, err); } } setRepositories(allRepos); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to load repositories'); } finally { setIsLoading(false); } }; useEffect(() => { loadRepositories(); }, []); const handleRefresh = async () => { await loadRepositories(); }; const handleAiAnalysis = async (repositoryId: string) => { try { setAiAnalysisLoading(repositoryId); setAiAnalysisError(null); const response = await authApiClient.get(`/api/ai-stream/repository/${repositoryId}/ai-stream`); const data = response.data; console.log('AI Analysis Result:', data); alert('AI Analysis completed successfully!'); } catch (err) { const errorMessage = err instanceof Error ? err.message : 'AI Analysis failed'; setAiAnalysisError(errorMessage); console.error('AI Analysis Error:', err); } finally { setAiAnalysisLoading(null); } }; const getProviderIcon = (provider: string) => { switch (provider) { case 'github': return ; case 'gitlab': return ; case 'bitbucket': return ; case 'gitea': return ; default: return ; } }; const getProviderColor = (provider: string) => { switch (provider) { case 'github': return 'bg-gray-100 text-gray-800'; case 'gitlab': return 'bg-orange-100 text-orange-800'; case 'bitbucket': return 'bg-blue-100 text-blue-800'; case 'gitea': return 'bg-green-100 text-green-800'; default: return 'bg-gray-100 text-gray-800'; } }; const filteredRepositories = repositories.filter(repo => { const matchesSearch = repo.full_name?.toLowerCase().includes(searchQuery.toLowerCase()) || repo.description?.toLowerCase().includes(searchQuery.toLowerCase()) || repo.language?.toLowerCase().includes(searchQuery.toLowerCase()); const matchesFilter = filter === 'all' || (filter === 'public' && repo.visibility === 'public') || (filter === 'private' && repo.visibility === 'private'); const matchesProvider = providerFilter === 'all' || repo.provider === providerFilter; return matchesSearch && matchesFilter && matchesProvider; }); return (

My Repositories

Manage and analyze your repositories from all connected providers

{/* Search and Filters */}
setSearchQuery(e.target.value)} className="pl-10" />
{/* Error State */} {error && (

{error}

)} {/* Loading State */} {isLoading && (
Loading repositories...
)} {/* Repositories Grid */} {!isLoading && (
{filteredRepositories.map((repo) => (
{getProviderIcon(repo.provider)} {repo.name}
{repo.visibility}
{repo.provider.toUpperCase()}
{repo.description && (

{repo.description}

)}
{repo.language && (
{repo.language}
)}
{repo.default_branch}
{aiAnalysisError && (

{aiAnalysisError}

)}
))}
)} {/* Empty State */} {!isLoading && filteredRepositories.length === 0 && (

No repositories found

{searchQuery || filter !== 'all' || providerFilter !== 'all' ? 'Try adjusting your search or filters' : 'Connect your accounts to see your repositories' }

)}
); }; export default VcsReposPage;