Skip to content

fix(web): keep highlights card active index in range on refresh#1334

Open
abhay-codes07 wants to merge 1 commit into
supermemoryai:mainfrom
abhay-codes07:fix/highlights-card-stale-active-index
Open

fix(web): keep highlights card active index in range on refresh#1334
abhay-codes07 wants to merge 1 commit into
supermemoryai:mainfrom
abhay-codes07:fix/highlights-card-stale-active-index

Conversation

@abhay-codes07

Copy link
Copy Markdown
Contributor

Problem

HighlightsCard tracks the visible highlight with activeIndex, and derives currentItem = items[activeIndex]. When items changes, the effect keyed on [items] resets the reply and expansion state but never touches activeIndex:

useEffect(() => {
  setIsReplyOpen(false)
  setReplyText("")
  setIsExpanded(false)
}, [items])

The Daily Brief "refreshes automatically every few hours" (per the card's own info popover), which replaces items wholesale. If the user has paged to a later highlight and the refresh returns a shorter list, activeIndex is left pointing past the end. currentItem becomes undefined, and the render falls through to:

if (!currentItem || items.length === 0) {
  return ( /* "Add some documents to see highlights here" empty state */ )
}

So the card shows the empty "add documents" state even though highlights exist. The pagination row is only rendered in the populated branch, so there is no visible control to page back into range — the card stays stuck on the empty state until it remounts.

Repro

  1. Have at least 2 highlights so the pager shows.
  2. Page to the last highlight (activeIndex > 0).
  3. Let the brief refresh (or simulate it) with fewer highlights than the current activeIndex + 1.

Result on main: the card renders "Add some documents to see highlights here" despite having highlights, with no way to recover in-place. The same happens for any parent that swaps items for a shorter array while the user is on a later page.

Fix

Clamp activeIndex into range whenever items changes, next to the existing reset:

setActiveIndex((i) => Math.min(i, Math.max(items.length - 1, 0)))

This keeps the current position when it is still valid and only pulls it back when the list shrank. When items is genuinely empty it resolves to 0, and the existing items.length === 0 guard renders the empty state correctly.

Also removes a useExhaustiveDependencies suppression that is no longer needed: the effect body now reads items.length, so items is a real dependency rather than a suppressed one.

No test is included because apps/web has no component test harness set up; the change is a two-line clamp mirroring the same pattern used elsewhere for selection bounds. cc @MaheshtheDev @ishaanxgupta

The Daily Brief refreshes on its own every few hours, replacing the items
array, and the paging controls also let the user sit on a later index. When a
refresh returns fewer highlights than before, activeIndex was left pointing
past the end of the new list, so currentItem became undefined and the card
rendered the "Add some documents" empty state even though highlights existed,
with no pagination shown to recover from it.

Clamp activeIndex back into range whenever items changes, alongside the
existing reply/expansion reset. Also drops a now-unnecessary
useExhaustiveDependencies suppression, since the effect body now reads
items.length so items is a real dependency.
Copilot AI review requested due to automatic review settings July 22, 2026 11:29

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants