Skip to content
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

fix: explicitly list allowed image types for upload #7819

Open
wants to merge 1 commit into
base: next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,8 @@ function BaseImageInputComponent(props: BaseImageInputProps): JSX.Element {
}, [path])

const clearUploadStatus = useCallback(() => {
if (value?._upload) {
onChange(unset(['_upload']))
}
}, [onChange, value?._upload])
onChange(unset(['_upload']))
}, [onChange])
const cancelUpload = useCallback(() => {
if (uploadSubscription.current) {
uploadSubscription.current.unsubscribe()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {type Observable} from 'rxjs'
import {MenuItem} from '../../../../../ui-components'
import {useTranslation} from '../../../../i18n'
import {ActionsMenu} from '../common/ActionsMenu'
import {SUPPORTED_IMAGE_UPLOAD_TYPES} from '../constants'
import {ImageActionsMenu, ImageActionsMenuWaitPlaceholder} from './ImageActionsMenu'
import {type BaseImageInputProps} from './types'

Expand Down Expand Up @@ -54,7 +55,10 @@ function ImageInputAssetMenuComponent(
} = props
const {t} = useTranslation()

const accept = useMemo(() => get(schemaType, 'options.accept', 'image/*'), [schemaType])
const accept = useMemo(
() => get(schemaType, 'options.accept', SUPPORTED_IMAGE_UPLOAD_TYPES.join(',')),
[schemaType],
)
const asset = value?.asset

const showAdvancedEditButton = value && asset && isImageToolEnabled
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {get} from 'lodash'
import {memo, useMemo} from 'react'

import {WithReferencedAsset} from '../../../utils/WithReferencedAsset'
import {SUPPORTED_IMAGE_UPLOAD_TYPES} from '../constants'
import {type BaseImageInputProps} from './types'

function ImageInputAssetSourceComponent(
Expand All @@ -20,7 +21,10 @@ function ImageInputAssetSourceComponent(
selectedAssetSource,
value,
} = props
const accept = useMemo(() => get(schemaType, 'options.accept', 'image/*'), [schemaType])
const accept = useMemo(
() => get(schemaType, 'options.accept', SUPPORTED_IMAGE_UPLOAD_TYPES.join(',')),
[schemaType],
)

if (!selectedAssetSource) {
return null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {get} from 'lodash'
import {memo, useMemo} from 'react'

import {UploadPlaceholder} from '../common/UploadPlaceholder'
import {SUPPORTED_IMAGE_UPLOAD_TYPES} from '../constants'
import {type BaseImageInputProps, type FileInfo} from './types'

function ImageInputUploadPlaceholderComponent(props: {
Expand All @@ -28,7 +29,10 @@ function ImageInputUploadPlaceholderComponent(props: {
() => hoveringFiles.filter((file) => resolveUploader(schemaType, file)),
[hoveringFiles, resolveUploader, schemaType],
)
const accept = useMemo(() => get(schemaType, 'options.accept', 'image/*'), [schemaType])
const accept = useMemo(
() => get(schemaType, 'options.accept', SUPPORTED_IMAGE_UPLOAD_TYPES.join(',')),
[schemaType],
)

const rejectedFilesCount = hoveringFiles.length - acceptedFiles.length

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ import {Card, Container, Flex} from '@sanity/ui'

import {Button} from '../../../../../ui-components'
import {UploadPlaceholder} from '../common/UploadPlaceholder'
import {SUPPORTED_IMAGE_UPLOAD_TYPES} from '../constants'

export default function UploadPlaceholderStory() {
return (
<Flex align="center" height="fill" justify="center" padding={3}>
<Container width={1}>
<Card>
<UploadPlaceholder
accept="image/*"
accept={SUPPORTED_IMAGE_UPLOAD_TYPES.join(',')}
acceptedFiles={[{name: 'foo.jpg', type: 'image/jpeg'}]}
browse={<Button text="Browse btn" mode="ghost" />}
directUploads
Expand Down
16 changes: 16 additions & 0 deletions packages/sanity/src/core/form/inputs/files/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,19 @@
* the upload will be marked as stale/interrupted.
*/
export const STALE_UPLOAD_MS = 1000 * 60 * 2

/**
* The mime types of image formats we support uploading
*
* @internal
*/
export const SUPPORTED_IMAGE_UPLOAD_TYPES = [
'image/bmp',
'image/gif',
'image/jpeg',
'image/png',
'image/svg',
'image/tiff',
'image/webp',
'.psd', // Many different mime types for PSD files, so we just use the extension
]
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,13 @@ export const uploadImageAsset = (
client: SanityClient,
file: File | Blob,
options?: UploadOptions,
) => uploadAsset(client, 'image', file, options)
): Observable<UploadEvent> => uploadAsset(client, 'image', file, options)

export const uploadFileAsset = (client: SanityClient, file: File | Blob, options?: UploadOptions) =>
uploadAsset(client, 'file', file, options)
export const uploadFileAsset = (
client: SanityClient,
file: File | Blob,
options?: UploadOptions,
): Observable<UploadEvent> => uploadAsset(client, 'file', file, options)

/**
*
Expand Down Expand Up @@ -123,11 +126,17 @@ function observeAssetDoc(documentPreviewStore: DocumentPreviewStore, id: string)
)
}

export function observeImageAsset(documentPreviewStore: DocumentPreviewStore, id: string) {
export function observeImageAsset(
documentPreviewStore: DocumentPreviewStore,
id: string,
): Observable<ImageAsset> {
return observeAssetDoc(documentPreviewStore, id) as Observable<ImageAsset>
}

export function observeFileAsset(documentPreviewStore: DocumentPreviewStore, id: string) {
export function observeFileAsset(
documentPreviewStore: DocumentPreviewStore,
id: string,
): Observable<FileAsset> {
return observeAssetDoc(documentPreviewStore, id) as Observable<FileAsset>
}

Expand Down
5 changes: 2 additions & 3 deletions packages/sanity/src/core/form/studio/uploads/uploadImage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,11 @@ export function uploadImage(
options?: UploadOptions,
): Observable<UploadProgressEvent> {
const upload$ = uploadImageAsset(client, file, options).pipe(
filter((event: any) => event.stage !== 'download'),
filter((event) => !('stage' in event) || event.stage !== 'download'),
map((event) => ({
...event,
progress: 2 + (event.percent / 100) * 98,
progress: event.type === 'complete' ? 100 : 2 + (event.percent / 100) * 98,
})),

map((event) => {
if (event.type === 'complete') {
return createUploadEvent([
Expand Down
3 changes: 2 additions & 1 deletion packages/sanity/src/core/form/studio/uploads/uploaders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ import {type SanityClient} from '@sanity/client'
import {type SchemaType} from '@sanity/types'
import {map} from 'rxjs/operators'

import {SUPPORTED_IMAGE_UPLOAD_TYPES} from '../../inputs/files/constants'
import {set} from '../../patch'
import {type Uploader, type UploaderDef, type UploadOptions} from './types'
import {uploadFile} from './uploadFile'
import {uploadImage} from './uploadImage'

const UPLOAD_IMAGE: UploaderDef = {
type: 'image',
accepts: 'image/*',
accepts: SUPPORTED_IMAGE_UPLOAD_TYPES.join(','),
upload: (client: SanityClient, file: File, type?: SchemaType, options?: UploadOptions) =>
uploadImage(client, file, options),
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {styled} from 'styled-components'

import {Button, MenuButton, MenuItem} from '../../../../../../../../../../ui-components'
import {type Source} from '../../../../../../../../../config'
import {SUPPORTED_IMAGE_UPLOAD_TYPES} from '../../../../../../../../../form/inputs/files/constants'
import {FileSource, ImageSource} from '../../../../../../../../../form/studio/assetSource'
import {useClient} from '../../../../../../../../../hooks'
import {useTranslation} from '../../../../../../../../../i18n'
Expand Down Expand Up @@ -102,13 +103,15 @@ export function SearchFilterAssetInput(type?: AssetType) {

const AssetSourceComponent = selectedAssetSource?.component

const fontSize = fullscreen ? 2 : 1

const buttonText = t(value ? 'search.filter-asset-change' : 'search.filter-asset-select', {
context: type,
})

const accept = get(type, 'options.accept', type === 'image' ? 'image/*' : '')
const accept = get(
type,
'options.accept',
type === 'image' ? SUPPORTED_IMAGE_UPLOAD_TYPES.join(',') : '',
)

return (
<ContainerBox>
Expand Down
Loading