From ad513ff604e487295c74cb3e7ea25d3f91f3595f Mon Sep 17 00:00:00 2001 From: waleedlatif Date: Fri, 1 Aug 2025 12:13:04 -0700 Subject: [PATCH 1/2] fix(chat-deploy): added new image upload component, fixed some state issues with success view --- .../components/chat-deploy/chat-deploy.tsx | 385 +++++++++++++----- .../components/subdomain-input.tsx | 8 +- .../chat-deploy/components/success-view.tsx | 8 +- .../components/chat-deploy/hooks/index.ts | 3 +- .../chat-deploy/hooks/use-chat-deployment.ts | 5 +- .../chat-deploy/hooks/use-image-upload.ts | 184 +++++++++ .../hooks/use-subdomain-validation.ts | 20 +- .../components/deploy-modal/deploy-modal.tsx | 81 ++-- apps/sim/components/ui/image-upload.tsx | 230 +++++++++++ apps/sim/components/ui/index.ts | 1 + apps/sim/next.config.ts | 36 +- apps/sim/providers/utils.ts | 1 - apps/sim/stores/ollama/store.ts | 1 - 13 files changed, 833 insertions(+), 130 deletions(-) create mode 100644 apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/components/deploy-modal/components/chat-deploy/hooks/use-image-upload.ts create mode 100644 apps/sim/components/ui/image-upload.tsx diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/components/deploy-modal/components/chat-deploy/chat-deploy.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/components/deploy-modal/components/chat-deploy/chat-deploy.tsx index 56f583aca98..aaf6800063e 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/components/deploy-modal/components/chat-deploy/chat-deploy.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/components/deploy-modal/components/chat-deploy/chat-deploy.tsx @@ -1,18 +1,28 @@ 'use client' import { useEffect, useRef, useState } from 'react' -import { AlertTriangle } from 'lucide-react' +import { AlertTriangle, Loader2 } from 'lucide-react' import { Alert, AlertDescription, + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, Card, CardContent, + ImageUpload, Input, Label, Skeleton, Textarea, } from '@/components/ui' import { createLogger } from '@/lib/logs/console/logger' +import { getEmailDomain } from '@/lib/urls/utils' import { AuthSelector } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/components/deploy-modal/components/chat-deploy/components/auth-selector' import { SubdomainInput } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/components/deploy-modal/components/chat-deploy/components/subdomain-input' import { SuccessView } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/components/deploy-modal/components/chat-deploy/components/success-view' @@ -32,6 +42,9 @@ interface ChatDeployProps { setChatSubmitting: (submitting: boolean) => void onValidationChange?: (isValid: boolean) => void onPreDeployWorkflow?: () => Promise + showDeleteConfirmation?: boolean + setShowDeleteConfirmation?: (show: boolean) => void + onDeploymentComplete?: () => void } interface ExistingChat { @@ -56,9 +69,27 @@ export function ChatDeploy({ setChatSubmitting, onValidationChange, onPreDeployWorkflow, + showDeleteConfirmation: externalShowDeleteConfirmation, + setShowDeleteConfirmation: externalSetShowDeleteConfirmation, + onDeploymentComplete, }: ChatDeployProps) { const [isLoading, setIsLoading] = useState(false) const [existingChat, setExistingChat] = useState(null) + const [imageUrl, setImageUrl] = useState(null) + const [imageUploadError, setImageUploadError] = useState(null) + const [isDeleting, setIsDeleting] = useState(false) + const [isImageUploading, setIsImageUploading] = useState(false) + const [internalShowDeleteConfirmation, setInternalShowDeleteConfirmation] = useState(false) + const [showSuccessView, setShowSuccessView] = useState(false) + + // Use external state for delete confirmation if provided + const showDeleteConfirmation = + externalShowDeleteConfirmation !== undefined + ? externalShowDeleteConfirmation + : internalShowDeleteConfirmation + + const setShowDeleteConfirmation = + externalSetShowDeleteConfirmation || setInternalShowDeleteConfirmation const { formData, errors, updateField, setError, validateForm, setFormData } = useChatForm() const { deployedUrl, deployChat } = useChatDeployment() @@ -115,10 +146,18 @@ export function ChatDeploy({ : [], }) + // Set image URL if it exists + if (chatDetail.customizations?.imageUrl) { + setImageUrl(chatDetail.customizations.imageUrl) + } + setImageUploadError(null) + onChatExistsChange?.(true) } } else { setExistingChat(null) + setImageUrl(null) + setImageUploadError(null) onChatExistsChange?.(false) } } @@ -150,9 +189,14 @@ export function ChatDeploy({ return } - await deployChat(workflowId, formData, deploymentInfo, existingChat?.id) + await deployChat(workflowId, formData, deploymentInfo, existingChat?.id, imageUrl) onChatExistsChange?.(true) + setShowSuccessView(true) + + // Fetch the updated chat data immediately after deployment + // This ensures existingChat is available when switching back to edit mode + await fetchExistingChat() } catch (error: any) { if (error.message?.includes('subdomain')) { setError('subdomain', error.message) @@ -164,111 +208,266 @@ export function ChatDeploy({ } } + const handleDelete = async () => { + if (!existingChat || !existingChat.id) return + + try { + setIsDeleting(true) + + const response = await fetch(`/api/chat/edit/${existingChat.id}`, { + method: 'DELETE', + }) + + if (!response.ok) { + const error = await response.json() + throw new Error(error.error || 'Failed to delete chat') + } + + // Update state + setExistingChat(null) + setImageUrl(null) + setImageUploadError(null) + onChatExistsChange?.(false) + + // Notify parent of successful deletion + onDeploymentComplete?.() + } catch (error: any) { + logger.error('Failed to delete chat:', error) + setError('general', error.message || 'An unexpected error occurred while deleting') + } finally { + setIsDeleting(false) + setShowDeleteConfirmation(false) + } + } + if (isLoading) { return } - if (deployedUrl) { - return + if (deployedUrl && showSuccessView) { + return ( + <> +
+ setShowDeleteConfirmation(true)} + onUpdate={() => { + console.log('Update clicked, existingChat:', existingChat) + setShowSuccessView(false) + }} + /> +
+ + {/* Delete Confirmation Dialog */} + + + + Delete Chat? + + This will permanently delete your chat deployment at{' '} + + {existingChat?.subdomain}.{getEmailDomain()} + + . + + All users will lose access immediately, and this action cannot be undone. + + + + + Cancel + + {isDeleting ? ( + + + Deleting... + + ) : ( + 'Delete' + )} + + + + + + ) } return ( -
- {errors.general && ( - - - {errors.general} - - )} - -
- updateField('subdomain', value)} - originalSubdomain={existingChat?.subdomain} - disabled={chatSubmitting} - onValidationChange={setIsSubdomainValid} - /> -
- - updateField('title', e.target.value)} - required + <> + + {errors.general && ( + + + {errors.general} + + )} + +
+ updateField('subdomain', value)} + originalSubdomain={existingChat?.subdomain || undefined} disabled={chatSubmitting} + onValidationChange={setIsSubdomainValid} + isEditingExisting={!!existingChat} /> - {errors.title &&

{errors.title}

} -
-
- -