From 75be22dda5beb54dd1b682ef6f96f5c568e3b123 Mon Sep 17 00:00:00 2001
From: Audrey Hamelers <hamelers@ebi.ac.uk>
Date: Mon, 30 Jul 2018 11:14:04 -0400
Subject: [PATCH] Breaking: major changes to file data storage

---
 app/components/Create.jsx             |  29 ++++--
 app/components/FilePreview.jsx        |  10 +-
 app/components/ManuscriptPreview.jsx  |  20 ++--
 app/components/Submit.jsx             |  80 ++++++++-------
 app/components/UploadFileListItem.jsx |   5 +-
 app/components/UploadFiles.jsx        | 134 ++++++++++++--------------
 app/components/createsubmission.js    |  10 +-
 app/components/ui/atoms/Select.jsx    |  25 ++---
 app/components/ui/atoms/Select.md     |  59 +++---------
 app/redux/createsubmission.js         |  40 ++++----
 config/validations.js                 |  35 ++-----
 server/bulk/api.js                    |  99 +++++++------------
 12 files changed, 231 insertions(+), 315 deletions(-)

diff --git a/app/components/Create.jsx b/app/components/Create.jsx
index 1a86dc16a..6783af8cd 100644
--- a/app/components/Create.jsx
+++ b/app/components/Create.jsx
@@ -12,6 +12,7 @@ import {
   updateManuscriptGrants,
   updateManuscriptEmbargo,
   addManuscriptReviewer,
+  submissionFileTypes,
 } from './createsubmission'
 import { Buttons, Center, InfoPanel, SplitPage, StepPanel } from './ui/'
 import CreatePageHeader from './CreateHeader'
@@ -29,7 +30,6 @@ const Status = styled.div`
   align-items: center;
   color: ${th('colorWarning')};
 `
-const submissionFileTypes = ['figure', 'table', 'supplementary file']
 class EPMCCreated extends React.Component {
   constructor(props) {
     super(props)
@@ -94,8 +94,12 @@ class EPMCCreated extends React.Component {
         if (!files || !this.state.checked) {
           return true
         } else if (
-          files.supplementary &&
-          files.supplementary.some(file => !file.label || !file.type)
+          files &&
+          files
+            .filter(
+              file => !file.type || submissionFileTypes.includes(file.type),
+            )
+            .some(file => !file.label || !file.type)
         ) {
           return true
         }
@@ -130,8 +134,10 @@ class EPMCCreated extends React.Component {
     const newState = { checked: !checked }
     if (
       !checked &&
-      files.supplementary &&
-      files.supplementary.some(file => !file.label || !file.type)
+      files &&
+      files
+        .filter(file => !file.type || submissionFileTypes.includes(file.type))
+        .some(file => !file.label || !file.type)
     ) {
       newState.error = 'All indicated files must have a type and a label.'
     } else {
@@ -142,8 +148,14 @@ class EPMCCreated extends React.Component {
   render() {
     const { currentStep, status, error, checked } = this.state
     const { metadata, files: allfiles } = this.props.version
-    const { xml, ...submitted } = allfiles || ''
-    const files = { ...submitted } || ''
+    const files = allfiles
+      ? allfiles.filter(
+          file =>
+            !file.type ||
+            file.type === 'manuscript' ||
+            submissionFileTypes.includes(file.type),
+        )
+      : []
     return (
       <SplitPage>
         <StepPanel>
@@ -176,6 +188,7 @@ class EPMCCreated extends React.Component {
             )}
             {currentStep === 1 && (
               <div>
+                <H2>Files</H2>
                 <UploadFiles
                   addFiles={this.addManuscriptFiles}
                   checked={checked}
@@ -188,7 +201,7 @@ class EPMCCreated extends React.Component {
                   uploadFile={this.props.uploadFile}
                   version={this.props.currentVersion}
                 />
-                {Object.keys(files).length > 0 && (
+                {files.length > 0 && (
                   <div>
                     <p>Please certify the following statement is true:</p>
                     <Checkbox
diff --git a/app/components/FilePreview.jsx b/app/components/FilePreview.jsx
index b1cf76077..bc52c9c11 100644
--- a/app/components/FilePreview.jsx
+++ b/app/components/FilePreview.jsx
@@ -46,16 +46,16 @@ class FilePreview extends React.Component {
             style={{ wordBreak: 'break-all' }}
             title="Preview figure"
           >
-            {file.name}
+            {file.filename}
           </Action>
         ) : (
           <A
-            download={file.name}
+            download={file.filename}
             href={file.url}
             style={{ wordBreak: 'break-all' }}
             title="Download this file"
           >
-            {file.name}
+            {file.filename}
           </A>
         )}
         {preview &&
@@ -71,7 +71,7 @@ class FilePreview extends React.Component {
                     <Center>
                       <p>
                         <b>{preview.label ? `${preview.label}: ` : ''}</b>
-                        {preview.name}
+                        {preview.filename}
                       </p>
                     </Center>
                   </PDF>
@@ -80,7 +80,7 @@ class FilePreview extends React.Component {
                     <Image src={preview.url} />
                     <p>
                       <b>{preview.label ? `${preview.label}: ` : ''}</b>
-                      {preview.name}
+                      {preview.filename}
                     </p>
                   </Center>
                 )}
diff --git a/app/components/ManuscriptPreview.jsx b/app/components/ManuscriptPreview.jsx
index cbf5ed688..3f2d3a831 100644
--- a/app/components/ManuscriptPreview.jsx
+++ b/app/components/ManuscriptPreview.jsx
@@ -3,7 +3,7 @@ import SimpleEditor from 'wax-editor-react'
 import PDFViewer from './pdf-viewer/PDFViewer'
 import { A } from './ui/'
 
-const ManuscriptPreview = ({ source, files }) => {
+const ManuscriptPreview = ({ source, file }) => {
   if (source) {
     return (
       <SimpleEditor
@@ -14,20 +14,16 @@ const ManuscriptPreview = ({ source, files }) => {
         readOnly
       />
     )
-  } else if (files.manuscript.mimeType === 'application/pdf') {
-    return <PDFViewer url={files.manuscript.url} />
+  } else if (file.mimeType === 'application/pdf') {
+    return <PDFViewer url={file.url} />
   }
   return (
     <p>
-      Unable to generate manuscript preview from {files.manuscript.name}.
-      Previews can only be generated from files with the extensions
-      <em> .docx</em> and <em>.pdf</em>. If your file is one of these types,
-      please ensure it is uncorrupted.
-      <A
-        download={files.manuscript.name}
-        href={files.manuscript.url}
-        title="Download this file"
-      >
+      Unable to generate manuscript preview from {file.name}. Previews can only
+      be generated from files with the extensions <em> .docx</em> and
+      <em>.pdf</em>. If your file is one of these types, please ensure it is
+      uncorrupted.
+      <A download={file.name} href={file.url} title="Download this file">
         Download your file.
       </A>
     </p>
diff --git a/app/components/Submit.jsx b/app/components/Submit.jsx
index b96279fe2..c52997088 100644
--- a/app/components/Submit.jsx
+++ b/app/components/Submit.jsx
@@ -1,5 +1,5 @@
 import React from 'react'
-
+import { withRouter } from 'react-router-dom'
 import styled, { withTheme } from 'styled-components'
 import { th } from '@pubsweet/ui-toolkit'
 import { ErrorText, H1, H2, H3, Icon } from '@pubsweet/ui'
@@ -29,6 +29,7 @@ import {
   updateManuscriptGrants,
   updateManuscriptEmbargo,
   addManuscriptReviewer,
+  submissionFileTypes,
 } from './createsubmission'
 import Citation from './Citation'
 import PubMedSearch from './PubMedSearch'
@@ -83,7 +84,6 @@ const FileTable = styled(Table)`
     border-top: ${th('borderWidth')} ${th('borderStyle')} ${th('colorBorder')};
   }
 `
-const submissionFileTypes = ['figure', 'table', 'supplementary file']
 class EPMCSubmit extends React.Component {
   constructor(props) {
     super(props)
@@ -118,8 +118,14 @@ class EPMCSubmit extends React.Component {
     const { project, currentVersion, currentUser, uploadFile } = this.props
     const { metadata, files: allfiles } = currentVersion
     const { editing } = this.state
-    const { xml, ...submitted } = allfiles || ''
-    const files = { ...submitted } || ''
+    const files = allfiles
+      ? allfiles.filter(
+          file =>
+            !file.type ||
+            file.type === 'manuscript' ||
+            submissionFileTypes.includes(file.type),
+        )
+      : []
     const { fundingGroup: grants = [], customMeta = {} } = metadata
     const { releaseDelay = '', unmatchedJournal } = customMeta
     const reviewer = currentVersion.suggestions
@@ -159,26 +165,24 @@ class EPMCSubmit extends React.Component {
               <th>Filename</th>
               <th>Label</th>
             </tr>
-            {Object.keys(files).map(
-              (sec, i) =>
-                Array.isArray(files[sec]) ? (
-                  files[sec].map((file, n) => (
-                    <tr key={file.url}>
-                      <td>{file.type}</td>
-                      <td>
-                        <FilePreview file={file} />
-                      </td>
-                      <td>{file.label}</td>
-                    </tr>
-                  ))
-                ) : (
+            {files.map(
+              file =>
+                file.type === 'manuscript' ? (
                   <tr key="manuscript">
                     <td>manuscript</td>
                     <td>
-                      <FilePreview file={files[sec]} />
+                      <FilePreview file={file} />
                     </td>
                     <td />
                   </tr>
+                ) : (
+                  <tr key={file.url}>
+                    <td>{file.type}</td>
+                    <td>
+                      <FilePreview file={file} />
+                    </td>
+                    <td>{file.label}</td>
+                  </tr>
                 ),
             )}
           </tbody>
@@ -186,8 +190,10 @@ class EPMCSubmit extends React.Component {
       ),
       edit: 'upload',
       error:
-        files.supplementary &&
-        files.supplementary.some(file => !file.label || !file.type) ? (
+        files &&
+        files
+          .filter(file => !file.type || submissionFileTypes.includes(file.type))
+          .some(file => !file.label || !file.type) ? (
           <ErrorText>
             <Icon color="currentColor" size={2}>
               alert_circle
@@ -287,18 +293,21 @@ class EPMCSubmit extends React.Component {
             />
           </Close>
           {editing === 'upload' ? (
-            <UploadFiles
-              addFiles={this.addManuscriptFiles}
-              checked
-              deleteFile={this.deleteManuscriptFile}
-              files={files}
-              newManuscriptFile={this.setNewManuscript}
-              parentStatus={this.state.status}
-              types={submissionFileTypes}
-              updateFiles={this.updateManuscriptFiles}
-              uploadFile={uploadFile}
-              version={currentVersion}
-            />
+            <div>
+              <H2>Files</H2>
+              <UploadFiles
+                addFiles={this.addManuscriptFiles}
+                checked
+                deleteFile={this.deleteManuscriptFile}
+                files={files}
+                newManuscriptFile={this.setNewManuscript}
+                parentStatus={this.state.status}
+                types={submissionFileTypes}
+                updateFiles={this.updateManuscriptFiles}
+                uploadFile={uploadFile}
+                version={currentVersion}
+              />
+            </div>
           ) : (
             <div>{editing}</div>
           )}
@@ -320,7 +329,10 @@ class EPMCSubmit extends React.Component {
             <H1>Preview submission</H1>
           </PanelHeader>
           <PanelContent>
-            <ManuscriptPreview files={files} source={currentVersion.source} />
+            <ManuscriptPreview
+              file={files.find(file => file.type === 'manuscript')}
+              source={currentVersion.source}
+            />
           </PanelContent>
         </PreviewPanel>
         <EditPanel>
@@ -361,4 +373,4 @@ class EPMCSubmit extends React.Component {
   }
 }
 
-export default EPMCSubmit
+export default withRouter(EPMCSubmit)
diff --git a/app/components/UploadFileListItem.jsx b/app/components/UploadFileListItem.jsx
index 55e125c7c..6e8def5b0 100644
--- a/app/components/UploadFileListItem.jsx
+++ b/app/components/UploadFileListItem.jsx
@@ -125,8 +125,8 @@ class UploadFileListItem extends React.Component {
     })
   }
   render() {
-    const { types, sec, status, checked, file } = this.props
-    if (sec === 'manuscript') {
+    const { types, status, checked, file } = this.props
+    if (file.type === 'manuscript') {
       return (
         <FileListItem>
           <LabeledDiv>
@@ -171,7 +171,6 @@ class UploadFileListItem extends React.Component {
           icon="chevron_down"
           invalidTest={checked && !this.state.type}
           label="Select file type"
-          noValueOption=" "
           onChange={this.onTypeChange}
           options={types}
           value={this.state.type}
diff --git a/app/components/UploadFiles.jsx b/app/components/UploadFiles.jsx
index f38840bf3..1f41a9376 100644
--- a/app/components/UploadFiles.jsx
+++ b/app/components/UploadFiles.jsx
@@ -2,10 +2,9 @@ import React from 'react'
 import { withRouter } from 'react-router-dom'
 import styled from 'styled-components'
 import Dropzone from 'react-dropzone'
-import { omit } from 'lodash'
 
 import { th, lighten } from '@pubsweet/ui-toolkit'
-import { H2, H3, Icon } from '@pubsweet/ui'
+import { H3, Icon } from '@pubsweet/ui'
 import { LoadingIcon } from './ui/'
 import { ManuscriptTypes, FileTypes } from '../redux/uploadtypes'
 import UploadFileListItem from './UploadFileListItem'
@@ -62,94 +61,79 @@ const UploadFiles = props => {
     props.addFiles(acceptedFiles)
   }
   const updateFile = fileData => {
-    const { file, sec, index, remove } = fileData
-    const { files } = props
-    const newFiles = omit(files, sec)
+    const { file, remove } = fileData
     if (remove) {
-      files[sec].splice(index, 1)
-      newFiles[sec] = files[sec]
-      props.deleteFile(newFiles)
+      props.deleteFile(file)
     } else {
-      files[sec][index] = file
-      newFiles[sec] = files[sec]
-      props.updateFiles(newFiles)
+      props.updateFiles(file)
     }
   }
   const { types, checked = false, files, parentStatus: status } = props
   return (
-    <div>
-      <H2>Files</H2>
-      <UploadDiv>
-        {Object.keys(files).length > 0 ? (
-          <div>
-            <FileList>
-              {Object.keys(files).map(
-                (sec, i) =>
-                  Array.isArray(files[sec]) ? (
-                    files[sec].map((file, n) => (
-                      <UploadFileListItem
-                        checked={checked}
-                        file={file}
-                        fileData={updateFile}
-                        index={n}
-                        key={file.url}
-                        sec={sec}
-                        types={types}
-                      />
-                    ))
-                  ) : (
-                    <UploadFileListItem
-                      file={files[sec]}
-                      fileData={addManuscript}
-                      key="manuscript"
-                      sec={sec}
-                      status={status}
-                    />
-                  ),
-              )}
-            </FileList>
-            <DropMore
-              accept={FileTypes.join(', ')}
-              disabled={status === 'Saving...'}
-              onDrop={addFiles}
-            >
-              {status === 'Saving...' ? (
-                <LoadingIcon size={6} />
-              ) : (
-                <Icon color="currentColor" size={6}>
-                  upload
-                </Icon>
-              )}
-              <p>
-                Drop additional files here, or click to select from your
-                computer.
-              </p>
-            </DropMore>
-          </div>
-        ) : (
-          <DropArea
-            accept={ManuscriptTypes.join(', ')}
+    <UploadDiv>
+      {files.length > 0 ? (
+        <div>
+          <FileList>
+            {files.map(
+              file =>
+                file.type === 'manuscript' ? (
+                  <UploadFileListItem
+                    file={file}
+                    fileData={addManuscript}
+                    key="manuscript"
+                    status={status}
+                  />
+                ) : (
+                  <UploadFileListItem
+                    checked={checked}
+                    file={file}
+                    fileData={updateFile}
+                    key={file.url}
+                    types={types}
+                  />
+                ),
+            )}
+          </FileList>
+          <DropMore
+            accept={FileTypes.join(', ')}
             disabled={status === 'Saving...'}
-            onDrop={addManuscript}
+            onDrop={addFiles}
           >
             {status === 'Saving...' ? (
-              <LoadingIcon size={8} />
+              <LoadingIcon size={6} />
             ) : (
-              <Icon color="currentColor" size={8}>
+              <Icon color="currentColor" size={6}>
                 upload
               </Icon>
             )}
-            <H3>
-              Drop manuscript file here, or click to select from your computer.
-            </H3>
             <p>
-              Only Microsoft Word or PDF file formats are accepted for the
-              manuscript file.
+              Drop additional files here, or click to select from your computer.
             </p>
-          </DropArea>
-        )}
-      </UploadDiv>
-    </div>
+          </DropMore>
+        </div>
+      ) : (
+        <DropArea
+          accept={ManuscriptTypes.join(', ')}
+          disabled={status === 'Saving...'}
+          onDrop={addManuscript}
+        >
+          {status === 'Saving...' ? (
+            <LoadingIcon size={8} />
+          ) : (
+            <Icon color="currentColor" size={8}>
+              upload
+            </Icon>
+          )}
+          <H3>
+            Drop manuscript file here, or click to select from your computer.
+          </H3>
+          <p>
+            Only Microsoft Word or PDF file formats are accepted for the
+            manuscript file.
+          </p>
+        </DropArea>
+      )}
+    </UploadDiv>
   )
 }
 
diff --git a/app/components/createsubmission.js b/app/components/createsubmission.js
index 8d7a725b7..25c82ee02 100644
--- a/app/components/createsubmission.js
+++ b/app/components/createsubmission.js
@@ -17,6 +17,8 @@ import {
   addReviewer,
 } from '../redux/createsubmission'
 
+export const submissionFileTypes = ['', 'figure', 'table', 'supplementary file']
+
 const toSubmit = (project, currentVersion, history) => dispatch => {
   const route = `/projects/${project.id}/versions/${currentVersion.id}/submit`
   history.push(route)
@@ -145,17 +147,17 @@ export function addManuscriptFiles(acceptedFiles) {
     this.props.currentVersion,
   )
 }
-export function deleteManuscriptFile(newFiles) {
+export function deleteManuscriptFile(removeFile) {
   this.props.newVersionDeleteFile(
-    newFiles,
+    removeFile,
     this.props.project,
     this.props.currentVersion,
   )
 }
-export function updateManuscriptFiles(newFiles) {
+export function updateManuscriptFiles(newFile) {
   this.setState({ status: 'Saving...' })
   this.props
-    .changeFiles(newFiles, this.props.project, this.props.currentVersion)
+    .changeFiles(newFile, this.props.project, this.props.currentVersion)
     .then(this.setState({ status: 'All changes saved.' }))
 }
 export function updateManuscriptGrants(grants) {
diff --git a/app/components/ui/atoms/Select.jsx b/app/components/ui/atoms/Select.jsx
index ac4fff18b..39166fe17 100644
--- a/app/components/ui/atoms/Select.jsx
+++ b/app/components/ui/atoms/Select.jsx
@@ -82,9 +82,7 @@ class Select extends React.Component {
       value = '',
       icon = 'chevrons_down',
       dropIcon: DropIcon = DefaultDropIcon,
-      options,
-      displayValues,
-      noValueOption,
+      options = [],
       inline,
       width,
       ...props
@@ -94,15 +92,18 @@ class Select extends React.Component {
         {label && <Label htmlFor={this.inputId}>{label}</Label>}
         <Dropdown>
           <DropdownText id={this.inputId} value={value} {...props}>
-            {noValueOption && <option>{noValueOption}</option>}
-            {options.map((option, t) => (
-              <option
-                key={Math.round(Math.random() * 1e12).toString(36)}
-                value={option}
-              >
-                {displayValues ? displayValues[t] : option}
-              </option>
-            ))}
+            {options.map(
+              opt =>
+                typeof opt === 'object' ? (
+                  <option key={opt.value} value={opt.value}>
+                    {opt.label}
+                  </option>
+                ) : (
+                  <option key={opt} value={opt}>
+                    {opt}
+                  </option>
+                ),
+            )}
           </DropdownText>
           <DropIcon icon={icon} />
         </Dropdown>
diff --git a/app/components/ui/atoms/Select.md b/app/components/ui/atoms/Select.md
index 1cd965447..a108a410e 100644
--- a/app/components/ui/atoms/Select.md
+++ b/app/components/ui/atoms/Select.md
@@ -35,64 +35,29 @@ initialState = {
 />
 ```
 
-You can provide an array of displayValues for your options, so the option "value" and the option label text shown to the user can be different.
+You can provide labels for your options, so the option value and the option label text shown to the user can be different.
 
 ```js
 initialState = { 
   value: '',
   options: [
-    '1',
-    '2',
-    '3'
-  ]
-  displayValues: [
-    'One week',
-    'Two weeks',
-    'Three weeks'
+    {
+      label: 'One week',
+      value: 1,
+    },
+    {
+      label: 'Two weeks',
+      value: 2,
+    },
+    {
+      label: 'Three weeks',
+      value: 3,
   ]
 }
 
 ;<Select
   label="How many weeks?"
   options={state.options}
-  displayValues={state.displayValues}
-  onChange={event => setState({ value: event.target.value })}
-/>
-```
-
-You can provide a "no value" first option, or an option that is just a label with no valid value, which can be blank to indicate the user has not selected anything, or used as the equivalent of a placeholder in a text imput.
-
-```js
-initialState = { 
-  value: '',
-  options: [
-    'one',
-    'two',
-    'three'
-  ]
-}
-
-;<Select
-  label="Select option"
-  options={state.options}
-  noValueOption=" "
-  onChange={event => setState({ value: event.target.value })}
-/>
-```
-```js
-initialState = { 
-  value: '',
-  options: [
-    'one',
-    'two',
-    'three'
-  ]
-}
-
-;<Select
-  label="Select option"
-  options={state.options}
-  noValueOption="Click to select option from list"
   onChange={event => setState({ value: event.target.value })}
 />
 ```
diff --git a/app/redux/createsubmission.js b/app/redux/createsubmission.js
index 0e4b3eeae..34017bd1b 100644
--- a/app/redux/createsubmission.js
+++ b/app/redux/createsubmission.js
@@ -119,25 +119,18 @@ export const uploadManuscript = (
       source,
       ...otherProps
     } = currentVersion
-    let newFiles = {}
+    let newFiles = []
     const newManuscript = {
-      name: inputFile.name,
+      filename: inputFile.name,
       url: fileURL,
       size: inputFile.size,
       mimeType: inputFile.type,
       type: 'manuscript',
     }
     if (files) {
-      const { manuscript, ...otherFiles } = files
-      newFiles = {
-        manuscript: newManuscript,
-        ...otherFiles,
-      }
-    } else {
-      newFiles = {
-        manuscript: newManuscript,
-      }
+      newFiles = files.filter(file => file.type !== 'manuscript')
     }
+    newFiles.push(newManuscript)
     dispatch(
       actions.createFragment(project, {
         created: new Date(), // TODO: set on server
@@ -203,8 +196,7 @@ export const addFiles = (
 ) => dispatch => {
   dispatch(uploadManuscriptRequest())
   const { files, ...otherProps } = currentVersion
-  const { supplementary = [], ...otherFiles } = files
-  const originalLength = supplementary.length
+  const originalLength = files.length
   acceptedFiles.forEach(file => {
     if (!FileTypes.includes(file.type)) {
       throw new Error(`${file.name} is not in an allowed file type.`)
@@ -220,21 +212,18 @@ export const addFiles = (
         throw new Error(`There was an error uploading the file ${file.name}`)
       }
       const fileURL = request.responseText
-      supplementary.push({
-        name: file.name,
+      files.push({
+        filename: file.name,
         url: fileURL,
         size: file.size,
         mimeType: file.type,
       })
-      if (supplementary.length - originalLength === acceptedFiles.length) {
+      if (files.length - originalLength === acceptedFiles.length) {
         return dispatch(
           actions.updateFragment(project, {
             id: currentVersion.id,
             rev: currentVersion.rev,
-            files: {
-              ...otherFiles,
-              supplementary,
-            },
+            files,
             ...otherProps,
           }),
         ).then(() => {
@@ -246,12 +235,18 @@ export const addFiles = (
 }
 
 export const changeFiles = (
-  newFiles,
+  newFile,
   project,
   currentVersion,
   history,
 ) => dispatch => {
   const { files, ...other } = currentVersion
+  const newFiles = files.map(file => {
+    if (file.url === newFile.url) {
+      return newFile
+    }
+    return file
+  })
   return dispatch(
     actions.updateFragment(project, {
       id: currentVersion.id,
@@ -332,12 +327,13 @@ export const addReviewer = (
 }
 
 export const newVersionDeleteFile = (
-  newFiles,
+  removeFile,
   project,
   currentVersion,
   history,
 ) => dispatch => {
   const { id, created, fragmentType, version, files, ...other } = currentVersion
+  const newFiles = files.filter(file => file.url !== removeFile.url)
   dispatch(
     actions.createFragment(project, {
       created: new Date(), // TODO: set on server
diff --git a/config/validations.js b/config/validations.js
index ca2ed6924..18757d884 100644
--- a/config/validations.js
+++ b/config/validations.js
@@ -83,35 +83,16 @@ module.exports = {
           opposed: Joi.array().items(Joi.string().allow('')),
         }),
       }),
-      files: Joi.object({
-        manuscript: Joi.object({
-          name: Joi.string().required(),
-          size: Joi.number(),
-          mimeType: Joi.string().required(),
-          url: Joi.string().required(),
+      files: Joi.array().items(
+        Joi.object({
           type: Joi.string(),
+          label: Joi.string(),
+          filename: Joi.string().required(),
+          url: Joi.string().required(),
+          mimeType: Joi.string().required(),
+          size: Joi.number(),
         }),
-        supplementary: Joi.array().items(
-          Joi.object({
-            name: Joi.string().required(),
-            size: Joi.number(),
-            mimeType: Joi.string().required(),
-            url: Joi.string().required(),
-            type: Joi.string(),
-            label: Joi.string(),
-          }),
-        ),
-        xml: Joi.array().items(
-          Joi.object({
-            name: Joi.string().required(),
-            size: Joi.number(),
-            mimeType: Joi.string().required(),
-            url: Joi.string().required(),
-            type: Joi.string(),
-            label: Joi.string(),
-          }),
-        ),
-      }),
+      ),
       notes: Joi.object({
         fundingAcknowledgement: Joi.string(),
         specialInstructions: Joi.string().allow(''),
diff --git a/server/bulk/api.js b/server/bulk/api.js
index 835b03809..8cbde66b5 100644
--- a/server/bulk/api.js
+++ b/server/bulk/api.js
@@ -433,7 +433,6 @@ function updateFragment(
   const url = `${pubsweetServer}/api/collections/${manId}/fragments/${
     fragment.id
   }`
-
   const {
     id,
     created,
@@ -444,45 +443,14 @@ function updateFragment(
     ...otherProps
   } = fragment
 
-  let newFiles = {}
-  for (let i = 0; i < fileObjects.length; i += 1) {
-    const fileObject = fileObjects[i]
-    if (fileObject.fileType === 'manuscript') {
-      const newFile = {
-        name: fileObject.filename,
-        url: fileObject.fileURI,
-        size: fileObject.fileSize,
-        type: fileObject.fileType,
-        mimeType: fileObject.mimeType,
-      }
-      newFiles = {
-        manuscript: newFile,
-      }
-    } else {
-      const newFile = {
-        name: fileObject.filename,
-        url: fileObject.fileURI,
-        size: fileObject.fileSize,
-        type: fileObject.fileType,
-        label: fileObject.label,
-        mimeType: fileObject.mimeType,
-      }
-      const { manuscript, ...otherFiles } = newFiles
-      if (otherFiles.supplementary) {
-        otherFiles.supplementary.push(newFile)
-        newFiles = {
-          manuscript,
-          ...otherFiles,
-        }
-      } else {
-        const newFilesArray = [newFile]
-        newFiles = {
-          manuscript,
-          supplementary: newFilesArray,
-        }
-      }
-    }
-  }
+  const newFiles = fileObjects.map(fileObject => ({
+    filename: fileObject.filename,
+    url: fileObject.fileURI,
+    size: fileObject.fileSize,
+    type: fileObject.fileType,
+    label: fileObject.label,
+    mimeType: fileObject.mimeType,
+  }))
   const newFragment = {
     created,
     fragmentType: 'version',
@@ -552,33 +520,32 @@ function createManuscript(pubsweetServer, manuscript, token) {
 }
 
 function convertFromInk(pubsweetServer, parsedInfo, token) {
-  for (let i = 0; i < parsedInfo.files.length; i += 1) {
-    const fileObject = parsedInfo.files[i]
-    if (
-      fileObject.type === 'manuscript' &&
-      fileObject.filename.endsWith('.docx')
-    ) {
-      const url = `${pubsweetServer}/api/ink?recipe=editoria-typescript`
-      const form = new FormData()
-
-      const readStream = fs.createReadStream(fileObject.fileURI)
-      form.append('file', readStream)
-      return new Promise((resolve, reject) => {
-        fetch(url, {
-          method: 'POST',
-          headers: {
-            Accept: 'application/json',
-            Authorization: `Bearer ${token}`,
-          },
-          body: form,
-        })
-          .then(response => response.json())
-          .then(data => resolve(data.converted))
-          .catch(err => {
-            reject(err)
-          })
+  const manuscript = parsedInfo.files.find(file => file.type === 'manuscript')
+  if (
+    manuscript &&
+    manuscript.mimeType ===
+      'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
+  ) {
+    const url = `${pubsweetServer}/api/ink?recipe=editoria-typescript`
+    const form = new FormData()
+
+    const readStream = fs.createReadStream(manuscript.fileURI)
+    form.append('file', readStream)
+    return new Promise((resolve, reject) => {
+      fetch(url, {
+        method: 'POST',
+        headers: {
+          Accept: 'application/json',
+          Authorization: `Bearer ${token}`,
+        },
+        body: form,
       })
-    }
+        .then(response => response.json())
+        .then(data => resolve(data.converted))
+        .catch(err => {
+          reject(err)
+        })
+    })
   }
 }
 
-- 
GitLab