Skip to content

fix: offline fallback for analysis dashboard scan result#107

Open
vaishnavidesai09 wants to merge 1 commit into
jpdevhub:mainfrom
vaishnavidesai09:fix/offline-analysis-dashboard
Open

fix: offline fallback for analysis dashboard scan result#107
vaishnavidesai09 wants to merge 1 commit into
jpdevhub:mainfrom
vaishnavidesai09:fix/offline-analysis-dashboard

Conversation

@vaishnavidesai09

@vaishnavidesai09 vaishnavidesai09 commented Jun 14, 2026

Copy link
Copy Markdown

Description

This PR fixes an issue where the Analysis Dashboard would show an empty or error state when a scan was performed in offline mode.

Previously, the dashboard depended entirely on the backend API response. When the backend was unavailable (offline mode), the scan data could not be fetched, resulting in a blank or broken UI.

This update introduces a fallback mechanism using sessionStorage to ensure offline scan results are still rendered correctly.

Closes #100


Fix

Added offline fallback for analysis dashboard when backend is unavailable.


Changes

  • Store edge inference result in sessionStorage (offlineScanResult) before navigating to analysis page
  • Dashboard fetches scan data from API first (normal flow)
  • On API failure, falls back to sessionStorage data
  • Prevents empty dashboard state during offline mode
  • Improves reliability of offline scan workflow

Tested

  • Offline scan flow works correctly
  • sessionStorage contains valid offlineScanResult
  • Analysis Dashboard renders correctly in offline mode
  • Backend unavailable scenario handled gracefully
  • No blank or crash screen observed

Notes

  • Docker backend remains unchanged and is used when available
  • A toast notification may still appear once during network failure (non-blocking UX issue)
  • Offline UX is now stable and functional

Checklist

  • npm run lint passes with no errors
  • npm run build compiles without TypeScript errors
  • python -m pytest passes (not applicable / frontend-only change)
  • No .env files, API keys, secrets, model weights, or __pycache__ in this diff
  • Branch is rebased on main, not merged
Screenshot from 2026-06-14 17-03-46

Summary by CodeRabbit

  • New Features
    • Added offline scan result caching to maintain app functionality without internet connectivity.
    • Improved error handling with offline fallback—the app now attempts to load stored scan data when network requests fail.

@vercel

vercel Bot commented Jun 14, 2026

Copy link
Copy Markdown

@vaishnavidesai09 is attempting to deploy a commit to the karan3431's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

.coderabbit.yaml has a parsing error

The CodeRabbit configuration file in this repository has a parsing error and default settings were used instead. Please fix the error(s) in the configuration file. You can initialize chat with CodeRabbit to get help with the configuration file.

💥 Parsing errors (1)
Validation error: Invalid input: expected object, received boolean at "reviews.auto_review"
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json
📝 Walkthrough

Walkthrough

ScannerPage's ONNX offline inference path now constructs a structured scan result object and saves it to sessionStorage as offlineScanResult. AnalysisDashboard's load effect now catches fetch failures, reads that sessionStorage entry, and uses it to populate the scan state if freshness_index is present; otherwise it sets an error message. Loading state is finalized in a finally block.

Changes

Offline Scan Fallback Flow

Layer / File(s) Summary
ONNX result serialized to sessionStorage in ScannerPage
src/pages/ScannerPage.tsx
After ONNX fusion inference, constructs a complete offlineScanResult object (grade derivation, confidence parsing, classification mapping, placeholder species/biomarkers/recommendations) and writes it to sessionStorage under "offlineScanResult". On-screen rendering continues to use fusion outputs directly.
AnalysisDashboard offline fallback on fetch failure
src/pages/AnalysisDashboard.tsx
load() resets error state and uses double-quoted keys to read id and lastScanId. On API failure, reads and JSON-parses offlineScanResult from sessionStorage; if freshness_index is present, populates scan state silently. Otherwise sets error from the thrown value. loading is always cleared in finally.

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant ScannerPage
  participant ONNX as ONNX Runtime
  participant sessionStorage
  participant AnalysisDashboard
  participant api as API Server

  User->>ScannerPage: initiate scan (offline)
  ScannerPage->>ONNX: run edge inference
  ONNX-->>ScannerPage: fusion outputs (label, freshness, confidence)
  ScannerPage->>ScannerPage: build offlineScanResult object
  ScannerPage->>sessionStorage: setItem("offlineScanResult", JSON)
  ScannerPage->>AnalysisDashboard: navigate to /analysis

  AnalysisDashboard->>api: getScan(scanId)
  api-->>AnalysisDashboard: network error (offline)
  AnalysisDashboard->>sessionStorage: getItem("offlineScanResult")
  sessionStorage-->>AnalysisDashboard: parsed offline result
  AnalysisDashboard->>AnalysisDashboard: setScan(offlineResult), setLoading(false)
  AnalysisDashboard-->>User: render analysis from offline data
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • jpdevhub/FreshScanAi#97: Both PRs modify the same offline/ONNX inference path inside ScannerPage's runScan function; that PR updated the background api.submitScan call in the same code block this PR now extends.

Suggested labels

SSoC26, Hard, size/level: hard

Poem

🐇 Hoppity-hop through the offline fog,
No server? No worry — check the sessionStorage log!
The scanner writes freshness, the dashboard reads back,
A fallback so nimble, nothing goes black.
Even without Wi-Fi, the scan still shows,
🥦 Fresh data delivered wherever the bunny goes!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: implementing an offline fallback mechanism for the analysis dashboard when scan results cannot be fetched from the API.
Linked Issues check ✅ Passed All coding requirements from issue #100 are implemented: ScannerPage saves edge inference results to sessionStorage under offlineScanResult, and AnalysisDashboard attempts API fetch first then falls back to sessionStorage on failure.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the offline fallback mechanism specified in issue #100; no unrelated modifications are present in the changeset.

✏️ 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.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🤖 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 `@src/pages/AnalysisDashboard.tsx`:
- Around line 35-37: The fallback data validation needs to ensure that cached
offline scan results are only used when they match the requested ID. In the
AnalysisDashboard component where targetId is determined from idParam or lastId,
add validation logic to check that any offlineScanResult being used has a
scan_id that matches the targetId. Specifically, when an explicit id parameter
is provided (idParam is not null), only use the cached offlineScanResult if its
scan_id matches idParam, otherwise discard it. This validation should be applied
at the point where offlineScanResult is accessed and used (lines 45-55) to
prevent displaying unrelated scan data from the cache when a specific scan ID is
explicitly requested.

In `@src/pages/ScannerPage.tsx`:
- Around line 302-305: The sessionStorage.setItem call for persisting
offlineScanResult is not handling potential failures, which causes the entire
offline inference operation to abort if the write fails. Wrap the
sessionStorage.setItem call in a try-catch block so that if the persistence
fails (due to quota exceeded or other reasons), the error is caught and logged
without interrupting the successful offline inference flow.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a6f7747c-96d9-495f-9876-96bd441b7ac3

📥 Commits

Reviewing files that changed from the base of the PR and between b748bcf and e63c781.

📒 Files selected for processing (2)
  • src/pages/AnalysisDashboard.tsx
  • src/pages/ScannerPage.tsx

Comment on lines +35 to 37
const idParam = params.get("id");
const lastId = sessionStorage.getItem("lastScanId");
const targetId = idParam || lastId;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard fallback data against request-ID mismatch.

When id is explicitly requested, catch-path fallback currently accepts any cached offlineScanResult, which can show unrelated scan data.

Use fallback only when no explicit id exists, or when cached scan_id matches the requested ID.

Suggested patch
-      try {
-        const idParam = params.get("id");
-        const lastId = sessionStorage.getItem("lastScanId");
-        const targetId = idParam || lastId;
+      const idParam = params.get("id");
+      const lastId = sessionStorage.getItem("lastScanId");
+      const targetId = idParam || lastId;
+      try {
@@
-        if (offlineData) {
+        if (offlineData) {
           try {
             const parsed = JSON.parse(offlineData);
-
-            if (parsed?.freshness_index != null) {
+            const matchesRequestedId =
+              !idParam || parsed?.scan_id === idParam;
+            if (parsed?.freshness_index != null && matchesRequestedId) {
               setScan(parsed);
               setLoading(false); 
               return;
             }
           } catch (e) {

Also applies to: 45-55

🤖 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 `@src/pages/AnalysisDashboard.tsx` around lines 35 - 37, The fallback data
validation needs to ensure that cached offline scan results are only used when
they match the requested ID. In the AnalysisDashboard component where targetId
is determined from idParam or lastId, add validation logic to check that any
offlineScanResult being used has a scan_id that matches the targetId.
Specifically, when an explicit id parameter is provided (idParam is not null),
only use the cached offlineScanResult if its scan_id matches idParam, otherwise
discard it. This validation should be applied at the point where
offlineScanResult is accessed and used (lines 45-55) to prevent displaying
unrelated scan data from the cache when a specific scan ID is explicitly
requested.

Comment thread src/pages/ScannerPage.tsx
Comment on lines +302 to +305
sessionStorage.setItem(
"offlineScanResult",
JSON.stringify(offlineScanResult),
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Make offlineScanResult persistence non-fatal.

A sessionStorage.setItem(...) failure here aborts the successful offline inference path and sends users to error state. The cache write should be best-effort only.

Suggested patch
-        sessionStorage.setItem(
-          "offlineScanResult",
-          JSON.stringify(offlineScanResult),
-        );
+        try {
+          sessionStorage.setItem(
+            "offlineScanResult",
+            JSON.stringify(offlineScanResult),
+          );
+        } catch (storageErr) {
+          console.warn("Failed to persist offline scan result", storageErr);
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
sessionStorage.setItem(
"offlineScanResult",
JSON.stringify(offlineScanResult),
);
try {
sessionStorage.setItem(
"offlineScanResult",
JSON.stringify(offlineScanResult),
);
} catch (storageErr) {
console.warn("Failed to persist offline scan result", storageErr);
}
🤖 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 `@src/pages/ScannerPage.tsx` around lines 302 - 305, The sessionStorage.setItem
call for persisting offlineScanResult is not handling potential failures, which
causes the entire offline inference operation to abort if the write fails. Wrap
the sessionStorage.setItem call in a try-catch block so that if the persistence
fails (due to quota exceeded or other reasons), the error is caught and logged
without interrupting the successful offline inference flow.

@vaishnavidesai09

Copy link
Copy Markdown
Author

Thanks @jpdevhub for the opportunity to work on this issue!

This PR fixes the offline analysis dashboard issue where scan results were not displayed when the backend is unavailable.

What changed

  • Added sessionStorage fallback (offlineScanResult) for offline scan results
  • Analysis Dashboard now:
    • Tries API fetch first (normal flow)
    • Falls back to sessionStorage on failure (offline mode)
  • Ensures no blank/error dashboard when backend is unreachable

Why this approach

sessionStorage was used to persist edge inference results across route navigation (/scanner → /analysis) without relying on backend availability. This ensures a smooth offline-first experience while keeping online behavior unchanged.

Safety

  • All sessionStorage parsing is wrapped in try/catch to prevent crashes
  • If fallback data is invalid or missing, UI safely shows the existing error state
  • No changes affect the online API flow or backend logic

Tested

  • Offline scan flow works correctly
  • sessionStorage stores valid scan data
  • Dashboard renders properly in offline mode
  • Backend-offline scenario handled without blank screen

Let me know if any changes or improvements are needed. Happy to iterate 👍

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Empty Analysis Dashboard when scanning in Offline Mode

1 participant