feat: enhance metrics dashboard with new components and data handling

- Introduced `MetricsOverview`, `MetricsMainCharts`, `MetricsDistributionCharts`, `MetricsVelocitySection`, and `MetricsProductivitySection` for improved metrics visualization.
- Updated `MetricsTab` to integrate new components and streamline data presentation.
- Added compatibility fields in `JiraTask` and `AssigneeDistribution` for better data handling.
- Refactored `calculateAssigneeDistribution` to include a count for total issues.
- Enhanced `JiraAnalyticsService` and `JiraAdvancedFiltersService` to support new metrics calculations.
- Cleaned up unused imports and components for a more maintainable codebase.
This commit is contained in:
Julien Froidefond
2025-09-21 15:55:11 +02:00
parent c650c67627
commit 0a03e40469
43 changed files with 2781 additions and 1805 deletions

View File

@@ -1,17 +1,19 @@
'use client';
import { Header } from '@/components/ui/Header';
import { Card, CardHeader, CardContent } from '@/components/ui/Card';
import { useUserPreferences } from '@/contexts/UserPreferencesContext';
import Link from 'next/link';
import { useState, useEffect, useTransition } from 'react';
import { backupClient } from '@/clients/backup-client';
import { jiraClient } from '@/clients/jira-client';
import { getSystemInfo } from '@/actions/system-info';
import { SystemInfo } from '@/services/system-info';
import { QuickStats } from './index/QuickStats';
import { SettingsNavigation } from './index/SettingsNavigation';
import { QuickActions } from './index/QuickActions';
import { SystemInfo as SystemInfoComponent } from './index/SystemInfo';
interface SettingsIndexPageClientProps {
initialSystemInfo?: SystemInfo;
initialSystemInfo: SystemInfo;
}
export function SettingsIndexPageClient({ initialSystemInfo }: SettingsIndexPageClientProps) {
@@ -158,249 +160,29 @@ export function SettingsIndexPageClient({ initialSystemInfo }: SettingsIndexPage
</div>
{/* Quick Stats */}
<div className="grid grid-cols-1 md:grid-cols-4 gap-4 mb-8">
<Card>
<CardContent className="p-4">
<div className="flex items-center gap-3">
<span className="text-2xl">🎨</span>
<div>
<p className="text-sm text-[var(--muted-foreground)]">Thème actuel</p>
<p className="font-medium capitalize">{preferences.viewPreferences.theme}</p>
</div>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="p-4">
<div className="flex items-center gap-3">
<span className="text-2xl">🔌</span>
<div>
<p className="text-sm text-[var(--muted-foreground)]">Jira</p>
<div className="flex items-center gap-2">
<p className="font-medium">
{preferences.jiraConfig.enabled ? 'Configuré' : 'Non configuré'}
</p>
{preferences.jiraConfig.enabled && (
<span className="w-2 h-2 bg-green-500 rounded-full" title="Jira configuré"></span>
)}
</div>
</div>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="p-4">
<div className="flex items-center gap-3">
<span className="text-2xl">📏</span>
<div>
<p className="text-sm text-[var(--muted-foreground)]">Taille police</p>
<p className="font-medium capitalize">{preferences.viewPreferences.fontSize}</p>
</div>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="p-4">
<div className="flex items-center gap-3">
<span className="text-2xl">💾</span>
<div>
<p className="text-sm text-[var(--muted-foreground)]">Sauvegardes</p>
<p className="font-medium">
{systemInfo ? systemInfo.database.totalBackups : '...'}
</p>
</div>
</div>
</CardContent>
</Card>
</div>
<QuickStats preferences={preferences} systemInfo={systemInfo} />
{/* Settings Sections */}
<div className="space-y-4">
<h2 className="text-xl font-semibold text-[var(--foreground)] mb-4">
Sections de configuration
</h2>
<div className="grid grid-cols-1 md:grid-cols-1 gap-4">
{settingsPages.map((page) => (
<Link key={page.href} href={page.href}>
<Card className="transition-all hover:shadow-md hover:border-[var(--primary)]/30 cursor-pointer">
<CardContent className="p-6">
<div className="flex items-start justify-between">
<div className="flex items-start gap-4">
<span className="text-3xl">{page.icon}</span>
<div className="flex-1">
<h3 className="text-lg font-semibold text-[var(--foreground)] mb-1">
{page.title}
</h3>
<p className="text-[var(--muted-foreground)] mb-2">
{page.description}
</p>
<div className="flex items-center gap-2">
<span className={`px-2 py-1 rounded text-xs font-medium ${
page.status === 'Fonctionnel'
? 'bg-[var(--success)]/20 text-[var(--success)]'
: page.status === 'En développement'
? 'bg-[var(--warning)]/20 text-[var(--warning)]'
: 'bg-[var(--muted)]/20 text-[var(--muted-foreground)]'
}`}>
{page.status}
</span>
</div>
</div>
</div>
<svg
className="w-5 h-5 text-[var(--muted-foreground)]"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
</div>
</CardContent>
</Card>
</Link>
))}
</div>
</div>
<SettingsNavigation settingsPages={settingsPages} />
{/* Quick Actions */}
<div className="mt-8">
<h2 className="text-xl font-semibold text-[var(--foreground)] mb-4">
Actions rapides
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Card>
<CardContent className="p-4">
<div className="flex items-center justify-between">
<div>
<h3 className="font-medium mb-1">Sauvegarde manuelle</h3>
<p className="text-sm text-[var(--muted-foreground)]">
Créer une sauvegarde des données
</p>
{messages.backup && (
<p className={`text-xs mt-1 ${
messages.backup.type === 'success'
? 'text-green-600 dark:text-green-400'
: 'text-red-600 dark:text-red-400'
}`}>
{messages.backup.text}
</p>
)}
</div>
<button
onClick={handleCreateBackup}
disabled={isBackupLoading}
className="px-3 py-1.5 bg-[var(--primary)] text-[var(--primary-foreground)] rounded text-sm disabled:opacity-50 disabled:cursor-not-allowed"
>
{isBackupLoading ? 'En cours...' : 'Sauvegarder'}
</button>
</div>
</CardContent>
</Card>
<Card>
<CardContent className="p-4">
<div className="flex items-center justify-between">
<div>
<h3 className="font-medium mb-1">Test Jira</h3>
<p className="text-sm text-[var(--muted-foreground)]">
Tester la connexion Jira
</p>
{messages.jira && (
<p className={`text-xs mt-1 ${
messages.jira.type === 'success'
? 'text-green-600 dark:text-green-400'
: 'text-red-600 dark:text-red-400'
}`}>
{messages.jira.text}
</p>
)}
</div>
<button
onClick={handleTestJira}
disabled={!preferences.jiraConfig.enabled || isJiraTestLoading}
className="px-3 py-1.5 bg-[var(--card)] text-[var(--foreground)] border border-[var(--border)] rounded text-sm disabled:opacity-50 disabled:cursor-not-allowed"
>
{isJiraTestLoading ? 'Test...' : 'Tester'}
</button>
</div>
</CardContent>
</Card>
</div>
</div>
<QuickActions
onCreateBackup={handleCreateBackup}
onTestJira={handleTestJira}
isBackupLoading={isBackupLoading}
isJiraTestLoading={isJiraTestLoading}
jiraEnabled={preferences.jiraConfig.enabled}
messages={messages}
/>
{/* System Info */}
<Card className="mt-8">
<CardHeader>
<div className="flex items-center justify-between">
<h2 className="text-lg font-semibold"> Informations système</h2>
<button
onClick={loadSystemInfo}
disabled={isSystemInfoLoading}
className="text-xs px-2 py-1 bg-[var(--card)] border border-[var(--border)] rounded hover:bg-[var(--card-hover)] disabled:opacity-50 disabled:cursor-not-allowed"
>
{isSystemInfoLoading ? '🔄 Chargement...' : '🔄 Actualiser'}
</button>
</div>
</CardHeader>
<CardContent>
{systemInfo ? (
<>
<div className="grid grid-cols-1 md:grid-cols-4 gap-4 text-sm mb-4">
<div>
<p className="text-[var(--muted-foreground)]">Version</p>
<p className="font-medium">TowerControl v{systemInfo.version}</p>
</div>
<div>
<p className="text-[var(--muted-foreground)]">Dernière maj</p>
<p className="font-medium">{systemInfo.lastUpdate}</p>
</div>
<div>
<p className="text-[var(--muted-foreground)]">Environnement</p>
<p className="font-medium capitalize">{systemInfo.environment}</p>
</div>
<div>
<p className="text-[var(--muted-foreground)]">Uptime</p>
<p className="font-medium">{systemInfo.uptime}</p>
</div>
</div>
<div className="border-t border-[var(--border)] pt-4">
<h3 className="text-sm font-medium mb-3 text-[var(--muted-foreground)]">Base de données</h3>
<div className="grid grid-cols-1 md:grid-cols-4 gap-4 text-sm">
<div>
<p className="text-[var(--muted-foreground)]">Tâches</p>
<p className="font-medium">{systemInfo.database.totalTasks}</p>
</div>
<div>
<p className="text-[var(--muted-foreground)]">Utilisateurs</p>
<p className="font-medium">{systemInfo.database.totalUsers}</p>
</div>
<div>
<p className="text-[var(--muted-foreground)]">Sauvegardes</p>
<p className="font-medium">{systemInfo.database.totalBackups}</p>
</div>
<div>
<p className="text-[var(--muted-foreground)]">Taille DB</p>
<p className="font-medium">{systemInfo.database.databaseSize}</p>
</div>
</div>
</div>
</>
) : (
<div className="text-center py-4">
<p className="text-[var(--muted-foreground)]">Chargement des informations système...</p>
</div>
)}
</CardContent>
</Card>
<SystemInfoComponent
systemInfo={systemInfo}
isLoading={isSystemInfoLoading}
onRefresh={loadSystemInfo}
/>
</div>
</div>
</div>
);
}
}