diff --git a/__tests__/src/components/AnnotationSettings.test.js b/__tests__/src/components/AnnotationSettings.test.js new file mode 100644 index 0000000000000000000000000000000000000000..259453fc1f770d322ad6e34066d5178b3559eed6 --- /dev/null +++ b/__tests__/src/components/AnnotationSettings.test.js @@ -0,0 +1,78 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import { AnnotationSettings } from '../../../src/components/AnnotationSettings'; + +/** */ +function createWrapper(props) { + return shallow( + <AnnotationSettings + displayAll={false} + displayAllDisabled={false} + t={k => k} + toggleAnnotationDisplay={() => {}} + windowId="abc123" + {...props} + />, + ); +} + +describe('AnnotationSettings', () => { + let control; + let wrapper; + const toggleAnnotationDisplayMock = jest.fn(); + + + it('renders a FormControlLabel and a Switch', () => { + wrapper = createWrapper(); + control = shallow( + wrapper.find('WithStyles(WithFormControlContext(FormControlLabel))').props().control, + ); + expect(wrapper.find('WithStyles(WithFormControlContext(FormControlLabel))').length).toBe(1); + expect(control.find('Switch').length).toBe(1); + }); + + describe('control', () => { + it('is not checked when the displayAll prop is false', () => { + wrapper = createWrapper(); + control = shallow( + wrapper.find('WithStyles(WithFormControlContext(FormControlLabel))').props().control, + ); + + expect(control.find('Switch').props().checked).toBe(false); + }); + + it('is checked when the displayAll prop is true', () => { + wrapper = createWrapper({ displayAll: true }); + control = shallow( + wrapper.find('WithStyles(WithFormControlContext(FormControlLabel))').props().control, + ); + + expect(control.find('Switch').props().checked).toBe(true); + }); + + it('is disabled based on the displayAllDisabled prop', () => { + wrapper = createWrapper(); + control = shallow( + wrapper.find('WithStyles(WithFormControlContext(FormControlLabel))').props().control, + ); + expect(control.find('Switch').props().disabled).toBe(false); + + wrapper = createWrapper({ displayAllDisabled: true }); + control = shallow( + wrapper.find('WithStyles(WithFormControlContext(FormControlLabel))').props().control, + ); + expect(control.find('Switch').props().disabled).toBe(true); + }); + + it('calls the toggleAnnotationDisplay prop function on change', () => { + wrapper = createWrapper({ toggleAnnotationDisplay: toggleAnnotationDisplayMock }); + control = shallow( + wrapper.find('WithStyles(WithFormControlContext(FormControlLabel))').props().control, + ); + + control.find('Switch').props().onChange(); // trigger the onChange prop + + expect(toggleAnnotationDisplayMock).toHaveBeenCalledTimes(1); + }); + }); +}); diff --git a/src/components/AnnotationSettings.js b/src/components/AnnotationSettings.js new file mode 100644 index 0000000000000000000000000000000000000000..6d8313cc4bc6e50189c4162a8726ac06eb2fc33f --- /dev/null +++ b/src/components/AnnotationSettings.js @@ -0,0 +1,42 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import FormControlLabel from '@material-ui/core/FormControlLabel'; +import Switch from '@material-ui/core/Switch'; + +/** + * AnnotationSettings is a component to handle various annotation + * display settings in the Annotation companion window +*/ +export class AnnotationSettings extends Component { + /** + * Returns the rendered component + */ + render() { + const { + displayAll, displayAllDisabled, t, toggleAnnotationDisplay, + } = this.props; + + return ( + <FormControlLabel + control={( + <Switch + checked={displayAll} + disabled={displayAllDisabled} + onChange={toggleAnnotationDisplay} + value={displayAll ? 'all' : 'select'} + /> + )} + label={t('displayAllAnnotations')} + labelPlacement="start" + /> + ); + } +} + +AnnotationSettings.propTypes = { + displayAll: PropTypes.bool.isRequired, + displayAllDisabled: PropTypes.bool.isRequired, + t: PropTypes.func.isRequired, + toggleAnnotationDisplay: PropTypes.func.isRequired, + windowId: PropTypes.string.isRequired, // eslint-disable-line react/no-unused-prop-types +}; diff --git a/src/containers/AnnotationSettings.js b/src/containers/AnnotationSettings.js new file mode 100644 index 0000000000000000000000000000000000000000..5fbec40b2e8c34e514c2e1aa4447d81c32f0fb1a --- /dev/null +++ b/src/containers/AnnotationSettings.js @@ -0,0 +1,39 @@ +import { compose } from 'redux'; +import { connect } from 'react-redux'; +import { withTranslation } from 'react-i18next'; +import * as actions from '../state/actions'; +import { withPlugins } from '../extend'; +import { + getAnnotationResourcesByMotivation, + getSelectedTargetAnnotations, + getSelectedCanvas, +} from '../state/selectors'; +import { AnnotationSettings } from '../components/AnnotationSettings'; + +/** + * Mapping redux state to component props using connect + */ +const mapStateToProps = (state, { windowId }) => ({ + displayAll: state.windows[windowId].displayAllAnnotations, + displayAllDisabled: getAnnotationResourcesByMotivation( + getSelectedTargetAnnotations(state, (getSelectedCanvas(state, { windowId }) || {}).id), + ['oa:commenting', 'sc:painting'], + ).length < 2, +}); + +/** + * Mapping redux action dispatches to component props using connect + */ +const mapDispatchToProps = (dispatch, { windowId }) => ({ + toggleAnnotationDisplay: () => { + dispatch(actions.toggleAnnotationDisplay(windowId)); + }, +}); + +const enhance = compose( + withTranslation(), + connect(mapStateToProps, mapDispatchToProps), + withPlugins('AnnotationSettings'), +); + +export default enhance(AnnotationSettings); diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 2aa1e49e42f0abeae1f1a88c078b4338616abba6..ceac6cbdc12f1815eab761a3f19879df40925620 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -18,6 +18,7 @@ "currentItem": "Current item", "dark": "Dark theme", "dismiss": "Dismiss", + "displayAllAnnotations": "Highlight all", "downloadExport": "Download/Export workspace", "downloadExportWorkspace": "Download/Export workspace", "elastic": "Elastic",