101 lines
3.5 KiB
TypeScript
101 lines
3.5 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useTransition } from 'react';
|
|
import { Card, CardHeader, CardContent } from '@/components/ui/Card';
|
|
import { syncTfsPullRequests } from '@/actions/tfs';
|
|
|
|
export function TfsSync() {
|
|
const [isPending, startTransition] = useTransition();
|
|
const [lastSync, setLastSync] = useState<{
|
|
success: boolean;
|
|
message: string;
|
|
stats?: {
|
|
created: number;
|
|
updated: number;
|
|
skipped: number;
|
|
deleted: number;
|
|
}
|
|
} | null>(null);
|
|
|
|
const handleSync = () => {
|
|
startTransition(async () => {
|
|
setLastSync(null);
|
|
|
|
const result = await syncTfsPullRequests();
|
|
|
|
if (result.success) {
|
|
setLastSync({
|
|
success: true,
|
|
message: result.message || 'Synchronisation réussie',
|
|
stats: result.data ? {
|
|
created: result.data.pullRequestsCreated,
|
|
updated: result.data.pullRequestsUpdated,
|
|
skipped: result.data.pullRequestsSkipped,
|
|
deleted: result.data.pullRequestsDeleted
|
|
} : undefined
|
|
});
|
|
} else {
|
|
setLastSync({
|
|
success: false,
|
|
message: result.error || 'Erreur lors de la synchronisation'
|
|
});
|
|
}
|
|
});
|
|
};
|
|
|
|
return (
|
|
<Card>
|
|
<CardHeader>
|
|
<h3 className="text-lg font-semibold flex items-center gap-2">
|
|
<span className="text-blue-600">🔄</span>
|
|
Synchronisation TFS
|
|
</h3>
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
<p className="text-sm text-[var(--muted-foreground)]">
|
|
Synchronise manuellement les Pull Requests depuis Azure DevOps
|
|
</p>
|
|
|
|
{/* Résultat de la dernière synchronisation */}
|
|
{lastSync && (
|
|
<div className={`p-3 rounded-lg text-sm ${
|
|
lastSync.success
|
|
? 'bg-green-50 text-green-800 border border-green-200'
|
|
: 'bg-red-50 text-red-800 border border-red-200'
|
|
}`}>
|
|
<div className="font-medium mb-1">
|
|
{lastSync.success ? '✅' : '❌'} {lastSync.message}
|
|
</div>
|
|
{lastSync.stats && (
|
|
<div className="text-xs opacity-80">
|
|
Créées: {lastSync.stats.created} |
|
|
Mises à jour: {lastSync.stats.updated} |
|
|
Ignorées: {lastSync.stats.skipped} |
|
|
Supprimées: {lastSync.stats.deleted}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
|
|
<button
|
|
onClick={handleSync}
|
|
disabled={isPending}
|
|
className="w-full px-4 py-2 bg-[var(--primary)] text-[var(--primary-foreground)] rounded-lg hover:bg-[var(--primary)]/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
|
|
>
|
|
{isPending && (
|
|
<svg className="animate-spin h-4 w-4" viewBox="0 0 24 24">
|
|
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" fill="none" />
|
|
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 0 1 8-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 0 1 4 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
|
|
</svg>
|
|
)}
|
|
{isPending ? 'Synchronisation en cours...' : 'Synchroniser maintenant'}
|
|
</button>
|
|
|
|
<div className="text-xs text-[var(--muted-foreground)] text-center">
|
|
Les Pull Requests seront importées comme tâches dans le tableau Kanban
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
}
|