Skip to content

Add error handling and retry to lookahead dashboard#51

Merged
Ross1116 merged 4 commits into
mainfrom
staging
Mar 28, 2026
Merged

Add error handling and retry to lookahead dashboard#51
Ross1116 merged 4 commits into
mainfrom
staging

Conversation

@Ross1116

@Ross1116 Ross1116 commented Mar 28, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Retry CTAs and richer empty-state titles/messages for load errors
    • Search, pagination, and card-style review UI with per-item action panels and inline error feedback
    • Snapshot history can reflect and highlight the current snapshot’s row counts
  • Bug Fixes

    • Improved error handling and clearer load-failure messaging across forecast/diagnostics
    • More robust row-count derivation from diverse history payloads
  • Tests

    • Added test to preserve summarized snapshot row counts

@vercel

vercel Bot commented Mar 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
sitespace-app Ready Ready Preview, Comment Mar 28, 2026 3:17am

@coderabbitai

coderabbitai Bot commented Mar 28, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b683a915-9d59-4d60-aaf9-8193e9130341

📥 Commits

Reviewing files that changed from the base of the PR and between ee09d15 and 8ad233b.

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

📝 Walkthrough

Walkthrough

Adds a load-error empty state and retry CTA, surfaces/structures snapshot and diagnostics API errors, preserves and surfaces snapshot row_count in history, and refactors the upload review dialog with search, pagination, and per-row correction action handling.

Changes

Cohort / File(s) Summary
Empty / Error UI
src/components/lookahead/EmptyForecastState.tsx
Adds load-error reason and optional title/message/actionLabel/onAction props, replaces hardcoded copy with STATE_COPY, picks icon dynamically, and conditionally renders CTA button.
Dashboard & Error Handling
src/components/lookahead/LookaheadDashboard.tsx
Adds axios-aware error-message builders, consumes snapshotError/alertsError, derives forecastLoadState/diagnosticsLoadMessage, switches empty-state to load-error with retry CTA, appends synthetic diagnostics alert with retry, and defers some UI until mount.
History API & Types
src/hooks/lookahead/api.ts, src/hooks/lookahead/api.test.ts, src/types/index.ts
Introduces fetchLookaheadHistory mapping to compute row_count (prioritized fields -> fallback to rows length when rows array present), adds `row_count?: number
Snapshot History UI
src/components/lookahead/SnapshotHistoryPanel.tsx
Accepts optional currentSnapshot prop, computes currentSnapshotRowCount, and changes row-count badge precedence to entry.row_countentry.rows.length → matched currentSnapshotRowCount → "Row count unavailable".
Upload Review Dialog (UI + Logic)
src/components/lookahead/UploadReviewDialog.tsx
Large refactor: adds deferred search, pagination, visibleRows list, per-row busy maps and centralized handlers, expanded dropdown/options merging drafts, inline per-row error handling, and updated empty/loading variants.

Sequence Diagram

sequenceDiagram
    participant User
    participant Dashboard as LookaheadDashboard
    participant Hooks as Lookahead Hooks
    participant API as Server
    participant Empty as EmptyForecastState
    participant History as SnapshotHistoryPanel

    User->>Dashboard: mount / interact
    Dashboard->>Hooks: fetch snapshot & diagnostics
    Hooks->>API: GET /snapshot, GET /diagnostics
    API-->>Hooks: response (data or error)
    Hooks-->>Dashboard: data or snapshotError / alertsError
    alt snapshotError blocking
        Dashboard->>Empty: render reason="load-error" with title/message and Retry CTA
        User->>Empty: clicks Retry
        Empty->>Dashboard: onAction -> refreshLookaheadWorkspace()
        Dashboard->>Hooks: retry fetch / mutate
    else snapshot ok, alertsError present
        Dashboard->>Dashboard: append synthetic diagnostics alert with Retry CTA -> mutateAlerts()
    end
    Dashboard->>History: pass currentSnapshot
    History-->>User: render history rows with prioritized row_count badge
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped through code with careful paws,
Errors now speak, clear and without pause.
Retry buttons twinkle, row counts hold true,
Pages and searches show the view anew.
A carrot nibble — fresh features, woohoo!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed Title check skipped as CodeRabbit has written the PR title.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch staging

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 changed the title @coderabbitai Add error handling and retry to lookahead dashboard Mar 28, 2026

@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 the current code and only fix it if needed.

Inline comments:
In `@src/components/lookahead/LookaheadDashboard.tsx`:
- Around line 700-711: The workspace blocking logic should check for a blocking
snapshot error (snapshotError && !heatmap) instead of snapshotError alone;
create a derived boolean (e.g., hasBlockingSnapshotError = Boolean(snapshotError
&& !heatmap)) and use it in the diagnostics suppression branches that push the
diagnostics_unavailable alert (where alertsError and diagnosticsLoadMessage are
checked), the hero copy logic, and the load-error empty state; update the
condition that currently reads if (alertsError && !snapshotError &&
diagnosticsLoadMessage) to if (alertsError && !hasBlockingSnapshotError &&
diagnosticsLoadMessage) and replace other usages of snapshotError in the same
contexts (see uses around nextAlerts push, the hero copy branch, and the
load-error state) to ensure cached snapshot heatmap data is not incorrectly
blocked, keeping mutateAlerts and diagnosticsLoadMessage behavior unchanged.

In `@src/hooks/lookahead/api.ts`:
- Around line 224-230: The rowCount calculation currently uses rows.length first
and the || operator which causes authoritative numeric counts (including 0) in
entry.row_count (or other count fields) to be ignored or collapsed to null;
update the logic in the rowCount assignment to prefer numeric counts returned by
asNumber(entry.row_count), asNumber(entry.rows_count),
asNumber(entry.snapshot_row_count), asNumber(entry.count) using nullish
coalescing (or explicit undefined checks) so 0 is preserved, and only fall back
to rows?.length (via rows.length or asNumber on rows.length) as the last option,
referencing the rowCount variable and the asNumber helper to locate and change
the expression.
🪄 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

Run ID: 58e0ad71-4fa1-4206-81cf-7ea6528659c6

📥 Commits

Reviewing files that changed from the base of the PR and between fa8f469 and dbb89be.

📒 Files selected for processing (6)
  • src/components/lookahead/EmptyForecastState.tsx
  • src/components/lookahead/LookaheadDashboard.tsx
  • src/components/lookahead/SnapshotHistoryPanel.tsx
  • src/hooks/lookahead/api.test.ts
  • src/hooks/lookahead/api.ts
  • src/types/index.ts

Comment thread src/components/lookahead/LookaheadDashboard.tsx Outdated
Comment thread src/hooks/lookahead/api.ts Outdated

@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

🧹 Nitpick comments (2)
src/components/lookahead/LookaheadDashboard.tsx (1)

154-207: Well-structured error message helpers with HTTP-aware logic.

The functions correctly handle various error scenarios (5xx, 404, offset-naive timezone issues). A few observations:

  1. Line 201: The hardcoded "Something went wrong" string comparison could be brittle if getApiErrorMessage changes its default fallback.
  2. Line 188: The conditional rawMessage === fallback ? fallback : ... appears redundant since both branches produce similar output.
♻️ Consider extracting the magic string
+const GENERIC_ERROR_FALLBACK = "Something went wrong";
+
 function getDiagnosticsLoadMessage(error: unknown): string {
   const fallback =
     "Planning diagnostics could not be refreshed right now. You can still use the heatmap, but alert badges may be stale until the next retry.";
   const rawMessage = getApiErrorMessage(error, fallback).trim();

   if (
     /offset-naive|offset-aware/i.test(rawMessage) ||
     (isAxiosError(error) && (error.response?.status ?? 0) >= 500) ||
     /status code 5\d\d/i.test(rawMessage) ||
-    rawMessage === "Something went wrong"
+    rawMessage === GENERIC_ERROR_FALLBACK
   ) {
     return fallback;
   }

   return rawMessage;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/lookahead/LookaheadDashboard.tsx` around lines 154 - 207, Both
helpers should avoid the brittle hardcoded "Something went wrong" and simplify
the fallback logic: extract a shared constant (e.g., DEFAULT_API_FALLBACK or
DEFAULT_ERROR_MSG) and use that constant as the fallback argument to
getApiErrorMessage and for comparisons in getDiagnosticsLoadMessage (replace
rawMessage === "Something went wrong" with rawMessage === DEFAULT_ERROR_MSG or
startsWith check). In getForecastLoadMessage simplify the final return by
consistently building the message from the fallback and rawMessage but prevent
duplication by checking rawMessage === fallback (or
rawMessage.startsWith(fallback)) before concatenating; refer to the functions
getForecastLoadMessage and getDiagnosticsLoadMessage and the local variables
fallback and rawMessage to locate the changes.
src/components/lookahead/UploadReviewDialog.tsx (1)

427-451: Consider extracting duplicated pagination controls

Top and bottom pagination blocks duplicate behavior/UI. Extracting a small PaginationControls subcomponent would reduce drift risk when logic changes.

Also applies to: 690-723

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/lookahead/UploadReviewDialog.tsx` around lines 427 - 451,
Extract the duplicated pagination UI into a new presentational component (e.g.,
PaginationControls) that accepts props {page, totalPages, setPage} and renders
the two Buttons and the page/totalPages span using the existing handlers
(onClick setPage((p)=>Math.max(1,p-1)) and
setPage((p)=>Math.min(totalPages,p+1))) and icons (ChevronLeft, ChevronRight);
replace both occurrences in UploadReviewDialog with this new component to
centralize behavior and prevent drift while preserving the existing disabled
logic (disabled={page <= 1} and disabled={page >= totalPages}).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/lookahead/UploadReviewDialog.tsx`:
- Around line 185-187: busyId/memoryBusyId currently store a single inflight id
which lets overlapping actions overwrite each other and re-enable rows
prematurely; change these to per-row inflight tracking (e.g.,
useState<Record<string, boolean>> or a Ref holding a Set) and update usages in
the UploadReviewDialog handlers (replace setBusyId/setMemoryBusyId calls with
keyed updates and check the per-row map/set before allowing an action), and
update actionErrors to be maintained per-row consistently so each row's
busy/error state is isolated (apply the same pattern where busyId/memoryBusyId
are read/checked and cleared).
- Around line 428-450: The icon-only pagination Buttons around ChevronLeft and
ChevronRight lack accessible names; add descriptive accessible labels (e.g.,
aria-label="Previous page" and aria-label="Next page" or aria-labelledby
pointing to a visually-hidden label) on the Button components that invoke
setPage so screen readers announce their purpose; update the two Button elements
that call setPage((p) => Math.max(1, p - 1)) and setPage((p) =>
Math.min(totalPages, p + 1)) (the ones rendering ChevronLeft and ChevronRight)
to include those aria attributes and ensure any visually-hidden text IDs
referenced are unique and present.

---

Nitpick comments:
In `@src/components/lookahead/LookaheadDashboard.tsx`:
- Around line 154-207: Both helpers should avoid the brittle hardcoded
"Something went wrong" and simplify the fallback logic: extract a shared
constant (e.g., DEFAULT_API_FALLBACK or DEFAULT_ERROR_MSG) and use that constant
as the fallback argument to getApiErrorMessage and for comparisons in
getDiagnosticsLoadMessage (replace rawMessage === "Something went wrong" with
rawMessage === DEFAULT_ERROR_MSG or startsWith check). In getForecastLoadMessage
simplify the final return by consistently building the message from the fallback
and rawMessage but prevent duplication by checking rawMessage === fallback (or
rawMessage.startsWith(fallback)) before concatenating; refer to the functions
getForecastLoadMessage and getDiagnosticsLoadMessage and the local variables
fallback and rawMessage to locate the changes.

In `@src/components/lookahead/UploadReviewDialog.tsx`:
- Around line 427-451: Extract the duplicated pagination UI into a new
presentational component (e.g., PaginationControls) that accepts props {page,
totalPages, setPage} and renders the two Buttons and the page/totalPages span
using the existing handlers (onClick setPage((p)=>Math.max(1,p-1)) and
setPage((p)=>Math.min(totalPages,p+1))) and icons (ChevronLeft, ChevronRight);
replace both occurrences in UploadReviewDialog with this new component to
centralize behavior and prevent drift while preserving the existing disabled
logic (disabled={page <= 1} and disabled={page >= totalPages}).
🪄 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

Run ID: 35ebbfa0-95c5-4dbe-9f5b-dd57eefabf00

📥 Commits

Reviewing files that changed from the base of the PR and between dbb89be and 65b9e14.

📒 Files selected for processing (3)
  • src/components/lookahead/LookaheadDashboard.tsx
  • src/components/lookahead/UploadReviewDialog.tsx
  • src/hooks/lookahead/api.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/hooks/lookahead/api.ts

Comment thread src/components/lookahead/UploadReviewDialog.tsx Outdated
Comment thread src/components/lookahead/UploadReviewDialog.tsx Outdated

@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: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/lookahead/UploadReviewDialog.tsx`:
- Around line 450-455: The Input components (e.g., the search box using
value={searchTerm} onChange={setSearchTerm} and the custom asset-type Input
fields referenced elsewhere) currently only use placeholders and need
programmatic labels for accessibility; add either an explicit aria-label prop or
associate an HTML label with an id/htmlFor for each Input (give the search Input
a descriptive label like "Search activities, locations, or types" and similarly
label each custom asset-type field) so assistive technologies can identify them.
- Around line 285-301: The page value can be stale during render and causes
empty/incorrect UI; clamp the derived page before using it for slicing and range
calculations by computing a local clampedPage = Math.max(1, Math.min(page,
totalPages)) (use the existing totalPages logic) and replace uses of page inside
the visibleRows useMemo (start calculation and slice), and the
rangeStart/rangeEnd calculations with clampedPage; leave the existing effect
that updates state but ensure all render-time computations reference clampedPage
(also apply same change to the other occurrences around
visibleRows/rangeStart/rangeEnd).
- Around line 264-279: The search filter in filteredRows currently compares raw
snake_case values (e.g., asset_type) against the query, so queries like "scissor
lift" won't match "scissor_lift"; update the filter inside the useMemo to
normalize asset_type to the same displayed label before matching (e.g., replace
underscores with spaces and toLowerCase(), or map asset_type to its display
string) and use that normalized string in the array passed to .some; keep the
rest of the fields (activity_name, source_value, etc.) unchanged and ensure the
normalization is applied to suggested_classification/current_classification if
they also render with spaces.
🪄 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

Run ID: 5cd99d49-957e-46a8-943a-6e591840dd40

📥 Commits

Reviewing files that changed from the base of the PR and between 65b9e14 and ee09d15.

📒 Files selected for processing (2)
  • src/components/lookahead/LookaheadDashboard.tsx
  • src/components/lookahead/UploadReviewDialog.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/lookahead/LookaheadDashboard.tsx

Comment thread src/components/lookahead/UploadReviewDialog.tsx
Comment thread src/components/lookahead/UploadReviewDialog.tsx Outdated
Comment thread src/components/lookahead/UploadReviewDialog.tsx
@Ross1116

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Mar 28, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@Ross1116 Ross1116 merged commit 78ea4f4 into main Mar 28, 2026
3 checks passed
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.

1 participant