Skip to content

Commit

Permalink
Merge pull request #5 from zooniverse/general-editor
Browse files Browse the repository at this point in the history
Generalise the contents editor
  • Loading branch information
eatyourgreens authored Jun 22, 2017
2 parents 6b85bed + 7ef41fb commit c160b51
Show file tree
Hide file tree
Showing 13 changed files with 444 additions and 13 deletions.
2 changes: 1 addition & 1 deletion src/components/ProjectContents.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class ProjectContents extends Component {

render() {
const { contents } = this.props;
const project_contents = contents.data.length ? contents.data[0] : {};
const project_contents = contents.original.length ? contents.original[0] : {};
return (
<div>
<h2>Project Contents</h2>
Expand Down
54 changes: 54 additions & 0 deletions src/components/ProjectDashboard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from 'react';
import PropTypes from 'prop-types';
import fixIt from 'react-fix-it';
import { Link } from 'react-router';
import ProjectContentsContainer from '../containers/ProjectContentsContainer';
import ProjectContents from './ProjectContents';

const propTypes = {
project: PropTypes.object.isRequired,
tutorials: PropTypes.array.isRequired,
workflows: PropTypes.array.isRequired,
};

function ProjectDashboard(props) {
const { project } = props;
return (
<div>
<ProjectContentsContainer {...props}>
<ProjectContents />
</ProjectContentsContainer>
<h3>Workflows</h3>
<ul>
{props.workflows.map((workflow) => {
return (
<li key={workflow.id}>
<Link to={`/project/${project.id}/workflows/${workflow.id}`}>{workflow.display_name}</Link>
</li>
);
})}
</ul>
<h3>Tutorials</h3>
<ul>
{props.tutorials.map((tutorial) => {
return (
<li key={tutorial.id}>
<Link to={`/project/${project.id}/tutorials/${tutorial.id}`}>{tutorial.id}: {tutorial.display_name}</Link>
</li>
);
})}
</ul>
</div>
);
}

ProjectDashboard.propTypes = propTypes;

ProjectDashboard.defaultProps = {
project: {
tutorials: [],
workflows: []
}
};

export default fixIt(ProjectDashboard);
2 changes: 1 addition & 1 deletion src/components/ProjectList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class ProjectList extends Component {
<div>
<h2>Projects</h2>
<ul>
{projects.data.map(project => <ProjectListItem project={project} />)}
{projects.data.map(project => <ProjectListItem key={project.id} project={project} />)}
</ul>
</div>
);
Expand Down
30 changes: 30 additions & 0 deletions src/components/Resource.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import PropTypes from 'prop-types';
import fixIt, { options } from 'react-fix-it';
import Tutorial from './Tutorial';
import WorkflowContents from './WorkflowContents';

const resources = {
tutorials: Tutorial,
workflows: WorkflowContents
};

const propTypes = {
contents: PropTypes.object.isRequired,
params: PropTypes.shape({
resource_type: PropTypes.string
})
};

options.log = (test) => {
console.warn(test);
};

function Resource(props) {
const { contents } = props;
const ResourceViewer = resources[props.params.resource_type];
return (<ResourceViewer contents={contents} />);
}

Resource.propTypes = propTypes;
export default fixIt(Resource);
29 changes: 29 additions & 0 deletions src/components/Tutorial.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import PropTypes from 'prop-types';
import fixIt, { options } from 'react-fix-it';

const propTypes = {
contents: PropTypes.object.isRequired,
};

options.log = (test) => {
console.warn(test);
};

function Tutorial(props) {
const { contents } = props;
const tutorial = contents.original.length ? contents.original[0] : { steps: [] };
const steps = [];
tutorial.steps && tutorial.steps.map((step, key) => {
steps.push(<p key={key}><b>{key}</b> {step.content}</p>);
});
return (
<div>
<h2>Tutorial</h2>
{steps}
</div>
);
}

Tutorial.propTypes = propTypes;
export default fixIt(Tutorial);
33 changes: 33 additions & 0 deletions src/components/WorkflowContents.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import fixIt, { options } from 'react-fix-it';

const propTypes = {
contents: PropTypes.object.isRequired,
};

options.log = (test) => {
console.warn(test);
};

class WorkflowContents extends Component {

render() {
const { contents } = this.props;
const workflow_contents = contents.original.length ? contents.original[0] : {strings: []};
console.log(workflow_contents)
const strings = [];
for (const key in workflow_contents.strings) {
strings.push(<p key={key}><b>{key}</b> {workflow_contents.strings[key]}</p>);
}
return (
<div>
<h2>Workflow Contents</h2>
{strings}
</div>
);
}
}

WorkflowContents.propTypes = propTypes;
export default fixIt(WorkflowContents);
20 changes: 13 additions & 7 deletions src/containers/ProjectContentsContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as contentsActions from '../ducks/contents';
import ProjectContents from '../components/ProjectContents';
import * as contentsActions from '../ducks/resource';
import { BaseModal, ModalBody, ModalFooter } from 'pui-react-modals';
import { DefaultButton } from 'pui-react-buttons';

const propTypes = {
actions: PropTypes.object.isRequired,
contents: PropTypes.object.isRequired,
children: PropTypes.node,
params: PropTypes.shape({
project_id: PropTypes.string,
resource_id: PropTypes.string,
resource_type: PropTypes.string
})
};

class ProjectContentsContainer extends Component {
Expand All @@ -24,7 +28,9 @@ class ProjectContentsContainer extends Component {

componentDidMount() {
const { actions } = this.props;
return actions.fetchProjectContents(this.props.params.project_id);
const type = this.props.params.resource_type;
const id = type ? this.props.params.resource_id : this.props.params.project_id;
actions.fetchResource(id, type);
}

handleClick(event) {
Expand All @@ -35,7 +41,7 @@ class ProjectContentsContainer extends Component {
}

render() {
const { contents } = this.props;
const { resource } = this.props;
return (
<div>
<BaseModal
Expand All @@ -55,15 +61,15 @@ class ProjectContentsContainer extends Component {
</ModalFooter>
</BaseModal>
<div onClick={this.handleClick}>
<ProjectContents contents={contents} />
{React.cloneElement(this.props.children, { contents: resource })}
</div>
</div>
);
}
}

const mapStateToProps = (state) => ({
contents: state.contents,
resource: state.resource,
});
const mapDispatchToProps = (dispatch) => ({
actions: bindActionCreators(contentsActions, dispatch),
Expand Down
58 changes: 58 additions & 0 deletions src/containers/ProjectDashboardContainer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as projectActions from '../ducks/project';

const propTypes = {
actions: PropTypes.object.isRequired,
children: PropTypes.node,
project: PropTypes.shape({
data: PropTypes.object,
tutorials: PropTypes.array,
workflows: PropTypes.array
}),
params: PropTypes.shape({
project_id: PropTypes.string
})
};

class ProjectDashboardContainer extends Component {

componentDidMount() {
const { actions } = this.props;
actions.fetchProject(this.props.params.project_id);
}

render() {
const project = this.props.project.data;
const { workflows, tutorials } = this.props.project;
return (
<div>
<h2>Project Dashboard</h2>
{React.cloneElement(this.props.children, { project, workflows, tutorials })}
</div>
);
}
}

const mapStateToProps = (state) => ({
project: state.project
});
const mapDispatchToProps = (dispatch) => ({
actions: bindActionCreators(projectActions, dispatch),
});

ProjectDashboardContainer.propTypes = propTypes;
ProjectDashboardContainer.defaultProps = {
children: null,
project: {
data: null,
tutorials: [],
workflows: []
}
};
export default connect(
mapStateToProps,
mapDispatchToProps,
)(ProjectDashboardContainer);
102 changes: 102 additions & 0 deletions src/ducks/project.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import apiClient from 'panoptes-client/lib/api-client';

// Action Types
export const FETCH_PROJECT = 'FETCH_PROJECT';
export const FETCH_PROJECT_SUCCESS = 'FETCH_PROJECT_SUCCESS';
export const FETCH_PROJECT_ERROR = 'FETCH_PROJECT_ERROR';
export const FETCH_WORKFLOWS = 'FETCH_WORKFLOWS';
export const FETCH_WORKFLOWS_SUCCESS = 'FETCH_WORKFLOWS_SUCCESS';
export const FETCH_WORKFLOWS_ERROR = 'FETCH_WORKFLOWS_ERROR';
export const FETCH_TUTORIALS = 'FETCH_TUTORIALS';
export const FETCH_TUTORIALS_SUCCESS = 'FETCH_TUTORIALS_SUCCESS';
export const FETCH_TUTORIALS_ERROR = 'FETCH_TUTORIALS_ERROR';

// Reducer
const initialState = {
data: {},
tutorials: [],
workflows: [],
error: false,
loading: false,
};

const projectReducer = (state = initialState, action) => {
switch (action.type) {
case FETCH_PROJECT:
return Object.assign({}, initialState, { loading: true });
case FETCH_PROJECT_SUCCESS:
return Object.assign({}, state, { data: action.payload, loading: false });
case FETCH_PROJECT_ERROR:
return Object.assign({}, state, { error: action.payload, loading: false });
case FETCH_WORKFLOWS:
return Object.assign({}, state, { loading: true });
case FETCH_WORKFLOWS_SUCCESS:
return Object.assign({}, state, { workflows: action.payload, loading: false });
case FETCH_TUTORIALS:
return Object.assign({}, state, { loading: true });
case FETCH_TUTORIALS_SUCCESS:
return Object.assign({}, state, { tutorials: action.payload, loading: false });
default:
return state;
}
};

// Action Creators
const fetchProject = (id) => {
return (dispatch) => {
dispatch({
type: FETCH_PROJECT,
});
const query = {
id,
current_user_roles: ['owner', 'translator'],
include: ['workflows']
};
apiClient.type('projects').get(query)
.then(([project]) => {
dispatch(fetchWorkflows(project));
dispatch(fetchTutorials(project));
dispatch({
type: FETCH_PROJECT_SUCCESS,
payload: project,
});
});
};
};

function fetchWorkflows(project) {
return (dispatch) => {
dispatch({
type: FETCH_WORKFLOWS,
});
apiClient.type('workflows').get(project.links.workflows)
.then((workflows) => {
dispatch({
type: FETCH_WORKFLOWS_SUCCESS,
payload: workflows,
});
});
};
}

function fetchTutorials(project) {
return (dispatch) => {
dispatch({
type: FETCH_TUTORIALS,
});
apiClient.type('tutorials').get({ project_id: project.id })
.then((tutorials) => {
dispatch({
type: FETCH_TUTORIALS_SUCCESS,
payload: tutorials,
});
});
};
}

// Exports
export default projectReducer;

export {
fetchProject
};
2 changes: 1 addition & 1 deletion src/ducks/projects.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const fetchProjects = () => {
});
const query = {
current_user_roles: ['owner', 'translator']
}
};
apiClient.type('projects').get(query)
.then((projects) => {
dispatch({
Expand Down
Loading

0 comments on commit c160b51

Please sign in to comment.