diff --git a/app/packs/src/apps/admin/textTemplates/TextTemplate.js b/app/packs/src/apps/admin/textTemplates/TextTemplate.js deleted file mode 100644 index bedf98c426..0000000000 --- a/app/packs/src/apps/admin/textTemplates/TextTemplate.js +++ /dev/null @@ -1,303 +0,0 @@ -import { AgGridReact } from 'ag-grid-react'; -import { cloneDeep } from 'lodash'; -import PropTypes from 'prop-types'; -import Delta from 'quill-delta'; -import React from 'react'; -import { Button, Form, Container, Col, InputGroup, Row } from 'react-bootstrap'; - -import QuillEditor from 'src/components/QuillEditor'; -import TextTemplateIcon from 'src/apps/admin/textTemplates/TextTemplateIcon'; - -function RemoveRowBtn({ removeRow, node }) { - const { data } = node; - - const btnClick = () => { - removeRow(data.name); - }; - - return ( - - ); -} - -RemoveRowBtn.propTypes = { - removeRow: PropTypes.func.isRequired, - // eslint-disable-next-line react/forbid-prop-types - node: PropTypes.object.isRequired, -}; - -function AddRowBtn({ addRow }) { - return ( - - ); -} - -AddRowBtn.propTypes = { - addRow: PropTypes.func.isRequired, -}; - -export default class TextTemplate extends React.Component { - constructor(props) { - super(props); - - this.state = { - selectedTemplate: null, - text: '', - icon: '' - }; - - this.reactQuillRef = React.createRef(); - - this.onSelectionChanged = this.onSelectionChanged.bind(this); - this.onGridReady = this.onGridReady.bind(this); - this.onCellValueChanged = this.onCellValueChanged.bind(this); - this.onChangeText = this.onChangeText.bind(this); - this.onChangeIcon = this.onChangeIcon.bind(this); - - this.saveTemplate = this.saveTemplate.bind(this); - this.removeRow = this.removeRow.bind(this); - this.addRow = this.addRow.bind(this); - - this.columnDefs = [ - { - field: 'name', - editable: true, - minWidth: 150, - onCellValueChanged: this.onCellValueChanged - }, - { - headerName: '', - colId: 'actions', - headerComponent: AddRowBtn, - headerComponentParams: { - addRow: this.addRow - }, - cellRenderer: RemoveRowBtn, - cellRendererParams: { - removeRow: this.removeRow, - }, - editable: false, - filter: false, - width: 35, - }, - ]; - } - - // eslint-disable-next-line camelcase - UNSAFE_componentWillReceiveProps(newProps) { - const { fetchedTemplates } = newProps; - const selectedRows = this.gridApi.getSelectedRows(); - if (selectedRows.length === 0) return; - - const selectedNameIdx = fetchedTemplates.findIndex(t => ( - t.name === selectedRows[0].name - )); - if (selectedNameIdx < 0) return; - - const newSelectedTemplate = cloneDeep(fetchedTemplates[selectedNameIdx]); - this.setState({ - selectedTemplate: cloneDeep(newSelectedTemplate), - text: newSelectedTemplate.data.text || '', - icon: newSelectedTemplate.data.icon || '' - }); - } - - componentDidUpdate() { - if (this.gridApi) { - this.gridApi.sizeColumnsToFit(); - } - } - - // eslint-disable-next-line class-methods-use-this - onGridReady(e) { - if (!e.api) return; - this.gridApi = e.api; - this.gridApi.sizeColumnsToFit(); - } - - onSelectionChanged() { - if (!this.gridApi) return; - - const selectedRows = this.gridApi.getSelectedRows(); - if (selectedRows.length === 0) return; - - const templateName = selectedRows[0].name; - const { fetchedTemplates } = this.props; - const selectedNameIdx = fetchedTemplates.findIndex(t => ( - t.name === templateName - )); - - if (selectedNameIdx >= 0) { - const selectedTemplate = cloneDeep(fetchedTemplates[selectedNameIdx]); - this.setState({ - selectedTemplate, - text: selectedTemplate.data.text || '', - icon: selectedTemplate.data.icon || '' - }); - } else { - const { fetchTemplate } = this.props; - fetchTemplate(templateName); - } - } - - onCellValueChanged(params) { - const { oldValue, newValue } = params; - const { fetchedTemplates, updateTemplate } = this.props; - const selectedNameIdx = fetchedTemplates.findIndex(t => ( - t.name === oldValue - )); - if (selectedNameIdx < 0) return; - - const selectedTemplate = cloneDeep(fetchedTemplates[selectedNameIdx]); - selectedTemplate.name = newValue; - updateTemplate(selectedTemplate); - } - - onChangeText(e) { - const { selectedTemplate } = this.state; - const { value } = e.target; - selectedTemplate.data.text = value; - - this.setState({ - text: value, - selectedTemplate - }); - } - - onChangeIcon(e) { - const { selectedTemplate } = this.state; - const { value } = e.target; - selectedTemplate.data.icon = value; - - this.setState({ icon: value, selectedTemplate }); - } - - saveTemplate() { - if (this.reactQuillRef.current == null) { - return; - } - - const quill = this.reactQuillRef.current; - const delta = quill.getContents(); - - // Quill automatically append a trailing newline, we don't want that - // Remove it !!! - const deltaLength = delta.length(); - const removeTrailingNewline = new Delta().retain(deltaLength - 1).delete(1); - const content = delta.compose(removeTrailingNewline); - - const selectedTemplate = cloneDeep(this.state.selectedTemplate); - selectedTemplate.data.ops = content.ops; - this.props.updateTemplate(selectedTemplate); - } - - removeRow(name) { - const { removeTemplate } = this.props; - removeTemplate(name); - this.setState({ selectedTemplate: null }); - } - - addRow() { - const { addTemplate } = this.props; - addTemplate(this.gridApi); - } - - handleInputChange = () => {} - - render() { - const { predefinedTemplateNames } = this.props; - const { selectedTemplate, text, icon } = this.state; - - return ( - - - -
-
- -
-
- - -
- - Preview - - -
- - Text - {}} - className='py-3' - /> - - - Icon - {}} - className='py-3' - /> - - - this.handleInputChange(event)} - /> - -
- -
- -
-
- ); - } -} - -TextTemplate.propTypes = { - predefinedTemplateNames: PropTypes.arrayOf(PropTypes.object), - // eslint-disable-next-line react/forbid-prop-types - fetchedTemplates: PropTypes.arrayOf(PropTypes.object), - fetchTemplate: PropTypes.func.isRequired, - addTemplate: PropTypes.func.isRequired, - updateTemplate: PropTypes.func.isRequired, - removeTemplate: PropTypes.func.isRequired, -}; - -TextTemplate.defaultProps = { - predefinedTemplateNames: [], - fetchedTemplates: [], -}; diff --git a/app/packs/src/apps/admin/textTemplates/TextTemplateContainer.js b/app/packs/src/apps/admin/textTemplates/TextTemplateContainer.js index 1cf6aabbb1..4a56e1ed06 100644 --- a/app/packs/src/apps/admin/textTemplates/TextTemplateContainer.js +++ b/app/packs/src/apps/admin/textTemplates/TextTemplateContainer.js @@ -1,103 +1,158 @@ import React from 'react'; +import { Container, Col, Row } from 'react-bootstrap'; + import TextTemplatesFetcher from 'src/fetchers/TextTemplatesFetcher'; -import TextTemplate from 'src/apps/admin/textTemplates/TextTemplate'; +import TextTemplateForm from 'src/apps/admin/textTemplates/TextTemplateForm'; +import TextTemplateSelector from 'src/apps/admin/textTemplates/TextTemplateSelector'; + export default class TextTemplateContainer extends React.Component { constructor(props) { super(props); this.state = { - predefinedTemplateNames: [], - fetchedTemplates: [], + templateNames: [], + fetchedTemplates: {}, + selectedTemplateName: null, }; this.addTemplate = this.addTemplate.bind(this); - this.fetchTemplate = this.fetchTemplate.bind(this); + this.renameTemplate = this.renameTemplate.bind(this); this.removeTemplate = this.removeTemplate.bind(this); this.updateTemplate = this.updateTemplate.bind(this); + this.selectTemplate = this.selectTemplate.bind(this); } componentDidMount() { TextTemplatesFetcher.fetchPredefinedTemplateNames().then((res) => { - const templateNames = res.map(n => ({ name: n })); - this.setState({ predefinedTemplateNames: templateNames }); + this.setState({ templateNames: res }); }); } addTemplate(gridApi) { - const { predefinedTemplateNames, fetchedTemplates } = this.state; + const { templateNames, fetchedTemplates } = this.state; this.setState({ - predefinedTemplateNames: [{ name: '' }, ...predefinedTemplateNames], - fetchedTemplates: [ - { name: '', data: {} }, - ...fetchedTemplates - ] + templateNames: ['', ...templateNames], + fetchedTemplates: { + ...fetchedTemplates, + '': { name: '', data: {} }, + }, + selectedTemplateName: '', }, () => { - if (!gridApi) return; - - gridApi.startEditingCell({ rowIndex: 0, colKey: 'name' }); + if (gridApi) { + gridApi.startEditingCell({ rowIndex: 0, colKey: 'name' }); + } }); } - fetchTemplate(name) { - TextTemplatesFetcher.fetchPredefinedTemplateByNames([name]).then((res) => { + selectTemplate(name) { + const { fetchedTemplates, selectedTemplateName } = this.state; + if (name === selectedTemplateName && fetchedTemplates[name]) return; + + if (fetchedTemplates[name]) { + this.setState({ selectedTemplateName: name }); + } else { + TextTemplatesFetcher.fetchPredefinedTemplateByNames([name]).then((res) => { + if (!res) return; + + const newTemplates = {}; + res.forEach((r) => newTemplates[r.name] = r); + + this.setState({ + fetchedTemplates: { + ...fetchedTemplates, + ...newTemplates, + }, + selectedTemplateName: name, + }); + }); + } + } + + removeTemplate(name) { + TextTemplatesFetcher.deletePredefinedTemplateByName(name).then((res) => { if (!res) return; - const { fetchedTemplates } = this.state; + const { templateNames, fetchedTemplates, selectedTemplateName } = this.state; + const newFetchedTemplates = { ...fetchedTemplates }; + delete newFetchedTemplates[name]; + this.setState({ - fetchedTemplates: [...fetchedTemplates].concat(res), + templateNames: templateNames.filter((n) => n !== name), + fetchedTemplates: newFetchedTemplates, + selectedTemplateName: selectedTemplateName === name ? null : selectedTemplateName, }); }); } - removeTemplate(name) { - TextTemplatesFetcher.deletePredefinedTemplateByName(name).then((res) => { + renameTemplate(oldName, newName) { + const { templateNames, fetchedTemplates, selectedTemplateName } = this.state; + const template = fetchedTemplates[oldName]; + + const newTemplate = {...template, name: newName}; + const newFetchedTemplates = { ...fetchedTemplates, [newName]: newTemplate }; + delete newFetchedTemplates[oldName]; + + TextTemplatesFetcher.updatePredefinedTemplates(newTemplate).then((res) => { if (!res) return; - const { fetchedTemplates, predefinedTemplateNames } = this.state; this.setState({ - fetchedTemplates: fetchedTemplates.filter(t => t.name !== name), - predefinedTemplateNames: predefinedTemplateNames.filter(t => ( - t.name !== name - )) + templateNames: templateNames.with(templateNames.indexOf(oldName), newName), + fetchedTemplates: newFetchedTemplates, + selectedTemplateName: selectedTemplateName === oldName ? newName : selectedTemplateName, }); }); } updateTemplate(template) { const { fetchedTemplates } = this.state; - const selectedNameIdx = fetchedTemplates.findIndex(t => ( - t.id === template.id - )); - if (selectedNameIdx < 0) return; - TextTemplatesFetcher.updatePredefinedTemplates(template).then((res) => { if (!res) return; - const newTemplates = fetchedTemplates.map((t, idx) => ( - (idx === selectedNameIdx) ? res : t - )); - this.setState({ fetchedTemplates: newTemplates }); + this.setState({ + fetchedTemplates: { + ...fetchedTemplates, + [template.name]: template + } + }); }); } render() { const { - predefinedTemplateNames, + templateNames, fetchedTemplates, + selectedTemplateName, } = this.state; + const selectedTemplate = fetchedTemplates[selectedTemplateName]; + return ( - + + + + + + + {selectedTemplate ? ( + + ) : ( +

Select a template to edit

+ )} + +
+
); } } diff --git a/app/packs/src/apps/admin/textTemplates/TextTemplateForm.js b/app/packs/src/apps/admin/textTemplates/TextTemplateForm.js new file mode 100644 index 0000000000..a94e23966d --- /dev/null +++ b/app/packs/src/apps/admin/textTemplates/TextTemplateForm.js @@ -0,0 +1,129 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import Delta from 'quill-delta'; +import { Button, Form, InputGroup } from 'react-bootstrap'; + +import QuillEditor from 'src/components/QuillEditor'; +import TextTemplateIcon from 'src/apps/admin/textTemplates/TextTemplateIcon'; + + +export default class TextTemplateForm extends React.Component { + constructor(props) { + super(props); + + this.state = { + text: props.selectedTemplate?.data?.text ?? '', + icon: props.selectedTemplate?.data?.icon ?? '', + }; + + this.reactQuillRef = React.createRef(); + + this.onChangeText = this.onChangeText.bind(this); + this.onChangeIcon = this.onChangeIcon.bind(this); + this.saveTemplate = this.saveTemplate.bind(this); + + } + + componentDidUpdate(prevProps) { + const { selectedTemplate } = this.props; + if (selectedTemplate !== prevProps.selectedTemplate) { + this.setState({ + text: selectedTemplate?.data?.text ?? '', + icon: selectedTemplate?.data?.icon ?? '', + }); + } + } + + onChangeText(e) { + const { value } = e.target; + this.setState({ text: value }); + } + + onChangeIcon(e) { + const { value } = e.target; + this.setState({ icon: value }); + } + + saveTemplate() { + if (this.reactQuillRef.current == null) { + return; + } + + const quill = this.reactQuillRef.current; + const delta = quill.getContents(); + + // Quill automatically append a trailing newline, we don't want that + // Remove it !!! + const deltaLength = delta.length(); + const removeTrailingNewline = new Delta().retain(deltaLength - 1).delete(1); + const { ops } = delta.compose(removeTrailingNewline); + + const { selectedTemplate, updateTemplate } = this.props; + const { text, icon } = this.state; + updateTemplate({ + ...selectedTemplate, + data: { + ops, + text: text.trim() == '' ? null : text.trim(), + icon: icon.trim() == '' ? null : icon.trim(), + } + }); + } + + render() { + const { selectedTemplate } = this.props; + const { text, icon } = this.state; + + return ( +
+

Editing '{selectedTemplate.name}'

+ + Preview + + +
+ + Text + + + + Icon + + + + {}} + /> + +
+ +
+ ); + } +} + +TextTemplateForm.propTypes = { + selectedTemplate: PropTypes.object, + updateTemplate: PropTypes.func.isRequired, +}; + +TextTemplateForm.defaultProps = { + selectedTemplate: null, +}; diff --git a/app/packs/src/apps/admin/textTemplates/TextTemplateIcon.js b/app/packs/src/apps/admin/textTemplates/TextTemplateIcon.js index 6766e368e7..3f3736a947 100644 --- a/app/packs/src/apps/admin/textTemplates/TextTemplateIcon.js +++ b/app/packs/src/apps/admin/textTemplates/TextTemplateIcon.js @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; const TextTemplateIcon = ({ template, iconClass }) => { - if (!template) return ; + if (!template) return null; const { data, name } = template; @@ -12,7 +12,7 @@ const TextTemplateIcon = ({ template, iconClass }) => { ); } - const text = (data || {}).text || name; + const text = data?.text ?? name ?? ''; return ( {text.toUpperCase()} diff --git a/app/packs/src/apps/admin/textTemplates/TextTemplateSelector.js b/app/packs/src/apps/admin/textTemplates/TextTemplateSelector.js new file mode 100644 index 0000000000..2863a21868 --- /dev/null +++ b/app/packs/src/apps/admin/textTemplates/TextTemplateSelector.js @@ -0,0 +1,128 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types'; +import { Button } from 'react-bootstrap'; +import { AgGridReact } from 'ag-grid-react'; + +function RemoveRowBtn({ removeRow, node }) { + const { data } = node; + + const btnClick = () => { + removeRow(data.name); + }; + + return ( + + ); +} + +RemoveRowBtn.propTypes = { + removeRow: PropTypes.func.isRequired, + // eslint-disable-next-line react/forbid-prop-types + node: PropTypes.object.isRequired, +}; + +function AddRowBtn({ addRow }) { + return ( + + ); +} + +AddRowBtn.propTypes = { + addRow: PropTypes.func.isRequired, +}; + +class TextTemplateSelector extends Component { + constructor(props) { + super(props); + } + + componentDidMount() { + this.gridApi?.sizeColumnsToFit() + } + + componentDidUpdate() { + this.gridApi?.sizeColumnsToFit() + } + + onSelectionChanged = ({api}) => { + const selectedRows = api.getSelectedRows(); + if (selectedRows.length === 0) return; + + const { selectTemplate } = this.props; + selectTemplate(selectedRows[0].name); + } + + onGridReady = ({api}) => { + this.gridApi = api; + } + + render() { + const { + templateNames, + addTemplate, + renameTemplate, + removeTemplate + } = this.props; + + const columnDefs = [ + { + field: 'name', + editable: true, + minWidth: 150, + onCellValueChanged: ({ oldValue, newValue }) => { + renameTemplate(oldValue, newValue); + } + }, + { + headerName: '', + colId: 'actions', + headerComponent: AddRowBtn, + headerComponentParams: { + addRow: addTemplate, + }, + cellRenderer: RemoveRowBtn, + cellRendererParams: { + removeRow: removeTemplate, + }, + editable: false, + filter: false, + width: 35, + }, + ]; + + return ( +
+
+ ({ name: n }))} + className='fs-6' + rowHeight={35} + /> +
+
+ ); + } +}; + +export default TextTemplateSelector; diff --git a/app/packs/src/apps/mydb/collections/CollectionSubtree.js b/app/packs/src/apps/mydb/collections/CollectionSubtree.js index 17b6486487..90588b3187 100644 --- a/app/packs/src/apps/mydb/collections/CollectionSubtree.js +++ b/app/packs/src/apps/mydb/collections/CollectionSubtree.js @@ -15,11 +15,7 @@ export default class CollectionSubtree extends React.Component { super(props); this.state = { - isRemote: props.isRemote, - label: props.root.label, - inventoryPrefix: props.root.inventory_prefix, selected: false, - root: props.root, visible: false } @@ -29,48 +25,31 @@ export default class CollectionSubtree extends React.Component { this.handleTakeOwnership = this.handleTakeOwnership.bind(this) } - componentDidMount() { UIStore.listen(this.onChange); } - // eslint-disable-next-line camelcase - UNSAFE_componentWillReceiveProps(nextProps) { - this.setState({ - root: nextProps.root, - label: nextProps.root.label, - inventoryPrefix: nextProps.root.inventory_prefix - }); - } - componentWillUnmount() { UIStore.unlisten(this.onChange); } onChange(state) { - if (state.currentCollection) { - const visible = this.isVisible(this.state.root, state) - const { root } = this.state; + const { root } = this.props; + if (state.currentCollection) { + const visible = this.isVisible(root, state) const selectedCol = ( - state.currentCollection.id == root.id && - state.currentCollection.is_synchronized == root.is_synchronized - ) || ( - state.currentCollection.id == root.id && - state.currentCollection.isRemote == root.isRemote + state.currentCollection.id == root.id + && ( + state.currentCollection.is_synchronized == root.is_synchronized + || state.currentCollection.isRemote == root.isRemote ) + ); - if (selectedCol) { - this.setState({ - selected: true, - visible - }); - } else { - this.setState({ - selected: false, + this.setState({ + selected: selectedCol, visible - }); - } + }); } } @@ -85,68 +64,58 @@ export default class CollectionSubtree extends React.Component { } children() { - return this.state.root.children || []; - } - - hasChildren() { - return this.children().length > 0; + const { root } = this.props; + return root.children || []; } canTakeOwnership() { - const { root, isRemote } = this.state; + const { root, isRemote } = this.props; const isTakeOwnershipAllowed = root.permission_level === 5; const isSync = !!((root.sharer && root.user && root.user.type !== 'Group')); return (isRemote || isSync) && isTakeOwnershipAllowed; } handleTakeOwnership() { - const { root: { sharer, id } } = this.state; + const { root: { sharer, id } } = this.props; const isSync = !!sharer; CollectionActions.takeOwnership({ id, isSync }); } handleClick(e) { - const { fakeRoot } = this.props; - if (fakeRoot) { - e.stopPropagation(); - return; - } - - const { root } = this.state; - let { visible } = this.state; + const { root } = this.props; + const { visible } = this.state; const uiState = UIStore.getState(); + this.setState({ visible: visible || this.isVisible(root, uiState) }); - visible = visible || this.isVisible(root, uiState); - this.setState({ visible }); - let collectionID = 'all'; if (root.label === 'All' && root.is_locked) { Aviator.navigate(`/collection/all/${this.urlForCurrentElement()}`, { silent: true }); - collectionShow({ params: { collectionID } }); + collectionShow({ params: { collectionID: 'all' } }); return; } - const url = (this.props.root.sharer) + + const url = (root.sharer) ? `/scollection/${root.id}/${this.urlForCurrentElement()}` : `/collection/${root.id}/${this.urlForCurrentElement()}`; Aviator.navigate(url, { silent: true }); - collectionID = this.state.root.id; - const collShow = this.props.root.sharer ? scollectionShow : collectionShow; - collShow({ params: { collectionID } }); + + const collShow = root.sharer ? scollectionShow : collectionShow; + collShow({ params: { collectionID: root.id } }); } urlForCurrentElement() { const { currentElement } = ElementStore.getState(); if (currentElement) { - if (currentElement.isNew) { - return `${currentElement.type}/new`; - } - return `${currentElement.type}/${currentElement.id}`; + return currentElement.isNew + ? `${currentElement.type}/new` + : `${currentElement.type}/${currentElement.id}`; } return ''; } toggleExpansion(e) { e.stopPropagation() - let { visible, root } = this.state + const { root } = this.props; + let { visible } = this.state visible = !visible this.setState({ visible: visible }) @@ -156,7 +125,7 @@ export default class CollectionSubtree extends React.Component { } else { let descendantIds = root.descendant_ids ? root.descendant_ids - : root.children.map(function (s) { return s.id }) + : root.children.map((s) => s.id); descendantIds.push(root.id) visibleRootsIds = visibleRootsIds.filter(x => descendantIds.indexOf(x) == -1) } @@ -167,11 +136,12 @@ export default class CollectionSubtree extends React.Component { } render() { - const { label, root, inventoryPrefix, visible, selected } = this.state; + const { root, isRemote } = this.props; + const { visible, selected } = this.state; const sharedUsers = root.sync_collections_users; const children = this.children(); - const showGatePushButton = root && root.is_locked && label === 'chemotion-repository.net'; + const showGatePushButton = root && root.is_locked && root.label === 'chemotion-repository.net'; return (
@@ -181,13 +151,13 @@ export default class CollectionSubtree extends React.Component { onClick={this.handleClick} > {showGatePushButton && ()} - {label} - {inventoryPrefix && ( + {root.label} + {root.inventory_prefix && ( Inventory Label} > - {inventoryPrefix} + {root.inventory_prefix} )} {this.canTakeOwnership() && ( @@ -201,7 +171,7 @@ export default class CollectionSubtree extends React.Component { )} - {this.hasChildren() && ( + {children.length > 0 && ( {children.map((child) => (
  • - +
  • ))} diff --git a/app/packs/src/apps/mydb/elements/details/NumeralInput.js b/app/packs/src/apps/mydb/elements/details/NumeralInput.js index d789bce3b5..30a007dd86 100644 --- a/app/packs/src/apps/mydb/elements/details/NumeralInput.js +++ b/app/packs/src/apps/mydb/elements/details/NumeralInput.js @@ -13,12 +13,13 @@ export default class NumeralInput extends Component { }; } - // eslint-disable-next-line camelcase - UNSAFE_componentWillReceiveProps(nextProps) { - const { value } = nextProps; - this.setState({ - numeralValue: this._convertValueToNumeralValue(value) - }); + componentDidUpdate(prevProps) { + const { value } = this.props; + if (value !== prevProps.value) { + this.setState({ + numeralValue: this._convertValueToNumeralValue(value) + }); + } } _convertValueToNumeralValue(value) { diff --git a/app/packs/src/apps/mydb/elements/details/NumeralInputWithUnitsCompo.js b/app/packs/src/apps/mydb/elements/details/NumeralInputWithUnitsCompo.js index 5f29f7edb7..e1bc89da43 100644 --- a/app/packs/src/apps/mydb/elements/details/NumeralInputWithUnitsCompo.js +++ b/app/packs/src/apps/mydb/elements/details/NumeralInputWithUnitsCompo.js @@ -1,5 +1,6 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; +import { isEqual } from 'lodash'; import { Form, InputGroup, Button } from 'react-bootstrap'; import { metPreConv, metPrefSymbols } from 'src/utilities/metricPrefix'; @@ -22,9 +23,12 @@ export default class NumeralInputWithUnitsCompo extends Component { this.forceUpdate(); } - UNSAFE_componentWillReceiveProps(nextProps) { - const { value, block } = nextProps; - this.setState({ value, block }); + componentDidUpdate(prevProps) { + const { value, block } = this.props; + // isEqual considers NaN to be equal to NaN + if (!isEqual(value, prevProps.value) || block !== prevProps.block) { + this.setState({ value, block }); + } } shouldComponentUpdate(nextProps, nextState) { diff --git a/app/packs/src/apps/mydb/elements/details/reactions/ReactionDetails.js b/app/packs/src/apps/mydb/elements/details/reactions/ReactionDetails.js index 98f039469b..165ea1f7cc 100644 --- a/app/packs/src/apps/mydb/elements/details/reactions/ReactionDetails.js +++ b/app/packs/src/apps/mydb/elements/details/reactions/ReactionDetails.js @@ -96,20 +96,13 @@ export default class ReactionDetails extends Component { } } - // eslint-disable-next-line camelcase - UNSAFE_componentWillReceiveProps(nextProps) { - const { reaction } = this.state; - const nextReaction = nextProps.reaction; - - if (nextReaction.id !== reaction.id || - nextReaction.updated_at !== reaction.updated_at || - nextReaction.reaction_svg_file !== reaction.reaction_svg_file || - nextReaction.changed || nextReaction.editedSample) { - this.setState(prevState => ({ ...prevState, reaction: nextReaction })); + componentDidUpdate(prevProps) { + const { reaction } = this.props; + if (reaction.id !== prevProps.reaction.id) { + this.setState({ reaction }); } } - shouldComponentUpdate(nextProps, nextState) { const reactionFromNextProps = nextProps.reaction; const reactionFromNextState = nextState.reaction; diff --git a/app/packs/src/apps/mydb/elements/details/reactions/ReactionDetailsMainProperties.js b/app/packs/src/apps/mydb/elements/details/reactions/ReactionDetailsMainProperties.js index 404c8beb84..150cc39938 100644 --- a/app/packs/src/apps/mydb/elements/details/reactions/ReactionDetailsMainProperties.js +++ b/app/packs/src/apps/mydb/elements/details/reactions/ReactionDetailsMainProperties.js @@ -20,30 +20,18 @@ import { permitOn } from 'src/components/common/uis'; export default class ReactionDetailsMainProperties extends Component { constructor(props) { super(props); - const { temperature } = props && props.reaction; + this.state = { showTemperatureChart: false, - temperature, }; + this.toggleTemperatureChart = this.toggleTemperatureChart.bind(this); this.updateTemperature = this.updateTemperature.bind(this); - this.temperatureUnit = props.reaction.temperature.valueUnit; - } - - // eslint-disable-next-line camelcase - UNSAFE_componentWillReceiveProps(nextProps) { - this.setState({ - temperature: nextProps.reaction.temperature, - }); - - this.temperatureUnit = nextProps.reaction.temperature.valueUnit; } updateTemperature(newData) { - const { temperature } = this.state; - temperature.data = newData; - this.setState({ temperature }); - this.props.onInputChange('temperatureData', temperature); + const { reaction: { temperature } } = this.props; + this.props.onInputChange('temperatureData', { ...temperature, data: newData }); } toggleTemperatureChart() { @@ -52,42 +40,18 @@ export default class ReactionDetailsMainProperties extends Component { } changeUnit() { - const index = Reaction.temperature_unit.indexOf(this.temperatureUnit); - const unit = Reaction.temperature_unit[(index + 1) % 3]; + const { reaction: { temperature } } = this.props; + + const units = Reaction.temperature_unit; + const index = units.indexOf(temperature.valueUnit); + const unit = units[(index + 1) % units.length]; this.props.onInputChange('temperatureUnit', unit); } - render() { const { reaction, onInputChange } = this.props; - const temperatureTooltip = ( - Show temperature chart - ); - - const temperatureDisplay = reaction.temperature_display; - const { showTemperatureChart, temperature } = this.state; - const tempUnitLabel = `Temperature (${this.temperatureUnit})`; - - let TempChartRow = ; - if (showTemperatureChart) { - TempChartRow = ( - - - - - - - - - ); - } + const { temperature } = reaction; + const { showTemperatureChart } = this.state; return ( <> @@ -126,7 +90,9 @@ export default class ReactionDetailsMainProperties extends Component { Temperature - + Show temperature chart + )}> - - {TempChartRow} - + + {showTemperatureChart && ( + + + + + + + + + )} ); } diff --git a/app/packs/src/apps/mydb/elements/details/reactions/analysesTab/ReactionDetailsContainers.js b/app/packs/src/apps/mydb/elements/details/reactions/analysesTab/ReactionDetailsContainers.js index d6814949dd..02af5d1b52 100644 --- a/app/packs/src/apps/mydb/elements/details/reactions/analysesTab/ReactionDetailsContainers.js +++ b/app/packs/src/apps/mydb/elements/details/reactions/analysesTab/ReactionDetailsContainers.js @@ -60,15 +60,13 @@ const nmrMsg = (reaction, container) => { export default class ReactionDetailsContainers extends Component { constructor(props) { - super(); - const { reaction } = props; + super(props); + this.state = { - reaction, activeContainer: UIStore.getState().reaction.activeAnalysis }; this.containerRefs = {}; - this.handleChange = this.handleChange.bind(this); this.handleAdd = this.handleAdd.bind(this); this.handleRemove = this.handleRemove.bind(this); this.handleUndo = this.handleUndo.bind(this); @@ -100,16 +98,8 @@ export default class ReactionDetailsContainers extends Component { } } - // eslint-disable-next-line camelcase - UNSAFE_componentWillReceiveProps(nextProps) { - this.setState({ - reaction: nextProps.reaction, - }); - } - handleChange = () => { - const { handleReactionChange } = this.props; - const { reaction } = this.state; + const { reaction, handleReactionChange } = this.props; handleReactionChange(reaction); }; @@ -120,15 +110,13 @@ export default class ReactionDetailsContainers extends Component { } handleUndo(container) { - const { handleReactionChange } = this.props; - const { reaction } = this.state; + const { reaction, handleReactionChange } = this.props; container.is_deleted = false; handleReactionChange(reaction, { schemaChanged: false }); } handleAdd() { - const { handleReactionChange } = this.props; - const { reaction } = this.state; + const { reaction, handleReactionChange } = this.props; const container = Container.buildEmpty(); container.container_type = 'analysis'; container.extended_metadata.content = { ops: [{ insert: '' }] }; @@ -218,9 +206,7 @@ export default class ReactionDetailsContainers extends Component { handleRemove(container) { - const { handleReactionChange } = this.props; - const { reaction } = this.state; - + const { reaction, handleReactionChange } = this.props; container.is_deleted = true; handleReactionChange(reaction, { schemaChanged: false }); } @@ -249,8 +235,8 @@ export default class ReactionDetailsContainers extends Component { } render() { - const { reaction, activeContainer } = this.state; - const { readOnly } = this.props; + const { activeContainer } = this.state; + const { reaction, readOnly } = this.props; const containerHeader = (container) => { let kind = container.extended_metadata.kind || ''; @@ -371,7 +357,9 @@ export default class ReactionDetailsContainers extends Component { > - {container.is_deleted ? containerHeaderDeleted(container) : containerHeader(container)} + {container.is_deleted + ? containerHeaderDeleted(container) + : containerHeader(container)} diff --git a/app/packs/src/apps/mydb/elements/details/reactions/propertiesTab/ReactionDetailsProperties.js b/app/packs/src/apps/mydb/elements/details/reactions/propertiesTab/ReactionDetailsProperties.js index 5895b61eea..c763996dec 100644 --- a/app/packs/src/apps/mydb/elements/details/reactions/propertiesTab/ReactionDetailsProperties.js +++ b/app/packs/src/apps/mydb/elements/details/reactions/propertiesTab/ReactionDetailsProperties.js @@ -16,18 +16,11 @@ import { EditUserLabels } from 'src/components/UserLabels'; export default class ReactionDetailsProperties extends Component { constructor(props) { super(props); - props.reaction.convertDurationDisplay(); this.handleOnReactionChange = this.handleOnReactionChange.bind(this); this.handleOnSolventSelect = this.handleOnSolventSelect.bind(this); } - // eslint-disable-next-line camelcase - UNSAFE_componentWillReceiveProps(nextProps) { - if (!nextProps.reaction) { return; } - nextProps.reaction.convertDurationDisplay(); - } - handleOnReactionChange(reaction) { this.props.onReactionChange(reaction); } diff --git a/app/packs/src/apps/mydb/elements/details/reactions/schemeTab/ReactionDetailsDuration.js b/app/packs/src/apps/mydb/elements/details/reactions/schemeTab/ReactionDetailsDuration.js index 38177dde7d..f4dab39dd6 100644 --- a/app/packs/src/apps/mydb/elements/details/reactions/schemeTab/ReactionDetailsDuration.js +++ b/app/packs/src/apps/mydb/elements/details/reactions/schemeTab/ReactionDetailsDuration.js @@ -8,18 +8,11 @@ import { copyToClipboard } from 'src/utilities/clipboard'; export default class ReactionDetailsDuration extends Component { constructor(props) { super(props); - props.reaction.convertDurationDisplay(); this.setCurrentTime = this.setCurrentTime.bind(this); this.copyToDuration = this.copyToDuration.bind(this); this.handleDurationChange = this.handleDurationChange.bind(this); } - // eslint-disable-next-line camelcase - UNSAFE_componentWillReceiveProps(nextProps) { - if (!nextProps.reaction) { return; } - nextProps.reaction.convertDurationDisplay(); - } - setCurrentTime(type) { const currentTime = new Date().toLocaleString('en-GB').split(', ').join(' '); const { reaction } = this.props; diff --git a/app/packs/src/apps/mydb/elements/details/reactions/schemeTab/ReactionDetailsScheme.js b/app/packs/src/apps/mydb/elements/details/reactions/schemeTab/ReactionDetailsScheme.js index c10c2b3d89..61a3c780a4 100644 --- a/app/packs/src/apps/mydb/elements/details/reactions/schemeTab/ReactionDetailsScheme.js +++ b/app/packs/src/apps/mydb/elements/details/reactions/schemeTab/ReactionDetailsScheme.js @@ -40,11 +40,8 @@ export default class ReactionDetailsScheme extends Component { constructor(props) { super(props); - const { reaction } = props; - const textTemplate = TextTemplateStore.getState().reactionDescription; this.state = { - reaction, lockEquivColumn: false, reactionDescTemplate: textTemplate.toJS(), }; @@ -76,12 +73,6 @@ export default class ReactionDetailsScheme extends Component { TextTemplateActions.fetchTextTemplates('reactionDescription'); } - // eslint-disable-next-line camelcase - UNSAFE_componentWillReceiveProps(nextProps) { - const { reaction } = nextProps; - this.setState({ reaction }); - } - componentWillUnmount() { TextTemplateStore.unlisten(this.handleTemplateChange); this.resetGasPhaseStore(); @@ -93,7 +84,7 @@ export default class ReactionDetailsScheme extends Component { } dropSample(srcSample, tagMaterial, tagGroup, extLabel, isNewSample = false) { - const { reaction } = this.state; + const { reaction } = this.props; let splitSample; if (srcSample instanceof Molecule || isNewSample) { @@ -165,11 +156,12 @@ export default class ReactionDetailsScheme extends Component { } renderRoleSelect() { - const { role } = this.props.reaction; + const { reaction } = this.props; + const { role } = reaction; return (