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