Repository: h2oai/wave
File: ui/src/file_upload.tsx (TypeScript)

Code before:
      fontSize: 20,
      position: 'absolute',
      top: -15,
      right: 0,
      cursor: 'pointer'
    },
    compact: {
      position: 'relative'
    }
  })

const convertMegabytesToBytes = (bytes: F) => bytes * 1024 * 1024
export const
  XFileUpload = ({ model }: { model: FileUpload }) => {
    const
      { name, label, file_extensions, max_file_size, compact, height, max_size, multiple } = model,
      [isDragging, setIsDragging] = React.useState(false),
      [files, setFiles] = React.useState<File[]>([]),
      [fileNames, setFileNames] = React.useState<S>(''),
      [percentComplete, setPercentComplete] = React.useState(0.0),
      [error, setError] = React.useState(''),
      [successMsg, setSuccessMsg] = React.useState(''),
      maxFileSizeBytes = max_file_size ? convertMegabytesToBytes(max_file_size) : 0,
      maxSizeBytes = max_size ? convertMegabytesToBytes(max_size) : 0,
      fileExtensions = file_extensions ? file_extensions.map(e => e.startsWith('.') ? e : `.${e}`) : null,
      isAborted = React.useRef<B>(false),
      xhrRef = React.useRef<XMLHttpRequest>(),
      upload = async (uploadFiles = files) => {
        const formData = new FormData()
        uploadFiles.forEach((f: File) => formData.append('files', f))

        try {
          const { responseText } = await new Promise<XMLHttpRequest>((resolve, reject) => {
            xhrRef.current = new XMLHttpRequest()
            const xhr = xhrRef.current
            xhr.open("POST", wave.uploadURL)
            xhr.upload.onprogress = e => setPercentComplete(e.loaded / e.total)
            xhr.send(formData)
            xhr.onreadystatechange = () => {
              if (xhr.readyState !== XMLHttpRequest.DONE) return
              xhr.status >= 200 && xhr.status < 300 ? resolve(xhr) : reject(xhr)
            }
            xhr.onabort = () => isAborted.current = true
          })
          const { files } = JSON.parse(responseText)
          wave.args[name] = files

          if (!compact) wave.push()
          setSuccessMsg(`Successfully uploaded files: ${files.map(({ name }: File) => name).join(',')}.`)
        }
        catch ({ responseText }) {

Review comment (bug):
No need for extra ref to check if the request was aborted or not. See [this answer](https://stackoverflow.com/questions/3648309/how-to-detect-if-a-request-was-aborted), the `status` should equal `0` in case of abort.
```suggestion
```

Code after:
      fontSize: 20,
      position: 'absolute',
      top: -15,
      right: 0,
      cursor: 'pointer'
    },
    compact: {
      position: 'relative'
    }
  })

const convertMegabytesToBytes = (bytes: F) => bytes * 1024 * 1024
export const
  XFileUpload = ({ model }: { model: FileUpload }) => {
    const
      { name, label, file_extensions, max_file_size, compact, height, max_size, multiple } = model,
      [isDragging, setIsDragging] = React.useState(false),
      [files, setFiles] = React.useState<File[]>([]),
      [fileNames, setFileNames] = React.useState<S>(''),
      [percentComplete, setPercentComplete] = React.useState(0.0),
      [error, setError] = React.useState(''),
      [successMsg, setSuccessMsg] = React.useState(''),
      maxFileSizeBytes = max_file_size ? convertMegabytesToBytes(max_file_size) : 0,
      maxSizeBytes = max_size ? convertMegabytesToBytes(max_size) : 0,
      fileExtensions = file_extensions ? file_extensions.map(e => e.startsWith('.') ? e : `.${e}`) : null,
      rejectXhr = React.useRef<(reason?: any) => void>(),
      upload = async (uploadFiles = files) => {
        const formData = new FormData()
        uploadFiles.forEach((f: File) => formData.append('files', f))

        try {
          const { responseText } = await new Promise<XMLHttpRequest>((resolve, reject) => {
            const xhr = new XMLHttpRequest()
            rejectXhr.current = () => {
              reject()
              xhr.abort()
              setPercentComplete(0)
            }
            xhr.open("POST", wave.uploadURL)
            xhr.upload.onprogress = e => setPercentComplete(e.loaded / e.total)
            xhr.send(formData)
            xhr.onreadystatechange = () => {
              if (xhr.readyState !== XMLHttpRequest.DONE) return
              xhr.status >= 200 && xhr.status < 300 ? resolve(xhr) : reject(xhr)
            }
          })
          const { files } = JSON.parse(responseText)
          wave.args[name] = files

          if (!compact) wave.push()
          setSuccessMsg(`Successfully uploaded files: ${files.map(({ name }: File) => name).join(',')}.`)