perf(desktop): pause hidden-pane timers in agents view, cron sidebar, and floating pet

Partial pick of the surviving renderer hunks from #75395 (perf commit
6502e441d plus fixup 3fbbc9c1d): gate the 500ms subagent now-ticker and
the cron sidebar 1s ticker/run-poll on usePaneVisible, and skip the
legacy floating-pet poll while the document is hidden. Dropped hunks
(electron/main.ts, vitest.setup.ts/config) intentionally excluded.
This commit is contained in:
Daisuke Suzuki 2026-08-03 17:47:16 +05:30 committed by kshitij
parent 7700597a17
commit 52fb96de4b
3 changed files with 24 additions and 9 deletions

View File

@ -1,6 +1,7 @@
import { useStore } from '@nanostores/react'
import { type ReactNode, useEffect, useMemo, useState } from 'react'
import { usePaneVisible } from '@/components/pane-shell/pane-visibility'
import { useElapsedSeconds } from '@/components/chat/activity-timer'
import { ActivityTimerText } from '@/components/chat/activity-timer-text'
import { Codicon } from '@/components/ui/codicon'
@ -189,15 +190,17 @@ function SubagentTree({ tree }: { tree: SubagentNode[] }) {
const tokens = flat.reduce((sum, n) => sum + (n.inputTokens ?? 0) + (n.outputTokens ?? 0), 0)
const cost = flat.reduce((sum, n) => sum + (n.costUsd ?? 0), 0)
const visible = usePaneVisible()
useEffect(() => {
if (active <= 0 || typeof window === 'undefined') {
if (active <= 0 || !visible || typeof window === 'undefined') {
return
}
const id = window.setInterval(() => setNowMs(Date.now()), 500)
return () => window.clearInterval(id)
}, [active])
}, [active, visible])
if (tree.length === 0) {
return (

View File

@ -1,6 +1,8 @@
import { useStore } from '@nanostores/react'
import { useEffect, useMemo, useState } from 'react'
import { usePaneVisible } from '@/components/pane-shell/pane-visibility'
import { ActionsContextMenu, type MenuKit, renderActionItem } from '@/components/ui/actions-menu'
import { Codicon } from '@/components/ui/codicon'
import { DisclosureCaret } from '@/components/ui/disclosure-caret'
@ -92,17 +94,19 @@ export function SidebarCronJobsSection({
// Rows revealed so far; starts compact, grows in steps via "load more".
const [visibleCount, setVisibleCount] = useState(INITIAL_VISIBLE_JOBS)
const visible = usePaneVisible()
// One clock for the whole section (rows are pure) so the countdowns tick
// without re-rendering the rest of the sidebar. Only runs while expanded.
// without re-rendering the rest of the sidebar. Only runs while expanded and visible.
useEffect(() => {
if (!open) {
if (!open || !visible) {
return
}
const id = window.setInterval(() => setNowMs(Date.now()), 1000)
return () => window.clearInterval(id)
}, [open])
}, [open, visible])
// Upcoming first (soonest next run), jobs with no next run sink to the bottom,
// then alphabetical for stability.
@ -328,6 +332,7 @@ function CronJobSidebarRuns({ jobId, onOpenRun }: { jobId: string; onOpenRun: (s
const changeEventsAvailable = useStore($changeEventsAvailable)
const cronChangeTick = useStore($cronChangeTick)
const [runs, setRuns] = useState<null | SessionInfo[]>(null)
const visible = usePaneVisible()
useEffect(() => {
let cancelled = false
@ -345,11 +350,14 @@ function CronJobSidebarRuns({ jobId, onOpenRun }: { jobId: string; onOpenRun: (s
}
})
void load()
// Initial load when visible
if (visible) {
void load()
}
const intervalId = window.setInterval(
() => {
if (document.visibilityState === 'visible') {
if (visible && document.visibilityState === 'visible') {
void load()
}
},
@ -361,7 +369,7 @@ function CronJobSidebarRuns({ jobId, onOpenRun }: { jobId: string; onOpenRun: (s
window.clearInterval(intervalId)
}
// cronChangeTick: a fired run reloads the peek immediately.
}, [changeEventsAvailable, cronChangeTick, jobId])
}, [changeEventsAvailable, cronChangeTick, jobId, visible])
return (
<div className="mb-1 ml-[1.375rem] flex flex-col gap-px">

View File

@ -214,7 +214,11 @@ export function FloatingPet() {
// so no timer. Legacy backend: the historical poll.
const timer = changeEventsAvailable
? null
: window.setInterval(() => void pull(), active ? PET_ACTIVE_REFRESH_MS : PET_POLL_MS)
: window.setInterval(() => {
if (document.visibilityState === 'visible') {
void pull()
}
}, active ? PET_ACTIVE_REFRESH_MS : PET_POLL_MS)
return () => {
cancelled = true