From 25a31feec491e2b8d4e89b14e6e2da2e8b849004 Mon Sep 17 00:00:00 2001 From: Anthony Coyaud Date: Sat, 15 Aug 2026 13:28:36 +0200 Subject: [PATCH] =?UTF-8?q?feat(dashboard):=20filtres=20services/cat=C3=A9?= =?UTF-8?q?gories=20restreints=20aux=20r=C3=A9sultats?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Les select de service et catégorie utilisaient getServices()/getCategories(), soit les référentiels complets — dont certaines entrées (ex. "Business Intelligence") n'ont aucun monitoring rattaché et menaient sur un dashboard vide. Bascule vers le nouvel endpoint GET /dashboard/filtres (VUE_CONSO), avec filtrage en cascade : sélectionner un service restreint la liste des catégories proposées à celles qui ont réellement des résultats pour ce service. --- .../src/pages/Dashboard/Dashboard.jsx | 45 ++++++++++++++----- DataSentinel/src/services/api.js | 12 +++++ 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/DataSentinel/src/pages/Dashboard/Dashboard.jsx b/DataSentinel/src/pages/Dashboard/Dashboard.jsx index 7797dbf..79c30e2 100644 --- a/DataSentinel/src/pages/Dashboard/Dashboard.jsx +++ b/DataSentinel/src/pages/Dashboard/Dashboard.jsx @@ -1,8 +1,8 @@ /* Page principale du dashboard : KPI cards + grille de monitorings */ -import { useState, useEffect, useCallback } from 'react'; +import { useState, useEffect, useCallback, useMemo } from 'react'; import { RefreshCw } from 'lucide-react'; -import { getDashboard, getDashboardSummary, getServices, getCategories } from '../../services/api'; +import { getDashboard, getDashboardSummary, getDashboardFiltres } from '../../services/api'; import MonitoringCard from '../../components/common/MonitoringCard'; import LoadingSpinner from '../../components/common/LoadingSpinner'; import ErrorMessage from '../../components/common/ErrorMessage'; @@ -22,19 +22,22 @@ export default function Dashboard() { const [summary, setSummary] = useState(null); const [monitorings, setMonitorings] = useState([]); const [services, setServices] = useState([]); - const [categories, setCategories] = useState([]); + const [combinaisons, setCombinaisons] = useState([]); const [filtreService, setFiltreService] = useState(''); const [filtreCategorie, setFiltreCategorie] = useState(''); const [loading, setLoading] = useState(true); const [erreur, setErreur] = useState(''); - /* Chargement initial des filtres */ + /* Chargement initial des filtres. + On n'utilise pas les référentiels SERVICE / CATEGORIE complets : ils + contiennent des entrées sans aucun monitoring rattaché (ex. « Business + Intelligence »), qui mèneraient sur un dashboard vide. */ useEffect(() => { async function loadFiltres() { try { - const [svcs, cats] = await Promise.all([getServices(), getCategories()]); - setServices(svcs); - setCategories(cats); + const filtres = await getDashboardFiltres(); + setServices(filtres.services); + setCombinaisons(filtres.combinaisons); } catch { /* Non bloquant, les filtres restent vides */ } @@ -42,6 +45,28 @@ export default function Dashboard() { loadFiltres(); }, []); + /* Catégories proposées : restreintes au service sélectionné, le cas échéant */ + const categoriesDisponibles = useCallback(service => { + const pertinentes = service + ? combinaisons.filter(c => c.service === service) + : combinaisons; + return [...new Set(pertinentes.map(c => c.categorie))].sort(); + }, [combinaisons]); + + const categories = useMemo( + () => categoriesDisponibles(filtreService), + [categoriesDisponibles, filtreService], + ); + + /* Changer de service peut rendre la catégorie sélectionnée sans résultat : + on la remet à zéro dans le même rendu, pour ne déclencher qu'un seul appel. */ + function handleServiceChange(service) { + setFiltreService(service); + if (filtreCategorie && !categoriesDisponibles(service).includes(filtreCategorie)) { + setFiltreCategorie(''); + } + } + /* Chargement des données dashboard */ const loadData = useCallback(async () => { setLoading(true); @@ -105,11 +130,11 @@ export default function Dashboard() { diff --git a/DataSentinel/src/services/api.js b/DataSentinel/src/services/api.js index 7c6f0c9..bbd1116 100644 --- a/DataSentinel/src/services/api.js +++ b/DataSentinel/src/services/api.js @@ -245,6 +245,18 @@ export async function getDashboard(service, categorie) { })) : data; } +/* Récupère les valeurs de filtre qui ramènent au moins un monitoring (VUE_CONSO). + Évite de proposer un service ou une catégorie du référentiel qui n'a aucun + monitoring rattaché, et donc de mener l'utilisateur sur un écran vide. */ +export async function getDashboardFiltres() { + const data = await fetchApi('/dashboard/filtres'); + return { + services: Array.isArray(data?.services) ? data.services : [], + categories: Array.isArray(data?.categories) ? data.categories : [], + combinaisons: Array.isArray(data?.combinaisons) ? data.combinaisons : [], + }; +} + /* Récupère le résumé global KPI du dashboard */ export async function getDashboardSummary() { const data = await fetchApi('/dashboard/summary');