Skip to content

Image preview Gen UI #790

Open
Open

Description

@ngoiyaeric

The image preview generative user interface stopped working. It usually pops out with a slider.

Activity

  1. ngoiyaeric commented on Sep 5, 2026

    @ngoiyaeric
    CollaboratorAuthor
  2. coderabbitai commented on Sep 5, 2026

    @coderabbitai
    Contributor

    Coding Plan

    Summary

    • Fix the desktop trigger button in components/header-search-button.tsx so it enables in Google provider mode, matching the mobile button's provider-aware disabled condition.
    • Document NEXT_PUBLIC_GOOGLE_MAPS_API_KEY in .env.local.example, because the compare slider needs the Google Static Maps image.
    • Replace the silent Google Static Map failure with user-facing toasts, and continue with a single-image fallback instead of aborting.
    • Add onError image fallbacks in components/compare-slider.tsx to avoid blank/broken images.

    File-Level Changes and Follow-Up Notes

    • components/header-search-button.tsx: Fix the desktop button disabled condition to guard map with mapProvider === 'mapbox'. In handleResolutionSearch, add toasts for a missing NEXT_PUBLIC_GOOGLE_MAPS_API_KEY and for a failed Google Static Map fetch, and keep the flow running with the available images.
    • .env.local.example: Add and document NEXT_PUBLIC_GOOGLE_MAPS_API_KEY.
    • components/compare-slider.tsx: Add onError fallbacks to both <img> elements using the existing placeholder image.

    Follow-up instruction for the implementing agent:

    • First verify the fix by testing both provider modes on desktop: set mapProvider to 'mapbox' and to 'google', then confirm the search button is enabled and handleResolutionSearch fires in both.
    • Confirm that with a valid NEXT_PUBLIC_GOOGLE_MAPS_API_KEY, both mapboxImage and googleImage reach components/resolution-carousel.tsx and the CompareSlider slide renders.
    • Do not modify the resolution_search server action logic in app/actions.tsx or lib/agents/resolution-search.tsx; the exploration confirmed that branch is intact.
    • Ignore the stale root-level .patch files (chat-panel.patch, app_actions_diff.patch, layout.patch); they are already-applied or superseded and are not the cause of this regression.
    Design Choices
    Design Choice 1: Primary root cause of the regression

    Options Considered:

    1. The desktop trigger button is permanently disabled when the Google map provider is active, because its disabled condition requires the Mapbox map instance unconditionally.
    2. The NEXT_PUBLIC_GOOGLE_MAPS_API_KEY is unset and undocumented, so the Google Static Map fetch is skipped silently, and the compare slider never gets its second image.

    Chosen Option: 1

    Rationale: Fix both defects: the desktop button condition and the missing key documentation. The compare slider needs both a working trigger and both images to render. Both defects fail silently today.

    💡 User Tips

    Regenerate the plan with different choices with @coderabbitai <feedback>.

    Implementation Steps

    Phase 1: Restore the trigger and its prerequisites

    This phase restores the user's ability to start a resolution search and documents the configuration the compare slider needs. The goal is to make the trigger fire in all supported provider modes and to make the Google Static Maps requirement explicit.

    Task 1: Fix the desktop search button disabled condition

    The desktop trigger button is disabled whenever the Mapbox map instance is absent. When mapProvider === 'google', the Mapbox map is never mounted, so map stays null and the button never enables. This blocks the whole resolution-search flow on desktop in Google mode.

    • Update components/header-search-button.tsx.
    • Change the desktop button disabled condition to match the mobile button.
    • Require map only when mapProvider === 'mapbox' (for example, disabled={isAnalyzing || !actions || (mapProvider === 'mapbox' && !map)}).
    • Keep the mobile button condition unchanged, because it already has the provider-aware guard.
    Task 2: Document the Google Static Maps API key requirement

    The compare slider needs a Google image. components/header-search-button.tsx fetches it from the Google Static Maps API using NEXT_PUBLIC_GOOGLE_MAPS_API_KEY. This variable is not documented in any example env file, so it is likely unset in most environments, and the fetch is skipped silently.

    • Add NEXT_PUBLIC_GOOGLE_MAPS_API_KEY to .env.local.example.
    • State in a comment that this key is required for the Google Static Maps fetch and the compare slider, and that it is also used by components/map/google-map.tsx and lib/agents/tools/geospatial.tsx.
    • Do not add secrets. Add the variable name and an explanatory comment only.
    🤖 Prompt for AI agents
    Implement Phase 1: restore the resolution-search trigger and document its
    required configuration.
    
    1. In `components/header-search-button.tsx`, locate the desktop search button
    and its `disabled` condition. Change the condition so it requires the Mapbox
    `map` instance only when `mapProvider === 'mapbox'`. Use a condition such as
    `disabled={isAnalyzing || !actions || (mapProvider === 'mapbox' && !map)}`.
    Match this to the logic already used by the mobile button. Do not change the
    mobile button condition.
    
    2. In `.env.local.example`, add the `NEXT_PUBLIC_GOOGLE_MAPS_API_KEY` variable
    name with a comment. The comment must state that this key is required for the
    Google Static Maps fetch used by the compare slider, and that it is also used by
    `components/map/google-map.tsx` and `lib/agents/tools/geospatial.tsx`. Do not
    add an actual secret value, only the variable name and comment.
    

    Phase 2: Make image-capture failures visible and add resilience

    This phase removes the silent failure modes that hide the compare slider. The goal is that a missing key or a failed image fetch produces a clear message and, where possible, a graceful fallback, instead of a quietly dropped slide.

    Task 1: Surface Google Static Map fetch failures

    In components/header-search-button.tsx, the Google Static Map fetch is wrapped in logic that only writes to console.error or skips when the key is missing. When this happens, googleBlob stays null, the compare slide is dropped, and the user sees no reason.

    • Update components/header-search-button.tsx handleResolutionSearch.
    • When NEXT_PUBLIC_GOOGLE_MAPS_API_KEY is missing, show a user-facing toast that explains the Google image is unavailable and the compare view will not appear.
    • When the Google Static Map fetch throws or returns a non-OK response, show a toast with a short error message.
    • Continue the resolution search with the available images (single-image fallback) rather than aborting the whole flow.
    Task 2: Add image error fallback in the compare slider

    components/compare-slider.tsx renders two <img> elements with no onError handling. A broken or expired image URL shows a blank area with no indication of failure. Other image components in the repo already use a placeholder fallback.

    • Update components/compare-slider.tsx.
    • Add onError handling to both <img> elements to fall back to the existing placeholder image (/images/placeholder-image.png), consistent with components/search-results-image.tsx.
    • Do not change the drag/slider behavior or the layout logic.
    🤖 Prompt for AI agents
    Implement Phase 2: remove silent failure modes around the resolution-search
    image capture and add fallback handling for broken images.
    
    1. In `components/header-search-button.tsx`, inside `handleResolutionSearch`,
    add user-facing toasts:
    - If `NEXT_PUBLIC_GOOGLE_MAPS_API_KEY` is missing, show a toast that explains
    the Google image is unavailable and the compare view will not appear.
    - If the Google Static Map fetch throws an error or returns a non-OK response,
    show a toast with a short error message.
    - In both cases, continue the resolution search using the available images as a
    single-image fallback. Do not abort the whole flow.
    
    2. In `components/compare-slider.tsx`, add an `onError` handler to both `<img>`
    elements. On error, fall back to the existing placeholder image at
    `/images/placeholder-image.png`, consistent with the pattern in
    `components/search-results-image.tsx`. Do not change the drag/slider behavior or
    the layout logic.
    
    Research

    The app uses the Vercel AI SDK RSC streaming pattern. A submit server action in app/actions.tsx streams React components into a uiStream. The compare slider path is a dedicated action === 'resolution_search' branch, not an LLM tool. components/header-search-button.tsx is the client trigger. It captures the Mapbox canvas and fetches a Google Static Map image, then submits both as a FormData to the resolution_search action. app/actions.tsx renders components/resolution-carousel.tsx, which renders components/compare-slider.tsx only when both a Mapbox image and a Google image exist. The provider state lives in lib/store/settings.ts (mapProvider, default 'mapbox').


    🚀 Next Steps

    🤖 All AI agent prompts combined
    Task: 1
    
    Implement Phase 1: restore the resolution-search trigger and document its
    required configuration.
    
    1. In `components/header-search-button.tsx`, locate the desktop search button
    and its `disabled` condition. Change the condition so it requires the Mapbox
    `map` instance only when `mapProvider === 'mapbox'`. Use a condition such as
    `disabled={isAnalyzing || !actions || (mapProvider === 'mapbox' && !map)}`.
    Match this to the logic already used by the mobile button. Do not change the
    mobile button condition.
    
    2. In `.env.local.example`, add the `NEXT_PUBLIC_GOOGLE_MAPS_API_KEY` variable
    name with a comment. The comment must state that this key is required for the
    Google Static Maps fetch used by the compare slider, and that it is also used by
    `components/map/google-map.tsx` and `lib/agents/tools/geospatial.tsx`. Do not
    add an actual secret value, only the variable name and comment.
    ===============================================================================
    
    Task: 2
    
    Implement Phase 2: remove silent failure modes around the resolution-search
    image capture and add fallback handling for broken images.
    
    1. In `components/header-search-button.tsx`, inside `handleResolutionSearch`,
    add user-facing toasts:
    - If `NEXT_PUBLIC_GOOGLE_MAPS_API_KEY` is missing, show a toast that explains
    the Google image is unavailable and the compare view will not appear.
    - If the Google Static Map fetch throws an error or returns a non-OK response,
    show a toast with a short error message.
    - In both cases, continue the resolution search using the available images as a
    single-image fallback. Do not abort the whole flow.
    
    2. In `components/compare-slider.tsx`, add an `onError` handler to both `<img>`
    elements. On error, fall back to the existing placeholder image at
    `/images/placeholder-image.png`, consistent with the pattern in
    `components/search-results-image.tsx`. Do not change the drag/slider behavior or
    the layout logic.
    
    💡 Iterate on the plan with: `@coderabbitai` <feedback>
    Example Feedback
    - `@coderabbitai` You can skip phase 3. Add a simple unit test case for phase 2.
    - `@coderabbitai` For design choice 1 go ahead with option 3 and replan.
    

    Start Coding

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions