diff --git a/locales/en/translations.json b/locales/en/translations.json index 8cb141d860e40d6961486406f8a6ffa0aa00b5af..440912e8f1701c7ad85c9944dd9528620cb1618c 100644 --- a/locales/en/translations.json +++ b/locales/en/translations.json @@ -591,6 +591,12 @@ "DIGITIZER": "Data digitizer", "CURATOR": "Data curator", "null": "Not specified" + }, + "roledesc": { + "MANAGER": "Responsible of the planning and execution of the germplasm characterization and evaluation activity which resulted in the dataset.\n Oversees the collection and management of characterization and evaluation data, and has final sign-off on publication.", + "COLLECTOR": "Records germplasm characterization or evaluation data in the field.", + "DIGITIZER": "Digitizes data.", + "CURATOR": "Organizes and validates data and metadata in correct format, ensures quality of both." } } }, @@ -603,6 +609,9 @@ "label": "Dataset title", "placeholder": "Name given to the dataset (e.g., Characterization of maize accessions in Kenya)" }, + "rights": { + "label": "Rights" + }, "partner": { "label": "Select Data provider", "placeholder": "Data provider" diff --git a/src/crops/ui/c/CropSelector.tsx b/src/crops/ui/c/CropSelector.tsx deleted file mode 100644 index 705fe08d347b578d2467f64830a7848bbca33e98..0000000000000000000000000000000000000000 --- a/src/crops/ui/c/CropSelector.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import * as React from 'react'; -import { connect } from 'react-redux'; -import { translate } from 'react-i18next'; - -import Grid from '@material-ui/core/Grid'; -import FormControlLabel from '@material-ui/core/FormControlLabel'; -import FormLabel from '@material-ui/core/FormLabel'; -import FormControl from '@material-ui/core/FormControl'; -import FormHelperText from '@material-ui/core/FormHelperText'; -import Checkbox from '@material-ui/core/Checkbox'; -import Radio from '@material-ui/core/Radio'; - -import Crop from 'model/genesys/Crop'; - -interface ICropSelectorProps extends React.ClassAttributes { - t: any; - crops: Crop[]; - fields?: any; - label: string; - input?: any; - single?: boolean; -} - -const handleCheckboxChange = (fields, code) => () => { - const index = fields.getAll() ? fields.getAll().indexOf(code) : -1; - - if (index === -1) { - fields.push(code); - } else { - fields.remove(index); - } -}; - -const handleRadioButtonChange = (input, code) => () => { - input.onChange(code); -}; - -const renderCheckbox = (fields, code) => ( - -); - -const renderRadioButton = (input, code) => ( - -); - -const CropSelector = ({t, crops, label, single, fields, input}: ICropSelectorProps) => crops && ( - - { label } - { t('crop.public.c.cropSelector.helper') } - - { - crops.sort((a, b) => a.name.localeCompare(b.name)).map((crop: Crop) => ( - - - - )) - } - - -); - - -const mapStateToProps = (state) => ({ - crops: state.crop.list, -}); - - -export default connect(mapStateToProps, null)(translate()(CropSelector)); diff --git a/src/datasets/translations.json b/src/datasets/translations.json index c81afe8fa3e4376f5d87b719dd9b37b3b3c0d302..339d532b22acf12a31cc29202a048c4c64124bc6 100644 --- a/src/datasets/translations.json +++ b/src/datasets/translations.json @@ -11,6 +11,12 @@ "DIGITIZER": "Data digitizer", "CURATOR": "Data curator", "null": "Not specified" + }, + "roledesc": { + "MANAGER": "Responsible of the planning and execution of the germplasm characterization and evaluation activity which resulted in the dataset.\n Oversees the collection and management of characterization and evaluation data, and has final sign-off on publication.", + "COLLECTOR": "Records germplasm characterization or evaluation data in the field.", + "DIGITIZER": "Digitizes data.", + "CURATOR": "Organizes and validates data and metadata in correct format, ensures quality of both." } } }, @@ -23,6 +29,9 @@ "label": "Dataset title", "placeholder": "Name given to the dataset (e.g., Characterization of maize accessions in Kenya)" }, + "rights": { + "label": "Rights" + }, "partner": { "label": "Select Data provider", "placeholder": "Data provider" diff --git a/src/datasets/ui/dataset-stepper/steps/basic-info/BasicInfoForm.tsx b/src/datasets/ui/dataset-stepper/steps/basic-info/BasicInfoForm.tsx index 039751e3f6d8157309239c68132e4cfeddafa058..a9ea07c48a3a91078c0ea711c02db11dd9d6ce62 100644 --- a/src/datasets/ui/dataset-stepper/steps/basic-info/BasicInfoForm.tsx +++ b/src/datasets/ui/dataset-stepper/steps/basic-info/BasicInfoForm.tsx @@ -4,30 +4,43 @@ import { translate } from 'react-i18next'; import {DATASET_BASIC_INFO_FORM} from 'datasets/constants'; +import { AVAILABLE_LICENSES } from 'model/License'; +import Crop from 'model/genesys/Crop'; + import {TextField} from 'ui/common/text-field'; import {MarkdownField} from 'ui/catalog/markdown'; import SelectPartner from 'partners/ui/c/SelectPartner'; -import CropSelector from 'crops/ui/c/CropSelector'; import Validators from 'utilities/Validators'; -import BasicInfoRadioGroup from './LicenceSelector'; import remoteSubmit from './RemoteSubmit'; import VocabularyTermPicker from 'vocabulary/ui/c/VocabularyTermPicker'; +import RadioSelection from 'ui/common/forms/RadioSelection'; +import { ExternalLink } from 'ui/catalog/Links'; +import CheckboxSelection from 'ui/common/forms/CheckboxSelection'; interface ILoginContainerProps extends React.ClassAttributes { handleSubmit: () => void; initialValues: any; classes: any; + crops: Crop[]; uuid: string; t: any; } +const renderLicenseLabel = (license) => ( +
{ license.code } { license.title } + { license.url && +
{ license.url }
+ } +
+); + class BasicInfoStep extends React.Component { public render() { - const {initialValues, handleSubmit, t} = this.props; + const {initialValues, crops, handleSubmit, t} = this.props; return (
@@ -70,7 +83,12 @@ class BasicInfoStep extends React.Component { /> { /> crop.name } + formLabel={ t('datasets.dashboard.p.stepper.basicInfo.crops.label') } /> ); diff --git a/src/datasets/ui/dataset-stepper/steps/basic-info/LicenceSelector.tsx b/src/datasets/ui/dataset-stepper/steps/basic-info/LicenceSelector.tsx deleted file mode 100644 index 0d6ad5c35cf70ad9a00af19249b8bba270a37d06..0000000000000000000000000000000000000000 --- a/src/datasets/ui/dataset-stepper/steps/basic-info/LicenceSelector.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import * as React from 'react'; - -import FormControlLabel from '@material-ui/core/FormControlLabel'; -import FormLabel from '@material-ui/core/FormLabel'; -import FormControl from '@material-ui/core/FormControl'; -import Radio from '@material-ui/core/Radio'; -import RadioGroup from '@material-ui/core/RadioGroup'; -import { withStyles } from '@material-ui/core/styles'; -import { AVAILABLE_LICENSES } from 'model/License'; -import { ExternalLink } from 'ui/catalog/Links'; - -const styles = { - // None -}; - -const LicenceSelector = ({input, meta, classes, ...rest}) => ( - - Rights - input.onChange(value) // tslint:disable-line - } - > - { - AVAILABLE_LICENSES.map((license) => ( - { license.code } { license.title } - { license.url && -
{ license.url }
- } - - ) } - control={ } - /> - )) - } -
-
-); - -export default withStyles(styles)(LicenceSelector); diff --git a/src/datasets/ui/dataset-stepper/steps/basic-info/index.tsx b/src/datasets/ui/dataset-stepper/steps/basic-info/index.tsx index 4b9770d15a270c5888b99ea8e187bab02dde7ff3..74a5ecdb5bd3a807af50d95d4ed5f9df2c8aeb51 100644 --- a/src/datasets/ui/dataset-stepper/steps/basic-info/index.tsx +++ b/src/datasets/ui/dataset-stepper/steps/basic-info/index.tsx @@ -7,6 +7,7 @@ import BasicInfoForm from './BasicInfoForm'; import Dataset from 'model/catalog/Dataset'; import {loadMyPartners} from 'partners/actions/dashboard'; +import { listCrops } from 'actions/crop'; import Partner from 'model/genesys/Partner'; import Crop from 'model/genesys/Crop'; import {submit, isInvalid} from 'redux-form'; @@ -19,6 +20,7 @@ interface IDatasetProps extends React.ClassAttributes { dataset: Dataset; saveDataset: (dataset: Dataset) => Promise; + listCrops: any; loadMyPartners: any; myPartners: Partner[]; crops: Crop[]; @@ -38,12 +40,14 @@ class BasicInfoStep extends React.Component { ]; public componentWillMount() { - const {myPartners, loadMyPartners} = this.props; - + const {myPartners, loadMyPartners, crops, listCrops} = this.props; if (!myPartners || myPartners.length === 0) { loadMyPartners(); } - } + if (! crops || crops.length === 0) { + listCrops(true); + } + } protected gotoStep = (id) => () => { const { submit, onGotoStep } = this.props; @@ -53,7 +57,7 @@ class BasicInfoStep extends React.Component { } public render() { - const {myPartners, dataset, location, stillLoading, onDelete, onPublish, isInvalidForm} = this.props; + const {myPartners, crops, dataset, location, stillLoading, onDelete, onPublish, isInvalidForm} = this.props; return ( { ); @@ -70,7 +75,9 @@ class BasicInfoStep extends React.Component { const mapStateToProps = (state, ownProps) => ({ dataset: state.datasets.dashboard.dataset, + crops: state.crop.list, myPartners: state.partner.dashboard.myPartners, + crop: state.crop.list, stillLoading: ownProps.stillLoading, location: ownProps.location, onDelete: ownProps.onDelete, @@ -81,6 +88,7 @@ const mapStateToProps = (state, ownProps) => ({ const mapDispatchToProps = (dispatch) => bindActionCreators({ loadMyPartners, + listCrops, submit, }, dispatch); diff --git a/src/datasets/ui/dataset-stepper/steps/creators/DatasetCreatorForm.tsx b/src/datasets/ui/dataset-stepper/steps/creators/DatasetCreatorForm.tsx index ddc487b1d9fe3585aedff4d1f04677dd3fc372a0..b9489c6548845122627e3a3e39f6a76806b0a6ad 100644 --- a/src/datasets/ui/dataset-stepper/steps/creators/DatasetCreatorForm.tsx +++ b/src/datasets/ui/dataset-stepper/steps/creators/DatasetCreatorForm.tsx @@ -7,11 +7,6 @@ import Button from '@material-ui/core/Button'; import Grid from '@material-ui/core/Grid'; import IconButton from '@material-ui/core/IconButton'; import DeleteIcon from '@material-ui/icons/Delete'; -import Radio from '@material-ui/core/Radio'; -import RadioGroup from '@material-ui/core/RadioGroup'; -import FormControlLabel from '@material-ui/core/FormControlLabel'; -import FormLabel from '@material-ui/core/FormLabel'; -import FormControl from 'ui/common/forms/FormControl'; import Validators from 'utilities/Validators'; import {log} from 'utilities/debug'; @@ -20,6 +15,7 @@ import {TextField} from 'ui/common/text-field'; import {DATASET_CREATOR_FORM} from 'datasets/constants'; import Dataset from 'model/catalog/Dataset'; import DatasetCreator, { CreatorRole} from 'model/catalog/DatasetCreator'; +import RadioSelection from 'ui/common/forms/RadioSelection'; interface IDatasetCreatorFormProps extends React.ClassAttributes { t: any; @@ -42,25 +38,7 @@ const styles = (theme) => ({ } }); /* tslint:enable */ -const renderRadioGroup = translate()(({input, meta, t, classes}) => { - const onInputChange = (event, value) => input.onChange(value); - - return ( - - { t('datasets.dashboard.p.stepper.creators.role') } - - { Object.keys(CreatorRole).map((role) => ( - } /> - )) } - - - ); -}); + class DatasetCreatorForm extends React.Component { @@ -73,6 +51,16 @@ class DatasetCreatorForm extends React.Component this.props.deleteCreatorRequest(this.props.dataset.uuid, fields.get(index)); } + + private renderRoleLabel = (role) => ( +
+ { this.props.t(`datasets.common.creator.role.${role}`) } +
+

{ this.props.t(`datasets.common.creator.roledesc.${role}`) }

+
+
+ ) + public renderCreators = ({ classes, fields, meta: { touched, error, submitFailed } }) => { const { t } = this.props; @@ -94,7 +82,11 @@ class DatasetCreatorForm extends React.Component /> { public render() { - const {error, handleSubmit, initialValues, partners, t} = this.props; + const {error, handleSubmit, initialValues, partners, crops, t} = this.props; return (
{ initialValues && initialValues.version &&
Version: { initialValues.version }
} @@ -56,8 +56,10 @@ class DescriptorListForm extends React.Component { crop.name } /> { loadDescriptorList: any; saveDescriptorList: any; loadMyPartners: any; + listCrops: any; + crops: Crop[]; myPartners: Partner[]; stillLoading: boolean; onDelete: () => void; @@ -36,10 +40,13 @@ class BasicInfoStep extends React.Component { ]; public componentWillMount() { - const {myPartners, loadMyPartners} = this.props; + const {myPartners, loadMyPartners, crops, listCrops} = this.props; if (! myPartners || myPartners.length === 0) { loadMyPartners(); } + if (! crops || crops.length === 0) { + listCrops(true); + } } protected gotoStep = (id) => () => { @@ -49,7 +56,7 @@ class BasicInfoStep extends React.Component { } public render() { - const {myPartners, stillLoading, onDelete, onPublish, isInvalidForm, location} = this.props; + const {myPartners, crops, stillLoading, onDelete, onPublish, isInvalidForm, location} = this.props; let {descriptorList} = this.props; if (! descriptorList) { @@ -63,6 +70,7 @@ class BasicInfoStep extends React.Component { ); @@ -71,6 +79,7 @@ class BasicInfoStep extends React.Component { const mapStateToProps = (state, ownProps) => ({ myPartners: state.partner.dashboard.myPartners, + crops: state.crop.list, descriptorList: state.descriptorList.dashboard.descriptorList, location: ownProps.location, onDelete: ownProps.onDelete, @@ -82,6 +91,7 @@ const mapStateToProps = (state, ownProps) => ({ const mapDispatchToProps = (dispatch) => bindActionCreators({ saveDescriptorList, loadMyPartners, + listCrops, loadDescriptorList, submit, }, dispatch); diff --git a/src/descriptors/ui/c/DescriptorForm.tsx b/src/descriptors/ui/c/DescriptorForm.tsx index 004ae1b19a0d8bf50857a8157754d645694d534f..e7d7f1460fd6b64791dc26d53b1b012fe9deff50 100644 --- a/src/descriptors/ui/c/DescriptorForm.tsx +++ b/src/descriptors/ui/c/DescriptorForm.tsx @@ -9,6 +9,7 @@ import {DESCRIPTOR_FORM} from 'descriptors/constants'; import ItemsEditor from 'ui/common/ItemsEditor'; import VocabularyTerm from 'model/vocabulary/VocabularyTerm'; +import Descriptor from 'model/catalog/Descriptor'; import Validators from 'utilities/Validators'; import { TextField } from 'ui/common/text-field'; @@ -18,16 +19,12 @@ import SelectPartner from 'partners/ui/c/SelectPartner'; import SelectVocabulary from './SelectVocabulary'; import Button from '@material-ui/core/Button'; -import Radio from '@material-ui/core/Radio'; -import RadioGroup from '@material-ui/core/RadioGroup'; -import { Toggle, FormControl } from 'ui/common/forms'; -import FormLabel from '@material-ui/core/FormLabel'; -import FormControlLabel from '@material-ui/core/FormControlLabel'; +import { Toggle } from 'ui/common/forms'; import Grid from '@material-ui/core/Grid'; import { setPageTitle } from 'actions/pageTitle'; import { bindActionCreators } from 'redux'; -import CropSelector from 'crops/ui/c/CropSelector'; +import RadioSelection from 'ui/common/forms/RadioSelection'; import withStyles from '@material-ui/core/styles/withStyles'; /* tslint:disable */ @@ -42,53 +39,6 @@ const styles = (theme) => ({ }); /* tslint:enable */ -// FIXME Use Descriptor.DATATYPES -const renderDataTypeRadioGroup = ({input, meta, classes, t, ...rest}) => ( - - { t(`descriptors.admin.c.form.dataType`) } - input.onChange(value) // tslint:disable-line - } - className={ classes.RadioGrid } - > - }/> - }/> - }/> - }/> - }/> - }/> - - -); - -// FIXME Use Descriptor.CATEGORIES -const renderCategoryRadioGroup = ({input, meta, classes, t, ...rest}) => ( - - { t(`descriptors.admin.c.form.descriptorCategory`) } - input.onChange(value) // tslint:disable-line - } - className={ classes.RadioGrid } - > - }/> - }/> - }/> - }/> - }/> - }/> - }/> - }/> - - -); class DescriptorForm extends React.Component { @@ -124,7 +74,7 @@ class DescriptorForm extends React.Component { } public render() { - const {error, handleSubmit, initialValues, pageTitle, onPublish, invalid, submitting, anyTouched, currentOwner, currentVocabulary, classes, t} = this.props; + const {crops, error, handleSubmit, initialValues, pageTitle, onPublish, invalid, submitting, anyTouched, currentOwner, currentVocabulary, classes, t} = this.props; if (! initialValues) { return null; @@ -167,8 +117,10 @@ class DescriptorForm extends React.Component { /> crop.name } /> { /> t(Descriptor.CATEGORIES[option]) } t={ t } validate={ [ Validators.required ] } /> @@ -216,7 +170,9 @@ class DescriptorForm extends React.Component { /> t(Descriptor.DATATYPES[option]) } t={ t } validate={ [ Validators.required ] } /> @@ -271,6 +227,7 @@ class DescriptorForm extends React.Component { const selector = formValueSelector(DESCRIPTOR_FORM); const mapStateToProps = (state, ownProps) => ({ + crops: state.crop.list, dataType: selector(state, 'dataType'), currentTerms: selector(state, 'terms'), currentOwner: selector(state, 'owner'), diff --git a/src/model/catalog/Descriptor.ts b/src/model/catalog/Descriptor.ts index e9e642e7b380be5311627921135e848165b9d9d5..78705f554dcd34a44e7d8c39ab2daf67c25aba92 100644 --- a/src/model/catalog/Descriptor.ts +++ b/src/model/catalog/Descriptor.ts @@ -54,12 +54,12 @@ export default class Descriptor implements IUserPermissions { }; public static DATATYPES: { [key: string]: any; } = { - TEXT: 'descriptors.common.category.TEXT', - BOOLEAN: 'Yes/No', - DATE: 'Date', - CODED: 'Controlled vocabulary', - NUMERIC: 'Numeric', - SCALE: 'Scale', + TEXT: 'descriptors.common.dataType.text', + BOOLEAN: 'descriptors.common.dataType.boolean', + DATE: 'descriptors.common.dataType.date', + CODED: 'descriptors.common.dataType.coded', + NUMERIC: 'descriptors.common.dataType.numeric', + SCALE: 'descriptors.common.dataType.scale', }; public static CATEGORIES: { [key: string]: any; } = { diff --git a/src/ui/common/forms/CheckboxSelection.tsx b/src/ui/common/forms/CheckboxSelection.tsx new file mode 100644 index 0000000000000000000000000000000000000000..60e5d738c3445cc5ff00b24c8611022adb53915b --- /dev/null +++ b/src/ui/common/forms/CheckboxSelection.tsx @@ -0,0 +1,73 @@ +import * as React from 'react'; +import { translate } from 'react-i18next'; + +import FormControlLabel from '@material-ui/core/FormControlLabel'; +import FormLabel from '@material-ui/core/FormLabel'; +import FormControl from '@material-ui/core/FormControl'; +import RadioGroup from '@material-ui/core/RadioGroup'; +import { withStyles } from '@material-ui/core/styles'; +import Checkbox from '@material-ui/core/Checkbox'; + +/* tslint:disable */ +const styles = (theme) =>({ + radioGroupMultiColumn: { + flexDirection: 'row' as 'row', + justifyContent: 'space-between' as 'space-between', + '& > label': { + flexBasis: '12%', + [theme.breakpoints.down('lg')]: { + flexBasis: '24%', + }, + [theme.breakpoints.down('md')]: { + flexBasis: '32%', + }, + [theme.breakpoints.down('sm')]: { + flexBasis: '45%', + }, + [theme.breakpoints.down('xs')]: { + flexBasis: '100%', + }, + }, + }, +}); +/* tslint:enable */ + +const handleCheckboxChange = (fields, code) => { + const index = fields.getAll() ? fields.getAll().indexOf(code) : -1; + + if (index === -1) { + fields.push(code); + } else { + fields.remove(index); + } +}; + +const CheckboxSelection = ({formLabel, singleColumn = false, options, renderOptionLabel, valueField, fields, input, meta, classes, t, ...rest}) => ( + + { formLabel } + + { options && options.length > 0 && + options.map((option, i) => ( + handleCheckboxChange(fields,valueField ? option[valueField] : option) } // tslint:disable-line + /> + } + className={ classes.label } + /> + )) + } + + +); + +export default withStyles(styles)(translate()(CheckboxSelection)); diff --git a/src/ui/common/forms/RadioSelection.tsx b/src/ui/common/forms/RadioSelection.tsx new file mode 100644 index 0000000000000000000000000000000000000000..be4a43d30baca3dd375c4ac0c3eafa9d91ff6b99 --- /dev/null +++ b/src/ui/common/forms/RadioSelection.tsx @@ -0,0 +1,59 @@ +import * as React from 'react'; +import { translate } from 'react-i18next'; + +import FormControlLabel from '@material-ui/core/FormControlLabel'; +import FormLabel from '@material-ui/core/FormLabel'; +import FormControl from '@material-ui/core/FormControl'; +import Radio from '@material-ui/core/Radio'; +import RadioGroup from '@material-ui/core/RadioGroup'; +import { withStyles } from '@material-ui/core/styles'; + +/* tslint:disable */ +const styles = (theme) =>({ + radioGroupMultiColumn: { + flexDirection: 'row' as 'row', + justifyContent: 'space-evenly' as 'space-evenly', + '& > label': { + flexBasis: '12%', + [theme.breakpoints.down('md')]: { + flexBasis: '24%', + }, + [theme.breakpoints.down('sm')]: { + flexBasis: '45%', + }, + [theme.breakpoints.down('xs')]: { + flexBasis: '100%', + }, + }, + }, +}); +/* tslint:enable */ + +const RadioSelection = ({formLabel, singleColumn = false, options, renderOptionLabel, valueField, input, meta, classes, t, ...rest}) => ( + + { formLabel } + input.onChange(value) // tslint:disable-line + } + className={ singleColumn ? classes.radioGroupSingleColumn : classes.radioGroupMultiColumn } + > + { options && options.length > 0 && + options.map((option, i) => ( + } + className={ classes.label } + /> + )) + } + + +); + +export default withStyles(styles)(translate()(RadioSelection));