Skip to content
Snippets Groups Projects
Commit c78e51cf authored by Chris Beer's avatar Chris Beer
Browse files

Move adding manifests to the workspace to a new component

parent 1474a721
No related branches found
No related tags found
No related merge requests found
Showing
with 204 additions and 105 deletions
...@@ -40,4 +40,13 @@ describe('workspace actions', () => { ...@@ -40,4 +40,13 @@ describe('workspace actions', () => {
expect(actions.toggleZoomControls(true)).toEqual(expectedAction); expect(actions.toggleZoomControls(true)).toEqual(expectedAction);
}); });
}); });
describe('setWorkspaceAddVisibility', () => {
it('should set the workspace add visibility', () => {
const expectedAction = {
type: ActionTypes.SET_WORKSPACE_ADD_VISIBILITY,
isWorkspaceAddVisible: true,
};
expect(actions.setWorkspaceAddVisibility(true)).toEqual(expectedAction);
});
});
}); });
...@@ -4,6 +4,7 @@ import { MuiThemeProvider } from '@material-ui/core/styles'; ...@@ -4,6 +4,7 @@ import { MuiThemeProvider } from '@material-ui/core/styles';
import Fullscreen from 'react-fullscreen-crossbrowser'; import Fullscreen from 'react-fullscreen-crossbrowser';
import WorkspaceControlPanel from '../../../src/components/WorkspaceControlPanel'; import WorkspaceControlPanel from '../../../src/components/WorkspaceControlPanel';
import Workspace from '../../../src/containers/Workspace'; import Workspace from '../../../src/containers/Workspace';
import WorkspaceAdd from '../../../src/containers/WorkspaceAdd';
import App from '../../../src/components/App'; import App from '../../../src/components/App';
/** */ /** */
...@@ -49,4 +50,11 @@ describe('App', () => { ...@@ -49,4 +50,11 @@ describe('App', () => {
expect(wrapper.find(Fullscreen).first().prop('enabled')) expect(wrapper.find(Fullscreen).first().prop('enabled'))
.toEqual(true); .toEqual(true);
}); });
describe('with isWorkspaceAddVisible', () => {
const wrapper = createWrapper({ isWorkspaceAddVisible: true });
expect(wrapper.find(Workspace).length).toBe(0);
expect(wrapper.find(WorkspaceAdd).length).toBe(1);
});
}); });
import React from 'react';
import { shallow } from 'enzyme';
import WorkspaceAdd from '../../../src/components/WorkspaceAdd';
import fixture from '../../fixtures/version-2/002.json';
/** create wrapper */
function createWrapper(props) {
return shallow(
<WorkspaceAdd
setWorkspaceAddVisibility={() => {}}
manifests={{ foo: fixture, bar: fixture }}
classes={{}}
t={str => str}
{...props}
/>,
);
}
describe('WorkspaceAddButton', () => {
it('renders a list item for each manifest in the state', () => {
const wrapper = createWrapper();
expect(wrapper.find('ul Connect(ManifestListItem)').length).toBe(2);
});
it('toggles the workspace visibility', () => {
const setWorkspaceAddVisibility = jest.fn();
const wrapper = createWrapper({ setWorkspaceAddVisibility });
wrapper.find('ul Connect(ManifestListItem)').first().props().handleClose();
expect(setWorkspaceAddVisibility).toHaveBeenCalledWith(false);
});
});
import React from 'react'; import React from 'react';
import { shallow } from 'enzyme'; import { shallow } from 'enzyme';
import Fab from '@material-ui/core/Fab';
import AddIcon from '@material-ui/icons/Add';
import ClearIcon from '@material-ui/icons/Clear';
import WorkspaceAddButton from '../../../src/components/WorkspaceAddButton'; import WorkspaceAddButton from '../../../src/components/WorkspaceAddButton';
import fixture from '../../fixtures/version-2/002.json';
describe('WorkspaceAddButton', () => { /** create wrapper */
let wrapper; function createWrapper(props) {
beforeEach(() => { return shallow(
wrapper = shallow( <WorkspaceAddButton
<WorkspaceAddButton manifests={{ foo: fixture, bar: fixture }} classes={{}} />, classes={{}}
).dive(); t={str => str}
}); {...props}
/>,
).dive(); // unwrap HOC created by withStyles()
}
it('renders a list item for each manifest in the state', () => { describe('WorkspaceAddButton', () => {
expect(wrapper.find('ul Connect(ManifestListItem)').length).toBe(2); it('renders a button to open the load window area', () => {
}); const setWorkspaceAddVisibility = jest.fn();
const wrapper = createWrapper({ isWorkspaceAddVisible: false, setWorkspaceAddVisibility });
describe('handleAddManifestClick', () => { expect(wrapper.find(AddIcon).length).toBe(1);
it('sets the anchor state', () => {
wrapper.instance().handleAddManifestClick({ currentTarget: true });
expect(wrapper.dive().find('WithStyles(Menu)').props().open).toBe(true); wrapper.find(Fab).simulate('click');
}); expect(setWorkspaceAddVisibility).toHaveBeenCalledWith(true);
}); });
describe('handleAddManifestClose', () => { it('renders a button to close the load window area', () => {
it('resets the anchor state', () => { const setWorkspaceAddVisibility = jest.fn();
wrapper.instance().handleAddManifestClose(); const wrapper = createWrapper({ isWorkspaceAddVisible: true, setWorkspaceAddVisibility });
expect(wrapper.dive().find('WithStyles(Menu)').props().open).toBe(false); expect(wrapper.find(ClearIcon).length).toBe(1);
});
wrapper.find(Fab).simulate('click');
expect(setWorkspaceAddVisibility).toHaveBeenCalledWith(false);
}); });
}); });
...@@ -34,4 +34,12 @@ describe('workspace reducer', () => { ...@@ -34,4 +34,12 @@ describe('workspace reducer', () => {
layout: { foo: 'bar' }, layout: { foo: 'bar' },
}); });
}); });
it('should handle SET_WORKSPACE_ADD_VISIBILITY', () => {
expect(reducer([], {
type: ActionTypes.SET_WORKSPACE_ADD_VISIBILITY,
isWorkspaceAddVisible: true,
})).toEqual({
isWorkspaceAddVisible: true,
});
});
}); });
...@@ -5,6 +5,7 @@ import { MuiThemeProvider, createMuiTheme, withStyles } from '@material-ui/core/ ...@@ -5,6 +5,7 @@ import { MuiThemeProvider, createMuiTheme, withStyles } from '@material-ui/core/
import Fullscreen from 'react-fullscreen-crossbrowser'; import Fullscreen from 'react-fullscreen-crossbrowser';
import WorkspaceControlPanel from './WorkspaceControlPanel'; import WorkspaceControlPanel from './WorkspaceControlPanel';
import Workspace from '../containers/Workspace'; import Workspace from '../containers/Workspace';
import WorkspaceAdd from '../containers/WorkspaceAdd';
import ns from '../config/css-ns'; import ns from '../config/css-ns';
/** /**
...@@ -32,7 +33,7 @@ class App extends Component { ...@@ -32,7 +33,7 @@ class App extends Component {
*/ */
render() { render() {
const { const {
isFullscreenEnabled, setWorkspaceFullscreen, classes, isFullscreenEnabled, setWorkspaceFullscreen, classes, isWorkspaceAddVisible,
} = this.props; } = this.props;
return ( return (
...@@ -42,7 +43,11 @@ class App extends Component { ...@@ -42,7 +43,11 @@ class App extends Component {
enabled={isFullscreenEnabled} enabled={isFullscreenEnabled}
onChange={setWorkspaceFullscreen} onChange={setWorkspaceFullscreen}
> >
<Workspace /> {
isWorkspaceAddVisible
? <WorkspaceAdd />
: <Workspace />
}
</Fullscreen> </Fullscreen>
<WorkspaceControlPanel /> <WorkspaceControlPanel />
</MuiThemeProvider> </MuiThemeProvider>
...@@ -56,10 +61,12 @@ App.propTypes = { ...@@ -56,10 +61,12 @@ App.propTypes = {
isFullscreenEnabled: PropTypes.bool, // eslint-disable-line react/forbid-prop-types isFullscreenEnabled: PropTypes.bool, // eslint-disable-line react/forbid-prop-types
classes: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types, classes: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types,
setWorkspaceFullscreen: PropTypes.func.isRequired, setWorkspaceFullscreen: PropTypes.func.isRequired,
isWorkspaceAddVisible: PropTypes.bool,
}; };
App.defaultProps = { App.defaultProps = {
isFullscreenEnabled: false, isFullscreenEnabled: false,
isWorkspaceAddVisible: false,
}; };
/** /**
Material UI style overrides Material UI style overrides
......
...@@ -4,7 +4,6 @@ import PropTypes from 'prop-types'; ...@@ -4,7 +4,6 @@ import PropTypes from 'prop-types';
/** /**
* Provides a form for user input of a manifest url * Provides a form for user input of a manifest url
* @prop {Function} fetchManifest * @prop {Function} fetchManifest
* @prop {Function} setLastRequested
*/ */
class ManifestForm extends Component { class ManifestForm extends Component {
/** /**
...@@ -26,11 +25,10 @@ class ManifestForm extends Component { ...@@ -26,11 +25,10 @@ class ManifestForm extends Component {
* @private * @private
*/ */
formSubmit(event) { formSubmit(event) {
const { fetchManifest, setLastRequested } = this.props; const { fetchManifest } = this.props;
const { formValue } = this.state; const { formValue } = this.state;
event.preventDefault(); event.preventDefault();
fetchManifest(formValue); fetchManifest(formValue);
setLastRequested(formValue);
} }
/** /**
...@@ -69,7 +67,6 @@ class ManifestForm extends Component { ...@@ -69,7 +67,6 @@ class ManifestForm extends Component {
ManifestForm.propTypes = { ManifestForm.propTypes = {
fetchManifest: PropTypes.func.isRequired, fetchManifest: PropTypes.func.isRequired,
setLastRequested: PropTypes.func.isRequired,
t: PropTypes.func, t: PropTypes.func,
}; };
......
import React from 'react';
import PropTypes from 'prop-types';
import ns from '../config/css-ns';
import ManifestForm from '../containers/ManifestForm';
import ManifestListItem from '../containers/ManifestListItem';
/**
* An area for managing manifests and adding them to workspace
* @memberof Workspace
* @private
*/
class WorkspaceAdd extends React.Component {
/**
* render
*/
render() {
const { manifests, setWorkspaceAddVisibility } = this.props;
const manifestList = Object.keys(manifests).map(manifest => (
<ManifestListItem
key={manifest}
manifest={manifest}
handleClose={() => setWorkspaceAddVisibility(false)}
/>
));
return (
<div className={ns('workspace-add')}>
<ManifestForm
id="add-form"
/>
<ul>{manifestList}</ul>
</div>
);
}
}
WorkspaceAdd.propTypes = {
manifests: PropTypes.instanceOf(Object).isRequired,
setWorkspaceAddVisibility: PropTypes.func.isRequired,
};
export default WorkspaceAdd;
...@@ -3,113 +3,50 @@ import PropTypes from 'prop-types'; ...@@ -3,113 +3,50 @@ import PropTypes from 'prop-types';
import ListItem from '@material-ui/core/ListItem'; import ListItem from '@material-ui/core/ListItem';
import Fab from '@material-ui/core/Fab'; import Fab from '@material-ui/core/Fab';
import AddIcon from '@material-ui/icons/Add'; import AddIcon from '@material-ui/icons/Add';
import ClearIcon from '@material-ui/icons/Clear';
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import Menu from '@material-ui/core/Menu';
import ManifestForm from '../containers/ManifestForm';
import ManifestListItem from '../containers/ManifestListItem';
/** /**
*/ */
class WorkspaceAddButton extends Component { class WorkspaceAddButton extends Component {
/**
* constructor -
*/
constructor(props) {
super(props);
this.state = {
lastRequested: '',
anchorEl: null,
};
this.handleAddManifestClick = this.handleAddManifestClick.bind(this);
this.handleAddManifestClose = this.handleAddManifestClose.bind(this);
this.setLastRequested = this.setLastRequested.bind(this);
}
/**
* setLastRequested - Sets the state lastRequested
*
* @private
*/
setLastRequested(requested) {
this.setState({
lastRequested: requested,
});
}
/**
* @private
*/
handleAddManifestClick(event) {
this.setState({
anchorEl: event.currentTarget,
});
}
/**
* @private
*/
handleAddManifestClose() {
this.setState({
anchorEl: null,
});
}
/** /**
* render * render
* @return * @return
*/ */
render() { render() {
const { classes, t, manifests } = this.props; const {
const { lastRequested, anchorEl } = this.state; classes, t, setWorkspaceAddVisibility, isWorkspaceAddVisible,
} = this.props;
const manifestList = Object.keys(manifests).map(manifest => (
<ManifestListItem
key={manifest}
manifest={manifest}
handleClose={this.handleAddManifestClose}
/>
));
return ( return (
<ListItem> <ListItem>
<Fab <Fab
color="primary" color="primary"
id="addBtn" id="addBtn"
aria-label={t('add')} aria-label={isWorkspaceAddVisible ? t('closeWindow') : t('add')}
className={classes.fab} className={classes.fab}
aria-owns={anchorEl ? 'add-form' : undefined} onClick={() => { setWorkspaceAddVisibility(!isWorkspaceAddVisible); }}
aria-haspopup="true"
onClick={this.handleAddManifestClick}
> >
<AddIcon /> {
isWorkspaceAddVisible
? <ClearIcon />
: <AddIcon />
}
</Fab> </Fab>
<Menu
id="ws-ctrl-pnl-mn"
anchorEl={anchorEl}
open={Boolean(anchorEl)}
onClose={this.handleAddManifestClose}
>
<ManifestForm
id="add-form"
setLastRequested={this.setLastRequested}
/>
<ul>{manifestList}</ul>
{lastRequested}
</Menu>
</ListItem> </ListItem>
); );
} }
} }
WorkspaceAddButton.propTypes = { WorkspaceAddButton.propTypes = {
manifests: PropTypes.instanceOf(Object).isRequired,
classes: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types classes: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
t: PropTypes.func, t: PropTypes.func,
setWorkspaceAddVisibility: PropTypes.func.isRequired,
isWorkspaceAddVisible: PropTypes.bool,
}; };
WorkspaceAddButton.defaultProps = { WorkspaceAddButton.defaultProps = {
t: key => key, t: key => key,
isWorkspaceAddVisible: false,
}; };
/** /**
......
...@@ -12,6 +12,7 @@ const mapStateToProps = state => ( ...@@ -12,6 +12,7 @@ const mapStateToProps = state => (
{ {
theme: state.config.theme, theme: state.config.theme,
isFullscreenEnabled: state.workspace.isFullscreenEnabled, isFullscreenEnabled: state.workspace.isFullscreenEnabled,
isWorkspaceAddVisible: state.workspace.isWorkspaceAddVisible,
} }
); );
......
import { compose } from 'redux';
import { connect } from 'react-redux';
import * as actions from '../state/actions';
import WorkspaceAdd from '../components/WorkspaceAdd';
/**
* mapStateToProps - to hook up connect
* @memberof Workspace
* @private
*/
const mapStateToProps = state => ({ manifests: state.manifests });
/**
* mapDispatchToProps - used to hook up connect to action creators
* @memberof Workspace
* @private
*/
const mapDispatchToProps = { setWorkspaceAddVisibility: actions.setWorkspaceAddVisibility };
const enhance = compose(
connect(mapStateToProps, mapDispatchToProps),
// further HOC go here
);
export default enhance(WorkspaceAdd);
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { compose } from 'redux'; import { compose } from 'redux';
import { withNamespaces } from 'react-i18next'; import { withNamespaces } from 'react-i18next';
import * as actions from '../state/actions';
import miradorWithPlugins from '../lib/miradorWithPlugins'; import miradorWithPlugins from '../lib/miradorWithPlugins';
import WorkspaceAddButton from '../components/WorkspaceAddButton'; import WorkspaceAddButton from '../components/WorkspaceAddButton';
...@@ -12,11 +13,19 @@ import WorkspaceAddButton from '../components/WorkspaceAddButton'; ...@@ -12,11 +13,19 @@ import WorkspaceAddButton from '../components/WorkspaceAddButton';
const mapStateToProps = state => ( const mapStateToProps = state => (
{ {
manifests: state.manifests, manifests: state.manifests,
isWorkspaceAddVisible: state.workspace.isWorkspaceAddVisible,
} }
); );
/**
* mapDispatchToProps - used to hook up connect to action creators
* @memberof Workspace
* @private
*/
const mapDispatchToProps = { setWorkspaceAddVisibility: actions.setWorkspaceAddVisibility };
const enhance = compose( const enhance = compose(
connect(mapStateToProps), connect(mapStateToProps, mapDispatchToProps),
withNamespaces(), withNamespaces(),
miradorWithPlugins, miradorWithPlugins,
); );
......
...@@ -14,6 +14,7 @@ const ActionTypes = { ...@@ -14,6 +14,7 @@ const ActionTypes = {
SET_CONFIG: 'SET_CONFIG', SET_CONFIG: 'SET_CONFIG',
SET_WINDOW_THUMBNAIL_POSITION: 'SET_WINDOW_THUMBNAIL_POSITION', SET_WINDOW_THUMBNAIL_POSITION: 'SET_WINDOW_THUMBNAIL_POSITION',
SET_WINDOW_VIEW_TYPE: 'SET_WINDOW_VIEW_TYPE', SET_WINDOW_VIEW_TYPE: 'SET_WINDOW_VIEW_TYPE',
SET_WORKSPACE_ADD_VISIBILITY: 'SET_WORKSPACE_ADD_VISIBILITY',
TOGGLE_WINDOW_SIDE_BAR: 'TOGGLE_WINDOW_SIDE_BAR', TOGGLE_WINDOW_SIDE_BAR: 'TOGGLE_WINDOW_SIDE_BAR',
TOGGLE_WINDOW_SIDE_BAR_PANEL: 'TOGGLE_WINDOW_SIDE_BAR_PANEL', TOGGLE_WINDOW_SIDE_BAR_PANEL: 'TOGGLE_WINDOW_SIDE_BAR_PANEL',
TOGGLE_ZOOM_CONTROLS: 'TOGGLE_ZOOM_CONTROLS', TOGGLE_ZOOM_CONTROLS: 'TOGGLE_ZOOM_CONTROLS',
......
...@@ -29,3 +29,13 @@ export function toggleZoomControls(showZoomControls) { ...@@ -29,3 +29,13 @@ export function toggleZoomControls(showZoomControls) {
export function updateWorkspaceMosaicLayout(layout) { export function updateWorkspaceMosaicLayout(layout) {
return { type: ActionTypes.UPDATE_WORKSPACE_MOSAIC_LAYOUT, layout }; return { type: ActionTypes.UPDATE_WORKSPACE_MOSAIC_LAYOUT, layout };
} }
/**
* updateWorkspaceMosaicLayout - action creator
*
* @param {Object} layout
* @memberof ActionCreators
*/
export function setWorkspaceAddVisibility(isWorkspaceAddVisible) {
return { type: ActionTypes.SET_WORKSPACE_ADD_VISIBILITY, isWorkspaceAddVisible };
}
...@@ -13,6 +13,8 @@ const workspaceReducer = (state = {}, action) => { ...@@ -13,6 +13,8 @@ const workspaceReducer = (state = {}, action) => {
return { ...state, showZoomControls: action.showZoomControls }; return { ...state, showZoomControls: action.showZoomControls };
case ActionTypes.UPDATE_WORKSPACE_MOSAIC_LAYOUT: case ActionTypes.UPDATE_WORKSPACE_MOSAIC_LAYOUT:
return { ...state, layout: action.layout }; return { ...state, layout: action.layout };
case ActionTypes.SET_WORKSPACE_ADD_VISIBILITY:
return { ...state, isWorkspaceAddVisible: action.isWorkspaceAddVisible };
default: default:
return state; return state;
} }
......
...@@ -19,6 +19,10 @@ ...@@ -19,6 +19,10 @@
top: 0; top: 0;
} }
&-workspace-add {
padding-left: 100px;
}
&-window-middle-content { &-window-middle-content {
display: flex; display: flex;
flex: 1; flex: 1;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment