Commit f464520c authored by Alexandros Georgantas's avatar Alexandros Georgantas

global teams added

parent 494ab12f
......@@ -472,7 +472,12 @@ function mapStateToProps(state, { match }) {
'index',
)
if (book) {
teams = _.filter(state.teams, t => t.object.id === book.id)
teams = _.filter(state.teams, t => {
if (!t.global) {
return t.object.id === book.id
}
return false
})
}
const { error, currentUser: user, users } = state
......
import { get, includes } from 'lodash'
import { get } from 'lodash'
import React from 'react'
import PropTypes from 'prop-types'
import withLink from 'editoria-common/src/withLink'
......
......@@ -82,6 +82,9 @@ class Navigation extends React.Component {
<LinkContainer to="/users">
<NavItem>Users</NavItem>
</LinkContainer>
<LinkContainer to="/globalTeams">
<NavItem>Global Teams</NavItem>
</LinkContainer>
</Authorize>
{BackToBooks}
......
......@@ -3,6 +3,7 @@ import { Redirect, Route, Switch } from 'react-router-dom'
// Users and Teams
import UsersManager from 'pubsweet-component-users-manager/UsersManagerContainer'
import GlobalTeamsManager from 'pubsweet-component-booksprints-globalteams/src/GlobalTeamsManager'
// import TeamsManager from 'pubsweet-component-teams-manager/TeamsManagerContainer'
// Authentication
......@@ -87,6 +88,7 @@ export default (
path="/books/:bookId/fragments/:fragmentId"
/>
<PrivateRoute component={UsersManager} path="/users" />
<PrivateRoute component={GlobalTeamsManager} path="/globalTeams" />
</Manage>
</Switch>
)
......
......@@ -14,14 +14,11 @@ const logger = new winston.Logger({
module.exports = {
authsome: {
mode: require.resolve('pubsweet-editoria-authsome'),
mode: require.resolve('pubsweet-editoria-booksprints-authsome'),
teams: {
productionEditor: {
name: 'Production Editor',
},
copyEditor: {
name: 'Copy Editor',
},
author: {
name: 'Author',
},
......
......@@ -26,4 +26,7 @@ module.exports = {
title: Joi.string().allow(null),
trackChanges: Joi.boolean(),
},
team: {
global: Joi.boolean().allow(null),
},
}
......@@ -152,11 +152,12 @@
]
},
"scripts": {
"setupdb": "pubsweet setupdb ./",
"setupdb": "pubsweet setupdb && npm run seed",
"start": "pubsweet start",
"server": "pubsweet start",
"resetdb": "pubsweet setupdb --clobber ./",
"resetdb": "pubsweet setupdb --clobber && npm run seed",
"start:services": "docker-compose up postgres",
"seed": "node ./scripts/seedGlobalTeams.js",
"test": "NODE_ENV=test jest",
"test:watch": "NODE_ENV=test jest --watch",
"test:cover": "NODE_ENV=test jest --coverage",
......
#!/usr/bin/env node
const logger = require('@pubsweet/logger')
const { Team } = require('pubsweet-server/src/models')
const makeTeam = async type => {
const names = {
productionEditor: 'Production Editor',
author: 'Author',
}
logger.info(`Create ${names[type]} team`)
const team = new Team({
global: true,
members: [],
name: names[type],
teamType: type,
})
await team.save()
logger.info(`${names[type]} team successfully created`)
}
const seed = async () => {
logger.info('### RUNNING GLOBAL TEAMS SEED SCRIPTS ###')
logger.info('=> Checking if global teams exist...')
try {
const teams = await Team.findByField({ global: true })
const editorsTeam = teams.find(t => t.teamType === 'productionEditor')
const scienceOfficersTeam = teams.find(t => t.teamType === 'author')
if (editorsTeam && scienceOfficersTeam) {
logger.info('All global teams found, exiting...')
} else {
if (!editorsTeam) {
logger.warn('No Production Editor team found')
await makeTeam('productionEditor')
} else {
logger.info('Production Editor team already exists')
}
if (!scienceOfficersTeam) {
logger.warn('No Author team found')
await makeTeam('author')
} else {
logger.info('Author team already exists')
}
}
} catch (err) {
logger.warn('No global teams found')
await makeTeam('productionEditor')
await makeTeam('author')
}
logger.info('Team seed successfully finished')
}
seed()
{
"name": "pubsweet-editoria-authsome",
"version": "1.0.1",
"description": "Authsome mode for Editoria",
"name": "pubsweet-editoria-booksprints-authsome",
"version": "1.0.0",
"description": "Authsome mode for Editoria Book Sprints",
"main": "src/index.js",
"scripts": {
"test": "jest",
......
This diff is collapsed.
module.exports = {
frontend: {
components: [() => require('./src/GlobalTeamsManager')],
},
}
{
"name": "pubsweet-component-booksprints-globalteams",
"version": "0.1.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"pubsweet-component",
"pubsweet-client"
],
"author": "",
"license": "ISC",
"dependencies": {
"classnames": "^2.2.5",
"config": "^1.27.0",
"editoria-common": "^0.1.1",
"font-awesome": "4.7.0",
"formik": "^0.11.11",
"styled-components": "^3.3.0",
"lodash": "4.17.4",
"pubsweet-client": "^2.5.5",
"react-select": "^2.0.0",
"react": "^16.2.0",
"react-dom": "^16.2.0",
"react-redux": "5.0.4",
"react-router-dom": "4.2.2",
"redux": "3.7.2"
},
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-preset-env": "^1.6.0",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-2": "^6.24.1",
"enzyme": "^2.9.1",
"enzyme-to-json": "^1.5.1",
"file-loader": "^0.11.2",
"identity-obj-proxy": "^3.0.0",
"jest": "^20.0.4",
"node-sass": "^4.5.3",
"prop-types": "^15.5.10",
"react-addons-test-utils": "^15.6.0",
"react-styleguidist": "^6.0.24",
"react-test-renderer": "^15.6.1",
"sass-loader": "^6.0.6",
"sinon": "^2.3.6",
"sinon-as-promised": "^4.0.3",
"webpack": "^2.7.0",
"webpack-node-externals": "^1.6.0"
}
}
/* eslint-disable react/prop-types */
import styled from 'styled-components'
import { Form, Formik } from 'formik'
import React, { Component } from 'react'
import Select from 'react-select'
import { sortBy, keys } from 'lodash'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
// TODO -- clean up this import
import Actions from 'pubsweet-client/src/actions'
const TeamHeadingWrapper = styled.h4`
border-bottom: 1px solid black;
font-size: 24px;
line-height: 28px;
margin: 0;
`
const TeamSectionWrapper = styled.div`
padding: calc(8px * 2) 0;
`
const Ribbon = styled.div`
background: green;
border-radius: 3px;
color: #fff;
font-size: 14px;
line-height: 16px;
padding: calc(8px / 2) 0;
margin-top: 8px;
text-align: center;
visibility: ${props => (props.hide ? 'hidden' : 'visible')};
width: 60%;
`
const ButtonWrapper = styled.div`
padding: calc(8px * 2) 0;
`
const StyledSelect = styled(Select)`
margin-top: 8px;
outline: none;
> div:first-of-type {
border-radius: 0;
border: 1px solid black;
box-shadow: none;
&:hover {
border-color: #0b65cb;
}
> div > div > div:last-child {
&:hover {
background: #ff2d1a;
color: #ff2d1a;
}
}
}
`
const PageHeading = styled.h2`
margin: 0;
padding: 0 calc(8px * 2);
`
const PageWrapper = styled.div`
align-items: center;
display: flex;
flex-direction: column;
form {
width: 60%;
}
`
const TeamHeading = props => {
const { name } = props
return <TeamHeadingWrapper>{name}</TeamHeadingWrapper>
}
const TeamSection = props => {
const { name, setFieldValue, type, users, value } = props
const options = users
? users.map(user => ({
label: user.username,
value: user.id,
}))
: []
const selectValue = value.map(userId => {
const user = users.find(u => u.id === userId)
if (user) {
return {
label: user.username,
value: userId,
}
}
return userId
})
const handleChange = newValue => {
setFieldValue(type, newValue)
}
return (
<TeamSectionWrapper>
<TeamHeading name={name} />
<StyledSelect
closeMenuOnSelect={false}
isMulti
name={type}
onChange={handleChange}
options={options}
value={selectValue}
/>
</TeamSectionWrapper>
)
}
const TeamManagerForm = props => {
const { setFieldValue, teams, users, values } = props
return (
<Form>
{teams.map(team => (
<TeamSection
key={team.id}
name={team.name}
setFieldValue={setFieldValue}
type={team.teamType}
users={users}
value={values[team.teamType]}
/>
))}
<ButtonWrapper>
<button disabled={!props.dirty} primary type="submit">
Save
</button>
</ButtonWrapper>
</Form>
)
}
class GlobalTeamsManager extends Component {
constructor(props) {
super(props)
this.state = {
hideRibbon: true,
ready: false,
}
}
componentWillMount() {
const { getUsers, getTeams } = this.props.actions
Promise.all([getUsers(), getTeams()]).then(values => {
this.setState({ ready: true })
})
}
handleSubmit = (formValues, formikBag) => {
const { teams, actions } = this.props
const { updateTeam } = actions
const data = keys(formValues).map(teamType => ({
id: teams.find(t => t.teamType === teamType && t.global).id,
members: formValues[teamType].map(item => {
if (item.id) return item.id
return item.value
}),
}))
const promises = data.map(team => updateTeam(team))
Promise.all(promises).then(res => {
this.showRibbon()
formikBag.resetForm(formValues)
})
}
// TODO -- handle better cases like many quick saves
showRibbon = () => {
this.setState({
hideRibbon: false,
})
setTimeout(
() =>
this.setState({
hideRibbon: true,
}),
4000,
)
}
render() {
const { users, teams } = this.props
const { hideRibbon, ready } = this.state
if (!ready) return null
let globalTeams = teams.filter(team => team.global)
const infoMessage = 'Your teams have been successfully updated'
const initialValues = {}
globalTeams.forEach(team => {
initialValues[team.teamType] = team.members
})
globalTeams = sortBy(globalTeams, 'name')
return (
<PageWrapper>
<PageHeading>Team Manager</PageHeading>
<Ribbon hide={hideRibbon}>{infoMessage}</Ribbon>
<Formik
initialValues={initialValues}
onSubmit={this.handleSubmit}
render={formikProps => (
<TeamManagerForm
teams={globalTeams}
users={users}
{...formikProps}
/>
)}
/>
</PageWrapper>
)
}
}
GlobalTeamsManager.defaultProps = {
teams: null,
users: null,
}
function mapStateToProps(state, { match }) {
const { users, teams } = state
return {
users: users.users,
teams,
}
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(Actions, dispatch),
}
}
export default connect(
mapStateToProps,
mapDispatchToProps,
)(GlobalTeamsManager)
import React, { Component } from 'react'
import Select from 'react-select'
import { sortBy, key } from 'lodash'
// import PropTypes from 'prop-types'
import { bindActionCreators } from 'redux'
// import Authorize from 'pubsweet-client/src/helpers/Authorize'
import { connect } from 'react-redux'
// TODO -- clean up this import
import Actions from 'pubsweet-client/src/actions'
// const options = [
// { value: 'chocolate', label: 'Chocolate' },
// { value: 'strawberry', label: 'Strawberry' },
// { value: 'vanilla', label: 'Vanilla' },
// ]
const TeamHeading = props => {
const { name, type } = props
return <label htmlFor={type}>{name}</label>
}
const TeamSection = props => {
const { name, setFieldValue, type, users, value } = props
// console.log(props)
const options = users
? users.map(user => ({
label: user.username,
value: user.id,
}))
: []
const selectValue = value.map(user => {
if (!user.label && !user.value)
return {
label: user.username,
value: user.id,
}
return user
})
const handleChange = newValue => {
// console.log('here: new val', newValue)
// setFieldValue(type, newValue)
}
return (
<div>
<TeamHeading name={name} type={type} />
<Select
id={type}
isMulti
onChange={this.handleChange}
options={options}
value={selectValue}
/>
</div>
)
}
const TeamManagerForm = props => {
const { setFieldValue, teams, users, values } = props
// console.log(props)
const handleUpdate = (e) => {
e.preventDefault()
console.log(e)
}
return (
<form>
{teams.map(team => (
<TeamSection
key={team.id}
name={team.name}
setFieldValue={setFieldValue}
type={team.teamType}
users={users}
value={values[team.teamType]}
/>
))}
<button onSubmit={handleUpdate} type="submit">
Save
</button>
</form>
)
}
class GlobalTeamsManager extends Component {
state = {
selectedOption: null,
ready: false,
}
componentWillMount() {
const { getUsers, getTeams } = this.props.actions
Promise.all([getUsers(), getTeams()]).then(values => {
this.setState({ ready: true })
})
}
componentDidMount() {}
handleChange = selectedOption => {
this.setState({ selectedOption })
console.log(`Option selected:`, selectedOption)
}
render() {
const { selectedOption, ready } = this.state
console.log('props', this.props)
const { users, teams } = this.props
// let options
if (!ready) return null
const infoMessage = 'Your teams have been successfully updated'
const initialValues = {}
let globalTeams = teams.filter(team => team.global)
globalTeams.forEach(team => {
initialValues[team.teamType] = team.members
})
globalTeams = sortBy(globalTeams, 'name')
return (
<div>
<h1>Global Teams</h1>
<TeamManagerForm teams={globalTeams} users={users} values={initialValues} />
</div>
)
}
}
GlobalTeamsManager.defaultProps = {
teams: null,
users: null,
}
function mapStateToProps(state, { match }) {
const { users, teams } = state
return {
users: users.users,
teams,
}
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(Actions, dispatch),
}
}
export default connect(
mapStateToProps,
mapDispatchToProps,
)(GlobalTeamsManager)
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment