// app/diff-viewer/page.tsx 'use client'; import React, { useState, useEffect, Suspense } from 'react'; import { useSearchParams } from 'next/navigation'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Badge } from '@/components/ui/badge'; import { GitCommit, FolderOpen, Search, RefreshCw, ExternalLink, Brain, CheckSquare, Square } from 'lucide-react'; import DiffViewer from '@/components/diff-viewer/DiffViewer'; import { authApiClient } from '@/components/apis/authApiClients'; interface Repository { id: string; repository_name: string; owner_name: string; sync_status: string; created_at: string; } interface Commit { id: string; commit_sha: string; author_name: string; message: string; committed_at: string; files_changed: number; diffs_processed: number; total_diff_size: number; } const DiffViewerContent: React.FC = () => { const searchParams = useSearchParams(); const [repositories, setRepositories] = useState([]); const [commits, setCommits] = useState([]); const [selectedRepository, setSelectedRepository] = useState(''); const [selectedCommit, setSelectedCommit] = useState(''); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const [searchQuery, setSearchQuery] = useState(''); const [selectedCommits, setSelectedCommits] = useState([]); const [bulkAnalysisLoading, setBulkAnalysisLoading] = useState(false); const [bulkAnalysisError, setBulkAnalysisError] = useState(null); // Load repositories useEffect(() => { const loadRepositories = async () => { try { setIsLoading(true); const response = await authApiClient.get('/api/diffs/repositories'); const data = response.data; if (data.success) { setRepositories(data.data.repositories); // Handle URL parameters after repositories are loaded const repoId = searchParams.get('repo') || searchParams.get('repository'); console.log('URL repoId:', repoId); console.log('Available repositories:', data.data.repositories.map((r: Repository) => ({ id: r.id, name: r.repository_name }))); if (repoId) { console.log('Setting selected repository to:', repoId); setSelectedRepository(repoId); } } else { setError(data.message || 'Failed to load repositories'); } } catch (err) { setError(err instanceof Error ? err.message : 'Failed to load repositories'); } finally { setIsLoading(false); } }; loadRepositories(); }, [searchParams]); // Load commits when repository is selected useEffect(() => { if (selectedRepository) { const loadCommits = async () => { try { setIsLoading(true); const response = await authApiClient.get(`/api/diffs/repositories/${selectedRepository}/commits`); const data = response.data; if (data.success) { setCommits(data.data.commits); // Auto-select first commit if (data.data.commits.length > 0) { setSelectedCommit(data.data.commits[0].id); } } else { setError(data.message || 'Failed to load commits'); } } catch (err) { setError(err instanceof Error ? err.message : 'Failed to load commits'); } finally { setIsLoading(false); } }; loadCommits(); } }, [selectedRepository]); const handleRepositoryChange = (repositoryId: string) => { setSelectedRepository(repositoryId); setSelectedCommit(''); setSelectedCommits([]); // Reset bulk selection }; const handleCommitChange = (commitId: string) => { setSelectedCommit(commitId); }; const handleRefresh = () => { if (selectedRepository) { const loadCommits = async () => { try { setIsLoading(true); const response = await authApiClient.get(`/api/diffs/repositories/${selectedRepository}/commits`); const data = response.data; if (data.success) { setCommits(data.data.commits); } } catch (err) { setError(err instanceof Error ? err.message : 'Failed to refresh commits'); } finally { setIsLoading(false); } }; loadCommits(); } }; const handleBulkAnalysis = async () => { if (!selectedRepository || selectedCommits.length === 0) { setBulkAnalysisError('Please select a repository and at least one commit for bulk analysis.'); return; } setBulkAnalysisLoading(true); setBulkAnalysisError(null); try { const response = await authApiClient.post(`/api/ai/repository/${selectedRepository}/bulk-analysis`, { commit_ids: selectedCommits, analysis_type: "bulk", include_content: "true", stream: "false" }, { timeout: 120000 // 2 minutes timeout for bulk analysis }); const data = response.data; console.log('Bulk Analysis Result:', data); // Log user ID from response if (data.user_id) { console.log('🔍 [USER-ID] Received user ID in bulk analysis response:', data.user_id); } alert(`Bulk AI Analysis completed successfully for ${selectedCommits.length} commits!`); } catch (err) { const errorMessage = err instanceof Error ? err.message : 'Bulk AI Analysis failed'; setBulkAnalysisError(errorMessage); console.error('Bulk Analysis Error:', err); } finally { setBulkAnalysisLoading(false); } }; const toggleCommitSelection = (commitId: string) => { setSelectedCommits(prev => prev.includes(commitId) ? prev.filter(id => id !== commitId) : [...prev, commitId] ); }; const selectAllCommits = () => { setSelectedCommits(commits.map(commit => commit.id)); }; const clearSelection = () => { setSelectedCommits([]); }; const filteredCommits = commits.filter(commit => commit.message.toLowerCase().includes(searchQuery.toLowerCase()) || commit.author_name.toLowerCase().includes(searchQuery.toLowerCase()) || commit.commit_sha.toLowerCase().includes(searchQuery.toLowerCase()) ); return (

Git Diff Viewer

View and analyze git diffs from your repositories

{/* Repository and Commit Selection */} Select Repository & Commit {/* Repository Selection */}
{/* Commit Selection */} {selectedRepository && (
{commits.length} commits
{/* Search */}
setSearchQuery(e.target.value)} className="pl-10" />
)} {/* Commit Info */} {selectedCommit && (
Selected Commit
{(() => { const commit = commits.find(c => c.id === selectedCommit); return commit ? (
{commit.commit_sha.substring(0, 8)} by {commit.author_name}

{commit.message}

{commit.files_changed} files changed {commit.diffs_processed} diffs processed {(commit.total_diff_size / 1024).toFixed(1)} KB
) : null; })()}
)}
{/* Error Display */} {error && (

Error

{error}

)} {/* Bulk Analysis Error Display */} {bulkAnalysisError && (

Bulk Analysis Error

{bulkAnalysisError}

)} {/* Bulk Analysis Section */} {selectedRepository && commits.length > 0 && ( Bulk AI Analysis

Select multiple commits for bulk AI analysis

{/* Commit Selection List */}
{filteredCommits.map((commit) => (
toggleCommitSelection(commit.id)} >
{selectedCommits.includes(commit.id) ? ( ) : ( )}
{commit.commit_sha.substring(0, 8)} {commit.message}
by {commit.author_name} • {new Date(commit.committed_at).toLocaleDateString()}
))}
{/* Bulk Analysis Button */}
{selectedCommits.length} commit{selectedCommits.length !== 1 ? 's' : ''} selected
)} {/* Diff Viewer */} {selectedRepository && selectedCommit && ( )} {/* No Selection State */} {!selectedRepository && (

No Repository Selected

Please select a repository to view its diffs

)} {selectedRepository && !selectedCommit && (

No Commit Selected

Please select a commit to view its diffs

)}
); }; const DiffViewerPage: React.FC = () => { return (

Loading diff viewer...

}>
); }; export default DiffViewerPage;