'use client'; import { useState } from 'react'; import { Button } from '@/components/ui/Button'; import { Card, CardHeader, CardContent } from '@/components/ui/Card'; import { Badge } from '@/components/ui/Badge'; import { getToday } from '@/lib/date-utils'; import { Modal } from '@/components/ui/Modal'; import { TfsSyncResult, TfsSyncAction } from '@/services/integrations/tfs'; interface TfsSyncProps { onSyncComplete?: () => void; className?: string; } export function TfsSync({ onSyncComplete, className = "" }: TfsSyncProps) { const [isConnected, setIsConnected] = useState(null); const [isLoading, setIsLoading] = useState(false); const [isSyncing, setIsSyncing] = useState(false); const [lastSyncResult, setLastSyncResult] = useState(null); const [error, setError] = useState(null); const [showDetails, setShowDetails] = useState(false); const testConnection = async () => { setIsLoading(true); setError(null); try { const response = await fetch('/api/tfs/test'); const result = await response.json(); setIsConnected(result.connected); if (!result.connected) { setError(result.error || result.message); } } catch (err) { setIsConnected(false); setError(err instanceof Error ? err.message : 'Erreur de connexion'); } finally { setIsLoading(false); } }; const startSync = async () => { setIsSyncing(true); setError(null); try { const response = await fetch('/api/tfs/sync', { method: 'POST' }); const result = await response.json(); console.log('TFS Sync API Response:', result); // L'API retourne { message: '...', data: result } ou { error: '...', data: result } const syncResult = result.data || result; console.log('TFS Sync Result:', syncResult); setLastSyncResult(syncResult); // Considérer comme succès si on a une réponse (même avec status 207) if (response.ok || response.status === 207) { onSyncComplete?.(); } } catch (err) { console.error('TFS Sync Error:', err); setError(err instanceof Error ? err.message : 'Erreur de synchronisation'); } finally { setIsSyncing(false); } }; const getConnectionStatus = () => { if (isConnected === null) return null; return isConnected ? ( ✓ Connecté ) : ( ✗ Déconnecté ); }; const getSyncStatus = () => { if (!lastSyncResult) return null; const { success, totalPullRequests = 0, pullRequestsCreated = 0, pullRequestsUpdated = 0, pullRequestsSkipped = 0, pullRequestsDeleted = 0, errors = [], actions = [] } = lastSyncResult; return (
0 ? "danger" : (totalPullRequests > 0 ? "warning" : "success")) } size="sm"> {success ? "✓ Succès" : (errors.length > 0 ? "⚠ Erreurs" : (totalPullRequests > 0 ? "✓ À jour" : "✓ Synchronisé"))} {getToday().toLocaleTimeString()}
{totalPullRequests > 0 ? `${totalPullRequests} PR${totalPullRequests > 1 ? 's' : ''} trouvée${totalPullRequests > 1 ? 's' : ''}` : 'Aucune PR trouvée' }
{pullRequestsCreated}
Créées
{pullRequestsUpdated}
Mises à jour
{pullRequestsSkipped}
Ignorées
{pullRequestsDeleted}
Supprimées
{/* Résumé textuel avec bouton détails */}
Résumé:
{actions && actions.length > 0 && ( )}
{pullRequestsCreated > 0 && `${pullRequestsCreated} nouvelle${pullRequestsCreated > 1 ? 's' : ''} • `} {pullRequestsUpdated > 0 && `${pullRequestsUpdated} mise${pullRequestsUpdated > 1 ? 's' : ''} à jour • `} {pullRequestsDeleted > 0 && `${pullRequestsDeleted} supprimée${pullRequestsDeleted > 1 ? 's' : ''} (fermées) • `} {pullRequestsSkipped > 0 && `${pullRequestsSkipped} déjà synchronisée${pullRequestsSkipped > 1 ? 's' : ''} • `} {(pullRequestsCreated + pullRequestsUpdated + pullRequestsDeleted + pullRequestsSkipped) === 0 && 'Aucune PR trouvée'}
{errors && errors.length > 0 && (
Erreurs ({errors.length}):
{errors.map((err, i) => (
{err}
))}
)}
); }; return (

TFS SYNC

{getConnectionStatus()}
{/* Test de connexion */}
{/* Messages d'erreur */} {error && (
{error}
)} {/* Résultats de sync */} {getSyncStatus()} {/* Info */}
• Synchronisation unidirectionnelle (TFS → TowerControl)
• Les modifications locales sont préservées
• Seules les Pull Requests assignées sont synchronisées
• Les PRs fermées sont automatiquement supprimées
{/* Modal détails de synchronisation */} {lastSyncResult && ( setShowDetails(false)} title="📋 DÉTAILS DE SYNCHRONISATION" size="xl" >

{(lastSyncResult.actions || []).length} action{(lastSyncResult.actions || []).length > 1 ? 's' : ''} effectuée{(lastSyncResult.actions || []).length > 1 ? 's' : ''}

{(lastSyncResult.actions || []).length > 0 ? ( ) : (
📝
Aucun détail disponible pour cette synchronisation
Les détails sont disponibles pour les nouvelles synchronisations
)}
)}
); } // Composant pour afficher la liste des actions function SyncActionsList({ actions }: { actions: TfsSyncAction[] }) { const getActionIcon = (type: TfsSyncAction['type']) => { switch (type) { case 'created': return '➕'; case 'updated': return '🔄'; case 'skipped': return '⏭️'; case 'deleted': return '🗑️'; default: return '❓'; } }; const getActionColor = (type: TfsSyncAction['type']) => { switch (type) { case 'created': return 'text-emerald-400'; case 'updated': return 'text-blue-400'; case 'skipped': return 'text-orange-400'; case 'deleted': return 'text-red-400'; default: return 'text-gray-400'; } }; const getActionLabel = (type: TfsSyncAction['type']) => { switch (type) { case 'created': return 'Créée'; case 'updated': return 'Mise à jour'; case 'skipped': return 'Ignorée'; case 'deleted': return 'Supprimée'; default: return 'Inconnue'; } }; // Grouper les actions par type const groupedActions = actions.reduce((acc, action) => { if (!acc[action.type]) acc[action.type] = []; acc[action.type].push(action); return acc; }, {} as Record); return (
{Object.entries(groupedActions).map(([type, typeActions]) => (

{getActionIcon(type as TfsSyncAction['type'])} {getActionLabel(type as TfsSyncAction['type'])} ({typeActions.length})

{typeActions.map((action, index) => (
PR #{action.pullRequestId} {action.prTitle}
{getActionLabel(action.type)}
{action.reason && (
💡 {action.reason}
)} {action.changes && action.changes.length > 0 && (
Modifications:
{action.changes.map((change, changeIndex) => (
{change}
))}
)}
))}
))}
); }