Skip to content

fix(person-images): prevent flash of previous page's images (#1315)#1321

Open
tanmaysachann wants to merge 2 commits into
AOSSIE-Org:mainfrom
tanmaysachann:fix/1315-ai-tagging-page-flash
Open

fix(person-images): prevent flash of previous page's images (#1315)#1321
tanmaysachann wants to merge 2 commits into
AOSSIE-Org:mainfrom
tanmaysachann:fix/1315-ai-tagging-page-flash

Conversation

@tanmaysachann

@tanmaysachann tanmaysachann commented Jun 13, 2026

Copy link
Copy Markdown

When a face cluster is opened from the Navbar search panel, PersonImages briefly rendered the previous page's images before the person's photos loaded, producing the flash described in the issue. This PR scopes the grid to the active cluster so the stale images can never paint.

Root cause: the original "redirect to /ai-tagging" hypothesis did not match the code; PersonImages has no such redirect (it only navigates on the user-clicked "Back to AI Tagging" button). The real cause is the shared images Redux slice: the grid renders from selectImages, which still holds whatever the previous page left there until fetchClusterImages resolves and setImages runs. For the first frame(s) that stale set is on screen. Thanks to @VanshajPoonia for independently confirming this and flagging the cached-navigation case.

The fix (scoped to PersonImages.tsx):

  • Track which cluster the shared slice holds via a loadedClusterId marker, set alongside setImages when the query succeeds.
  • Once the slice is in sync for the active clusterId, read the slice (so the optimistic favourite toggle keeps working); during the brief window before it syncs, fall back to the ['person-images', clusterId] React Query data, which is already scoped to the active id and can only ever be the correct person's photos.
  • Point the grid and media viewer at this derived list instead of the raw slice.

This does not rely on a loading flag, so it also covers person A to person B when B is already cached (isLoading is false immediately while the slice still holds A for a tick), which was @VanshajPoonia's review point.

Addressed Issues:

Fixes #1315

Screenshots/Recordings:

This is a sub-frame rendering flash, so it is covered by an automated regression test rather than a recording. PersonImages.test.tsx pre-seeds the shared slice with a previous page's images, navigates to a different cluster, and asserts the previous images never paint (on the first frame and after the query resolves). The test fails against the pre-fix code and passes with the fix.

Additional Notes:

Reading the slice once synced (rather than reading query data everywhere) is deliberate: the favourite/heart toggle updates the slice, and its ['images'] cache invalidation does not match the ['person-images', id] key, so reading query data everywhere would fix the flash but stop the heart icon from updating. The hybrid keeps both correct. Scope is limited to PersonImages.tsx and its test. Verified locally: full frontend suite (133 tests), tsc, and ESLint all pass.

AI Usage Disclosure:

We encourage contributors to use AI tools responsibly when creating Pull Requests. While AI can be a valuable aid, it is essential to ensure that your contributions meet the task requirements, build successfully, include relevant tests, and pass all linters. Submissions that do not meet these standards may be closed without warning to maintain the quality and integrity of the project. Please take the time to understand the changes you are proposing and their impact. AI slop is strongly discouraged and may lead to banning and blocking. Do not spam our repos with AI slop.

Check one of the checkboxes below:

  • This PR does not contain AI-generated code at all.
  • This PR contains AI-generated code. I have read the AI Usage Policy and this PR complies with this policy. I
    have tested the code locally and I am responsible for it.

I have used the following AI models and tools: Claude Code (Anthropic Claude). I used it to investigate the root cause, draft the fix in PersonImages.tsx, and write the regression test. I reviewed every line, verified the diagnosis against the code myself, and confirmed the full frontend test suite, tsc, and ESLint pass locally before submitting.

Checklist

  • My PR addresses a single issue, fixes a single bug or makes a single improvement.
  • My code follows the project's code style and conventions
  • If applicable, I have made corresponding changes or additions to the documentation
  • If applicable, I have made corresponding changes or additions to tests
  • My changes generate no new warnings or errors
  • I have joined the Discord server and I will share a link to this PR with
    the project maintainers there
  • I have read the Contribution Guidelines
  • Once I submit my PR, CodeRabbit AI will automatically review it and I will address CodeRabbit's comments.
  • I have filled this PR template completely and carefully, and I understand that my PR may be closed without
    review otherwise.

Summary by CodeRabbit

  • Bug Fixes
    • Prevented stale images from briefly appearing when navigating between clusters—only images for the current cluster are shown during loading and after transition.
  • Tests
    • Added tests to ensure previous-cluster images never flash during navigation and that the navigated cluster’s name and images render after loading.

…rg#1315)

Scope the grid to the active cluster so the shared `images` slice left by the
previous page can no longer paint before the person's photos load. Track which
cluster the slice holds via `loadedClusterId`; until it syncs, render from the
`['person-images', clusterId]` query data, which is always scoped to the active
id. Reading the slice once synced keeps the optimistic favourite toggle working.

Adds a regression test that fails when the previous page's images render.
@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2ef68798-acb9-4923-9fb1-20d94c216c94

📥 Commits

Reviewing files that changed from the base of the PR and between c85b57f and 1eebcba.

📒 Files selected for processing (1)
  • frontend/src/pages/PersonImages/PersonImages.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/pages/PersonImages/PersonImages.tsx

Walkthrough

PersonImages now prevents stale image flash during cluster navigation by tracking which cluster's images are loaded in Redux via loadedClusterId, deriving the correct image source that falls back to query data until the slice syncs, and updating rendering to use derived personImages. Regression tests validate the fix prevents stale images during transitions.

Changes

Prevent stale images when navigating between person clusters

Layer / File(s) Summary
Track loaded cluster and derive current images
frontend/src/pages/PersonImages/PersonImages.tsx
loadedClusterId state records which cluster's images are in the Redux images slice. Derived personImages selects Redux images when loadedClusterId === clusterId, otherwise falls back to current query data.images to avoid stale contents during cluster transitions.
Update rendering to use derived images
frontend/src/pages/PersonImages/PersonImages.tsx
Image grid map and MediaView modal both switch from Redux images to personImages for rendering.
Regression tests for stale image flash
frontend/src/pages/__tests__/PersonImages.test.tsx
Full Jest/React Testing Library suite for issue #1315. Mocks Tauri and cluster image fetching, renders PersonImages with preloaded state seeded with "Person A" images, navigates to cluster "B", and validates that stale images do not render while new images appear correctly after async load.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

TypeScript/JavaScript

Suggested reviewers

  • rahulharpal1603

Poem

🐰 A hop, a gaze, no stale frame in sight,
Redux remembers which cluster's light,
Derived images hold the newest view,
No flashing ghosts — the pictures stay true,
I nibble bugs and cheer this code's delight.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and specifically describes the main change: preventing a visual flash of previous page images when navigating to PersonImages, directly matching the core fix in the changeset.
Linked Issues check ✅ Passed The PR successfully addresses issue #1315 by implementing a hybrid state-tracking approach (loadedClusterId) that prevents stale images from rendering, which is more robust than the originally hypothesized redirect guard fix.
Out of Scope Changes check ✅ Passed All code changes are directly scoped to fixing the image flash issue: PersonImages.tsx tracks loadedClusterId and uses fallback query data, while test file comprehensively covers the regression with appropriate mocks.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added bug Something isn't working frontend good first issue Good for newcomers labels Jun 13, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
frontend/src/pages/PersonImages/PersonImages.tsx (1)

64-65: 💤 Low value

Remove redundant assignment.

setClusterName(clusterName) sets the state to its current value, which is redundant.

♻️ Proposed simplification
   const handleEditName = () => {
-    setClusterName(clusterName);
     setIsEditing(true);
   };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/pages/PersonImages/PersonImages.tsx` around lines 64 - 65,
Remove the redundant state call setClusterName(clusterName) inside the handler
and only call setIsEditing(true); if the intent was to update the cluster name
to a different value, replace the current argument with the new value (e.g.,
setClusterName(newValue))—otherwise delete the setClusterName(clusterName) line
so only setIsEditing(true) remains.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/src/pages/PersonImages/PersonImages.tsx`:
- Around line 55-61: The code uses a triple-cast to any when reading images from
data; replace that with an explicit BackendRes<{ images: Image[] }> typed
access. Change the expression for personImages to use (data as BackendRes<{
images: Image[] }> | undefined)?.data?.images ?? [] so you avoid "any" and
preserve types for images, leaving loadedClusterId, clusterId and images logic
unchanged; add an import or reference to BackendRes and Image if not already
present.
- Line 50: The component is calling setLoadedClusterId with clusterId from
useParams which can be undefined; update the logic in PersonImages (where
clusterId and setLoadedClusterId are used) to guard against undefined by
returning early if clusterId is undefined (or at least do not call
setLoadedClusterId when clusterId is undefined) so the derived check that picks
between Redux images and query data doesn't mistakenly treat a stale
loadedClusterId; ensure the early-return or conditional prevents running the
downstream image-selection logic when clusterId is missing.

---

Nitpick comments:
In `@frontend/src/pages/PersonImages/PersonImages.tsx`:
- Around line 64-65: Remove the redundant state call setClusterName(clusterName)
inside the handler and only call setIsEditing(true); if the intent was to update
the cluster name to a different value, replace the current argument with the new
value (e.g., setClusterName(newValue))—otherwise delete the
setClusterName(clusterName) line so only setIsEditing(true) remains.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c6bba0b1-9ef7-4259-8319-f80129c377e5

📥 Commits

Reviewing files that changed from the base of the PR and between 0d0cbec and c85b57f.

📒 Files selected for processing (2)
  • frontend/src/pages/PersonImages/PersonImages.tsx
  • frontend/src/pages/__tests__/PersonImages.test.tsx

Comment thread frontend/src/pages/PersonImages/PersonImages.tsx
Comment thread frontend/src/pages/PersonImages/PersonImages.tsx Outdated
Addresses CodeRabbit review on the PR: only treat the slice as synced when
clusterId is defined, and type the query-data fallback explicitly instead of
casting through any.
@tanmaysachann

Copy link
Copy Markdown
Author

Re: the nitpick about the redundant setClusterName(clusterName) in handleEditName. This is pre-existing code that isn't part of the flash fix, so I've left it out to keep this PR scoped to #1315. Happy to remove it in a separate cleanup if preferred.

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.

Pull request overview

This PR fixes a UI flash in the PersonImages page where images from the previously visited page could briefly render while the target person’s cluster images are still loading (due to a shared images Redux slice being reused across pages).

Changes:

  • Track which clusterId the shared images slice currently represents (loadedClusterId) and only render from the slice once it matches the active route param.
  • While the slice is still “out of sync”, render images from the cluster-scoped React Query response (['person-images', clusterId]) to prevent stale images from ever painting.
  • Add a regression test that pre-seeds the shared slice with previous-page images and asserts they never appear when navigating to a different cluster.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
frontend/src/pages/PersonImages/PersonImages.tsx Adds cluster-scoping logic to prevent stale Redux-slice images from rendering during navigation/loading.
frontend/src/pages/__tests__/PersonImages.test.tsx Adds a regression test to ensure previous-page images never paint when opening a person cluster.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@@ -109,7 +123,7 @@ export const PersonImages = () => {
</div>
<h1 className="mb-6 text-2xl font-bold">{clusterName}</h1>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working frontend good first issue Good for newcomers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Brief Flash of AI Tagging Page When Navigating to a Person's Images from the Search Bar

2 participants