Commit 21cda7d6 authored by Viacheslav Pavlov's avatar Viacheslav Pavlov Committed by Matija Obreza

custom CheckBox/Radio selectors replaced by generic versions

 - see genesys-pgr/catalog/genesys-catalog-ui#404
parent a5a2c52b
......@@ -566,6 +566,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"
......
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<any> {
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) => (
<Checkbox
checked={ fields.getAll() && fields.getAll().indexOf(code) !== -1 }
onChange={ handleCheckboxChange(fields, code) }
value={ code }
/>
);
const renderRadioButton = (input, code) => (
<Radio
checked={ input.value === code }
onChange={ handleRadioButtonChange(input, code) }
value={ code }
/>
);
const CropSelector = ({t, crops, label, single, fields, input}: ICropSelectorProps) => crops && (
<FormControl fullWidth>
<FormLabel>{ label }</FormLabel>
<FormHelperText>{ t('crop.public.c.cropSelector.helper') }</FormHelperText>
<Grid container>
{
crops.sort((a, b) => a.name.localeCompare(b.name)).map((crop: Crop) => (
<Grid item key={ crop.shortName } xs={ 6 } md={ 4 } lg={ 3 } xl={ 2 }>
<FormControlLabel
control={
single ? renderRadioButton(input, crop.shortName)
: renderCheckbox(fields, crop.shortName)
}
label={ crop.name }
/>
</Grid>
))
}
</Grid>
</FormControl>
);
const mapStateToProps = (state) => ({
crops: state.crop.public.list,
});
export default connect(mapStateToProps, null)(translate()(CropSelector));
......@@ -31,6 +31,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"
......
......@@ -5,30 +5,43 @@ import { translate } from 'react-i18next';
import { saveDataset } from 'datasets/actions/editor';
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/common/markdown';
import SelectPartner from 'partners/ui/c/SelectPartner';
import CropSelector from 'crop/ui/c/CropSelector';
import Validators from 'utilities/Validators';
import LicenseSelector from 'ui/genesys/LicenseSelector';
import RadioSelection from 'ui/common/forms/RadioSelection';
import { ExternalLink } from 'ui/catalog/Links';
import CheckboxSelection from 'ui/common/forms/CheckboxSelection';
import VocabularyTermPicker from 'vocabulary/ui/c/VocabularyTermPicker';
interface ILoginContainerProps extends React.ClassAttributes<any> {
handleSubmit: () => void;
initialValues: any;
classes: any;
crops: Crop[];
uuid: string;
t: any;
}
const renderLicenseLabel = (license) => (
<div><b>{ license.code }</b> { license.title }
{ license.url &&
<div><ExternalLink link={ license.url }>{ license.url }</ExternalLink></div>
}
</div>
);
class BasicInfoStep extends React.Component<ILoginContainerProps, any> {
public render() {
const { initialValues, handleSubmit, t } = this.props;
const { initialValues, crops, handleSubmit, t } = this.props;
return (
<form onSubmit={ handleSubmit } className="p-20 m-20 even-row">
......@@ -71,7 +84,12 @@ class BasicInfoStep extends React.Component<ILoginContainerProps, any> {
/>
<Field
name="rights"
component={ LicenseSelector }
component={ RadioSelection }
formLabel={ t('datasets.dashboard.p.stepper.basicInfo.rights.label') }
options={ AVAILABLE_LICENSES }
valueField="code"
renderOptionLabel={ renderLicenseLabel }
singleColumn
/>
<Field
name="language"
......@@ -89,8 +107,11 @@ class BasicInfoStep extends React.Component<ILoginContainerProps, any> {
/>
<FieldArray
name="crops"
component={ CropSelector }
label={ t('datasets.dashboard.p.stepper.basicInfo.crops.label') }
component={ CheckboxSelection }
options={ crops }
valueField="shortName"
renderOptionLabel={ (crop) => crop.name }
formLabel={ t('datasets.dashboard.p.stepper.basicInfo.crops.label') }
/>
</form>
);
......
......@@ -4,10 +4,12 @@ import { connect } from 'react-redux';
import { submit, isInvalid } from 'redux-form';
// actions
import { loadMyPartners } from 'partners/actions/dashboard';
import { loadCrops } from 'crop/actions/public';
// constants
import { DATASET_BASIC_INFO_FORM } from 'datasets/constants';
// models
import Partner from 'model/genesys/Partner';
import Crop from 'model/genesys/Crop';
// utilities
import { log } from 'utilities/debug';
// ui
......@@ -19,6 +21,8 @@ interface IDatasetProps extends React.ClassAttributes<any> {
loadMyPartners: any;
myPartners: Partner[];
submit: any;
loadCrops: any;
crops: Crop[];
}
class BasicInfoStep extends StepperTemplate<IDatasetProps> {
......@@ -30,24 +34,29 @@ class BasicInfoStep extends StepperTemplate<IDatasetProps> {
setTimeout(() => onGotoStep(id));
}
protected renderContent = () => (<BasicInfoForm initialValues={ this.props.item } partners={ this.props.myPartners }/>);
protected renderContent = () => (<BasicInfoForm initialValues={ this.props.item } partners={ this.props.myPartners } crops={ this.props.crops }/>);
public componentWillMount() {
const { myPartners, loadMyPartners } = this.props;
const {myPartners, loadMyPartners, crops, loadCrops} = this.props;
if (!myPartners || myPartners.length === 0) {
loadMyPartners();
}
if (! crops || crops.length === 0) {
loadCrops(true);
}
}
}
const mapStateToProps = (state, ownProps) => ({
crops: state.crop.public.list,
myPartners: state.partner.dashboard.myPartners,
isInvalidForm: isInvalid(DATASET_BASIC_INFO_FORM)(state),
});
const mapDispatchToProps = (dispatch) => bindActionCreators({
loadMyPartners,
loadCrops,
submit,
}, dispatch);
......
......@@ -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<any> {
t: any;
......@@ -42,25 +38,6 @@ const styles = (theme) => ({
}
});
/* tslint:enable */
const renderRadioGroup = translate()(({ input, meta, t, classes }) => {
const onInputChange = (event, value) => input.onChange(value);
return (
<FormControl fullWidth required meta={ meta }>
<FormLabel>{ t('datasets.dashboard.p.stepper.creators.role') }</FormLabel>
<RadioGroup
{ ...input }
value={ input.value }
onChange={ onInputChange }
className={ classes.RadioGrid }
>
{ Object.keys(CreatorRole).map((role) => (
<FormControlLabel key={ role } value={ role } label={ t(`datasets.common.creator.role.${role}`) } control={ <Radio/> }/>
)) }
</RadioGroup>
</FormControl>
);
});
class DatasetCreatorForm extends React.Component<IDatasetCreatorFormProps, any> {
......@@ -73,6 +50,15 @@ class DatasetCreatorForm extends React.Component<IDatasetCreatorFormProps, any>
this.props.deleteCreatorRequest(fields.get(index));
}
private renderRoleLabel = (role) => (
<div style={ {paddingTop: '6px', marginBottom: '-6px'} }>
<b style={ {fontSize: '14px'} }>{ this.props.t(`datasets.common.creator.role.${role}`) }</b>
<div>
<p style={ {whiteSpace: 'pre-line'} }>{ this.props.t(`datasets.common.creator.roledesc.${role}`) }</p>
</div>
</div>
)
public renderCreators = ({ classes, fields, meta: { touched, error, submitFailed } }) => {
const { t } = this.props;
......@@ -96,7 +82,11 @@ class DatasetCreatorForm extends React.Component<IDatasetCreatorFormProps, any>
<Field
required name={ `${creator}.role` }
classes={ classes }
component={ renderRadioGroup }
component={ RadioSelection }
options={ Object.keys(CreatorRole) }
formLabel={ t('datasets.dashboard.p.stepper.creators.role') }
renderOptionLabel={ this.renderRoleLabel }
singleColumn
/>
<Field
name={ `${creator}.institutionalAffiliation` }
......
......@@ -8,13 +8,13 @@ import { MarkdownField } from 'ui/common/markdown';
import Authorize from 'ui/common/authorized/Authorize';
import SelectPartner from 'partners/ui/c/SelectPartner';
import Validators from 'utilities/Validators';
import CropSelector from 'crop/ui/c/CropSelector';
import RadioSelection from 'ui/common/forms/RadioSelection';
import { saveDescriptorList } from 'descriptorlists/actions/editor';
class DescriptorListForm extends React.Component<any, any> {
public render() {
const { error, handleSubmit, initialValues, partners, t } = this.props;
const {error, handleSubmit, initialValues, partners, crops, t} = this.props;
return (
<form onSubmit={ handleSubmit } className="p-20 m-20 even-row">
{ initialValues && initialValues.version && <div>Version: { initialValues.version }</div> }
......@@ -58,8 +58,10 @@ class DescriptorListForm extends React.Component<any, any> {
name="crop"
label={ t('descriptorlists.public.common.crop') }
placeholder={ t('descriptorlists.public.c.form.maize') }
component={ CropSelector }
single
component={ RadioSelection }
options={ crops }
valueField="shortName"
renderOptionLabel={ (crop) => crop.name }
/>
<Field
required
......
......@@ -6,7 +6,9 @@ import DescriptorListForm from 'descriptorlists/ui/c/DescriptorListForm';
import { loadDescriptorList, saveDescriptorList } from 'descriptorlists/actions/editor';
import { loadMyPartners } from 'partners/actions/dashboard';
import { loadCrops } from 'crop/actions/public';
import Partner from 'model/genesys/Partner';
import Crop from 'model/genesys/Crop';
import { submit, isInvalid } from 'redux-form';
import { DESCRIPTORLIST_FORM } from 'descriptors/constants';
import StepperTemplate from 'ui/common/stepper/StepperTemplate';
......@@ -14,6 +16,8 @@ import StepperTemplate from 'ui/common/stepper/StepperTemplate';
interface IDescriptorListProps extends React.ClassAttributes<any> {
uuid: string;
loadMyPartners: any;
loadCrops: any;
crops: Crop[];
myPartners: Partner[];
isInvalidForm: boolean;
submit: any;
......@@ -34,25 +38,31 @@ class BasicInfoStep extends StepperTemplate<IDescriptorListProps> {
<DescriptorListForm
initialValues={ this.props.item }
partners={ this.props.myPartners }
crops={ this.props.crops }
/>
)
public componentWillMount() {
const { myPartners, loadMyPartners } = this.props;
const {myPartners, loadMyPartners, crops, loadCrops} = this.props;
if (!myPartners || myPartners.length === 0) {
loadMyPartners();
}
if (! crops || crops.length === 0) {
loadCrops(true);
}
}
}
const mapStateToProps = (state, ownProps) => ({
myPartners: state.partner.dashboard.myPartners,
crops: state.crop.list,
isInvalidForm: isInvalid(DESCRIPTORLIST_FORM)(state),
});
const mapDispatchToProps = (dispatch) => bindActionCreators({
saveDescriptorList,
loadMyPartners,
loadCrops,
loadDescriptorList,
submit,
}, dispatch);
......
......@@ -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 'crop/ui/c/CropSelector';
import RadioSelection from 'ui/common/forms/RadioSelection';
import withStyles from '@material-ui/core/styles/withStyles';
/* tslint:disable */
......@@ -42,69 +39,22 @@ const styles = (theme) => ({
});
/* tslint:enable */
// FIXME Use Descriptor.DATATYPES
const renderDataTypeRadioGroup = ({ input, meta, classes, t, ...rest }) => (
<FormControl required fullWidth>
<FormLabel>{ t(`descriptors.admin.c.form.dataType`) }</FormLabel>
<RadioGroup
{ ...input }
{ ...rest }
value={ input.value }
onChange={
(event, value) => input.onChange(value) // tslint:disable-line
}
className={ classes.RadioGrid }
>
<FormControlLabel value="TEXT" label={ t(`descriptors.common.dataType.text`) } control={ <Radio/> }/>
<FormControlLabel value="BOOLEAN" label={ t(`descriptors.common.dataType.boolean`) } control={ <Radio/> }/>
<FormControlLabel value="DATE" label={ t(`descriptors.common.dataType.date`) } control={ <Radio/> }/>
<FormControlLabel value="CODED" label={ t(`descriptors.common.dataType.coded`) } control={ <Radio/> }/>
<FormControlLabel value="NUMERIC" label={ t(`descriptors.common.dataType.numeric`) } control={ <Radio/> }/>
<FormControlLabel value="SCALE" label={ t(`descriptors.common.dataType.scale`) } control={ <Radio/> }/>
</RadioGroup>
</FormControl>
);
// FIXME Use Descriptor.CATEGORIES
const renderCategoryRadioGroup = ({ input, meta, classes, t, ...rest }) => (
<FormControl required fullWidth>
<FormLabel>{ t(`descriptors.admin.c.form.descriptorCategory`) }</FormLabel>
<RadioGroup
{ ...input }
{ ...rest }
value={ input.value }
onChange={
(event, value) => input.onChange(value) // tslint:disable-line
}
className={ classes.RadioGrid }
>
<FormControlLabel value="PASSPORT" label={ t(`descriptors.common.category.passport`) } control={ <Radio/> }/>
<FormControlLabel value="MANAGEMENT" label={ t(`descriptors.common.category.management`) } control={ <Radio/> }/>
<FormControlLabel value="ENVIRONMENT" label={ t(`descriptors.common.category.environment`) } control={ <Radio/> }/>
<FormControlLabel value="CHARACTERIZATION" label={ t(`descriptors.common.category.characterization`) } control={ <Radio/> }/>
<FormControlLabel value="EVALUATION" label={ t(`descriptors.common.category.evaluation`) } control={ <Radio/> }/>
<FormControlLabel value="ABIOTICSTRESS" label={ t(`descriptors.common.category.abioticstress`) } control={ <Radio/> }/>
<FormControlLabel value="BIOTICSTRESS" label={ t(`descriptors.common.category.bioticstress`) } control={ <Radio/> }/>
<FormControlLabel value="MOLECULAR" label={ t(`descriptors.common.category.molecular`) } control={ <Radio/> }/>
</RadioGroup>
</FormControl>
);
class DescriptorForm extends React.Component<any, any> {
private requiresMaxValue = () => {
const { dataType } = this.props;
return dataType === 'SCALE';
}
public constructor(props: any) {
super(props);
const { setPageTitle, pageTitle } = this.props;
setPageTitle(pageTitle);
}
private requiresMaxValue = () => {
const { dataType } = this.props;
return dataType === 'SCALE';
}
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;
......@@ -151,8 +101,10 @@ class DescriptorForm extends React.Component<any, any> {
<Field
name="crop"
label={ t(`descriptors.admin.c.form.crop`) }
component={ CropSelector }
single
component={ RadioSelection }
options={ crops }
valueField="shortName"
renderOptionLabel={ (crop) => crop.name }
/>
<Field
required
......@@ -192,7 +144,9 @@ class DescriptorForm extends React.Component<any, any> {
required
name="category"
classes={ classes }
component={ renderCategoryRadioGroup }
component={ RadioSelection }
options={ Object.getOwnPropertyNames(Descriptor.CATEGORIES) }
renderOptionLabel={ (option) => t(Descriptor.CATEGORIES[option]) }
t={ t }
validate={ [Validators.required] }
/>
......@@ -219,7 +173,9 @@ class DescriptorForm extends React.Component<any, any> {
<Field
required name="dataType"
classes={ classes }
component={ renderDataTypeRadioGroup }
component={ RadioSelection }
options={ Object.getOwnPropertyNames(Descriptor.DATATYPES) }
renderOptionLabel={ (option) => t(Descriptor.DATATYPES[option]) }
t={ t }
validate={ [Validators.required] }
/>
......@@ -303,6 +259,7 @@ class DescriptorForm extends React.Component<any, any> {
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'),
......
......@@ -59,12 +59,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; } = {
......
......@@ -5,14 +5,16 @@ import {saveSubset} from 'subsets/actions/editor';
import {SUBSET_FORM} from 'subsets/constants';
import Validators from 'utilities/Validators';
import Crop from 'model/genesys/Crop';
import {TextField} from 'ui/common/text-field';
import {MarkdownFieldWithAttach} from 'ui/common/markdown/MarkdownFieldWithAttach';
import CropSelector from 'crop/ui/c/CropSelector';
import CheckboxSelection from 'ui/common/forms/CheckboxSelection';
interface ILoginContainerProps extends React.ClassAttributes<any> {
handleSubmit: () => void;
initialValues: any;
classes: any;
crops: Crop[];
uuid: string;
t: any;
}
......@@ -21,7 +23,7 @@ class BasicInfoStep extends React.Component<ILoginContainerProps, any> {
public render() {
const {handleSubmit, t} = this.props;
const { crops, handleSubmit, t } = this.props;
return (
<form onSubmit={ handleSubmit } className="p-20 m-20 even-row">
......@@ -49,8 +51,11 @@ class BasicInfoStep extends React.Component<ILoginContainerProps, any> {
/>
<FieldArray