diff --git a/openbis_ng_ui/src/js/components/common/form/CheckboxField.jsx b/openbis_ng_ui/src/js/components/common/form/CheckboxField.jsx index 62a39657b87ca1a54c520f47536faa70c1fb41f0..b8f32015dacf2b8421c5205ef812153ace966a65 100644 --- a/openbis_ng_ui/src/js/components/common/form/CheckboxField.jsx +++ b/openbis_ng_ui/src/js/components/common/form/CheckboxField.jsx @@ -1,23 +1,113 @@ import React from 'react' import { withStyles } from '@material-ui/core/styles' import Checkbox from '@material-ui/core/Checkbox' -import FormField from './FormField.jsx' +import Typography from '@material-ui/core/Typography' +import FormFieldContainer from './FormFieldContainer.jsx' +import FormFieldLabel from './FormFieldLabel.jsx' import logger from '../../../common/logger.js' -const styles = () => ({}) +const styles = () => ({ + container: { + display: 'flex', + alignItems: 'center' + }, + label: { + cursor: 'pointer' + } +}) class CheckboxFormField extends React.PureComponent { + constructor(props) { + super(props) + this.reference = React.createRef() + this.action = null + this.handleLabelClick = this.handleLabelClick.bind(this) + this.handleChange = this.handleChange.bind(this) + this.handleFocus = this.handleFocus.bind(this) + } + + handleLabelClick() { + this.getReference().current.click() + } + + handleChange(event) { + this.handleEvent(event, this.props.onChange) + } + + handleFocus(event) { + this.handleEvent(event, this.props.onFocus) + if (this.action) { + this.action.focusVisible() + } + } + + handleEvent(event, handler) { + if (handler) { + const newEvent = { + ...event, + target: { + ...event.target, + name: event.target.value, + value: event.target.checked + } + } + delete newEvent.target.checked + handler(newEvent) + } + } + render() { logger.log(logger.DEBUG, 'CheckboxFormField.render') - const { value, disabled } = this.props + const { + name, + label, + description, + value, + mandatory, + disabled, + metadata, + styles, + classes, + onClick + } = this.props return ( - <FormField {...this.props}> - <Checkbox checked={value} disabled={disabled} /> - </FormField> + <FormFieldContainer + description={description} + metadata={metadata} + styles={styles} + onClick={onClick} + > + <div className={classes.container}> + <Checkbox + inputRef={this.getReference()} + action={action => (this.action = action)} + value={name} + checked={value} + disabled={disabled} + onChange={this.handleChange} + onFocus={this.handleFocus} + /> + <Typography + component='label' + className={classes.label} + onClick={this.handleLabelClick} + > + <FormFieldLabel + label={label} + mandatory={mandatory} + styles={styles} + /> + </Typography> + </div> + </FormFieldContainer> ) } + + getReference() { + return this.props.reference ? this.props.reference : this.reference + } } export default withStyles(styles)(CheckboxFormField) diff --git a/openbis_ng_ui/src/js/components/common/form/FormField.jsx b/openbis_ng_ui/src/js/components/common/form/FormField.jsx deleted file mode 100644 index 4b605bcc1e929c0553fe8363e46c5c4281f0ece7..0000000000000000000000000000000000000000 --- a/openbis_ng_ui/src/js/components/common/form/FormField.jsx +++ /dev/null @@ -1,88 +0,0 @@ -import React from 'react' -import { withStyles } from '@material-ui/core/styles' -import FormControl from '@material-ui/core/FormControl' -import FormHelperText from '@material-ui/core/FormHelperText' -import Typography from '@material-ui/core/Typography' -import logger from '../../../common/logger.js' - -const styles = theme => ({ - labelContainer: { - display: 'flex', - alignItems: 'stretch', - '& div': { - flex: '0 0 auto', - paddingRight: theme.spacing(1) - }, - '& b': { - fontWeight: 'bold', - color: theme.palette.error.main - }, - '& pre': { - flex: '0 0 auto', - margin: 0, - marginLeft: theme.spacing(1), - color: theme.palette.grey.main - } - }, - controlContainer: { - width: '100%' - } -}) - -class FormField extends React.PureComponent { - constructor(props) { - super(props) - } - - render() { - logger.log(logger.DEBUG, 'FormField.render') - - const { description, onClick, styles = {} } = this.props - - return ( - <div onClick={onClick} className={styles.container}> - <FormControl fullWidth={true}> - <Typography component='label'>{this.renderLabel()}</Typography> - <div>{this.renderControl()}</div> - <FormHelperText> - <span data-part='description' className={styles.description}> - {description} - </span> - </FormHelperText> - </FormControl> - </div> - ) - } - - renderLabel() { - const { label, mandatory, metadata, classes, styles = {} } = this.props - return ( - <div className={classes.labelContainer}> - <div> - <span data-part='label' className={styles.label}> - {label} - </span>{' '} - {mandatory && ( - <b data-part='mandatory' className={styles.mandatory}> - * - </b> - )} - </div> - <pre data-part='metadata' className={styles.metadata}> - {metadata} - </pre> - </div> - ) - } - - renderControl() { - const { children, classes, styles = {} } = this.props - return ( - <div data-part='control' className={classes.controlContainer}> - <div className={styles.control}>{children}</div> - </div> - ) - } -} - -export default withStyles(styles)(FormField) diff --git a/openbis_ng_ui/src/js/components/common/form/FormFieldContainer.jsx b/openbis_ng_ui/src/js/components/common/form/FormFieldContainer.jsx new file mode 100644 index 0000000000000000000000000000000000000000..a12904fb715428d3a08ff581358e8e70f1be6320 --- /dev/null +++ b/openbis_ng_ui/src/js/components/common/form/FormFieldContainer.jsx @@ -0,0 +1,90 @@ +import React from 'react' +import { withStyles } from '@material-ui/core/styles' +import FormControl from '@material-ui/core/FormControl' +import FormHelperText from '@material-ui/core/FormHelperText' +import logger from '../../../common/logger.js' + +const styles = theme => ({ + metadataDefault: { + flex: '0 0 auto', + margin: 0, + marginBottom: theme.spacing(1), + color: theme.palette.grey.main + }, + controlDefault: { + flex: '0 0' + }, + descriptionDefault: {} +}) + +class FormFieldContainer extends React.PureComponent { + constructor(props) { + super(props) + } + + render() { + logger.log(logger.DEBUG, 'FormField.render') + + const { onClick, styles = {} } = this.props + + return ( + <FormControl fullWidth={true}> + <div onClick={onClick} className={styles.container}> + {this.renderMetadata()} + {this.renderControl()} + {this.renderDescription()} + </div> + </FormControl> + ) + } + + renderMetadata() { + const { metadata, classes, styles = {} } = this.props + + if (metadata) { + return ( + <pre + data-part='metadata' + className={`${classes.metadataDefault} ${styles.metadata}`} + > + {metadata} + </pre> + ) + } else { + return null + } + } + + renderControl() { + const { children, classes, styles = {} } = this.props + return ( + <div + data-part='control' + className={`${classes.controlDefault} ${styles.control}`} + > + {children} + </div> + ) + } + + renderDescription() { + const { description, classes, styles = {} } = this.props + + if (description) { + return ( + <FormHelperText> + <span + data-part='description' + className={`${classes.descriptionDefault} ${styles.description}`} + > + {description} + </span> + </FormHelperText> + ) + } else { + return null + } + } +} + +export default withStyles(styles)(FormFieldContainer) diff --git a/openbis_ng_ui/src/js/components/common/form/FormFieldLabel.jsx b/openbis_ng_ui/src/js/components/common/form/FormFieldLabel.jsx new file mode 100644 index 0000000000000000000000000000000000000000..5e3976ffb9b0ebe321461c51a009fd75194b8757 --- /dev/null +++ b/openbis_ng_ui/src/js/components/common/form/FormFieldLabel.jsx @@ -0,0 +1,44 @@ +import React from 'react' +import { withStyles } from '@material-ui/core/styles' +import logger from '../../../common/logger.js' + +const styles = theme => ({ + labelDefault: { + marginRight: theme.spacing(1) + }, + mandatoryDefault: { + fontWeight: 'bold', + color: theme.palette.error.main + } +}) + +class FormFieldLabel extends React.PureComponent { + render() { + logger.log(logger.DEBUG, 'FormFieldLabel.render') + + const { label, mandatory, styles = {}, classes } = this.props + + return ( + <span className={classes.container}> + {label && ( + <span + data-part='label' + className={`${classes.labelDefault} ${styles.label}`} + > + {label} + </span> + )} + {mandatory && ( + <span + data-part='mandatory' + className={`${classes.mandatoryDefault} ${styles.mandatory}`} + > + * + </span> + )} + </span> + ) + } +} + +export default withStyles(styles)(FormFieldLabel) diff --git a/openbis_ng_ui/src/js/components/common/form/SelectField.jsx b/openbis_ng_ui/src/js/components/common/form/SelectField.jsx index 6bf390ed039c6ae9b7cdac06bca5c22707a36b94..57b968b201dfef2705f25fe8433c2d469fb148c1 100644 --- a/openbis_ng_ui/src/js/components/common/form/SelectField.jsx +++ b/openbis_ng_ui/src/js/components/common/form/SelectField.jsx @@ -1,8 +1,8 @@ import React from 'react' import { withStyles } from '@material-ui/core/styles' import TextField from '@material-ui/core/TextField' -import MenuItem from '@material-ui/core/MenuItem' -import FormField from './FormField.jsx' +import FormFieldContainer from './FormFieldContainer.jsx' +import FormFieldLabel from './FormFieldLabel.jsx' import logger from '../../../common/logger.js' const styles = () => ({}) @@ -11,19 +11,58 @@ class SelectFormField extends React.PureComponent { render() { logger.log(logger.DEBUG, 'SelectFormField.render') - const { value, disabled, options } = this.props + const { + reference, + name, + label, + description, + value, + mandatory, + disabled, + options, + metadata, + styles, + onClick, + onChange, + onFocus + } = this.props return ( - <FormField {...this.props}> - <TextField select value={value} disabled={disabled} fullWidth={true}> + <FormFieldContainer + description={description} + metadata={metadata} + styles={styles} + onClick={onClick} + > + <TextField + select + inputRef={reference} + label={ + <FormFieldLabel + label={label} + mandatory={mandatory} + styles={styles} + /> + } + name={name} + value={value} + disabled={disabled} + onChange={onChange} + onFocus={onFocus} + fullWidth={true} + SelectProps={{ + native: true + }} + variant='filled' + > {options && options.map(option => ( - <MenuItem key={option.value} value={option.value}> + <option key={option.value} value={option.value}> {option.label || option.value} - </MenuItem> + </option> ))} </TextField> - </FormField> + </FormFieldContainer> ) } } diff --git a/openbis_ng_ui/src/js/components/common/form/TextField.jsx b/openbis_ng_ui/src/js/components/common/form/TextField.jsx index 40e3b611f2e2e32889e1551c9482e26c945d0810..02e571b7800e6e63212059468ee9305e180bf1a9 100644 --- a/openbis_ng_ui/src/js/components/common/form/TextField.jsx +++ b/openbis_ng_ui/src/js/components/common/form/TextField.jsx @@ -1,7 +1,8 @@ import React from 'react' import { withStyles } from '@material-ui/core/styles' import TextField from '@material-ui/core/TextField' -import FormField from './FormField.jsx' +import FormFieldContainer from './FormFieldContainer.jsx' +import FormFieldLabel from './FormFieldLabel.jsx' import logger from '../../../common/logger.js' const styles = () => ({}) @@ -10,17 +11,48 @@ class SelectFormField extends React.PureComponent { render() { logger.log(logger.DEBUG, 'SelectFormField.render') - const { type, value, disabled } = this.props + const { + reference, + type, + name, + label, + description, + value, + mandatory, + disabled, + metadata, + styles, + onClick, + onChange, + onFocus + } = this.props return ( - <FormField {...this.props}> + <FormFieldContainer + description={description} + metadata={metadata} + styles={styles} + onClick={onClick} + > <TextField + inputRef={reference} type={type} + label={ + <FormFieldLabel + label={label} + mandatory={mandatory} + styles={styles} + /> + } + name={name} value={value} disabled={disabled} + onChange={onChange} + onFocus={onFocus} fullWidth={true} + variant='filled' /> - </FormField> + </FormFieldContainer> ) } } diff --git a/openbis_ng_ui/src/js/components/types/objectType/ObjectType.jsx b/openbis_ng_ui/src/js/components/types/objectType/ObjectType.jsx index 6ac80111e6609176597d704668b9ee0f4db51443..e4c6690e9c249b401579afc5ebffbb9ec3f0e65c 100644 --- a/openbis_ng_ui/src/js/components/types/objectType/ObjectType.jsx +++ b/openbis_ng_ui/src/js/components/types/objectType/ObjectType.jsx @@ -23,6 +23,8 @@ const styles = theme => ({ preview: { height: '100%', flex: '1 1 auto', + display: 'flex', + flexDirection: 'column', overflow: 'auto' }, buttons: { @@ -513,6 +515,10 @@ class ObjectType extends React.PureComponent { </div> </div> <Resizable + defaultSize={{ + width: 400, + height: 'auto' + }} enable={{ left: true, top: false, diff --git a/openbis_ng_ui/src/js/components/types/objectType/ObjectTypeParameters.jsx b/openbis_ng_ui/src/js/components/types/objectType/ObjectTypeParameters.jsx index 6eeabc6918c48627d4e7695b4096bdf23ddb714c..883dd9392471fb5f8078e55ffb49f10a93d3144e 100644 --- a/openbis_ng_ui/src/js/components/types/objectType/ObjectTypeParameters.jsx +++ b/openbis_ng_ui/src/js/components/types/objectType/ObjectTypeParameters.jsx @@ -5,11 +5,7 @@ import ObjectTypeParametersProperty from './ObjectTypeParametersProperty.jsx' import ObjectTypeParametersSection from './ObjectTypeParametersSection.jsx' import logger from '../../../common/logger.js' -const styles = () => ({ - container: { - minWidth: '400px' - } -}) +const styles = () => ({}) class ObjectTypeParameters extends React.PureComponent { constructor(props) { @@ -25,12 +21,11 @@ class ObjectTypeParameters extends React.PureComponent { properties, selection, onChange, - onSelectionChange, - classes + onSelectionChange } = this.props return ( - <div className={classes.container}> + <div> <ObjectTypeParametersType type={type} selection={selection} @@ -40,6 +35,7 @@ class ObjectTypeParameters extends React.PureComponent { sections={sections} selection={selection} onChange={onChange} + onSelectionChange={onSelectionChange} /> <ObjectTypeParametersProperty properties={properties} diff --git a/openbis_ng_ui/src/js/components/types/objectType/ObjectTypeParametersProperty.jsx b/openbis_ng_ui/src/js/components/types/objectType/ObjectTypeParametersProperty.jsx index 9a28a232926c6a771c7e2603d2d84a4a2e13f4d7..e89a50d388703da3d37dc7bcc2dd9015b7ba4479 100644 --- a/openbis_ng_ui/src/js/components/types/objectType/ObjectTypeParametersProperty.jsx +++ b/openbis_ng_ui/src/js/components/types/objectType/ObjectTypeParametersProperty.jsx @@ -1,16 +1,21 @@ -import _ from 'lodash' import React from 'react' import { withStyles } from '@material-ui/core/styles' import Typography from '@material-ui/core/Typography' -import FormControlLabel from '@material-ui/core/FormControlLabel' -import Checkbox from '@material-ui/core/Checkbox' -import TextField from '@material-ui/core/TextField' +import CheckboxField from '../../common/form/CheckboxField.jsx' +import TextField from '../../common/form/TextField.jsx' +import SelectField from '../../common/form/SelectField.jsx' import { facade, dto } from '../../../services/openbis.js' import logger from '../../../common/logger.js' const styles = theme => ({ container: { padding: theme.spacing(2) + }, + header: { + paddingBottom: theme.spacing(2) + }, + field: { + paddingBottom: theme.spacing(2) } }) @@ -25,7 +30,6 @@ class ObjectTypeParametersProperty extends React.PureComponent { dataType: React.createRef(), mandatory: React.createRef() } - this.actions = {} this.handleChange = this.handleChange.bind(this) this.handleFocus = this.handleFocus.bind(this) } @@ -99,10 +103,6 @@ class ObjectTypeParametersProperty extends React.PureComponent { if (reference) { reference.current.focus() } - const action = this.actions[part] - if (action) { - action.focusVisible() - } } } } @@ -110,20 +110,10 @@ class ObjectTypeParametersProperty extends React.PureComponent { handleChange(event) { const property = this.getProperty(this.props) - let params = null - - if (_.has(event.target, 'checked')) { - params = { - id: property.id, - field: event.target.value, - value: event.target.checked - } - } else { - params = { - id: property.id, - field: event.target.name, - value: event.target.value - } + const params = { + id: property.id, + field: event.target.name, + value: event.target.value } this.props.onChange('property', params) @@ -132,18 +122,9 @@ class ObjectTypeParametersProperty extends React.PureComponent { handleFocus(event) { const property = this.getProperty(this.props) - let params = null - - if (_.has(event.target, 'checked')) { - params = { - id: property.id, - part: event.target.value - } - } else { - params = { - id: property.id, - part: event.target.name - } + const params = { + id: property.id, + part: event.target.name } this.props.onSelectionChange('property', params) @@ -152,187 +133,184 @@ class ObjectTypeParametersProperty extends React.PureComponent { render() { logger.log(logger.DEBUG, 'ObjectTypeParametersProperty.render') - let property = this.getProperty(this.props) + const property = this.getProperty(this.props) if (!property) { return null } - let { classes } = this.props - let { vocabularies, materialTypes } = this.state + const { classes } = this.props return ( <div className={classes.container}> - <Typography variant='h6'>Property</Typography> - <form> - <div> - <TextField - inputRef={this.references.label} - label='Label' - name='label' - value={property.label} - fullWidth={true} - margin='normal' - variant='filled' - InputLabelProps={{ - shrink: true - }} - onChange={this.handleChange} - onFocus={this.handleFocus} - /> - </div> - <div> - <TextField - inputRef={this.references.code} - label='Code' - name='code' - value={property.code} - fullWidth={true} - margin='normal' - variant='filled' - InputLabelProps={{ - shrink: true - }} - onChange={this.handleChange} - onFocus={this.handleFocus} - /> - </div> - <div> - <TextField - inputRef={this.references.description} - label='Description' - name='description' - value={property.description} - fullWidth={true} - margin='normal' - variant='filled' - InputLabelProps={{ - shrink: true - }} - onChange={this.handleChange} - onFocus={this.handleFocus} - /> - </div> - <div> - <TextField - select - inputRef={this.references.dataType} - label='Data Type' - name='dataType' - SelectProps={{ - native: true - }} - value={property.dataType} - fullWidth={true} - margin='normal' - variant='filled' - InputLabelProps={{ - shrink: true - }} - onChange={this.handleChange} - onFocus={this.handleFocus} - > - {dto.DataType.values.sort().map(dataType => { - return ( - <option key={dataType} value={dataType}> - {dataType} - </option> - ) - })} - </TextField> - </div> - {property.dataType === 'CONTROLLEDVOCABULARY' && ( - <div> - <TextField - select - label='Vocabulary' - name='vocabulary' - SelectProps={{ - native: true - }} - value={property.vocabulary ? property.vocabulary : ''} - fullWidth={true} - margin='normal' - variant='filled' - InputLabelProps={{ - shrink: true - }} - onChange={this.handleChange} - onFocus={this.handleFocus} - > - <option key='' value=''></option> - {vocabularies && - vocabularies.map(vocabulary => { - return ( - <option key={vocabulary.code} value={vocabulary.code}> - {vocabulary.code} - </option> - ) - })} - </TextField> - </div> - )} - {property.dataType === 'MATERIAL' && ( - <div> - <TextField - select - label='Material Type' - name='materialType' - SelectProps={{ - native: true - }} - value={property.materialType ? property.materialType : ''} - fullWidth={true} - margin='normal' - variant='filled' - InputLabelProps={{ - shrink: true - }} - onChange={this.handleChange} - onFocus={this.handleFocus} - > - <option key='' value=''></option> - {materialTypes && - materialTypes.map(materialType => { - return ( - <option key={materialType.code} value={materialType.code}> - {materialType.code} - </option> - ) - })} - </TextField> - </div> - )} - <div> - <FormControlLabel - control={ - <Checkbox - inputRef={this.references.mandatory} - action={actions => { - this.actions.mandatory = actions - }} - value='mandatory' - checked={property.mandatory} - onChange={this.handleChange} - onFocus={this.handleFocus} - /> - } - label='Mandatory' - /> - </div> - <div> - <FormControlLabel - control={ - <Checkbox - value='visible' - checked={property.visible} - onChange={this.handleChange} - onFocus={this.handleFocus} - /> - } - label='Visible' - /> - </div> - </form> + <Typography variant='h6' className={classes.header}> + Property + </Typography> + {this.renderCode(property)} + {this.renderDataType(property)} + {this.renderLabel(property)} + {this.renderDescription(property)} + {this.renderVocabulary(property)} + {this.renderMaterial(property)} + {this.renderMandatory(property)} + {this.renderVisible(property)} + </div> + ) + } + + renderLabel(property) { + const { classes } = this.props + return ( + <div className={classes.field}> + <TextField + reference={this.references.label} + label='Label' + name='label' + value={property.label} + onChange={this.handleChange} + onFocus={this.handleFocus} + /> + </div> + ) + } + + renderCode(property) { + const { classes } = this.props + return ( + <div className={classes.field}> + <TextField + reference={this.references.code} + label='Code' + name='code' + value={property.code} + onChange={this.handleChange} + onFocus={this.handleFocus} + /> + </div> + ) + } + + renderDescription(property) { + const { classes } = this.props + return ( + <div className={classes.field}> + <TextField + reference={this.references.description} + label='Description' + name='description' + value={property.description} + onChange={this.handleChange} + onFocus={this.handleFocus} + /> + </div> + ) + } + + renderDataType(property) { + const options = dto.DataType.values.sort().map(dataType => { + return { + label: dataType, + value: dataType + } + }) + const { classes } = this.props + return ( + <div className={classes.field}> + <SelectField + reference={this.references.dataType} + label='Data Type' + name='dataType' + value={property.dataType} + options={options} + onChange={this.handleChange} + onFocus={this.handleFocus} + /> + </div> + ) + } + + renderVocabulary(property) { + let { vocabularies } = this.state + + if (property.dataType === 'CONTROLLEDVOCABULARY' && vocabularies) { + const options = vocabularies.map(vocabulary => { + return { + label: vocabulary.code, + value: vocabulary.code + } + }) + const { classes } = this.props + return ( + <div className={classes.field}> + <SelectField + label='Vocabulary' + name='vocabulary' + value={property.vocabulary ? property.vocabulary : ''} + options={options} + onChange={this.handleChange} + onFocus={this.handleFocus} + /> + </div> + ) + } else { + return null + } + } + + renderMaterial(property) { + let { materialTypes } = this.state + + if (property.dataType === 'MATERIAL' && materialTypes) { + const options = materialTypes.map(materialType => { + return { + label: materialType.code, + value: materialType.code + } + }) + const { classes } = this.props + return ( + <div className={classes.field}> + <SelectField + label='Material Type' + name='materialType' + value={property.materialType ? property.materialType : ''} + options={options} + onChange={this.handleChange} + onFocus={this.handleFocus} + /> + </div> + ) + } else { + return null + } + } + + renderMandatory(property) { + const { classes } = this.props + return ( + <div className={classes.field}> + <CheckboxField + reference={this.references.mandatory} + label='Mandatory' + name='mandatory' + value={property.mandatory} + onChange={this.handleChange} + onFocus={this.handleFocus} + /> + </div> + ) + } + + renderVisible(property) { + const { classes } = this.props + return ( + <div className={classes.field}> + <CheckboxField + label='Visible' + name='visible' + value={property.visible} + onChange={this.handleChange} + onFocus={this.handleFocus} + /> </div> ) } diff --git a/openbis_ng_ui/src/js/components/types/objectType/ObjectTypeParametersSection.jsx b/openbis_ng_ui/src/js/components/types/objectType/ObjectTypeParametersSection.jsx index 0f637f295bd68f6dd0b86eb343498c3390e5c362..7cbb1e28ec68369637a9824835ff0ea5d0513003 100644 --- a/openbis_ng_ui/src/js/components/types/objectType/ObjectTypeParametersSection.jsx +++ b/openbis_ng_ui/src/js/components/types/objectType/ObjectTypeParametersSection.jsx @@ -1,24 +1,53 @@ import React from 'react' import { withStyles } from '@material-ui/core/styles' import Typography from '@material-ui/core/Typography' -import TextField from '@material-ui/core/TextField' +import TextField from '../../common/form/TextField.jsx' import logger from '../../../common/logger.js' const styles = theme => ({ container: { padding: theme.spacing(2) + }, + header: { + paddingBottom: theme.spacing(2) + }, + field: { + paddingBottom: theme.spacing(2) } }) class ObjectTypeParametersSection extends React.PureComponent { constructor(props) { super(props) + this.reference = React.createRef() this.handleChange = this.handleChange.bind(this) } + componentDidMount() { + this.focus() + } + + componentDidUpdate(prevProps) { + const prevSelection = prevProps.selection + const selection = this.props.selection + + if (prevSelection !== selection) { + this.focus() + } + } + + focus() { + const section = this.getSection(this.props) + if (section) { + this.reference.current.focus() + } + } + handleChange(event) { + const section = this.getSection(this.props) + const params = { - id: this.props.selection.params.id, + id: section.id, field: event.target.name, value: event.target.value } @@ -29,38 +58,43 @@ class ObjectTypeParametersSection extends React.PureComponent { render() { logger.log(logger.DEBUG, 'ObjectTypeParametersSection.render') - let { classes, sections, selection } = this.props - - if (!selection || selection.type !== 'section') { + const section = this.getSection(this.props) + if (!section) { return null } - let [section] = sections.filter( - section => section.id === selection.params.id - ) + let { classes } = this.props return ( <div className={classes.container}> - <Typography variant='h6'>Section</Typography> - <form> - <div> - <TextField - label='Name' - name='name' - value={section.name || ''} - fullWidth={true} - margin='normal' - variant='filled' - InputLabelProps={{ - shrink: true - }} - onChange={this.handleChange} - /> - </div> - </form> + <Typography variant='h6' className={classes.header}> + Section + </Typography> + <div className={classes.field}> + <TextField + reference={this.reference} + label='Name' + name='name' + value={section.name || ''} + onChange={this.handleChange} + /> + </div> </div> ) } + + getSection(props) { + let { sections, selection } = props + + if (selection && selection.type === 'section') { + let [section] = sections.filter( + section => section.id === selection.params.id + ) + return section + } else { + return null + } + } } export default withStyles(styles)(ObjectTypeParametersSection) diff --git a/openbis_ng_ui/src/js/components/types/objectType/ObjectTypeParametersType.jsx b/openbis_ng_ui/src/js/components/types/objectType/ObjectTypeParametersType.jsx index bb960629b6f1f15151f380ba6c9ae8b87297f723..04c3f660a63c5c64916a97122720ddfdd354113d 100644 --- a/openbis_ng_ui/src/js/components/types/objectType/ObjectTypeParametersType.jsx +++ b/openbis_ng_ui/src/js/components/types/objectType/ObjectTypeParametersType.jsx @@ -1,15 +1,19 @@ -import _ from 'lodash' import React from 'react' import { withStyles } from '@material-ui/core/styles' import Typography from '@material-ui/core/Typography' -import FormControlLabel from '@material-ui/core/FormControlLabel' -import TextField from '@material-ui/core/TextField' -import Checkbox from '@material-ui/core/Checkbox' +import CheckboxField from '../../common/form/CheckboxField.jsx' +import TextField from '../../common/form/TextField.jsx' import logger from '../../../common/logger.js' const styles = theme => ({ container: { padding: theme.spacing(2) + }, + header: { + paddingBottom: theme.spacing(2) + }, + field: { + paddingBottom: theme.spacing(2) } }) @@ -20,20 +24,10 @@ class ObjectTypeParametersType extends React.PureComponent { } handleChange(event) { - let params = null - - if (_.has(event.target, 'checked')) { - params = { - field: event.target.value, - value: event.target.checked - } - } else { - params = { - field: event.target.name, - value: event.target.value - } + let params = { + field: event.target.name, + value: event.target.value } - this.props.onChange('type', params) } @@ -51,78 +45,51 @@ class ObjectTypeParametersType extends React.PureComponent { return ( <div className={classes.container}> - <Typography variant='h6'>Type</Typography> - <form> - <div> - <TextField - label='Code' - name='code' - value={type.code} - fullWidth={true} - margin='normal' - variant='filled' - InputLabelProps={{ - shrink: true - }} - onChange={this.handleChange} - /> - </div> - <div> + <Typography variant='h6' className={classes.header}> + Type + </Typography> + <div className={classes.field}> + <TextField + label='Code' + name='code' + value={type.code} + onChange={this.handleChange} + /> + </div> + <div className={classes.field}> + <TextField + label='Description' + name='description' + value={type.description} + onChange={this.handleChange} + /> + </div> + <div className={classes.field}> + <CheckboxField + label='Generate codes automatically' + name='autoGeneratedCode' + value={type.autoGeneratedCode} + onChange={this.handleChange} + /> + </div> + {type.autoGeneratedCode && ( + <div className={classes.field}> <TextField - label='Description' - name='description' - value={type.description} - fullWidth={true} - margin='normal' - variant='filled' - multiline={true} - InputLabelProps={{ - shrink: true - }} + label='Generated code prefix' + name='generatedCodePrefix' + value={type.generatedCodePrefix} onChange={this.handleChange} /> </div> - <div> - <FormControlLabel - control={ - <Checkbox - value='autoGeneratedCode' - checked={type.autoGeneratedCode} - onChange={this.handleChange} - /> - } - label='Generate codes automatically' - /> - </div> - {type.autoGeneratedCode && ( - <div> - <TextField - label='Generated code prefix' - name='generatedCodePrefix' - value={type.generatedCodePrefix} - fullWidth={true} - margin='normal' - variant='filled' - InputLabelProps={{ - shrink: true - }} - onChange={this.handleChange} - /> - </div> - )} - <div> - <FormControlLabel - control={ - <Checkbox - value='subcodeUnique' - checked={type.subcodeUnique} - onChange={this.handleChange} - /> - } - label='Unique subcodes' - /> - </div> - </form> + )} + <div className={classes.field}> + <CheckboxField + label='Unique subcodes' + name='subcodeUnique' + value={type.subcodeUnique} + onChange={this.handleChange} + /> + </div> </div> ) } diff --git a/openbis_ng_ui/src/js/components/types/objectType/ObjectTypePreview.jsx b/openbis_ng_ui/src/js/components/types/objectType/ObjectTypePreview.jsx index 17a63a5b1eba9bc1e6b4428f6baf368ba37b7196..c631b7cf43391b1422b1da591834322bf35495de 100644 --- a/openbis_ng_ui/src/js/components/types/objectType/ObjectTypePreview.jsx +++ b/openbis_ng_ui/src/js/components/types/objectType/ObjectTypePreview.jsx @@ -10,6 +10,7 @@ import logger from '../../../common/logger.js' const styles = theme => ({ container: { + flex: '1 1 auto', display: 'flex', padding: `${theme.spacing(2)}px ${theme.spacing(4)}px` }, diff --git a/openbis_ng_ui/src/js/components/types/objectType/ObjectTypePreviewCode.jsx b/openbis_ng_ui/src/js/components/types/objectType/ObjectTypePreviewCode.jsx index 77b78c0684f8ec69dbcf6c43ca52f4edc14f689b..84ad0f5d7360688ee02b9f20e239bf0edd56e1c7 100644 --- a/openbis_ng_ui/src/js/components/types/objectType/ObjectTypePreviewCode.jsx +++ b/openbis_ng_ui/src/js/components/types/objectType/ObjectTypePreviewCode.jsx @@ -4,28 +4,47 @@ import TextField from '../../common/form/TextField.jsx' import { withStyles } from '@material-ui/core/styles' import logger from '../../../common/logger.js' -const styles = () => ({}) +const styles = theme => ({ + container: { + marginBottom: theme.spacing(2) + } +}) class ObjectTypePreviewCode extends React.PureComponent { constructor(props) { super(props) + this.state = { + value: '' + } + this.handleChange = this.handleChange.bind(this) + } + + handleChange(event) { + this.setState({ + value: event.target.value + }) } render() { logger.log(logger.DEBUG, 'ObjectTypePreviewCode.render') + const { classes } = this.props + return ( - <TextField - label='Code' - value={this.getValue()} - disabled={this.getDisabled()} - /> + <div className={classes.container}> + <TextField + label='Code' + value={this.getValue()} + disabled={this.getDisabled()} + onChange={this.handleChange} + /> + </div> ) } getValue() { let { type } = this.props - return type.autoGeneratedCode ? type.generatedCodePrefix : '' + return type.autoGeneratedCode ? type.generatedCodePrefix : this.state.value } getDisabled() { diff --git a/openbis_ng_ui/src/js/components/types/objectType/ObjectTypePreviewProperty.jsx b/openbis_ng_ui/src/js/components/types/objectType/ObjectTypePreviewProperty.jsx index 0492c52266ac947824a3bd79508d6d078bc7a0cd..37d0e4583468ba375fc739c0d538912d3e887a0c 100644 --- a/openbis_ng_ui/src/js/components/types/objectType/ObjectTypePreviewProperty.jsx +++ b/openbis_ng_ui/src/js/components/types/objectType/ObjectTypePreviewProperty.jsx @@ -9,6 +9,8 @@ import { facade, dto } from '../../../services/openbis.js' import logger from '../../../common/logger.js' import * as util from '../../../common/util.js' +const EMPTY = 'empty' + const styles = theme => ({ draggable: { width: '100%', @@ -33,13 +35,11 @@ const styles = theme => ({ partEmpty: { fontStyle: 'italic', opacity: 0.7, - color: theme.palette.grey.main, - '&:after': { - content: '"empty"' - } + color: theme.palette.grey.main }, partSelected: { cursor: 'pointer', + pointerEvents: 'initial', paddingBottom: '1px', borderColor: theme.palette.secondary.main, borderStyle: 'solid', @@ -50,6 +50,7 @@ const styles = theme => ({ }, partNotSelected: { cursor: 'pointer', + pointerEvents: 'initial', paddingBottom: '1px', '&:hover': { borderStyle: 'solid', @@ -139,8 +140,7 @@ class ObjectTypePreviewProperty extends React.PureComponent { handleDraggableClick(event) { event.stopPropagation() this.props.onSelectionChange('property', { - id: this.props.property.id, - part: 'label' + id: this.props.property.id }) } @@ -200,72 +200,42 @@ class ObjectTypePreviewProperty extends React.PureComponent { } } - renderMetadata() { - const { code, dataType } = this.props.property - const styles = this.createStyles() - - return ( - <React.Fragment> - [ - <span - data-part='code' - className={styles.code} - onClick={this.handlePropertyClick} - > - {code} - </span> - ][ - <span - data-part='dataType' - className={styles.dataType} - onClick={this.handlePropertyClick} - > - {dataType} - </span> - ] - </React.Fragment> - ) - } - renderVarcharProperty() { - const { property } = this.props return ( <TextField - label={property.label} - description={property.description} - mandatory={property.mandatory} - metadata={this.renderMetadata()} - styles={this.createStyles()} + label={this.getLabel()} + description={this.getDescription()} + mandatory={this.getMandatory()} + metadata={this.getMetadata()} + styles={this.getStyles()} onClick={this.handlePropertyClick} /> ) } renderNumberProperty() { - const { property } = this.props return ( <TextField type='number' - label={property.label} - description={property.description} - mandatory={property.mandatory} - metadata={this.renderMetadata()} - styles={this.createStyles()} + label={this.getLabel()} + description={this.getDescription()} + mandatory={this.getMandatory()} + metadata={this.getMetadata()} + styles={this.getStyles()} onClick={this.handlePropertyClick} /> ) } renderBooleanProperty() { - const { property } = this.props return ( <div> <CheckboxField - label={property.label} - description={property.description} - mandatory={property.mandatory} - metadata={this.renderMetadata()} - styles={this.createStyles()} + label={this.getLabel()} + description={this.getDescription()} + mandatory={this.getMandatory()} + metadata={this.getMetadata()} + styles={this.getStyles()} onClick={this.handlePropertyClick} /> </div> @@ -273,7 +243,6 @@ class ObjectTypePreviewProperty extends React.PureComponent { } renderVocabularyProperty() { - const { property } = this.props const { terms } = this.state let options = [] @@ -286,19 +255,18 @@ class ObjectTypePreviewProperty extends React.PureComponent { return ( <SelectField - label={property.label} - description={property.description} - mandatory={property.mandatory} + label={this.getLabel()} + description={this.getDescription()} + mandatory={this.getMandatory()} options={options} - metadata={this.renderMetadata()} - styles={this.createStyles()} + metadata={this.getMetadata()} + styles={this.getStyles()} onClick={this.handlePropertyClick} /> ) } renderMaterialProperty() { - const { property } = this.props const { materials } = this.state let options = [] @@ -310,18 +278,64 @@ class ObjectTypePreviewProperty extends React.PureComponent { return ( <SelectField - label={property.label} - description={property.description} - mandatory={property.mandatory} + label={this.getLabel()} + description={this.getDescription()} + mandatory={this.getMandatory()} options={options} - metadata={this.renderMetadata()} - styles={this.createStyles()} + metadata={this.getMetadata()} + styles={this.getStyles()} onClick={this.handlePropertyClick} /> ) } - createStyles() { + getCode() { + return this.props.property.code || EMPTY + } + + getLabel() { + return this.props.property.label || EMPTY + } + + getDescription() { + return this.props.property.description || EMPTY + } + + getDataType() { + return this.props.property.dataType + } + + getMandatory() { + return this.props.property.mandatory + } + + getMetadata() { + const styles = this.getStyles() + + return ( + <React.Fragment> + [ + <span + data-part='code' + className={styles.code} + onClick={this.handlePropertyClick} + > + {this.getCode()} + </span> + ][ + <span + data-part='dataType' + className={styles.dataType} + onClick={this.handlePropertyClick} + > + {this.getDataType()} + </span> + ] + </React.Fragment> + ) + } + + getStyles() { const { property, selection, classes } = this.props let styles = {} diff --git a/openbis_ng_ui/src/js/components/types/objectType/ObjectTypePreviewSection.jsx b/openbis_ng_ui/src/js/components/types/objectType/ObjectTypePreviewSection.jsx index d84ead6d773cd610a3745a330b53a178a465a1b6..74c5c00861b1fc23aee733bb7af43922515807b4 100644 --- a/openbis_ng_ui/src/js/components/types/objectType/ObjectTypePreviewSection.jsx +++ b/openbis_ng_ui/src/js/components/types/objectType/ObjectTypePreviewSection.jsx @@ -10,32 +10,28 @@ const styles = theme => ({ draggable: { width: '100%', marginBottom: theme.spacing(2), - backgroundColor: theme.palette.background.paper + backgroundColor: theme.palette.background.paper, + '&:hover $droppable': { + borderColor: theme.palette.primary.main + } }, droppable: { padding: theme.spacing(2), borderWidth: '2px', borderStyle: 'dashed', - borderColor: theme.palette.background.secondary, - '&:hover': { - borderColor: theme.palette.primary.main - } + borderColor: theme.palette.background.secondary }, named: { '& $droppable': { - borderStyle: 'solid', - borderColor: theme.palette.background.secondary, - '&:hover': { - borderColor: theme.palette.primary.main - } + borderStyle: 'solid' } }, selected: { '& $droppable': { - borderColor: theme.palette.secondary.main, - '&:hover': { - borderColor: theme.palette.secondary.main - } + borderColor: theme.palette.secondary.main + }, + '&:hover $droppable': { + borderColor: theme.palette.secondary.main } } }) @@ -48,7 +44,10 @@ class ObjectTypePreviewSection extends React.PureComponent { handleClick(event) { event.stopPropagation() - this.props.onSelectionChange('section', { id: this.props.section.id }) + this.props.onSelectionChange('section', { + id: this.props.section.id, + part: 'name' + }) } render() { @@ -78,8 +77,10 @@ class ObjectTypePreviewSection extends React.PureComponent { > <Droppable droppableId={id} type='property'> {provided => ( - <React.Fragment> - <Typography variant='h6'>{name}</Typography> + <div> + <Typography variant='h6' data-part='name'> + {name} + </Typography> <div ref={provided.innerRef} {...provided.droppableProps} @@ -88,7 +89,7 @@ class ObjectTypePreviewSection extends React.PureComponent { <div>{children}</div> {provided.placeholder} </div> - </React.Fragment> + </div> )} </Droppable> </div> diff --git a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/util/FormUtil.js b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/util/FormUtil.js index ce86a6c0d955ae1c59cb0a5cb39b84efb258c0bc..1afec40f8ff5b228d3db1401aef0dabcac034460 100644 --- a/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/util/FormUtil.js +++ b/openbis_standard_technologies/dist/core-plugins/eln-lims/1/as/webapps/eln-lims/html/js/util/FormUtil.js @@ -1770,8 +1770,10 @@ var FormUtil = new function() { } this.prepareId = function(id) { - id = id[0] === '$' ? id.substring(1) : id; - id = id.split(".").join(""); - return id; - } + if (id) { + id = id[0] === '$' ? id.substring(1) : id; + id = id.split(".").join(""); + } + return id; + } } diff --git a/pybis/src/python/CHANGELOG.md b/pybis/src/python/CHANGELOG.md index 27cbb7d42c07aeb949315a00dd709f6da5bedf37..abfaa5ab7964d5cdf92ebe0ccb19f3366475e662 100644 --- a/pybis/src/python/CHANGELOG.md +++ b/pybis/src/python/CHANGELOG.md @@ -1,3 +1,7 @@ +## Changes with pybis-1.10.3 + +* print warning message when downloaded file-size does not match with promised file-size. Do not die. + ## Changes with pybis-1.10.2 * typo bugfix diff --git a/pybis/src/python/pybis/__init__.py b/pybis/src/python/pybis/__init__.py index 4eea0a84fdadaa16aa2e12fe94dc81ded8613a08..2d588f6a74cf8efc6015fd6d00e51ce3843c9b8f 100644 --- a/pybis/src/python/pybis/__init__.py +++ b/pybis/src/python/pybis/__init__.py @@ -1,7 +1,7 @@ name = 'pybis' __author__ = 'Swen Vermeul' __email__ = 'swen@ethz.ch' -__version__ = '1.10.2' +__version__ = '1.10.3' from . import pybis from .pybis import Openbis diff --git a/pybis/src/python/pybis/dataset.py b/pybis/src/python/pybis/dataset.py index ef6002322fa17ef09104cdebd70efee3a0c18662..fa99d564e6a6b736ea90f7099abab1c95b0c62ad 100644 --- a/pybis/src/python/pybis/dataset.py +++ b/pybis/src/python/pybis/dataset.py @@ -776,11 +776,16 @@ class DataSetDownloadQueue(): if chunk: # filter out keep-alive new chunks f.write(chunk) - if os.path.getsize(filename_dest) != int(file_size): + actual_file_size = os.path.getsize(filename_dest) + if actual_file_size != int(file_size): if self.collect_files_with_wrong_length: self.files_with_wrong_length.append(filename) else: - raise ValueError("File has the wrong length: {}".format(filename_dest)) + print ( + "WARNING! File {} has the wrong length: Expected: {} Actual size: {}".format( + filename_dest, int(file_size), actual_file_size) + ) + finally: self.download_queue.task_done() diff --git a/pybis/src/python/setup.py b/pybis/src/python/setup.py index b54537442f34c20e2960f837185e28c8e85910e2..a6507d023c035f02cbacc67a380f291980077d3b 100644 --- a/pybis/src/python/setup.py +++ b/pybis/src/python/setup.py @@ -11,7 +11,7 @@ with open("README.md", "r", encoding="utf-8") as fh: setup( name='PyBIS', - version= '1.10.2', + version= '1.10.3', author='Swen Vermeul • ID SIS • ETH Zürich', author_email='swen@ethz.ch', description='openBIS connection and interaction, optimized for using with Jupyter',