diff --git a/packages/component-faraday-ui/src/ShadowedBox.js b/packages/component-faraday-ui/src/ShadowedBox.js index f30f7ef8a6e2d26597b9ce402ec378c83672d54d..87c2e1ea56867aedf8e12771afd14488a400ccaf 100644 --- a/packages/component-faraday-ui/src/ShadowedBox.js +++ b/packages/component-faraday-ui/src/ShadowedBox.js @@ -9,12 +9,12 @@ const width = props => css` width: calc(${th('gridUnit')} * ${get(props, 'width', 50)}); ` -export default styled.div.attrs({ - pt: props => get(props, 'pt', 2), - pr: props => get(props, 'pr', 2), - pb: props => get(props, 'pb', 2), - pl: props => get(props, 'pl', 2), -})` +export default styled.div.attrs(props => ({ + pt: get(props, 'pt', 2), + pr: get(props, 'pr', 2), + pb: get(props, 'pb', 2), + pl: get(props, 'pl', 2), +}))` background-color: ${th('colorBackgroundHue')}; border-radius: ${th('borderRadius')}; box-shadow: ${th('boxShadow')}; diff --git a/packages/component-faraday-ui/src/modals/ValidatedMenuField.js b/packages/component-faraday-ui/src/ValidatedMenuField.js similarity index 100% rename from packages/component-faraday-ui/src/modals/ValidatedMenuField.js rename to packages/component-faraday-ui/src/ValidatedMenuField.js diff --git a/packages/component-faraday-ui/src/gridItems/Item.js b/packages/component-faraday-ui/src/gridItems/Item.js index a784d8561d2aaa1ee4e87ab87559efbeb79d650c..3314a5eda1525e86d2f22412ccb9f5623a06d28b 100644 --- a/packages/component-faraday-ui/src/gridItems/Item.js +++ b/packages/component-faraday-ui/src/gridItems/Item.js @@ -5,9 +5,9 @@ import styled from 'styled-components' import { marginHelper, paddingHelper } from 'pubsweet-component-faraday-ui' /** @component */ -const Item = styled.div.attrs({ - 'data-test-id': props => props['data-test-id'] || 'item', -})` +const Item = styled.div.attrs(props => ({ + 'data-test-id': props['data-test-id'] || 'item', +}))` align-items: ${({ alignItems }) => alignItems || 'initial'}; display: flex; flex: ${({ flex }) => (isNumber(flex) ? flex : 1)}; diff --git a/packages/component-faraday-ui/src/gridItems/Row.js b/packages/component-faraday-ui/src/gridItems/Row.js index 9885c26aa20d875994268925273dd173167d28a0..86bcafade7093e078865b478341eb64a03761a4b 100644 --- a/packages/component-faraday-ui/src/gridItems/Row.js +++ b/packages/component-faraday-ui/src/gridItems/Row.js @@ -5,9 +5,9 @@ import styled from 'styled-components' import { heightHelper, marginHelper, paddingHelper } from '../styledHelpers' /** @component */ -const Row = styled.div.attrs({ - 'data-test-id': props => props['data-test-id'] || 'row', -})` +const Row = styled.div.attrs(props => ({ + 'data-test-id': props['data-test-id'] || 'row', +}))` align-items: ${props => get(props, 'alignItems', 'flex-start')}; background-color: ${props => props.bgColor || 'transparent'}; display: flex; diff --git a/packages/component-faraday-ui/src/index.js b/packages/component-faraday-ui/src/index.js index 2d3859c78c7a2eda863ea5cef314771995ffa6b6..6d5f3b1be3fa8bc2fe83cf3c2bff21242bb75160 100644 --- a/packages/component-faraday-ui/src/index.js +++ b/packages/component-faraday-ui/src/index.js @@ -51,6 +51,7 @@ export { default as EditorialReportCard } from './EditorialReportCard' export { default as ReviewerReportAuthor } from './ReviewerReportAuthor' export { default as PasswordValidation } from './PasswordValidation' export { default as MenuCountry } from './MenuCountry' +export { default as ValidatedMenuField } from './ValidatedMenuField' export { SubmitRevision } from './submissionRevision' diff --git a/packages/component-faraday-ui/src/modals/MyMenu.js b/packages/component-faraday-ui/src/modals/MyMenu.js deleted file mode 100644 index 9fe37eb41ed0d80cc4c053850f8eecc5560a74cd..0000000000000000000000000000000000000000 --- a/packages/component-faraday-ui/src/modals/MyMenu.js +++ /dev/null @@ -1,26 +0,0 @@ -import React, { Fragment } from 'react' -import { compose, withStateHandlers } from 'recompose' - -const MyMenu = ({ open, toggleMenu, field, form }) => ( - <div onClick={toggleMenu}> - Click to open - {open && ( - <Fragment> - <span onClick={() => form.setFieldValue(field.name, 1)}>Option 1</span> - <span onClick={() => form.setFieldValue(field.name, 2)}>Option 2</span> - <span onClick={() => form.setFieldValue(field.name, 3)}>Option 3</span> - </Fragment> - )} - </div> -) - -export default compose( - withStateHandlers( - { open: false }, - { - toggleMenu: ({ open }) => () => ({ - open: !open, - }), - }, - ), -)(MyMenu) diff --git a/packages/component-faraday-ui/src/modals/OpenModal.js b/packages/component-faraday-ui/src/modals/OpenModal.js index d575f9a6ad599ae1512a35d76d59f8f511030ec9..6e5bc43d21ada388fc1c964b2e15fe8daae59a6c 100644 --- a/packages/component-faraday-ui/src/modals/OpenModal.js +++ b/packages/component-faraday-ui/src/modals/OpenModal.js @@ -17,6 +17,7 @@ const OpenModal = ({ content, modalKey, }) => <div>{children(showModal)}</div> + const selectModalComponent = props => { if (props.component) { return { @@ -54,15 +55,15 @@ OpenModal.propTypes = { modalKey: PropTypes.string, } OpenModal.defaultProps = { - title: undefined, - subtitle: undefined, + title: '', + subtitle: '', confirmText: 'OK', cancelText: 'Cancel', - onCancel: undefined, - onConfirm: undefined, - onClose: undefined, - content: undefined, - modalKey: undefined, + onCancel: () => {}, + onConfirm: () => {}, + onClose: () => {}, + content: null, + modalKey: 'aModal', } export default compose( diff --git a/packages/component-faraday-ui/src/modals/index.js b/packages/component-faraday-ui/src/modals/index.js index f45d2261541326dae4e34a5c8abed68aa62f2c56..fb4d8875a5d9973606474a543a65321bb1347e26 100644 --- a/packages/component-faraday-ui/src/modals/index.js +++ b/packages/component-faraday-ui/src/modals/index.js @@ -1,4 +1,3 @@ export { default as OpenModal } from './OpenModal' -export { default as FormModal } from './FormModal' export { default as MultiAction } from './MultiAction' export { default as SingleActionModal } from './SingleActionModal' diff --git a/packages/component-fixture-manager/src/helpers/Model.js b/packages/component-fixture-manager/src/helpers/Model.js index b59599b91db87ddedbc6311ce2a98ba94fb9363b..1f292351b8d27378cb54308a8d023b5b5eeabfd6 100644 --- a/packages/component-fixture-manager/src/helpers/Model.js +++ b/packages/component-fixture-manager/src/helpers/Model.js @@ -26,6 +26,9 @@ const build = fixtures => { UserMock.updateProperties = jest.fn(user => updatePropertiesMock(user, 'users'), ) + UserMock.update = jest.fn((id, input) => input) + UserMock.fetchOne = jest.fn(user => user) + UserMock.create = jest.fn(input => input) TeamMock.find = jest.fn(id => findMock(id, 'teams', fixtures)) TeamMock.updateProperties = jest.fn(team => diff --git a/packages/components-faraday/src/components/Admin/AdminRoute.js b/packages/component-user/app/AdminRoute.js similarity index 92% rename from packages/components-faraday/src/components/Admin/AdminRoute.js rename to packages/component-user/app/AdminRoute.js index 4b95cac85c1e8f52f6384f7fad2c47d8d25c0cb1..b243ce527f1a372210da8b1cfa73bbf3a5502942 100644 --- a/packages/components-faraday/src/components/Admin/AdminRoute.js +++ b/packages/component-user/app/AdminRoute.js @@ -2,8 +2,8 @@ import React from 'react' import { get } from 'lodash' import { compose } from 'recompose' import { connect } from 'react-redux' -import { Redirect, withRouter, Route } from 'react-router-dom' import { AuthenticatedComponent } from 'pubsweet-client' +import { Redirect, withRouter, Route } from 'react-router-dom' const AdminRoute = ({ currentUser, @@ -11,7 +11,7 @@ const AdminRoute = ({ component: Component, ...rest }) => { - const isAdmin = get(currentUser, 'user.admin') + const isAdmin = get(currentUser, 'user.admin', false) return ( <Route {...rest} diff --git a/packages/component-faraday-ui/src/modals/FormModal.js b/packages/component-user/app/components/AdminUserForm.js similarity index 53% rename from packages/component-faraday-ui/src/modals/FormModal.js rename to packages/component-user/app/components/AdminUserForm.js index a139df8e733baa7732263b383c066ba776220ed0..50a314f428bc0251880441d6a49f18d591d14f96 100644 --- a/packages/component-faraday-ui/src/modals/FormModal.js +++ b/packages/component-user/app/components/AdminUserForm.js @@ -4,66 +4,118 @@ import { Formik } from 'formik' import styled from 'styled-components' import { th } from '@pubsweet/ui-toolkit' import { required } from 'xpub-validators' -import { H2, Button, TextField, ValidatedFieldFormik } from '@pubsweet/ui' import { compose, setDisplayName, withHandlers, withProps } from 'recompose' +import { + H2, + Button, + Spinner, + TextField, + ValidatedFieldFormik, +} from '@pubsweet/ui' import { Row, Item, + Text, Label, IconButton, RowOverrideAlert, ItemOverrideAlert, + ValidatedMenuField, withRoles, + withFetching, withCountries, } from 'pubsweet-component-faraday-ui' -import ValidatedMenuField from './ValidatedMenuField' -import ValidatedCheckboxField from './ValidatedCheckboxField' +// #region helpers +const setInitialRole = a => { + if (get(a, 'admin', false)) { + return 'admin' + } + if (get(a, 'handlingEditor', false)) { + return 'handlingEditor' + } + if (get(a, 'editorInChief', false)) { + return 'editorInChief' + } + return 'author' +} + +const validate = values => { + const errors = {} + + if (get(values, 'email', '') === '') { + errors.email = 'Required' + } + + return errors +} +// #endregion const FormModal = ({ edit, - user, roles, title, titles, onClose, - subtitle, + onSubmit, onConfirm, countries, + isFetching, + fetchingError, + initialValues, confirmText = 'OK', cancelText = 'Cancel', - onSubmit, - initialValues, + user, }) => ( <Root> <IconButton icon="x" onClick={onClose} right={5} secondary top={5} /> <H2>{title}</H2> - <Formik initialValues={initialValues} onSubmit={onSubmit}> - {({ handleSubmit }) => ( + {edit && ( + <Text mb={1} secondary> + {get(user, 'email', '')} + </Text> + )} + <Formik + initialValues={initialValues} + onSubmit={onSubmit} + validate={validate} + > + {({ handleSubmit, ...rest }) => ( <Fragment> - <Row alignItems="baseline" mb={1} mt={1}> - <Item mr={1} vertical> - <Label required>Email</Label> - <ValidatedFieldFormik - component={TextField} - name="email" - validate={[required]} - /> - </Item> - <ItemOverrideAlert ml={1} vertical> - <Label required>Role</Label> - <ValidatedMenuField name="role" options={roles} /> - </ItemOverrideAlert> - </Row> + {!edit && ( + <Row alignItems="baseline" mb={1} mt={1}> + <ItemOverrideAlert mr={1} vertical> + <Label required>Email</Label> + <ValidatedFieldFormik + component={TextField} + inline + name="email" + validate={[required]} + /> + </ItemOverrideAlert> + <ItemOverrideAlert ml={1} vertical> + <Label required>Role</Label> + <ValidatedMenuField name="role" options={roles} /> + </ItemOverrideAlert> + </Row> + )} <Row mb={2}> <Item mr={1} vertical> <Label>First Name</Label> - <ValidatedFieldFormik component={TextField} name="firstName" /> + <ValidatedFieldFormik + component={TextField} + inline + name="firstName" + /> </Item> <Item ml={1} vertical> <Label>Last Name</Label> - <ValidatedFieldFormik component={TextField} name="lastName" /> + <ValidatedFieldFormik + component={TextField} + inline + name="lastName" + /> </Item> </Row> @@ -78,68 +130,48 @@ const FormModal = ({ </ItemOverrideAlert> </RowOverrideAlert> - <Row mb={!edit && 3}> - <Item vertical> + <Row mb={3}> + {edit && ( + <ItemOverrideAlert mr={1} vertical> + <Label required>Role</Label> + <ValidatedMenuField name="role" options={roles} /> + </ItemOverrideAlert> + )} + <Item ml={edit && 1} vertical> <Label>Affiliation</Label> - <ValidatedFieldFormik component={TextField} name="affiliation" /> + <ValidatedFieldFormik + component={TextField} + inline + name="affiliation" + /> </Item> </Row> - {edit && ( - <RowOverrideAlert mb={3}> - <Item> - <ValidatedCheckboxField - label="Editor in Chief" - name="editorInChief" - /> - </Item> - <Item> - <ValidatedCheckboxField label="Admin" name="admin" /> - </Item> - <Item> - <ValidatedCheckboxField - label="Handling Editor" - name="handlingEditor" - /> - </Item> - </RowOverrideAlert> + {fetchingError && ( + <Row mb={1}> + <Text error>{fetchingError}</Text> + </Row> )} - <Row> - <Button onClick={onClose}>Cancel</Button> - <Button onClick={handleSubmit} primary> - {confirmText} - </Button> - </Row> + {isFetching ? ( + <Spinner /> + ) : ( + <Row> + <Button onClick={onClose}>Cancel</Button> + <Button onClick={handleSubmit} primary> + {confirmText} + </Button> + </Row> + )} </Fragment> )} </Formik> </Root> ) -// #region FormHelpers -const setInitialRole = a => { - if (get(a, 'handlingEditor')) { - return 'handlingEditor' - } - if (get(a, 'editorInChief')) { - return 'editorInChief' - } - return 'author' -} - -const parseValues = ({ email, role, ...rest }) => ({ - email, - username: email, - admin: role === 'admin', - editorInChief: role === 'editorInChief', - handlingEditor: role === 'handlingEditor', - ...rest, -}) -// #endregion - export default compose( withRoles, + withFetching, withCountries, withProps(({ user, edit }) => ({ initialValues: { @@ -152,7 +184,7 @@ export default compose( withHandlers({ onSubmit: ({ onSubmit, ...props }) => (values, formProps) => { if (typeof onSubmit === 'function') { - onSubmit(parseValues(values), { formProps, props }) + onSubmit(values, { ...formProps, ...props }) } }, onClose: ({ onCancel, ...props }) => () => { @@ -163,7 +195,7 @@ export default compose( }, }), - setDisplayName('FormModal'), + setDisplayName('AdminUserForm'), )(FormModal) // #region styles diff --git a/packages/component-user/app/components/OpenStatusModal.js b/packages/component-user/app/components/OpenStatusModal.js new file mode 100644 index 0000000000000000000000000000000000000000..f97ea6a7ec8b6c945b9959cc0f5735fdab35124f --- /dev/null +++ b/packages/component-user/app/components/OpenStatusModal.js @@ -0,0 +1,46 @@ +import React from 'react' +import { Button } from '@pubsweet/ui' +import styled from 'styled-components' +import { th } from '@pubsweet/ui-toolkit' +import { withHandlers, compose, setDisplayName } from 'recompose' +import { OpenModal, withFetching } from 'pubsweet-component-faraday-ui' + +const OpenStatusModal = ({ + onConfirm, + isFetching, + user: { id, firstName = '', lastName = '', isActive }, +}) => ( + <OpenModal + isFetching={isFetching} + modalKey={`deactivate-${id}`} + onConfirm={onConfirm} + subtitle={`${firstName} ${lastName}`} + title={`Are you sure you want to ${ + !isActive ? 'activate' : 'deactivate' + } user?`} + > + {showModal => ( + <ActivateButton ml={1} mr={1} onClick={showModal} size="small"> + {!isActive ? 'ACTIVATE' : 'DEACTIVATE'} + </ActivateButton> + )} + </OpenModal> +) + +export default compose( + withFetching, + withHandlers({ + onConfirm: ({ user, onConfirm, ...props }) => modalProps => { + if (typeof onConfirm === 'function') { + onConfirm(user, { ...props, ...modalProps }) + } + }, + }), + setDisplayName('AdminStatusModal'), +)(OpenStatusModal) + +// #region styles +const ActivateButton = styled(Button)` + width: calc(${th('gridUnit')} * 10); +` +// #endregion diff --git a/packages/components-faraday/src/components/Admin/OpenUserForm.js b/packages/component-user/app/components/OpenUserForm.js similarity index 89% rename from packages/components-faraday/src/components/Admin/OpenUserForm.js rename to packages/component-user/app/components/OpenUserForm.js index 63b03c13f5c0ee40da1784ea55961fd185c89716..985c02360c081f1f71128f3c398baa6d57e473bd 100644 --- a/packages/components-faraday/src/components/Admin/OpenUserForm.js +++ b/packages/component-user/app/components/OpenUserForm.js @@ -6,10 +6,12 @@ import { IconButton, } from 'pubsweet-component-faraday-ui' +import AdminUserForm from './AdminUserForm' + const OpenUserForm = ({ edit, user, onSubmit, modalKey }) => ( <OpenModal + component={AdminUserForm} edit={edit} - formModal modalKey={modalKey} onSubmit={onSubmit} user={user} @@ -18,9 +20,9 @@ const OpenUserForm = ({ edit, user, onSubmit, modalKey }) => ( edit ? ( <IconButton fontIcon="editIcon" - paddingBottom={1.5} iconSize={2} onClick={showModal} + paddingBottom={1.5} pt={1 / 2} /> ) : ( diff --git a/packages/component-user/app/components/index.js b/packages/component-user/app/components/index.js new file mode 100644 index 0000000000000000000000000000000000000000..900efc4da7fce9eeff226effb58fff0f6e4305f6 --- /dev/null +++ b/packages/component-user/app/components/index.js @@ -0,0 +1,3 @@ +export { default as AdminUserForm } from './AdminUserForm' +export { default as OpenStatusModal } from './OpenStatusModal' +export { default as OpenUserForm } from './OpenUserForm' diff --git a/packages/component-user/app/graphql/fragments.js b/packages/component-user/app/graphql/fragments.js new file mode 100644 index 0000000000000000000000000000000000000000..36282982757d503eeb0a8da401ea3693c59a6ecb --- /dev/null +++ b/packages/component-user/app/graphql/fragments.js @@ -0,0 +1,18 @@ +import gql from 'graphql-tag' + +export const userFragment = gql` + fragment userDetails on User { + id + admin + email + title + country + username + lastName + isActive + firstName + affiliation + editorInChief + handlingEditor + } +` diff --git a/packages/component-user/app/graphql/index.js b/packages/component-user/app/graphql/index.js new file mode 100644 index 0000000000000000000000000000000000000000..cf105b664973c3d29668b05ebce1ccc06b981c21 --- /dev/null +++ b/packages/component-user/app/graphql/index.js @@ -0,0 +1,6 @@ +import * as fragments from './fragments' +import * as queries from './queries' +import * as mutations from './mutations' + +export { fragments, queries, mutations } +export { default } from './withUsersGQL' diff --git a/packages/component-user/app/graphql/mutations.js b/packages/component-user/app/graphql/mutations.js new file mode 100644 index 0000000000000000000000000000000000000000..fed993f4c47abed820d098295348c30adb5e5cbb --- /dev/null +++ b/packages/component-user/app/graphql/mutations.js @@ -0,0 +1,30 @@ +import gql from 'graphql-tag' + +import { userFragment } from './fragments' + +export const addUserAsAdmin = gql` + mutation addUserAsAdmin($input: UserInput!) { + addUserAsAdmin(input: $input) { + ...userDetails + } + } + ${userFragment} +` + +export const editUserAsAdmin = gql` + mutation editUserAsAdmin($id: ID!, $input: UserInput!) { + editUserAsAdmin(id: $id, input: $input) { + ...userDetails + } + } + ${userFragment} +` + +export const activateUserAsAdmin = gql` + mutation activateUserAsAdmin($id: ID!, $input: ActivateUserInput) { + activateUserAsAdmin(id: $id, input: $input) { + ...userDetails + } + } + ${userFragment} +` diff --git a/packages/component-user/app/graphql/queries.js b/packages/component-user/app/graphql/queries.js new file mode 100644 index 0000000000000000000000000000000000000000..9e65b0e68fb74d888b2d7d82c1d0929977bbf979 --- /dev/null +++ b/packages/component-user/app/graphql/queries.js @@ -0,0 +1,12 @@ +import gql from 'graphql-tag' + +import { userFragment } from './fragments' + +export const getUsers = gql` + { + users { + ...userDetails + } + } + ${userFragment} +` diff --git a/packages/component-user/app/graphql/withUsersGQL.js b/packages/component-user/app/graphql/withUsersGQL.js new file mode 100644 index 0000000000000000000000000000000000000000..aceee93b7866cb01e3d55256cdad7b479723ee71 --- /dev/null +++ b/packages/component-user/app/graphql/withUsersGQL.js @@ -0,0 +1,24 @@ +import { graphql } from 'react-apollo' +import { compose, withProps } from 'recompose' + +import * as queries from './queries' +import * as mutations from './mutations' + +export default compose( + graphql(queries.getUsers), + graphql(mutations.addUserAsAdmin, { + name: 'addUser', + options: { + refetchQueries: [{ query: queries.getUsers }], + }, + }), + graphql(mutations.editUserAsAdmin, { + name: 'updateUser', + }), + graphql(mutations.activateUserAsAdmin, { + name: 'activateUser', + }), + withProps(({ data }) => ({ + users: data.users, + })), +) diff --git a/packages/component-user/app/index.js b/packages/component-user/app/index.js new file mode 100644 index 0000000000000000000000000000000000000000..5cf2fee3273bda71f3524edd593d282797a0802b --- /dev/null +++ b/packages/component-user/app/index.js @@ -0,0 +1,3 @@ +export { default as AdminRoute } from './AdminRoute' +export { default as AdminUsers } from './pages/AdminUsers' +export { default as AdminDashboard } from './pages/AdminDashboard' diff --git a/packages/components-faraday/src/components/Admin/AdminDashboard.js b/packages/component-user/app/pages/AdminDashboard.js similarity index 100% rename from packages/components-faraday/src/components/Admin/AdminDashboard.js rename to packages/component-user/app/pages/AdminDashboard.js diff --git a/packages/components-faraday/src/components/Admin/AdminUsers.js b/packages/component-user/app/pages/AdminUsers.js similarity index 70% rename from packages/components-faraday/src/components/Admin/AdminUsers.js rename to packages/component-user/app/pages/AdminUsers.js index a28c576d7a4106e362ba3d6e5bbc2404f7941260..a76b5689c17a806f9e582461d2b9ade953cb5770 100644 --- a/packages/components-faraday/src/components/Admin/AdminUsers.js +++ b/packages/component-user/app/pages/AdminUsers.js @@ -1,6 +1,5 @@ import React, { Fragment } from 'react' import { get } from 'lodash' -import { Button } from '@pubsweet/ui' import styled from 'styled-components' import { th } from '@pubsweet/ui-toolkit' import { withJournal } from 'xpub-journal' @@ -11,35 +10,27 @@ import { Text, Item, Label, - OpenModal, Pagination, ActionLink, - handleError, - withFetching, withPagination, } from 'pubsweet-component-faraday-ui' -import { updateUserStatus } from './utils' -import { OpenUserForm, withUsersGQL } from './' +import withUsersGQL from '../graphql' +import { OpenUserForm, OpenStatusModal } from '../components' const Users = ({ page, users, - theme, history, journal, - getUsers, - isFetching, + addUser, + updateUser, getUserName, getUserRoles, itemsPerPage, - deactivateUser, getStatusLabel, paginatedItems, toggleUserStatus, - // - addUser, - updateUser, ...rest }) => ( <Fragment> @@ -48,9 +39,9 @@ const Users = ({ <ActionLink data-test-id="go-to-dashboard" fontIcon="arrowLeft" - paddingBottom={1.2} mr={2} onClick={history.goBack} + paddingBottom={1.2} > Admin Dashboard </ActionLink> @@ -108,26 +99,8 @@ const Users = ({ onSubmit={updateUser} user={user} /> - <OpenModal - isFetching={isFetching} - modalKey={`deactivate-${user.id}`} - onConfirm={deactivateUser(user)} - subtitle={`${user.firstName} ${user.lastName}`} - title={`Are you sure to ${ - !user.isActive ? 'activate' : 'deactivate' - } user?`} - > - {showModal => ( - <ActivateButton - ml={1} - mr={1} - onClick={showModal} - size="small" - > - {!user.isActive ? 'ACTIVATE' : 'DEACTIVATE'} - </ActivateButton> - )} - </OpenModal> + + <OpenStatusModal onConfirm={toggleUserStatus} user={user} /> </Item> </HiddenCell> </UserRow> @@ -139,7 +112,6 @@ const Users = ({ export default compose( withJournal, - withFetching, withUsersGQL, withProps(({ journal: { roles = {} }, users }) => ({ roles: Object.keys(roles), @@ -154,20 +126,86 @@ export default compose( } return isConfirmed ? 'ACTIVE' : 'INVITED' }, - deactivateUser: ({ setFetching, getUsers }) => user => ({ - hideModal, - setModalError, - }) => { + addUser: ({ addUser }) => ( + { + __typename, + id, + admin, + isActive, + editorInChief, + handlingEditor, + ...input + }, + { setFetching, hideModal, setError }, + ) => { + setFetching(true) + addUser({ + variables: { + input: { + ...input, + username: input.email, + }, + }, + }) + .then(() => { + setFetching(false) + hideModal() + }) + .catch(e => { + setFetching(false) + setError(e.message) + }) + }, + updateUser: ({ updateUser }) => ( + { + __typename, + id, + admin, + isActive, + handlingEditor, + editorInChief, + ...input + }, + { setFetching, hideModal, setError }, + ) => { + setFetching(true) + updateUser({ + variables: { + id, + input, + }, + }) + .then(() => { + setFetching(false) + hideModal() + }) + .catch(e => { + setFetching(false) + setError(e.message) + }) + }, + toggleUserStatus: ({ activateUser }) => ( + { id, email, username, isActive }, + { setFetching, hideModal, setModalError }, + ) => { setFetching(true) - updateUserStatus(user) + activateUser({ + variables: { + id, + input: { + email, + username, + isActive, + }, + }, + }) .then(() => { setFetching(false) - getUsers() hideModal() }) - .catch(err => { + .catch(e => { setFetching(false) - handleError(setModalError)(err) + setModalError(e.message) }) }, getUserName: () => user => { @@ -215,7 +253,3 @@ const UserRow = styled.tr` } } ` -const ActivateButton = styled(Button)` - width: 90px; -` -// #endregion diff --git a/packages/component-user/index.js b/packages/component-user/index.js index 307f862c05b48216eedc7514a3a76bf38f06eb11..c9b9c509b1ff10cbe0cd4af9b5e99c83429a9450 100644 --- a/packages/component-user/index.js +++ b/packages/component-user/index.js @@ -1,10 +1,7 @@ -const resolvers = require('./resolvers') -const typeDefs = require('./typeDefs') -const model = require('./user') +const resolvers = require('./server/resolvers') +const typeDefs = require('./server/typeDefs') module.exports = { - model, - modelName: 'User', - resolvers, typeDefs, + resolvers, } diff --git a/packages/component-user/package.json b/packages/component-user/package.json new file mode 100644 index 0000000000000000000000000000000000000000..fe634328db1f0bff247365e65866c259ecdbd65d --- /dev/null +++ b/packages/component-user/package.json @@ -0,0 +1,51 @@ +{ + "name": "pubsweet-component-user", + "version": "0.0.1", + "description": "User component for Hindawi peer review app.", + "license": "MIT", + "author": "Collaborative Knowledge Foundation", + "files": ["src"], + "main": "index.js", + "scripts": { + "test": "jest", + "docs": + "./node_modules/.bin/apidoc -e \"(node_modules|public)\" -o public/apidoc", + "open-docs": "open public/apidoc/index.html" + }, + "repository": { + "type": "git", + "url": "https://gitlab.coko.foundation/xpub/xpub-faraday", + "path": "component-user" + }, + "dependencies": { + "@pubsweet/ui": "^9.0.3", + "@pubsweet/ui-toolkit": "^2.0.3", + "chance": "^1.0.13", + "formik": "^1.4.0", + "graphql-tag": "^2.10.0", + "lodash": "^4.17.11", + "pubsweet-client": "^7.0.0", + "pubsweet-server": "^10.0.0", + "pubsweet-component-helper-service": "0.0.1", + "react": "^16.6.0", + "react-apollo": "^2.3.2", + "react-dom": "^16.6.0", + "react-redux": "^5.0.2", + "react-router-dom": "^4.2.2", + "recompose": "^0.30.0", + "styled-components": "^4.1.2", + "xpub-validators": "^0.0.6" + }, + "devDependencies": { + "apidoc": "^0.17.6", + "jest": "^23.6.0", + "supertest": "^3.0.0" + }, + "jest": { + "verbose": true, + "testRegex": "/server/.*.test.js$" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/component-user/resolvers.js b/packages/component-user/resolvers.js deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/packages/component-user/server/notifications/emailCopy.js b/packages/component-user/server/notifications/emailCopy.js new file mode 100644 index 0000000000000000000000000000000000000000..b8c618a83b4b1a6cddea14520e5aa142adfc1cf4 --- /dev/null +++ b/packages/component-user/server/notifications/emailCopy.js @@ -0,0 +1,33 @@ +const config = require('config') + +const journalName = config.get('journal.name') +const getEmailCopy = ({ emailType, role }) => { + let paragraph + let hasIntro = true + let hasSignature = true + switch (emailType) { + case 'user-signup': + paragraph = `Thank you for creating an account on Hindawi’s review system. + To submit a manuscript and access your dashboard, please confirm your account by clicking on the link below.` + break + case 'user-added-by-admin': + hasIntro = false + hasSignature = false + paragraph = `You have been invited to join Hindawi as a ${role}. + Please confirm your account and set your account details by clicking on the link below.` + break + case 'he-added-by-admin': + paragraph = `You have been invited to become an Academic Editor for the journal ${journalName}. + To begin performing your editorial duties, you will need to create an account on Hindawi’s review system.<br/><br/> + Please confirm your account details by clicking on the link below.` + break + default: + throw new Error(`The ${emailType} email type is not defined.`) + } + + return { paragraph, hasLink: true, hasIntro, hasSignature } +} + +module.exports = { + getEmailCopy, +} diff --git a/packages/component-user/server/notifications/notification.js b/packages/component-user/server/notifications/notification.js new file mode 100644 index 0000000000000000000000000000000000000000..c32282a6e7cbd60bd91ec4eb24add9254fa4fc95 --- /dev/null +++ b/packages/component-user/server/notifications/notification.js @@ -0,0 +1,58 @@ +const config = require('config') +const Email = require('@pubsweet/component-email-templating') +const { services } = require('pubsweet-component-helper-service') + +const { getEmailCopy } = require('./emailCopy') + +const { name: journalName, staffEmail } = config.get('journal') +const unsubscribeSlug = config.get('unsubscribe.url') + +class Notification { + constructor(user) { + this.user = user + } + + async notifyUserAddedByAdmin(role) { + const resetPath = config.get('invite-reset-password.url') + const { user } = this + const baseUrl = config.get('pubsweet-client.baseUrl') + const emailType = + role === 'Handling Editor' ? 'he-added-by-admin' : 'user-added-by-admin' + + const { paragraph, ...bodyProps } = getEmailCopy({ + role, + emailType, + }) + + const email = new Email({ + type: 'user', + fromEmail: `${journalName} <${staffEmail}>`, + toUser: { + email: user.email, + }, + content: { + subject: 'Confirm your account', + ctaLink: services.createUrl(baseUrl, resetPath, { + email: user.email, + token: user.accessTokens.passwordReset, + firstName: user.firstName, + lastName: user.lastName, + affiliation: user.affiliation, + title: user.title, + country: user.country, + }), + ctaText: 'CONFIRM ACCOUNT', + paragraph, + unsubscribeLink: services.createUrl(baseUrl, unsubscribeSlug, { + id: user.id, + token: user.accessTokens.unsubscribe, + }), + }, + bodyProps, + }) + + return email.sendEmail() + } +} + +module.exports = Notification diff --git a/packages/component-user/server/resolvers.js b/packages/component-user/server/resolvers.js new file mode 100644 index 0000000000000000000000000000000000000000..dd914063955f0aeee31ef236bb7dd79e82f63aa7 --- /dev/null +++ b/packages/component-user/server/resolvers.js @@ -0,0 +1,41 @@ +const Notification = require('./notifications/notification') + +const { parseUserFromAdmin } = require('./user') + +const { + editUser, + activateUser, + deactivateUser, + createUserAsAdmin, +} = require('./use-cases') + +const resolvers = { + Mutation: { + async addUserAsAdmin(_, { input }, ctx) { + return createUserAsAdmin + .initialize({ + ctx, + Notification, + User: ctx.connectors.User, + }) + .execute({ input: parseUserFromAdmin(input) }) + }, + async editUserAsAdmin(_, { id, input }, ctx) { + return editUser + .initialize({ User: ctx.connectors.User, ctx }) + .execute({ id, input: parseUserFromAdmin(input) }) + }, + async toggleUserActiveStatusAsAdmin(_, { id, input }, ctx) { + if (input.isActive) { + return activateUser + .initialize({ User: ctx.connectors.User, ctx }) + .execute({ id, input }) + } + return deactivateUser + .initialize({ User: ctx.connectors.User, ctx }) + .execute({ id, input }) + }, + }, +} + +module.exports = resolvers diff --git a/packages/component-user/server/tests/activateUser.test.js b/packages/component-user/server/tests/activateUser.test.js new file mode 100644 index 0000000000000000000000000000000000000000..864b65f69fcb0aea2816002a6eb09c3a0cdea405 --- /dev/null +++ b/packages/component-user/server/tests/activateUser.test.js @@ -0,0 +1,28 @@ +const { cloneDeep } = require('lodash') +const { Model, fixtures } = require('pubsweet-component-fixture-service') + +const { activateUser } = require('../use-cases') + +describe('activate use case', () => { + let testFixtures = {} + let models + const invalidPrefix = 'invalid***' + + beforeEach(() => { + testFixtures = cloneDeep(fixtures) + models = Model.build(testFixtures) + }) + + it('activate an user', async () => { + const { user } = testFixtures.users + user.username = `${invalidPrefix}${user.username}` + user.isActive = false + + const result = await activateUser + .initialize({ User: models.User }) + .execute({ id: user.id, input: user }) + + expect(result.isActive).toBeTruthy() + expect(result.username.indexOf(invalidPrefix)).toBeLessThan(0) + }) +}) diff --git a/packages/component-user/server/tests/createUserAsAdmin.test.js b/packages/component-user/server/tests/createUserAsAdmin.test.js new file mode 100644 index 0000000000000000000000000000000000000000..80c3155a6d7fbbf00043cf714312d256e3146c97 --- /dev/null +++ b/packages/component-user/server/tests/createUserAsAdmin.test.js @@ -0,0 +1,64 @@ +const { cloneDeep } = require('lodash') +const { Model, fixtures } = require('pubsweet-component-fixture-service') + +const { createUserAsAdmin } = require('../use-cases') + +class MockNotification { + constructor(user) { + this.user = user + } + + async notifyUserAddedByAdmin(role) { + jest.fn(() => this) + } +} + +describe('create user', () => { + let testFixtures = {} + let models + + beforeEach(() => { + testFixtures = cloneDeep(fixtures) + models = Model.build(testFixtures) + }) + + it('edit an user as admin', async () => { + const input = { + email: 'alexandrescu@gmail.com', + username: 'alexandrescu@gmail.com', + } + const ctx = { + user: { + admin: true, + }, + } + + const result = await createUserAsAdmin + .initialize({ User: models.User, Notification: MockNotification, ctx }) + .execute({ + input, + }) + + expect(result).toMatchObject(input) + }) + + it('does not allow non admins to create user', async (...props) => { + const ctx = { + user: { + admin: false, + }, + } + + try { + await createUserAsAdmin + .initialize({ + User: models.User, + Notification: MockNotification, + ctx, + }) + .execute({}) + } catch (e) { + expect(e.message).toBe('Unauthorized') + } + }) +}) diff --git a/packages/component-user/server/tests/deactivateUser.test.js b/packages/component-user/server/tests/deactivateUser.test.js new file mode 100644 index 0000000000000000000000000000000000000000..46a335ffa0bee01cb24f86ebb8c87351cf7b3b71 --- /dev/null +++ b/packages/component-user/server/tests/deactivateUser.test.js @@ -0,0 +1,28 @@ +const { cloneDeep } = require('lodash') +const { Model, fixtures } = require('pubsweet-component-fixture-service') + +const { deactivateUser } = require('../use-cases') + +describe('deactivate use case', () => { + let testFixtures = {} + let models + const invalidPrefix = 'invalid***' + + beforeEach(() => { + testFixtures = cloneDeep(fixtures) + models = Model.build(testFixtures) + }) + + it('deactivate an user', async () => { + const { user } = testFixtures.users + user.isActive = false + + const result = await deactivateUser + .initialize({ User: models.User }) + .execute({ id: user.id, input: user }) + + expect(result.isActive).toBeFalsy() + // invalid prefix should be present in the username + expect(result.username.indexOf(invalidPrefix)).toBeGreaterThanOrEqual(0) + }) +}) diff --git a/packages/component-user/server/tests/editUser.test.js b/packages/component-user/server/tests/editUser.test.js new file mode 100644 index 0000000000000000000000000000000000000000..baf29782f84c01334faaf59a732e978f8ed8fb25 --- /dev/null +++ b/packages/component-user/server/tests/editUser.test.js @@ -0,0 +1,30 @@ +const { cloneDeep } = require('lodash') +const { Model, fixtures } = require('pubsweet-component-fixture-service') + +const { editUser } = require('../use-cases') + +describe('edit user as admin', () => { + let testFixtures = {} + let models + + beforeEach(() => { + testFixtures = cloneDeep(fixtures) + models = Model.build(testFixtures) + }) + + it('edit an user', async () => { + const { user } = testFixtures.users + const input = { + ...user, + affiliation: 'TSD', + firstName: 'Sebibastian', + } + + const result = await editUser.initialize({ User: models.User }).execute({ + id: input.id, + input, + }) + + expect(result).toMatchObject(input) + }) +}) diff --git a/packages/component-user/typeDefs.js b/packages/component-user/server/typeDefs.js similarity index 52% rename from packages/component-user/typeDefs.js rename to packages/component-user/server/typeDefs.js index 3583a27be3d3a91e4f8aeb6de76bb57b59a1a001..249a380d2e775f1911c69fe9d95f75cc0279dffe 100644 --- a/packages/component-user/typeDefs.js +++ b/packages/component-user/server/typeDefs.js @@ -1,9 +1,4 @@ module.exports = ` - type Creasta { - id: String! - name: String - } - extend type User { affiliation: String country: String @@ -17,15 +12,30 @@ module.exports = ` } extend input UserInput { - isActive: Boolean - isConfirmed: Boolean firstName: String lastName: String title: String country: String affiliation: String - admin: Boolean - editorInChief: Boolean - handlingEditor: Boolean + role: AllowedRole + } + + input UserStatusInput { + email: String! + username: String! + isActive: Boolean + } + + extend type Mutation { + addUserAsAdmin(input: UserInput!): User + editUserAsAdmin(id: ID!, input: UserInput!): User + toggleUserActiveStatusAsAdmin(id: ID!, input: UserStatusInput): User + } + + enum AllowedRole { + editorInChief + handlingEditor + admin + author } ` diff --git a/packages/component-user/server/use-cases/activateUser.js b/packages/component-user/server/use-cases/activateUser.js new file mode 100644 index 0000000000000000000000000000000000000000..7572f52fc44f815a837bcb671d8699803cd2e2c0 --- /dev/null +++ b/packages/component-user/server/use-cases/activateUser.js @@ -0,0 +1,6 @@ +module.exports.initialize = ({ User, ctx }) => ({ + execute: async ({ id, input }) => { + const username = input.username.replace('invalid***', '') + return User.update(id, { ...input, username, isActive: true }, ctx) + }, +}) diff --git a/packages/component-user/server/use-cases/createUserAsAdmin.js b/packages/component-user/server/use-cases/createUserAsAdmin.js new file mode 100644 index 0000000000000000000000000000000000000000..6a46215e4067744cd558983c6bd8aed3be95aacb --- /dev/null +++ b/packages/component-user/server/use-cases/createUserAsAdmin.js @@ -0,0 +1,14 @@ +module.exports.initialize = ({ User, Notification, ctx }) => ({ + execute: async ({ input }) => { + const { admin } = await User.fetchOne(ctx.user, ctx) + if (!admin) { + throw new Error('Unauthorized') + } + + const user = await User.create(input, ctx) + const notification = new Notification(user) + await notification.notifyUserAddedByAdmin(input.role) + + return user + }, +}) diff --git a/packages/component-user/server/use-cases/deactivateUser.js b/packages/component-user/server/use-cases/deactivateUser.js new file mode 100644 index 0000000000000000000000000000000000000000..6c1703b638ea4bd75541a1c09465dd2e517cbd5b --- /dev/null +++ b/packages/component-user/server/use-cases/deactivateUser.js @@ -0,0 +1,7 @@ +module.exports.initialize = ({ User, ctx }) => ({ + execute: async ({ id, input }) => { + const username = `invalid***${input.username}` + + return User.update(id, { ...input, username, isActive: false }, ctx) + }, +}) diff --git a/packages/component-user/server/use-cases/editUser.js b/packages/component-user/server/use-cases/editUser.js new file mode 100644 index 0000000000000000000000000000000000000000..fff98ac5cebd104c24f899fa92bebd847c7c10c4 --- /dev/null +++ b/packages/component-user/server/use-cases/editUser.js @@ -0,0 +1,3 @@ +module.exports.initialize = ({ User, ctx }) => ({ + execute: ({ id, input }) => User.update(id, input, ctx), +}) diff --git a/packages/component-user/server/use-cases/index.js b/packages/component-user/server/use-cases/index.js new file mode 100644 index 0000000000000000000000000000000000000000..00ff37cad94784492bb38a8579aab8d664feff9c --- /dev/null +++ b/packages/component-user/server/use-cases/index.js @@ -0,0 +1,11 @@ +const activateUser = require('./activateUser') +const deactivateUser = require('./deactivateUser') +const editUser = require('./editUser') +const createUserAsAdmin = require('./createUserAsAdmin') + +module.exports = { + editUser, + activateUser, + deactivateUser, + createUserAsAdmin, +} diff --git a/packages/component-user/server/user.js b/packages/component-user/server/user.js new file mode 100644 index 0000000000000000000000000000000000000000..83e107959aab56dc564e63a869843f55fa02642d --- /dev/null +++ b/packages/component-user/server/user.js @@ -0,0 +1,34 @@ +const Chance = require('chance') +const { omit } = require('lodash') + +const chance = new Chance() + +module.exports = { + parseUserFromAdmin: input => { + const roles = { + admin: false, + editorInChief: false, + handlingEditor: false, + } + if (input.role && input.role !== 'author') { + roles[input.role] = true + } + + return { + ...omit(input, ['role']), + ...roles, + isActive: true, + isConfirmed: false, + notifications: { + email: { + system: true, + user: true, + }, + }, + accessTokens: { + passwordReset: chance.hash(), + unsubscribe: chance.hash(), + }, + } + }, +} diff --git a/packages/component-user/user.js b/packages/component-user/user.js deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/packages/components-faraday/src/components/Admin/index.js b/packages/components-faraday/src/components/Admin/index.js deleted file mode 100644 index 0bb7e9bedd5aa30878c77cf7bea2da6a179a7d31..0000000000000000000000000000000000000000 --- a/packages/components-faraday/src/components/Admin/index.js +++ /dev/null @@ -1,6 +0,0 @@ -export { default as withUsersGQL } from './withUsersGQL' - -export { default as AdminUsers } from './AdminUsers' -export { default as AdminRoute } from './AdminRoute' -export { default as OpenUserForm } from './OpenUserForm' -export { default as AdminDashboard } from './AdminDashboard' diff --git a/packages/components-faraday/src/components/Admin/utils.js b/packages/components-faraday/src/components/Admin/utils.js deleted file mode 100644 index 14835de252aa01e7e57419f3f28edbb8eca00136..0000000000000000000000000000000000000000 --- a/packages/components-faraday/src/components/Admin/utils.js +++ /dev/null @@ -1,86 +0,0 @@ -import { pick, omit, isBoolean, replace } from 'lodash' -import { update } from 'pubsweet-client/src/helpers/api' - -const generatePasswordHash = () => - Array.from({ length: 4 }, () => - Math.random() - .toString(36) - .slice(4), - ).join('') - -export const setAdmin = values => { - const newValues = { ...values, isActive: true } - if (newValues.roles && newValues.roles.includes('admin')) { - newValues.admin = true - } else { - newValues.admin = false - } - - return { - ...omit(newValues, ['role']), - username: newValues.email, - isConfirmed: false, - password: 'defaultpass', - editorInChief: newValues.role === 'editorInChief', - handlingEditor: newValues.role === 'handlingEditor', - notifications: { - email: { - system: true, - user: true, - }, - }, - accessTokens: { - passwordReset: generatePasswordHash(), - unsubscribe: generatePasswordHash(), - }, - } -} - -export const parseUpdateUser = values => { - const parsedValues = { - ...values, - editorInChief: values.editorInChief || false, - handlingEditor: values.handlingEditor || false, - admin: values.admin || false, - } - const valuesToSave = [ - 'admin', - 'firstName', - 'lastName', - 'affiliation', - 'title', - 'roles', - 'editorInChief', - 'handlingEditor', - 'isActive', - 'username', - 'country', - 'accessTokens', - ] - - return pick(parsedValues, valuesToSave) -} - -const toggleUserStatus = user => { - const { isActive, username } = user - let newState = true - let newUsername = '' - - if (!isBoolean(isActive) || isActive) { - newState = false - newUsername = `invalid***${username}` - } else { - newUsername = replace(username, 'invalid***', '') - } - - return { - ...user, - isActive: newState, - username: newUsername, - } -} - -export const updateUserStatus = user => { - const updatedUser = toggleUserStatus(user) - return update(`/users/${user.id}`, parseUpdateUser(updatedUser)) -} diff --git a/packages/components-faraday/src/components/Admin/withUsersGQL.js b/packages/components-faraday/src/components/Admin/withUsersGQL.js deleted file mode 100644 index 807a319249eb930c93cbbd45f41b4779ee69b658..0000000000000000000000000000000000000000 --- a/packages/components-faraday/src/components/Admin/withUsersGQL.js +++ /dev/null @@ -1,75 +0,0 @@ -import gql from 'graphql-tag' -import { graphql } from 'react-apollo' -import { compose, withHandlers, withProps } from 'recompose' - -const userFragment = gql` - fragment userDetails on User { - id - admin - email - title - country - username - lastName - isActive - firstName - affiliation - isConfirmed - editorInChief - handlingEditor - } -` - -const getUsersQuery = gql` - { - users { - ...userDetails - } - } - ${userFragment} -` - -const addUserMutation = gql` - mutation addUser($user: UserInput) { - createUser(input: $user) { - ...userDetails - } - } - ${userFragment} -` - -const updateUserMutation = gql` - mutation updateUser($id: ID, $input: UserInput) { - updateUser(id: $id, input: $input) { - ...userDetails - } - } - ${userFragment} -` - -export default compose( - graphql(getUsersQuery), - graphql(addUserMutation, { - name: 'addUser', - }), - graphql(updateUserMutation, { - name: 'updateUser', - }), - withHandlers({ - addUser: ({ addUser }) => (values, props) => {}, - updateUser: ({ updateUser }) => ( - { __typename, id, ...input }, - { props: { hideModal } }, - ) => { - updateUser({ - variables: { - id, - input, - }, - }).then(hideModal) - }, - }), - withProps(({ data }) => ({ - users: data.users, - })), -) diff --git a/packages/xpub-faraday/app/routes.js b/packages/xpub-faraday/app/routes.js index 95a60cdedf33e26ba516608667d3c78959b63bcc..cbc1a4804a6816c416e6bd83deff04b4aa891be5 100644 --- a/packages/xpub-faraday/app/routes.js +++ b/packages/xpub-faraday/app/routes.js @@ -11,6 +11,12 @@ import { UserProfilePage, ChangePasswordPage, } from 'pubsweet-components-faraday/src/components' + +import { + AdminRoute, + AdminUsers, + AdminDashboard, +} from 'pubsweet-component-user/app' import { ManuscriptPage } from 'pubsweet-component-manuscript/src/components' import DashboardPage from 'pubsweet-components-faraday/src/components/Dashboard' import LoginPage from 'pubsweet-components-faraday/src/components/Login/LoginPage' @@ -22,11 +28,6 @@ import { EQSDecisionPage, EQADecisionPage, } from 'pubsweet-components-faraday/src/components/UIComponents/' -import { - AdminUsers, - AdminRoute, - AdminDashboard, -} from 'pubsweet-components-faraday/src/components/Admin' import { ConfirmAccount, ReviewerSignUp, diff --git a/packages/xpub-faraday/config/authsome-mode.js b/packages/xpub-faraday/config/authsome-mode.js index f739b073104cea996d271dc6190ca908e7d08421..9bba3c507b3fc83fc986a4d7680ab0ce25d80d2e 100644 --- a/packages/xpub-faraday/config/authsome-mode.js +++ b/packages/xpub-faraday/config/authsome-mode.js @@ -226,6 +226,14 @@ async function applyAuthenticatedUserPolicy(user, operation, object, context) { ) { return helpers.isOwner({ user, object: object.fragment }) } + + // allow user to authenticate itself + if ( + get(object, 'type') === 'user' && + get(object, 'id') === get(user, 'id') + ) { + return true + } } if (operation === 'PATCH') { diff --git a/packages/xpub-faraday/config/components.json b/packages/xpub-faraday/config/components.json index 3083694230c19476ca18ffaac0a8d84ed7bf67e5..044b6a295a9bdb2f85b1fd4ad051fe37a8db7882 100644 --- a/packages/xpub-faraday/config/components.json +++ b/packages/xpub-faraday/config/components.json @@ -10,5 +10,6 @@ "pubsweet-component-email", "pubsweet-component-manuscript", "pubsweet-component-manuscript-manager", - "pubsweet-component-publons" + "pubsweet-component-publons", + "pubsweet-component-user" ] diff --git a/packages/xpub-faraday/config/default.js b/packages/xpub-faraday/config/default.js index 13eed68fde3e75c0cea41cde6d77d128783590d3..dff2f0db73f57fbf0b8023dce9a71a4f17ce0602 100644 --- a/packages/xpub-faraday/config/default.js +++ b/packages/xpub-faraday/config/default.js @@ -1,11 +1,9 @@ require('dotenv').config() const path = require('path') -const get = require('lodash/get') const logger = require('winston') const components = require('./components.json') const journalConfig = require('../app/config/journal') - -const users = require('../../component-user') +const { get } = require('lodash') const getDbConfig = () => { if (process.env.DATABASE) { @@ -48,8 +46,6 @@ module.exports = { secret: 'SECRET', enableExperimentalGraphql: true, graphiql: true, - typeDefs: `${users.typeDefs}`, - // resolvers, }, 'pubsweet-client': { API_ENDPOINT: '/api', @@ -151,4 +147,5 @@ module.exports = { passwordStrengthRegex: new RegExp( '^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&,.?;\'*><)([}{}":`~+=_-\\|/])(?=.{6,128})', ), + hostname: process.env.HOSTNAME || 'http://localhost:3000', } diff --git a/packages/xpub-faraday/config/validations.js b/packages/xpub-faraday/config/validations.js index 562ea5242cef0bcd0c3268496b72e70be656cf4a..d8e9c5bbdea33f58fb9c6d845740170a45cad97e 100644 --- a/packages/xpub-faraday/config/validations.js +++ b/packages/xpub-faraday/config/validations.js @@ -146,17 +146,17 @@ module.exports = { orcid: Joi.object(), name: Joi.string(), username: Joi.string(), - isConfirmed: Joi.boolean(), + title: Joi.string().allow(''), + agreeTC: Joi.boolean(), + isActive: Joi.boolean(), firstName: Joi.string().allow(''), lastName: Joi.string().allow(''), affiliation: Joi.string().allow(''), + isConfirmed: Joi.boolean(), + editorInChief: Joi.boolean(), country: Joi.string().allow(''), - title: Joi.string().allow(''), teams: Joi.array(), - editorInChief: Joi.boolean(), handlingEditor: Joi.boolean(), - agreeTC: Joi.boolean(), - isActive: Joi.boolean(), passwordHash: Joi.string(), notifications: Joi.object({ email: Joi.object({ diff --git a/yarn.lock b/yarn.lock index 0800a7fa664a6c4a705bd6b8d6c6648f94854b68..2eea57c1648738bddcff0b6825fe5f5c660b9ce1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -278,6 +278,15 @@ lodash "^4.17.4" styled-components "^4.1.1" +"@pubsweet/ui-toolkit@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@pubsweet/ui-toolkit/-/ui-toolkit-2.0.3.tgz#673be0f68bfe3fb8c0a43401a3a032a6cfde75f7" + integrity sha512-zINDKK+A6kXllcYr8+hBdBij8pxF3uOWFGmQjctLBVHzgE6DTV0mPj2iv2WKezO1nE1EbJD5EyXqF4/72gQqQg== + dependencies: + color "^3.0.0" + lodash "^4.17.4" + styled-components "^4.1.1" + "@pubsweet/ui-toolkit@latest": version "1.0.0" resolved "https://registry.yarnpkg.com/@pubsweet/ui-toolkit/-/ui-toolkit-1.0.0.tgz#df05b54e7bbfabcb10c7afc2991752e1087d2298" @@ -337,6 +346,31 @@ redux-form "^7.0.3" styled-components "^4.1.1" +"@pubsweet/ui@^9.0.3": + version "9.0.3" + resolved "https://registry.yarnpkg.com/@pubsweet/ui/-/ui-9.0.3.tgz#aac4746d6febecd88935e9b2ab1c9d0581baab29" + integrity sha512-8mfvxzNwTZIM0lgzHniJEn/fiyW7W5LyJh2pAYpc+Su8AuCDAKOCpQjeJlgtYzpJuZMoYJrRxfTbuLIz3c7q1g== + dependencies: + "@pubsweet/ui-toolkit" "^2.0.3" + babel-jest "^21.2.0" + classnames "^2.2.5" + enzyme "^3.7.0" + enzyme-adapter-react-16 "^1.1.1" + invariant "^2.2.3" + lodash "^4.17.4" + moment "^2.22.1" + prop-types "^15.5.10" + react "^16.2.0" + react-dom "^16.2.0" + react-feather "^1.0.8" + react-redux "^5.0.2" + react-router-dom "^4.2.2" + react-tag-autocomplete "^5.5.0" + recompose "^0.26.0" + redux "^3.6.0" + redux-form "^7.0.3" + styled-components "^4.1.1" + "@types/async@2.0.49": version "2.0.49" resolved "https://registry.yarnpkg.com/@types/async/-/async-2.0.49.tgz#92e33d13f74c895cb9a7f38ba97db8431ed14bc0" @@ -1392,6 +1426,14 @@ babel-jest@^22.4.0: babel-plugin-istanbul "^4.1.5" babel-preset-jest "^22.2.0" +babel-jest@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-23.6.0.tgz#a644232366557a2240a0c083da6b25786185a2f1" + integrity sha512-lqKGG6LYXYu+DQh/slrQ8nxXQkEkhugdXsU6St7GmhVS7Ilc/22ArwqXNJrf0QaOBjZB0360qZMwXqDYQHXaew== + dependencies: + babel-plugin-istanbul "^4.1.6" + babel-preset-jest "^23.2.0" + babel-loader@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-7.1.2.tgz#f6cbe122710f1aa2af4d881c6d5b54358ca24126" @@ -1424,6 +1466,16 @@ babel-plugin-istanbul@^4.0.0, babel-plugin-istanbul@^4.1.5: istanbul-lib-instrument "^1.7.5" test-exclude "^4.1.1" +babel-plugin-istanbul@^4.1.6: + version "4.1.6" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz#36c59b2192efce81c5b378321b74175add1c9a45" + integrity sha512-PWP9FQ1AhZhS01T/4qLSKoHGY/xvkZdVBGlKM/HuxxS3+sC66HhTNR7+MpbO/so/cz/wY94MeSWJuP1hXIPfwQ== + dependencies: + babel-plugin-syntax-object-rest-spread "^6.13.0" + find-up "^2.1.0" + istanbul-lib-instrument "^1.10.1" + test-exclude "^4.2.1" + babel-plugin-jest-hoist@^21.2.0: version "21.2.0" resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-21.2.0.tgz#2cef637259bd4b628a6cace039de5fcd14dbb006" @@ -1434,6 +1486,11 @@ babel-plugin-jest-hoist@^22.2.0: resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.2.0.tgz#bd34f39d652406669713b8c89e23ef25c890b993" integrity sha512-NwicD5n1YQaj6sM3PVULdPBDk1XdlWvh8xBeUJg3nqZwp79Vofb8Q7GOVeWoZZ/RMlMuJMMrEAgSQl/p392nLA== +babel-plugin-jest-hoist@^23.2.0: + version "23.2.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-23.2.0.tgz#e61fae05a1ca8801aadee57a6d66b8cefaf44167" + integrity sha1-5h+uBaHKiAGq3uV6bWa4zvr0QWc= + "babel-plugin-styled-components@>= 1": version "1.9.2" resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-1.9.2.tgz#0e6a6587454dcb1c9a362a8fd31fc0b075ccd260" @@ -1883,6 +1940,14 @@ babel-preset-jest@^22.2.0: babel-plugin-jest-hoist "^22.2.0" babel-plugin-syntax-object-rest-spread "^6.13.0" +babel-preset-jest@^23.2.0: + version "23.2.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-23.2.0.tgz#8ec7a03a138f001a1a8fb1e8113652bf1a55da46" + integrity sha1-jsegOhOPABoaj7HoETZSvxpV2kY= + dependencies: + babel-plugin-jest-hoist "^23.2.0" + babel-plugin-syntax-object-rest-spread "^6.13.0" + babel-preset-react@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-preset-react/-/babel-preset-react-6.24.1.tgz#ba69dfaea45fc3ec639b6a4ecea6e17702c91380" @@ -1948,7 +2013,7 @@ babel-template@^6.16.0, babel-template@^6.24.1, babel-template@^6.26.0: babylon "^6.18.0" lodash "^4.17.4" -babel-traverse@^6.18.0, babel-traverse@^6.24.1, babel-traverse@^6.26.0: +babel-traverse@^6.0.0, babel-traverse@^6.18.0, babel-traverse@^6.24.1, babel-traverse@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" integrity sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4= @@ -1963,7 +2028,7 @@ babel-traverse@^6.18.0, babel-traverse@^6.24.1, babel-traverse@^6.26.0: invariant "^2.2.2" lodash "^4.17.4" -babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: +babel-types@^6.0.0, babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc= @@ -2217,6 +2282,13 @@ browser-resolve@^1.11.2: dependencies: resolve "1.1.7" +browser-resolve@^1.11.3: + version "1.11.3" + resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6" + integrity sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ== + dependencies: + resolve "1.1.7" + browserify-aes@^1.0.0, browserify-aes@^1.0.4: version "1.1.1" resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.1.1.tgz#38b7ab55edb806ff2dcda1a7f1620773a477c49f" @@ -2322,6 +2394,11 @@ buffer-equal-constant-time@1.0.1: resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + buffer-indexof@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" @@ -4957,6 +5034,18 @@ expect@^22.4.0: jest-message-util "^22.4.0" jest-regex-util "^22.1.0" +expect@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-23.6.0.tgz#1e0c8d3ba9a581c87bd71fb9bc8862d443425f98" + integrity sha512-dgSoOHgmtn/aDGRVFWclQyPDKl2CQRq0hmIEoUAuQs/2rn2NcvCWcSCovm6BLeuB/7EZuLGu2QfnR+qRt5OM4w== + dependencies: + ansi-styles "^3.2.0" + jest-diff "^23.6.0" + jest-get-type "^22.1.0" + jest-matcher-utils "^23.6.0" + jest-message-util "^23.4.0" + jest-regex-util "^23.3.0" + express@^4.15.3, express@^4.16.1: version "4.16.2" resolved "https://registry.yarnpkg.com/express/-/express-4.16.2.tgz#e35c6dfe2d64b7dca0a5cd4f21781be3299e076c" @@ -5516,6 +5605,21 @@ formik@^1.3.2: tslib "^1.9.3" warning "^3.0.0" +formik@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/formik/-/formik-1.4.0.tgz#4261769f765dd41b7e791958fde7a08516d5920a" + integrity sha512-HOlb4cEgjTZ+5VMCYDlXt1r5Bt9wLhIH6uvJCAhJaIvqehmIM1RdzhYel8tCFPXzCcCx8QeZh3UcWKye5rsJmw== + dependencies: + create-react-context "^0.2.2" + deepmerge "^2.1.1" + hoist-non-react-statics "^2.5.5" + lodash "^4.17.11" + lodash-es "^4.17.11" + prop-types "^15.6.1" + react-fast-compare "^2.0.1" + tslib "^1.9.3" + warning "^3.0.0" + forwarded@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" @@ -7171,11 +7275,33 @@ istanbul-api@^1.1.14: mkdirp "^0.5.1" once "^1.4.0" +istanbul-api@^1.3.1: + version "1.3.7" + resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.3.7.tgz#a86c770d2b03e11e3f778cd7aedd82d2722092aa" + integrity sha512-4/ApBnMVeEPG3EkSzcw25wDe4N66wxwn+KKn6b47vyek8Xb3NBAcg4xfuQbS7BqcZuTX4wxfD5lVagdggR3gyA== + dependencies: + async "^2.1.4" + fileset "^2.0.2" + istanbul-lib-coverage "^1.2.1" + istanbul-lib-hook "^1.2.2" + istanbul-lib-instrument "^1.10.2" + istanbul-lib-report "^1.1.5" + istanbul-lib-source-maps "^1.2.6" + istanbul-reports "^1.5.1" + js-yaml "^3.7.0" + mkdirp "^0.5.1" + once "^1.4.0" + istanbul-lib-coverage@^1.1.1, istanbul-lib-coverage@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.2.tgz#4113c8ff6b7a40a1ef7350b01016331f63afde14" integrity sha512-tZYA0v5A7qBSsOzcebJJ/z3lk3oSzH62puG78DbBA1+zupipX2CakDyiPV3pOb8He+jBwVimuwB0dTnh38hX0w== +istanbul-lib-coverage@^1.2.0, istanbul-lib-coverage@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.1.tgz#ccf7edcd0a0bb9b8f729feeb0930470f9af664f0" + integrity sha512-PzITeunAgyGbtY1ibVIUiV679EFChHjoMNRibEIobvmrCRaIgwLxNucOSimtNWUhEib/oO7QY2imD75JVgCJWQ== + istanbul-lib-hook@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.1.0.tgz#8538d970372cb3716d53e55523dd54b557a8d89b" @@ -7183,6 +7309,26 @@ istanbul-lib-hook@^1.1.0: dependencies: append-transform "^0.4.0" +istanbul-lib-hook@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.2.2.tgz#bc6bf07f12a641fbf1c85391d0daa8f0aea6bf86" + integrity sha512-/Jmq7Y1VeHnZEQ3TL10VHyb564mn6VrQXHchON9Jf/AEcmQ3ZIiyD1BVzNOKTZf/G3gE+kiGK6SmpF9y3qGPLw== + dependencies: + append-transform "^0.4.0" + +istanbul-lib-instrument@^1.10.1, istanbul-lib-instrument@^1.10.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.2.tgz#1f55ed10ac3c47f2bdddd5307935126754d0a9ca" + integrity sha512-aWHxfxDqvh/ZlxR8BBaEPVSWDPUkGD63VjGQn3jcw8jCp7sHEMKcrj4xfJn/ABzdMEHiQNyvDQhqm5o8+SQg7A== + dependencies: + babel-generator "^6.18.0" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + babylon "^6.18.0" + istanbul-lib-coverage "^1.2.1" + semver "^5.3.0" + istanbul-lib-instrument@^1.7.5, istanbul-lib-instrument@^1.8.0, istanbul-lib-instrument@^1.9.2: version "1.9.2" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.9.2.tgz#84905bf47f7e0b401d6b840da7bad67086b4aab6" @@ -7206,6 +7352,16 @@ istanbul-lib-report@^1.1.3: path-parse "^1.0.5" supports-color "^3.1.2" +istanbul-lib-report@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.1.5.tgz#f2a657fc6282f96170aaf281eb30a458f7f4170c" + integrity sha512-UsYfRMoi6QO/doUshYNqcKJqVmFe9w51GZz8BS3WB0lYxAllQYklka2wP9+dGZeHYaWIdcXUx8JGdbqaoXRXzw== + dependencies: + istanbul-lib-coverage "^1.2.1" + mkdirp "^0.5.1" + path-parse "^1.0.5" + supports-color "^3.1.2" + istanbul-lib-source-maps@^1.2.1, istanbul-lib-source-maps@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.3.tgz#20fb54b14e14b3fb6edb6aca3571fd2143db44e6" @@ -7217,6 +7373,17 @@ istanbul-lib-source-maps@^1.2.1, istanbul-lib-source-maps@^1.2.3: rimraf "^2.6.1" source-map "^0.5.3" +istanbul-lib-source-maps@^1.2.4, istanbul-lib-source-maps@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.6.tgz#37b9ff661580f8fca11232752ee42e08c6675d8f" + integrity sha512-TtbsY5GIHgbMsMiRw35YBHGpZ1DVFEO19vxxeiDMYaeOFOCzfnYVxvl6pOUIZR4dtPhAGpSMup8OyF8ubsaqEg== + dependencies: + debug "^3.1.0" + istanbul-lib-coverage "^1.2.1" + mkdirp "^0.5.1" + rimraf "^2.6.1" + source-map "^0.5.3" + istanbul-reports@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.1.4.tgz#5ccba5e22b7b5a5d91d5e0a830f89be334bf97bd" @@ -7224,6 +7391,13 @@ istanbul-reports@^1.1.4: dependencies: handlebars "^4.0.3" +istanbul-reports@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.5.1.tgz#97e4dbf3b515e8c484caea15d6524eebd3ff4e1a" + integrity sha512-+cfoZ0UXzWjhAdzosCPP3AN8vvef8XDkWtTfgaN+7L3YTpNYITnCaEkceo5SEYy644VkHka/P1FvkWvrG/rrJw== + dependencies: + handlebars "^4.0.3" + items@2.x.x: version "2.1.1" resolved "https://registry.yarnpkg.com/items/-/items-2.1.1.tgz#8bd16d9c83b19529de5aea321acaada78364a198" @@ -7251,6 +7425,13 @@ jest-changed-files@^22.2.0: dependencies: throat "^4.0.0" +jest-changed-files@^23.4.2: + version "23.4.2" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-23.4.2.tgz#1eed688370cd5eebafe4ae93d34bb3b64968fe83" + integrity sha512-EyNhTAUWEfwnK0Is/09LxoqNDOn7mU7S3EHskG52djOFS/z+IT0jT3h3Ql61+dklcG7bJJitIWEMB4Sp1piHmA== + dependencies: + throat "^4.0.0" + jest-cli@^22.4.0: version "22.4.0" resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-22.4.0.tgz#234d6175166e87ecab40c6e5a4f7b3f6a4cd4257" @@ -7291,6 +7472,48 @@ jest-cli@^22.4.0: which "^1.2.12" yargs "^10.0.3" +jest-cli@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-23.6.0.tgz#61ab917744338f443ef2baa282ddffdd658a5da4" + integrity sha512-hgeD1zRUp1E1zsiyOXjEn4LzRLWdJBV//ukAHGlx6s5mfCNJTbhbHjgxnDUXA8fsKWN/HqFFF6X5XcCwC/IvYQ== + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.1" + exit "^0.1.2" + glob "^7.1.2" + graceful-fs "^4.1.11" + import-local "^1.0.0" + is-ci "^1.0.10" + istanbul-api "^1.3.1" + istanbul-lib-coverage "^1.2.0" + istanbul-lib-instrument "^1.10.1" + istanbul-lib-source-maps "^1.2.4" + jest-changed-files "^23.4.2" + jest-config "^23.6.0" + jest-environment-jsdom "^23.4.0" + jest-get-type "^22.1.0" + jest-haste-map "^23.6.0" + jest-message-util "^23.4.0" + jest-regex-util "^23.3.0" + jest-resolve-dependencies "^23.6.0" + jest-runner "^23.6.0" + jest-runtime "^23.6.0" + jest-snapshot "^23.6.0" + jest-util "^23.4.0" + jest-validate "^23.6.0" + jest-watcher "^23.4.0" + jest-worker "^23.2.0" + micromatch "^2.3.11" + node-notifier "^5.2.1" + prompts "^0.1.9" + realpath-native "^1.0.0" + rimraf "^2.5.4" + slash "^1.0.0" + string-length "^2.0.0" + strip-ansi "^4.0.0" + which "^1.2.12" + yargs "^11.0.0" + jest-config@^22.4.0: version "22.4.0" resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-22.4.0.tgz#34ab50ff52e68a3b0f2dd5df91bfd9b8cf2aa474" @@ -7308,6 +7531,26 @@ jest-config@^22.4.0: jest-validate "^22.4.0" pretty-format "^22.4.0" +jest-config@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-23.6.0.tgz#f82546a90ade2d8c7026fbf6ac5207fc22f8eb1d" + integrity sha512-i8V7z9BeDXab1+VNo78WM0AtWpBRXJLnkT+lyT+Slx/cbP5sZJ0+NDuLcmBE5hXAoK0aUp7vI+MOxR+R4d8SRQ== + dependencies: + babel-core "^6.0.0" + babel-jest "^23.6.0" + chalk "^2.0.1" + glob "^7.1.1" + jest-environment-jsdom "^23.4.0" + jest-environment-node "^23.4.0" + jest-get-type "^22.1.0" + jest-jasmine2 "^23.6.0" + jest-regex-util "^23.3.0" + jest-resolve "^23.6.0" + jest-util "^23.4.0" + jest-validate "^23.6.0" + micromatch "^2.3.11" + pretty-format "^23.6.0" + jest-diff@^22.4.0: version "22.4.0" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-22.4.0.tgz#384c2b78519ca44ca126382df53f134289232525" @@ -7318,6 +7561,16 @@ jest-diff@^22.4.0: jest-get-type "^22.1.0" pretty-format "^22.4.0" +jest-diff@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-23.6.0.tgz#1500f3f16e850bb3d71233408089be099f610c7d" + integrity sha512-Gz9l5Ov+X3aL5L37IT+8hoCUsof1CVYBb2QEkOupK64XyRR3h+uRpYIm97K7sY8diFxowR8pIGEdyfMKTixo3g== + dependencies: + chalk "^2.0.1" + diff "^3.2.0" + jest-get-type "^22.1.0" + pretty-format "^23.6.0" + jest-docblock@^21.0.0: version "21.2.0" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414" @@ -7330,6 +7583,21 @@ jest-docblock@^22.4.0: dependencies: detect-newline "^2.1.0" +jest-docblock@^23.2.0: + version "23.2.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-23.2.0.tgz#f085e1f18548d99fdd69b20207e6fd55d91383a7" + integrity sha1-8IXh8YVI2Z/dabICB+b9VdkTg6c= + dependencies: + detect-newline "^2.1.0" + +jest-each@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-23.6.0.tgz#ba0c3a82a8054387016139c733a05242d3d71575" + integrity sha512-x7V6M/WGJo6/kLoissORuvLIeAoyo2YqLOoCDkohgJ4XOXSqOtyvr8FbInlAWS77ojBsZrafbozWoKVRdtxFCg== + dependencies: + chalk "^2.0.1" + pretty-format "^23.6.0" + jest-environment-jsdom@^22.4.0: version "22.4.0" resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-22.4.0.tgz#09df84a1faf1ca47096aafc89411a095378f628e" @@ -7339,6 +7607,15 @@ jest-environment-jsdom@^22.4.0: jest-util "^22.4.0" jsdom "^11.5.1" +jest-environment-jsdom@^23.4.0: + version "23.4.0" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-23.4.0.tgz#056a7952b3fea513ac62a140a2c368c79d9e6023" + integrity sha1-BWp5UrP+pROsYqFAosNox52eYCM= + dependencies: + jest-mock "^23.2.0" + jest-util "^23.4.0" + jsdom "^11.5.1" + jest-environment-node@^22.4.0: version "22.4.0" resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-22.4.0.tgz#b6d9458275053028d4b1658851c3475ab22dfb56" @@ -7347,6 +7624,14 @@ jest-environment-node@^22.4.0: jest-mock "^22.2.0" jest-util "^22.4.0" +jest-environment-node@^23.4.0: + version "23.4.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-23.4.0.tgz#57e80ed0841dea303167cce8cd79521debafde10" + integrity sha1-V+gO0IQd6jAxZ8zozXlSHeuv3hA= + dependencies: + jest-mock "^23.2.0" + jest-util "^23.4.0" + jest-get-type@^21.2.0: version "21.2.0" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-21.2.0.tgz#f6376ab9db4b60d81e39f30749c6c466f40d4a23" @@ -7370,6 +7655,20 @@ jest-haste-map@^22.4.0: micromatch "^2.3.11" sane "^2.0.0" +jest-haste-map@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-23.6.0.tgz#2e3eb997814ca696d62afdb3f2529f5bbc935e16" + integrity sha512-uyNhMyl6dr6HaXGHp8VF7cK6KpC6G9z9LiMNsst+rJIZ8l7wY0tk8qwjPmEghczojZ2/ZhtEdIabZ0OQRJSGGg== + dependencies: + fb-watchman "^2.0.0" + graceful-fs "^4.1.11" + invariant "^2.2.4" + jest-docblock "^23.2.0" + jest-serializer "^23.0.1" + jest-worker "^23.2.0" + micromatch "^2.3.11" + sane "^2.0.0" + jest-jasmine2@^22.4.0: version "22.4.0" resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-22.4.0.tgz#1d9b607ede12a600ecadda2c8d89918d7d3c4d26" @@ -7387,6 +7686,24 @@ jest-jasmine2@^22.4.0: jest-snapshot "^22.4.0" source-map-support "^0.5.0" +jest-jasmine2@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-23.6.0.tgz#840e937f848a6c8638df24360ab869cc718592e0" + integrity sha512-pe2Ytgs1nyCs8IvsEJRiRTPC0eVYd8L/dXJGU08GFuBwZ4sYH/lmFDdOL3ZmvJR8QKqV9MFuwlsAi/EWkFUbsQ== + dependencies: + babel-traverse "^6.0.0" + chalk "^2.0.1" + co "^4.6.0" + expect "^23.6.0" + is-generator-fn "^1.0.0" + jest-diff "^23.6.0" + jest-each "^23.6.0" + jest-matcher-utils "^23.6.0" + jest-message-util "^23.4.0" + jest-snapshot "^23.6.0" + jest-util "^23.4.0" + pretty-format "^23.6.0" + jest-leak-detector@^22.4.0: version "22.4.0" resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-22.4.0.tgz#64da77f05b001c96d2062226e079f89989c4aa2f" @@ -7394,6 +7711,13 @@ jest-leak-detector@^22.4.0: dependencies: pretty-format "^22.4.0" +jest-leak-detector@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-23.6.0.tgz#e4230fd42cf381a1a1971237ad56897de7e171de" + integrity sha512-f/8zA04rsl1Nzj10HIyEsXvYlMpMPcy0QkQilVZDFOaPbv2ur71X5u2+C4ZQJGyV/xvVXtCCZ3wQ99IgQxftCg== + dependencies: + pretty-format "^23.6.0" + jest-matcher-utils@^22.4.0: version "22.4.0" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-22.4.0.tgz#d55f5faf2270462736bdf7c7485ee931c9d4b6a1" @@ -7403,6 +7727,15 @@ jest-matcher-utils@^22.4.0: jest-get-type "^22.1.0" pretty-format "^22.4.0" +jest-matcher-utils@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-23.6.0.tgz#726bcea0c5294261a7417afb6da3186b4b8cac80" + integrity sha512-rosyCHQfBcol4NsckTn01cdelzWLU9Cq7aaigDf8VwwpIRvWE/9zLgX2bON+FkEW69/0UuYslUe22SOdEf2nog== + dependencies: + chalk "^2.0.1" + jest-get-type "^22.1.0" + pretty-format "^23.6.0" + jest-message-util@^22.4.0: version "22.4.0" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-22.4.0.tgz#e3d861df16d2fee60cb2bc8feac2188a42579642" @@ -7414,16 +7747,37 @@ jest-message-util@^22.4.0: slash "^1.0.0" stack-utils "^1.0.1" +jest-message-util@^23.4.0: + version "23.4.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-23.4.0.tgz#17610c50942349508d01a3d1e0bda2c079086a9f" + integrity sha1-F2EMUJQjSVCNAaPR4L2iwHkIap8= + dependencies: + "@babel/code-frame" "^7.0.0-beta.35" + chalk "^2.0.1" + micromatch "^2.3.11" + slash "^1.0.0" + stack-utils "^1.0.1" + jest-mock@^22.2.0: version "22.2.0" resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-22.2.0.tgz#444b3f9488a7473adae09bc8a77294afded397a7" integrity sha512-eOfoUYLOB/JlxChOFkh/bzpWGqUXb9I+oOpkprHHs9L7nUNfL8Rk28h1ycWrqzWCEQ/jZBg/xIv7VdQkfAkOhw== +jest-mock@^23.2.0: + version "23.2.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-23.2.0.tgz#ad1c60f29e8719d47c26e1138098b6d18b261134" + integrity sha1-rRxg8p6HGdR8JuETgJi20YsmETQ= + jest-regex-util@^22.1.0: version "22.1.0" resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-22.1.0.tgz#5daf2fe270074b6da63e5d85f1c9acc866768f53" integrity sha512-on0LqVS6Xeh69sw3d1RukVnur+lVOl3zkmb0Q54FHj9wHoq6dbtWqb3TSlnVUyx36hqjJhjgs/QLqs07Bzu72Q== +jest-regex-util@^23.3.0: + version "23.3.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-23.3.0.tgz#5f86729547c2785c4002ceaa8f849fe8ca471bc5" + integrity sha1-X4ZylUfCeFxAAs6qj4Sf6MpHG8U= + jest-resolve-dependencies@^22.1.0: version "22.1.0" resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-22.1.0.tgz#340e4139fb13315cd43abc054e6c06136be51e31" @@ -7431,6 +7785,14 @@ jest-resolve-dependencies@^22.1.0: dependencies: jest-regex-util "^22.1.0" +jest-resolve-dependencies@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-23.6.0.tgz#b4526af24c8540d9a3fab102c15081cf509b723d" + integrity sha512-EkQWkFWjGKwRtRyIwRwI6rtPAEyPWlUC2MpzHissYnzJeHcyCn1Hc8j7Nn1xUVrS5C6W5+ZL37XTem4D4pLZdA== + dependencies: + jest-regex-util "^23.3.0" + jest-snapshot "^23.6.0" + jest-resolve@^22.4.0: version "22.4.0" resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-22.4.0.tgz#c3550280d77c47c2885809e7dc8e42560f0b3e71" @@ -7439,6 +7801,15 @@ jest-resolve@^22.4.0: browser-resolve "^1.11.2" chalk "^2.0.1" +jest-resolve@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-23.6.0.tgz#cf1d1a24ce7ee7b23d661c33ba2150f3aebfa0ae" + integrity sha512-XyoRxNtO7YGpQDmtQCmZjum1MljDqUCob7XlZ6jy9gsMugHdN2hY4+Acz9Qvjz2mSsOnPSH7skBmDYCHXVZqkA== + dependencies: + browser-resolve "^1.11.3" + chalk "^2.0.1" + realpath-native "^1.0.0" + jest-runner@^22.4.0: version "22.4.0" resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-22.4.0.tgz#2509b82834ab4aa7e984ff464626397c556177a7" @@ -7456,6 +7827,25 @@ jest-runner@^22.4.0: jest-worker "^22.2.2" throat "^4.0.0" +jest-runner@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-23.6.0.tgz#3894bd219ffc3f3cb94dc48a4170a2e6f23a5a38" + integrity sha512-kw0+uj710dzSJKU6ygri851CObtCD9cN8aNkg8jWJf4ewFyEa6kwmiH/r/M1Ec5IL/6VFa0wnAk6w+gzUtjJzA== + dependencies: + exit "^0.1.2" + graceful-fs "^4.1.11" + jest-config "^23.6.0" + jest-docblock "^23.2.0" + jest-haste-map "^23.6.0" + jest-jasmine2 "^23.6.0" + jest-leak-detector "^23.6.0" + jest-message-util "^23.4.0" + jest-runtime "^23.6.0" + jest-util "^23.4.0" + jest-worker "^23.2.0" + source-map-support "^0.5.6" + throat "^4.0.0" + jest-runtime@^22.4.0: version "22.4.0" resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-22.4.0.tgz#a4e3e3709a2289725790ed51ca41526a5700ddc4" @@ -7482,11 +7872,43 @@ jest-runtime@^22.4.0: write-file-atomic "^2.1.0" yargs "^10.0.3" +jest-runtime@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-23.6.0.tgz#059e58c8ab445917cd0e0d84ac2ba68de8f23082" + integrity sha512-ycnLTNPT2Gv+TRhnAYAQ0B3SryEXhhRj1kA6hBPSeZaNQkJ7GbZsxOLUkwg6YmvWGdX3BB3PYKFLDQCAE1zNOw== + dependencies: + babel-core "^6.0.0" + babel-plugin-istanbul "^4.1.6" + chalk "^2.0.1" + convert-source-map "^1.4.0" + exit "^0.1.2" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.1.11" + jest-config "^23.6.0" + jest-haste-map "^23.6.0" + jest-message-util "^23.4.0" + jest-regex-util "^23.3.0" + jest-resolve "^23.6.0" + jest-snapshot "^23.6.0" + jest-util "^23.4.0" + jest-validate "^23.6.0" + micromatch "^2.3.11" + realpath-native "^1.0.0" + slash "^1.0.0" + strip-bom "3.0.0" + write-file-atomic "^2.1.0" + yargs "^11.0.0" + jest-serializer@^22.4.0: version "22.4.0" resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-22.4.0.tgz#b5d145b98c4b0d2c20ab686609adbb81fe23b566" integrity sha512-dnqde95MiYfdc1ZJpjEiHCRvRGGJHPsZQARJFucEGIaOzxqqS9/tt2WzD/OUSGT6kxaEGLQE92faVJGdoCu+Rw== +jest-serializer@^23.0.1: + version "23.0.1" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-23.0.1.tgz#a3776aeb311e90fe83fab9e533e85102bd164165" + integrity sha1-o3dq6zEekP6D+rnlM+hRAr0WQWU= + jest-snapshot@^22.4.0: version "22.4.0" resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-22.4.0.tgz#03d3ce63f8fa7352388afc6a3c8b5ccc3a180ed7" @@ -7499,6 +7921,22 @@ jest-snapshot@^22.4.0: natural-compare "^1.4.0" pretty-format "^22.4.0" +jest-snapshot@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-23.6.0.tgz#f9c2625d1b18acda01ec2d2b826c0ce58a5aa17a" + integrity sha512-tM7/Bprftun6Cvj2Awh/ikS7zV3pVwjRYU2qNYS51VZHgaAMBs5l4o/69AiDHhQrj5+LA2Lq4VIvK7zYk/bswg== + dependencies: + babel-types "^6.0.0" + chalk "^2.0.1" + jest-diff "^23.6.0" + jest-matcher-utils "^23.6.0" + jest-message-util "^23.4.0" + jest-resolve "^23.6.0" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + pretty-format "^23.6.0" + semver "^5.5.0" + jest-util@^22.4.0: version "22.4.0" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-22.4.0.tgz#ebdc147548d613c5faf7c7534051f59740c98ada" @@ -7511,6 +7949,20 @@ jest-util@^22.4.0: jest-message-util "^22.4.0" mkdirp "^0.5.1" +jest-util@^23.4.0: + version "23.4.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-23.4.0.tgz#4d063cb927baf0a23831ff61bec2cbbf49793561" + integrity sha1-TQY8uSe68KI4Mf9hvsLLv0l5NWE= + dependencies: + callsites "^2.0.0" + chalk "^2.0.1" + graceful-fs "^4.1.11" + is-ci "^1.0.10" + jest-message-util "^23.4.0" + mkdirp "^0.5.1" + slash "^1.0.0" + source-map "^0.6.0" + jest-validate@^21.1.0: version "21.2.1" resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-21.2.1.tgz#cc0cbca653cd54937ba4f2a111796774530dd3c7" @@ -7532,6 +7984,25 @@ jest-validate@^22.4.0: leven "^2.1.0" pretty-format "^22.4.0" +jest-validate@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-23.6.0.tgz#36761f99d1ed33fcd425b4e4c5595d62b6597474" + integrity sha512-OFKapYxe72yz7agrDAWi8v2WL8GIfVqcbKRCLbRG9PAxtzF9b1SEDdTpytNDN12z2fJynoBwpMpvj2R39plI2A== + dependencies: + chalk "^2.0.1" + jest-get-type "^22.1.0" + leven "^2.1.0" + pretty-format "^23.6.0" + +jest-watcher@^23.4.0: + version "23.4.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-23.4.0.tgz#d2e28ce74f8dad6c6afc922b92cabef6ed05c91c" + integrity sha1-0uKM50+NrWxq/JIrksq+9u0FyRw= + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.1" + string-length "^2.0.0" + jest-worker@^22.2.2: version "22.2.2" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-22.2.2.tgz#c1f5dc39976884b81f68ec50cb8532b2cbab3390" @@ -7539,6 +8010,13 @@ jest-worker@^22.2.2: dependencies: merge-stream "^1.0.1" +jest-worker@^23.2.0: + version "23.2.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-23.2.0.tgz#faf706a8da36fae60eb26957257fa7b5d8ea02b9" + integrity sha1-+vcGqNo2+uYOsmlXJX+ntdjqArk= + dependencies: + merge-stream "^1.0.1" + jest@^22.1.1: version "22.4.0" resolved "https://registry.yarnpkg.com/jest/-/jest-22.4.0.tgz#476e2c08c6c2a6dbb5cfec520b8bf1cd4c99afd7" @@ -7547,6 +8025,14 @@ jest@^22.1.1: import-local "^1.0.0" jest-cli "^22.4.0" +jest@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-23.6.0.tgz#ad5835e923ebf6e19e7a1d7529a432edfee7813d" + integrity sha512-lWzcd+HSiqeuxyhG+EnZds6iO3Y3ZEnMrfZq/OTGvF/C+Z4fPMCdhWTGSAiO2Oym9rbEXfwddHhh6jqrTF3+Lw== + dependencies: + import-local "^1.0.0" + jest-cli "^23.6.0" + jmespath@0.15.0: version "0.15.0" resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" @@ -8240,6 +8726,11 @@ locate-path@^2.0.0: p-locate "^2.0.0" path-exists "^3.0.0" +lodash-es@^4.17.11: + version "4.17.11" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.11.tgz#145ab4a7ac5c5e52a3531fb4f310255a152b4be0" + integrity sha512-DHb1ub+rMjjrxqlB3H56/6MXtm1lSksDp2rA2cNWjG8mlDUYFhUj3Di2Zn5IwSU87xLv8tNIQ7sSwE/YOX/D/Q== + lodash-es@^4.17.3, lodash-es@^4.17.5, lodash-es@^4.2.1: version "4.17.5" resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.5.tgz#9fc6e737b1c4d151d8f9cae2247305d552ce748f" @@ -10568,6 +11059,14 @@ pretty-format@^22.4.0: ansi-regex "^3.0.0" ansi-styles "^3.2.0" +pretty-format@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-23.6.0.tgz#5eaac8eeb6b33b987b7fe6097ea6a8a146ab5760" + integrity sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw== + dependencies: + ansi-regex "^3.0.0" + ansi-styles "^3.2.0" + private@^0.1.6, private@^0.1.7, private@~0.1.5: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" @@ -10634,6 +11133,14 @@ prompt@^1.0.0, prompt@flatiron/prompt#1c95d1d8d333b5fbc13fa5f0619f3dcf0d514f87: utile "0.3.x" winston "2.x" +prompts@^0.1.9: + version "0.1.14" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-0.1.14.tgz#a8e15c612c5c9ec8f8111847df3337c9cbd443b2" + integrity sha512-rxkyiE9YH6zAz/rZpywySLKkpaj0NMVyNw1qhsubdbjjSgcayjTShDreZGlFMcGSu5sab3bAKPfFk78PB90+8w== + dependencies: + kleur "^2.0.1" + sisteransi "^0.1.1" + prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.5.9, prop-types@^15.6.0: version "15.6.0" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856" @@ -11246,6 +11753,11 @@ react-fast-compare@^1.0.0: resolved "http://registry.npmjs.org/react-fast-compare/-/react-fast-compare-1.0.0.tgz#813a039155e49b43ceffe99528fe5e9d97a6c938" integrity sha512-dcQpdWr62flXQJuM8/bVEY5/10ad2SYBUafp8H4q4WHR3fTA/MMlp8mpzX12I0CCoEJc1P6QdiMg7U+7lFS6Rw== +react-fast-compare@^2.0.1: + version "2.0.4" + resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9" + integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw== + react-feather@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/react-feather/-/react-feather-1.0.8.tgz#69b13d5c729949f194d33201dee91bab67fa31a2" @@ -12411,6 +12923,11 @@ semver@5.3.0, semver@~5.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8= +semver@^5.5.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" + integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== + send@0.16.1: version "0.16.1" resolved "https://registry.yarnpkg.com/send/-/send-0.16.1.tgz#a70e1ca21d1382c11d0d9f6231deb281080d7ab3" @@ -12593,6 +13110,11 @@ simple-swizzle@^0.2.2: dependencies: is-arrayish "^0.3.1" +sisteransi@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-0.1.1.tgz#5431447d5f7d1675aac667ccd0b865a4994cb3ce" + integrity sha512-PmGOd02bM9YO5ifxpw36nrNMBTptEtfRl4qUYl9SndkolplkrZZOW7PGHjrZL53QvMVj9nQ+TKqUnRsw4tJa4g== + slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" @@ -12718,6 +13240,14 @@ source-map-support@^0.5.0, source-map-support@^0.5.1: dependencies: source-map "^0.6.0" +source-map-support@^0.5.6: + version "0.5.9" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.9.tgz#41bc953b2534267ea2d605bccfa7bfa3111ced5f" + integrity sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" @@ -13487,6 +14017,17 @@ test-exclude@^4.1.1: read-pkg-up "^1.0.1" require-main-filename "^1.0.1" +test-exclude@^4.2.1: + version "4.2.3" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.2.3.tgz#a9a5e64474e4398339245a0a769ad7c2f4a97c20" + integrity sha512-SYbXgY64PT+4GAL2ocI3HwPa4Q4TBKm0cwAVeKOt/Aoc0gSpNRjJX8w0pA1LMKZ3LBmd8pYBqApFNQLII9kavA== + dependencies: + arrify "^1.0.1" + micromatch "^2.3.11" + object-assign "^4.1.0" + read-pkg-up "^1.0.1" + require-main-filename "^1.0.1" + text-extensions@^1.0.0: version "1.7.0" resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.7.0.tgz#faaaba2625ed746d568a23e4d0aacd9bf08a8b39" @@ -14726,6 +15267,13 @@ xpub-validators@^0.0.5: dependencies: striptags "^3.1.0" +xpub-validators@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/xpub-validators/-/xpub-validators-0.0.6.tgz#42ebc2d722b9ec6801cc44b7177eaa71029c1514" + integrity sha512-zkayEdxC3NQERycoTu8YUUPNlBuN153ESbIax9exmgrO0yt4LG3be+FirXcbkgIPYmgPAB0nnhPofOCTMTJx1g== + dependencies: + striptags "^3.1.0" + xregexp@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-2.0.0.tgz#52a63e56ca0b84a7f3a5f3d61872f126ad7a5943" @@ -14784,6 +15332,13 @@ yargs-parser@^8.1.0: dependencies: camelcase "^4.1.0" +yargs-parser@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077" + integrity sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc= + dependencies: + camelcase "^4.1.0" + yargs@6.6.0: version "6.6.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208" @@ -14821,6 +15376,24 @@ yargs@^10.0.3: y18n "^3.2.1" yargs-parser "^8.1.0" +yargs@^11.0.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.0.tgz#90b869934ed6e871115ea2ff58b03f4724ed2d77" + integrity sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A== + dependencies: + cliui "^4.0.0" + decamelize "^1.1.1" + find-up "^2.1.0" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^9.0.2" + yargs@^7.0.0: version "7.1.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8"