feat: enhance Jira dashboard with advanced filtering and sprint details

- Updated `TODO.md` to mark several tasks as complete, including anomaly detection and sprint detail integration.
- Enhanced `VelocityChart` to support click events for sprint details, improving user interaction.
- Added `FilterBar` and `AnomalyDetectionPanel` components to `JiraDashboardPageClient` for advanced filtering capabilities.
- Implemented state management for selected sprints and modal display for detailed sprint information.
- Introduced new types for advanced filtering in `types.ts`, expanding the filtering options available in the analytics.
This commit is contained in:
Julien Froidefond
2025-09-19 10:13:48 +02:00
parent b7707d7651
commit 3dd6e0fd1c
17 changed files with 2879 additions and 68 deletions

98
hooks/useJiraFilters.ts Normal file
View File

@@ -0,0 +1,98 @@
import { useState, useEffect, useCallback } from 'react';
import { getAvailableJiraFilters, getFilteredJiraAnalytics } from '@/actions/jira-filters';
import { AvailableFilters, JiraAnalyticsFilters, JiraAnalytics } from '@/lib/types';
import { JiraAdvancedFiltersService } from '@/services/jira-advanced-filters';
export function useJiraFilters() {
const [availableFilters, setAvailableFilters] = useState<AvailableFilters>({
components: [],
fixVersions: [],
issueTypes: [],
statuses: [],
assignees: [],
labels: [],
priorities: []
});
const [activeFilters, setActiveFilters] = useState<Partial<JiraAnalyticsFilters>>(
JiraAdvancedFiltersService.createEmptyFilters()
);
const [filteredAnalytics, setFilteredAnalytics] = useState<JiraAnalytics | null>(null);
const [isLoadingFilters, setIsLoadingFilters] = useState(false);
const [isLoadingAnalytics, setIsLoadingAnalytics] = useState(false);
const [error, setError] = useState<string | null>(null);
// Charger les filtres disponibles
const loadAvailableFilters = useCallback(async () => {
setIsLoadingFilters(true);
setError(null);
try {
const result = await getAvailableJiraFilters();
if (result.success && result.data) {
setAvailableFilters(result.data);
} else {
setError(result.error || 'Erreur lors du chargement des filtres');
}
} catch {
setError('Erreur de connexion');
} finally {
setIsLoadingFilters(false);
}
}, []);
// Appliquer les filtres et récupérer les analytics filtrées
const applyFilters = useCallback(async (filters: Partial<JiraAnalyticsFilters>) => {
setIsLoadingAnalytics(true);
setError(null);
try {
const result = await getFilteredJiraAnalytics(filters);
if (result.success && result.data) {
setFilteredAnalytics(result.data);
setActiveFilters(filters);
} else {
setError(result.error || 'Erreur lors du filtrage');
}
} catch {
setError('Erreur de connexion');
} finally {
setIsLoadingAnalytics(false);
}
}, []);
// Effacer tous les filtres
const clearFilters = useCallback(() => {
const emptyFilters = JiraAdvancedFiltersService.createEmptyFilters();
setActiveFilters(emptyFilters);
setFilteredAnalytics(null);
}, []);
// Chargement initial des filtres disponibles
useEffect(() => {
loadAvailableFilters();
}, [loadAvailableFilters]);
return {
// État
availableFilters,
activeFilters,
filteredAnalytics,
isLoadingFilters,
isLoadingAnalytics,
error,
// Actions
loadAvailableFilters,
applyFilters,
clearFilters,
// Helpers
hasActiveFilters: JiraAdvancedFiltersService.hasActiveFilters(activeFilters),
activeFiltersCount: JiraAdvancedFiltersService.countActiveFilters(activeFilters),
filtersSummary: JiraAdvancedFiltersService.getFiltersSummary(activeFilters)
};
}