diff --git a/Automation/src/test/java/CreateAccounts.java b/Automation/src/test/java/CreateAccounts.java
index 6b02b0bc624df2120461c91c0d82dfd162bd4385..1f355202351239db98617d21a86a34a6354ebba6 100644
--- a/Automation/src/test/java/CreateAccounts.java
+++ b/Automation/src/test/java/CreateAccounts.java
@@ -55,7 +55,7 @@ public class CreateAccounts {
 
 
         try {
-            wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("button[data-test='new-manuscript']")));
+            wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("button[data-test-id='new-manuscript']")));
         } catch (NoSuchElementException e) {
             System.out.println(e.toString());
         }
@@ -110,7 +110,7 @@ public class CreateAccounts {
 
 
         try {
-            wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("button[data-test='new-manuscript']")));
+            wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("button[data-test-id='new-manuscript']")));
         } catch (NoSuchElementException e) {
             System.out.println(e.toString());
         }
@@ -170,12 +170,12 @@ public class CreateAccounts {
         driver.findElement(By.cssSelector("button[type=submit]")).click();
 
         try {
-            wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("button[data-test='button-add-user']")));
+            wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("button[data-test-id='button-add-user']")));
         } catch (NoSuchElementException e) {
             System.out.println(e.toString());
         }
 
         assertEquals(URL + "admin/users", driver.getCurrentUrl() );
-        assertEquals("  Add User", driver.findElement(By.cssSelector("button[data-test='button-add-user']")).getText());
+        assertEquals("  Add User", driver.findElement(By.cssSelector("button[data-test-id='button-add-user']")).getText());
     }
 }
diff --git a/Automation/src/test/java/LoginTest.java b/Automation/src/test/java/LoginTest.java
index 99e83fb74708a01b70e64082ad1176501dac8828..d64542498ef12a79e85a8e6aee0af7bb4c36e92a 100644
--- a/Automation/src/test/java/LoginTest.java
+++ b/Automation/src/test/java/LoginTest.java
@@ -48,7 +48,7 @@ public class LoginTest {
         WebElement validLogin = null;
 
         try {
-          validLogin = wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("button[data-test='new-manuscript']")));
+          validLogin = wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("button[data-test-id='new-manuscript']")));
         } catch (NoSuchElementException e) {
 
         }
diff --git a/Automation/src/test/java/ManuscriptFlow.java b/Automation/src/test/java/ManuscriptFlow.java
index b51ad5808addd9f38ff1eb3609605848daf59e05..2b0351604eec583d58ae59e67442d8dfbe5b8fc9 100644
--- a/Automation/src/test/java/ManuscriptFlow.java
+++ b/Automation/src/test/java/ManuscriptFlow.java
@@ -78,12 +78,12 @@ public class ManuscriptFlow {
         driver.findElement(By.cssSelector("button[data-test-id='new-manuscript']")).click();
 
         try {
-            wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("button[data-test='submission-next']")));
+            wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("button[data-test-id='submission-next']")));
         } catch (NoSuchElementException e) {
 
         }
 
-        assertNotNull(driver.findElement(By.cssSelector("button[data-test='submission-next']")));
+        assertNotNull(driver.findElement(By.cssSelector("button[data-test-id='submission-next']")));
 
         // First step submission flow
 
@@ -91,7 +91,7 @@ public class ManuscriptFlow {
 
         Utils.scrollToElement(driver, subButton);
         driver.findElement(By.cssSelector("[data-test-id='agree-checkbox']")).click();
-        subButton.click();
+        driver.findElement(By.cssSelector("button[data-test-id='submission-next']")).click();
 
         // Second step submission flow
         try {
@@ -148,12 +148,12 @@ public class ManuscriptFlow {
         element1.click();
 
         try {
-            wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("button[data-test='submission-next']")));
+            wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("button[data-test-id='submission-next']")));
         } catch (NoSuchElementException e) {
 
         }
 
-        WebElement element2 = driver.findElement(By.cssSelector("button[data-test='submission-next']"));
+        WebElement element2 = driver.findElement(By.cssSelector("button[data-test-id='submission-next']"));
 
         Utils.scrollToElement(driver, element2);
         element2.click();
@@ -178,16 +178,19 @@ public class ManuscriptFlow {
         manuscriptId = Utils.mID(mURL);
         projectId = Utils.pID(mURL);
 
-        driver.findElement(By.cssSelector(/*"[data-test='upload-manuscripts']*/"input[type=\"file\"]")).sendKeys(Constants.fileManuscript);
-//        driver.findElement(By.cssSelector(/*"[data-test='upload-supplementary']*/ "input[type=\"file\"]")).sendKeys(Constants.fileSupplementary);
-//        driver.findElement(By.cssSelector("[data-test='upload-coverLetter'] input[type=\"file\"]")).sendKeys(Constants.fileCoverLetter);
+        driver.findElement(By.cssSelector(/*"[data-test-id='upload-manuscripts']*/"input[type=\"file\"]")).sendKeys(Constants.fileManuscript);
+//        driver.findElement(By.cssSelector("[data-test-id='upload-supplementary'] input[type=\"file\"]")).sendKeys(Constants.fileSupplementary);
+//        driver.findElement(By.cssSelector("[data-test-id='upload-coverLetter'] input[type=\"file\"]")).sendKeys(Constants.fileCoverLetter);
 
         try {
-            wait.until(ExpectedConditions.visibilityOf(driver.findElement(By.cssSelector("//span[text()='Progress Saved']"))));
+            wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("button[data-test-id='submission-next']")));
         } catch (NoSuchElementException e) {
 
         }
 
+        // Confirmation modal
+        WebElement element3 = driver.findElement(By.cssSelector("button[data-test-id='submission-next']"));
+
         try {
             wait.until(ExpectedConditions.visibilityOf(driver.findElement(By.cssSelector("[data-test='submission-next']"))));
         } catch (NoSuchElementException e) {
diff --git a/Automation/target/test-classes/Constants.class b/Automation/target/test-classes/Constants.class
new file mode 100644
index 0000000000000000000000000000000000000000..68f5d0974f805591d39f78d43fde36cc9337ebf7
Binary files /dev/null and b/Automation/target/test-classes/Constants.class differ
diff --git a/Automation/target/test-classes/CreateAuthor.class b/Automation/target/test-classes/CreateAuthor.class
new file mode 100644
index 0000000000000000000000000000000000000000..d1e3a30e0b3dccaf6b734477f1b6e5c13d401eb5
Binary files /dev/null and b/Automation/target/test-classes/CreateAuthor.class differ
diff --git a/Automation/target/test-classes/LoginTest.class b/Automation/target/test-classes/LoginTest.class
new file mode 100644
index 0000000000000000000000000000000000000000..65f092122d8b7d9c91c03fb301a44ce88bab4701
Binary files /dev/null and b/Automation/target/test-classes/LoginTest.class differ
diff --git a/Automation/target/test-classes/Utils.class b/Automation/target/test-classes/Utils.class
new file mode 100644
index 0000000000000000000000000000000000000000..6aef2c6abc7823d9e0e968ba0d1661279fcbea9f
Binary files /dev/null and b/Automation/target/test-classes/Utils.class differ
diff --git a/packages/component-faraday-selectors/src/index.js b/packages/component-faraday-selectors/src/index.js
index 424a53188c3058b27cd8a94af0fb92d34112611a..243136915cb994367d43744fa0c2822263679761 100644
--- a/packages/component-faraday-selectors/src/index.js
+++ b/packages/component-faraday-selectors/src/index.js
@@ -366,4 +366,14 @@ export const canMakeRecommendation = (state, collection, fragment = {}) => {
   const status = get(collection, 'status', 'draft')
   return isHE && canMakeRecommendationStatuses.includes(status)
 }
+
+export const canSubmitRevision = (state, collection, fragment) => {
+  const userId = get(state, 'currentUser.user.id')
+  const fragmentAuthors = chain(fragment)
+    .get('authors', [])
+    .map(a => a.id)
+    .value()
+
+  return get(fragment, 'revision', null) && fragmentAuthors.includes(userId)
+}
 // #endregion
diff --git a/packages/component-faraday-ui/src/AppBarMenu.js b/packages/component-faraday-ui/src/AppBarMenu.js
index 3a3a93ba7b682469bdcd67ff340efc3ebf8996f7..a4dd501c94d504b33d7273fa54f6d17df17d9d25 100644
--- a/packages/component-faraday-ui/src/AppBarMenu.js
+++ b/packages/component-faraday-ui/src/AppBarMenu.js
@@ -23,21 +23,31 @@ const AppBarMenu = ({
 }) =>
   currentUser.user ? (
     <Root>
-      <User onClick={toggleMenu}>
+      <User data-test-id="admin-menu-button" onClick={toggleMenu}>
         <Text>{username}</Text>
         <Icon secondary size={2}>
           {expanded ? 'chevron-up' : 'chevron-down'}
         </Icon>
       </User>
       {expanded && (
-        <Dropdown>
+        <Dropdown data-test-id="admin-menu-dropdown">
           {currentUser.user.admin && (
-            <DropdownOption onClick={goTo('/admin')}>
+            <DropdownOption
+              data-test-id="admin-dropdown-dashboard"
+              onClick={goTo('/admin')}
+            >
               Admin Dashboard
             </DropdownOption>
           )}
-          <DropdownOption onClick={goTo('/profile')}>My Profile</DropdownOption>
-          <DropdownOption onClick={logout}>Logout</DropdownOption>
+          <DropdownOption
+            data-test-id="admin-dropdown-profile"
+            onClick={goTo('/profile')}
+          >
+            My Profile
+          </DropdownOption>
+          <DropdownOption data-test-id="admin-dropdown-logout" onClick={logout}>
+            Logout
+          </DropdownOption>
         </Dropdown>
       )}
       {expanded && <ToggleOverlay onClick={toggleMenu} />}
diff --git a/packages/component-faraday-ui/src/AuthorCard.js b/packages/component-faraday-ui/src/AuthorCard.js
index bb4112cc6cb8edb64be1702b5132d208737f6dc7..2ace7fa985268bb535cdeff598a1a5ac7a030433 100644
--- a/packages/component-faraday-ui/src/AuthorCard.js
+++ b/packages/component-faraday-ui/src/AuthorCard.js
@@ -39,14 +39,14 @@ const AuthorTitle = ({
   formSubmitting,
   toggleEditMode,
   isCorresponding,
-  isAuthorsFetching,
 }) => (
   <Fragment>
     {!editMode ? (
       <Fragment>
         {!isSubmitting && (
           <OpenModal
-            isFetching={isAuthorsFetching}
+            isFetching={isFetching}
+            modalKey="deleteAuthor"
             onConfirm={deleteAuthor}
             subtitle={`${get(author, 'firstName', '')} ${get(
               author,
@@ -78,6 +78,7 @@ const AuthorTitle = ({
     ) : (
       <Fragment>
         <IconButton
+          data-test-id="author-card-cancel"
           icon="x-circle"
           iconSize={2}
           onClick={toggleEditMode}
@@ -90,6 +91,7 @@ const AuthorTitle = ({
           </StyledSpinner>
         ) : (
           <IconButton
+            data-test-id="author-card-save"
             disabled={formSubmitting}
             icon="check-circle"
             iconSize={2}
@@ -218,6 +220,7 @@ const EnhancedAuthorEdit = compose(
 const Author = ({
   author,
   listIndex,
+  isFetching,
   isAuthorEdit,
   deleteAuthor,
   toggleEditMode,
@@ -230,6 +233,7 @@ const Author = ({
       isAuthorEdit={isAuthorEdit}
       isAuthorsFetching={isAuthorsFetching}
       isCorresponding={author.isCorresponding}
+      isFetching={isFetching}
       isSubmitting={author.isSubmitting}
       listIndex={listIndex}
       toggleEditMode={toggleEditMode}
@@ -275,6 +279,7 @@ const AuthorCard = ({
         editMode={editMode}
         isAuthorEdit={isAuthorEdit}
         isAuthorsFetching={isAuthorsFetching}
+        isFetching={isFetching}
         listIndex={index}
         toggleEditMode={toggleEdit(index)}
       />
diff --git a/packages/component-faraday-ui/src/FileSection.js b/packages/component-faraday-ui/src/FileSection.js
index 0da010405bfdf934b7c65ee88d17d44e89849397..596f65e8436d8362ab1fdf506c1f5b1dd822071c 100644
--- a/packages/component-faraday-ui/src/FileSection.js
+++ b/packages/component-faraday-ui/src/FileSection.js
@@ -44,7 +44,7 @@ const FileSection = ({
   connectDropTarget,
   allowedFileExtensions,
   files = [],
-  onFilePick = () => {},
+  onFilePick,
   onPreview,
   onDownload,
   onDelete,
diff --git a/packages/component-faraday-ui/src/InviteReviewers.js b/packages/component-faraday-ui/src/InviteReviewers.js
index 94ce84bf2e74299f42d21386418e181c0fd527ce..7c93ebb316f9a1d7a10c664548a6ee94c6864cdd 100644
--- a/packages/component-faraday-ui/src/InviteReviewers.js
+++ b/packages/component-faraday-ui/src/InviteReviewers.js
@@ -23,10 +23,20 @@ const InviteReviewers = ({ countries, handleSubmit, reset }) => (
     <Row justify="space-between" mb={2}>
       <H4>Invite reviewer</H4>
       <Item justify="flex-end">
-        <Button onClick={reset} size="small">
+        <Button
+          data-type-id="button-invite-reviewer-clear-fields"
+          onClick={reset}
+          size="small"
+        >
           Clear Fields
         </Button>
-        <Button ml={2} onClick={handleSubmit} primary size="small">
+        <Button
+          data-type-id="button-invite-reviewer-invite"
+          ml={2}
+          onClick={handleSubmit}
+          primary
+          size="small"
+        >
           Invite
         </Button>
       </Item>
@@ -36,6 +46,7 @@ const InviteReviewers = ({ countries, handleSubmit, reset }) => (
         <Label required>Email</Label>
         <ValidatedField
           component={TextField}
+          data-test-id="invite-reviewer-email"
           name="email"
           validate={[required, validators.emailValidator]}
         />
@@ -44,6 +55,7 @@ const InviteReviewers = ({ countries, handleSubmit, reset }) => (
         <Label required>First Name</Label>
         <ValidatedField
           component={TextField}
+          data-test-id="invite-reviewer-first-name"
           name="firstName"
           validate={[required]}
         />
@@ -52,6 +64,7 @@ const InviteReviewers = ({ countries, handleSubmit, reset }) => (
         <Label required>Last Name</Label>
         <ValidatedField
           component={TextField}
+          data-test-id="invite-reviewer-last-name"
           name="lastName"
           validate={[required]}
         />
@@ -60,6 +73,7 @@ const InviteReviewers = ({ countries, handleSubmit, reset }) => (
         <Label required>Affiliation</Label>
         <ValidatedField
           component={TextField}
+          data-test-id="invite-reviewer-affiliation"
           name="affiliation"
           validate={[required]}
         />
diff --git a/packages/component-faraday-ui/src/RadioWithComments.js b/packages/component-faraday-ui/src/RadioWithComments.js
index b11595c361030e3a93b05645666c0f799db827f8..785149e94c2ca25bd7bc8b0ee30f21eb5e9b286f 100644
--- a/packages/component-faraday-ui/src/RadioWithComments.js
+++ b/packages/component-faraday-ui/src/RadioWithComments.js
@@ -40,7 +40,12 @@ const RadioWithComments = ({
       </Item>
     </Row>
 
-    <Row alignItems="center" justify="flex-start" mb={1}>
+    <Row
+      alignItems="center"
+      data-test-id={`submission-yes-or-no-${radioFieldName}`}
+      justify="flex-start"
+      mb={1}
+    >
       <Field
         component={({ input }) => <YesOrNo {...input} />}
         name={radioFieldName}
@@ -49,7 +54,7 @@ const RadioWithComments = ({
 
     {get(formValues, radioFieldName, '') === commentsOn && (
       <RowOverrideAlert alignItems="center" justify="flex-start">
-        <Item data-test="submission-conflicts-text" vertical>
+        <Item data-test-id="submission-conflicts-text" vertical>
           {commentsSubtitle && (
             <Text secondary>
               {commentsSubtitle}
diff --git a/packages/component-faraday-ui/src/WizardAuthors.js b/packages/component-faraday-ui/src/WizardAuthors.js
index 7ea00f08d3c6b3118b2db4edbcd84bb152977f6a..b9dbdcf9a3f93948130124018c7777d1173b643e 100644
--- a/packages/component-faraday-ui/src/WizardAuthors.js
+++ b/packages/component-faraday-ui/src/WizardAuthors.js
@@ -58,23 +58,23 @@ const WizardAuthors = ({
   error,
   journal,
   moveAuthor,
+  isFetching,
   authors = [],
   isAuthorEdit,
   deleteAuthor,
   addNewAuthor,
   setAuthorEdit,
   saveNewAuthor,
-  isAuthorsFetching,
   editExistingAuthor,
   authorEditorSubmit,
-  isFetching,
 }) => (
   <Fragment>
     <Row alignItems="center" justify="flex-start">
       <Item>
         <Label>Authors</Label>
         <ActionLink
-          data-test-id="add-author"
+          data-test-id="submission-add-author"
+          disabled={isAuthorEdit}
           icon="plus"
           onClick={addNewAuthor}
         >
@@ -103,7 +103,6 @@ const WizardAuthors = ({
           dragHandle={DragHandle}
           editExistingAuthor={editExistingAuthor}
           isAuthorEdit={isAuthorEdit}
-          isAuthorsFetching={isAuthorsFetching}
           isFetching={isFetching}
           itemKey="id"
           items={authors}
@@ -131,11 +130,12 @@ export default compose(
       setAuthors,
       setFetching,
       onAuthorEdit,
+      formName = 'submission',
     }) => authors => {
       setAuthors(authors)
       setFetching(false)
-      onAuthorEdit(null)
-      changeForm('submission', 'authors', authors)
+      typeof onAuthorEdit === 'function' && onAuthorEdit(null)
+      changeForm(formName, 'authors', authors)
     },
   }),
   withHandlers({
@@ -143,7 +143,7 @@ export default compose(
       if (authors.some(a => a.id === 'newAuthor')) {
         return
       }
-      onAuthorEdit(0)
+      typeof onAuthorEdit === 'function' && onAuthorEdit(0)
       setAuthors([
         ...authors,
         { id: 'newAuthor', isCorresponding: false, isSubmitting: false },
@@ -153,7 +153,7 @@ export default compose(
       setFormAuthors(SortableList.moveItem(authors, dragIndex, hoverIndex))
     },
     setAuthorEdit: ({ authors, setAuthors, onAuthorEdit }) => index => {
-      onAuthorEdit(index)
+      typeof onAuthorEdit === 'function' && onAuthorEdit(index)
       setAuthors(authors.filter(a => a.id !== 'newAuthor'))
     },
     saveNewAuthor: ({ authors, setFormAuthors }) => author => {
@@ -170,41 +170,52 @@ export default compose(
     },
     deleteAuthor: ({
       authors,
-      project,
-      version,
+      fragment,
+      collection,
+      setFetching,
       deleteAuthor,
       setFormAuthors,
-    }) => author => ({ hideModal, setModalError }) =>
-      deleteAuthor(project.id, version.id, author.id)
+    }) => author => ({ hideModal, setModalError }) => {
+      setFetching(true)
+      return deleteAuthor({
+        authorId: author.id,
+        fragmentId: fragment.id,
+        collectionId: collection.id,
+      })
         .then(() => {
+          setFetching(false)
           const newAuthors = setCorrespondingAuthor(
             authors.filter(a => a.id !== author.id),
           )
           setFormAuthors(newAuthors)
           hideModal()
         })
-        .catch(handleError(setModalError)),
+        .catch(err => {
+          setFetching(false)
+          handleError(setModalError)(err)
+        })
+    },
   }),
   withHandlers({
     authorEditorSubmit: ({
       authors,
-      project,
-      version,
+      fragment,
       addAuthor,
+      collection,
       setFetching,
       saveNewAuthor,
       editExistingAuthor,
     }) => (values, dispatch, { toggleEditMode }) => {
       if (values.id === 'newAuthor') {
         setFetching(true)
-        return addAuthor(
-          {
+        return addAuthor({
+          fragmentId: fragment.id,
+          collectionId: collection.id,
+          author: {
             ...omit(values, 'id'),
             isSubmitting: authors.length === 1,
           },
-          project.id,
-          version.id,
-        ).then(saveNewAuthor)
+        }).then(saveNewAuthor)
       }
       editExistingAuthor(values)
       setTimeout(toggleEditMode, 10)
diff --git a/packages/component-faraday-ui/src/WizardFiles.js b/packages/component-faraday-ui/src/WizardFiles.js
index 5c08242dd168384602c091f6b982435afd147169..9bd0591a7ff21c8ca020583682a8130d7b9da290 100644
--- a/packages/component-faraday-ui/src/WizardFiles.js
+++ b/packages/component-faraday-ui/src/WizardFiles.js
@@ -69,19 +69,29 @@ const WizardFiles = ({
   </Fragment>
 )
 
+const initialFiles = {
+  manuscripts: [],
+  coverLetter: [],
+  supplementary: [],
+}
+
 export default compose(
   withFilePreview,
   withFileDownload,
-  withState('files', 'setFiles', ({ files }) => files),
+  withState('files', 'setFiles', ({ files = initialFiles }) => files),
   withState('fetching', 'setFilesFetching', {
     manuscripts: false,
     coverLetter: false,
     supplementary: false,
   }),
   withHandlers({
-    setFormFiles: ({ changeForm, setFiles }) => files => {
+    setFormFiles: ({
+      setFiles,
+      changeForm,
+      formName = 'submission',
+    }) => files => {
       setFiles(files)
-      changeForm('submission', 'files', files)
+      changeForm(formName, 'files', files)
     },
     setFilesFetching: ({ setFilesFetching }) => (type, value) => {
       setFilesFetching(p => ({
@@ -93,13 +103,13 @@ export default compose(
   withHandlers({
     addFile: ({
       files,
-      version,
+      fragment,
       uploadFile,
       setFormFiles,
       setFilesFetching,
     }) => type => file => {
       setFilesFetching(type, true)
-      uploadFile({ file, type, fragment: version })
+      uploadFile({ file, type, fragment })
         .then(f => {
           const newFiles = {
             ...files,
@@ -112,17 +122,16 @@ export default compose(
           setFilesFetching(type, false)
         })
     },
-    downloadFile: ({ downloadFile, token }) => file => {
-      downloadFile(file)
-    },
+    previewFile: ({ previewFile }) => previewFile,
+    downloadFile: ({ downloadFile, token }) => downloadFile,
     deleteFile: ({
-      deleteFile,
       files,
+      deleteFile,
       setFormFiles,
       setFilesFetching,
     }) => type => file => {
       setFilesFetching(type, true)
-      deleteFile(file.id, type)
+      deleteFile({ fileId: file.id, type })
         .then(() => {
           const newFiles = {
             ...files,
@@ -142,9 +151,6 @@ export default compose(
       }
       setFormFiles(newFiles)
     },
-    previewFile: ({ previewFile }) => file => {
-      previewFile(file)
-    },
     changeList: ({ files, setFormFiles }) => (from, to, fileId) => {
       const swappedFile = files[from].find(f => f.id === fileId)
 
diff --git a/packages/component-faraday-ui/src/contextualBoxes/AssignHE.js b/packages/component-faraday-ui/src/contextualBoxes/AssignHE.js
index c449426ad91a4c5d541c75a602250c2dad27d2f9..c65487c70d9df515d6ec66f630bbef8b429d6eac 100644
--- a/packages/component-faraday-ui/src/contextualBoxes/AssignHE.js
+++ b/packages/component-faraday-ui/src/contextualBoxes/AssignHE.js
@@ -32,6 +32,7 @@ const AssignHE = ({
   <Root pb={2}>
     <TextContainer>
       <TextField
+        data-test-id="manuscript-assign-he-filter"
         onChange={changeSearch}
         placeholder="Filter by name or email"
         value={searchValue}
@@ -60,6 +61,7 @@ const AssignHE = ({
         {handlingEditors.map((he, index) => (
           <CustomRow
             alignItems="center"
+            data-test-id={`manuscript-assign-he-invite-${he.id}`}
             height={4}
             isFirst={index === 0}
             key={he.id}
diff --git a/packages/component-faraday-ui/src/contextualBoxes/HERecommendation.js b/packages/component-faraday-ui/src/contextualBoxes/HERecommendation.js
index e5143cfe49b9d9a77998fa1b3f9286355cb5d1d5..877243b16fc5e34b2cc9b4ccb2593124c031624e 100644
--- a/packages/component-faraday-ui/src/contextualBoxes/HERecommendation.js
+++ b/packages/component-faraday-ui/src/contextualBoxes/HERecommendation.js
@@ -73,7 +73,11 @@ const HERecommendation = ({
   >
     <Root>
       <Row justify="flex-start">
-        <ItemOverrideAlert flex={0} vertical>
+        <ItemOverrideAlert
+          data-test-id="editorial-recommendation-choose-options"
+          flex={0}
+          vertical
+        >
           <Label required>Recommendation</Label>
           <ValidatedField
             component={input => (
@@ -91,7 +95,11 @@ const HERecommendation = ({
       {get(formValues, 'recommendation') === 'minor' ||
       get(formValues, 'recommendation') === 'major' ? (
         <Row mt={2}>
-          <ResponsiveItem mr={1} vertical>
+          <ResponsiveItem
+            data-test-id="editorial-recommendation-message-for-author"
+            mr={1}
+            vertical
+          >
             <Label>
               Message for Author <Text secondary>Optional</Text>
             </Label>
@@ -100,14 +108,22 @@ const HERecommendation = ({
         </Row>
       ) : (
         <ResponsiveRow mt={2}>
-          <ResponsiveItem mr={1} vertical>
+          <ResponsiveItem
+            data-test-id="editorial-recommendation-message-for-author"
+            mr={1}
+            vertical
+          >
             <Label>
               Message for Author <Text secondary>Optional</Text>
             </Label>
             <ValidatedField component={Textarea} name="public" />
           </ResponsiveItem>
 
-          <ResponsiveItem ml={1} vertical>
+          <ResponsiveItem
+            data-test-id="editorial-recommendation-message-for-eic"
+            ml={1}
+            vertical
+          >
             <Label>
               Message for Editor in Chief <Text secondary>Optional</Text>
             </Label>
@@ -117,7 +133,12 @@ const HERecommendation = ({
       )}
 
       <Row justify="flex-end" mt={2}>
-        <Button onClick={handleSubmit} primary size="medium">
+        <Button
+          data-test-id="button-editorial-recommendation-submit"
+          onClick={handleSubmit}
+          primary
+          size="medium"
+        >
           {
             options.find(
               o => o.value === get(formValues, 'recommendation', 'publish'),
diff --git a/packages/component-faraday-ui/src/contextualBoxes/ReviewerDetails.js b/packages/component-faraday-ui/src/contextualBoxes/ReviewerDetails.js
index 8e242820b8a3077267b79efe84b7355b6d7029d0..232c2798046f6b1d50feba48c94b8d46a4ba3066 100644
--- a/packages/component-faraday-ui/src/contextualBoxes/ReviewerDetails.js
+++ b/packages/component-faraday-ui/src/contextualBoxes/ReviewerDetails.js
@@ -57,6 +57,7 @@ const ReviewerDetails = ({
           <Fragment>
             <TabsHeader>
               <TabButton
+                data-test-id="reviewer-tab-details"
                 ml={1}
                 mr={1}
                 onClick={() => changeTab(0)}
@@ -66,6 +67,7 @@ const ReviewerDetails = ({
               </TabButton>
               {canInviteReviewers && (
                 <TabButton
+                  data-test-id="reviewer-tab-suggestions"
                   ml={1}
                   mr={1}
                   onClick={() => changeTab(2)}
@@ -75,6 +77,7 @@ const ReviewerDetails = ({
                 </TabButton>
               )}
               <TabButton
+                data-test-id="reviewer-tab-reports"
                 ml={1}
                 mr={1}
                 onClick={() => changeTab(1)}
diff --git a/packages/component-faraday-ui/src/contextualBoxes/ReviewerReportForm.js b/packages/component-faraday-ui/src/contextualBoxes/ReviewerReportForm.js
index cd568ff1c9afd710040804d97e8e1d7988c5b17d..7e98eef25418e5b6cfdf9c0050568ee58b87b1fa 100644
--- a/packages/component-faraday-ui/src/contextualBoxes/ReviewerReportForm.js
+++ b/packages/component-faraday-ui/src/contextualBoxes/ReviewerReportForm.js
@@ -43,7 +43,11 @@ const ReviewerReportForm = ({
   >
     <Root>
       <Row justify="flex-start">
-        <ItemOverrideAlert flex={0} vertical>
+        <ItemOverrideAlert
+          data-test-id="form-report-recommendation"
+          flex={0}
+          vertical
+        >
           <Label required>Recommendation</Label>
           <ValidatedField
             component={input => <Menu {...input} options={recommendations} />}
@@ -53,7 +57,12 @@ const ReviewerReportForm = ({
         </ItemOverrideAlert>
       </Row>
 
-      <Row alignItems="center" justify="space-between" mt={1}>
+      <Row
+        alignItems="center"
+        data-test-id="form-report-upload-file"
+        justify="space-between"
+        mt={1}
+      >
         <Item>
           <Label required>Your report</Label>
           {!formValues.file && (
@@ -71,7 +80,7 @@ const ReviewerReportForm = ({
       </Row>
 
       <Row mb={1 / 2}>
-        <ItemOverrideAlert vertical>
+        <ItemOverrideAlert data-test-id="form-report-textarea" vertical>
           <ValidatedField component={Textarea} name="public" />
         </ItemOverrideAlert>
       </Row>
@@ -80,6 +89,7 @@ const ReviewerReportForm = ({
         <Row justify="flex-start" mb={1}>
           <Item flex={0}>
             <FileItem
+              data-test-id="form-report-file-item-actions"
               item={formValues.file}
               onDelete={removeFile}
               onDownload={downloadFile}
@@ -96,14 +106,18 @@ const ReviewerReportForm = ({
               <Label>Confidential note for the Editorial Team</Label>
             </Item>
             <Item justify="flex-end">
-              <ActionLink icon="x" onClick={removeNote}>
+              <ActionLink
+                data-test-id="form-report-remove-note"
+                icon="x"
+                onClick={removeNote}
+              >
                 Remove
               </ActionLink>
             </Item>
           </Fragment>
         ) : (
           <Item>
-            <ActionLink onClick={addNote}>
+            <ActionLink data-test-id="form-report-add-note" onClick={addNote}>
               Add Confidential note for the Editorial Team
             </ActionLink>
           </Item>
@@ -112,7 +126,10 @@ const ReviewerReportForm = ({
 
       {hasNote && (
         <Row>
-          <ItemOverrideAlert vertical>
+          <ItemOverrideAlert
+            data-test-id="textarea-form-report-add-note"
+            vertical
+          >
             <ValidatedField component={Textarea} name="confidential" />
           </ItemOverrideAlert>
         </Row>
@@ -128,7 +145,12 @@ const ReviewerReportForm = ({
         {isFetching ? (
           <Spinner />
         ) : (
-          <Button onClick={handleSubmit} primary size="medium">
+          <Button
+            data-test-id="button-submit-report"
+            onClick={handleSubmit}
+            primary
+            size="medium"
+          >
             Submit report
           </Button>
         )}
diff --git a/packages/component-faraday-ui/src/helpers/withCountries.js b/packages/component-faraday-ui/src/helpers/withCountries.js
index bd642eddd9bac3cd647a387b93179b957f9513da..fb72d5997d1270d94f7a11dd8325510a24034e1e 100644
--- a/packages/component-faraday-ui/src/helpers/withCountries.js
+++ b/packages/component-faraday-ui/src/helpers/withCountries.js
@@ -1,7 +1,7 @@
 import { withProps } from 'recompose'
 import countrylist from 'country-list'
 
-const countryMapper = c => {
+const countryMapper = (c = 'GB') => {
   switch (c) {
     case 'GB':
       return 'UK'
@@ -14,7 +14,7 @@ const countryMapper = c => {
   }
 }
 
-const codeMapper = c => {
+const codeMapper = (c = 'UK') => {
   switch (c) {
     case 'UK':
       return 'GB'
diff --git a/packages/component-faraday-ui/src/index.js b/packages/component-faraday-ui/src/index.js
index 263820a923f836e555affe74bed8bd51d6ea7b6d..a4feb94b3657fd39ecc004675bf70b84a544b20b 100644
--- a/packages/component-faraday-ui/src/index.js
+++ b/packages/component-faraday-ui/src/index.js
@@ -47,6 +47,8 @@ export { default as WizardFiles } from './WizardFiles'
 export { default as TextTooltip } from './TextTooltip'
 export { default as EditorialReportCard } from './EditorialReportCard'
 
+export { SubmitRevision } from './submissionRevision'
+
 export * from './OverrideAlert'
 export * from './manuscriptDetails'
 export * from './contextualBoxes'
diff --git a/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptDetailsTop.js b/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptDetailsTop.js
index 516a6ca9010541dc82558a0a29f46afbcf0d36cd..2564bf721c3db9d5cd719b699f1d18c57f319d5a 100644
--- a/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptDetailsTop.js
+++ b/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptDetailsTop.js
@@ -36,7 +36,7 @@ const ManuscriptDetailsTop = ({
     <Item alignItems="center" justify="flex-end">
       {canOverrideTechChecks && (
         <ActionLink
-          data-test-id={`button-qa-manuscript-${fragment.id}`}
+          data-test-id="button-qa-manuscript-technical-checks"
           icon="check-square"
           onClick={goToTechnicalCheck(collection)}
           pr={2}
@@ -46,7 +46,7 @@ const ManuscriptDetailsTop = ({
       )}
       {canEditManuscript && (
         <ActionLink
-          data-test-id={`button-qa-manuscript-${fragment.id}`}
+          data-test-id="button-qa-manuscript-edit"
           icon="edit"
           onClick={goToEdit(collection, fragment)}
           pr={2}
diff --git a/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptHeader.js b/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptHeader.js
index 268d7af507e41a54af7f5dd2088c905a7681d0ca..70c2afdd45b6ddaf6027801ad72a21902afed42c 100644
--- a/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptHeader.js
+++ b/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptHeader.js
@@ -146,7 +146,13 @@ export default compose(
 
       if (canAssignHE) {
         return (
-          <Button ml={1} onClick={inviteHE} primary size="small">
+          <Button
+            data-test-id="manuscript-invite-he-button"
+            ml={1}
+            onClick={inviteHE}
+            primary
+            size="small"
+          >
             Invite
           </Button>
         )
diff --git a/packages/component-faraday-ui/src/manuscriptDetails/ResponseToInvitation.js b/packages/component-faraday-ui/src/manuscriptDetails/ResponseToInvitation.js
index 7558e95eb92beb4ceeb8b13e1c504967b82c14f2..a638617e4a1adb041b45b48c310df51e95be1c29 100644
--- a/packages/component-faraday-ui/src/manuscriptDetails/ResponseToInvitation.js
+++ b/packages/component-faraday-ui/src/manuscriptDetails/ResponseToInvitation.js
@@ -47,7 +47,11 @@ const ResponseToInvitation = ({
         <Label required>{label}</Label>
         <ValidatedField
           component={input => (
-            <Row alignItems="center" justify="space-between">
+            <Row
+              alignItems="center"
+              data-test-id="radio-respond-to-invitation"
+              justify="space-between"
+            >
               <RadioGroup inline name="decision" options={options} {...input} />
               <Button
                 mb={1.7}
diff --git a/packages/component-faraday-ui/src/submissionRevision/DetailsAndAuthors.js b/packages/component-faraday-ui/src/submissionRevision/DetailsAndAuthors.js
new file mode 100644
index 0000000000000000000000000000000000000000..4b25942909135eec5dc15b08f14fe2d84162bf85
--- /dev/null
+++ b/packages/component-faraday-ui/src/submissionRevision/DetailsAndAuthors.js
@@ -0,0 +1,100 @@
+import React from 'react'
+import { get } from 'lodash'
+import { Field } from 'redux-form'
+import { required } from 'xpub-validators'
+import {
+  Row,
+  Item,
+  Label,
+  Textarea,
+  WizardAuthors,
+  RowOverrideAlert,
+  ItemOverrideAlert,
+} from 'pubsweet-component-faraday-ui'
+import { Menu, TextField, ValidatedField } from '@pubsweet/ui'
+import { th } from '@pubsweet/ui-toolkit'
+import styled from 'styled-components'
+import { ContextualBox } from '../'
+
+const Empty = () => <div />
+
+const DetailsAndAuthors = ({
+  journal,
+  fragment,
+  addAuthor,
+  collection,
+  changeForm,
+  formValues,
+  isAuthorEdit,
+  authorsError,
+  deleteAuthor,
+  manuscriptTypes,
+  getTooltipContent,
+  isAuthorsFetching,
+  onAuthorEdit,
+  ...rest
+}) => (
+  <ContextualBox label="Details and Authors" startExpanded transparent>
+    <Root>
+      <Row mb={3}>
+        <Item data-test-id="submission-title" flex={3} mr={1} vertical>
+          <Label required>MANUSCRIPT TITLE</Label>
+          <ValidatedField
+            component={TextField}
+            name="metadata.title"
+            validate={[required]}
+          />
+        </Item>
+        <ItemOverrideAlert data-test-id="submission-type" vertical>
+          <Label required>MANUSCRIPT TYPE</Label>
+          <ValidatedField
+            component={input => (
+              <Menu
+                options={manuscriptTypes}
+                {...input}
+                placeholder="Please select"
+              />
+            )}
+            name="metadata.type"
+            validate={[required]}
+          />
+        </ItemOverrideAlert>
+      </Row>
+
+      <RowOverrideAlert mb={2}>
+        <Item data-test-id="submission-abstract" vertical>
+          <Label required>ABSTRACT</Label>
+          <ValidatedField
+            component={Textarea}
+            minHeight={15}
+            name="metadata.abstract"
+            validate={[required]}
+          />
+        </Item>
+      </RowOverrideAlert>
+
+      <Field component={Empty} name="authors" />
+      <WizardAuthors
+        addAuthor={addAuthor}
+        authors={get(fragment, 'revision.authors', [])}
+        changeForm={changeForm}
+        collection={collection}
+        deleteAuthor={deleteAuthor}
+        error={authorsError}
+        formName="revision"
+        fragment={fragment}
+        isAuthorEdit={isAuthorEdit}
+        isAuthorsFetching={isAuthorsFetching}
+        journal={journal}
+        onAuthorEdit={onAuthorEdit}
+      />
+    </Root>
+  </ContextualBox>
+)
+
+const Root = styled.div`
+  border-left: ${th('borderWidth')} ${th('borderStyle')} ${th('colorBorder')};
+  padding-left: calc(${th('gridUnit')} * 1);
+`
+
+export default DetailsAndAuthors
diff --git a/packages/component-faraday-ui/src/submissionRevision/DetailsAndAuthors.md b/packages/component-faraday-ui/src/submissionRevision/DetailsAndAuthors.md
new file mode 100644
index 0000000000000000000000000000000000000000..1ac22499492ee611bb322827d7f5ad34fae164b8
--- /dev/null
+++ b/packages/component-faraday-ui/src/submissionRevision/DetailsAndAuthors.md
@@ -0,0 +1,167 @@
+```js
+const { compose, withProps, withHandlers } = require('recompose')
+const { connect } = require('react-redux')
+const { reduxForm, getFormValues, change } = require('redux-form')
+
+const Wrapper = compose(
+  withHandlers({
+    onAuthorEdit: props => () => console.log('Edit author'),
+  }),
+  withProps({
+    manuscriptTypes: [
+      {
+        label: 'Research',
+        value: 'research',
+        author: true,
+        peerReview: true,
+        abstractRequired: true,
+      },
+      {
+        label: 'Review',
+        value: 'review',
+        author: true,
+        peerReview: true,
+        abstractRequired: true,
+      },
+    ],
+    fragment: {
+      id: 'a9dc38fe-5524-4728-b97f-9495a2eb4bee',
+      type: 'fragment',
+      files: {
+        coverLetter: [],
+        manuscripts: [
+          {
+            id:
+              'a9dc38fe-5524-4728-b97f-9495a2eb4bee/4a452733-e05d-485a-a0be-7c199c5eb4a1',
+            name: 'manuscris.pdf',
+            size: 39973,
+            originalName: 'manuscris.pdf',
+          },
+        ],
+        supplementary: [],
+      },
+      owners: [
+        {
+          id: '81586d97-d2b4-4423-a1e3-efd228fc67b8',
+          username: 'mihail.hagiu+re@thinslices.com',
+        },
+        {
+          id: '96673581-5916-46c5-8a57-d9e69c3e713d',
+          username: 'admin',
+        },
+      ],
+      authors: [
+        {
+          id: '81586d97-d2b4-4423-a1e3-efd228fc67b8',
+          email: 'mihail.hagiu+re@thinslices.com',
+          country: 'AX',
+          lastName: 'ihail',
+          firstName: 'M',
+          affiliation: 'TS',
+          isSubmitting: true,
+          isCorresponding: true,
+        },
+      ],
+      created: '2018-10-11T08:04:47.636Z',
+      version: 1,
+      metadata: {
+        type: 'research',
+        title: 'czxcxzc',
+        journal: 'Bioinorganic Chemistry and Applications',
+        abstract: 'xdzczxc',
+      },
+      conflicts: {
+        hasFunding: '',
+        hasConflicts: 'no',
+        hasDataAvailability: '',
+      },
+      submitted: 1539606240257,
+      collectionId: 'e69cddda-74be-47aa-8f99-c388ef5c8a77',
+      declarations: {
+        agree: true,
+      },
+      fragmentType: 'version',
+      recommendations: [],
+    },
+    collection: {
+      id: 'e69cddda-74be-47aa-8f99-c388ef5c8a77',
+      type: 'collection',
+      owners: [
+        '96673581-5916-46c5-8a57-d9e69c3e713d',
+        '81586d97-d2b4-4423-a1e3-efd228fc67b8',
+      ],
+      status: 'rejected',
+      created: 1539245087543,
+      customId: '5074586',
+      fragments: ['a9dc38fe-5524-4728-b97f-9495a2eb4bee'],
+      technicalChecks: {},
+      currentVersion: {
+        id: 'a9dc38fe-5524-4728-b97f-9495a2eb4bee',
+        type: 'fragment',
+        files: {
+          coverLetter: [],
+          manuscripts: [
+            {
+              id:
+                'a9dc38fe-5524-4728-b97f-9495a2eb4bee/4a452733-e05d-485a-a0be-7c199c5eb4a1',
+              name: 'manuscris.pdf',
+              size: 39973,
+              originalName: 'manuscris.pdf',
+            },
+          ],
+          supplementary: [],
+        },
+        owners: [
+          '81586d97-d2b4-4423-a1e3-efd228fc67b8',
+          '96673581-5916-46c5-8a57-d9e69c3e713d',
+        ],
+        authors: [
+          {
+            id: '81586d97-d2b4-4423-a1e3-efd228fc67b8',
+            email: 'mihail.hagiu+re@thinslices.com',
+            country: 'AX',
+            lastName: 'ihail',
+            firstName: 'M',
+            affiliation: 'TS',
+            isSubmitting: true,
+            isCorresponding: true,
+          },
+        ],
+        created: '2018-10-11T08:04:47.636Z',
+        version: 1,
+        metadata: {
+          type: 'research',
+          title: 'czxcxzc',
+          journal: 'Bioinorganic Chemistry and Applications',
+          abstract: 'xdzczxc',
+        },
+        conflicts: {
+          hasFunding: '',
+          hasConflicts: 'no',
+          hasDataAvailability: '',
+        },
+        submitted: 1539606240257,
+        collectionId: 'e69cddda-74be-47aa-8f99-c388ef5c8a77',
+        declarations: {
+          agree: true,
+        },
+        fragmentType: 'version',
+        recommendations: [],
+      },
+      visibleStatus: 'Rejected',
+    },
+  }),
+  connect(
+    state => ({
+      formValues: getFormValues('styleguide')(state),
+    }),
+    {
+      changeForm: change,
+    },
+  ),
+  reduxForm({
+    form: 'styleguide',
+  }),
+)(props => console.log('Padadas', props) || <DetailsAndAuthors {...props} />)
+;<Wrapper />
+```
diff --git a/packages/component-faraday-ui/src/submissionRevision/ManuscriptFiles.js b/packages/component-faraday-ui/src/submissionRevision/ManuscriptFiles.js
new file mode 100644
index 0000000000000000000000000000000000000000..5edc9501d7ae2861cce821a8f8294f31b2986c97
--- /dev/null
+++ b/packages/component-faraday-ui/src/submissionRevision/ManuscriptFiles.js
@@ -0,0 +1,72 @@
+import React from 'react'
+import { get } from 'lodash'
+import { Field } from 'redux-form'
+import styled from 'styled-components'
+import { Icon } from '@pubsweet/ui'
+import { Row, Text, WizardFiles } from 'pubsweet-component-faraday-ui'
+import { th } from '@pubsweet/ui-toolkit'
+import { ContextualBox } from '../'
+
+const Empty = () => <div />
+
+const ManuscriptFiles = ({
+  token,
+  fragment,
+  formName,
+  collection,
+  changeForm,
+  deleteFile,
+  uploadFile,
+  filesError,
+  previewFile,
+  getSignedUrl,
+}) => (
+  <ContextualBox label="Manuscript Files" startExpanded transparent>
+    <Root>
+      <Row justify="flex-start" mb={2}>
+        <Text secondary>
+          Drag & drop files in the specific section or click{' '}
+          <CustomIcon secondary size={2}>
+            plus
+          </CustomIcon>{' '}
+          to upload. Use the{' '}
+          <CustomIcon secondary size={2}>
+            menu
+          </CustomIcon>{' '}
+          icon to reorder or move files to a different type.
+        </Text>
+      </Row>
+      <Field component={Empty} name="files" />
+      <WizardFiles
+        changeForm={changeForm}
+        collection={collection}
+        deleteFile={deleteFile}
+        files={get(fragment, 'revision.files', {})}
+        formName={formName}
+        fragment={fragment}
+        getSignedUrl={getSignedUrl}
+        previewFile={previewFile}
+        token={token}
+        uploadFile={uploadFile}
+      />
+      {filesError && (
+        <Row justify="flex-start" mt={1}>
+          <Text error>{filesError}</Text>
+        </Row>
+      )}
+    </Root>
+  </ContextualBox>
+)
+
+export default ManuscriptFiles
+
+// #region styled-components
+const Root = styled.div`
+  border-left: ${th('borderWidth')} ${th('borderStyle')} ${th('colorBorder')};
+  padding-left: calc(${th('gridUnit')} * 1);
+`
+
+const CustomIcon = styled(Icon)`
+  vertical-align: sub;
+`
+// #endregion
diff --git a/packages/component-faraday-ui/src/submissionRevision/ManuscriptFiles.md b/packages/component-faraday-ui/src/submissionRevision/ManuscriptFiles.md
new file mode 100644
index 0000000000000000000000000000000000000000..42a8e212005461b35ce3cedc2926dc0ffff6b7a2
--- /dev/null
+++ b/packages/component-faraday-ui/src/submissionRevision/ManuscriptFiles.md
@@ -0,0 +1,21 @@
+```js
+const { compose, withHandlers } = require('recompose')
+const { connect } = require('react-redux')
+const { reduxForm, getFormValues } = require('redux-form')
+
+const Wrapper = compose(
+  withHandlers({
+    uploadFile: props => file => Promise.resolve(file),
+    deleteFile: props => file => console.log('Deleted', file),
+  }),
+  connect(state => ({
+    formValues: getFormValues('styleguide')(state),
+  })),
+  reduxForm({
+    form: 'styleguide',
+  }),
+)(( props ) => (
+  <ManuscriptFiles {...props} />
+))
+;<Wrapper />
+```
\ No newline at end of file
diff --git a/packages/component-faraday-ui/src/submissionRevision/ResponseToReviewer.js b/packages/component-faraday-ui/src/submissionRevision/ResponseToReviewer.js
new file mode 100644
index 0000000000000000000000000000000000000000..f3b6c168fa2da6e0526cdd2d94f8634efa3809b6
--- /dev/null
+++ b/packages/component-faraday-ui/src/submissionRevision/ResponseToReviewer.js
@@ -0,0 +1,85 @@
+import React from 'react'
+import { isEmpty } from 'lodash'
+import styled from 'styled-components'
+import { th } from '@pubsweet/ui-toolkit'
+import { FilePicker, Spinner, ValidatedField } from '@pubsweet/ui'
+
+import {
+  Row,
+  Item,
+  Textarea,
+  ActionLink,
+} from 'pubsweet-component-faraday-ui/src'
+
+import {
+  Label,
+  FileItem,
+  ContextualBox,
+  ItemOverrideAlert,
+  withFilePreview,
+  withFileDownload,
+} from '../'
+
+const allowedFileExtensions = ['pdf', 'doc', 'docx', 'txt', 'rdf', 'odt']
+const ResponseToReviewer = ({
+  file,
+  onDelete,
+  onUpload,
+  isFetching,
+  previewFile,
+  downloadFile,
+}) => (
+  <ContextualBox
+    label="Response to Reviewer Comments"
+    startExpanded
+    transparent
+  >
+    <Root>
+      <Row alignItems="center" justify="space-between">
+        <Item>
+          <Label required>Your Reply</Label>
+          {isFetching ? (
+            <Spinner />
+          ) : (
+            <FilePicker
+              allowedFileExtensions={allowedFileExtensions}
+              disabled={!isEmpty(file)}
+              onUpload={onUpload}
+            >
+              <ActionLink disabled={!isEmpty(file)} icon="plus">
+                UPLOAD FILE
+              </ActionLink>
+            </FilePicker>
+          )}
+        </Item>
+      </Row>
+
+      <Row>
+        <ItemOverrideAlert vertical>
+          <ValidatedField
+            component={Textarea}
+            name="responseToReviewers.content"
+          />
+        </ItemOverrideAlert>
+      </Row>
+
+      {!isEmpty(file) && (
+        <Row justify="flex-start" mt={1}>
+          <FileItem
+            item={file}
+            onDelete={onDelete}
+            onDownload={downloadFile}
+            onPreview={previewFile}
+          />
+        </Row>
+      )}
+    </Root>
+  </ContextualBox>
+)
+
+const Root = styled.div`
+  border-left: ${th('borderWidth')} ${th('borderStyle')} ${th('colorBorder')};
+  padding-left: calc(${th('gridUnit')} * 1);
+`
+
+export default withFileDownload(withFilePreview(ResponseToReviewer))
diff --git a/packages/component-faraday-ui/src/submissionRevision/ResponseToReviewer.md b/packages/component-faraday-ui/src/submissionRevision/ResponseToReviewer.md
new file mode 100644
index 0000000000000000000000000000000000000000..e9264445b46902365f4a0d50608d13bd67fde690
--- /dev/null
+++ b/packages/component-faraday-ui/src/submissionRevision/ResponseToReviewer.md
@@ -0,0 +1,7 @@
+```js
+const allowedFileExtensions = ['pdf', 'doc', 'docx']
+
+const onUpload = (f) => {console.log('Upload', f)}
+
+<ResponseToReviewer onUpload={onUpload} allowedFileExtensions={allowedFileExtensions}/>
+```
diff --git a/packages/component-faraday-ui/src/submissionRevision/SubmitRevision.js b/packages/component-faraday-ui/src/submissionRevision/SubmitRevision.js
new file mode 100644
index 0000000000000000000000000000000000000000..be61f16dd096256d2538fdcbbb4cdae27a5eeb80
--- /dev/null
+++ b/packages/component-faraday-ui/src/submissionRevision/SubmitRevision.js
@@ -0,0 +1,94 @@
+import React from 'react'
+import { Button } from '@pubsweet/ui'
+import styled from 'styled-components'
+import { reduxForm } from 'redux-form'
+import { th } from '@pubsweet/ui-toolkit'
+import { Row } from 'pubsweet-component-faraday-ui/src'
+
+import { ContextualBox, Text } from '../'
+import { ManuscriptFiles, DetailsAndAuthors, ResponseToReviewer } from './'
+
+const SubmitRevision = ({
+  journal,
+  addFile,
+  fragment,
+  addAuthor,
+  deleteFile,
+  collection,
+  changeForm,
+  isFetching,
+  currentUser,
+  previewFile,
+  hasFormError,
+  deleteAuthor,
+  getSignedUrl,
+  handleSubmit,
+  responseFile,
+  downloadFile,
+  fetchingError,
+  addResponseFile,
+  deleteResponseFile,
+  //
+  onAuthorEdit,
+  isEditingAuthor,
+}) => (
+  <ContextualBox highlight label="Submit Revision" mb={2}>
+    <Root>
+      <DetailsAndAuthors
+        addAuthor={addAuthor}
+        changeForm={changeForm}
+        collection={collection}
+        deleteAuthor={deleteAuthor}
+        fragment={fragment}
+        isAuthorEdit={isEditingAuthor}
+        manuscriptTypes={journal.manuscriptTypes}
+        onAuthorEdit={onAuthorEdit}
+      />
+
+      <ManuscriptFiles
+        changeForm={changeForm}
+        collection={collection}
+        deleteFile={deleteFile}
+        downloadFile={downloadFile}
+        formName="revision"
+        fragment={fragment}
+        getSignedUrl={getSignedUrl}
+        previewFile={previewFile}
+        token={currentUser.token}
+        uploadFile={addFile}
+      />
+
+      <ResponseToReviewer
+        file={responseFile}
+        getSignedUrl={getSignedUrl}
+        isFetching={isFetching}
+        onDelete={deleteResponseFile}
+        onUpload={addResponseFile}
+        token={currentUser.token}
+      />
+
+      <Row>
+        {hasFormError && (
+          <Text align="center" error mt={1}>
+            There are some missing required fields.
+          </Text>
+        )}
+      </Row>
+
+      <Row justify="flex-end" mt={1}>
+        <Button ml={2} onClick={handleSubmit} primary size="medium">
+          Submit revision
+        </Button>
+      </Row>
+    </Root>
+  </ContextualBox>
+)
+
+const Root = styled.div`
+  background-color: ${th('colorBackgroundHue2')};
+  padding: calc(${th('gridUnit')} * 2);
+`
+
+export default reduxForm({ form: 'revision', destroyOnUnmount: false })(
+  SubmitRevision,
+)
diff --git a/packages/component-faraday-ui/src/submissionRevision/SubmitRevision.md b/packages/component-faraday-ui/src/submissionRevision/SubmitRevision.md
new file mode 100644
index 0000000000000000000000000000000000000000..6c9a0bde8927225e69c55be3fa2ee2cf2f78938c
--- /dev/null
+++ b/packages/component-faraday-ui/src/submissionRevision/SubmitRevision.md
@@ -0,0 +1,156 @@
+```js
+const props = {
+  fragment: {
+    id: 'a9dc38fe-5524-4728-b97f-9495a2eb4bee',
+    type: 'fragment',
+    files: {
+      coverLetter: [],
+      manuscripts: [
+        {
+          id:
+            'a9dc38fe-5524-4728-b97f-9495a2eb4bee/4a452733-e05d-485a-a0be-7c199c5eb4a1',
+          name: 'manuscris.pdf',
+          size: 39973,
+          originalName: 'manuscris.pdf',
+        },
+      ],
+      supplementary: [],
+    },
+    owners: [
+      {
+        id: '81586d97-d2b4-4423-a1e3-efd228fc67b8',
+        username: 'mihail.hagiu+re@thinslices.com',
+      },
+      {
+        id: '96673581-5916-46c5-8a57-d9e69c3e713d',
+        username: 'admin',
+      },
+    ],
+    authors: [
+      {
+        id: '81586d97-d2b4-4423-a1e3-efd228fc67b8',
+        email: 'mihail.hagiu+re@thinslices.com',
+        country: 'RO',
+        lastName: 'ihail',
+        firstName: 'M',
+        affiliation: 'TS',
+        isSubmitting: true,
+        isCorresponding: true,
+      },
+    ],
+    created: '2018-10-11T08:04:47.636Z',
+    version: 1,
+    metadata: {
+      type: 'research',
+      title: 'czxcxzc',
+      journal: 'Bioinorganic Chemistry and Applications',
+      abstract: 'xdzczxc',
+    },
+    conflicts: {
+      hasFunding: '',
+      hasConflicts: 'no',
+      hasDataAvailability: '',
+    },
+    submitted: 1539606240257,
+    collectionId: 'e69cddda-74be-47aa-8f99-c388ef5c8a77',
+    declarations: {
+      agree: true,
+    },
+    fragmentType: 'version',
+    recommendations: [],
+  },
+  collection: {
+    id: 'e69cddda-74be-47aa-8f99-c388ef5c8a77',
+    type: 'collection',
+    owners: [
+      '96673581-5916-46c5-8a57-d9e69c3e713d',
+      '81586d97-d2b4-4423-a1e3-efd228fc67b8',
+    ],
+    status: 'rejected',
+    created: 1539245087543,
+    customId: '5074586',
+    fragments: ['a9dc38fe-5524-4728-b97f-9495a2eb4bee'],
+    technicalChecks: {},
+    currentVersion: {
+      id: 'a9dc38fe-5524-4728-b97f-9495a2eb4bee',
+      type: 'fragment',
+      files: {
+        coverLetter: [],
+        manuscripts: [
+          {
+            id:
+              'a9dc38fe-5524-4728-b97f-9495a2eb4bee/4a452733-e05d-485a-a0be-7c199c5eb4a1',
+            name: 'manuscris.pdf',
+            size: 39973,
+            originalName: 'manuscris.pdf',
+          },
+        ],
+        supplementary: [],
+      },
+      owners: [
+        '81586d97-d2b4-4423-a1e3-efd228fc67b8',
+        '96673581-5916-46c5-8a57-d9e69c3e713d',
+      ],
+      authors: [
+        {
+          id: '81586d97-d2b4-4423-a1e3-efd228fc67b8',
+          email: 'mihail.hagiu+re@thinslices.com',
+          country: 'AX',
+          lastName: 'ihail',
+          firstName: 'M',
+          affiliation: 'TS',
+          isSubmitting: true,
+          isCorresponding: true,
+        },
+      ],
+      created: '2018-10-11T08:04:47.636Z',
+      version: 1,
+      metadata: {
+        type: 'research',
+        title: 'czxcxzc',
+        journal: 'Bioinorganic Chemistry and Applications',
+        abstract: 'xdzczxc',
+      },
+      conflicts: {
+        hasFunding: '',
+        hasConflicts: 'no',
+        hasDataAvailability: '',
+      },
+      submitted: 1539606240257,
+      collectionId: 'e69cddda-74be-47aa-8f99-c388ef5c8a77',
+      declarations: {
+        agree: true,
+      },
+      fragmentType: 'version',
+      recommendations: [],
+    },
+    visibleStatus: 'Rejected',
+  },
+  journal: {
+    manuscriptTypes: [
+      {
+        label: 'Research Article',
+        value: 'research',
+        author: true,
+        peerReview: true,
+        abstractRequired: true,
+      },
+      {
+        label: 'Review Article',
+        value: 'review',
+        author: true,
+        peerReview: true,
+        abstractRequired: true,
+      },
+      {
+        label: 'Letter to the editor',
+        value: 'letter-to-editor',
+        author: true,
+        peerReview: false,
+        abstractRequired: false,
+      },
+    ],
+  },
+}
+;<SubmitRevision {...props} />
+```
diff --git a/packages/component-faraday-ui/src/submissionRevision/index.js b/packages/component-faraday-ui/src/submissionRevision/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..262a71e3f9707fbb08597535af9a3f1aef39b22f
--- /dev/null
+++ b/packages/component-faraday-ui/src/submissionRevision/index.js
@@ -0,0 +1,4 @@
+export { default as ResponseToReviewer } from './ResponseToReviewer'
+export { default as ManuscriptFiles } from './ManuscriptFiles'
+export { default as DetailsAndAuthors } from './DetailsAndAuthors'
+export { default as SubmitRevision } from './SubmitRevision'
diff --git a/packages/component-manuscript-manager/src/routes/collections/get.js b/packages/component-manuscript-manager/src/routes/collections/get.js
index ddeeb504d1efee96f4362a6e72455cb7529298f2..1314ffda0107a1e4c80a0edab70561f97db82093 100644
--- a/packages/component-manuscript-manager/src/routes/collections/get.js
+++ b/packages/component-manuscript-manager/src/routes/collections/get.js
@@ -1,3 +1,8 @@
+const { last, get } = require('lodash')
+
+const filterDuplicates = collection =>
+  get(collection, 'currentVersion.id') === last(collection.fragments)
+
 const {
   authsome: authsomeHelper,
 } = require('pubsweet-component-helper-service')
@@ -16,5 +21,5 @@ module.exports = models => async (req, res) => {
     })
   }
 
-  res.status(200).json(collections)
+  res.status(200).json(collections.filter(filterDuplicates))
 }
diff --git a/packages/component-manuscript-manager/src/routes/fragments/notifications/emailCopy.js b/packages/component-manuscript-manager/src/routes/fragments/notifications/emailCopy.js
index 64f10e4fc62bc24ca139281b489037818d93ec55..ecfadb0a4ae20fb38e8e9511b10120fb33fabfaf 100644
--- a/packages/component-manuscript-manager/src/routes/fragments/notifications/emailCopy.js
+++ b/packages/component-manuscript-manager/src/routes/fragments/notifications/emailCopy.js
@@ -5,10 +5,12 @@ const journalName = config.get('journal.name')
 const getEmailCopy = ({ emailType, titleText, expectedDate, customId }) => {
   let paragraph
   const hasLink = true
-  const hasIntro = true
-  const hasSignature = true
+  let hasIntro = true
+  let hasSignature = true
   switch (emailType) {
     case 'he-new-version-submitted':
+      hasIntro = false
+      hasSignature = false
       paragraph = `The authors of ${titleText} have submitted a revised version. <br/><br/>
         To review this new submission and proceed with the review process, please visit the manuscript details page.`
       break
diff --git a/packages/component-manuscript-manager/src/routes/fragments/notifications/notifications.js b/packages/component-manuscript-manager/src/routes/fragments/notifications/notifications.js
index 75be73180ca247e1d78800a3f1ac34587cc85208..7f0b8fd3d3364ddc038385f6424ec53b9578fba3 100644
--- a/packages/component-manuscript-manager/src/routes/fragments/notifications/notifications.js
+++ b/packages/component-manuscript-manager/src/routes/fragments/notifications/notifications.js
@@ -21,6 +21,7 @@ module.exports = {
     UserModel,
     collection,
     isNewVersion = false,
+    previousVersion,
     isTechnicalCheck,
     isMajorRecommendation,
   }) {
@@ -59,7 +60,6 @@ module.exports = {
       const heUser = await UserModel.find(handlingEditor.id)
       sendHandlingEditorEmail({
         email,
-        eicName,
         baseUrl,
         customId,
         title: parsedFragment.title,
@@ -73,8 +73,9 @@ module.exports = {
         baseUrl,
         customId,
         UserModel,
-        fragmentHelper,
+        previousVersion,
         title: parsedFragment.title,
+        heName: collection.handlingEditor.name,
       })
     }
 
@@ -104,7 +105,6 @@ module.exports = {
 const sendHandlingEditorEmail = ({
   email,
   title,
-  eicName,
   baseUrl,
   customId,
   handlingEditor,
@@ -113,19 +113,17 @@ const sendHandlingEditorEmail = ({
 
   email.toUser = {
     email: handlingEditor.email,
-    name: handlingEditor.name,
   }
   email.content.unsubscribeLink = services.createUrl(baseUrl, unsubscribeSlug, {
     id: handlingEditor.id,
     token: handlingEditor.accessTokens.unsubscribe,
   })
-  email.content.signatureName = eicName
   email.content.subject = `${customId}: Revision submitted`
 
   const { html, text } = email.getNotificationBody({
     emailBodyProps: getEmailCopy({
       emailType,
-      titleText: `the manuscript titled ${title}`,
+      titleText: `the manuscript titled "${title}"`,
     }),
   })
   email.sendEmail({ html, text })
@@ -134,14 +132,18 @@ const sendHandlingEditorEmail = ({
 const sendReviewersEmail = async ({
   email,
   title,
+  heName,
   baseUrl,
   customId,
   UserModel,
-  fragmentHelper,
+  previousVersion,
 }) => {
   email.content.subject = `${customId}: A manuscript you reviewed has been revised`
+  email.content.signatureName = heName
+  email.fromEmail = `${heName} <${staffEmail}>`
   const emailType = 'submitted-reviewers-after-revision'
 
+  const fragmentHelper = new Fragment({ fragment: previousVersion })
   const reviewers = await fragmentHelper.getReviewers({
     UserModel,
     type: 'submitted',
@@ -165,7 +167,7 @@ const sendReviewersEmail = async ({
     const { html, text } = email.getNotificationBody({
       emailBodyProps: getEmailCopy({
         emailType,
-        titleText: `the manuscript titled ${title}`,
+        titleText: `the manuscript titled "${title}"`,
         expectedDate: services.getExpectedDate({ daysExpected: 14 }),
       }),
     })
diff --git a/packages/component-manuscript-manager/src/routes/fragments/patch.js b/packages/component-manuscript-manager/src/routes/fragments/patch.js
index 6f4cd8a9eb18956142727537add44c9ed28035e0..09e3dbc8f106ff8414952801c8b722eb9e0d711b 100644
--- a/packages/component-manuscript-manager/src/routes/fragments/patch.js
+++ b/packages/component-manuscript-manager/src/routes/fragments/patch.js
@@ -116,10 +116,11 @@ module.exports = models => async (req, res) => {
     collection.save()
 
     notifications.sendNotifications({
-      fragment,
       collection,
       isNewVersion: true,
+      fragment: newFragment,
       UserModel: models.User,
+      previousVersion: fragment,
       baseUrl: services.getBaseUrl(req),
       isMajorRecommendation: heRecommendation.recommendation === 'major',
     })
diff --git a/packages/component-manuscript/src/components/ManuscriptLayout.js b/packages/component-manuscript/src/components/ManuscriptLayout.js
index eb3581a466de4eb6213a08f54cbb7756eac811ba..38ef102fa143ae12a2a5bf78261312211e8d8083 100644
--- a/packages/component-manuscript/src/components/ManuscriptLayout.js
+++ b/packages/component-manuscript/src/components/ManuscriptLayout.js
@@ -12,6 +12,7 @@ import {
   ManuscriptDetailsTop,
   ResponseToInvitation,
   ManuscriptEicDecision,
+  SubmitRevision,
 } from 'pubsweet-component-faraday-ui'
 
 import ReviewerReportCard from './ReviewReportCard'
@@ -68,6 +69,7 @@ const ManuscriptLayout = ({
   editorialCommentsExpanded,
   toggleEditorialComments,
   onInvitePublonReviewer,
+  submitRevision,
 }) => (
   <Root pb={30}>
     {!isEmpty(collection) && !isEmpty(fragment) ? (
@@ -108,6 +110,10 @@ const ManuscriptLayout = ({
           />
         )}
 
+        {get(currentUser, 'permissions.canSubmitRevision', false) && (
+          <SubmitRevision {...submitRevision} />
+        )}
+
         {submittedOwnRecommendation && (
           <ReviewerReportCard
             getSignedUrl={getSignedUrl}
diff --git a/packages/component-manuscript/src/components/ManuscriptPage.js b/packages/component-manuscript/src/components/ManuscriptPage.js
index 3304d0385603f47ed75cdc1b78bf04a6b3fa7aa7..781fb962155bac6ca78ee9eef5f51f16901d6530 100644
--- a/packages/component-manuscript/src/components/ManuscriptPage.js
+++ b/packages/component-manuscript/src/components/ManuscriptPage.js
@@ -42,6 +42,7 @@ import {
   canMakeRevision,
   canMakeDecision,
   isHEToManuscript,
+  canSubmitRevision,
   canEditManuscript,
   canInviteReviewers,
   pendingHEInvitation,
@@ -65,6 +66,7 @@ import {
 } from 'pubsweet-component-faraday-ui'
 
 import ManuscriptLayout from './ManuscriptLayout'
+import withSubmitRevision from '../submitRevision/withSubmitRevision'
 import {
   parseEicDecision,
   parseSearchParams,
@@ -145,11 +147,11 @@ export default compose(
         journal,
         fragment,
         collection,
+        isFetching,
         currentUser,
         pendingHEInvitation,
         pendingOwnRecommendation,
         pendingReviewerInvitation,
-        isFetching,
       },
     ) => ({
       currentUser: {
@@ -162,6 +164,7 @@ export default compose(
         isReviewer: currentUserIsReviewer(state, get(fragment, 'id', '')),
         isHEToManuscript: isHEToManuscript(state, get(collection, 'id', '')),
         permissions: {
+          canSubmitRevision: canSubmitRevision(state, collection, fragment),
           canMakeHERecommendation: canMakeHERecommendation(state, {
             collection,
             statuses: get(journal, 'statuses', {}),
@@ -192,6 +195,7 @@ export default compose(
         publonsFetching: isFetching,
       },
       formValues: {
+        revision: getFormValues('revision')(state),
         eicDecision: getFormValues('eic-decision')(state),
         reviewerReport: getFormValues('reviewerReport')(state),
         responseToInvitation: getFormValues('answer-invitation')(state),
@@ -503,6 +507,7 @@ export default compose(
       get(currentUser, 'isReviewer', false) &&
       isUndefined(submittedOwnRecommendation),
   })),
+  withSubmitRevision,
   lifecycle({
     componentDidMount() {
       const {
@@ -519,11 +524,11 @@ export default compose(
         fetchUpdatedCollection,
         editorialRecommendations,
         currentUser: {
+          isEIC,
           isInvitedHE,
           isInvitedToReview,
           isHEToManuscript,
-          isEIC,
-          permissions: { canInviteReviewers },
+          permissions: { canInviteReviewers, canSubmitRevision },
         },
       } = this.props
 
@@ -573,6 +578,10 @@ export default compose(
       if ((isEIC || isHEToManuscript) && !!editorialRecommendations.length) {
         this.props.toggleEditorialComments()
       }
+
+      if (canSubmitRevision) {
+        this.props.toggleEditorialComments()
+      }
     },
     componentDidUpdate(prevProps) {
       const {
diff --git a/packages/component-manuscript/src/submitRevision/utils.js b/packages/component-manuscript/src/submitRevision/utils.js
new file mode 100644
index 0000000000000000000000000000000000000000..ab28ccc47a0564071bd987022aa022f5f3fe20a8
--- /dev/null
+++ b/packages/component-manuscript/src/submitRevision/utils.js
@@ -0,0 +1,92 @@
+import { actions } from 'pubsweet-client'
+import { get, debounce, omit, set } from 'lodash'
+import { handleError } from 'pubsweet-component-faraday-ui'
+import { autosaveRequest } from 'pubsweet-component-wizard/src/redux/autosave'
+import { submitRevision } from 'pubsweet-component-wizard/src/redux/conversion'
+
+const parseRevision = (values, fragment) => {
+  const v = omit(values, 'authorForm')
+
+  return {
+    ...fragment,
+    revision: {
+      ...v,
+    },
+  }
+}
+
+const _onChange = (values, dispatch, { collection, fragment }) => {
+  dispatch(autosaveRequest())
+  dispatch(actions.updateFragment(collection, parseRevision(values, fragment)))
+}
+
+export const onChange = debounce(_onChange, 1000, { maxWait: 5000 })
+
+export const onSubmit = (
+  values,
+  dispatch,
+  { history, fragment, collection, showModal, setFetching, canSubmit },
+) => {
+  if (!canSubmit) return
+
+  showModal({
+    title: 'Ready to submit your revision?',
+    subtitle: `Once submitted, the submission can't be modified.`,
+    onConfirm: ({ hideModal, setModalError }) => {
+      setFetching(true)
+      return submitRevision({
+        fragmentId: fragment.id,
+        collectionId: collection.id,
+      })
+        .then(
+          r => {
+            Promise.all([
+              dispatch(actions.getCollection(collection)),
+              dispatch(actions.getFragments({ id: collection.id })),
+            ]).then(() => {
+              setFetching(false)
+              hideModal()
+              history.push(
+                `/projects/${r.collectionId}/versions/${r.id}/details`,
+              )
+            })
+          },
+          err => {
+            throw err
+          },
+        )
+        .catch(err => {
+          setFetching(false)
+          handleError(setModalError)(err)
+        })
+    },
+  })
+}
+
+export const getInitialValues = fragment => ({
+  files: get(fragment, 'revision.files', {}),
+  authors: get(fragment, 'revision.authors', []),
+  metadata: get(fragment, 'revision.metadata', {
+    abstract: '',
+    title: '',
+    type: '',
+  }),
+  responseToReviewers: get(fragment, 'revision.responseToReviewers', {
+    content: '',
+    file: null,
+  }),
+})
+
+export const validate = ({ responseToReviewers }) => {
+  const errors = {}
+
+  if (!responseToReviewers.content && !responseToReviewers.file) {
+    set(
+      errors,
+      'responseToReviewers.content',
+      'A reply or a report file is needed.',
+    )
+  }
+
+  return errors
+}
diff --git a/packages/component-manuscript/src/submitRevision/withSubmitRevision.js b/packages/component-manuscript/src/submitRevision/withSubmitRevision.js
new file mode 100644
index 0000000000000000000000000000000000000000..40427a9ceed7074deb17f989c677d9f3224a7279
--- /dev/null
+++ b/packages/component-manuscript/src/submitRevision/withSubmitRevision.js
@@ -0,0 +1,148 @@
+import { connect } from 'react-redux'
+import { get, pick, isNull } from 'lodash'
+import { withRouter } from 'react-router-dom'
+import {
+  MultiAction,
+  handleError,
+  withFetching,
+  withFilePreview,
+  withFileDownload,
+} from 'pubsweet-component-faraday-ui'
+import { DragDropContext } from 'react-dnd'
+import { change as changeForm } from 'redux-form'
+import HTML5Backend from 'react-dnd-html5-backend'
+import { withModal } from 'pubsweet-component-modal/src/components'
+import {
+  compose,
+  toClass,
+  withProps,
+  withHandlers,
+  setDisplayName,
+  withStateHandlers,
+} from 'recompose'
+
+import {
+  addAuthor,
+  deleteAuthor,
+} from 'pubsweet-components-faraday/src/redux/authors'
+
+import {
+  uploadFile,
+  deleteFile,
+} from 'pubsweet-components-faraday/src/redux/files'
+
+import { onChange, onSubmit, getInitialValues, validate } from './utils'
+
+export default compose(
+  withRouter,
+  withFetching,
+  withFilePreview,
+  withFileDownload,
+  withStateHandlers(
+    { authorEditIndex: null },
+    {
+      onAuthorEdit: () => index => ({
+        authorEditIndex: index,
+      }),
+    },
+  ),
+  connect(
+    state => ({
+      canSubmit: !get(state, 'form.revision.syncErrors'),
+      hasFormError:
+        get(state, 'form.revision.syncErrors') &&
+        get(state, 'form.revision.anyTouched', false),
+    }),
+    { changeForm },
+  ),
+  withProps(() => ({
+    modalKey: 'submitRevision',
+  })),
+  withModal(({ isFetching }) => ({
+    isFetching,
+    modalComponent: MultiAction,
+  })),
+  withHandlers({
+    addResponseFile: ({
+      setError,
+      fragment,
+      changeForm,
+      setFetching,
+    }) => file => {
+      setFetching(true)
+      return uploadFile({
+        file,
+        fragment,
+        type: 'responseToReviewers',
+      })
+        .then(f => {
+          setFetching(false)
+          changeForm('revision', 'responseToReviewers.file', f)
+        })
+        .catch(err => {
+          setFetching(false)
+          handleError(setError)(err)
+        })
+    },
+    deleteResponseFile: ({ setError, changeForm, setFetching }) => file => {
+      setFetching(true)
+      return deleteFile(file.id, 'responseToReviewers')
+        .then(r => {
+          setFetching(false)
+          changeForm('revision', 'responseToReviewers.file', null)
+        })
+        .catch(err => {
+          setFetching(false)
+          handleError(setError)(err)
+        })
+    },
+    addFile: () => uploadFile,
+    addAuthor: () => addAuthor,
+    deleteFile: () => deleteFile,
+    deleteAuthor: () => deleteAuthor,
+    previewFile: ({ previewFile }) => previewFile,
+    downloadFile: ({ downloadFile }) => downloadFile,
+  }),
+  DragDropContext(HTML5Backend),
+  toClass,
+  withProps(props => ({
+    submitRevision: {
+      initialValues: getInitialValues(props.fragment),
+      ...pick(props, [
+        'addFile',
+        'journal',
+        'history',
+        'fragment',
+        'canSubmit',
+        'addAuthor',
+        'showModal',
+        'changeForm',
+        'collection',
+        'isFetching',
+        'deleteFile',
+        'currentUser',
+        'setFetching',
+        'previewFile',
+        'downloadFile',
+        'onAuthorEdit',
+        'deleteAuthor',
+        'getSignedUrl',
+        'hasFormError',
+        'fetchingError',
+        'addResponseFile',
+        'deleteResponseFile',
+      ]),
+      isEditingAuthor: !isNull(props.authorEditIndex),
+      onChange,
+      onSubmit,
+      validate,
+      responseFile: get(
+        props,
+        'formValues.revision.responseToReviewers.file',
+        null,
+      ),
+    },
+  })),
+
+  setDisplayName('SubmitRevisionHOC'),
+)
diff --git a/packages/component-modal/src/components/ConfirmationModal.js b/packages/component-modal/src/components/ConfirmationModal.js
index 55b2b1012309f77fdf25e892516c8c6ff9662fdf..01e52582e3327b54a579e05cf5e19973b47422cc 100644
--- a/packages/component-modal/src/components/ConfirmationModal.js
+++ b/packages/component-modal/src/components/ConfirmationModal.js
@@ -16,7 +16,7 @@ const ConfirmationModal = ({
   cancelText = 'Cancel',
 }) => (
   <Root>
-    <CloseIcon data-test="icon-modal-hide" onClick={onClose}>
+    <CloseIcon data-test-id="icon-modal-hide" onClick={onClose}>
       <Icon primary>x</Icon>
     </CloseIcon>
     {title && <Title dangerouslySetInnerHTML={{ __html: title }} />}
@@ -26,7 +26,7 @@ const ConfirmationModal = ({
     {modalError && <ErrorMessage>{modalError}</ErrorMessage>}
 
     <ButtonsContainer>
-      <Button data-test="button-modal-hide" onClick={onClose}>
+      <Button data-test-id="button-modal-hide" onClick={onClose}>
         {cancelText}
       </Button>
       {onConfirm &&
@@ -35,7 +35,11 @@ const ConfirmationModal = ({
             <Spinner size={4} />
           </SpinnerContainer>
         ) : (
-          <Button data-test="button-modal-confirm" onClick={onConfirm} primary>
+          <Button
+            data-test-id="button-modal-confirm"
+            onClick={onConfirm}
+            primary
+          >
             {confirmText}
           </Button>
         ))}
diff --git a/packages/component-modal/src/components/SubmissionModal.js b/packages/component-modal/src/components/SubmissionModal.js
index e88fdf1695129a07e11d78c2cdc36f22bbb3afa1..f2223512482016ef96d14a8e077759dbbd5883d8 100644
--- a/packages/component-modal/src/components/SubmissionModal.js
+++ b/packages/component-modal/src/components/SubmissionModal.js
@@ -46,7 +46,7 @@ const SubmissionModal = ({
     </Text>
     {modalError && <ErrorMessage>{modalError}</ErrorMessage>}
     <ButtonsContainer>
-      <Button data-test="button-modal-hide" onClick={hideModal}>
+      <Button data-test-id="button-modal-hide" onClick={hideModal}>
         {cancelText}
       </Button>
       {onConfirm &&
@@ -55,7 +55,11 @@ const SubmissionModal = ({
             <Spinner size={4} />
           </SpinnerContainer>
         ) : (
-          <Button data-test="button-modal-confirm" onClick={onConfirm} primary>
+          <Button
+            data-test-id="button-modal-confirm"
+            onClick={onConfirm}
+            primary
+          >
             {confirmText}
           </Button>
         ))}
diff --git a/packages/component-modal/src/components/SuccessModal.js b/packages/component-modal/src/components/SuccessModal.js
index aa63fb4613805ee5cfff44883b7151b9042c4565..7e2b5752655d82ab4085f552796d7a9b3867ff0c 100644
--- a/packages/component-modal/src/components/SuccessModal.js
+++ b/packages/component-modal/src/components/SuccessModal.js
@@ -7,7 +7,7 @@ const SuccessModal = ({ title, confirmText = 'OK', hideModal, theme }) => (
   <Root>
     {title && <Title dangerouslySetInnerHTML={{ __html: title }} />}
     <ButtonsContainer>
-      <Button data-test="button-modal-confirm" onClick={hideModal} primary>
+      <Button data-test-id="button-modal-confirm" onClick={hideModal} primary>
         {confirmText}
       </Button>
     </ButtonsContainer>
diff --git a/packages/component-modal/src/components/withModal.js b/packages/component-modal/src/components/withModal.js
index 3d7f9913d86dd3fb67526c1b0e81d958c7df2a76..a79c64635bc549950020e9251f5af02dbf82e796 100644
--- a/packages/component-modal/src/components/withModal.js
+++ b/packages/component-modal/src/components/withModal.js
@@ -1,7 +1,7 @@
 import React, { Fragment } from 'react'
-import { omit } from 'lodash'
-import { connect } from 'react-redux'
+import { omit, get } from 'lodash'
 import { compose } from 'recompose'
+import { connect } from 'react-redux'
 
 import Modal from './Modal'
 import { showModal, hideModal, setModalError } from '../redux/modal'
@@ -15,7 +15,7 @@ const mapState = state => ({
 const mapDispatch = (dispatch, props) => ({
   hideModal: () => dispatch(hideModal()),
   showModal: (modalProps = {}) =>
-    dispatch(showModal(props.modalKey, modalProps)),
+    dispatch(showModal(get(props, 'modalKey'), modalProps)),
   setModalError: errorMessage => dispatch(setModalError(errorMessage)),
 })
 
diff --git a/packages/component-wizard/src/components/StepThree.js b/packages/component-wizard/src/components/StepThree.js
index 9a4a67aabed1c0cbe89bded838d20fa29f74fc3c..4b7666551a992a1a389bfdd0e050ee00a8bd3a19 100644
--- a/packages/component-wizard/src/components/StepThree.js
+++ b/packages/component-wizard/src/components/StepThree.js
@@ -9,8 +9,8 @@ import { Empty } from './'
 
 const StepThree = ({
   token,
-  version,
-  project,
+  fragment,
+  collection,
   changeForm,
   deleteFile,
   uploadFile,
@@ -36,13 +36,13 @@ const StepThree = ({
     <Field component={Empty} name="files" />
     <WizardFiles
       changeForm={changeForm}
+      collection={collection}
       deleteFile={deleteFile}
-      files={get(version, 'files', {})}
+      files={get(fragment, 'files', {})}
+      fragment={fragment}
       getSignedUrl={getSignedUrl}
-      project={project}
       token={token}
       uploadFile={uploadFile}
-      version={version}
     />
     {filesError && (
       <Row justify="flex-start" mt={1}>
diff --git a/packages/component-wizard/src/components/StepTwo.js b/packages/component-wizard/src/components/StepTwo.js
index 659b4fccc156231e9deaf5baf8f9b042069b9005..4060c434bfab905255b55fddf63e87f9d3548a8d 100644
--- a/packages/component-wizard/src/components/StepTwo.js
+++ b/packages/component-wizard/src/components/StepTwo.js
@@ -20,10 +20,10 @@ import { H2, Menu, TextField, ValidatedField } from '@pubsweet/ui'
 import { Empty } from './'
 
 const StepTwo = ({
-  version,
-  project,
+  fragment,
   journal,
   addAuthor,
+  collection,
   changeForm,
   formValues,
   isAuthorEdit,
@@ -88,16 +88,16 @@ const StepTwo = ({
     <Field component={Empty} name="authors" />
     <WizardAuthors
       addAuthor={addAuthor}
-      authors={get(version, 'authors', [])}
+      authors={get(fragment, 'authors', [])}
       changeForm={changeForm}
+      collection={collection}
       deleteAuthor={deleteAuthor}
       error={authorsError}
+      fragment={fragment}
       isAuthorEdit={isAuthorEdit}
       isAuthorsFetching={isAuthorsFetching}
       journal={journal}
       onAuthorEdit={setAuthorEditIndex}
-      project={project}
-      version={version}
     />
 
     {questions.map(q => (
diff --git a/packages/component-wizard/src/components/SubmissionWizard.js b/packages/component-wizard/src/components/SubmissionWizard.js
index 74047fae170ce629995ecc945d4acecb70fc8e51..2280a49a7cf5e13c423bd0d32021021b96a06dcc 100644
--- a/packages/component-wizard/src/components/SubmissionWizard.js
+++ b/packages/component-wizard/src/components/SubmissionWizard.js
@@ -82,12 +82,12 @@ const Wizard = ({
         ) : (
           <Fragment>
             <Button
-              data-test="submission-back"
+              data-test-id="submission-back"
               mr={1}
               onClick={isFirstStep ? history.goBack : prevStep}
             >{`< BACK`}</Button>
             <Button
-              data-test="submission-next"
+              data-test-id="submission-next"
               ml={isFirstStep ? 0 : 1}
               onClick={handleSubmit}
               primary
@@ -116,19 +116,17 @@ export default compose(
     (state, { match }) => ({
       token: getUserToken(state),
       isFetching: getAutosaveFetching(state),
+      isFilesFetching: getFileFetching(state),
+      reduxAuthorError: getAuthorError(state),
       formValues: getFormValues('submission')(state),
       submitFailed: hasSubmitFailed('submission')(state),
       formSyncErrors: getFormSyncErrors('submission')(state),
-      version: selectFragment(state, get(match, 'params.version')),
-      project: selectCollection(state, get(match, 'params.project')),
-      isFilesFetching: getFileFetching(state),
+      fragment: selectFragment(state, get(match, 'params.version')),
+      collection: selectCollection(state, get(match, 'params.project')),
       isAuthorsFetching: getAuthorFetching(state) || getAutosaveFetching(state),
-      reduxAuthorError: getAuthorError(state),
     }),
     {
-      addAuthor,
       changeForm,
-      deleteAuthor,
       submitManuscript,
       updateFragment: actions.updateFragment,
     },
@@ -156,8 +154,10 @@ export default compose(
       authorEditIndex,
       reduxAuthorError,
     }) => ({
+      addAuthor,
       deleteFile,
       uploadFile,
+      deleteAuthor,
       getSignedUrl,
       isFirstStep: step === 0,
       isAuthorEdit: !isNull(authorEditIndex),
diff --git a/packages/component-wizard/src/components/utils.js b/packages/component-wizard/src/components/utils.js
index 9b922cfc1ee32ab719b35ab431cebafdac41cceb..eb333851dd032ea8341ef8b25144b3d2a0233e0d 100644
--- a/packages/component-wizard/src/components/utils.js
+++ b/packages/component-wizard/src/components/utils.js
@@ -17,21 +17,21 @@ import {
 } from '../redux/autosave'
 import { SubmissionStatement } from './'
 
-export const setInitialValues = ({ version }) => ({
+export const setInitialValues = ({ fragment }) => ({
   initialValues: {
-    files: get(version, 'files', {}),
-    authors: get(version, 'authors', []),
-    metadata: get(version, 'metadata', {}),
-    conflicts: get(version, 'conflicts', {
+    files: get(fragment, 'files', {}),
+    authors: get(fragment, 'authors', []),
+    metadata: get(fragment, 'metadata', {}),
+    conflicts: get(fragment, 'conflicts', {
       hasConflicts: 'no',
       hasDataAvailability: '',
       hasFunding: '',
     }),
-    declarations: get(version, 'declarations', { agree: false }),
+    declarations: get(fragment, 'declarations', { agree: false }),
   },
 })
 
-export const validate = (values, props) => {
+export const validate = values => {
   const errors = {}
 
   if (!get(values, 'declarations.agree')) {
@@ -57,8 +57,12 @@ export const validate = (values, props) => {
   return errors
 }
 
-const _onChange = (values, dispatch, { project, version, updateFragment }) => {
-  const previousValues = pick(version, [
+const _onChange = (
+  values,
+  dispatch,
+  { collection, fragment, updateFragment },
+) => {
+  const previousValues = pick(fragment, [
     'files',
     'authors',
     'metadata',
@@ -68,8 +72,8 @@ const _onChange = (values, dispatch, { project, version, updateFragment }) => {
   const newValues = omit(values, ['agree', 'authorForm'])
   if (!isEqual(newValues, previousValues)) {
     dispatch(autosaveRequest())
-    updateFragment(project, {
-      ...version,
+    updateFragment(collection, {
+      ...fragment,
       ...newValues,
     }).then(
       () => dispatch(autosaveSuccess()),
@@ -92,8 +96,8 @@ export const onSubmit = (
     isEditMode,
     setModalError,
     submitManuscript,
-    version: { id: fragmentId },
-    project: { id: collectionId, customId },
+    fragment: { id: fragmentId },
+    collection: { id: collectionId, customId },
   },
 ) => {
   if (step !== 2) {
@@ -107,14 +111,14 @@ export const onSubmit = (
       cancelText: 'BACK TO SUBMISSION',
       onConfirm: () => {
         dispatch(autosaveRequest())
-        submitManuscript(collectionId, fragmentId)
+        submitManuscript({ collectionId, fragmentId })
           .then(r => {
             hideModal()
             dispatch(autosaveSuccess())
             history.push('/confirmation-page', {
               customId,
-              version: fragmentId,
-              project: collectionId,
+              fragment: fragmentId,
+              collection: collectionId,
             })
           })
           .catch(err => {
diff --git a/packages/component-wizard/src/redux/autosave.js b/packages/component-wizard/src/redux/autosave.js
index 772755f4eb6f3f65900020f484c50bc6ee141f3b..28ec87bc0dc7586c52df6f84cb291d38cbf066af 100644
--- a/packages/component-wizard/src/redux/autosave.js
+++ b/packages/component-wizard/src/redux/autosave.js
@@ -28,6 +28,8 @@ export const getAutosave = state => get(state, 'autosave', initialState)
 export const getAutosaveFetching = state =>
   get(state, 'autosave.isFetching', false)
 
+// due to faulty error handing inside the updateFragment action, we have to
+// handle error and success here
 export default (state = initialState, action) => {
   switch (action.type) {
     case AUTOSAVE_REQUEST:
@@ -35,11 +37,13 @@ export default (state = initialState, action) => {
         ...initialState,
         isFetching: true,
       }
+    case 'UPDATE_FRAGMENT_FAILURE':
     case AUTOSAVE_FAILURE:
       return {
         ...initialState,
         error: action.error,
       }
+    case 'UPDATE_FRAGMENT_SUCCESS':
     case AUTOSAVE_SUCCESS:
       return {
         ...initialState,
diff --git a/packages/component-wizard/src/redux/conversion.js b/packages/component-wizard/src/redux/conversion.js
index 16a116a0dd13395cf820675a45f10e091c3afe9c..12a1703c7baaa28ba973ea8ddf3ecb8d3ed2dc31 100644
--- a/packages/component-wizard/src/redux/conversion.js
+++ b/packages/component-wizard/src/redux/conversion.js
@@ -1,8 +1,8 @@
 import moment from 'moment'
 import { pick, get } from 'lodash'
 import { actions } from 'pubsweet-client'
-import { create, update } from 'pubsweet-client/src/helpers/api'
 import journalConfig from 'xpub-faraday/app/config/journal'
+import { create, update } from 'pubsweet-client/src/helpers/api'
 
 /* constants */
 export const CREATE_DRAFT_REQUEST = 'CREATE_DRAFT_REQUEST'
@@ -90,7 +90,7 @@ export const createDraftSubmission = history => (dispatch, getState) => {
   })
 }
 
-export const submitManuscript = (collectionId, fragmentId) => dispatch =>
+export const submitManuscript = ({ collectionId, fragmentId }) => dispatch =>
   create(`/collections/${collectionId}/fragments/${fragmentId}/submit`)
 
 export const createRevision = (
@@ -122,8 +122,8 @@ export const createRevision = (
   })
 }
 
-export const submitRevision = (collId, fragId) => dispatch =>
-  update(`/collections/${collId}/fragments/${fragId}/submit`)
+export const submitRevision = ({ collectionId, fragmentId }) =>
+  update(`/collections/${collectionId}/fragments/${fragmentId}/submit`)
 
 /* reducer */
 const initialState = {
diff --git a/packages/components-faraday/src/components/Dashboard/DashboardFilters.js b/packages/components-faraday/src/components/Dashboard/DashboardFilters.js
index 2f1794281d784ee183df364b9322a61c56c5f251..642099f9136951bec02aef4983b0a2e796eea196 100644
--- a/packages/components-faraday/src/components/Dashboard/DashboardFilters.js
+++ b/packages/components-faraday/src/components/Dashboard/DashboardFilters.js
@@ -8,17 +8,17 @@ const DashboardFilters = ({
   changeFilterValue,
   getDefaultFilterValue,
 }) => (
-  <Row
-    alignItems="flex-end"
-    data-test-id="dashboard-filters"
-    justify="flex-start"
-    mb={1}
-    mt={2}
-  >
+  <Row alignItems="flex-end" justify="flex-start" mb={1} mt={2}>
     <Text mr={1} pb={1} secondary>
       Filters
     </Text>
-    <Item alignItems="flex-start" flex={0} mr={1} vertical>
+    <Item
+      alignItems="flex-start"
+      data-test-id="dashboard-filter-priority"
+      flex={0}
+      mr={1}
+      vertical
+    >
       <Label>Priority</Label>
       <Menu
         inline
@@ -28,7 +28,12 @@ const DashboardFilters = ({
         value={getDefaultFilterValue('priority')}
       />
     </Item>
-    <Item alignItems="flex-start" flex={0} vertical>
+    <Item
+      alignItems="flex-start"
+      data-test-id="dashboard-filter-order"
+      flex={0}
+      vertical
+    >
       <Label>Order</Label>
       <Menu
         inline
diff --git a/packages/components-faraday/src/components/Dashboard/DashboardItems.js b/packages/components-faraday/src/components/Dashboard/DashboardItems.js
index 97c067c08aa06b312193e906bdae3bcf11b73485..f5a5e24df3fff52a255f0a70b427cec11726a782 100644
--- a/packages/components-faraday/src/components/Dashboard/DashboardItems.js
+++ b/packages/components-faraday/src/components/Dashboard/DashboardItems.js
@@ -19,7 +19,7 @@ const DashboardItem = compose(
 )(ManuscriptCard)
 
 const DashboardItems = ({ list, onClick, deleteProject, canViewReports }) => (
-  <Root>
+  <Root data-test-id="dashboard-list-items">
     {!list.length ? (
       <Row justify="center" mt={4}>
         <H3>Manuscripts will appear here!</H3>
diff --git a/packages/components-faraday/src/components/Reviewers/InviteReviewers.js b/packages/components-faraday/src/components/Reviewers/InviteReviewers.js
index bb7b1048f4f6046697f73c9daf1c811c5bfe15cc..773a148c2d0b19522f89690d3d5ac76e3e756d57 100644
--- a/packages/components-faraday/src/components/Reviewers/InviteReviewers.js
+++ b/packages/components-faraday/src/components/Reviewers/InviteReviewers.js
@@ -76,7 +76,7 @@ const InviteReviewersModal = compose(
     invitations = [],
   }) => (
     <Root>
-      <CloseIcon data-test="icon-modal-hide" onClick={closeModal}>
+      <CloseIcon data-test-id="icon-modal-hide" onClick={closeModal}>
         <Icon primary>x</Icon>
       </CloseIcon>
 
diff --git a/packages/components-faraday/src/components/SignUp/SignUpStep0.js b/packages/components-faraday/src/components/SignUp/SignUpStep0.js
index f17aabd46a27554e01396ab0369eb5b3124769fd..a158b73643dcabe91d17db7779a17f9f67ffae42 100644
--- a/packages/components-faraday/src/components/SignUp/SignUpStep0.js
+++ b/packages/components-faraday/src/components/SignUp/SignUpStep0.js
@@ -134,7 +134,7 @@ const Step0 = ({
       <Row mt={3}>
         <Text display="flex">
           Already have an account?
-          <ActionLink internal pl={1 / 2} to="/">
+          <ActionLink data-test-id="go-to-sign-in" internal pl={1 / 2} to="/">
             Sign in
           </ActionLink>
         </Text>
diff --git a/packages/components-faraday/src/components/UIComponents/EQSDecisionPage.js b/packages/components-faraday/src/components/UIComponents/EQSDecisionPage.js
index 1b411d6170dd77f33ad83c5c14e203bbd590220b..da01cc78751def42896d1f8bb2dd4a04cb1658ba 100644
--- a/packages/components-faraday/src/components/UIComponents/EQSDecisionPage.js
+++ b/packages/components-faraday/src/components/UIComponents/EQSDecisionPage.js
@@ -34,6 +34,7 @@ const Enhanched = () => (
       <Label required>Manuscript ID</Label>
       <ValidatedField
         component={TextField}
+        data-test-id="eqs-manuscript-id"
         name="customId"
         validate={[required, digitValidator, sizeValidator]}
       />
diff --git a/packages/components-faraday/src/redux/authors.js b/packages/components-faraday/src/redux/authors.js
index c867b596751e0c7db39949b1cfa30077156c137c..308d8a6b4b7fe58ec53c093ab3e30b6af1e3c153 100644
--- a/packages/components-faraday/src/redux/authors.js
+++ b/packages/components-faraday/src/redux/authors.js
@@ -1,8 +1,6 @@
 import { get } from 'lodash'
 import { create, remove, get as apiGet } from 'pubsweet-client/src/helpers/api'
 
-import { handleError } from './utils'
-
 // constants
 const REQUEST = 'authors/REQUEST'
 const FAILURE = 'authors/FAILURE'
@@ -25,26 +23,17 @@ export const authorSuccess = () => ({
 export const getAuthors = (collectionId, fragmentId) =>
   apiGet(`/collections/${collectionId}/fragments/${fragmentId}/users`)
 
-export const addAuthor = (author, collectionId, fragmentId) => dispatch => {
-  dispatch(authorRequest())
-  return create(`/collections/${collectionId}/fragments/${fragmentId}/users`, {
+export const addAuthor = ({ author, collectionId, fragmentId }) =>
+  create(`/collections/${collectionId}/fragments/${fragmentId}/users`, {
     email: author.email,
     role: 'author',
     ...author,
-  }).then(author => {
-    dispatch(authorSuccess())
-    return author
-  }, handleError(authorFailure, dispatch))
-}
+  })
 
-export const deleteAuthor = (collectionId, fragmentId, userId) => dispatch => {
-  dispatch(authorRequest())
-  return remove(
-    `/collections/${collectionId}/fragments/${fragmentId}/users/${userId}`,
+export const deleteAuthor = ({ authorId, fragmentId, collectionId }) =>
+  remove(
+    `/collections/${collectionId}/fragments/${fragmentId}/users/${authorId}`,
   )
-    .then(() => dispatch(authorSuccess()))
-    .catch(handleError(authorFailure, dispatch))
-}
 
 // selectors
 export const getFragmentAuthors = (state, fragmentId) =>
diff --git a/packages/components-faraday/src/redux/files.js b/packages/components-faraday/src/redux/files.js
index 02a36e8517af01e2768c6868b75c67467d78e557..4e79e1f65454bfeb0ba21de652bad73557460c03 100644
--- a/packages/components-faraday/src/redux/files.js
+++ b/packages/components-faraday/src/redux/files.js
@@ -72,7 +72,7 @@ export const uploadFile = ({ file, type, fragment }) => {
   )
 }
 
-export const deleteFile = (fileId, type = 'manuscripts') =>
+export const deleteFile = ({ fileId, type = 'manuscripts' }) =>
   remove(`/files/${fileId}`)
 
 export const getSignedUrl = fileId => apiGet(`/files/${fileId}`)
diff --git a/packages/styleguide/styleguide.config.js b/packages/styleguide/styleguide.config.js
index 1a6fe7ba50ad201d0bc3ee0a474e8ac2c01d53d9..b59df5cb30351edf8f76fe3d11ed90e15664b03a 100644
--- a/packages/styleguide/styleguide.config.js
+++ b/packages/styleguide/styleguide.config.js
@@ -22,6 +22,11 @@ module.exports = {
       sectionDepth: 1,
       components: ['../component-faraday-ui/src/contextualBoxes/[A-Z]*.js'],
     },
+    {
+      name: 'Submit Revision',
+      sectionDepth: 1,
+      components: ['../component-faraday-ui/src/submissionRevision/[A-Z]*.js'],
+    },
     {
       name: 'Pending Items',
       sectionDepth: 1,
diff --git a/packages/xpub-faraday/config/validations.js b/packages/xpub-faraday/config/validations.js
index 978904daf61d9ad44ee03ad187d33d30dc64ac83..cc116eecca70a91cb64c085c77fc0c6b6da39cfd 100644
--- a/packages/xpub-faraday/config/validations.js
+++ b/packages/xpub-faraday/config/validations.js
@@ -42,7 +42,18 @@ module.exports = {
         hasFunding: Joi.any().valid(['yes', 'no', '']),
         fundingMessage: Joi.string().allow(''),
       }),
-      commentsToReviewers: Joi.string(),
+      responseToReviewers: Joi.object({
+        file: Joi.object({
+          id: Joi.string(),
+          name: Joi.string().required(),
+          originalName: Joi.string(),
+          type: Joi.string(),
+          size: Joi.number(),
+          url: Joi.string(),
+          signedUrl: Joi.string(),
+        }).allow(null),
+        content: Joi.string().allow(''),
+      }),
       files: Joi.object({
         manuscript: Joi.any(),
         manuscripts: Joi.array().items(