fix(scan): recent-scan strip survives page navigation - #17
Conversation
The recents strip lived in component-local state on the Scan page, so navigating to any other tab disposed the component and wiped everything but the latest scan (re-seeded from MenuVM on return). The strip now derives from the DI-singleton SessionHistoryService (the same store backing the History page), which already records every scan for the session. Selecting a recent entry reuses the stored historical view model directly. Fixes #12
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 13 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (2)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
This comment was marked as resolved.
This comment was marked as resolved.
| private void SelectRecent(ScanResultViewModel scan) | ||
| { | ||
| _result = ScanResultAdapter.Map(scan, MenuVM, true); | ||
| _result = scan; | ||
| _detailsOpen = false; | ||
| _copiedId = false; | ||
| } |
There was a problem hiding this comment.
📝 Info: SelectRecent now shows a snapshot rather than freshly re-mapped data
Previously SelectRecent re-mapped from the live ItemScan via ScanResultAdapter.Map(scan, MenuVM, true), recomputing quest/hideout requirements and pricing against the current MenuVM/TarkovTracker state at click time. Now it reuses the ScanResultViewModel snapshot captured at scan time by SessionHistoryService.Record (src/App/Presentation/SessionHistoryService.cs:43-54). If quest/hideout progress or prices change during a session, clicking a recent thumbnail will show stale requirement/price data. This is consistent with the History page behavior and appears intended per the PR description, so it is not flagged as a bug, but reviewers should confirm the desired semantics.
Was this helpful? React with 👍 or 👎 to provide feedback.
| // The recent-scans strip derives from the DI-singleton SessionHistoryService | ||
| // instead of component-local state, so navigating away from the Scan page | ||
| // and back no longer wipes it (issue #12). | ||
| private IReadOnlyList<ScanResultViewModel> RecentScans => History.Items.Take(RecentLimit).ToArray(); |
There was a problem hiding this comment.
📝 Info: RecentScans property takes two independent snapshots per render
RecentScans (src/App/Pages/App/Index.razor:437) locks and copies History.Items each time it is evaluated. In the markup it is evaluated separately in @if (RecentScans.Count > 0) and @foreach (... in RecentScans), so two independent snapshots are taken per render. A concurrent scan landing between the two evaluations could theoretically produce a brief inconsistency (Count > 0 but different content), though it is harmless in practice. Minor allocation/locking overhead only.
Was this helpful? React with 👍 or 👎 to provide feedback.
This comment was marked as resolved.
This comment was marked as resolved.
There was a problem hiding this comment.
DysektAI has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
There was a problem hiding this comment.
DysektAI has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
There was a problem hiding this comment.
DysektAI has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
Root cause
Index.razorkept the recents list (_recent) as component-local state. Navigating to History/Settings/Credits disposes the Scan page component; on return, the list was re-seeded fromMenuVM.LastItemScanonly — so users saw just the latest scan (#12).Fix
The strip now derives from
SessionHistoryService— a DI singleton that already records every scan for the session (and backs the History page). No state lives in the component anymore:RecentScans= first 5 entries ofHistory.ItemsSelectRecentreuses the stored historicalScanResultViewModeldirectly (same dataScanResultAdapter.Map(..., isHistorical: true)produced before)History.Changedfor re-render, unsubscribes inDisposeValidation
Fixes #12
Summary by cubic
Persist the Recent Scans strip across navigation by sourcing it from
SessionHistoryServiceinstead of component-local state. Shows the first 5 session scans; selecting a recent uses the storedScanResultViewModel.RecentScansfromHistory.Itemsand snapshot per render to avoid double evaluation and extra allocations.History.Changedfor re-render; unsubscribed inDispose.AddRecent;SelectRecentassigns the historical view model; thumbnails useItem.ImageUrl.Written for commit 3e11aad. Summary will update on new commits.
Greptile Summary
Fixes the recent-scan strip being wiped on page navigation (#12) by sourcing it from the
SessionHistoryServicesingleton instead of component-local state. The component now subscribes toHistory.Changedfor re-renders and unsubscribes inDispose.RecentScanscomputes the first 5 entries fromHistory.Items;SelectRecentassigns the storedScanResultViewModeldirectly instead of re-mapping viaScanResultAdapter, so clicked recents now reflect scan-time pricing (matching History page behavior).AddRecentand the_recentfield are removed; lifecycle wiring is moved toOnInitialized/Disposewith correct event unsubscription.Confidence Score: 4/5
Safe to merge. The change is a focused, single-file fix with no new dependencies; event subscription and disposal are wired correctly.
The fix is straightforward and correctly solves the stated problem. The only finding is that
RecentScansis evaluated twice per render, causing two lock acquisitions and four allocations per cycle — a minor inefficiency with no behavioural impact given that history grows monotonically within a session.Files Needing Attention: No files require special attention; the single changed file is self-contained.
Important Files Changed
Sequence Diagram
sequenceDiagram participant ScanThread as Scan Thread participant History as SessionHistoryService participant Index as Index.razor participant Renderer as Blazor Renderer ScanThread->>History: ItemQueue.Changed fires History->>History: Record(ScanResultViewModel) History-->>Index: History.Changed event Index->>Renderer: InvokeAsync(StateHasChanged) Renderer->>Index: Re-render Index->>History: RecentScans → History.Items.Take(5) History-->>Index: "IReadOnlyList<ScanResultViewModel>" Index->>Renderer: Display recent strip note over Index: User navigates away Index->>Index: Dispose() — unsubscribe History.Changed note over History: Items survive (singleton) note over Index: User navigates back Index->>History: OnInitialized — subscribe History.Changed Index->>History: RecentScans → History.Items.Take(5) History-->>Index: All session scans still presentComments Outside Diff (1)
src/App/Pages/App/Index.razor, line 48-62 (link)RecentScansproperty evaluated twice per renderRecentScansis a computed property backed byHistory.Items, which internally acquires a lock and allocates a full copy of the history list (up to 50 entries) before.Take(5).ToArray()produces a second allocation. The Razor template evaluates the property twice per render cycle — once for the.Count > 0guard and again for the@foreach— resulting in two lock acquisitions and four heap allocations. Snapshotting the result into a cached field (refreshed inOnHistoryChangedandOnInitialized) would eliminate the redundancy and also guarantee theif-guard and theforeachsee the same snapshot.Prompt To Fix With AI
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Prompt To Fix All With AI
Reviews (1): Last reviewed commit: "fix(scan): keep recent-scan strip across..." | Re-trigger Greptile