fix(simulations): resolve FTD-23 autosave after correction + FTD-24 auto-polling pending jobs
- FTD-23: propagate enabled=false to useAutosave when step is done/correcting, preventing 400 PATCH after correction - FTD-24: add conditional refetchInterval (3s) in useRapport for pending exercices/modele, 2min timeout with retry UI - 7 new tests (2 regression + 5 polling), 122/122 green Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
bc2a1174d1
commit
cab9c8c92b
8 changed files with 379 additions and 20 deletions
|
|
@ -99,7 +99,8 @@ export function SimulationForm({
|
|||
|
||||
const timer = useTimer(config.dureeMinutes, !isSubmitting)
|
||||
const idees = useIdees()
|
||||
const autosave = useAutosave(simulationId, texte, !isSubmitting)
|
||||
const autosaveEnabled = !isSubmitting && step !== 'done' && step !== 'correcting'
|
||||
const autosave = useAutosave(simulationId, texte, autosaveEnabled)
|
||||
|
||||
// FTD-21 — marquer la simulation en cours pour le resume au refresh.
|
||||
useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -1,38 +1,58 @@
|
|||
/**
|
||||
* JobStatusFallback — Sprint 3.6b.
|
||||
* JobStatusFallback — Sprint 3.6b + FTD-24.
|
||||
*
|
||||
* Affiche un fallback visuel pour les sections générées en asynchrone par le
|
||||
* backend (exercices, production modèle) :
|
||||
* - 'pending' → "Génération en cours…" avec spinner (refresh manuel côté user)
|
||||
* - 'error' → "Indisponible pour le moment"
|
||||
*
|
||||
* FTD-24 tracera le polling automatique (laissé pour une session ultérieure).
|
||||
* - 'pending' → "Génération en cours…" avec spinner. Polling automatique
|
||||
* géré par useRapport (cf. FTD-24).
|
||||
* - 'pending' + hasTimedOut → message "La génération prend plus de temps
|
||||
* que prévu" + bouton Réessayer.
|
||||
* - 'error' → "Indisponible pour le moment".
|
||||
*
|
||||
* Règle L : tokens Direction H exclusivement.
|
||||
*/
|
||||
|
||||
import { Loader2 } from 'lucide-react'
|
||||
import { Card } from '@/shared/ui/Card'
|
||||
import { Button } from '@/shared/ui/Button'
|
||||
import type { JobStatus } from '@/entities/report/types'
|
||||
|
||||
interface Props {
|
||||
status: JobStatus
|
||||
pendingLabel?: string
|
||||
errorLabel?: string
|
||||
hasTimedOut?: boolean
|
||||
onRetry?: () => void
|
||||
}
|
||||
|
||||
export function JobStatusFallback({
|
||||
status,
|
||||
pendingLabel = 'Génération en cours…',
|
||||
errorLabel = 'Indisponible pour le moment.',
|
||||
hasTimedOut = false,
|
||||
onRetry,
|
||||
}: Props) {
|
||||
if (status === 'pending') {
|
||||
if (hasTimedOut) {
|
||||
return (
|
||||
<Card variant="default" className="space-y-3 p-4">
|
||||
<p className="text-sm text-ink-2" role="alert">
|
||||
La génération prend plus de temps que prévu.
|
||||
</p>
|
||||
{onRetry && (
|
||||
<Button variant="secondary" size="sm" onClick={onRetry}>
|
||||
Réessayer
|
||||
</Button>
|
||||
)}
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Card variant="default" className="flex items-center gap-3 p-4">
|
||||
<Loader2 className="size-4 animate-spin text-ink-4" aria-hidden="true" />
|
||||
<p className="text-sm text-ink-3" aria-live="polite">
|
||||
{pendingLabel}{' '}
|
||||
<span className="text-ink-4">Rafraîchissez la page dans quelques instants.</span>
|
||||
{pendingLabel}
|
||||
</p>
|
||||
</Card>
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue