Browse Source

fix: upload remote image preview (#9952)

zxhlyh 5 months ago
parent
commit
78b74cce8e

+ 8 - 18
web/app/components/base/file-uploader/file-uploader-in-attachment/file-item.tsx

@@ -1,6 +1,5 @@
 import {
   memo,
-  useMemo,
 } from 'react'
 import {
   RiDeleteBinLine,
@@ -35,17 +34,9 @@ const FileInAttachmentItem = ({
   onRemove,
   onReUpload,
 }: FileInAttachmentItemProps) => {
-  const { id, name, type, progress, supportFileType, base64Url, url } = file
-  const ext = getFileExtension(name, type)
+  const { id, name, type, progress, supportFileType, base64Url, url, isRemote } = file
+  const ext = getFileExtension(name, type, isRemote)
   const isImageFile = supportFileType === SupportUploadFileTypes.image
-  const nameArr = useMemo(() => {
-    const nameMatch = name.match(/(.+)\.([^.]+)$/)
-
-    if (nameMatch)
-      return [nameMatch[1], nameMatch[2]]
-
-    return [name, '']
-  }, [name])
 
   return (
     <div className={cn(
@@ -75,12 +66,7 @@ const FileInAttachmentItem = ({
           className='flex items-center mb-0.5 system-xs-medium text-text-secondary truncate'
           title={file.name}
         >
-          <div className='truncate'>{nameArr[0]}</div>
-          {
-            nameArr[1] && (
-              <span>.{nameArr[1]}</span>
-            )
-          }
+          <div className='truncate'>{name}</div>
         </div>
         <div className='flex items-center system-2xs-medium-uppercase text-text-tertiary'>
           {
@@ -93,7 +79,11 @@ const FileInAttachmentItem = ({
               <span className='mx-1 system-2xs-medium'>•</span>
             )
           }
-          <span>{formatFileSize(file.size || 0)}</span>
+          {
+            !!file.size && (
+              <span>{formatFileSize(file.size)}</span>
+            )
+          }
         </div>
       </div>
       <div className='shrink-0 flex items-center'>

+ 5 - 3
web/app/components/base/file-uploader/file-uploader-in-chat-input/file-item.tsx

@@ -31,8 +31,8 @@ const FileItem = ({
   onRemove,
   onReUpload,
 }: FileItemProps) => {
-  const { id, name, type, progress, url } = file
-  const ext = getFileExtension(name, type)
+  const { id, name, type, progress, url, isRemote } = file
+  const ext = getFileExtension(name, type, isRemote)
   const uploadError = progress === -1
 
   return (
@@ -75,7 +75,9 @@ const FileItem = ({
               </>
             )
           }
-          {formatFileSize(file.size || 0)}
+          {
+            !!file.size && formatFileSize(file.size)
+          }
         </div>
         {
           showDownloadAction && (

+ 28 - 9
web/app/components/base/file-uploader/hooks.ts

@@ -25,7 +25,7 @@ import { TransferMethod } from '@/types/app'
 import { SupportUploadFileTypes } from '@/app/components/workflow/types'
 import type { FileUpload } from '@/app/components/base/features/types'
 import { formatFileSize } from '@/utils/format'
-import { fetchRemoteFileInfo } from '@/service/common'
+import { uploadRemoteFileInfo } from '@/service/common'
 import type { FileUploadConfigResponse } from '@/models/common'
 
 export const useFileSizeLimit = (fileUploadConfig?: FileUploadConfigResponse) => {
@@ -49,7 +49,7 @@ export const useFile = (fileConfig: FileUpload) => {
   const params = useParams()
   const { imgSizeLimit, docSizeLimit, audioSizeLimit, videoSizeLimit } = useFileSizeLimit(fileConfig.fileUploadConfig)
 
-  const checkSizeLimit = (fileType: string, fileSize: number) => {
+  const checkSizeLimit = useCallback((fileType: string, fileSize: number) => {
     switch (fileType) {
       case SupportUploadFileTypes.image: {
         if (fileSize > imgSizeLimit) {
@@ -120,7 +120,7 @@ export const useFile = (fileConfig: FileUpload) => {
         return true
       }
     }
-  }
+  }, [audioSizeLimit, docSizeLimit, imgSizeLimit, notify, t, videoSizeLimit])
 
   const handleAddFile = useCallback((newFile: FileEntity) => {
     const {
@@ -188,6 +188,17 @@ export const useFile = (fileConfig: FileUpload) => {
     }
   }, [fileStore, notify, t, handleUpdateFile, params])
 
+  const startProgressTimer = useCallback((fileId: string) => {
+    const timer = setInterval(() => {
+      const files = fileStore.getState().files
+      const file = files.find(file => file.id === fileId)
+
+      if (file && file.progress < 80 && file.progress >= 0)
+        handleUpdateFile({ ...file, progress: file.progress + 20 })
+      else
+        clearTimeout(timer)
+    }, 200)
+  }, [fileStore, handleUpdateFile])
   const handleLoadFileFromLink = useCallback((url: string) => {
     const allowedFileTypes = fileConfig.allowed_file_types
 
@@ -197,19 +208,27 @@ export const useFile = (fileConfig: FileUpload) => {
       type: '',
       size: 0,
       progress: 0,
-      transferMethod: TransferMethod.remote_url,
+      transferMethod: TransferMethod.local_file,
       supportFileType: '',
       url,
+      isRemote: true,
     }
     handleAddFile(uploadingFile)
+    startProgressTimer(uploadingFile.id)
 
-    fetchRemoteFileInfo(url).then((res) => {
+    uploadRemoteFileInfo(url).then((res) => {
       const newFile = {
         ...uploadingFile,
-        type: res.file_type,
-        size: res.file_length,
+        type: res.mime_type,
+        size: res.size,
         progress: 100,
-        supportFileType: getSupportFileType(url, res.file_type, allowedFileTypes?.includes(SupportUploadFileTypes.custom)),
+        supportFileType: getSupportFileType(res.name, res.mime_type, allowedFileTypes?.includes(SupportUploadFileTypes.custom)),
+        uploadedId: res.id,
+        url: res.url,
+      }
+      if (!isAllowedFileExtension(res.name, res.mime_type, fileConfig.allowed_file_types || [], fileConfig.allowed_file_extensions || [])) {
+        notify({ type: 'error', message: t('common.fileUploader.fileExtensionNotSupport') })
+        handleRemoveFile(uploadingFile.id)
       }
       if (!checkSizeLimit(newFile.supportFileType, newFile.size))
         handleRemoveFile(uploadingFile.id)
@@ -219,7 +238,7 @@ export const useFile = (fileConfig: FileUpload) => {
       notify({ type: 'error', message: t('common.fileUploader.pasteFileLinkInvalid') })
       handleRemoveFile(uploadingFile.id)
     })
-  }, [checkSizeLimit, handleAddFile, handleUpdateFile, notify, t, handleRemoveFile, fileConfig?.allowed_file_types])
+  }, [checkSizeLimit, handleAddFile, handleUpdateFile, notify, t, handleRemoveFile, fileConfig?.allowed_file_types, fileConfig.allowed_file_extensions, startProgressTimer])
 
   const handleLoadFileFromLinkSuccess = useCallback(() => { }, [])
 

+ 1 - 0
web/app/components/base/file-uploader/types.ts

@@ -29,4 +29,5 @@ export type FileEntity = {
   uploadedId?: string
   base64Url?: string
   url?: string
+  isRemote?: boolean
 }

+ 4 - 1
web/app/components/base/file-uploader/utils.ts

@@ -43,10 +43,13 @@ export const fileUpload: FileUpload = ({
     })
 }
 
-export const getFileExtension = (fileName: string, fileMimetype: string) => {
+export const getFileExtension = (fileName: string, fileMimetype: string, isRemote?: boolean) => {
   if (fileMimetype)
     return mime.getExtension(fileMimetype) || ''
 
+  if (isRemote)
+    return ''
+
   if (fileName) {
     const fileNamePair = fileName.split('.')
     const fileNamePairLength = fileNamePair.length

+ 1 - 0
web/app/components/base/image-uploader/image-list.tsx

@@ -133,6 +133,7 @@ const ImageList: FC<ImageListProps> = ({
         <ImagePreview
           url={imagePreviewUrl}
           onCancel={() => setImagePreviewUrl('')}
+          title=''
         />
       )}
     </div>

+ 3 - 2
web/service/common.ts

@@ -324,9 +324,10 @@ export const verifyForgotPasswordToken: Fetcher<CommonResponse & { is_valid: boo
 export const changePasswordWithToken: Fetcher<CommonResponse, { url: string; body: { token: string; new_password: string; password_confirm: string } }> = ({ url, body }) =>
   post<CommonResponse>(url, { body })
 
-export const fetchRemoteFileInfo = (url: string) => {
-  return get<{ file_type: string; file_length: number }>(`/remote-files/${url}`)
+export const uploadRemoteFileInfo = (url: string) => {
+  return post<{ id: string; name: string; size: number; mime_type: string; url: string }>('/remote-files/upload', { body: { url } })
 }
+
 export const sendEMailLoginCode = (email: string, language = 'en-US') =>
   post<CommonResponse & { data: string }>('/email-code-login', { body: { email, language } })