Skip to content

Commit

Permalink
feat: #203 allow users to specify maximum upload size
Browse files Browse the repository at this point in the history
  • Loading branch information
azaxarov committed Jul 16, 2024
1 parent 8c566b3 commit ae2bcd8
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 16 deletions.
15 changes: 10 additions & 5 deletions src/components/Tool/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import {Flex} from '@sanity/ui'
import React from 'react'
import React, {ComponentProps} from 'react'
import Browser from '../Browser'
import {ToolOptionsProvider} from '../../contexts/ToolOptionsContext'
import {Tool as SanityTool} from 'sanity'
import {MediaToolOptions} from '@types'

const Tool = () => {
const Tool = ({tool: {options}}: ComponentProps<SanityTool<MediaToolOptions>['component']>) => {
return (
<Flex direction="column" height="fill" flex={1}>
<Browser />
</Flex>
<ToolOptionsProvider options={options}>
<Flex direction="column" height="fill" flex={1}>
<Browser />
</Flex>
</ToolOptionsProvider>
)
}

Expand Down
24 changes: 22 additions & 2 deletions src/components/UploadDropzone/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import {white} from '@sanity/color'
import {Flex, Text} from '@sanity/ui'
import React, {ReactNode} from 'react'
import {DropEvent, useDropzone} from 'react-dropzone'
import {DropEvent, DropzoneOptions, useDropzone} from 'react-dropzone'
import {useDispatch} from 'react-redux'
import styled from 'styled-components'
import {useAssetSourceActions} from '../../contexts/AssetSourceDispatchContext'
import {DropzoneDispatchProvider} from '../../contexts/DropzoneDispatchContext'
import useTypedSelector from '../../hooks/useTypedSelector'
import {notificationsActions} from '../../modules/notifications'
import {uploadsActions} from '../../modules/uploads'
import {useToolOptions} from '../../contexts/ToolOptionsContext'

type Props = {
children: ReactNode
Expand Down Expand Up @@ -62,6 +63,10 @@ async function filterFiles(fileList: FileList) {
const UploadDropzone = (props: Props) => {
const {children} = props

const {
dropzone: {maxSize}
} = useToolOptions()

const {onSelect} = useAssetSourceActions()

// Redux
Expand All @@ -82,6 +87,19 @@ const UploadDropzone = (props: Props) => {
)
}

const handleDropRejected: DropzoneOptions['onDropRejected'] = rejections => {
const errorCodes = rejections.flatMap(({errors}) => errors.map(({code}) => code))

if (errorCodes.includes('file-too-large')) {
dispatch(
notificationsActions.add({
status: 'error',
title: 'One or more files exceed the maximum upload size.'
})
)
}
}

// Use custom file selector to obtain files on file drop + change events (excluding folders and packages)
const handleFileGetter = async (event: DropEvent) => {
let fileList: FileList | undefined
Expand Down Expand Up @@ -123,7 +141,9 @@ const UploadDropzone = (props: Props) => {
// HACK: Disable drag and drop functionality when in a selecting context
// (This is currently due to Sanity's native image input taking precedence with drag and drop)
noDrag: !!onSelect,
onDrop: handleDrop
onDrop: handleDrop,
maxSize,
onDropRejected: handleDropRejected
})

return (
Expand Down
34 changes: 34 additions & 0 deletions src/contexts/ToolOptionsContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import {MediaToolOptions} from '@types'
import React, {PropsWithChildren, createContext, useContext, useMemo} from 'react'
import {DropzoneOptions} from 'react-dropzone'

type ContextProps = {
dropzone: Pick<DropzoneOptions, 'maxSize'>
}

const ToolOptionsContext = createContext<ContextProps | null>(null)

type Props = {
options?: MediaToolOptions
}

export const ToolOptionsProvider = ({options, children}: PropsWithChildren<Props>) => {
const value = useMemo<ContextProps>(
() => ({dropzone: {maxSize: options?.maximumUploadSize}}),
[options?.maximumUploadSize]
)

return <ToolOptionsContext.Provider value={value}>{children}</ToolOptionsContext.Provider>
}

export const useToolOptions = () => {
const context = useContext(ToolOptionsContext)

if (!context) {
throw new Error('useToolOptions must be used within an ToolOptionsProvider')
}

return context
}

export default ToolOptionsContext
21 changes: 12 additions & 9 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import {definePlugin, Tool as SanityTool} from 'sanity'
import {definePlugin} from 'sanity'
import {ImageIcon} from '@sanity/icons'
import type {AssetSource} from 'sanity'
import FormBuilderTool from './components/FormBuilderTool'
import Tool from './components/Tool'
import mediaTag from './schemas/tag'
import {MediaToolOptions} from '@types'

const plugin = {
icon: ImageIcon,
Expand All @@ -16,12 +17,7 @@ export const mediaAssetSource: AssetSource = {
component: FormBuilderTool
}

const tool = {
...plugin,
component: Tool
} as SanityTool

export const media = definePlugin({
export const media = definePlugin<MediaToolOptions | void>(options => ({
name: 'media',
form: {
file: {
Expand All @@ -39,6 +35,13 @@ export const media = definePlugin({
types: [mediaTag]
},
tools: prev => {
return [...prev, tool]
return [
...prev,
{
...plugin,
options,
component: Tool
}
]
}
})
}))
4 changes: 4 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import * as z from 'zod'
import {assetFormSchema, tagFormSchema, tagOptionSchema} from '../formSchema'
import {RootReducerState} from '../modules/types'

export type MediaToolOptions = {
maximumUploadSize?: number
}

type CustomFields = {
altText?: string
description?: string
Expand Down

0 comments on commit ae2bcd8

Please sign in to comment.