Commit 45a79659 authored by pei-chi.huang's avatar pei-chi.huang
Browse files

add a switch button for Equiv, to fix the Equiv connection between material and reactants

parent 417da543
......@@ -213,7 +213,7 @@ class Material extends Component {
<NumeralInputWithUnitsCompo
precision={4}
value={material.equivalent}
disabled={((material.reference || false) && material.equivalent) !== false}
disabled={(((material.reference || false) && material.equivalent) !== false) || this.props.lockEquivColumn}
onChange={e => this.handleEquivalentChange(e)}
/>
);
......@@ -692,4 +692,5 @@ Material.propTypes = {
isDragging: PropTypes.bool,
canDrop: PropTypes.bool,
isOver: PropTypes.bool,
lockEquivColumn: PropTypes.bool.isRequired
};
import React from 'react';
import PropTypes from 'prop-types';
import { Button, Glyphicon } from 'react-bootstrap';
import { Button, Glyphicon, Tooltip, OverlayTrigger } from 'react-bootstrap';
import VirtualizedSelect from 'react-virtualized-select';
import Material from './Material';
import MaterialCalculations from './MaterialCalculations';
......@@ -15,11 +15,10 @@ import { reagents_kombi } from './staticDropdownOptions/reagents_kombi';
const MaterialGroup = ({
materials, materialGroup, deleteMaterial, onChange,
showLoadingColumn, reaction, addDefaultSolvent, headIndex,
dropMaterial, dropSample,
dropMaterial, dropSample, switchEquiv, lockEquivColumn
}) => {
const contents = [];
let index = headIndex;
materials.forEach((material) => {
index += 1;
contents.push((
......@@ -34,6 +33,7 @@ const MaterialGroup = ({
index={index}
dropMaterial={dropMaterial}
dropSample={dropSample}
lockEquivColumn={lockEquivColumn}
/>
));
......@@ -69,12 +69,34 @@ const MaterialGroup = ({
showLoadingColumn={showLoadingColumn}
reaction={reaction}
addDefaultSolvent={addDefaultSolvent}
switchEquiv={switchEquiv}
lockEquivColumn={lockEquivColumn}
/>
);
};
const switchEquivTooltip = () => (
<Tooltip id="assign_button">Lock/unlock Equiv <br /> for target amounts</Tooltip>
);
const SwitchEquivButton = (lockEquivColumn, switchEquiv) => {
return (
<OverlayTrigger placement="top" overlay={switchEquivTooltip()} >
<Button
id="lock_equiv_column_btn"
bsSize="xsmall"
bsStyle={lockEquivColumn ? 'warning' : 'light'}
onClick={switchEquiv}
>
<i className={lockEquivColumn ? 'fa fa-lock' : 'fa fa-unlock'} />
</Button>
</OverlayTrigger>
);
};
const GeneralMaterialGroup = ({
contents, materialGroup, showLoadingColumn, reaction, addDefaultSolvent
contents, materialGroup, showLoadingColumn, reaction, addDefaultSolvent,
switchEquiv, lockEquivColumn
}) => {
const isReactants = materialGroup === 'reactants';
let headers = {
......@@ -171,8 +193,7 @@ const GeneralMaterialGroup = ({
{ !isReactants && <th /> }
{ showLoadingColumn && !isReactants && <th>{headers.loading}</th> }
{ !isReactants && <th>{headers.concn}</th> }
{ !isReactants && <th>{headers.eq}</th> }
{ !isReactants && <th /> }
{ !isReactants && <th>{headers.eq} {!isReactants && materialGroup !== 'products' && SwitchEquivButton(lockEquivColumn, switchEquiv)}</th> }
</tr>
</thead>
<tbody>
......@@ -183,6 +204,7 @@ const GeneralMaterialGroup = ({
);
};
const SolventsMaterialGroup = ({
contents, materialGroup, reaction, addDefaultSolvent
}) => {
......@@ -265,6 +287,8 @@ MaterialGroup.propTypes = {
addDefaultSolvent: PropTypes.func.isRequired,
dropMaterial: PropTypes.func.isRequired,
dropSample: PropTypes.func.isRequired,
switchEquiv: PropTypes.func.isRequired,
lockEquivColumn: PropTypes.bool.isRequired
};
GeneralMaterialGroup.propTypes = {
......@@ -272,7 +296,9 @@ GeneralMaterialGroup.propTypes = {
showLoadingColumn: PropTypes.bool,
reaction: PropTypes.instanceOf(Reaction).isRequired,
addDefaultSolvent: PropTypes.func.isRequired,
contents: PropTypes.arrayOf(PropTypes.shape).isRequired
contents: PropTypes.arrayOf(PropTypes.shape).isRequired,
switchEquiv: PropTypes.func.isRequired,
lockEquivColumn: PropTypes.bool.isRequired
};
SolventsMaterialGroup.propTypes = {
......@@ -282,13 +308,13 @@ SolventsMaterialGroup.propTypes = {
contents: PropTypes.arrayOf(PropTypes.shape).isRequired
};
MaterialGroup.defaultProps = {
showLoadingColumn: false
showLoadingColumn: false,
};
GeneralMaterialGroup.defaultProps = {
showLoadingColumn: false
showLoadingColumn: false,
};
export { MaterialGroup, GeneralMaterialGroup, SolventsMaterialGroup };
......@@ -56,7 +56,7 @@ class MaterialGroupContainer extends Component {
const {
materials, materialGroup, showLoadingColumn, headIndex,
isOver, canDrop, connectDropTarget,
deleteMaterial, onChange, reaction, dropSample, dropMaterial,
deleteMaterial, onChange, reaction, dropSample, dropMaterial, switchEquiv, lockEquivColumn
} = this.props;
const style = {
padding: '2px 5px',
......@@ -81,6 +81,8 @@ class MaterialGroupContainer extends Component {
dropSample={dropSample}
dropMaterial={dropMaterial}
headIndex={headIndex}
switchEquiv={switchEquiv}
lockEquivColumn={lockEquivColumn}
/>
</div>,
);
......@@ -106,6 +108,8 @@ MaterialGroupContainer.propTypes = {
isOver: PropTypes.bool.isRequired,
canDrop: PropTypes.bool.isRequired,
connectDropTarget: PropTypes.func.isRequired,
switchEquiv: PropTypes.func.isRequired,
lockEquivColumn: PropTypes.bool.isRequired
};
MaterialGroupContainer.defaultProps = {
......
......@@ -22,13 +22,14 @@ export default class ReactionDetailsScheme extends Component {
constructor(props) {
super(props);
let { reaction } = props;
this.state = { reaction };
this.state = { reaction, lockEquivColumn: false };
this.onChangeRole = this.onChangeRole.bind(this);
this.renderRole = this.renderRole.bind(this);
this.addSampleToDescription = this.addSampleToDescription.bind(this);
this.dropMaterial = this.dropMaterial.bind(this);
this.dropSample = this.dropSample.bind(this);
this.switchEquiv = this.switchEquiv.bind(this);
}
componentWillReceiveProps(nextProps) {
......@@ -71,6 +72,11 @@ export default class ReactionDetailsScheme extends Component {
onInputChange('role', value);
}
switchEquiv() {
const { lockEquivColumn } = this.state;
this.setState({ lockEquivColumn: !lockEquivColumn });
}
renderGPDnD() {
const { reaction } = this.props;
return (
......@@ -385,6 +391,7 @@ export default class ReactionDetailsScheme extends Component {
updatedSamplesForAmountChange(samples, updatedSample, materialGroup) {
const { referenceMaterial } = this.props.reaction;
const { lockEquivColumn } = this.state;
return samples.map((sample) => {
if (referenceMaterial) {
if (sample.id === updatedSample.id) {
......@@ -395,19 +402,45 @@ export default class ReactionDetailsScheme extends Component {
this.checkMassPolymer(referenceMaterial, updatedSample, massAnalyses);
return sample;
}
sample.equivalent = sample.amount_mol / referenceMaterial.amount_mol;
} else {
if (!lockEquivColumn) {
sample.equivalent = sample.amount_mol / referenceMaterial.amount_mol;
} else {
if (referenceMaterial && referenceMaterial.amount_value) {
sample.setAmountAndNormalizeToGram({
value: sample.equivalent * referenceMaterial.amount_mol,
unit: 'mol',
});
} else if (sample.amount_value) {
sample.setAmountAndNormalizeToGram({
value: sample.equivalent * sample.amount_mol,
unit: 'mol'
});
}
}
}
sample.equivalent = sample.amount_mol / referenceMaterial.amount_mol;
} else {
if (materialGroup === 'products') {
sample.equivalent = 0.0;
}else {
sample.equivalent = 1.0;
} else {
sample.equivalent = 1.0; // to be check (Paggy)
}
}
} else {
// calculate equivalent, don't touch real amount
sample.equivalent = sample.amount_mol / referenceMaterial.amount_mol;
if (!lockEquivColumn || materialGroup === 'products' ) {
// calculate equivalent, don't touch real amount
sample.equivalent = sample.amount_mol / referenceMaterial.amount_mol;
} else {
//sample.amount_mol = sample.equivalent * referenceMaterial.amount_mol;
if (referenceMaterial && referenceMaterial.amount_value) {
sample.setAmountAndNormalizeToGram({
value: sample.equivalent * referenceMaterial.amount_mol,
unit: 'mol',
});
}
}
}
if (materialGroup === 'products' && (sample.equivalent < 0.0 || sample.equivalent > 1.0 || isNaN(sample.equivalent) || !isFinite(sample.equivalent))) {
......@@ -511,7 +544,7 @@ export default class ReactionDetailsScheme extends Component {
}
render() {
const { reaction } = this.state;
const { reaction, lockEquivColumn } = this.state;
const minPadding = { padding: '1px 2px 2px 0px' };
if (reaction.editedSample !== undefined) {
if (reaction.editedSample.amountType === 'target') {
......@@ -556,6 +589,8 @@ export default class ReactionDetailsScheme extends Component {
dropSample={this.dropSample}
showLoadingColumn={!!reaction.hasPolymers()}
onChange={changeEvent => this.handleMaterialsChange(changeEvent)}
switchEquiv={this.switchEquiv}
lockEquivColumn={this.state.lockEquivColumn}
headIndex={0}
/>
</ListGroupItem>
......@@ -570,6 +605,8 @@ export default class ReactionDetailsScheme extends Component {
dropSample={this.dropSample}
showLoadingColumn={!!reaction.hasPolymers()}
onChange={changeEvent => this.handleMaterialsChange(changeEvent)}
switchEquiv={this.toggleLockEquivColumn}
lockEquivColumn={lockEquivColumn}
headIndex={headReactants}
/>
</ListGroupItem>
......@@ -584,6 +621,8 @@ export default class ReactionDetailsScheme extends Component {
dropSample={this.dropSample}
showLoadingColumn={!!reaction.hasPolymers()}
onChange={changeEvent => this.handleMaterialsChange(changeEvent)}
switchEquiv={this.toggleLockEquivColumn}
lockEquivColumn={this.state.lockEquivColumn}
headIndex={0}
/>
</ListGroupItem>
......@@ -600,6 +639,8 @@ export default class ReactionDetailsScheme extends Component {
dropSample={this.dropSample}
showLoadingColumn={!!reaction.hasPolymers()}
onChange={changeEvent => this.handleMaterialsChange(changeEvent)}
switchEquiv={this.toggleLockEquivColumn}
lockEquivColumn={this.state.lockEquivColumn}
headIndex={0}
/>
</div>
......
require 'rails_helper'
feature 'Reaction Equiv Spec' do
let!(:user) { create(:user, first_name: 'Hallo', last_name: 'Complat') }
let!(:m1) { create(:molecule, molecular_weight: 171.03448) }
let!(:m2) { create(:molecule, molecular_weight: 133.15058) }
let!(:r1) { create(:residue, custom_info:({"formula"=>"CH","loading"=>"0.96","loading_type"=>"mass","polymer_type"=>"polystyrene","external_loading"=>"2"})) }
let!(:r2) { create(:residue, custom_info:({"formula"=>"CH","loading"=>"0.78","loading_type"=>"mass","polymer_type"=>"polystyrene","external_loading"=>"2"})) }
let!(:mr1) { create(:molecule, molecular_weight: 85.0813) }
let!(:mr2) { create(:molecule, molecular_weight: 330.2360496) }
let(:material) { create(:sample, name:'Material', target_amount_value: 7.15, creator: user, collections: user.collections, molecule: m1) }
let(:reactant1) { create(:sample, name:'Reactant1', target_amount_value: 5.435, creator: user, collections: user.collections) }
let(:reactant2) { create(:sample, name:'Reactant2', target_amount_value: 3.123, creator: user, collections: user.collections) }
let(:solvent) { create(:sample, name:'Solvent',creator: user, collections: user.collections) }
let(:product) { create(:sample, name:'Product',real_amount_value: 4.671, creator: user, collections: user.collections, molecule: m2) }
let(:reaction) { create(:reaction, short_label: 'Reaction 1', creator: user, collections: user.collections) }
let(:material_r) { create(:sample, name:'Material', target_amount_value: 4.000, creator: user, collections: user.collections, molecule: mr1, residues: [r1]) }
let(:product_r) { create(:sample, name:'Product',real_amount_value: 3.600, creator: user, collections: user.collections, molecule: mr2, residues: [r2]) }
let(:reaction_r) { create(:reaction, short_label: 'Reaction 2', creator: user, collections: user.collections) }
background do
user.confirmed_at = Time.now
user.save
sign_in(user)
fp = Rails.root.join("public", "images", "molecules")
`ln -s #{Rails.root.join("spec", "fixtures", "images", "molecule.svg")} #{fp} ` unless File.exist?(Rails.root.join(fp, "molecule.svg"))
end
describe 'reaction amount changed with fixed Equiv' do
before do
user.collections.each { |c| CollectionsSample.find_or_create_by!(sample: material, collection: c) }
user.collections.each { |c| CollectionsSample.find_or_create_by!(sample: reactant1, collection: c) }
user.collections.each { |c| CollectionsSample.find_or_create_by!(sample: reactant2, collection: c) }
user.collections.each { |c| CollectionsSample.find_or_create_by!(sample: solvent, collection: c) }
user.collections.each { |c| CollectionsSample.find_or_create_by!(sample: product, collection: c) }
user.collections.each { |c| CollectionsReaction.find_or_create_by!(reaction: reaction, collection: c) }
ReactionsStartingMaterialSample.create!(reaction: reaction, sample: material, reference: true, equivalent: 1)
ReactionsReactantSample.create!(reaction: reaction, sample: reactant1, equivalent: 2)
ReactionsSolventSample.create!(reaction: reaction, sample: solvent, equivalent: 1)
ReactionsProductSample.create!(reaction: reaction, sample: product, equivalent: 1)
end
scenario 'change material amount', js: true do
find('.tree-view', text: 'chemotion.net').click
first('i.icon-reaction').click
find('span.isvg').click
material_new_amount = 5000
tab_pane = find('div#reaction-detail-tab', match: :first, wait: 10).click
tab_scheme = tab_pane.first('div.tab-content').click
switch_equiv_button = tab_pane.first('button#lock_equiv_column_btn').click
material_field = tab_scheme.first('span.input-group').find_all('input').first
material_orig_amount = material_field.value.to_i
reactants_table = find('th', text: 'Reactants').find(:xpath, '../../../..')
reactants_field = reactants_table.first('tr.general-material').first("span.input-group").find('input')
reactants_orig_amount = reactants_field.value.to_i
material_field.click
material_field.set(material_new_amount)
material_field.click
reactants_field.click
reactants_new_amount = reactants_field.value.to_i
expect_result = (material_new_amount / material.molecule.molecular_weight * 2) * reactant1.molecule.molecular_weight
expect(reactants_new_amount).to eq(expect_result.to_i)
end
end
describe 'reaction amount changed with fixed Equiv contains residues' do
before do
user.collections.each { |c| CollectionsSample.find_or_create_by!(sample: material_r, collection: c) }
user.collections.each { |c| CollectionsSample.find_or_create_by!(sample: reactant1, collection: c) }
user.collections.each { |c| CollectionsSample.find_or_create_by!(sample: reactant2, collection: c) }
user.collections.each { |c| CollectionsSample.find_or_create_by!(sample: solvent, collection: c) }
user.collections.each { |c| CollectionsSample.find_or_create_by!(sample: product_r, collection: c) }
user.collections.each { |c| CollectionsReaction.find_or_create_by!(reaction: reaction_r, collection: c) }
ReactionsStartingMaterialSample.create!(reaction: reaction_r, sample: material_r, reference: true, equivalent: 1)
ReactionsReactantSample.create!(reaction: reaction_r, sample: reactant1, equivalent: 2)
ReactionsReactantSample.create!(reaction: reaction_r, sample: reactant2, equivalent: 2)
ReactionsSolventSample.create!(reaction: reaction_r, sample: solvent, equivalent: 1)
ReactionsProductSample.create!(reaction: reaction_r, sample: product_r, equivalent: 0.73)
end
scenario 'change material amount for contains residues', js: true do
find('.tree-view', text: 'chemotion.net').click
first('i.icon-reaction').click
find('span.isvg').click
material_new_amount = 8000
tab_pane = find('div#reaction-detail-tab', match: :first, wait: 10).click
tab_scheme = tab_pane.first('div.tab-content').click
switch_equiv_button = tab_pane.first('button#lock_equiv_column_btn').click
material_field = tab_scheme.first('span.input-group').find_all('input').first
material_orig_amount = material_field.value.to_i
reactants_table = find('th', text: 'Reactants').find(:xpath, '../../../..')
reactants_field = reactants_table.first('tr.general-material').first("span.input-group").find('input')
reactants_orig_amount = reactants_field.value.to_i
material_field.click
material_field.set(material_new_amount)
material_field.click
reactants_field.click
reactants_new_amount = reactants_field.value.to_i
expect_result = (material_new_amount * material_r.residues[0].custom_info['loading'].to_f / 1000) * 2 * reactant1.molecule.molecular_weight
expect(reactants_new_amount).to eq(expect_result.to_i)
end
end
end
......@@ -43,35 +43,6 @@ feature 'Reaction management' do
ReactionsSolventSample.create!(reaction: reaction, sample: solvent, equivalent: 1)
ReactionsProductSample.create!(reaction: reaction, sample: product, equivalent: 1)
end
scenario 'Yield 100%', js: true do
find('.tree-view', text: 'chemotion.net').click
first('i.icon-reaction').click
find('span.isvg').click
material_amount = 6800
pane = first('div#elements-tabs-pane-0', wait: 10).click
tab_pane = pane.find('div#reaction-detail-tab').click
#tab_pane = pane.first('div.panel-detail')
tab_scheme = tab_pane.first('div.tab-content').click
material_field = tab_scheme.first('span.input-group').find_all('input').first
material_field.click
material_field.set(material_amount)
material_field.click
maxAmount = material_amount / material.molecule.molecular_weight * product.molecule.molecular_weight
product_table = find('th', text: 'Products').find(:xpath, '../../../..')
prod_field = product_table.first('tr.general-material').first("span.input-group").find('input')
prod_field.click
prod_field.set(maxAmount.round(2))
prod_field.click
mol_m = material_field.value.to_f / material.molecule.molecular_weight
mol_p = prod_field.value.to_f / product.molecule.molecular_weight
current_yield = ( mol_p / mol_m * 100 ).to_i.to_s + '%'
yield_field = product_table.find_all('input').last
yield_field.click
expect(yield_field.value).to eq('100%')
expect(page).to have_content('max theoretical mass')
end
scenario 'Yield 50%', js: true do
find('.tree-view', text: 'chemotion.net').click
......@@ -79,8 +50,7 @@ feature 'Reaction management' do
find('span.isvg').click
material_amount = 6800
pane = first('div#elements-tabs-pane-0', wait: 10).click
tab_pane = pane.find('div#reaction-detail-tab').click
tab_pane = find('div#reaction-detail-tab', match: :first, wait: 10).click
tab_scheme = tab_pane.first('div.tab-content').click
material_field = tab_scheme.first('span.input-group').find_all('input').first
material_field.click
......@@ -126,8 +96,7 @@ feature 'Reaction management' do
find('span.isvg').click
material_amount = 3780
pane = first('div#elements-tabs-pane-0', wait: 10).click
tab_pane = pane.find('div#reaction-detail-tab').click
tab_pane = find('div#reaction-detail-tab', match: :first, wait: 10).click
tab_scheme = tab_pane.first('div.tab-content').click
material_field = tab_scheme.first('span.input-group').find_all('input').first
material_field.click
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment