mirror of
https://github.com/langgenius/dify.git
synced 2026-09-05 08:48:10 +08:00
fix(web): align avatar file extension with output type (#41662)
This commit is contained in:
parent
b1eafb0d82
commit
7664ad7149
@ -16,7 +16,7 @@ import Divider from '@/app/components/base/divider'
|
||||
import { useLocalFileUploader } from '@/app/components/base/image-uploader/hooks'
|
||||
import { DISABLE_UPLOAD_IMAGE_AS_ICON } from '@/config'
|
||||
import { updateUserProfile } from '@/service/common'
|
||||
import { createCroppedAvatarImage } from './avatar-image'
|
||||
import { createAvatarImageFile, createCroppedAvatarImage } from './avatar-image'
|
||||
|
||||
type InputImageInfo =
|
||||
| { file: File }
|
||||
@ -111,7 +111,7 @@ const AvatarWithEdit = ({ onSave, ...props }: AvatarWithEditProps) => {
|
||||
inputImageInfo.croppedAreaPixels,
|
||||
inputImageInfo.fileName,
|
||||
)
|
||||
const file = new File([blob], inputImageInfo.fileName, { type: blob.type })
|
||||
const file = createAvatarImageFile(blob, inputImageInfo.fileName)
|
||||
handleLocalFileUpload(file)
|
||||
}, [handleLocalFileUpload, inputImageInfo])
|
||||
|
||||
|
||||
@ -45,9 +45,13 @@ vi.mock('@/app/components/base/image-uploader/hooks', () => ({
|
||||
}),
|
||||
}))
|
||||
|
||||
vi.mock('../avatar-image', () => ({
|
||||
createCroppedAvatarImage: vi.fn(),
|
||||
}))
|
||||
vi.mock('../avatar-image', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('../avatar-image')>()
|
||||
return {
|
||||
...actual,
|
||||
createCroppedAvatarImage: vi.fn(),
|
||||
}
|
||||
})
|
||||
|
||||
const mockedCreateCroppedAvatarImage = vi.mocked(createCroppedAvatarImage)
|
||||
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
import type { Area } from 'react-easy-crop'
|
||||
import { createImage } from '@/app/components/base/app-icon-picker/utils'
|
||||
import { createCroppedAvatarImage, getBoundedAvatarImageSize } from '../avatar-image'
|
||||
import {
|
||||
createAvatarImageFile,
|
||||
createCroppedAvatarImage,
|
||||
getBoundedAvatarImageSize,
|
||||
} from '../avatar-image'
|
||||
|
||||
vi.mock('@/app/components/base/app-icon-picker/utils', async (importOriginal) => {
|
||||
const actual =
|
||||
@ -58,4 +62,13 @@ describe('avatar image', () => {
|
||||
expect(context.drawImage).toHaveBeenCalledWith(image, 40, 20, 1000, 1000, 0, 0, 256, 256)
|
||||
expect(canvas.toBlob).toHaveBeenCalledWith(expect.any(Function), 'image/png', 0.85)
|
||||
})
|
||||
|
||||
it('matches the file extension to the browser output type', () => {
|
||||
const blob = new Blob(['avatar'], { type: 'image/png' })
|
||||
|
||||
const file = createAvatarImageFile(blob, 'avatar.webp')
|
||||
|
||||
expect(file.name).toBe('avatar.png')
|
||||
expect(file.type).toBe('image/png')
|
||||
})
|
||||
})
|
||||
|
||||
@ -3,6 +3,11 @@ import { createImage, getMimeType } from '@/app/components/base/app-icon-picker/
|
||||
|
||||
const AVATAR_IMAGE_MAX_SIZE = 256
|
||||
const AVATAR_IMAGE_QUALITY = 0.85
|
||||
const AVATAR_IMAGE_EXTENSION_BY_MIME_TYPE: Record<string, string> = {
|
||||
'image/jpeg': 'jpg',
|
||||
'image/png': 'png',
|
||||
'image/webp': 'webp',
|
||||
}
|
||||
|
||||
export const getBoundedAvatarImageSize = (
|
||||
crop: Pick<Area, 'width' | 'height'>,
|
||||
@ -55,3 +60,15 @@ export const createCroppedAvatarImage = async (
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
export const createAvatarImageFile = (blob: Blob, fileName: string) => {
|
||||
const extension = AVATAR_IMAGE_EXTENSION_BY_MIME_TYPE[blob.type]
|
||||
|
||||
if (!extension || getMimeType(fileName) === blob.type)
|
||||
return new File([blob], fileName, { type: blob.type })
|
||||
|
||||
const extensionStart = fileName.lastIndexOf('.')
|
||||
const baseName = extensionStart > 0 ? fileName.slice(0, extensionStart) : fileName
|
||||
|
||||
return new File([blob], `${baseName}.${extension}`, { type: blob.type })
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user