file-item.tsx 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. import {
  2. memo,
  3. useState,
  4. } from 'react'
  5. import {
  6. RiDeleteBinLine,
  7. RiDownloadLine,
  8. RiEyeLine,
  9. } from '@remixicon/react'
  10. import FileTypeIcon from '../file-type-icon'
  11. import {
  12. downloadFile,
  13. fileIsUploaded,
  14. getFileAppearanceType,
  15. getFileExtension,
  16. } from '../utils'
  17. import FileImageRender from '../file-image-render'
  18. import type { FileEntity } from '../types'
  19. import ActionButton from '@/app/components/base/action-button'
  20. import ProgressCircle from '@/app/components/base/progress-bar/progress-circle'
  21. import { formatFileSize } from '@/utils/format'
  22. import cn from '@/utils/classnames'
  23. import { ReplayLine } from '@/app/components/base/icons/src/vender/other'
  24. import { SupportUploadFileTypes } from '@/app/components/workflow/types'
  25. import ImagePreview from '@/app/components/base/image-uploader/image-preview'
  26. type FileInAttachmentItemProps = {
  27. file: FileEntity
  28. showDeleteAction?: boolean
  29. showDownloadAction?: boolean
  30. onRemove?: (fileId: string) => void
  31. onReUpload?: (fileId: string) => void
  32. canPreview?: boolean
  33. }
  34. const FileInAttachmentItem = ({
  35. file,
  36. showDeleteAction,
  37. showDownloadAction = true,
  38. onRemove,
  39. onReUpload,
  40. canPreview,
  41. }: FileInAttachmentItemProps) => {
  42. const { id, name, type, progress, supportFileType, base64Url, url, isRemote } = file
  43. const ext = getFileExtension(name, type, isRemote)
  44. const isImageFile = supportFileType === SupportUploadFileTypes.image
  45. const [imagePreviewUrl, setImagePreviewUrl] = useState('')
  46. return (
  47. <>
  48. <div className={cn(
  49. 'flex items-center pr-3 h-12 rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-on-panel-item-bg shadow-xs',
  50. progress === -1 && 'bg-state-destructive-hover border-state-destructive-border',
  51. )}>
  52. <div className='flex items-center justify-center w-12 h-12'>
  53. {
  54. isImageFile && (
  55. <FileImageRender
  56. className='w-8 h-8'
  57. imageUrl={base64Url || url || ''}
  58. />
  59. )
  60. }
  61. {
  62. !isImageFile && (
  63. <FileTypeIcon
  64. type={getFileAppearanceType(name, type)}
  65. size='lg'
  66. />
  67. )
  68. }
  69. </div>
  70. <div className='grow w-0 mr-1'>
  71. <div
  72. className='flex items-center mb-0.5 system-xs-medium text-text-secondary truncate'
  73. title={file.name}
  74. >
  75. <div className='truncate'>{name}</div>
  76. </div>
  77. <div className='flex items-center system-2xs-medium-uppercase text-text-tertiary'>
  78. {
  79. ext && (
  80. <span>{ext.toLowerCase()}</span>
  81. )
  82. }
  83. {
  84. ext && (
  85. <span className='mx-1 system-2xs-medium'>•</span>
  86. )
  87. }
  88. {
  89. !!file.size && (
  90. <span>{formatFileSize(file.size)}</span>
  91. )
  92. }
  93. </div>
  94. </div>
  95. <div className='shrink-0 flex items-center'>
  96. {
  97. progress >= 0 && !fileIsUploaded(file) && (
  98. <ProgressCircle
  99. className='mr-2.5'
  100. percentage={progress}
  101. />
  102. )
  103. }
  104. {
  105. progress === -1 && (
  106. <ActionButton
  107. className='mr-1'
  108. onClick={() => onReUpload?.(id)}
  109. >
  110. <ReplayLine className='w-4 h-4 text-text-tertiary' />
  111. </ActionButton>
  112. )
  113. }
  114. {
  115. showDeleteAction && (
  116. <ActionButton onClick={() => onRemove?.(id)}>
  117. <RiDeleteBinLine className='w-4 h-4' />
  118. </ActionButton>
  119. )
  120. }
  121. {
  122. canPreview && isImageFile && (
  123. <ActionButton className='mr-1' onClick={() => setImagePreviewUrl(url || '')}>
  124. <RiEyeLine className='w-4 h-4' />
  125. </ActionButton>
  126. )
  127. }
  128. {
  129. showDownloadAction && (
  130. <ActionButton onClick={(e) => {
  131. e.stopPropagation()
  132. downloadFile(url || base64Url || '', name)
  133. }}>
  134. <RiDownloadLine className='w-4 h-4' />
  135. </ActionButton>
  136. )
  137. }
  138. </div>
  139. </div>
  140. {
  141. imagePreviewUrl && canPreview && (
  142. <ImagePreview
  143. title={name}
  144. url={imagePreviewUrl}
  145. onCancel={() => setImagePreviewUrl('')}
  146. />
  147. )
  148. }
  149. </>
  150. )
  151. }
  152. export default memo(FileInAttachmentItem)