refactor(desktop): shared pulse beat + fully-gated cron peek (simplify folds)

Two findings from the simplify pass on the final trio diff:

- status-pulse: one pause controller + one aligned period timer shared by all StatusPulse instances (ref-counted), instead of N x (document/window/bridge listeners + unsynchronized 5s wakes) — a sidebar can show dozens of pulsing dots. Pause still cancels in-flight animations so the compositor sleeps immediately.
- cron-jobs-section: the runs-peek effect created its interval even while the pane was hidden (callback no-oped but the timer still woke the renderer every 8s/60s per expanded job). Early-return when hidden — visibility is already in the dep array, so becoming visible restarts load + timer.
This commit is contained in:
kshitij 2026-08-03 18:25:24 +05:30 committed by kshitij
parent e2a2149df4
commit aece98c5f3
2 changed files with 88 additions and 35 deletions

View File

@ -350,14 +350,20 @@ function CronJobSidebarRuns({ jobId, onOpenRun }: { jobId: string; onOpenRun: (s
}
})
// Initial load when visible
if (visible) {
void load()
// Hidden pane: skip the peek entirely — no initial load, no interval.
// `visible` is in the dep array, so becoming visible re-runs this effect
// and starts the load + timer fresh (same shape as the section clock).
if (!visible) {
return () => {
cancelled = true
}
}
void load()
const intervalId = window.setInterval(
() => {
if (visible && document.visibilityState === 'visible') {
if (document.visibilityState === 'visible') {
void load()
}
},

View File

@ -5,6 +5,78 @@ import { createRendererLoopPauseController } from '@/lib/renderer-loop-pause'
const PULSE_DURATION_MS = 400
const PULSE_PERIOD_MS = 5_000
// One pause controller + one period timer shared by every StatusPulse
// instance. A sidebar can show dozens of pulsing dots at once; per-instance
// controllers would mean N×(document/window/bridge) listeners and N
// unsynchronized 5s wakes. Ref-counted: the controller and timer exist only
// while at least one pulse is mounted, and all pulses play in one aligned
// wake so the renderer sleeps between beats.
type PulseSubscriber = { play: () => void; cancel: () => void }
const pulseSubscribers = new Set<PulseSubscriber>()
let sharedPauseController: ReturnType<typeof createRendererLoopPauseController> | null = null
let sharedTimer = 0
const stopSharedTimer = () => {
if (sharedTimer !== 0) {
window.clearTimeout(sharedTimer)
sharedTimer = 0
}
}
const beat = () => {
sharedTimer = 0
if (sharedPauseController?.isPaused() || pulseSubscribers.size === 0) {
return
}
for (const subscriber of pulseSubscribers) {
subscriber.play()
}
sharedTimer = window.setTimeout(beat, PULSE_PERIOD_MS)
}
const handleSharedPauseChange = () => {
stopSharedTimer()
if (sharedPauseController?.isPaused()) {
// Minimized/hidden: cancel in-flight animations so the compositor can
// sleep immediately instead of finishing a pulse nobody sees.
for (const subscriber of pulseSubscribers) {
subscriber.cancel()
}
return
}
beat()
}
const subscribePulse = (subscriber: PulseSubscriber): (() => void) => {
pulseSubscribers.add(subscriber)
if (!sharedPauseController) {
sharedPauseController = createRendererLoopPauseController(handleSharedPauseChange)
}
// First subscriber (or a new one joining mid-sleep): play immediately and
// start the beat. Later joiners just wait for the next aligned beat.
if (sharedTimer === 0 && !sharedPauseController.isPaused()) {
subscriber.play()
sharedTimer = window.setTimeout(beat, PULSE_PERIOD_MS)
}
return () => {
pulseSubscribers.delete(subscriber)
if (pulseSubscribers.size === 0) {
stopSharedTimer()
sharedPauseController?.dispose()
sharedPauseController = null
}
}
}
export interface StatusPulseProps extends Omit<ComponentProps<'span'>, 'children' | 'ref'> {
kind: 'opacity' | 'ping'
opacity?: number
@ -33,27 +105,8 @@ export function StatusPulse({ kind, opacity = 1, ...props }: StatusPulseProps) {
}
let animation: Animation | null = null
let timer = 0
let stopped = false
let pauseController: ReturnType<typeof createRendererLoopPauseController> | null = null
const clearScheduled = () => {
if (timer !== 0) {
window.clearTimeout(timer)
timer = 0
}
animation?.cancel()
animation = null
}
const play = () => {
timer = 0
if (stopped || pauseController?.isPaused()) {
return
}
animation?.cancel()
animation = element.animate(
kind === 'ping'
@ -68,24 +121,18 @@ export function StatusPulse({ kind, opacity = 1, ...props }: StatusPulseProps) {
iterations: 1
}
)
timer = window.setTimeout(play, PULSE_PERIOD_MS)
}
const handlePauseChange = () => {
clearScheduled()
if (!pauseController?.isPaused()) {
play()
}
const cancel = () => {
animation?.cancel()
animation = null
}
pauseController = createRendererLoopPauseController(handlePauseChange)
play()
const unsubscribe = subscribePulse({ play, cancel })
return () => {
stopped = true
clearScheduled()
pauseController?.dispose()
unsubscribe()
cancel()
}
}, [kind, opacity])