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:
97
src/components/settings/index/QuickActions.tsx
Normal file
97
src/components/settings/index/QuickActions.tsx
Normal file
@@ -0,0 +1,97 @@
|
||||
'use client';
|
||||
|
||||
import { Card, CardContent } from '@/components/ui/Card';
|
||||
|
||||
interface Message {
|
||||
type: 'success' | 'error';
|
||||
text: string;
|
||||
}
|
||||
|
||||
interface QuickActionsProps {
|
||||
onCreateBackup: () => void;
|
||||
onTestJira: () => void;
|
||||
isBackupLoading: boolean;
|
||||
isJiraTestLoading: boolean;
|
||||
jiraEnabled: boolean;
|
||||
messages: {
|
||||
backup?: Message;
|
||||
jira?: Message;
|
||||
};
|
||||
}
|
||||
|
||||
export function QuickActions({
|
||||
onCreateBackup,
|
||||
onTestJira,
|
||||
isBackupLoading,
|
||||
isJiraTestLoading,
|
||||
jiraEnabled,
|
||||
messages
|
||||
}: QuickActionsProps) {
|
||||
return (
|
||||
<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={onCreateBackup}
|
||||
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={onTestJira}
|
||||
disabled={!jiraEnabled || 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>
|
||||
);
|
||||
}
|
||||
73
src/components/settings/index/QuickStats.tsx
Normal file
73
src/components/settings/index/QuickStats.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
'use client';
|
||||
|
||||
import { Card, CardContent } from '@/components/ui/Card';
|
||||
import { UserPreferences } from '@/lib/types';
|
||||
import { SystemInfo } from '@/services/system-info';
|
||||
|
||||
interface QuickStatsProps {
|
||||
preferences: UserPreferences;
|
||||
systemInfo: SystemInfo | null;
|
||||
}
|
||||
|
||||
export function QuickStats({ preferences, systemInfo }: QuickStatsProps) {
|
||||
return (
|
||||
<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>
|
||||
);
|
||||
}
|
||||
69
src/components/settings/index/SettingsNavigation.tsx
Normal file
69
src/components/settings/index/SettingsNavigation.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
'use client';
|
||||
|
||||
import { Card, CardContent } from '@/components/ui/Card';
|
||||
import Link from 'next/link';
|
||||
|
||||
interface SettingsPage {
|
||||
href: string;
|
||||
icon: string;
|
||||
title: string;
|
||||
description: string;
|
||||
status: string;
|
||||
}
|
||||
|
||||
interface SettingsNavigationProps {
|
||||
settingsPages: SettingsPage[];
|
||||
}
|
||||
|
||||
export function SettingsNavigation({ settingsPages }: SettingsNavigationProps) {
|
||||
return (
|
||||
<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>
|
||||
);
|
||||
}
|
||||
79
src/components/settings/index/SystemInfo.tsx
Normal file
79
src/components/settings/index/SystemInfo.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
'use client';
|
||||
|
||||
import { Card, CardHeader, CardContent } from '@/components/ui/Card';
|
||||
import { SystemInfo as SystemInfoType } from '@/services/system-info';
|
||||
|
||||
interface SystemInfoProps {
|
||||
systemInfo: SystemInfoType | null;
|
||||
isLoading: boolean;
|
||||
onRefresh: () => void;
|
||||
}
|
||||
|
||||
export function SystemInfo({ systemInfo, isLoading, onRefresh }: SystemInfoProps) {
|
||||
return (
|
||||
<Card className="mt-8">
|
||||
<CardHeader>
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-lg font-semibold">ℹ️ Informations système</h2>
|
||||
<button
|
||||
onClick={onRefresh}
|
||||
disabled={isLoading}
|
||||
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"
|
||||
>
|
||||
{isLoading ? '🔄 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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user