feat: next run countdown in auto-cycle config
- auto_cycle.py: next_run_at now set to future timestamp (now + interval) instead of current time — was always showing wrong value - Config.tsx: NextRunCountdown component shows live countdown (updates every second) + absolute local time, only visible when auto-cycle enabled Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -744,9 +744,10 @@ def _scheduler_loop(stop_event: threading.Event):
|
||||
interval_hours = 3.0
|
||||
|
||||
_current_status["interval_hours"] = interval_hours
|
||||
next_run = datetime.utcnow().isoformat()
|
||||
from datetime import timedelta
|
||||
next_run = (datetime.utcnow() + timedelta(hours=interval_hours)).isoformat()
|
||||
_current_status["next_run_at"] = next_run
|
||||
logger.info(f"[Scheduler] Next cycle in {interval_hours}h")
|
||||
logger.info(f"[Scheduler] Next cycle in {interval_hours}h (at {next_run[:16]} UTC)")
|
||||
|
||||
# Wait for the interval (or until stop is signalled)
|
||||
stop_event.wait(timeout=interval_hours * 3600)
|
||||
|
||||
@@ -39,6 +39,34 @@ const PROFILE_COLORS = [
|
||||
{ value: '#eab308', label: 'Jaune' },
|
||||
]
|
||||
|
||||
function NextRunCountdown({ nextRunAt }: { nextRunAt: string }) {
|
||||
const [remaining, setRemaining] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
function update() {
|
||||
const diff = new Date(nextRunAt + 'Z').getTime() - Date.now()
|
||||
if (diff <= 0) { setRemaining('Imminent…'); return }
|
||||
const h = Math.floor(diff / 3_600_000)
|
||||
const m = Math.floor((diff % 3_600_000) / 60_000)
|
||||
const s = Math.floor((diff % 60_000) / 1_000)
|
||||
setRemaining(h > 0 ? `${h}h ${m.toString().padStart(2,'0')}min` : `${m}min ${s.toString().padStart(2,'0')}s`)
|
||||
}
|
||||
update()
|
||||
const id = setInterval(update, 1_000)
|
||||
return () => clearInterval(id)
|
||||
}, [nextRunAt])
|
||||
|
||||
const absTime = new Date(nextRunAt + 'Z').toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-2 text-emerald-400/80">
|
||||
<span className="inline-block w-1.5 h-1.5 rounded-full bg-emerald-400 animate-pulse" />
|
||||
<span>Prochain cycle dans <span className="font-mono font-semibold text-emerald-300">{remaining}</span></span>
|
||||
<span className="text-slate-600">({absTime} heure locale)</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function evNetLabel(evNet: number): { text: string; cls: string } {
|
||||
if (evNet > 0.05) return { text: `EV nette +${(evNet * 100).toFixed(0)}%`, cls: 'text-emerald-400' }
|
||||
if (evNet >= -0.01) return { text: 'EV nette ≈ 0', cls: 'text-yellow-400' }
|
||||
@@ -692,7 +720,7 @@ export default function Config() {
|
||||
<RiskProfilesCard />
|
||||
|
||||
{cs?.last_cycle && (
|
||||
<div className="card bg-dark-700/50 mb-4 text-xs">
|
||||
<div className="card bg-dark-700/50 mb-4 text-xs space-y-2">
|
||||
<div className="flex items-center gap-4 flex-wrap">
|
||||
<span className="text-slate-500">Dernier cycle :</span>
|
||||
<span className="text-slate-300">{cs.last_cycle.started_at?.slice(0, 16)} UTC</span>
|
||||
@@ -704,6 +732,9 @@ export default function Config() {
|
||||
<span className="text-slate-500">Géo: {cs.last_cycle.geo_score}</span>
|
||||
<span className="text-slate-500 capitalize">{cs.last_cycle.dominant_regime}</span>
|
||||
</div>
|
||||
{cs.enabled && cs.next_run_at && !cs.running && (
|
||||
<NextRunCountdown nextRunAt={cs.next_run_at} />
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user