diff --git a/components/agents/AgentProjectListSheet.tsx b/components/agents/AgentProjectListSheet.tsx index 90d85e32f..e20289f8a 100644 --- a/components/agents/AgentProjectListSheet.tsx +++ b/components/agents/AgentProjectListSheet.tsx @@ -17,23 +17,85 @@ import { } from "@/components/ui/sheet"; import { cn } from "@/lib/utils"; import { buildImageProxyUrl } from "@/lib/image-delivery"; -import type { AgentGenerationProject } from "@/types/agent"; +import type { + AgentGenerationProject, + AgentWorkflowMaterialImage, + AgentWorkflowMaterialSelectionState, +} from "@/types/agent"; + +function normalizePreviewUrl(value?: string | null) { + const normalizedValue = String(value || "").trim(); + return normalizedValue || null; +} + +function sortMaterialImages(images: AgentWorkflowMaterialImage[]) { + return [...images].sort((left, right) => { + const sortOrderDiff = (left.sortOrder || 0) - (right.sortOrder || 0); + if (sortOrderDiff !== 0) { + return sortOrderDiff; + } + return left.id.localeCompare(right.id); + }); +} + +function getImageUrlFromCandidates(images: AgentWorkflowMaterialImage[]) { + for (const image of images) { + const imageUrl = normalizePreviewUrl(image.imageUrl); + if (imageUrl) { + return imageUrl; + } + } + return null; +} + +function getMaterialSelectionPreviewUrl(selection?: AgentWorkflowMaterialSelectionState | null) { + const images = selection?.result?.images ?? []; + if (!images.length) { + return null; + } + + const sortedImages = sortMaterialImages(images); + const selectedImageIds = new Set(selection?.selectedImageIds ?? []); + + const selectedImages = sortedImages.filter((image) => selectedImageIds.has(image.id)); + const selectedUploadedImages = selectedImages.filter((image) => image.sourceType === "upload"); + const uploadedImages = sortedImages.filter((image) => image.sourceType === "upload"); + const searchImages = sortedImages.filter((image) => image.sourceType !== "upload"); + + return ( + getImageUrlFromCandidates(selectedUploadedImages) || + getImageUrlFromCandidates(selectedImages) || + getImageUrlFromCandidates(uploadedImages) || + getImageUrlFromCandidates(searchImages) || + getImageUrlFromCandidates(sortedImages) + ); +} function getProjectPreviewUrl(project: AgentGenerationProject) { - const explicitThumbnail = String(project.thumbnail || "").trim(); + const explicitThumbnail = normalizePreviewUrl(project.thumbnail); if (explicitThumbnail) { return explicitThumbnail; } const resultCollections = project.projectState?.resultCollections; - const fallbackUrl = + const resultPreviewUrl = resultCollections?.scene_generation?.[0] || resultCollections?.detail_generation?.[0] || resultCollections?.detail_replacement?.[0] || resultCollections?.sku_replacement?.[0] || ""; + const normalizedResultPreviewUrl = normalizePreviewUrl(resultPreviewUrl); + if (normalizedResultPreviewUrl) { + return normalizedResultPreviewUrl; + } - return String(fallbackUrl || "").trim() || null; + const materials = project.projectState?.workflowState?.materials; + + return ( + getMaterialSelectionPreviewUrl(materials?.primary) || + getMaterialSelectionPreviewUrl(materials?.secondary) || + null + ); } interface AgentProjectListSheetProps { diff --git a/components/agents/AgentWorkflowPanelDarkV2.tsx b/components/agents/AgentWorkflowPanelDarkV2.tsx index 9164285a8..bec8e2407 100644 --- a/components/agents/AgentWorkflowPanelDarkV2.tsx +++ b/components/agents/AgentWorkflowPanelDarkV2.tsx @@ -1,6 +1,6 @@ "use client"; -import { Fragment, useEffect, useMemo, useState, type ReactNode } from "react"; +import { useEffect, useMemo, useState, type ReactNode } from "react"; import { motion } from "framer-motion"; import { ArrowRight, Check, Copy, Sparkles, ChevronRight } from "lucide-react"; import { toast } from "sonner"; @@ -958,7 +958,7 @@ export function AgentWorkflowPanelDarkV2({ >