Checkpoint: Simplification de la classification IA dans l'onglet Veille Stratégique : suppression de la catégorie médico-sociale (Handicap, PA, Enfance, etc.), remplacement de "Générale" par "Informationnelle", classification IA réduite au seul type de veille (réglementaire/concurrentielle/technologique/informationnelle). Migration BDD des données generale → informationnelle. 0 erreur TypeScript, 21 tests passés.

This commit is contained in:
Manus
2026-06-17 04:02:17 -04:00
parent 937dda1cac
commit dcb726832c
17 changed files with 1310 additions and 331 deletions

View File

@@ -1,4 +1,4 @@
{
"version": "b19031d9",
"timestamp": 1781681307542
"version": "7708bf54",
"timestamp": 1781683337686
}

View File

@@ -61,7 +61,7 @@ import { cn } from "@/lib/utils";
// ─── Types ────────────────────────────────────────────────────────────────────
type FeedType = "veille" | "aap";
type TypeVeille = "reglementaire" | "concurrentielle" | "technologique" | "generale";
type TypeVeille = "reglementaire" | "concurrentielle" | "technologique" | "informationnelle";
type CategorieAap = "Handicap" | "PA" | "Enfance" | "Précarité" | "Sanitaire" | "Autre";
interface AutoRule {
@@ -89,11 +89,11 @@ const TYPE_VEILLE_LABELS: Record<TypeVeille, string> = {
reglementaire: "Réglementaire",
concurrentielle: "Concurrentielle",
technologique: "Technologique",
generale: "Générale",
informationnelle: "Informationnelle",
};
const CATEGORIE_AAP_OPTIONS: CategorieAap[] = ["Handicap", "PA", "Enfance", "Précarité", "Sanitaire", "Autre"];
const TYPE_VEILLE_OPTIONS: TypeVeille[] = ["reglementaire", "concurrentielle", "technologique", "generale"];
const TYPE_VEILLE_OPTIONS: TypeVeille[] = ["reglementaire", "concurrentielle", "technologique", "informationnelle"];
const INTERVAL_OPTIONS = [
{ value: 30, label: "30 minutes" },

View File

@@ -46,7 +46,7 @@ import { cn } from "@/lib/utils";
import { format } from "date-fns";
import { fr } from "date-fns/locale";
type TypeVeille = "reglementaire" | "concurrentielle" | "technologique" | "generale";
type TypeVeille = "reglementaire" | "concurrentielle" | "technologique" | "informationnelle";
interface VeilleItem {
id: number;
@@ -62,7 +62,6 @@ interface VeilleItem {
datePublication: Date | null;
importedAt: Date;
iaRelevant: boolean | null;
iaCategorie: string | null;
iaClassifiedBy: "ia" | "rules" | null;
iaReason: string | null;
iaResume: string | null;
@@ -72,28 +71,28 @@ const TYPE_LABELS: Record<TypeVeille, string> = {
reglementaire: "Réglementaire",
concurrentielle: "Concurrentielle",
technologique: "Technologique",
generale: "Générale",
informationnelle: "Informationnelle",
};
const TYPE_COLORS: Record<string, string> = {
reglementaire: "bg-blue-100 text-blue-800 border-blue-200",
concurrentielle: "bg-purple-100 text-purple-800 border-purple-200",
technologique: "bg-emerald-100 text-emerald-800 border-emerald-200",
generale: "bg-amber-100 text-amber-800 border-amber-200",
informationnelle: "bg-amber-100 text-amber-800 border-amber-200",
};
const TYPE_ACCENT: Record<string, string> = {
reglementaire: "border-l-blue-500",
concurrentielle: "border-l-purple-500",
technologique: "border-l-emerald-500",
generale: "border-l-amber-500",
informationnelle: "border-l-amber-500",
};
const TYPE_HEADER_BG: Record<string, string> = {
reglementaire: "from-blue-50 to-blue-100/30 border-blue-200",
concurrentielle: "from-purple-50 to-purple-100/30 border-purple-200",
technologique: "from-emerald-50 to-emerald-100/30 border-emerald-200",
generale: "from-amber-50 to-amber-100/30 border-amber-200",
informationnelle: "from-amber-50 to-amber-100/30 border-amber-200",
};
const PAGE_SIZE = 24;
@@ -151,15 +150,7 @@ function VeilleDetailDialog({
{/* Métadonnées en grille */}
<div className="grid grid-cols-2 sm:grid-cols-3 gap-3">
{item.categorie && (
<div className="flex items-start gap-2 p-3 rounded-lg bg-muted/40 border border-border/50">
<Tag size={14} className="text-muted-foreground mt-0.5 shrink-0" />
<div>
<p className="text-[10px] uppercase tracking-wide text-muted-foreground font-medium">Catégorie</p>
<p className="text-sm font-medium text-foreground">{item.categorie}</p>
</div>
</div>
)}
{item.niveau && (
<div className="flex items-start gap-2 p-3 rounded-lg bg-violet-50 border border-violet-200">
<Layers size={14} className="text-violet-500 mt-0.5 shrink-0" />
@@ -314,7 +305,6 @@ export default function VeilleDashboard() {
const totalPages = Math.ceil(total / PAGE_SIZE);
const filterOptions = [
{ key: "categorie", label: "Catégorie", options: filtersQuery.data?.categories ?? [] },
{ key: "niveau", label: "Niveau", options: filtersQuery.data?.niveaux ?? [] },
{ key: "territoire", label: "Territoire", options: filtersQuery.data?.territoires ?? [] },
{ key: "dateFrom", label: "Date depuis", type: "date" as const },
@@ -334,7 +324,7 @@ export default function VeilleDashboard() {
)}
</div>
<p className="text-muted-foreground text-sm">
Suivi réglementaire, concurrentiel, technologique et général
Suivi réglementaire, concurrentiel, technologique et informationnel
</p>
</div>
<div className="flex items-center gap-2">
@@ -460,7 +450,6 @@ function VeilleListView({ items, onDetail, readIds }: { items: VeilleItem[]; onD
<th className="text-left px-4 py-3 font-semibold text-muted-foreground w-8">#</th>
<th className="text-left px-4 py-3 font-semibold text-muted-foreground">Titre</th>
<th className="text-left px-4 py-3 font-semibold text-muted-foreground w-32">Type</th>
<th className="text-left px-4 py-3 font-semibold text-muted-foreground w-28">Catégorie</th>
<th className="text-left px-4 py-3 font-semibold text-muted-foreground w-24">Niveau</th>
<th className="text-left px-4 py-3 font-semibold text-muted-foreground w-36">Territoire</th>
<th className="text-left px-4 py-3 font-semibold text-muted-foreground w-28">Date</th>
@@ -487,9 +476,6 @@ function VeilleListView({ items, onDetail, readIds }: { items: VeilleItem[]; onD
{TYPE_LABELS[item.typeVeille as TypeVeille] || item.typeVeille}
</Badge>
</td>
<td className="px-4 py-3 text-xs">
<span className="text-muted-foreground">{item.categorie || "—"}</span>
</td>
<td className="px-4 py-3 text-muted-foreground text-xs">{item.niveau || "—"}</td>
<td className="px-4 py-3 text-muted-foreground text-xs">{item.territoire || "—"}</td>
<td className="px-4 py-3 text-muted-foreground text-xs whitespace-nowrap">{formatDate(item.datePublication) || "—"}</td>
@@ -562,8 +548,7 @@ function VeilleGridView({ items, onDetail, readIds }: { items: VeilleItem[]; onD
<CardContent className="px-4 pb-4 space-y-2">
{(item.iaResume || item.resume) && <p className="text-xs text-muted-foreground line-clamp-3 leading-relaxed">{item.iaResume || item.resume}</p>}
<div className="flex flex-wrap gap-1.5 pt-1">
{item.categorie && <span className="inline-flex items-center gap-1 text-xs text-muted-foreground"><Tag size={10} />{item.categorie}</span>}
{item.territoire && (
{item.territoire && (
<span className="inline-flex items-center gap-1 text-xs px-1.5 py-0.5 rounded bg-teal-50 text-teal-700 border border-teal-200">
<MapPin size={10} />{item.territoire}
</span>