fix Minified React error
This commit is contained in:
parent
5c73ae89b3
commit
7b225f1271
@ -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' },
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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
|
||||
|
||||
16
lib/utils.ts
16
lib/utils.ts
@ -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}`
|
||||
}
|
||||
|
||||
@ -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 d’autres 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 lorsqu’un 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 l’API 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 }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user