fix Minified React error

This commit is contained in:
corenthin-lebreton 2026-02-27 00:40:57 +01:00
parent 5c73ae89b3
commit 7b225f1271
5 changed files with 109 additions and 85 deletions

View File

@ -17,7 +17,7 @@ import {
Eye,
EyeOff,
} from 'lucide-react'
import { cn } from '@/lib/utils'
import { cn, formatDate } from '@/lib/utils'
import Link from 'next/link'
interface User {
@ -34,14 +34,6 @@ interface Props {
currentUserId: string
}
function formatDate(dateStr: string | null) {
if (!dateStr) return 'Jamais'
return new Date(dateStr).toLocaleDateString('fr-FR', {
day: '2-digit',
month: 'short',
year: 'numeric',
})
}
const roleConfig = {
admin: { label: 'Admin', color: 'bg-purple-500/10 text-purple-400 border-purple-500/20' },

View File

@ -20,7 +20,7 @@ import {
FileJson,
RefreshCw,
} from 'lucide-react'
import { cn } from '@/lib/utils'
import { cn, formatDate } from '@/lib/utils'
interface Quiz {
id: string
@ -50,13 +50,6 @@ interface Props {
}
}
function formatDate(dateStr: string): string {
return new Date(dateStr).toLocaleDateString('fr-FR', {
day: '2-digit',
month: 'short',
year: 'numeric',
})
}
export default function QuizzesClient({ initialCategories, stats: initialStats }: Props) {
const router = useRouter()

View File

@ -1,5 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { createClient } from '@/lib/supabase/server'
import { formatDate } from '@/lib/utils'
import { BarChart3 } from 'lucide-react'
import Link from 'next/link'
@ -48,7 +49,7 @@ export default async function ReportsPage() {
Code: <span className="font-mono text-primary">{session.short_code}</span>
{session.school_name && ` · ${session.school_name}`}
{session.class_name && ` · ${session.class_name}`}
{' · '}{new Date(session.created_at).toLocaleDateString('fr-FR')}
{' · '}{formatDate(session.created_at)}
</p>
</div>
<Link

View File

@ -13,3 +13,19 @@ export function calculateScore(correct: number, total: number): number {
export function formatScore(score: number): string {
return score.toFixed(2)
}
// Formatage de date identique sur Node.js (serveur) et navigateur (client).
// toLocaleDateString() produit des résultats différents selon l'environnement,
// ce qui cause des erreurs d'hydration React #418.
const MONTHS_FR = ['janv.', 'févr.', 'mars', 'avr.', 'mai', 'juin',
'juil.', 'août', 'sept.', 'oct.', 'nov.', 'déc.']
export function formatDate(dateStr: string | null | undefined): string {
if (!dateStr) return 'Jamais'
const d = new Date(dateStr)
if (isNaN(d.getTime())) return '—'
const day = String(d.getDate()).padStart(2, '0')
const month = MONTHS_FR[d.getMonth()]
const year = d.getFullYear()
return `${day} ${month} ${year}`
}

View File

@ -1,110 +1,132 @@
{
"title": "Control plane",
"title": "Worker nodes",
"questions": [
{
"question": "Le Scheduler et le Controller Manager accèdent directement à etcd pour lire l'état du cluster.",
"explanation": "C'est une règle d'or : seul le kube-apiserver communique directement avec etcd. Tous les autres composants passent par l'API Server pour obtenir ou modifier des informations.",
"question": "Que fait la commande 'kubectl drain <node-name>' ?",
"explanation": "Le 'drain' prépare un nœud pour la maintenance en expulsant les Pods existants (vers d'autres nœuds via leurs Controllers) et en marquant le nœud comme non-planifiable (cordon).",
"answers": [
{ "text": "Vrai", "correct": false },
{ "text": "Faux", "correct": true }
{ "text": "Supprime tous les Pods du cluster", "correct": false },
{ "text": "Redémarre kubelet", "correct": false },
{ "text": "Déplace les Pods vers dautres nœuds", "correct": true },
{ "text": "Vide les fichiers de logs", "correct": false }
]
},
{
"question": "Quelles sont les trois fonctions principales de l'API Server ?",
"explanation": "L'API Server sert de hub central : il authentifie/valide les requêtes, stocke les données de manière persistante dans etcd et expose l'état actuel du cluster aux utilisateurs et composants.",
"question": "Lequel de ces outils est un runtime de conteneurs compatible avec Kubernetes ?",
"explanation": "Pour être compatible, un runtime doit implémenter l'interface CRI. containerd, CRI-O ou Podman (via cri-o) en font partie.",
"answers": [
{ "text": "Valider les requêtes, persister dans etcd, exposer l'état du cluster", "correct": true },
{ "text": "Scheduler les Pods, créer les ReplicaSets, monitorer les Nodes", "correct": false },
{ "text": "Lancer les conteneurs, assigner les Pods, gérer le réseau", "correct": false },
{ "text": "Authentifier les utilisateurs, chiffrer les secrets, gérer les certificats", "correct": false }
{ "text": "Cilium", "correct": false },
{ "text": "Podman", "correct": true },
{ "text": "Kubectl", "correct": false },
{ "text": "Kubelet", "correct": false }
]
},
{
"question": "Quel composant du Control Plane détecte les Nodes en panne ?",
"explanation": "Le Node Controller (intégré au kube-controller-manager) est responsable de la surveillance des nœuds et de l'éviction des Pods si un nœud ne répond plus.",
"question": "Quel composant exécute les conteneurs à la demande du kubelet ?",
"explanation": "La Container Runtime Interface (CRI) est l'interface standard qui permet au kubelet d'interagir avec différents moteurs de conteneurs sans connaître leurs spécificités internes.",
"answers": [
{ "text": "Node controller", "correct": true },
{ "text": "Job controller", "correct": false },
{ "text": "ReplicaSet controller", "correct": false },
{ "text": "Endpoints controller", "correct": false }
{ "text": "etcd", "correct": false },
{ "text": "scheduler", "correct": false },
{ "text": "kube-proxy", "correct": false },
{ "text": "CRI", "correct": true }
]
},
{
"question": "Le kube-controller-manager communique directement avec etcd pour mettre à jour l'état du cluster.",
"explanation": "Comme pour le Scheduler, le Controller Manager doit envoyer des requêtes à l'API Server, qui se chargera ensuite d'écrire dans etcd.",
"answers": [
{ "text": "Vrai", "correct": false },
{ "text": "Faux", "correct": true }
]
},
{
"question": "Quelles sont les deux étapes du processus de scheduling ?",
"explanation": "Le scheduler procède d'abord par 'Filtrage' (éliminer les nœuds incompatibles) puis par 'Scoring' (classer les nœuds restants pour choisir le meilleur).",
"answers": [
{ "text": "Création puis démarrage", "correct": false },
{ "text": "Filtrage puis scoring", "correct": true },
{ "text": "Validation puis persistence", "correct": false },
{ "text": "Assignation puis Exécution", "correct": false }
]
},
{
"question": "Si le Control Plane tombe, les Pods existants continuent de tourner sur les Worker Nodes.",
"explanation": "Le Control Plane gère l'orchestration. Si il disparaît, le cluster devient 'gelé' (pas de nouveaux Pods), mais le plan de données (les Workers) continue d'exécuter ce qui est déjà en place.",
"question": "Le mode iptables de kube-proxy peut devenir lent avec des milliers de Services.",
"explanation": "iptables utilise une recherche séquentielle (O(n)). Plus il y a de règles (services), plus le temps de traitement augmente. IPVS est alors recommandé.",
"answers": [
{ "text": "Vrai", "correct": true },
{ "text": "Faux", "correct": false }
]
},
{
"question": "Le kube-controller-manager agit uniquement lorsquun utilisateur interagit avec le cluster.",
"explanation": "Faux. C'est une boucle de contrôle infinie (control loop) qui compare l'état désiré à l'état réel en permanence, même sans action humaine.",
"question": "Quel outil permet de surveiller létat du service kubelet sur un nœud Linux ?",
"explanation": "Kubelet tournant généralement comme un service système (Systemd) sur les nœuds, la commande standard est 'systemctl status kubelet'.",
"answers": [
{ "text": "systemctl status kubelet", "correct": true },
{ "text": "kubectl logs kubelet", "correct": false },
{ "text": "docker ps", "correct": false },
{ "text": "journalctl -u kubelet", "correct": true }
]
},
{
"question": "Kube-proxy fonctionne uniquement sur le control plane",
"explanation": "Kube-proxy doit tourner sur chaque nœud (Worker et Master) pour gérer les règles réseau permettant la communication vers les Services.",
"answers": [
{ "text": "Vrai", "correct": false },
{ "text": "Faux", "correct": true }
]
},
{
"question": "L'API Server est le seul composant du Control Plane qui peut lire et écrire dans etcd.",
"explanation": "C'est une architecture conçue pour la sécurité et la cohérence des données : l'API Server est le gardien d'etcd.",
"question": "Quel fichier contient les manifests locaux de Pods lus automatiquement par le kubelet ?",
"explanation": "Le chemin par défaut pour les Static Pods (Pods gérés par Kubelet sans passer par l'API Server) est souvent défini dans ce répertoire via le paramètre staticPodPath.",
"answers": [
{ "text": "/var/lib/kubelet/config/pod.yaml", "correct": true },
{ "text": "/etc/kubernetes/manifests", "correct": true },
{ "text": "/etc/pod.d/", "correct": false },
{ "text": "/var/run/kubernetes.json", "correct": false }
]
},
{
"question": "runc est le composant bas niveau qui crée réellement les conteneurs avec les namespaces et cgroups Linux.",
"explanation": "runc est l'implémentation de référence de l'OCI (Open Container Initiative) qui dialogue avec le noyau Linux pour isoler les processus.",
"answers": [
{ "text": "Vrai", "correct": true },
{ "text": "Faux", "correct": false }
]
},
{
"question": "Quel champ du Pod le Scheduler remplit-il lors de l'assignation à un Node ?",
"explanation": "Le processus de scheduling consiste techniquement à mettre à jour le champ 'nodeName' dans la définition du Pod.",
"answers": [
{ "text": "nodeName", "correct": true },
{ "text": "NamePod", "correct": false },
{ "text": "NomDuPod", "correct": false },
{ "text": "NameOfThePod", "correct": false }
]
},
{
"question": "Dans quel ordre les composants interviennent-ils lors de la création d'un Deployment ?",
"explanation": "L'API Server reçoit l'ordre, les Controllers créent les objets (RS, Pods), le Scheduler choisit le nœud, et enfin le Kubelet exécute.",
"answers": [
{ "text": "Scheduler → API Server → Controller Manager → Kubelet", "correct": false },
{ "text": "Controller Manager → Scheduler → Kubelet → API Server", "correct": false },
{ "text": "Kubelet → Scheduler → API Server → Controller Manager", "correct": false },
{ "text": "API Server → Deployment Controller → ReplicaSet Controller → Scheduler → Kubelet", "correct": true }
]
},
{
"question": "Un seul controller manager peut gérer plusieurs types de contrôleurs.",
"explanation": "Le 'kube-controller-manager' est un binaire unique qui regroupe de nombreux contrôleurs (Node, Deployment, Namespace, etc.) pour simplifier la gestion.",
"question": "Les Static Pods peuvent être créés même si l'API Server n'est pas disponible.",
"explanation": "Oui, car le Kubelet surveille un dossier local sur le disque. Il lance les Pods qu'il y trouve sans attendre d'ordre du Control Plane.",
"answers": [
{ "text": "Vrai", "correct": true },
{ "text": "Faux", "correct": false }
]
},
{
"question": "Le kube-apiserver interagit directement avec les kubelets sur les nœuds",
"explanation": "Bien que l'API Server puisse initier des connexions (pour les logs ou l'exécution de commandes), c'est généralement le Kubelet qui surveille l'API Server pour recevoir ses instructions.",
"question": "Le kubelet utilise le modèle pull pour obtenir l'état désiré depuis l'API Server.",
"explanation": "Le Kubelet 'watch' l'API Server. Il tire (pull) les informations concernant les Pods qui lui sont assignés.",
"answers": [
{ "text": "Vrai", "correct": false },
{ "text": "Faux", "correct": true }
{ "text": "Vrai", "correct": true },
{ "text": "Faux", "correct": false }
]
},
{
"question": "Quelle commande réactive la planification sur un Node après maintenance ?",
"explanation": "'uncordon' retire la marque 'node.kubernetes.io/unschedulable' et permet au scheduler d'y placer de nouveaux Pods.",
"answers": [
{ "text": "kubectl enable", "correct": false },
{ "text": "kubectl resume", "correct": false },
{ "text": "kubectl uncordon", "correct": true },
{ "text": "kubectl activate", "correct": false }
]
},
{
"question": "Quel protocole utilise le kubelet pour communiquer avec le runtime via CRI ?",
"explanation": "L'interface CRI est basée sur gRPC, ce qui permet des communications performantes et fortement typées entre Kubelet et le runtime.",
"answers": [
{ "text": "WebSocket", "correct": false },
{ "text": "TCP Socket", "correct": false },
{ "text": "gRPC", "correct": true },
{ "text": "REST API", "correct": false }
]
},
{
"question": "Quel mode de kube-proxy offre une performance constante O(1) grâce aux hash tables ?",
"explanation": "IPVS (IP Virtual Server) utilise des tables de hachage pour rediriger le trafic, ce qui le rend beaucoup plus performant que les listes séquentielles d'iptables sur de grands clusters.",
"answers": [
{ "text": "userspace", "correct": false },
{ "text": "iptables", "correct": false },
{ "text": "nftables", "correct": false },
{ "text": "ipvs", "correct": true }
]
},
{
"question": "Le kubelet communique avec le Control Plane via lAPI server.",
"explanation": "L'API Server est le seul point de contact du Kubelet pour rapporter l'état des nœuds et recevoir les spécifications des Pods.",
"answers": [
{ "text": "Vrai", "correct": true },
{ "text": "Faux", "correct": false }
]
}
]