- Simplified the title prop in `FilterBar` for better readability. - Updated dependency array in `useJiraFilters` to include `filterAnalyticsLocally`, ensuring proper effect execution. - Added new line at the end of `test-jira-fields.ts` and `test-story-points.ts` for consistency.
215 lines
7.1 KiB
TypeScript
215 lines
7.1 KiB
TypeScript
import { useState, useEffect, useCallback } from 'react';
|
|
import { getAvailableJiraFilters } from '@/actions/jira-filters';
|
|
import { AvailableFilters, JiraAnalyticsFilters, JiraAnalytics } from '@/lib/types';
|
|
import { JiraAdvancedFiltersService } from '@/services/integrations/jira/advanced-filters';
|
|
|
|
export function useJiraFilters(initialAnalytics?: JiraAnalytics | null) {
|
|
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 [error, setError] = useState<string | null>(null);
|
|
|
|
// Extraire les filtres depuis les analytics existantes
|
|
const extractFiltersFromAnalytics = useCallback((analytics: JiraAnalytics) => {
|
|
// On peut extraire les filtres directement des métriques existantes
|
|
const filters: AvailableFilters = {
|
|
components: [],
|
|
fixVersions: [],
|
|
issueTypes: [],
|
|
statuses: [],
|
|
assignees: [],
|
|
labels: [],
|
|
priorities: []
|
|
};
|
|
|
|
// Extraire les assignees depuis la distribution
|
|
if (analytics.teamMetrics.issuesDistribution) {
|
|
filters.assignees = analytics.teamMetrics.issuesDistribution.map(item => ({
|
|
value: item.displayName,
|
|
label: item.displayName,
|
|
count: item.totalIssues
|
|
}));
|
|
}
|
|
|
|
// Extraire les statuts depuis workInProgress
|
|
if (analytics.workInProgress.byStatus) {
|
|
filters.statuses = analytics.workInProgress.byStatus.map(item => ({
|
|
value: item.status,
|
|
label: item.status,
|
|
count: item.count
|
|
}));
|
|
}
|
|
|
|
// Extraire les types d'issues depuis cycleTimeByType
|
|
if (analytics.cycleTimeMetrics.cycleTimeByType) {
|
|
filters.issueTypes = analytics.cycleTimeMetrics.cycleTimeByType.map(item => ({
|
|
value: item.issueType,
|
|
label: item.issueType,
|
|
count: item.samples
|
|
}));
|
|
}
|
|
|
|
return filters;
|
|
}, []);
|
|
|
|
// Filtrer les analytics localement
|
|
const filterAnalyticsLocally = useCallback((analytics: JiraAnalytics, filters: Partial<JiraAnalyticsFilters>): JiraAnalytics => {
|
|
// Filtrage simplifié basé sur les métriques disponibles
|
|
let filteredAnalytics = { ...analytics };
|
|
|
|
// Filtrer par assignees
|
|
if (filters.assignees && filters.assignees.length > 0) {
|
|
const filteredDistribution = analytics.teamMetrics.issuesDistribution.filter(item =>
|
|
filters.assignees!.includes(item.displayName)
|
|
);
|
|
|
|
filteredAnalytics = {
|
|
...filteredAnalytics,
|
|
teamMetrics: {
|
|
...filteredAnalytics.teamMetrics,
|
|
issuesDistribution: filteredDistribution,
|
|
totalAssignees: filteredDistribution.length,
|
|
activeAssignees: filteredDistribution.filter(a => a.totalIssues > 0).length
|
|
}
|
|
};
|
|
}
|
|
|
|
// Filtrer par statuts
|
|
if (filters.statuses && filters.statuses.length > 0) {
|
|
const filteredStatusDistribution = analytics.workInProgress.byStatus.filter(item =>
|
|
filters.statuses!.includes(item.status)
|
|
);
|
|
|
|
filteredAnalytics = {
|
|
...filteredAnalytics,
|
|
workInProgress: {
|
|
...filteredAnalytics.workInProgress,
|
|
byStatus: filteredStatusDistribution
|
|
}
|
|
};
|
|
}
|
|
|
|
// Filtrer par types d'issues
|
|
if (filters.issueTypes && filters.issueTypes.length > 0) {
|
|
const filteredCycleTime = analytics.cycleTimeMetrics.cycleTimeByType.filter(item =>
|
|
filters.issueTypes!.includes(item.issueType)
|
|
);
|
|
|
|
filteredAnalytics = {
|
|
...filteredAnalytics,
|
|
cycleTimeMetrics: {
|
|
...filteredAnalytics.cycleTimeMetrics,
|
|
cycleTimeByType: filteredCycleTime
|
|
}
|
|
};
|
|
}
|
|
|
|
// Recalculer le total des issues
|
|
const totalIssues = filteredAnalytics.teamMetrics.issuesDistribution.reduce((sum, item) => sum + item.totalIssues, 0);
|
|
filteredAnalytics.project.totalIssues = totalIssues;
|
|
|
|
return filteredAnalytics;
|
|
}, []);
|
|
|
|
// Charger les filtres disponibles
|
|
const loadAvailableFilters = useCallback(async () => {
|
|
// Si on a déjà des analytics, extraire les filtres directement
|
|
if (initialAnalytics) {
|
|
const filters = extractFiltersFromAnalytics(initialAnalytics);
|
|
setAvailableFilters(filters);
|
|
return;
|
|
}
|
|
|
|
// Sinon, faire l'appel API
|
|
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);
|
|
}
|
|
}, [initialAnalytics, extractFiltersFromAnalytics]);
|
|
|
|
// Appliquer les filtres localement sur les analytics existantes
|
|
const applyFilters = useCallback((filters: Partial<JiraAnalyticsFilters>) => {
|
|
// Mettre à jour les filtres actifs immédiatement
|
|
setActiveFilters(filters);
|
|
|
|
// Si aucun filtre actif, effacer les analytics filtrées
|
|
if (!JiraAdvancedFiltersService.hasActiveFilters(filters)) {
|
|
setFilteredAnalytics(null);
|
|
return;
|
|
}
|
|
|
|
// Si on a des analytics initiales, les filtrer localement
|
|
if (initialAnalytics) {
|
|
// Pour le filtrage local, on simule le filtrage en modifiant les métriques
|
|
// En réalité, on devrait avoir accès aux issues individuelles pour un vrai filtrage
|
|
// Pour l'instant, on fait un filtrage simplifié sur les métriques disponibles
|
|
const filteredAnalytics = filterAnalyticsLocally(initialAnalytics, filters);
|
|
setFilteredAnalytics(filteredAnalytics);
|
|
}
|
|
}, [initialAnalytics, filterAnalyticsLocally]);
|
|
|
|
// Effacer tous les filtres
|
|
const clearFilters = useCallback(() => {
|
|
const emptyFilters = JiraAdvancedFiltersService.createEmptyFilters();
|
|
setActiveFilters(emptyFilters);
|
|
setFilteredAnalytics(null);
|
|
}, []);
|
|
|
|
// Chargement initial des filtres disponibles
|
|
useEffect(() => {
|
|
loadAvailableFilters();
|
|
}, [loadAvailableFilters]);
|
|
|
|
// Mettre à jour les filtres quand les analytics changent
|
|
useEffect(() => {
|
|
if (initialAnalytics) {
|
|
const filters = extractFiltersFromAnalytics(initialAnalytics);
|
|
setAvailableFilters(filters);
|
|
}
|
|
}, [initialAnalytics, extractFiltersFromAnalytics]);
|
|
|
|
return {
|
|
// État
|
|
availableFilters,
|
|
activeFilters,
|
|
filteredAnalytics,
|
|
isLoadingFilters,
|
|
error,
|
|
|
|
// Actions
|
|
loadAvailableFilters,
|
|
applyFilters,
|
|
clearFilters,
|
|
|
|
// Helpers
|
|
hasActiveFilters: JiraAdvancedFiltersService.hasActiveFilters(activeFilters),
|
|
activeFiltersCount: JiraAdvancedFiltersService.countActiveFilters(activeFilters),
|
|
filtersSummary: JiraAdvancedFiltersService.getFiltersSummary(activeFilters)
|
|
};
|
|
}
|