mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-31 19:16:29 +00:00
fix(desktop): track kanban lane phase in state, not a mirrored ref
main landed a lint rule banning refs mirrored from reactive values in an effect — they lag a render and cause stale reads. The lane-collapse override tracker did exactly that with a counts ref. Hold the empty/non-empty signature in state instead. React bails out when it's unchanged, so a poll where no lane's emptiness moved costs no extra render, and the comparison always sees the current value.
This commit is contained in:
parent
81e196f236
commit
1238efce13
2 changed files with 20 additions and 11 deletions
|
|
@ -1,7 +1,7 @@
|
|||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import { registry } from '@/contrib/registry'
|
||||
import { createPluginContext } from '@/contrib/plugin'
|
||||
import { registry } from '@/contrib/registry'
|
||||
import { allKeybindActions, contributedKeybindHandler, KEYBINDS_AREA } from '@/lib/keybinds/actions'
|
||||
import { bindingsFor } from '@/store/keybinds'
|
||||
|
||||
|
|
|
|||
|
|
@ -1244,28 +1244,37 @@ export function KanbanBoardPage() {
|
|||
// override is dropped and auto takes over — so a drained lane collapses even
|
||||
// if it was manually expanded ages ago, while expanding an empty lane still
|
||||
// sticks for as long as it stays empty.
|
||||
const laneCounts = useRef<null | Record<string, number>>(null)
|
||||
//
|
||||
// The phase is a string signature held in state, not a ref: React bails out
|
||||
// when it's unchanged, so the common case (a poll where no lane's emptiness
|
||||
// moved) costs no extra render, and nothing lags a render behind the value
|
||||
// it mirrors.
|
||||
const lanePhase = filtered
|
||||
? filtered.columns.map(col => `${col.name}:${col.tasks.length === 0 ? 'empty' : 'full'}`).join('|')
|
||||
: null
|
||||
|
||||
const [prevLanePhase, setPrevLanePhase] = useState<null | string>(null)
|
||||
|
||||
useEffect(() => {
|
||||
if (!filtered) {
|
||||
if (lanePhase === null || lanePhase === prevLanePhase) {
|
||||
return
|
||||
}
|
||||
|
||||
const counts = Object.fromEntries(filtered.columns.map(col => [col.name, col.tasks.length]))
|
||||
const prev = laneCounts.current
|
||||
laneCounts.current = counts
|
||||
setPrevLanePhase(lanePhase)
|
||||
|
||||
if (!prev) {
|
||||
if (prevLanePhase === null) {
|
||||
return
|
||||
}
|
||||
|
||||
const before = new Map(prevLanePhase.split('|').map(entry => entry.split(':') as [string, string]))
|
||||
const overrides = { ...$collapsedLanes.get() }
|
||||
let changed = false
|
||||
|
||||
for (const [name, count] of Object.entries(counts)) {
|
||||
const before = prev[name]
|
||||
for (const entry of lanePhase.split('|')) {
|
||||
const [name, phase] = entry.split(':')
|
||||
const was = before.get(name)
|
||||
|
||||
if (before !== undefined && (before === 0) !== (count === 0) && name in overrides) {
|
||||
if (was !== undefined && was !== phase && name in overrides) {
|
||||
delete overrides[name]
|
||||
changed = true
|
||||
}
|
||||
|
|
@ -1274,7 +1283,7 @@ export function KanbanBoardPage() {
|
|||
if (changed) {
|
||||
$collapsedLanes.set(overrides)
|
||||
}
|
||||
}, [filtered])
|
||||
}, [lanePhase, prevLanePhase])
|
||||
|
||||
const toggleLane = (name: string, auto: boolean) => {
|
||||
const overrides = { ...laneOverrides }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue