Skip to content

Commit

Permalink
Merge pull request #1667 from LD4P/bottom-actions
Browse files Browse the repository at this point in the history
Display edit actions at the bottom of the form
  • Loading branch information
jermnelson committed Nov 4, 2019
2 parents 8e71251 + b498f8b commit 2031a2a
Show file tree
Hide file tree
Showing 23 changed files with 61 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import React from 'react'
import { createStore } from 'redux'
import CopyToNewButton from 'components/editor/CopyToNewButton'
import CopyToNewButton from 'components/editor/actions/CopyToNewButton'
import appReducer from 'reducers/index'
import { renderWithRedux } from 'testUtils'
import { fireEvent, wait } from '@testing-library/react'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import React from 'react'
import { createStore } from 'redux'
import PreviewButton from 'components/editor/PreviewButton'
import PreviewButton from 'components/editor/actions/PreviewButton'
import appReducer from 'reducers/index'
import { renderWithRedux } from 'testUtils'
import { fireEvent, wait } from '@testing-library/react'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// Copyright 2019 Stanford University see LICENSE for license

import React from 'react'
import { renderWithRedux, createReduxStore } from 'testUtils'
import SaveAndPublishButton from 'components/editor/SaveAndPublishButton'
import SaveAndPublishButton from 'components/editor/actions/SaveAndPublishButton'

const createInitialState = () => ({
selectorReducer: {
Expand Down Expand Up @@ -78,7 +79,7 @@ describe('<SaveAndPublishButton />', () => {
it('is enabled if resource has changed and validation errors are not shown', () => {
const store = createReduxStore(createInitialState())
const { getByText } = renderWithRedux(
<SaveAndPublishButton id="test" />, store,
<SaveAndPublishButton class="test" />, store,
)
expect(getByText('Save')).not.toBeDisabled()
})
Expand All @@ -87,7 +88,7 @@ describe('<SaveAndPublishButton />', () => {
initialState.selectorReducer.editor.resourceValidation.show = true
const store = createReduxStore(initialState)
const { getByText } = renderWithRedux(
<SaveAndPublishButton id="test" />, store,
<SaveAndPublishButton class="test" />, store,
)
expect(getByText('Save')).not.toBeDisabled()
})
Expand All @@ -96,7 +97,7 @@ describe('<SaveAndPublishButton />', () => {
initialState.selectorReducer.editor.lastSaveChecksum = 'c5c8da42a2b460a740c33c72acb4d115'
const store = createReduxStore(initialState)
const { getByText } = renderWithRedux(
<SaveAndPublishButton id="test" />, store,
<SaveAndPublishButton class="test" />, store,
)
expect(getByText('Save')).toBeDisabled()
})
Expand All @@ -120,7 +121,7 @@ describe('<SaveAndPublishButton />', () => {
]
const store = createReduxStore(initialState)
const { getByText } = renderWithRedux(
<SaveAndPublishButton id="test" />, store,
<SaveAndPublishButton class="test" />, store,
)
expect(getByText('Save')).toBeDisabled()
})
Expand Down
4 changes: 2 additions & 2 deletions __tests__/integration/leaveEditor.ppt.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ describe('Leaving the editor', () => {

// Load up a Bibframe Instance
await pupExpect(page).toClick('a', { text: 'BIBFRAME Instance' })
await pupExpect(page).toMatchElement('button#editor-save')
await pupExpect(page).toMatchElement('button.editor-save')

// Can navigate away, since no changes
await pupExpect(page).toClick('a.nav-link', { text: 'Load RDF' })
await pupExpect(page).toMatch('Load RDF into Editor')

// Navigate back
await pupExpect(page).toClick('a.nav-link', { text: /^Editor$/ })
await pupExpect(page).toMatchElement('button#editor-save')
await pupExpect(page).toMatchElement('button.editor-save')

// Change something
await pupExpect(page).toMatchElement('[placeholder=\'Statement of Responsibility Relating to Title Proper (RDA 2.4.2)\'', 'World')
Expand Down
9 changes: 4 additions & 5 deletions __tests__/integration/previewSaveIncompleteResource.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ describe('Preview and try to save resource', () => {
const store = createReduxStore(createInitialState())
setupModal()
const {
getByText, getByTitle, getByTestId, queryAllByText, findByText, findByLabelText,
findByLabelText, findByText, getAllByTitle, getByText, getByTestId, queryAllByText,
} = renderWithRedux(
(<MemoryRouter><App /></MemoryRouter>), store,
)
Expand All @@ -101,9 +101,8 @@ describe('Preview and try to save resource', () => {
expect(groupChoiceModal.classList.contains('show')).not.toBe(true)

// Preview the RDF
const previewBtn = getByTitle('Preview RDF')

fireEvent.click(previewBtn)
const previewBtn = getAllByTitle('Preview RDF')
fireEvent.click(previewBtn[0])
await wait(() => {
expect(rdfModal.classList.contains('show')).toBe(true)
})
Expand All @@ -115,7 +114,7 @@ describe('Preview and try to save resource', () => {
// There are multiple of these on screen, so selecting by id.
// There is probably a more idiomatic way of doing this.
const saveAndPublish = queryAllByText('Save').find((btn) => {
return btn.id === 'modal-save'
return btn.classList.contains('modal-save')
})
fireEvent.click(saveAndPublish)
await wait(() => {
Expand Down
8 changes: 4 additions & 4 deletions __tests__/integration/previewSaveResource.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ describe('Preview and save resource', () => {
const store = createReduxStore(createInitialState())
setupModal()
const {
getByText, queryByText, queryAllByText, getByTestId, getByTitle, findByLabelText,
findByLabelText, getAllByTitle, getByTestId, getByText, queryAllByText, queryByText,
} = renderWithRedux(
(<MemoryRouter><App /></MemoryRouter>), store,
)
Expand All @@ -99,15 +99,15 @@ describe('Preview and save resource', () => {
fireEvent.click(getByText('Editor'))

// Preview the RDF
fireEvent.click(getByTitle('Preview RDF'))
fireEvent.click(getAllByTitle('Preview RDF')[0])
fireEvent.change(await findByLabelText(/Format/), { target: { value: 'n-triples' } })
expect(getByText(/<> <http:\/\/id.loc.gov\/ontologies\/bibframe\/mainTitle> "foo"@en \./)).toBeInTheDocument()

// Save
// There are multiple of these on screen, so selecting by id.
// There is probably a more idiomatic way of doing this.
const save = queryAllByText('Save').find((btn) => {
return btn.id === 'modal-save'
return btn.classList.contains('modal-save')
})
fireEvent.click(save)
expect(queryByText('Which group do you want to save to?')).toBeInTheDocument()
Expand All @@ -116,7 +116,7 @@ describe('Preview and save resource', () => {

// There are multiple of these on screen, so selecting by id
const finalSave = queryAllByText('Save').find((btn) => {
return btn.id !== 'modal-save' && btn.id !== 'editor-save'
return !btn.classList.contains('modal-save') && !btn.classList.contains('editor-save')
})
fireEvent.click(finalSave)

Expand Down
2 changes: 1 addition & 1 deletion __tests__/integration/validationErrors.ppt.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ describe('Validation errors', () => {
await pupExpect(page).toClick('button.btn-remove[data-id=\'content\']', { text: 'Remove' })

// Request validation
await pupExpect(page).toClick('button:enabled#editor-save', { text: 'Save' })
await pupExpect(page).toClick('button:enabled.editor-save', { text: 'Save' })

await pupExpect(page).toMatch('There was a problem saving this resource.')
await pupExpect(page).toMatch('BIBFRAME Instance > Agent Contribution: Required')
Expand Down
4 changes: 2 additions & 2 deletions cypress/integration/end2end.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,15 @@ describe('End-to-end test', () => {
})

it('Previews the RDF', () => {
cy.get('button[title="Preview RDF"]').click()
cy.get('button[title="Preview RDF"]').first().click()
cy.get('select#rdfFormat').select('n-triples')
cy.contains(`<> <http://id.loc.gov/ontologies/bibframe/mainTitle> "${title}"@en .`)
cy.contains('<> <http://sinopia.io/vocabulary/hasResourceTemplate> "ld4p:RT:bf2:WorkTitle" .')
cy.contains('<> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://id.loc.gov/ontologies/bibframe/Title> .')
})

it('Saves', () => {
cy.get('button#modal-save').click()
cy.get('button.modal-save').click()

cy.contains('Which group do you want to save to?')
cy.get('div#group-choice-modal button').contains('Save').click()
Expand Down
13 changes: 3 additions & 10 deletions src/components/editor/Editor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ import ResourceTemplate from './ResourceTemplate'
import Header from '../Header'
import RDFModal from './RDFModal'
import GroupChoiceModal from './GroupChoiceModal'
import CopyToNewButton from './CopyToNewButton'
import PreviewButton from './PreviewButton'
import SaveAndPublishButton from './SaveAndPublishButton'
import EditorActions from './EditorActions'
import ErrorMessages from './ErrorMessages'
import AuthenticationMessage from './AuthenticationMessage'
import Alert from '../Alert'
Expand All @@ -36,18 +34,13 @@ const Editor = (props) => {
<Prompt when={isPrompt} message="Resource has unsaved changes. Are you sure you want to leave?" />
<Header triggerEditorMenu={ triggerHandleOffsetMenu }/>
<AuthenticationMessage />
<div className="row">
<section className="col-md-3 offset-md-9 text-right">
<CopyToNewButton />
<PreviewButton />
<SaveAndPublishButton id="editor-save" />
</section>
</div>
<EditorActions />
<RDFModal />
<ErrorMessages />
<Alert text={saveError} />
<GroupChoiceModal />
<ResourceTemplate />
<EditorActions />
</div>
) }

Expand Down
20 changes: 20 additions & 0 deletions src/components/editor/EditorActions.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2019 Stanford University see LICENSE for license

import React from 'react'
import CopyToNewButton from './actions/CopyToNewButton'
import PreviewButton from './actions/PreviewButton'
import SaveAndPublishButton from './actions/SaveAndPublishButton'

const EditorActions = () => {
return (
<div className="row">
<section className="col-md-3 offset-md-9 text-right">
<CopyToNewButton />
<PreviewButton />
<SaveAndPublishButton class="editor-save" />
</section>
</div>
)
}

export default EditorActions
2 changes: 1 addition & 1 deletion src/components/editor/GroupChoiceModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import PropTypes from 'prop-types'
import Config from 'Config'
import { hideModal } from 'actions/index'
import { getCurrentUser } from 'authSelectors'
import { resourceEditErrorKey } from 'selectors/resourceSelectors'
import { publishResource } from 'actionCreators/resources'
import ModalWrapper, { useDisplayStyle, useModalCss } from '../ModalWrapper'
import { resourceEditErrorKey } from './ResourceTemplate'

const GroupChoiceModal = (props) => {
// The ld4p group is only for templates
Expand Down
4 changes: 2 additions & 2 deletions src/components/editor/RDFModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { connect, useDispatch } from 'react-redux'
import PropTypes from 'prop-types'
import GraphBuilder from 'GraphBuilder'
import ModalWrapper, { useDisplayStyle, useModalCss } from '../ModalWrapper'
import SaveAndPublishButton from './SaveAndPublishButton'
import SaveAndPublishButton from './actions/SaveAndPublishButton'
import RDFDisplay from './RDFDisplay'

const RDFModal = (props) => {
Expand Down Expand Up @@ -36,7 +36,7 @@ const RDFModal = (props) => {
<div className="row" style={{ marginLeft: '0', marginRight: '0' }}>
<div className="col-sm-6">If this looks good, then click Save and Publish</div>
<div className="col-sm-6" style={{ textAlign: 'right' }}>
<SaveAndPublishButton id="modal-save" />
<SaveAndPublishButton class="modal-save" />
</div>
</div>
<RDFDisplay rdf={props.rdf()} />
Expand Down
5 changes: 1 addition & 4 deletions src/components/editor/ResourceTemplate.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,14 @@ import React, { Component } from 'react'
import { connect } from 'react-redux'
import PropTypes from 'prop-types'
import ResourceTemplateForm from './ResourceTemplateForm'
import { getResourceTemplate, findErrors } from 'selectors/resourceSelectors'
import { resourceEditErrorKey, getResourceTemplate, findErrors } from 'selectors/resourceSelectors'
import CopyToNewMessage from './CopyToNewMessage'
import ResourceURIMessage from './ResourceURIMessage'
import SaveAlert from './SaveAlert'
import RDFDisplay from './RDFDisplay'
import Alerts from '../Alerts'
import _ from 'lodash'

// Error key for errors that occur while editing a resource.
export const resourceEditErrorKey = 'resourceedit'

/**
* This is the root component of the editor on the resource edit page
*/
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@ import PropTypes from 'prop-types'
import { update as updateCreator } from 'actionCreators/resources'
import {
rootResourceId, resourceHasChangesSinceLastSave, findResourceValidationErrors,
getDisplayResourceValidations,
resourceEditErrorKey, getDisplayResourceValidations,
} from 'selectors/resourceSelectors'
import { getCurrentUser } from 'authSelectors'
import {
showGroupChooser as showGroupChooserAction,
showValidationErrors as showValidationErrorsAction,
hideValidationErrors as hideValidationErrorsAction,
} from 'actions/index'
import { resourceEditErrorKey } from './ResourceTemplate'

const SaveAndPublishButton = (props) => {
const dispatch = useDispatch()
Expand Down Expand Up @@ -53,18 +52,14 @@ const SaveAndPublishButton = (props) => {
}

return (
<button id={ props.id } className="btn btn-primary" onClick={ save } aria-label="Save" disabled={ isDisabled }>
<button className={ `btn btn-primary ${props.class}` } onClick={ save } aria-label="Save" disabled={ isDisabled }>
Save
</button>
)
}

SaveAndPublishButton.propTypes = {
id: PropTypes.string,
isDisabled: PropTypes.bool,
update: PropTypes.func,
isSaved: PropTypes.bool,
currentUser: PropTypes.object,
class: PropTypes.string,
}

export default SaveAndPublishButton
4 changes: 2 additions & 2 deletions src/components/editor/property/OutlineHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import { faAngleRight, faAngleDown } from '@fortawesome/free-solid-svg-icons'
import PropertyLabel from './PropertyLabel'
import PropertyLabelInfo from './PropertyLabelInfo'
import {
findNode, isExpanded, getPropertyTemplate, findResourceValidationErrorsByPath, getDisplayResourceValidations,
resourceEditErrorKey, findNode, isExpanded, getPropertyTemplate,
findResourceValidationErrorsByPath, getDisplayResourceValidations,
} from 'selectors/resourceSelectors'
import { toggleCollapse, removeResource } from 'actions/index'
import { expandResource } from 'actionCreators/resources'
import _ from 'lodash'
import { resourceEditErrorKey } from '../ResourceTemplate'

const OutlineHeader = (props) => {
const icon = props.collapsed === true ? faAngleRight : faAngleDown
Expand Down
3 changes: 1 addition & 2 deletions src/components/editor/property/PropertyActionButtons.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { addResource } from 'actionCreators/resources'
import { removeResource } from 'actions/index'
import { getResourceTemplate } from 'selectors/resourceSelectors'
import { resourceEditErrorKey } from '../ResourceTemplate'
import { resourceEditErrorKey, getResourceTemplate } from 'selectors/resourceSelectors'

const PropertyActionButtons = (props) => {
const handleAddClick = (event) => {
Expand Down
3 changes: 1 addition & 2 deletions src/components/editor/property/PropertyPanel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { findNode, getPropertyTemplate } from 'selectors/resourceSelectors'
import { removeResource } from 'actions/index'
import { expandResource } from 'actionCreators/resources'
import { resourceEditErrorKey, expandResource } from 'actionCreators/resources'
import _ from 'lodash'
import { resourceEditErrorKey } from '../ResourceTemplate'

const PropertyPanel = (props) => {
const isAdd = _.isEmpty(props.resourceModel)
Expand Down
3 changes: 1 addition & 2 deletions src/components/search/SinopiaSearchResults.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@ import { copyNewResource, clearErrors } from 'actions/index'
import { retrieveResource } from 'actionCreators/resources'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faCopy, faEdit } from '@fortawesome/free-solid-svg-icons'
import { rootResource, findErrors } from 'selectors/resourceSelectors'
import { resourceEditErrorKey, rootResource, findErrors } from 'selectors/resourceSelectors'
import Alerts from '../Alerts'
import SinopiaSort from './SinopiaSort'
import _ from 'lodash'
import { resourceEditErrorKey } from 'components/editor/ResourceTemplate'

// Errors from retrieving a resource from this page.
export const searchRetrieveErrorKey = 'searchresource'
Expand Down
3 changes: 1 addition & 2 deletions src/hooks/useResource.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import { rdfDatasetFromN3 } from 'Utilities'
import { useDispatch, useSelector } from 'react-redux'
import { existingResource } from 'actionCreators/resources'
import { appendError, clearErrors } from 'actions/index'
import { rootResource as rootResourceSelector } from 'selectors/resourceSelectors'
import { resourceEditErrorKey } from 'components/editor/ResourceTemplate'
import { resourceEditErrorKey, rootResource as rootResourceSelector } from 'selectors/resourceSelectors'

/**
* Hook for transforming a resource to state and changing the page to the editor (i.e., /editor path).
Expand Down
3 changes: 3 additions & 0 deletions src/selectors/resourceSelectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
import GraphBuilder from 'GraphBuilder'
import { generateMD5 } from 'Utilities'

// Error key for errors that occur while editing a resource.
export const resourceEditErrorKey = 'resourceedit'

export const rootResource = state => Object.values(state.selectorReducer.resource)[0]

export const rootResourceTemplateId = state => Object.keys(state.selectorReducer.resource)[0]
Expand Down
2 changes: 1 addition & 1 deletion src/styles/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pre {
padding: 0px;
}

#editor-save {
.editor-save {
margin-left: 11px;
}

Expand Down

0 comments on commit 2031a2a

Please sign in to comment.