-
Notifications
You must be signed in to change notification settings - Fork 1.7k
feat: rename/delete/add image #2967
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
e176c99
59ac396
176ac91
d2348da
055a996
220a04f
a4feecf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -56,12 +56,44 @@ export const useImageOperations = (projectId: string, branchId: string, activeFo | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Handle file rename | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const handleRename = async (oldPath: string, newName: string) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!codeEditor) throw new Error('Code editor not available'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const directory = path.dirname(oldPath); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const sanitizedName = sanitizeFilename(newName); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const newPath = path.join(directory, sanitizedName); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Check if it's still an image file | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!isImageFile(sanitizedName)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error('File must be an image'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Read the existing file content | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const content = await codeEditor.readFile(oldPath); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!content) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error('Could not read file content'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Write to new path and delete old file | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await codeEditor.writeFile(newPath, content); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await codeEditor.deleteFile(oldPath); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
62
to
117
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add collision check and improve error handling. The rename operation has two issues:
Apply this diff to add collision check: const handleRename = async (oldPath: string, newName: string) => {
if (!codeEditor) throw new Error('Code editor not available');
const directory = path.dirname(oldPath);
const sanitizedName = sanitizeFilename(newName);
const newPath = path.join(directory, sanitizedName);
// Check if it's still an image file
if (!isImageFile(sanitizedName)) {
throw new Error('File must be an image');
}
+
+ // Check if the target path already exists
+ if (newPath !== oldPath) {
+ try {
+ const existingContent = await codeEditor.readFile(newPath);
+ if (existingContent) {
+ throw new Error('A file with this name already exists');
+ }
+ } catch (error) {
+ // File doesn't exist, which is what we want
+ if (!(error instanceof Error) || !error.message.includes('not found')) {
+ throw error;
+ }
+ }
+ }
// Read the existing file content
const content = await codeEditor.readFile(oldPath);
if (!content) {
throw new Error('Could not read file content');
}
- // Write to new path and delete old file
- await codeEditor.writeFile(newPath, content);
- await codeEditor.deleteFile(oldPath);
+ // Write to new path and delete old file
+ try {
+ await codeEditor.writeFile(newPath, content);
+ await codeEditor.deleteFile(oldPath);
+ } catch (error) {
+ // If write succeeded but delete failed, attempt cleanup
+ try {
+ await codeEditor.deleteFile(newPath);
+ } catch {
+ // Cleanup failed, log the inconsistent state
+ console.error('Failed to cleanup after partial rename failure');
+ }
+ throw error;
+ }
};📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Handle file delete | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const handleDelete = async (filePath: string) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!codeEditor) throw new Error('Code editor not available'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await codeEditor.deleteFile(filePath); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| folders, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| images, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| loading, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| error, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isUploading, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| handleUpload, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| handleRename, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| handleDelete, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,9 +12,12 @@ interface ImageGridProps { | |
| branchId: string; | ||
| search: string; | ||
| onUpload: (files: FileList) => Promise<void>; | ||
| onRename: (oldPath: string, newName: string) => Promise<void>; | ||
| onDelete: (filePath: string) => Promise<void>; | ||
| onAddToChat: (image: any) => void; | ||
|
||
| } | ||
|
|
||
| export const ImageGrid = ({ images, projectId, branchId, search, onUpload }: ImageGridProps) => { | ||
| export const ImageGrid = ({ images, projectId, branchId, search, onUpload, onRename, onDelete, onAddToChat }: ImageGridProps) => { | ||
| const { | ||
| handleDragEnter, handleDragLeave, handleDragOver, handleDrop, isDragging, | ||
| onImageDragStart, onImageDragEnd, onImageMouseDown, onImageMouseUp | ||
|
|
@@ -41,6 +44,9 @@ export const ImageGrid = ({ images, projectId, branchId, search, onUpload }: Ima | |
| onImageDragEnd={onImageDragEnd} | ||
| onImageMouseDown={onImageMouseDown} | ||
| onImageMouseUp={onImageMouseUp} | ||
| onRename={onRename} | ||
| onDelete={onDelete} | ||
| onAddToChat={onAddToChat} | ||
| /> | ||
| ))} | ||
| </div> | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2,7 +2,25 @@ | |||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| import { useFile } from '@onlook/file-system/hooks'; | ||||||||||||||||||||||||||||||||||||||
| import type { ImageContentData } from '@onlook/models'; | ||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||
| AlertDialog, | ||||||||||||||||||||||||||||||||||||||
| AlertDialogAction, | ||||||||||||||||||||||||||||||||||||||
| AlertDialogCancel, | ||||||||||||||||||||||||||||||||||||||
| AlertDialogContent, | ||||||||||||||||||||||||||||||||||||||
| AlertDialogDescription, | ||||||||||||||||||||||||||||||||||||||
| AlertDialogFooter, | ||||||||||||||||||||||||||||||||||||||
| AlertDialogHeader, | ||||||||||||||||||||||||||||||||||||||
| AlertDialogTitle | ||||||||||||||||||||||||||||||||||||||
| } from '@onlook/ui/alert-dialog'; | ||||||||||||||||||||||||||||||||||||||
| import { Button } from '@onlook/ui/button'; | ||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||
| DropdownMenu, | ||||||||||||||||||||||||||||||||||||||
| DropdownMenuContent, | ||||||||||||||||||||||||||||||||||||||
| DropdownMenuItem, | ||||||||||||||||||||||||||||||||||||||
| DropdownMenuTrigger | ||||||||||||||||||||||||||||||||||||||
| } from '@onlook/ui/dropdown-menu'; | ||||||||||||||||||||||||||||||||||||||
| import { Icons } from '@onlook/ui/icons'; | ||||||||||||||||||||||||||||||||||||||
| import { Input } from '@onlook/ui/input'; | ||||||||||||||||||||||||||||||||||||||
| import { useEffect, useState } from 'react'; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| interface ImageItemProps { | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -17,12 +35,18 @@ interface ImageItemProps { | |||||||||||||||||||||||||||||||||||||
| onImageDragEnd: () => void; | ||||||||||||||||||||||||||||||||||||||
| onImageMouseDown: () => void; | ||||||||||||||||||||||||||||||||||||||
| onImageMouseUp: () => void; | ||||||||||||||||||||||||||||||||||||||
| onRename: (oldPath: string, newName: string) => Promise<void>; | ||||||||||||||||||||||||||||||||||||||
| onDelete: (filePath: string) => Promise<void>; | ||||||||||||||||||||||||||||||||||||||
| onAddToChat: (image: ImageContentData) => void; | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| export const ImageItem = ({ image, projectId, branchId, onImageDragStart, onImageDragEnd, onImageMouseDown, onImageMouseUp }: ImageItemProps) => { | ||||||||||||||||||||||||||||||||||||||
| export const ImageItem = ({ image, projectId, branchId, onImageDragStart, onImageDragEnd, onImageMouseDown, onImageMouseUp, onRename, onDelete, onAddToChat }: ImageItemProps) => { | ||||||||||||||||||||||||||||||||||||||
| const { content, loading } = useFile(projectId, branchId, image.path); | ||||||||||||||||||||||||||||||||||||||
| const [imageUrl, setImageUrl] = useState<string | null>(null); | ||||||||||||||||||||||||||||||||||||||
| const [isDisabled, setIsDisabled] = useState(false); | ||||||||||||||||||||||||||||||||||||||
| const [isRenaming, setIsRenaming] = useState(false); | ||||||||||||||||||||||||||||||||||||||
| const [newName, setNewName] = useState(image.name); | ||||||||||||||||||||||||||||||||||||||
| const [showDeleteDialog, setShowDeleteDialog] = useState(false); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| // Convert content to data URL for display | ||||||||||||||||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||||||||||||||||
|
|
@@ -87,24 +111,158 @@ export const ImageItem = ({ image, projectId, branchId, onImageDragStart, onImag | |||||||||||||||||||||||||||||||||||||
| onImageDragStart(e, imageContentData); | ||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const handleRename = async () => { | ||||||||||||||||||||||||||||||||||||||
| if (newName.trim() && newName !== image.name) { | ||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||
| await onRename(image.path, newName.trim()); | ||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||
| console.error('Failed to rename file:', error); | ||||||||||||||||||||||||||||||||||||||
Kitenite marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||
| setNewName(image.name); // Reset on error | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| setIsRenaming(false); | ||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||
Kitenite marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const handleDelete = async () => { | ||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||
| await onDelete(image.path); | ||||||||||||||||||||||||||||||||||||||
| setShowDeleteDialog(false); | ||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||
| console.error('Failed to delete file:', error); | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| const handleAddToChat = () => { | ||||||||||||||||||||||||||||||||||||||
| const imageContentData: ImageContentData = { | ||||||||||||||||||||||||||||||||||||||
| fileName: image.name, | ||||||||||||||||||||||||||||||||||||||
| content: content as string, | ||||||||||||||||||||||||||||||||||||||
| mimeType: imageUrl || '', | ||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||
| mimeType: imageUrl || '', | |
| mimeType: imageUrl ? imageUrl.split(';')[0].split(':')[1] : 'image/png', |
Spotted by Diamond
Is this helpful? React 👍 or 👎 to let us know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix incorrect mimeType assignment.
Line 139 has the same issue as line 108: mimeType is set to imageUrl (a data URL) instead of the actual MIME type.
Apply this diff:
const handleAddToChat = () => {
const imageContentData: ImageContentData = {
fileName: image.name,
content: content as string,
- mimeType: imageUrl || '',
+ mimeType: image.mimeType || 'image/*',
originPath: image.path,
};
onAddToChat(imageContentData);
};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const handleAddToChat = () => { | |
| const imageContentData: ImageContentData = { | |
| fileName: image.name, | |
| content: content as string, | |
| mimeType: imageUrl || '', | |
| originPath: image.path, | |
| }; | |
| onAddToChat(imageContentData); | |
| }; | |
| const handleAddToChat = () => { | |
| const imageContentData: ImageContentData = { | |
| fileName: image.name, | |
| content: content as string, | |
| mimeType: image.mimeType || 'image/*', | |
| originPath: image.path, | |
| }; | |
| onAddToChat(imageContentData); | |
| }; |
🤖 Prompt for AI Agents
In
apps/web/client/src/app/project/[id]/_components/left-panel/image-tab/image-item.tsx
around lines 135 to 143, the mimeType for ImageContentData is incorrectly set to
imageUrl (a data URL); change the assignment to use the actual MIME type from
the image object (e.g. image.mimeType || ''), ensuring the field contains a MIME
type string rather than a data URL and preserving types when calling
onAddToChat.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,9 @@ | ||
| 'use client'; | ||
|
|
||
| import { useEditorEngine } from '@/components/store/editor'; | ||
| import { MessageContextType, type FileMessageContext } from '@onlook/models/chat'; | ||
| import { Icons } from '@onlook/ui/icons'; | ||
| import { toast } from '@onlook/ui/sonner'; | ||
| import { observer } from 'mobx-react-lite'; | ||
| import { BreadcrumbNavigation } from './breadcrumb-navigation'; | ||
| import { FolderList } from './folder-list'; | ||
|
|
@@ -37,11 +39,55 @@ export const ImagesTab = observer(() => { | |
| error, | ||
| isUploading, | ||
| handleUpload, | ||
| handleRename, | ||
| handleDelete, | ||
| } = useImageOperations(projectId, branchId, activeFolder, branchData?.codeEditor); | ||
|
|
||
| // Filter images based on search | ||
| const images = filterImages(allImages); | ||
|
|
||
| // Handler functions with error handling and feedback | ||
| const handleRenameWithFeedback = async (oldPath: string, newName: string) => { | ||
| try { | ||
| await handleRename(oldPath, newName); | ||
| toast.success('Image renamed successfully'); | ||
| } catch (error) { | ||
| console.error('Failed to rename image:', error); | ||
| toast.error(`Failed to rename image: ${error instanceof Error ? error.message : 'Unknown error'}`); | ||
| throw error; | ||
| } | ||
| }; | ||
|
|
||
| const handleDeleteWithFeedback = async (filePath: string) => { | ||
| try { | ||
| await handleDelete(filePath); | ||
| toast.success('Image deleted successfully'); | ||
| } catch (error) { | ||
| console.error('Failed to delete image:', error); | ||
| toast.error(`Failed to delete image: ${error instanceof Error ? error.message : 'Unknown error'}`); | ||
| throw error; | ||
| } | ||
| }; | ||
|
|
||
| const handleAddToChat = async (imageContentData: any) => { | ||
| try { | ||
| // Convert the image content data to file context for chat | ||
| const fileContext: FileMessageContext = { | ||
| type: MessageContextType.FILE, | ||
| content: '', // File content will be loaded by the chat system | ||
| displayName: imageContentData.fileName, | ||
| path: imageContentData.originPath, | ||
| branchId: branchId, | ||
| }; | ||
|
|
||
| editorEngine.chat.context.addContexts([fileContext]); | ||
| toast.success('Image added to chat'); | ||
| } catch (error) { | ||
| console.error('Failed to add image to chat:', error); | ||
| toast.error('Failed to add image to chat'); | ||
| } | ||
| }; | ||
|
||
|
|
||
| if (loading) { | ||
| return ( | ||
| <div className="w-full h-full flex items-center justify-center gap-2"> | ||
|
|
@@ -84,6 +130,9 @@ export const ImagesTab = observer(() => { | |
| branchId={branchId} | ||
| search={search} | ||
| onUpload={handleUpload} | ||
| onRename={handleRenameWithFeedback} | ||
| onDelete={handleDeleteWithFeedback} | ||
| onAddToChat={handleAddToChat} | ||
| /> | ||
| </div> | ||
| ); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider checking if a file already exists at the target (newPath) before renaming to avoid accidental overwrites.