@ -1,6 +1,6 @@
"use client" ;
import React , { useCallback , useState , useEffect , useMemo } from "react" ;
import React , { useCallback , useState , useEffect , useMemo , useRef } from "react" ;
import { Handle , Position , NodeProps , Node , useReactFlow } from "@xyflow/react" ;
import { BaseNode } from "./BaseNode" ;
import { ModelParameters } from "./ModelParameters" ;
@ -8,6 +8,7 @@ import { useWorkflowStore, saveNanoBananaDefaults } from "@/store/workflowStore"
import { NanoBananaNodeData , AspectRatio , Resolution , ModelType , ProviderType , SelectedModel , ModelInputDef } from "@/types" ;
import { ProviderModel , ModelCapability } from "@/lib/providers/types" ;
import { ModelSearchDialog } from "@/components/modals/ModelSearchDialog" ;
import { useToast } from "@/components/Toast" ;
// All 10 aspect ratios supported by both models
const ASPECT_RATIOS : AspectRatio [ ] = [ "1:1" , "2:3" , "3:2" , "3:4" , "4:3" , "4:5" , "5:4" , "9:16" , "16:9" , "21:9" ] ;
@ -385,6 +386,17 @@ export function GenerateImageNode({ id, data, selected }: NodeProps<NanoBananaNo
const isNanoBananaPro = isGeminiProvider && nodeData . model === "nano-banana-pro" ;
const hasCarouselImages = ( nodeData . imageHistory || [ ] ) . length > 1 ;
// Track previous status to detect error transitions
const prevStatusRef = useRef ( nodeData . status ) ;
// Show toast when error occurs
useEffect ( ( ) = > {
if ( nodeData . status === "error" && prevStatusRef . current !== "error" && nodeData . error ) {
useToast . getState ( ) . show ( "Generation failed" , "error" , true , nodeData . error ) ;
}
prevStatusRef . current = nodeData . status ;
} , [ nodeData . status , nodeData . error ] ) ;
return (
< >
< BaseNode
@ -541,6 +553,22 @@ export function GenerateImageNode({ id, data, selected }: NodeProps<NanoBananaNo
< / svg >
< / div >
) }
{ /* Error overlay when generation failed */ }
{ nodeData . status === "error" && (
< div className = "absolute inset-0 bg-red-900/70 rounded flex flex-col items-center justify-center gap-1" >
< svg
className = "w-6 h-6 text-red-400"
fill = "none"
viewBox = "0 0 24 24"
stroke = "currentColor"
strokeWidth = { 2 }
>
< path strokeLinecap = "round" strokeLinejoin = "round" d = "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" / >
< / svg >
< span className = "text-red-400 text-xs font-medium" > Generation failed < / span >
< span className = "text-red-400/70 text-[10px]" > See toast for details < / span >
< / div >
) }
{ /* Loading overlay for carousel navigation */ }
{ isLoadingCarouselImage && (
< div className = "absolute inset-0 bg-neutral-900/50 rounded flex items-center justify-center" >