diff --git a/.gitignore b/.gitignore
index 04bc33b34..8e5e32451 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,4 @@ npm-debug.log
*.offsets
yarn-error.log
/yarn.lock
+/debug.log
diff --git a/js/components/datasets/crossReferenceDialog.js b/js/components/datasets/crossReferenceDialog.js
index d6dc9ec95..9f719cc88 100644
--- a/js/components/datasets/crossReferenceDialog.js
+++ b/js/components/datasets/crossReferenceDialog.js
@@ -16,7 +16,7 @@ import {
} from './redux/dispatchActions';
import { Button } from '../common/Inputs/Button';
import classNames from 'classnames';
-import { useDisableUserInteraction } from '../helpers/useEnableUserInteracion';
+// import { useDisableUserInteraction } from '../helpers/useEnableUserInteracion';
import { colourList, DatasetMoleculeView } from './datasetMoleculeView';
import { NglContext } from '../nglView/nglProvider';
import { VIEWS } from '../../constants/constants';
@@ -132,7 +132,7 @@ export const CrossReferenceDialog = memo(
const { getNglView } = useContext(NglContext);
const stage = getNglView(VIEWS.MAJOR_VIEW) && getNglView(VIEWS.MAJOR_VIEW).stage;
- const disableUserInteraction = useDisableUserInteraction();
+ // const disableUserInteraction = useDisableUserInteraction();
const moleculeList = useSelector(state => getCrossReferenceCompoundListByCompoundName(state));
const isLoadingCrossReferenceScores = useSelector(state => state.datasetsReducers.isLoadingCrossReferenceScores);
@@ -272,7 +272,7 @@ export const CrossReferenceDialog = memo(
onClick={() =>
dispatch(handleAllLigandsOfCrossReferenceDialog(isLigandOn, moleculeList, stage))
}
- disabled={disableUserInteraction}
+ disabled={false}
>
L
@@ -289,7 +289,7 @@ export const CrossReferenceDialog = memo(
onClick={() =>
dispatch(removeOrAddAllHitProteinsOfList(isProteinOn, moleculeList, stage))
}
- disabled={disableUserInteraction}
+ disabled={false}
>
P
@@ -305,7 +305,7 @@ export const CrossReferenceDialog = memo(
[classes.contColButtonHalfSelected]: isComplexOn === null
})}
onClick={() => dispatch(removeOrAddAllComplexesOfList(isComplexOn, moleculeList, stage))}
- disabled={disableUserInteraction}
+ disabled={false}
>
C
@@ -336,6 +336,11 @@ export const CrossReferenceDialog = memo(
previousItemData={previousData}
nextItemData={nextData}
removeOfAllSelectedTypes={removeOfAllSelectedTypes}
+ L={ligandList.includes(data.id)}
+ P={proteinList.includes(data.id)}
+ C={complexList.includes(data.id)}
+ S={false}
+ V={false}
/>
);
})}
diff --git a/js/components/datasets/datasetMoleculeList.js b/js/components/datasets/datasetMoleculeList.js
index 828b1b2bd..ed8c5b157 100644
--- a/js/components/datasets/datasetMoleculeList.js
+++ b/js/components/datasets/datasetMoleculeList.js
@@ -14,7 +14,7 @@ import {
IconButton,
ButtonGroup
} from '@material-ui/core';
-import React, { useState, useEffect, memo, useRef, useContext, useCallback } from 'react';
+import React, { useState, useEffect, memo, useRef, useContext } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { DatasetMoleculeView, colourList } from './datasetMoleculeView';
import InfiniteScroll from 'react-infinite-scroller';
@@ -23,7 +23,7 @@ import { Panel } from '../common/Surfaces/Panel';
import { ComputeSize } from '../../utils/computeSize';
import { VIEWS } from '../../constants/constants';
import { NglContext } from '../nglView/nglProvider';
-import { useDisableUserInteraction } from '../helpers/useEnableUserInteracion';
+// import { useDisableUserInteraction } from '../helpers/useEnableUserInteracion';
import classNames from 'classnames';
import {
addDatasetLigand,
@@ -34,7 +34,9 @@ import {
removeDatasetComplex,
addDatasetSurface,
removeDatasetSurface,
- autoHideDatasetDialogsOnScroll
+ autoHideDatasetDialogsOnScroll,
+ moveMoleculeInspirationsSettings,
+ removeAllSelectedDatasetMolecules
} from './redux/dispatchActions';
import { setFilterDialogOpen, setSearchStringOfCompoundSet } from './redux/actions';
import { DatasetFilter } from './datasetFilter';
@@ -44,6 +46,8 @@ import { debounce } from 'lodash';
import { InspirationDialog } from './inspirationDialog';
import { CrossReferenceDialog } from './crossReferenceDialog';
import { AlertModal } from '../common/Modal/AlertModal';
+import { hideAllSelectedMolecules } from '../preview/molecule/redux/dispatchActions';
+import { getMoleculeList } from '../preview/molecule/redux/selectors';
import { setSelectedAllByType, setDeselectedAllByType } from './redux/actions';
const useStyles = makeStyles(theme => ({
@@ -226,7 +230,10 @@ export const DatasetMoleculeList = memo(
const filterRef = useRef();
let joinedMoleculeLists = moleculeLists[datasetID] || [];
- const disableUserInteraction = useDisableUserInteraction();
+ const getJoinedMoleculeList = useSelector(state => getMoleculeList(state));
+ const inspirationMoleculeDataList = useSelector(state => state.datasetsReducers.allInspirationMoleculeDataList);
+
+ // const disableUserInteraction = useDisableUserInteraction();
// TODO Reset Infinity scroll
@@ -258,6 +265,15 @@ export const DatasetMoleculeList = memo(
const selectedAll = useRef(false);
+ const objectsInView = useSelector(state => state.nglReducers.objectsInView) || {};
+
+ const proteinListMolecule = useSelector(state => state.selectionReducers.proteinList);
+ const complexListMolecule = useSelector(state => state.selectionReducers.complexList);
+ const fragmentDisplayListMolecule = useSelector(state => state.selectionReducers.fragmentDisplayList);
+ const surfaceListMolecule = useSelector(state => state.selectionReducers.surfaceList);
+ const densityListMolecule = useSelector(state => state.selectionReducers.densityList);
+ const vectorOnListMolecule = useSelector(state => state.selectionReducers.vectorOnList);
+
const ligandList = useSelector(state => state.datasetsReducers.ligandLists[datasetID]);
const proteinList = useSelector(state => state.datasetsReducers.proteinLists[datasetID]);
const complexList = useSelector(state => state.datasetsReducers.complexLists[datasetID]);
@@ -280,31 +296,30 @@ export const DatasetMoleculeList = memo(
surface: removeDatasetSurface
};
+ const removeOfAllSelectedTypesOfInspirations = () => {
+ let molecules = [...getJoinedMoleculeList, ...inspirationMoleculeDataList];
+ dispatch(hideAllSelectedMolecules(stage, [...molecules]));
+ };
+
const removeOfAllSelectedTypes = () => {
- ligandList?.forEach(moleculeID => {
- const foundedMolecule = joinedMoleculeLists?.find(mol => mol.id === moleculeID);
- dispatch(
- removeDatasetLigand(stage, foundedMolecule, colourList[foundedMolecule.id % colourList.length], datasetID)
- );
- });
- proteinList?.forEach(moleculeID => {
- const foundedMolecule = joinedMoleculeLists?.find(mol => mol.id === moleculeID);
- dispatch(
- removeDatasetHitProtein(stage, foundedMolecule, colourList[foundedMolecule.id % colourList.length], datasetID)
- );
- });
- complexList?.forEach(moleculeID => {
- const foundedMolecule = joinedMoleculeLists?.find(mol => mol.id === moleculeID);
- dispatch(
- removeDatasetComplex(stage, foundedMolecule, colourList[foundedMolecule.id % colourList.length], datasetID)
- );
- });
- surfaceList?.forEach(moleculeID => {
- const foundedMolecule = joinedMoleculeLists?.find(mol => mol.id === moleculeID);
- dispatch(
- removeDatasetSurface(stage, foundedMolecule, colourList[foundedMolecule.id % colourList.length], datasetID)
- );
- });
+ dispatch(removeAllSelectedDatasetMolecules(stage));
+ };
+
+ const moveSelectedMoleculeInspirationsSettings = (data, newItemData) => (dispatch, getState) => {
+ dispatch(
+ moveMoleculeInspirationsSettings(
+ data,
+ newItemData,
+ stage,
+ objectsInView,
+ fragmentDisplayListMolecule,
+ proteinListMolecule,
+ complexListMolecule,
+ surfaceListMolecule,
+ densityListMolecule,
+ vectorOnListMolecule
+ )
+ );
};
// TODO "currentMolecules" do not need to correspondent to selections in {type}List
@@ -552,7 +567,7 @@ export const DatasetMoleculeList = memo(
[classes.contColButtonSelected]: isLigandOn
})}
onClick={() => onButtonToggle('ligand')}
- disabled={disableUserInteraction}
+ disabled={false}
>
L
@@ -566,7 +581,7 @@ export const DatasetMoleculeList = memo(
[classes.contColButtonSelected]: isProteinOn
})}
onClick={() => onButtonToggle('protein')}
- disabled={disableUserInteraction}
+ disabled={false}
>
P
@@ -581,7 +596,7 @@ export const DatasetMoleculeList = memo(
[classes.contColButtonSelected]: isComplexOn
})}
onClick={() => onButtonToggle('complex')}
- disabled={disableUserInteraction}
+ disabled={false}
>
C
@@ -646,6 +661,13 @@ export const DatasetMoleculeList = memo(
previousItemData={index > 0 && array[index - 1]}
nextItemData={index < array?.length && array[index + 1]}
removeOfAllSelectedTypes={removeOfAllSelectedTypes}
+ removeOfAllSelectedTypesOfInspirations={removeOfAllSelectedTypesOfInspirations}
+ moveSelectedMoleculeInspirationsSettings={moveSelectedMoleculeInspirationsSettings}
+ L={ligandList.includes(data.id)}
+ P={proteinList.includes(data.id)}
+ C={complexList.includes(data.id)}
+ S={surfaceList.includes(data.id)}
+ V={false}
/>
))}
diff --git a/js/components/datasets/datasetMoleculeView.js b/js/components/datasets/datasetMoleculeView.js
index d834c70d1..43aa58a57 100644
--- a/js/components/datasets/datasetMoleculeView.js
+++ b/js/components/datasets/datasetMoleculeView.js
@@ -10,7 +10,7 @@ import SVGInline from 'react-svg-inline';
import classNames from 'classnames';
import { VIEWS } from '../../constants/constants';
import { NglContext } from '../nglView/nglProvider';
-import { useDisableUserInteraction } from '../helpers/useEnableUserInteracion';
+// import { useDisableUserInteraction } from '../helpers/useEnableUserInteracion';
import {
addDatasetLigand,
removeDatasetLigand,
@@ -23,6 +23,7 @@ import {
clickOnInspirations,
getDatasetMoleculeID
} from './redux/dispatchActions';
+
import { base_url } from '../routes/constants';
import { api } from '../../utils/api';
import { isAnyInspirationTurnedOn, getFilteredDatasetMoleculeList } from './redux/selectors';
@@ -31,13 +32,19 @@ import {
removeMoleculeFromCompoundsOfDatasetToBuy,
setCrossReferenceCompoundName,
setIsOpenCrossReferenceDialog,
+ setInspirationFragmentList,
+ setInspirationMoleculeDataList,
setSelectedAll,
setDeselectedAll
} from './redux/actions';
import { centerOnLigandByMoleculeID } from '../../reducers/ngl/dispatchActions';
import { ArrowDownward, ArrowUpward, MyLocation } from '@material-ui/icons';
-import { isNumber, isString } from 'lodash';
+import { isString } from 'lodash';
import { SvgTooltip } from '../common';
+import { OBJECT_TYPE } from '../nglView/constants';
+import { getRepresentationsByType } from '../nglView/generatingObjects';
+import { getMolImage } from '../preview/molecule/redux/dispatchActions';
+import { MOL_TYPE } from '../preview/molecule/redux/constants';
const useStyles = makeStyles(theme => ({
container: {
@@ -252,36 +259,38 @@ export const DatasetMoleculeView = memo(
index,
previousItemData,
nextItemData,
- removeOfAllSelectedTypes
+ removeOfAllSelectedTypes,
+ removeOfAllSelectedTypesOfInspirations,
+ moveSelectedMoleculeInspirationsSettings,
+ L, P, C, S, V
}) => {
const selectedAll = useRef(false);
const currentID = (data && data.id) || undefined;
const classes = useStyles();
const ref = useRef(null);
-
const dispatch = useDispatch();
const compoundsToBuyList = useSelector(state => state.datasetsReducers.compoundsToBuyDatasetMap[datasetID]);
- const ligandList = useSelector(state => state.datasetsReducers.ligandLists[datasetID]);
- const proteinList = useSelector(state => state.datasetsReducers.proteinLists[datasetID]);
- const complexList = useSelector(state => state.datasetsReducers.complexLists[datasetID]);
- const surfaceList = useSelector(state => state.datasetsReducers.surfaceLists[datasetID]);
+ const allInspirations = useSelector(state => state.datasetsReducers.allInspirations);
+
const datasets = useSelector(state => state.datasetsReducers.datasets);
const filteredScoreProperties = useSelector(state => state.datasetsReducers.filteredScoreProperties);
const filter = useSelector(state => state.selectionReducers.filter);
const isAnyInspirationOn = useSelector(state =>
isAnyInspirationTurnedOn(state, (data && data.computed_inspirations) || [])
);
+
const filteredDatasetMoleculeList = useSelector(state => getFilteredDatasetMoleculeList(state, datasetID));
+ const objectsInView = useSelector(state => state.nglReducers.objectsInView) || {};
const [image, setImage] = useState(img_data_init);
const { getNglView } = useContext(NglContext);
const stage = getNglView(VIEWS.MAJOR_VIEW) && getNglView(VIEWS.MAJOR_VIEW).stage;
- const isLigandOn = (currentID && ligandList.includes(currentID)) || false;
- const isProteinOn = (currentID && proteinList.includes(currentID)) || false;
- const isComplexOn = (currentID && complexList.includes(currentID)) || false;
- const isSurfaceOn = (currentID && surfaceList.includes(currentID)) || false;
+ const isLigandOn = L;
+ const isProteinOn = P;
+ const isComplexOn = C;
+ const isSurfaceOn = S;
const isCheckedToBuy = (currentID && compoundsToBuyList && compoundsToBuyList.includes(currentID)) || false;
@@ -290,7 +299,7 @@ export const DatasetMoleculeView = memo(
const areArrowsVisible = isLigandOn || isProteinOn || isComplexOn || isSurfaceOn;
- const disableUserInteraction = useDisableUserInteraction();
+ // const disableUserInteraction = useDisableUserInteraction();
const refOnCancelImage = useRef();
const getRandomColor = () => colourList[currentID % colourList.length];
@@ -307,45 +316,20 @@ export const DatasetMoleculeView = memo(
// componentDidMount
useEffect(() => {
- if (/*refOnCancelImage.current === undefined && */ data && data.smiles) {
- let onCancel = () => {};
- let url = new URL(`${base_url}/viewer/img_from_smiles/`);
- const params = {
- width: imageHeight,
- height: imageWidth,
- smiles: data.smiles
- };
- Object.keys(params).forEach(key => url.searchParams.append(key, params[key]));
-
- api({
- url,
- cancel: onCancel
- })
- .then(response => {
- if (response.data !== undefined) {
- setImage(response.data);
- }
- })
- .catch(error => {
- throw new Error(error);
- });
- refOnCancelImage.current = onCancel;
- }
- return () => {
- if (refOnCancelImage) {
- refOnCancelImage.current();
- }
- };
+ dispatch(getMolImage(data.smiles, MOL_TYPE.DATASET, imageHeight, imageWidth)).then(i => {
+ setImage(i);
+ });
}, [
- complexList,
+ C,
currentID,
data,
- ligandList,
+ L,
imageHeight,
imageWidth,
data.smiles,
data.id,
- filteredDatasetMoleculeList
+ filteredDatasetMoleculeList,
+ dispatch
]);
const svg_image = (
@@ -505,35 +489,84 @@ export const DatasetMoleculeView = memo(
const moveSelectedMoleculeSettings = (newItemData, datasetIdOfMolecule) => {
if (newItemData) {
if (isLigandOn) {
- dispatch(addDatasetLigand(stage, newItemData, colourToggle, datasetIdOfMolecule));
+ let representations = getRepresentationsByType(objectsInView, data, OBJECT_TYPE.LIGAND, datasetID);
+ dispatch(addDatasetLigand(stage, newItemData, colourToggle, datasetIdOfMolecule, representations));
}
if (isProteinOn) {
- dispatch(addDatasetHitProtein(stage, newItemData, colourToggle, datasetIdOfMolecule));
+ let representations = getRepresentationsByType(objectsInView, data, OBJECT_TYPE.PROTEIN, datasetID);
+ dispatch(addDatasetHitProtein(stage, newItemData, colourToggle, datasetIdOfMolecule, representations));
}
if (isComplexOn) {
- dispatch(addDatasetComplex(stage, newItemData, colourToggle, datasetIdOfMolecule));
+ let representations = getRepresentationsByType(objectsInView, data, OBJECT_TYPE.COMPLEX, datasetID);
+ dispatch(addDatasetComplex(stage, newItemData, colourToggle, datasetIdOfMolecule, representations));
}
if (isSurfaceOn) {
- dispatch(addDatasetSurface(stage, newItemData, colourToggle, datasetIdOfMolecule));
+ let representations = getRepresentationsByType(objectsInView, data, OBJECT_TYPE.SURFACE, datasetID);
+ dispatch(addDatasetSurface(stage, newItemData, colourToggle, datasetIdOfMolecule, representations));
}
}
};
+ const scrollToElement = element => {
+ element.scrollIntoView({
+ behavior: 'auto',
+ block: 'nearest',
+ inline: 'nearest'
+ });
+ };
+
+ const getInspirationsForMol = (datasetId, molId) => {
+ let inspirations = [];
+
+ if (allInspirations && allInspirations.hasOwnProperty(datasetId) && allInspirations[datasetId].hasOwnProperty(molId)) {
+ inspirations = allInspirations[datasetId][molId];
+ }
+
+ return inspirations;
+ };
+
const handleClickOnDownArrow = () => {
+ const refNext = ref.current.nextSibling;
+ scrollToElement(refNext);
+
removeOfAllSelectedTypes();
+ removeOfAllSelectedTypesOfInspirations();
+
const nextItem = (nextItemData.hasOwnProperty('molecule') && nextItemData.molecule) || nextItemData;
const nextDatasetID = (nextItemData.hasOwnProperty('datasetID') && nextItemData.datasetID) || datasetID;
+ const moleculeTitleNext = nextItem && nextItem.name;
+
+ const inspirations = getInspirationsForMol(datasetID, nextItem.id);
+ dispatch(setInspirationMoleculeDataList(inspirations));
moveSelectedMoleculeSettings(nextItem, nextDatasetID);
+ dispatch(moveSelectedMoleculeInspirationsSettings(data, nextItem));
+ dispatch(setCrossReferenceCompoundName(moleculeTitleNext));
+ if (setRef && ref.current) {
+ setRef(refNext);
+ }
};
const handleClickOnUpArrow = () => {
+ const refPrevious = ref.current.previousSibling;
+ scrollToElement(refPrevious);
+
removeOfAllSelectedTypes();
+ removeOfAllSelectedTypesOfInspirations();
+
const previousItem =
(previousItemData.hasOwnProperty('molecule') && previousItemData.molecule) || previousItemData;
const previousDatasetID =
(previousItemData.hasOwnProperty('datasetID') && previousItemData.datasetID) || datasetID;
+ const moleculeTitlePrev = previousItem && previousItem.name;
+ const inspirations = getInspirationsForMol(datasetID, previousItem.id);
+ dispatch(setInspirationMoleculeDataList(inspirations));
moveSelectedMoleculeSettings(previousItem, previousDatasetID);
+ dispatch(moveSelectedMoleculeInspirationsSettings(data, previousItem));
+ dispatch(setCrossReferenceCompoundName(moleculeTitlePrev));
+ if (setRef && ref.current) {
+ setRef(refPrevious);
+ }
};
const moleculeTitle = data && data.name;
@@ -618,7 +651,7 @@ export const DatasetMoleculeView = memo(
onClick={() => {
dispatch(centerOnLigandByMoleculeID(stage, getDatasetMoleculeID(datasetID, currentID)));
}}
- disabled={disableUserInteraction || !isLigandOn}
+ disabled={false || !isLigandOn}
>
@@ -646,7 +679,7 @@ export const DatasetMoleculeView = memo(
onProtein(true);
onComplex(true);
}}
- disabled={disableUserInteraction}
+ disabled={false}
>
A
@@ -660,7 +693,7 @@ export const DatasetMoleculeView = memo(
[classes.contColButtonSelected]: isLigandOn
})}
onClick={() => onLigand()}
- disabled={disableUserInteraction}
+ disabled={false}
>
L
@@ -674,7 +707,7 @@ export const DatasetMoleculeView = memo(
[classes.contColButtonSelected]: isProteinOn
})}
onClick={() => onProtein()}
- disabled={disableUserInteraction}
+ disabled={false}
>
P
@@ -689,7 +722,7 @@ export const DatasetMoleculeView = memo(
[classes.contColButtonSelected]: isComplexOn
})}
onClick={() => onComplex()}
- disabled={disableUserInteraction}
+ disabled={false}
>
C
@@ -703,7 +736,7 @@ export const DatasetMoleculeView = memo(
[classes.contColButtonSelected]: isSurfaceOn
})}
onClick={() => onSurface()}
- disabled={disableUserInteraction}
+ disabled={false}
>
S
@@ -722,14 +755,14 @@ export const DatasetMoleculeView = memo(
clickOnInspirations({
datasetID,
currentID,
- computed_inspirations: data && data.computed_inspirations
+ computed_inspirations: getInspirationsForMol(datasetID, currentID)
})
);
if (setRef) {
setRef(ref.current);
}
}}
- disabled={disableUserInteraction}
+ disabled={false}
>
F
@@ -751,7 +784,7 @@ export const DatasetMoleculeView = memo(
setRef(ref.current);
}
}}
- disabled={disableUserInteraction}
+ disabled={false}
>
X
@@ -812,7 +845,7 @@ export const DatasetMoleculeView = memo(
@@ -822,7 +855,7 @@ export const DatasetMoleculeView = memo(
diff --git a/js/components/datasets/inspirationDialog.js b/js/components/datasets/inspirationDialog.js
index 3ad1f5de5..f124f75c3 100644
--- a/js/components/datasets/inspirationDialog.js
+++ b/js/components/datasets/inspirationDialog.js
@@ -24,14 +24,13 @@ import {
removeDensity,
removeVector
} from '../preview/molecule/redux/dispatchActions';
-import { loadInspirationMoleculesDataList } from './redux/dispatchActions';
import MoleculeView from '../preview/molecule/moleculeView';
import { moleculeProperty } from '../preview/molecule/helperConstants';
import { debounce } from 'lodash';
-import { setInspirationMoleculeDataList, setIsOpenInspirationDialog } from './redux/actions';
+import { setIsOpenInspirationDialog } from './redux/actions';
import { Button } from '../common/Inputs/Button';
import classNames from 'classnames';
-import { useDisableUserInteraction } from '../helpers/useEnableUserInteracion';
+// import { useDisableUserInteraction } from '../helpers/useEnableUserInteracion';
import { colourList } from './datasetMoleculeView';
import { NglContext } from '../nglView/nglProvider';
import { VIEWS } from '../../constants/constants';
@@ -143,8 +142,6 @@ export const InspirationDialog = memo(
const { getNglView } = useContext(NglContext);
const stage = getNglView(VIEWS.MAJOR_VIEW) && getNglView(VIEWS.MAJOR_VIEW).stage;
- const inspirationFragmentList = useSelector(state => state.datasetsReducers.inspirationFragmentList);
-
const isLoadingInspirationListOfMolecules = useSelector(
state => state.datasetsReducers.isLoadingInspirationListOfMolecules
);
@@ -158,17 +155,7 @@ export const InspirationDialog = memo(
const vectorOnList = useSelector(state => state.selectionReducers.vectorOnList);
const dispatch = useDispatch();
- const disableUserInteraction = useDisableUserInteraction();
-
- useEffect(() => {
- if (inspirationFragmentList && inspirationFragmentList.length > 0) {
- dispatch(loadInspirationMoleculesDataList(inspirationFragmentList)).catch(error => {
- throw new Error(error);
- });
- } else {
- dispatch(setInspirationMoleculeDataList([]));
- }
- }, [dispatch, inspirationFragmentList]);
+ // const disableUserInteraction = useDisableUserInteraction();
let debouncedFn;
@@ -393,7 +380,7 @@ export const InspirationDialog = memo(
[classes.contColButtonHalfSelected]: isLigandOn === null
})}
onClick={() => onButtonToggle('ligand')}
- disabled={disableUserInteraction}
+ disabled={false}
>
L
@@ -408,7 +395,7 @@ export const InspirationDialog = memo(
[classes.contColButtonHalfSelected]: isProteinOn === null
})}
onClick={() => onButtonToggle('protein')}
- disabled={disableUserInteraction}
+ disabled={false}
>
P
@@ -424,7 +411,7 @@ export const InspirationDialog = memo(
[classes.contColButtonHalfSelected]: isComplexOn === null
})}
onClick={() => onButtonToggle('complex')}
- disabled={disableUserInteraction}
+ disabled={false}
>
C
@@ -454,6 +441,11 @@ export const InspirationDialog = memo(
nextItemData={nextData}
removeOfAllSelectedTypes={removeOfAllSelectedTypes}
selectMoleculeSite={selectMoleculeSite}
+ L={ligandList.includes(molecule.id)}
+ P={proteinList.includes(molecule.id)}
+ C={complexList.includes(molecule.id)}
+ S={surfaceList.includes(molecule.id)}
+ V={vectorOnList.includes(molecule.id)}
/>
);
})}
diff --git a/js/components/datasets/redux/actions.js b/js/components/datasets/redux/actions.js
index 75d7f144a..53cbcbe7e 100644
--- a/js/components/datasets/redux/actions.js
+++ b/js/components/datasets/redux/actions.js
@@ -26,6 +26,11 @@ export const setMoleculeListIsLoading = isLoading => ({
payload: isLoading
});
+export const replaceAllMoleculeLists = allMoleculeLists => ({
+ type: constants.REPLACE_ALL_MOLECULELISTS,
+ payload: allMoleculeLists
+});
+
export const setFilterSettings = (datasetID, filter) => ({
type: constants.SET_FILTER_SETTINGS,
payload: { datasetID, filter }
@@ -249,11 +254,26 @@ export const setInspirationMoleculeDataList = (moleculeList = []) => ({
payload: moleculeList
});
+export const setAllInspirations = (allInspirationsMap) => ({
+ type: constants.SET_ALL_INSPIRATIONS,
+ payload: allInspirationsMap
+});
+
+export const setAllInspirationMoleculeDataList = (moleculeList = []) => ({
+ type: constants.SET_ALL_INSPIRATION_MOLECULE_DATA_LIST,
+ payload: moleculeList
+});
+
export const appendToInspirationMoleculeDataList = molecule => ({
type: constants.APPEND_TO_INSPIRATION_MOLECULE_DATA_LIST,
payload: molecule
});
+export const appendToAllInspirationMoleculeDataList = molecule => ({
+ type: constants.APPEND_TO_ALL_INSPIRATION_MOLECULE_DATA_LIST,
+ payload: molecule
+});
+
export const removeFromInspirationMoleculeDataList = moleculeID => ({
type: constants.REMOVE_FROM_INSPIRATION_MOLECULE_DATA_LIST,
payload: moleculeID
diff --git a/js/components/datasets/redux/constants.js b/js/components/datasets/redux/constants.js
index 9d47c6ad3..e1d95a045 100644
--- a/js/components/datasets/redux/constants.js
+++ b/js/components/datasets/redux/constants.js
@@ -3,6 +3,7 @@ const prefix = 'CUSTOM_DATASETS_';
export const constants = {
ADD_DATASET: prefix + 'ADD_DATASET',
SET_DATASET: prefix + 'SET_DATASET',
+ REPLACE_ALL_MOLECULELISTS: prefix + 'REPLACE_ALL_MOLECULELISTS',
ADD_MOLECULELIST: prefix + 'ADD_MOLECULELIST',
REMOVE_MOLECULELIST: prefix + 'REMOVE_MOLECULELIST',
SET_IS_LOADING_MOLECULE_LIST: prefix + 'SET_IS_LOADING_MOLECULE_LIST',
@@ -28,6 +29,7 @@ export const constants = {
SET_INSPIRATION_LIST: prefix + 'SET_INSPIRATION_LIST',
APPEND_INSPIRATION_LIST: prefix + 'APPEND_INSPIRATION_LIST',
REMOVE_FROM_INSPIRATION_LIST: prefix + 'REMOVE_FROM_INSPIRATION_LIST',
+ SET_ALL_INSPIRATIONS: prefix + 'SET_ALL_INSPIRATIONS',
APPEND_TO_SCORE_DATASET_MAP: prefix + 'APPEND_TO_SCORE_DATASET_MAP',
REMOVE_FROM_SCORE_DATASET_MAP: prefix + 'REMOVE_FROM_SCORE_DATASET_MAP',
@@ -52,7 +54,9 @@ export const constants = {
SET_INSPIRATION_FRAGMENT_LIST: prefix + 'SET_INSPIRATION_FRAGMENT_LIST',
REMOVE_FROM_INSPIRATION_FRAGMENT_LIST: prefix + 'REMOVE_FROM_INSPIRATION_FRAGMENT_LIST',
SET_INSPIRATION_MOLECULE_DATA_LIST: prefix + 'SET_INSPIRATION_MOLECULE_DATA_LIST',
+ SET_ALL_INSPIRATION_MOLECULE_DATA_LIST: prefix + 'SET_ALL_INSPIRATION_MOLECULE_DATA_LIST',
APPEND_TO_INSPIRATION_MOLECULE_DATA_LIST: prefix + 'APPEND_TO_INSPIRATION_MOLECULE_DATA_LIST',
+ APPEND_TO_ALL_INSPIRATION_MOLECULE_DATA_LIST: prefix + 'APPEND_TO_ALL_INSPIRATION_MOLECULE_DATA_LIST',
REMOVE_FROM_INSPIRATION_MOLECULE_DATA_LIST: prefix + 'REMOVE_FROM_INSPIRATION_MOLECULE_DATA_LIST',
APPEND_MOLECULE_TO_COMPOUNDS_TO_BUY_OF_DATASET: prefix + 'APPEND_MOLECULE_TO_COMPOUNDS_TO_BUY_OF_DATASET',
diff --git a/js/components/datasets/redux/dispatchActions.js b/js/components/datasets/redux/dispatchActions.js
index 25c6830f8..9a0956056 100644
--- a/js/components/datasets/redux/dispatchActions.js
+++ b/js/components/datasets/redux/dispatchActions.js
@@ -16,7 +16,9 @@ import {
setFilterProperties,
setIsLoadingInspirationListOfMolecules,
appendToInspirationMoleculeDataList,
+ appendToAllInspirationMoleculeDataList,
setInspirationMoleculeDataList,
+ setAllInspirationMoleculeDataList,
setInspirationList,
setIsOpenInspirationDialog,
clearScoreCompoundMap,
@@ -41,6 +43,17 @@ import { getInitialDatasetFilterProperties, getInitialDatasetFilterSettings } fr
import { COUNT_OF_VISIBLE_SCORES } from './constants';
import { colourList } from '../../preview/molecule/moleculeView';
import { appendMoleculeOrientation } from '../../../reducers/ngl/actions';
+import { isAnyInspirationTurnedOnByType } from './selectors';
+import {
+ addVector,
+ addHitProtein,
+ addComplex,
+ addSurface,
+ addLigand,
+ addDensity
+} from '../../preview/molecule/redux/dispatchActions';
+import { OBJECT_TYPE } from '../../nglView/constants';
+import { getRepresentationsByType } from '../../nglView/generatingObjects';
import { setSelectedAllByType, setDeselectedAllByType } from './actions';
export const initializeDatasetFilter = datasetID => (dispatch, getState) => {
@@ -51,7 +64,7 @@ export const initializeDatasetFilter = datasetID => (dispatch, getState) => {
dispatch(setFilterProperties(datasetID, initFilterProperties));
};
-export const addDatasetHitProtein = (stage, data, colourToggle, datasetID, skipTracking = false) => dispatch => {
+export const addDatasetHitProtein = (stage, data, colourToggle, datasetID, skipTracking = false, representations = undefined) => dispatch => {
dispatch(
loadObject({
target: Object.assign(
@@ -59,6 +72,7 @@ export const addDatasetHitProtein = (stage, data, colourToggle, datasetID, skipT
generateHitProteinObject(data, colourToggle, base_url, datasetID)
),
stage,
+ previousRepresentations: representations,
orientationMatrix: null
})
).finally(() => {
@@ -81,7 +95,7 @@ export const removeDatasetHitProtein = (stage, data, colourToggle, datasetID, sk
dispatch(removeFromProteinList(datasetID, generateMoleculeCompoundId(data), skipTracking));
};
-export const addDatasetComplex = (stage, data, colourToggle, datasetID, skipTracking = false) => dispatch => {
+export const addDatasetComplex = (stage, data, colourToggle, datasetID, skipTracking = false, representations = undefined) => dispatch => {
dispatch(
loadObject({
target: Object.assign(
@@ -89,6 +103,7 @@ export const addDatasetComplex = (stage, data, colourToggle, datasetID, skipTrac
generateComplexObject(data, colourToggle, base_url, datasetID)
),
stage,
+ previousRepresentations: representations,
orientationMatrix: null
})
).finally(() => {
@@ -108,7 +123,7 @@ export const removeDatasetComplex = (stage, data, colourToggle, datasetID, skipT
dispatch(removeFromComplexList(datasetID, generateMoleculeCompoundId(data), skipTracking));
};
-export const addDatasetSurface = (stage, data, colourToggle, datasetID) => dispatch => {
+export const addDatasetSurface = (stage, data, colourToggle, datasetID, representations = undefined) => dispatch => {
dispatch(
loadObject({
target: Object.assign(
@@ -116,6 +131,7 @@ export const addDatasetSurface = (stage, data, colourToggle, datasetID) => dispa
generateSurfaceObject(data, colourToggle, base_url, datasetID)
),
stage,
+ previousRepresentations: representations,
orientationMatrix: null
})
).finally(() => {
@@ -135,12 +151,13 @@ export const removeDatasetSurface = (stage, data, colourToggle, datasetID) => di
dispatch(removeFromSurfaceList(datasetID, generateMoleculeCompoundId(data)));
};
-export const addDatasetLigand = (stage, data, colourToggle, datasetID, skipTracking = false) => dispatch => {
+export const addDatasetLigand = (stage, data, colourToggle, datasetID, skipTracking = false, representations = undefined) => dispatch => {
const currentOrientation = stage.viewerControls.getOrientation();
dispatch(
loadObject({
target: Object.assign({ display_div: VIEWS.MAJOR_VIEW }, generateMoleculeObject(data, colourToggle, datasetID)),
stage,
+ previousRepresentations: representations,
markAsRightSideLigand: true
})
).finally(() => {
@@ -336,6 +353,7 @@ export const loadInspirationMoleculesDataList = (inspirationList = []) => (dispa
arrayOfInspirationListSet.map(moleculeID =>
api({ url: `${base_url}/api/molecules/${moleculeID}/` }).then(response => {
dispatch(appendToInspirationMoleculeDataList(response.data));
+ dispatch(appendToAllInspirationMoleculeDataList(response.data));
})
)
).finally(() => {
@@ -345,6 +363,11 @@ export const loadInspirationMoleculesDataList = (inspirationList = []) => (dispa
return Promise.resolve();
};
+export const clearAllInspirationsOfDataset = () => dispatch => {
+ // clear inspirations
+ dispatch(setAllInspirationMoleculeDataList([]));
+};
+
export const clearInspirationsOfDataset = datasetID => dispatch => {
// clear inspirations
dispatch(setInspirationList(datasetID, []));
@@ -364,7 +387,7 @@ export const clearDatasetSettings = datasetID => dispatch => {
export const clickOnInspirations = ({ datasetID, currentID, computed_inspirations = [] }) => dispatch => {
dispatch(setInspirationList(datasetID, [currentID]));
- dispatch(setInspirationFragmentList(computed_inspirations));
+ dispatch(setInspirationMoleculeDataList(computed_inspirations));
dispatch(setIsOpenInspirationDialog(true));
};
@@ -584,4 +607,136 @@ export const autoHideDatasetDialogsOnScroll = ({ inspirationDialogRef, crossRefe
}
};
+export const removeAllSelectedDatasetMolecules = stage => (dispatch, getState) => {
+ const state = getState();
+ const datasets = state.datasetsReducers.datasets;
+ const currentMolecules = state.datasetsReducers.moleculeLists;
+ if (datasets) {
+ datasets.forEach(dataset => {
+ let datasetID = dataset.id;
+ const ligandList = state.datasetsReducers.ligandLists[datasetID];
+ const proteinList = state.datasetsReducers.proteinLists[datasetID];
+ const complexList = state.datasetsReducers.complexLists[datasetID];
+ const surfaceList = state.datasetsReducers.surfaceLists[datasetID];
+
+ let molecules = currentMolecules[datasetID];
+ ligandList?.forEach(moleculeID => {
+ const foundedMolecule = molecules?.find(mol => mol.id === moleculeID);
+ dispatch(
+ removeDatasetLigand(stage, foundedMolecule, colourList[foundedMolecule.id % colourList.length], datasetID)
+ );
+ });
+ proteinList?.forEach(moleculeID => {
+ const foundedMolecule = molecules?.find(mol => mol.id === moleculeID);
+ dispatch(
+ removeDatasetHitProtein(stage, foundedMolecule, colourList[foundedMolecule.id % colourList.length], datasetID)
+ );
+ });
+ complexList?.forEach(moleculeID => {
+ const foundedMolecule = molecules?.find(mol => mol.id === moleculeID);
+ dispatch(
+ removeDatasetComplex(stage, foundedMolecule, colourList[foundedMolecule.id % colourList.length], datasetID)
+ );
+ });
+ surfaceList?.forEach(moleculeID => {
+ const foundedMolecule = molecules?.find(mol => mol.id === moleculeID);
+ dispatch(
+ removeDatasetSurface(stage, foundedMolecule, colourList[foundedMolecule.id % colourList.length], datasetID)
+ );
+ });
+ });
+ }
+};
+
+export const moveMoleculeInspirationsSettings = (
+ data,
+ newItemData,
+ stage,
+ objectsInView,
+ fragmentDisplayListMolecule,
+ proteinListMolecule,
+ complexListMolecule,
+ surfaceListMolecule,
+ densityListMolecule,
+ vectorOnListMolecule
+) => (dispatch, getState) => {
+ dispatch(clearAllInspirationsOfDataset());
+ if (newItemData) {
+ let computed_inspirations = (data && data.computed_inspirations) || [];
+ let isAnyInspirationLigandOn = isAnyInspirationTurnedOnByType(computed_inspirations, fragmentDisplayListMolecule);
+ let isAnyInspirationProteinOn = isAnyInspirationTurnedOnByType(computed_inspirations, proteinListMolecule);
+ let isAnyInspirationComplexOn = isAnyInspirationTurnedOnByType(computed_inspirations, complexListMolecule);
+ let isAnyInspirationSurfaceOn = isAnyInspirationTurnedOnByType(computed_inspirations, surfaceListMolecule);
+ let isAnyInspirationDensityOn = isAnyInspirationTurnedOnByType(computed_inspirations, densityListMolecule);
+ let isAnyInspirationVectorOn = isAnyInspirationTurnedOnByType(computed_inspirations, vectorOnListMolecule);
+
+ if (
+ isAnyInspirationLigandOn ||
+ isAnyInspirationProteinOn ||
+ isAnyInspirationComplexOn ||
+ isAnyInspirationSurfaceOn ||
+ isAnyInspirationDensityOn ||
+ isAnyInspirationVectorOn
+ ) {
+ // dispatch(loadInspirationMoleculesDataList(newItemData.computed_inspirations)).then(() => {
+ dispatch(
+ moveInspirations(
+ stage,
+ objectsInView,
+ isAnyInspirationLigandOn,
+ isAnyInspirationProteinOn,
+ isAnyInspirationComplexOn,
+ isAnyInspirationSurfaceOn,
+ isAnyInspirationDensityOn,
+ isAnyInspirationVectorOn
+ )
+ );
+ // });
+ }
+ }
+};
+
+const moveInspirations = (
+ stage,
+ objectsInView,
+ isAnyInspirationLigandOn,
+ isAnyInspirationProteinOn,
+ isAnyInspirationComplexOn,
+ isAnyInspirationSurfaceOn,
+ isAnyInspirationDensityOn,
+ isAnyInspirationVectorOn
+) => (dispatch, getState) => {
+ const state = getState();
+ const molecules = state.datasetsReducers.inspirationMoleculeDataList;
+ if (molecules) {
+ molecules.forEach(molecule => {
+ if (molecule) {
+ if (isAnyInspirationLigandOn) {
+ let representations = getRepresentationsByType(objectsInView, molecule, OBJECT_TYPE.LIGAND);
+ dispatch(addLigand(stage, molecule, colourList[molecule.id % colourList.length], false, representations));
+ }
+ if (isAnyInspirationProteinOn) {
+ let representations = getRepresentationsByType(objectsInView, molecule, OBJECT_TYPE.HIT_PROTEIN);
+ dispatch(addHitProtein(stage, molecule, colourList[molecule.id % colourList.length], representations));
+ }
+ if (isAnyInspirationComplexOn) {
+ let representations = getRepresentationsByType(objectsInView, molecule, OBJECT_TYPE.COMPLEX);
+ dispatch(addComplex(stage, molecule, colourList[molecule.id % colourList.length], representations));
+ }
+ if (isAnyInspirationSurfaceOn) {
+ let representations = getRepresentationsByType(objectsInView, molecule, OBJECT_TYPE.SURFACE);
+ dispatch(addSurface(stage, molecule, colourList[molecule.id % colourList.length], representations));
+ }
+ if (isAnyInspirationDensityOn) {
+ let representations = getRepresentationsByType(objectsInView, molecule, OBJECT_TYPE.DENSITY);
+ dispatch(addDensity(stage, molecule, colourList[molecule.id % colourList.length], representations));
+ }
+ if (isAnyInspirationVectorOn) {
+ dispatch(addVector(stage, molecule, colourList[molecule.id % colourList.length]));
+ }
+ }
+ });
+ }
+};
+
export const getDatasetMoleculeID = (datasetID, moleculeID) => `datasetID-${datasetID}_moleculeID-${moleculeID}`;
diff --git a/js/components/datasets/redux/reducer.js b/js/components/datasets/redux/reducer.js
index 4d04a1b65..379e4298d 100644
--- a/js/components/datasets/redux/reducer.js
+++ b/js/components/datasets/redux/reducer.js
@@ -32,6 +32,8 @@ export const INITIAL_STATE = {
inspirationFragmentList: [],
isLoadingInspirationListOfMolecules: false,
inspirationMoleculeDataList: [],
+ allInspirationMoleculeDataList: [],
+ allInspirations: {},
// cross reference
isOpenCrossReferenceDialog: false,
@@ -135,6 +137,9 @@ export const datasetsReducers = (state = INITIAL_STATE, action = {}) => {
case constants.SET_DATASET:
return Object.assign({}, state, { datasets: action.payload });
+ case constants.REPLACE_ALL_MOLECULELISTS:
+ return {...state, moleculeLists: action.payload};
+
case constants.ADD_MOLECULELIST:
// initialize also control containers
const initializedState = initializeContainerLists(state, action.payload.datasetID);
@@ -295,11 +300,21 @@ export const datasetsReducers = (state = INITIAL_STATE, action = {}) => {
case constants.SET_INSPIRATION_MOLECULE_DATA_LIST:
return Object.assign({}, state, { inspirationMoleculeDataList: action.payload });
+ case constants.SET_ALL_INSPIRATION_MOLECULE_DATA_LIST:
+ return Object.assign({}, state, { allInspirationMoleculeDataList: action.payload });
+
case constants.APPEND_TO_INSPIRATION_MOLECULE_DATA_LIST:
const extendedInspirationMoleculeDataList = new Set(state.inspirationMoleculeDataList);
extendedInspirationMoleculeDataList.add(action.payload);
return Object.assign({}, state, { inspirationMoleculeDataList: [...extendedInspirationMoleculeDataList] });
+ case constants.APPEND_TO_ALL_INSPIRATION_MOLECULE_DATA_LIST:
+ const molecules = new Set(state.allInspirationMoleculeDataList);
+ if (!molecules.has(action.payload)) {
+ molecules.add(action.payload);
+ }
+ return Object.assign({}, state, { allInspirationMoleculeDataList: [...molecules] });
+
case constants.REMOVE_FROM_INSPIRATION_MOLECULE_DATA_LIST:
const diminishedInspirationMoleculeDataList = new Set(state.inspirationMoleculeDataList);
@@ -331,6 +346,9 @@ export const datasetsReducers = (state = INITIAL_STATE, action = {}) => {
}
return Object.assign({}, state, { inspirationFragmentList: [...diminishedInspirationFragmentList] });
+ case constants.SET_ALL_INSPIRATIONS:
+ return {...state, allInspirations: action.payload};
+
case constants.APPEND_MOLECULE_TO_COMPOUNDS_TO_BUY_OF_DATASET:
const setOfMolecules = new Set(state.compoundsToBuyDatasetMap[action.payload.datasetID]);
setOfMolecules.add(action.payload.moleculeID);
diff --git a/js/components/datasets/redux/selectors.js b/js/components/datasets/redux/selectors.js
index 3ceaf3a7e..6e768ce6c 100644
--- a/js/components/datasets/redux/selectors.js
+++ b/js/components/datasets/redux/selectors.js
@@ -160,6 +160,18 @@ export const isAnyInspirationTurnedOn = createSelector(
}
);
+export const isAnyInspirationTurnedOnByType = (inspirations, data) => {
+ let typeLists = new Set(data);
+ let hasInspirationType = false;
+ inspirations.forEach(moleculeID => {
+ if (typeLists.has(moleculeID)) {
+ hasInspirationType = true;
+ return hasInspirationType;
+ }
+ });
+ return hasInspirationType;
+};
+
export const getFilteredDatasetMoleculeList = createSelector(
(_, datasetID) => datasetID,
filterDatasetMap,
@@ -254,11 +266,11 @@ export const getFilteredDatasetMoleculeList = createSelector(
for (let prioAttr of sortedAttributes) {
const order = filterProperties[prioAttr].order;
- const scoreValueOfA =
+ let scoreValueOfA =
Object.keys(a.numerical_scores).find(key => key === prioAttr) && a.numerical_scores[prioAttr];
scoreValueOfA =
scoreValueOfA || (Object.keys(a.text_scores).find(key => key === prioAttr) && a.text_scores[prioAttr]);
- const scoreValueOfB =
+ let scoreValueOfB =
Object.keys(b.numerical_scores).find(key => key === prioAttr) && b.numerical_scores[prioAttr];
scoreValueOfB =
scoreValueOfB || (Object.keys(b.text_scores).find(key => key === prioAttr) && b.text_scores[prioAttr]);
@@ -284,7 +296,6 @@ export const getFilteredDatasetMoleculeList = createSelector(
}
}
});
- return filteredMolecules;
}
return datasetMoleculeList;
}
diff --git a/js/components/datasets/selectedCompoundsList.js b/js/components/datasets/selectedCompoundsList.js
index bcc764b97..06c3ff709 100644
--- a/js/components/datasets/selectedCompoundsList.js
+++ b/js/components/datasets/selectedCompoundsList.js
@@ -11,15 +11,15 @@ import { setIsOpenInspirationDialog } from './redux/actions';
import { CrossReferenceDialog } from './crossReferenceDialog';
import {
autoHideDatasetDialogsOnScroll,
+ resetCrossReferenceDialog,
removeDatasetComplex,
removeDatasetHitProtein,
removeDatasetLigand,
- removeDatasetSurface,
- resetCrossReferenceDialog
+ removeDatasetSurface
} from './redux/dispatchActions';
-import MoleculeView from '../preview/molecule/moleculeView';
import { NglContext } from '../nglView/nglProvider';
import { VIEWS } from '../../constants/constants';
+import { getMoleculeList } from '../preview/molecule/redux/selectors';
import FileSaver from 'file-saver';
import JSZip from 'jszip';
@@ -238,6 +238,11 @@ export const SelectedCompoundList = memo(({ height }) => {
previousItemData={index > 0 && array[index - 1]}
nextItemData={index < array?.length && array[index + 1]}
removeOfAllSelectedTypes={removeOfAllSelectedTypes}
+ L={ligandListAllDatasets[data.datasetID].includes(data.molecule.id)}
+ P={proteinListAllDatasets[data.datasetID].includes(data.molecule.id)}
+ C={complexListAllDatasets[data.datasetID].includes(data.molecule.id)}
+ S={surfaceListAllDatasets[data.datasetID].includes(data.molecule.id)}
+ V={false}
/>
))}
diff --git a/js/components/header/index.js b/js/components/header/index.js
index 30ea8e58b..db831a1f0 100644
--- a/js/components/header/index.js
+++ b/js/components/header/index.js
@@ -35,7 +35,7 @@ import { URLS } from '../routes/constants';
import { useCombinedRefs } from '../../utils/refHelpers';
import { ComputeSize } from '../../utils/computeSize';
import { DJANGO_CONTEXT } from '../../utils/djangoContext';
-import { useDisableUserInteraction } from '../helpers/useEnableUserInteracion';
+// import { useDisableUserInteraction } from '../helpers/useEnableUserInteracion';
import { useHistory } from 'react-router-dom';
import { IssueReport } from '../userFeedback/issueReport';
import { IdeaReport } from '../userFeedback/ideaReport';
@@ -92,7 +92,7 @@ export default memo(
let history = useHistory();
const classes = useStyles();
const { isLoading, headerNavbarTitle, setHeaderNavbarTitle, headerButtons } = useContext(HeaderContext);
- const disableUserInteraction = useDisableUserInteraction();
+ // const disableUserInteraction = useDisableUserInteraction();
const [openMenu, setOpenMenu] = useState(false);
const [openFunders, setOpenFunders] = useState(false);
@@ -283,7 +283,8 @@ export default memo(
- {(isLoading === true || disableUserInteraction === true) && (
+ {//TODO this needs to be reworked if the optimizations help
+ (isLoading === true || false === true) && (
)}
diff --git a/js/components/helpers/useEnableUserInteracion.js b/js/components/helpers/useEnableUserInteracion.js
index afead7509..40ea5a2cc 100644
--- a/js/components/helpers/useEnableUserInteracion.js
+++ b/js/components/helpers/useEnableUserInteracion.js
@@ -12,9 +12,11 @@ export const useDisableUserInteraction = () => {
const countOfPendingNglObjects = useSelector(state => state.nglReducers.countOfPendingNglObjects);
const isLoadingTree = useSelector(state => state.projectReducers.isLoadingTree);
const isLoadingCurrentSnapshot = useSelector(state => state.projectReducers.isLoadingCurrentSnapshot);
+ const isRestoring = useSelector(state => state.trackingReducers.isActionRestoring);
useEffect(() => {
if (
+ isRestoring === false &&
isLoadingTree === false &&
isLoadingCurrentSnapshot === false &&
countOfPendingVectorLoadRequests === 0 &&
@@ -39,6 +41,7 @@ export const useDisableUserInteraction = () => {
disableInteraction,
isLoadingCurrentSnapshot,
isLoadingTree,
+ isRestoring,
proteinsHasLoaded
]);
diff --git a/js/components/nglView/generatingObjects.js b/js/components/nglView/generatingObjects.js
index bb73083ec..298867e6d 100644
--- a/js/components/nglView/generatingObjects.js
+++ b/js/components/nglView/generatingObjects.js
@@ -220,3 +220,10 @@ export const getVectorWithColorByCountOfCompounds = (item, currentVectorCompound
}
return { ...item, colour: colour, radius: 0.3 };
};
+
+export const getRepresentationsByType = (objectsInView, object, objectType, datasetId) => {
+ let parentItem = `${object.protein_code || object.name}_${objectType}${datasetId ? '_' + datasetId : ''}`;
+ let objectInView = objectsInView[parentItem];
+ var representations = (objectInView && objectInView.representations) || undefined;
+ return representations;
+};
diff --git a/js/components/nglView/redux/dispatchActions.js b/js/components/nglView/redux/dispatchActions.js
index eec05e82c..4d8b2d0f6 100644
--- a/js/components/nglView/redux/dispatchActions.js
+++ b/js/components/nglView/redux/dispatchActions.js
@@ -8,7 +8,7 @@ import { setDuckYankData, setMolGroupOn, setPanddaSiteOn } from '../../../reduce
import * as listTypes from '../../../constants/listTypes';
import { selectVectorAndResetCompounds } from '../../../reducers/selection/dispatchActions';
-export const toggleMoleculeGroup = (molGroupId, summaryViewStage, majorViewStage) => (dispatch, getState) => {
+export const toggleMoleculeGroup = (molGroupId, summaryViewStage) => (dispatch, getState) => {
const state = getState();
const molGroupSelection = state.selectionReducers.mol_group_selection;
const objIdx = molGroupSelection.indexOf(molGroupId);
@@ -58,11 +58,7 @@ export const toggleMoleculeGroup = (molGroupId, summaryViewStage, majorViewStage
throw new Error(error);
});
dispatch(
- clearAfterDeselectingMoleculeGroup({
- molGroupId,
- currentMolGroup,
- majorViewStage
- })
+ clearAfterDeselectingMoleculeGroup()
);
}
};
@@ -117,9 +113,9 @@ export const handleNglViewPick = (stage, pickingProxy, getNglView) => (dispatch,
const type = name.split('_')[0];
const pk = parseInt(name.split('_')[1], 10);
if (type === OBJECT_TYPE.MOLECULE_GROUP && getNglView(VIEWS.MAJOR_VIEW)) {
- dispatch(toggleMoleculeGroup(pk, stage, getNglView(VIEWS.MAJOR_VIEW).stage));
+ dispatch(toggleMoleculeGroup(pk, stage));
} else if (type === OBJECT_TYPE.MOLGROUPS_SELECT && getNglView(VIEWS.MAJOR_VIEW)) {
- dispatch(toggleMoleculeGroup(pk, stage, getNglView(VIEWS.MAJOR_VIEW).stage));
+ dispatch(toggleMoleculeGroup(pk, stage));
} else if (type === listTypes.PANDDA_SITE) {
dispatch(setPanddaSiteOn(pk));
}
diff --git a/js/components/nglView/renderingObjects.js b/js/components/nglView/renderingObjects.js
index b1f755bac..1ed54a329 100644
--- a/js/components/nglView/renderingObjects.js
+++ b/js/components/nglView/renderingObjects.js
@@ -6,6 +6,7 @@ import {
defaultFocus
} from './generatingObjects';
import { concatStructures, Selection, Shape, Matrix4 } from 'ngl';
+import {addToPdbCache} from '../../reducers/ngl/actions';
const showSphere = ({ stage, input_dict, object_name, representations }) => {
let colour = input_dict.colour;
@@ -80,18 +81,53 @@ const renderHitProtein = (ol, representations, orientationMatrix) => {
return assignRepresentationArrayToComp(reprArray, comp);
};
-const showHitProtein = ({ stage, input_dict, object_name, representations, orientationMatrix }) => {
+const loadPdbFile = (url) => {
+ return fetch(url).then(response => response.text()).then(str => {
+ return new Blob([str], { type: 'text/plain' })
+ });
+};
+
+const getNameOfPdb = (url) => {
+ const parts = url.split('/');
+ const last = parts[parts.length - 1];
+ return last;
+};
+
+const getPdb = (url) => (dispatch, getState) => {
+ const state = getState();
+
+ const pdbCache = state.nglReducers.pdbCache;
+ const pdbName = getNameOfPdb(url);
+ if (pdbCache.hasOwnProperty(pdbName)) {
+ return new Promise((resolve, reject) => {
+ resolve(pdbCache[pdbName])
+ });
+ } else {
+ return loadPdbFile(url).then(b => {
+ dispatch(addToPdbCache(pdbName, b));
+ return b;
+ });
+ };
+};
+
+const showHitProtein = ({ stage, input_dict, object_name, representations, orientationMatrix, dispatch }) => {
let stringBlob = new Blob([input_dict.sdf_info], { type: 'text/plain' });
- return Promise.all([
- stage.loadFile(input_dict.prot_url, { ext: 'pdb', defaultAssembly: 'BU1' }),
- stage.loadFile(stringBlob, { ext: 'sdf' }),
- stage,
- defaultFocus,
- object_name,
- input_dict.colour
- ]).then(ol => renderHitProtein(ol, representations, orientationMatrix));
+
+ return dispatch(getPdb(input_dict.prot_url)).then(pdbBlob => {
+ return Promise.all([
+ stage.loadFile(pdbBlob, { ext: 'pdb', defaultAssembly: 'BU1' }),
+ stage.loadFile(stringBlob, { ext: 'sdf' }),
+ stage,
+ defaultFocus,
+ object_name,
+ input_dict.colour
+ ]);
+ }).then(ol => {
+ renderHitProtein(ol, representations, orientationMatrix)
+ });
};
+
const renderComplex = (ol, representations, orientationMatrix) => {
let cs = concatStructures(
ol[4],
diff --git a/js/components/preview/Preview.js b/js/components/preview/Preview.js
index a5f890105..b85a4e7a2 100644
--- a/js/components/preview/Preview.js
+++ b/js/components/preview/Preview.js
@@ -2,7 +2,7 @@
* Created by abradley on 14/04/2018.
*/
-import React, { memo, useContext, useEffect, useRef, useState } from 'react';
+import React, { memo, useCallback, useContext, useEffect, useRef, useState } from 'react';
import { Grid, makeStyles, useTheme, ButtonGroup, Button } from '@material-ui/core';
import NGLView from '../nglView/nglView';
import HitNavigator from './molecule/hitNavigator';
@@ -31,7 +31,7 @@ import { loadDatasetCompoundsWithScores, loadDataSets } from '../datasets/redux/
import { SelectedCompoundList } from '../datasets/selectedCompoundsList';
import { DatasetSelectorMenuButton } from '../datasets/datasetSelectorMenuButton';
import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown';
-import { setMoleculeListIsLoading } from '../datasets/redux/actions';
+import { setMoleculeListIsLoading, setAllInspirations } from '../datasets/redux/actions';
const hitNavigatorWidth = 504;
@@ -96,6 +96,10 @@ const Preview = memo(({ isStateLoaded, hideProjects }) => {
const target_on = useSelector(state => state.apiReducers.target_on);
const isTrackingRestoring = useSelector(state => state.trackingReducers.isTrackingCompoundsRestoring);
+ const all_mol_lists = useSelector(state => state.apiReducers.all_mol_lists);
+ const moleculeLists = useSelector(state => state.datasetsReducers.moleculeLists);
+ const isLoadingMoleculeList = useSelector(state => state.datasetsReducers.isLoadingMoleculeList);
+
/*
Loading datasets
*/
@@ -118,6 +122,44 @@ const Preview = memo(({ isStateLoaded, hideProjects }) => {
}
}, [customDatasets.length, dispatch, target_on, isTrackingRestoring]);
+ useEffect(() => {
+ const allMolsGroupsCount = Object.keys(all_mol_lists || {}).length;
+ const moleculeListsCount = Object.keys(moleculeLists || {}).length;
+ if (allMolsGroupsCount > 0 && moleculeListsCount > 0 && !isLoadingMoleculeList) {
+ const allDatasets = {};
+ const allMolsMap = linearizeMoleculesLists();
+ const keys = Object.keys(moleculeLists);
+ keys.forEach(key => {
+ let dataset = moleculeLists[key];
+ let mols = {};
+ dataset.forEach(dsMol => {
+ let inspirations = [];
+ dsMol.computed_inspirations.forEach(id => {
+ let lhsMol = allMolsMap[id];
+ inspirations.push(lhsMol);
+ });
+ mols[dsMol.id] = inspirations;
+ });
+ allDatasets[key] = mols;
+ });
+ dispatch(setAllInspirations(allDatasets));
+ }
+ }, [all_mol_lists, moleculeLists, isLoadingMoleculeList, linearizeMoleculesLists, dispatch]);
+
+ const linearizeMoleculesLists = useCallback(() => {
+ const keys = Object.keys(all_mol_lists);
+ const allMolsMap = {};
+
+ keys.forEach(key => {
+ let molList = all_mol_lists[key];
+ molList.forEach(mol => {
+ allMolsMap[mol.id] = mol;
+ });
+ });
+
+ return allMolsMap;
+ }, [all_mol_lists]);
+
const [molGroupsHeight, setMolGroupsHeight] = useState(0);
const [filterItemsHeight, setFilterItemsHeight] = useState(0);
const [filterItemsHeightDataset, setFilterItemsHeightDataset] = useState(0);
diff --git a/js/components/preview/molecule/moleculeList.js b/js/components/preview/molecule/moleculeList.js
index a72b1e46e..5931d6268 100644
--- a/js/components/preview/molecule/moleculeList.js
+++ b/js/components/preview/molecule/moleculeList.js
@@ -28,7 +28,7 @@ import { ComputeSize } from '../../../utils/computeSize';
import { moleculeProperty } from './helperConstants';
import { VIEWS } from '../../../constants/constants';
import { NglContext } from '../../nglView/nglProvider';
-import { useDisableUserInteraction } from '../../helpers/useEnableUserInteracion';
+// import { useDisableUserInteraction } from '../../helpers/useEnableUserInteracion';
import classNames from 'classnames';
import {
addVector,
@@ -250,6 +250,9 @@ export const MoleculeList = memo(({ height, setFilterItemsHeight, filterItemsHei
const firstLoad = useSelector(state => state.selectionReducers.firstLoad);
const target_on = useSelector(state => state.apiReducers.target_on);
const mol_group_on = useSelector(state => state.apiReducers.mol_group_on);
+
+ const allInspirationMoleculeDataList = useSelector(state => state.datasetsReducers.allInspirationMoleculeDataList);
+
const mol_group_list = useSelector(state => state.apiReducers.mol_group_list);
const all_mol_lists = useSelector(state => state.apiReducers.all_mol_lists);
const directDisplay = useSelector(state => state.apiReducers.direct_access);
@@ -268,7 +271,7 @@ export const MoleculeList = memo(({ height, setFilterItemsHeight, filterItemsHei
const filterRef = useRef();
- const disableUserInteraction = useDisableUserInteraction();
+ // const disableUserInteraction = useDisableUserInteraction();
if (directDisplay && directDisplay.target) {
target = directDisplay.target;
@@ -292,11 +295,51 @@ export const MoleculeList = memo(({ height, setFilterItemsHeight, filterItemsHei
// Used for MoleculeListSortFilterDialog when using textSearch
const joinedMoleculeListsCopy = useMemo(() => [...joinedMoleculeLists], [joinedMoleculeLists]);
- if (isActiveFilter) {
- joinedMoleculeLists = filterMolecules(joinedMoleculeLists, filter);
- } else {
+ const addSelectedMoleculesFromUnselectedSites = useCallback((joinedMoleculeLists, list) => {
+ const result = [...joinedMoleculeLists];
+ list?.forEach(moleculeID => {
+ const foundJoinedMolecule = result.find(mol => mol.id === moleculeID);
+ if (!foundJoinedMolecule) {
+ const molecule = getAllMoleculeList.find(mol => mol.id === moleculeID);
+ if (molecule) {
+ result.push(molecule);
+ }
+ }
+ });
+
+ return result;
+ }, [getAllMoleculeList]);
+
+ joinedMoleculeLists = useMemo(
+ () => addSelectedMoleculesFromUnselectedSites(joinedMoleculeLists, proteinList),
+ [addSelectedMoleculesFromUnselectedSites, joinedMoleculeLists, proteinList]
+ );
+ joinedMoleculeLists = useMemo(
+ () => addSelectedMoleculesFromUnselectedSites(joinedMoleculeLists, complexList),
+ [addSelectedMoleculesFromUnselectedSites, joinedMoleculeLists, complexList]
+ );
+ joinedMoleculeLists = useMemo(
+ () => addSelectedMoleculesFromUnselectedSites(joinedMoleculeLists, fragmentDisplayList),
+ [addSelectedMoleculesFromUnselectedSites, joinedMoleculeLists, fragmentDisplayList]
+ );
+ joinedMoleculeLists = useMemo(
+ () => addSelectedMoleculesFromUnselectedSites(joinedMoleculeLists, surfaceList),
+ [addSelectedMoleculesFromUnselectedSites, joinedMoleculeLists, surfaceList]
+ );
+ joinedMoleculeLists = useMemo(
+ () => addSelectedMoleculesFromUnselectedSites(joinedMoleculeLists, densityList),
+ [addSelectedMoleculesFromUnselectedSites, joinedMoleculeLists, densityList]
+ );
+ joinedMoleculeLists = useMemo(
+ () => addSelectedMoleculesFromUnselectedSites(joinedMoleculeLists, vectorOnList),
+ [addSelectedMoleculesFromUnselectedSites, joinedMoleculeLists, vectorOnList]
+ );
+
+ if (!isActiveFilter) {
// default sort is by site
joinedMoleculeLists.sort((a, b) => a.site - b.site || a.number - b.number);
+ } else {
+ joinedMoleculeLists = filterMolecules(joinedMoleculeLists, filter);
}
const loadNextMolecules = () => {
@@ -409,6 +452,12 @@ export const MoleculeList = memo(({ height, setFilterItemsHeight, filterItemsHei
}
}, [isActiveFilter, setFilterItemsHeight]);
+ useEffect(() => {
+ if (!joinedMoleculeListsCopy.length) {
+ dispatch(setSortDialogOpen(false));
+ }
+ }, [dispatch, joinedMoleculeListsCopy.length]);
+
const handleFilterChange = filter => {
const filterSet = Object.assign({}, filter);
for (let attr of MOL_ATTRIBUTES) {
@@ -512,6 +561,8 @@ export const MoleculeList = memo(({ height, setFilterItemsHeight, filterItemsHei
};
const removeOfAllSelectedTypes = () => {
+ let molecules = [...getJoinedMoleculeList, ...allInspirationMoleculeDataList];
+
proteinList?.forEach(moleculeID => {
const foundedMolecule = joinedMoleculeLists?.find(mol => mol.id === moleculeID);
dispatch(removeHitProtein(majorViewStage, foundedMolecule, colourList[foundedMolecule.id % colourList.length]));
@@ -621,7 +672,7 @@ export const MoleculeList = memo(({ height, setFilterItemsHeight, filterItemsHei
};
const actions = [
-
+
,
dispatch(hideAllSelectedMolecules(majorViewStage, joinedMoleculeLists))}
>
@@ -676,7 +727,7 @@ export const MoleculeList = memo(({ height, setFilterItemsHeight, filterItemsHei
}
}}
color={'inherit'}
- disabled={!(object_selection || []).length || predefinedFilter !== 'none'}
+ disabled={!joinedMoleculeListsCopy.length || predefinedFilter !== 'none'}
>
@@ -785,10 +836,8 @@ export const MoleculeList = memo(({ height, setFilterItemsHeight, filterItemsHei
[classes.contColButtonSelected]: isLigandOn === true,
[classes.contColButtonHalfSelected]: isLigandOn === null
})}
- onClick={() => {
- onButtonToggle('ligand');
- }}
- disabled={disableUserInteraction}
+ onClick={() => onButtonToggle('ligand')}
+ disabled={false}
>
L
@@ -802,10 +851,8 @@ export const MoleculeList = memo(({ height, setFilterItemsHeight, filterItemsHei
[classes.contColButtonSelected]: isProteinOn,
[classes.contColButtonHalfSelected]: isProteinOn === null
})}
- onClick={() => {
- onButtonToggle('protein');
- }}
- disabled={disableUserInteraction}
+ onClick={() => onButtonToggle('protein')}
+ disabled={false}
>
P
@@ -820,10 +867,8 @@ export const MoleculeList = memo(({ height, setFilterItemsHeight, filterItemsHei
[classes.contColButtonSelected]: isComplexOn,
[classes.contColButtonHalfSelected]: isComplexOn === null
})}
- onClick={() => {
- onButtonToggle('complex');
- }}
- disabled={disableUserInteraction}
+ onClick={() => onButtonToggle('complex')}
+ disabled={false}
>
C
@@ -867,6 +912,11 @@ export const MoleculeList = memo(({ height, setFilterItemsHeight, filterItemsHei
previousItemData={index > 0 && array[index - 1]}
nextItemData={index < array?.length && array[index + 1]}
removeOfAllSelectedTypes={removeOfAllSelectedTypes}
+ L={fragmentDisplayList.includes(data.id)}
+ P={proteinList.includes(data.id)}
+ C={complexList.includes(data.id)}
+ S={surfaceList.includes(data.id)}
+ V={vectorOnList.includes(data.id)}
selectMoleculeSite={selectMoleculeSite}
/>
))}
diff --git a/js/components/preview/molecule/moleculeListSortFilterDialog.js b/js/components/preview/molecule/moleculeListSortFilterDialog.js
index 0d659ddb8..2b727af1f 100644
--- a/js/components/preview/molecule/moleculeListSortFilterDialog.js
+++ b/js/components/preview/molecule/moleculeListSortFilterDialog.js
@@ -173,6 +173,9 @@ export const MoleculeListSortFilterDialog = memo(
}, [joinedMoleculeLists]);
const [initState, setInitState] = useState(initialize());
+
+ filter = filter || initState;
+
const [filteredCount, setFilteredCount] = useState(getFilteredMoleculesCount(joinedMoleculeLists, filter));
const [predefinedFilter, setPredefinedFilter] = useState(filter.predefined);
diff --git a/js/components/preview/molecule/moleculeView.js b/js/components/preview/molecule/moleculeView.js
index efaa161b2..c2667f31d 100644
--- a/js/components/preview/molecule/moleculeView.js
+++ b/js/components/preview/molecule/moleculeView.js
@@ -5,13 +5,13 @@
import React, { memo, useEffect, useState, useRef, useContext, useCallback } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Grid, Button, makeStyles, Typography, Tooltip, IconButton } from '@material-ui/core';
-import { MyLocation, ArrowDownward, ArrowUpward } from '@material-ui/icons';
+import { MyLocation, ArrowDownward, ArrowUpward, FormatListBulletedTwoTone, FormatListBulletedSharp, FormatListNumbered } from '@material-ui/icons';
import SVGInline from 'react-svg-inline';
import classNames from 'classnames';
import { VIEWS } from '../../../constants/constants';
import { loadFromServer } from '../../../utils/genericView';
import { NglContext } from '../../nglView/nglProvider';
-import { useDisableUserInteraction } from '../../helpers/useEnableUserInteracion';
+// import { useDisableUserInteraction } from '../../helpers/useEnableUserInteracion';
import {
addVector,
removeVector,
@@ -25,13 +25,17 @@ import {
removeDensity,
addLigand,
removeLigand,
- searchMoleculeGroupByMoleculeID
+ searchMoleculeGroupByMoleculeID,
+ getMolImage
} from './redux/dispatchActions';
import { setSelectedAll, setDeselectedAll } from '../../../reducers/selection/actions';
import { base_url } from '../../routes/constants';
import { moleculeProperty } from './helperConstants';
import { centerOnLigandByMoleculeID } from '../../../reducers/ngl/dispatchActions';
import { SvgTooltip } from '../../common';
+import { OBJECT_TYPE } from '../../nglView/constants';
+import { getRepresentationsByType } from '../../nglView/generatingObjects';
+import {MOL_TYPE} from './redux/constants';
const useStyles = makeStyles(theme => ({
container: {
@@ -206,44 +210,42 @@ const MoleculeView = memo(
previousItemData,
nextItemData,
removeOfAllSelectedTypes,
+ L, P, C, S, V,
selectMoleculeSite
}) => {
// const [countOfVectors, setCountOfVectors] = useState('-');
// const [cmpds, setCmpds] = useState('-');
const selectedAll = useRef(false);
+ const ref = useRef(null);
const currentID = (data && data.id) || undefined;
const classes = useStyles();
const key = 'mol_image';
const [moleculeGroupID, setMoleculeGroupID] = useState();
const dispatch = useDispatch();
- const proteinList = useSelector(state => state.selectionReducers.proteinList);
- const complexList = useSelector(state => state.selectionReducers.complexList);
- const surfaceList = useSelector(state => state.selectionReducers.surfaceList);
- const densityList = useSelector(state => state.selectionReducers.densityList);
- const fragmentDisplayList = useSelector(state => state.selectionReducers.fragmentDisplayList);
- const vectorOnList = useSelector(state => state.selectionReducers.vectorOnList);
const target_on_name = useSelector(state => state.apiReducers.target_on_name);
const filter = useSelector(state => state.selectionReducers.filter);
const url = new URL(base_url + '/api/molimg/' + data.id + '/');
const [img_data, setImg_data] = useState(img_data_init);
+ const objectsInView = useSelector(state => state.nglReducers.objectsInView) || {};
+
const { getNglView } = useContext(NglContext);
const stage = getNglView(VIEWS.MAJOR_VIEW) && getNglView(VIEWS.MAJOR_VIEW).stage;
- const isLigandOn = (currentID && fragmentDisplayList.includes(currentID)) || false;
- const isProteinOn = (currentID && proteinList.includes(currentID)) || false;
- const isComplexOn = (currentID && complexList.includes(currentID)) || false;
- const isSurfaceOn = (currentID && surfaceList.includes(currentID)) || false;
- const isDensityOn = (currentID && densityList.includes(currentID)) || false;
- const isVectorOn = (currentID && vectorOnList.includes(currentID)) || false;
+ const isLigandOn = L;
+ const isProteinOn = P;
+ const isComplexOn = C;
+ const isSurfaceOn = S;
+ // const isDensityOn = false;
+ const isVectorOn = V;
const hasAllValuesOn = isLigandOn && isProteinOn && isComplexOn;
const hasSomeValuesOn = !hasAllValuesOn && (isLigandOn || isProteinOn || isComplexOn);
- const areArrowsVisible = isLigandOn || isProteinOn || isComplexOn || isSurfaceOn || isDensityOn || isVectorOn;
+ const areArrowsVisible = isLigandOn || isProteinOn || isComplexOn || isSurfaceOn || isVectorOn;
- const disableUserInteraction = useDisableUserInteraction();
+ // const disableUserInteraction = useDisableUserInteraction();
const oldUrl = useRef('');
const setOldUrl = url => {
@@ -281,37 +283,10 @@ const MoleculeView = memo(
// componentDidMount
useEffect(() => {
- if (refOnCancel.current === undefined) {
- let onCancel = () => {};
- Promise.all([
- loadFromServer({
- width: imageHeight,
- height: imageWidth,
- key,
- old_url: oldUrl.current,
- setImg_data,
- setOld_url: newUrl => setOldUrl(newUrl),
- url,
- cancel: onCancel
- })
- /* api({ url: `${base_url}/api/vector/${data.id}` }).then(response => {
- const vectors = response.data.vectors['3d'];
- setCountOfVectors(generateObjectList(vectors).length);
- }),
- api({ url: `${base_url}/api/graph/${data.id}` }).then(response => {
- setCmpds(getTotalCountOfCompounds(response.data.graph));
- })*/
- ]).catch(error => {
- throw new Error(error);
- });
- refOnCancel.current = onCancel;
- }
- return () => {
- if (refOnCancel) {
- refOnCancel.current();
- }
- };
- }, [complexList, data.id, data.smiles, fragmentDisplayList, imageHeight, url, vectorOnList, imageWidth]);
+ dispatch(getMolImage(data.id, MOL_TYPE.HIT, imageHeight, imageWidth)).then(i => {
+ setImg_data(i);
+ });
+ }, [data.id, data.smiles, imageHeight, url, imageWidth, dispatch]);
useEffect(() => {
if (searchMoleculeGroup) {
@@ -459,13 +434,13 @@ const MoleculeView = memo(
dispatch(addDensity(stage, data, colourToggle));
};
- const onDensity = () => {
- if (isDensityOn === false) {
- addNewDensity();
- } else {
- removeSelectedDensity();
- }
- };
+ // const onDensity = () => {
+ // if (isDensityOn === false) {
+ // addNewDensity();
+ // } else {
+ // removeSelectedDensity();
+ // }
+ // };
const removeSelectedVector = () => {
dispatch(removeVector(stage, data));
@@ -526,20 +501,25 @@ const MoleculeView = memo(
const moveSelectedMolSettings = newItemDataset => {
if (newItemDataset) {
if (isLigandOn) {
- dispatch(addLigand(stage, newItemDataset, colourToggle));
+ let representations = getRepresentationsByType(objectsInView, data, OBJECT_TYPE.LIGAND);
+ dispatch(addLigand(stage, newItemDataset, colourToggle, false, representations));
}
if (isProteinOn) {
- dispatch(addHitProtein(stage, newItemDataset, colourToggle));
+ let representations = getRepresentationsByType(objectsInView, data, OBJECT_TYPE.HIT_PROTEIN);
+ dispatch(addHitProtein(stage, newItemDataset, colourToggle, representations));
}
if (isComplexOn) {
- dispatch(addComplex(stage, newItemDataset, colourToggle));
+ let representations = getRepresentationsByType(objectsInView, data, OBJECT_TYPE.COMPLEX);
+ dispatch(addComplex(stage, newItemDataset, colourToggle, representations));
}
if (isSurfaceOn) {
- dispatch(addSurface(stage, newItemDataset, colourToggle));
- }
- if (isDensityOn) {
- dispatch(addDensity(stage, newItemDataset, colourToggle));
+ let representations = getRepresentationsByType(objectsInView, data, OBJECT_TYPE.SURFACE);
+ dispatch(addSurface(stage, newItemDataset, colourToggle, representations));
}
+ // if (isDensityOn) {
+ // let representations = getRepresentationsByType(objectsInView, data, OBJECT_TYPE.DENSITY);
+ // dispatch(addDensity(stage, newItemDataset, colourToggle, representations));
+ // }
if (isVectorOn) {
dispatch(addVector(stage, newItemDataset)).catch(error => {
throw new Error(error);
@@ -548,12 +528,26 @@ const MoleculeView = memo(
}
};
+ const scrollToElement = element => {
+ element.scrollIntoView({
+ behavior: 'auto',
+ block: 'nearest',
+ inline: 'nearest'
+ });
+ };
+
const handleClickOnDownArrow = () => {
+ const refNext = ref.current.nextSibling;
+ scrollToElement(refNext);
+
removeOfAllSelectedTypes();
moveSelectedMolSettings(nextItemData);
};
const handleClickOnUpArrow = () => {
+ const refPrevious = ref.current.previousSibling;
+ scrollToElement(refPrevious);
+
removeOfAllSelectedTypes();
moveSelectedMolSettings(previousItemData);
};
@@ -562,7 +556,7 @@ const MoleculeView = memo(
return (
<>
-
+
{/* Site number */}
@@ -597,7 +591,7 @@ const MoleculeView = memo(
onClick={() => {
dispatch(centerOnLigandByMoleculeID(stage, data?.id));
}}
- disabled={disableUserInteraction || !isLigandOn}
+ disabled={false || !isLigandOn}
>
@@ -618,14 +612,14 @@ const MoleculeView = memo(
)}
onClick={() => {
// always deselect all if are selected only some of options
- selectedAll.current = hasSomeValuesOn ? false : !selectedAll.current;
+ selectedAll.current = hasSomeValuesOn || hasAllValuesOn ? false : !selectedAll.current;
setCalledFromAll();
onLigand(true);
onProtein(true);
onComplex(true);
}}
- disabled={disableUserInteraction}
+ disabled={false}
>
A
@@ -639,7 +633,7 @@ const MoleculeView = memo(
[classes.contColButtonSelected]: isLigandOn
})}
onClick={() => onLigand()}
- disabled={disableUserInteraction}
+ disabled={false}
>
L
@@ -653,7 +647,7 @@ const MoleculeView = memo(
[classes.contColButtonSelected]: isProteinOn
})}
onClick={() => onProtein()}
- disabled={disableUserInteraction}
+ disabled={false}
>
P
@@ -668,7 +662,7 @@ const MoleculeView = memo(
[classes.contColButtonSelected]: isComplexOn
})}
onClick={() => onComplex()}
- disabled={disableUserInteraction}
+ disabled={false}
>
C
@@ -682,7 +676,7 @@ const MoleculeView = memo(
[classes.contColButtonSelected]: isSurfaceOn
})}
onClick={() => onSurface()}
- disabled={disableUserInteraction}
+ disabled={false}
>
S
@@ -694,10 +688,10 @@ const MoleculeView = memo(
@@ -711,7 +705,7 @@ const MoleculeView = memo(
[classes.contColButtonSelected]: isVectorOn
})}
onClick={() => onVector()}
- disabled={disableUserInteraction}
+ disabled={false}
>
V
@@ -753,7 +747,7 @@ const MoleculeView = memo(
@@ -763,7 +757,7 @@ const MoleculeView = memo(
diff --git a/js/components/preview/molecule/redux/actions.js b/js/components/preview/molecule/redux/actions.js
index 577e64328..0415ce91a 100644
--- a/js/components/preview/molecule/redux/actions.js
+++ b/js/components/preview/molecule/redux/actions.js
@@ -9,3 +9,8 @@ export const reloadMoleculeReducer = newState => ({
type: constants.SET_SORT_DIALOG_OPEN,
payload: newState
});
+
+export const addImageToCache = (molId, image) => ({
+ type: constants.ADD_IMAGE_TO_CACHE,
+ payload: {molId: molId, image: image}
+});
diff --git a/js/components/preview/molecule/redux/constants.js b/js/components/preview/molecule/redux/constants.js
index 387e19149..62f9fac26 100644
--- a/js/components/preview/molecule/redux/constants.js
+++ b/js/components/preview/molecule/redux/constants.js
@@ -2,7 +2,8 @@ const prefix = 'PREVIEW_MOLECULE_';
export const constants = {
SET_SORT_DIALOG_OPEN: prefix + 'SET_SORT_DIALOG_OPEN',
- RELOAD_REDUCER: prefix + 'RELOAD_REDUCER'
+ RELOAD_REDUCER: prefix + 'RELOAD_REDUCER',
+ ADD_IMAGE_TO_CACHE: prefix + 'ADD_IMAGE_TO_CACHE'
};
export const MOL_ATTR = {
@@ -88,3 +89,8 @@ export const MOL_ATTR = {
};
export const MOL_ATTRIBUTES = Object.values(MOL_ATTR);
+
+export const MOL_TYPE = {
+ HIT: 'HIT',
+ DATASET: 'DATASET'
+};
diff --git a/js/components/preview/molecule/redux/dispatchActions.js b/js/components/preview/molecule/redux/dispatchActions.js
index 7d4b8234e..c419d947f 100644
--- a/js/components/preview/molecule/redux/dispatchActions.js
+++ b/js/components/preview/molecule/redux/dispatchActions.js
@@ -45,6 +45,8 @@ import { getMoleculeOfCurrentVector } from '../../../../reducers/selection/selec
import { resetCurrentCompoundsSettings } from '../../compounds/redux/actions';
import { selectMoleculeGroup } from '../../moleculeGroups/redux/dispatchActions';
import { setDirectAccess, setDirectAccessProcessed } from '../../../../reducers/api/actions';
+import {MOL_TYPE} from './constants';
+import {addImageToCache} from './actions';
/**
* Convert the JSON into a list of arrow objects
@@ -179,11 +181,12 @@ export const removeVector = (stage, data, skipTracking = false) => async (dispat
dispatch(setVectorList(vector_list.filter(item => item.moleculeId !== data.id)));
};
-export const addHitProtein = (stage, data, colourToggle, skipTracking = false) => dispatch => {
+export const addHitProtein = (stage, data, colourToggle, skipTracking = false, representations = undefined) => dispatch => {
dispatch(
loadObject({
target: Object.assign({ display_div: VIEWS.MAJOR_VIEW }, generateHitProteinObject(data, colourToggle, base_url)),
stage,
+ previousRepresentations: representations,
orientationMatrix: null
})
).finally(() => {
@@ -203,11 +206,12 @@ export const removeHitProtein = (stage, data, colourToggle, skipTracking = false
dispatch(removeFromProteinList(generateMoleculeId(data), skipTracking));
};
-export const addComplex = (stage, data, colourToggle, skipTracking = false) => dispatch => {
+export const addComplex = (stage, data, colourToggle, skipTracking = false, representations = undefined) => dispatch => {
dispatch(
loadObject({
target: Object.assign({ display_div: VIEWS.MAJOR_VIEW }, generateComplexObject(data, colourToggle, base_url)),
stage,
+ previousRepresentations: representations,
orientationMatrix: null
})
).finally(() => {
@@ -227,11 +231,12 @@ export const removeComplex = (stage, data, colourToggle, skipTracking = false) =
dispatch(removeFromComplexList(generateMoleculeId(data), skipTracking));
};
-export const addSurface = (stage, data, colourToggle, skipTracking = false) => dispatch => {
+export const addSurface = (stage, data, colourToggle, skipTracking = false, representations = undefined) => dispatch => {
dispatch(
loadObject({
target: Object.assign({ display_div: VIEWS.MAJOR_VIEW }, generateSurfaceObject(data, colourToggle, base_url)),
stage,
+ previousRepresentations: representations,
orientationMatrix: null
})
).finally(() => {
@@ -251,13 +256,14 @@ export const removeSurface = (stage, data, colourToggle, skipTracking = false) =
dispatch(removeFromSurfaceList(generateMoleculeId(data), skipTracking));
};
-export const addDensity = (stage, data, colourToggle) => dispatch => {
+export const addDensity = (stage, data, colourToggle, representations = undefined) => dispatch => {
console.log('TODO');
return;
dispatch(
loadObject({
target: Object.assign({ display_div: VIEWS.MAJOR_VIEW }, generateDensityObject(data, colourToggle, base_url)),
stage,
+ previousRepresentations: representations,
orientationMatrix: null
})
).finally(() => {
@@ -279,7 +285,7 @@ export const removeDensity = (stage, data, colourToggle) => dispatch => {
dispatch(removeFromDensityList(generateMoleculeId(data)));
};
-export const addLigand = (stage, data, colourToggle, centerOn = false, skipTracking = false) => (
+export const addLigand = (stage, data, colourToggle, centerOn = false, skipTracking = false, representations = undefined) => (
dispatch,
getState
) => {
@@ -289,7 +295,7 @@ export const addLigand = (stage, data, colourToggle, centerOn = false, skipTrack
loadObject({
target: Object.assign({ display_div: VIEWS.MAJOR_VIEW }, generateMoleculeObject(data, colourToggle)),
stage,
- undefined
+ previousRepresentations: representations
})
).finally(() => {
const ligandOrientation = stage.viewerControls.getOrientation();
@@ -395,21 +401,43 @@ export const hideAllSelectedMolecules = (stage, currentMolecules) => (dispatch,
dispatch(setHideAll(data));
};
-export const searchMoleculeGroupByMoleculeID = moleculeID => (dispatch, getState) =>
- api({ url: `${base_url}/api/molgroup/?mol_id=${moleculeID}` }).then(response => {
- let resultMolGroupID = null;
- const molGroupID = response?.data?.results[0]?.id;
- const mol_group_list = getState().apiReducers.mol_group_list;
+// export const searchMoleculeGroupByMoleculeID = moleculeID => (dispatch, getState) =>
+// api({ url: `${base_url}/api/molgroup/?mol_id=${moleculeID}` }).then(response => {
+// let resultMolGroupID = null;
+// const molGroupID = response?.data?.results[0]?.id;
+// const mol_group_list = getState().apiReducers.mol_group_list;
+
+// if (mol_group_list && Array.isArray(mol_group_list) && molGroupID) {
+// mol_group_list.forEach((item, index) => {
+// if (item.id === molGroupID) {
+// resultMolGroupID = index + 1;
+// }
+// });
+// }
+// return Promise.resolve(resultMolGroupID);
+// });
+
+export const searchMoleculeGroupByMoleculeID = moleculeId => (dispatch, getState) => {
+ const state = getState();
+ const all_mol_lists = state.apiReducers.all_mol_lists;
+
+ let resultMolGroupID = null;
+ const molGroupIds = Object.keys(all_mol_lists);
+ for (let groupId of molGroupIds) {
+ const mols = all_mol_lists[groupId];
+ for (let mol of mols) {
+ if (mol.id === moleculeId) {
+ resultMolGroupID = groupId;
+ break;
+ };
+ };
+ if (resultMolGroupID != null) {
+ break;
+ };
+ };
- if (mol_group_list && Array.isArray(mol_group_list) && molGroupID) {
- mol_group_list.forEach((item, index) => {
- if (item.id === molGroupID) {
- resultMolGroupID = index + 1;
- }
- });
- }
- return Promise.resolve(resultMolGroupID);
- });
+ return Promise.resolve(resultMolGroupID);
+}
export const applyDirectSelection = (stage, stageSummaryView) => (dispatch, getState) => {
const state = getState();
@@ -472,3 +500,52 @@ export const applyDirectSelection = (stage, stageSummaryView) => (dispatch, getS
dispatch(setDirectAccessProcessed(true));
}
};
+
+export const getMolImage = (molId, molType, width, height) => (dispatch, getState) => {
+ const state = getState();
+
+ const imageCache = state.previewReducers.molecule.imageCache;
+
+ const molIdStr = molId.toString();
+ if (imageCache.hasOwnProperty(molIdStr)) {
+ return new Promise((resolve, reject) => {
+ resolve(imageCache[molIdStr]);
+ });
+ } else {
+ return loadMolImage(molId, molType, width, height).then(i => {
+ if (!imageCache.hasOwnProperty(molIdStr)) {
+ dispatch(addImageToCache(molId.toString(), i));
+ };
+ return i;
+ });
+ }
+};
+
+export const loadMolImage = (molId, molType, width, height) => {
+ let url = undefined;
+ if (molType === MOL_TYPE.HIT) {
+ url = new URL(`${base_url}/api/molimg/${molId}/`);
+ url.searchParams.append('width', width);
+ url.searchParams.append('height', height);
+ } else if (molType === MOL_TYPE.DATASET) {
+ url = new URL(`${base_url}/viewer/img_from_smiles/`);
+ url.searchParams.append('width', width);
+ url.searchParams.append('height', height);
+ url.searchParams.append('smiles', molId);
+ } else {
+ console.error('Trying to load image for unknown molecule type.');
+ return Promise.resolve();
+ }
+
+ let onCancel = () => {};
+ return api({
+ url,
+ onCancel
+ }).then(response => {
+ if (molType === MOL_TYPE.HIT) {
+ return response.data['mol_image'];
+ } else {
+ return response.data;
+ }
+ });
+};
diff --git a/js/components/preview/molecule/redux/reducer.js b/js/components/preview/molecule/redux/reducer.js
index 4c6311f50..81348038d 100644
--- a/js/components/preview/molecule/redux/reducer.js
+++ b/js/components/preview/molecule/redux/reducer.js
@@ -1,7 +1,8 @@
import { constants } from './constants';
export const INITIAL_STATE = {
- sortDialogOpen: false
+ sortDialogOpen: false,
+ imageCache: {}
};
export const molecule = (state = INITIAL_STATE, action = {}) => {
@@ -14,6 +15,11 @@ export const molecule = (state = INITIAL_STATE, action = {}) => {
case constants.RELOAD_REDUCER:
return Object.assign({}, state, { ...action.payload });
+ case constants.ADD_IMAGE_TO_CACHE:
+ return {...state, imageCache: {
+ ...state.imageCache, [action.payload.molId]: action.payload.image
+ }};
+
default:
return state;
}
diff --git a/js/components/preview/molecule/redux/selectors.js b/js/components/preview/molecule/redux/selectors.js
index 9fe926a7e..15c6d1222 100644
--- a/js/components/preview/molecule/redux/selectors.js
+++ b/js/components/preview/molecule/redux/selectors.js
@@ -29,10 +29,31 @@ export const selectJoinedMoleculeList = createSelector(
});
});
}
+
return joinedMoleculeLists;
}
);
+export const getMoleculeList = createSelector(
+ getAllMolecules,
+ getMoleculeGroupLists,
+ (all_mol_lists, mol_group_list) => {
+ let cachedDataArray = [];
+ if (mol_group_list) {
+ mol_group_list.forEach(obj => {
+ const cachedData = all_mol_lists[obj.id];
+
+ if (cachedData && Array.isArray(cachedData)) {
+ cachedDataArray.push(...cachedData);
+ } else if (cachedData && cachedData.results && Array.isArray(cachedData.results)) {
+ cachedDataArray.push(...cachedData.results);
+ }
+ });
+ }
+
+ return cachedDataArray;
+ }
+);
export const selectAllMoleculeList = createSelector(
getAllMolecules,
getMoleculeGroupLists,
@@ -51,4 +72,4 @@ export const selectAllMoleculeList = createSelector(
return allMoleculesList;
}
-);
\ No newline at end of file
+);
diff --git a/js/components/preview/moleculeGroups/molGroupChecklist.js b/js/components/preview/moleculeGroups/molGroupChecklist.js
index 9bf99efe6..b7c3fc6a3 100644
--- a/js/components/preview/moleculeGroups/molGroupChecklist.js
+++ b/js/components/preview/moleculeGroups/molGroupChecklist.js
@@ -3,7 +3,7 @@ import { Grid, makeStyles, Checkbox, Tooltip, Typography } from '@material-ui/co
import { useDispatch, useSelector } from 'react-redux';
import { heightOfBody } from './molGroupSelector';
import { VIEWS } from '../../../constants/constants';
-import { useDisableUserInteraction } from '../../helpers/useEnableUserInteracion';
+// import { useDisableUserInteraction } from '../../helpers/useEnableUserInteracion';
import { NglContext } from '../../nglView/nglProvider';
import { onSelectMoleculeGroup } from './redux/dispatchActions';
@@ -44,7 +44,7 @@ const useStyles = makeStyles(theme => ({
const molGroupChecklist = memo(({}) => {
const classes = useStyles();
- const disableUserInteraction = useDisableUserInteraction();
+ // const disableUserInteraction = useDisableUserInteraction();
const { getNglView } = useContext(NglContext);
const stageSummaryView = getNglView(VIEWS.SUMMARY_VIEW) && getNglView(VIEWS.SUMMARY_VIEW).stage;
const majorViewStage = getNglView(VIEWS.MAJOR_VIEW) && getNglView(VIEWS.MAJOR_VIEW).stage;
@@ -74,7 +74,7 @@ const molGroupChecklist = memo(({}) => {
color="primary"
checked={checked}
onChange={event => dispatch(onSelectMoleculeGroup({ moleculeGroup, stageSummaryView, majorViewStage, selectGroup: event.target.checked }))}
- disabled={disableUserInteraction}
+ disabled={false}
/>
diff --git a/js/components/preview/moleculeGroups/molGroupSelector.js b/js/components/preview/moleculeGroups/molGroupSelector.js
index 0a9841490..297ebeb3c 100644
--- a/js/components/preview/moleculeGroups/molGroupSelector.js
+++ b/js/components/preview/moleculeGroups/molGroupSelector.js
@@ -9,7 +9,7 @@ import { useDispatch } from 'react-redux';
import { VIEWS } from '../../../constants/constants';
import { withLoadingMolGroupList } from './withLoadingMolGroupList';
import { NglContext } from '../../nglView/nglProvider';
-import { useDisableUserInteraction } from '../../helpers/useEnableUserInteracion';
+// import { useDisableUserInteraction } from '../../helpers/useEnableUserInteracion';
import { clearMoleculeGroupSelection } from './redux/dispatchActions';
export const heightOfBody = '164px';
@@ -34,7 +34,7 @@ const MolGroupSelector = memo(({ handleHeightChange }) => {
const ref = useRef(null);
const { getNglView } = useContext(NglContext);
- const disableUserInteraction = useDisableUserInteraction();
+ // const disableUserInteraction = useDisableUserInteraction();
const dispatch = useDispatch();
return (
@@ -47,7 +47,7 @@ const MolGroupSelector = memo(({ handleHeightChange }) => {
headerActions={[
,
@@ -66,7 +66,7 @@ export const withSnapshotManagement = WrappedComponent => {
color="primary"
onClick={() => dispatch(restoreSnapshotActions({ nglViewList }))}
startIcon={}
- disabled={disableShareButton || disableUserInteraction}
+ disabled={disableShareButton || false}
>
Restore
@@ -76,7 +76,7 @@ export const withSnapshotManagement = WrappedComponent => {
color="primary"
size="small"
startIcon={}
- disabled={disableShareButton || disableUserInteraction}
+ disabled={disableShareButton || false}
onClick={() => {
dispatch(saveAndShareSnapshot(nglViewList));
}}
@@ -102,7 +102,6 @@ export const withSnapshotManagement = WrappedComponent => {
targetName,
setSnackBarColor,
projectId,
- disableUserInteraction,
currentSnapshotID,
currentProject,
disableShareButton,
diff --git a/js/components/tracking/timelineView.js b/js/components/tracking/timelineView.js
index 18036eed2..28bd99e14 100644
--- a/js/components/tracking/timelineView.js
+++ b/js/components/tracking/timelineView.js
@@ -4,7 +4,7 @@ import { makeStyles, IconButton, Tooltip, Grid, Box, Chip } from '@material-ui/c
import { Check, Clear, Warning, Favorite, Star } from '@material-ui/icons';
import { actionAnnotation } from '../../reducers/tracking/constants';
import { TimelineEvent } from 'react-event-timeline';
-import EditableText from './editableText';
+import EditableText from './EditableText';
import palette from '../../theme/palette';
import { updateTrackingActions } from '../../reducers/tracking/dispatchActions';
import { actionType } from '../../reducers/tracking/constants';
diff --git a/js/reducers/api/actions.js b/js/reducers/api/actions.js
index 925e9b56a..d384e30e4 100644
--- a/js/reducers/api/actions.js
+++ b/js/reducers/api/actions.js
@@ -59,6 +59,14 @@ export const setMolGroupOn = function(mol_group_id) {
};
};
+export const setMolGroupOff = function(mol_group_id, selectionGroups) {
+ return {
+ type: constants.SET_MOL_GROUP_OFF,
+ mol_group_off: mol_group_id,
+ selectionGroups
+ };
+};
+
export const setMolGroupList = function(mol_group_list) {
return {
type: constants.SET_MOL_GROUP_LIST,
diff --git a/js/reducers/api/constants.js b/js/reducers/api/constants.js
index b15a46d25..00208acbc 100644
--- a/js/reducers/api/constants.js
+++ b/js/reducers/api/constants.js
@@ -11,6 +11,7 @@ export const constants = {
SET_PANNDA_EVENT_ON: prefix + 'SET_PANNDA_EVENT_ON',
SET_MOL_GROUP_ON: prefix + 'SET_MOL_GROUP_ON',
+ SET_MOL_GROUP_OFF: prefix + 'SET_MOL_GROUP_OFF',
SET_MOL_GROUP_LIST: prefix + 'SET_MOL_GROUP_LIST',
SET_MOLECULE_LIST: prefix + 'SET_MOLECULE_LIST',
SET_CACHED_MOL_LISTS: prefix + 'SET_CACHED_MOL_LISTS',
diff --git a/js/reducers/ngl/actions.js b/js/reducers/ngl/actions.js
index e3256d0ec..b9ac62da3 100644
--- a/js/reducers/ngl/actions.js
+++ b/js/reducers/ngl/actions.js
@@ -1,6 +1,8 @@
/**
* Created by abradley on 03/03/2018.
*/
+import { constant } from 'lodash';
+import { constants } from '../selection/constants';
import { CONSTANTS } from './constants';
export const loadNglObject = (target, representations) => ({ type: CONSTANTS.LOAD_OBJECT, target, representations });
@@ -86,3 +88,8 @@ export const removeMoleculeOrientation = moleculeGroupID => ({
type: CONSTANTS.REMOVE_MOLECULE_ORIENTATION,
payload: moleculeGroupID
});
+
+export const addToPdbCache = (name, cacheItem) => ({
+ type: CONSTANTS.ADD_TO_PDB_CACHE,
+ payload: {name: name, cacheItem: cacheItem}
+});
diff --git a/js/reducers/ngl/actions.test.js b/js/reducers/ngl/actions.test.js
index d862ef084..bf7e6ac9a 100644
--- a/js/reducers/ngl/actions.test.js
+++ b/js/reducers/ngl/actions.test.js
@@ -297,35 +297,6 @@ describe("testing ngl reducer's actions", () => {
expect(result.nglOrientations).toStrictEqual(defaultScene[SCENES.defaultScene].nglOrientations);
});
- /*
- it('should reset current state to session scene', () => {
- expect.hasAssertions();
- const sessionScene = {
- objectsInView: {
- molecule_1: {
- properties: [{ a: 'dfg' }],
- representations: [
- {
- lastKnownID: 78904,
- uuid: 9903,
- other: 'fdjsdj'
- },
- {
- lastKnownID: 178904,
- uuid: 19903,
- other: '1fdjsdj'
- }
- ]
- }
- },
- nglOrientations: { a: [24, 566] }
- };
-
- let result = nglReducers(initialState, actions.setNglStateFromCurrentSnapshot(sessionScene));
- expect(result.objectsInView).toStrictEqual(sessionScene.objectsInView);
- expect(result.nglOrientations).toStrictEqual(sessionScene.nglOrientations);
- });
-*/
it('should remove all ngl view components', () => {
expect.hasAssertions();
let result = nglReducers(initialState, actions.removeAllNglComponents());
diff --git a/js/reducers/ngl/constants.js b/js/reducers/ngl/constants.js
index 78ca7400b..86a4de479 100644
--- a/js/reducers/ngl/constants.js
+++ b/js/reducers/ngl/constants.js
@@ -22,7 +22,9 @@ export const CONSTANTS = {
SET_MOLECULE_ORIENTATIONS: prefix + 'SET_MOLECULE_ORIENTATIONS',
APPEND_MOLECULE_ORIENTATION: prefix + 'SET_MOLECULE_ORIENTATION',
- REMOVE_MOLECULE_ORIENTATION: prefix + 'REMOVE_MOLECULE_ORIENTATION'
+ REMOVE_MOLECULE_ORIENTATION: prefix + 'REMOVE_MOLECULE_ORIENTATION',
+
+ ADD_TO_PDB_CACHE: prefix + 'ADD_TO_PDB_CACHE'
};
export const SCENES = {
diff --git a/js/reducers/ngl/dispatchActions.js b/js/reducers/ngl/dispatchActions.js
index 770dcde77..4e0665206 100644
--- a/js/reducers/ngl/dispatchActions.js
+++ b/js/reducers/ngl/dispatchActions.js
@@ -45,7 +45,8 @@ export const loadObject = ({
object_name: versionFixedTarget.name,
representations: previousRepresentations,
orientationMatrix,
- markAsRightSideLigand
+ markAsRightSideLigand,
+ dispatch
})
.then(representations => {
dispatch(loadNglObject(versionFixedTarget, representations))
diff --git a/js/reducers/ngl/nglReducers.js b/js/reducers/ngl/nglReducers.js
index a187a370b..dd528df9d 100644
--- a/js/reducers/ngl/nglReducers.js
+++ b/js/reducers/ngl/nglReducers.js
@@ -1,6 +1,5 @@
import { BACKGROUND_COLOR, NGL_PARAMS } from '../../components/nglView/constants';
import { CONSTANTS } from './constants';
-import NglView from '../../components/nglView/nglView';
import { VIEWS } from '../../constants/constants';
export const INITIAL_STATE = {
@@ -39,7 +38,8 @@ export const INITIAL_STATE = {
[VIEWS.MAJOR_VIEW]: 0,
[VIEWS.SUMMARY_VIEW]: 0
},
- moleculeOrientations: {}
+ moleculeOrientations: {},
+ pdbCache: {}
};
export default function nglReducers(state = INITIAL_STATE, action = {}) {
@@ -174,6 +174,11 @@ export default function nglReducers(state = INITIAL_STATE, action = {}) {
}
return Object.assign({}, state, { moleculeOrientations: diminishedMoleculeOrientations });
+ case CONSTANTS.ADD_TO_PDB_CACHE:
+ return {...state, pdbCache: {
+ ...state.pdbCache, [action.payload.name]: action.payload.cacheItem
+ }};
+
default:
return state;
}
diff --git a/js/reducers/selection/actions.js b/js/reducers/selection/actions.js
index 9c154498c..d1b9a5479 100644
--- a/js/reducers/selection/actions.js
+++ b/js/reducers/selection/actions.js
@@ -39,10 +39,11 @@ export const setCurrentVector = vectorSmile => {
};
};
-export const setFragmentDisplayList = function(fragmentDisplayList) {
+export const setFragmentDisplayList = function(fragmentDisplayList, skipTracking = false) {
return {
type: constants.SET_FRAGMENT_DISPLAY_LIST,
- fragmentDisplayList: fragmentDisplayList
+ fragmentDisplayList: fragmentDisplayList,
+ skipTracking
};
};
@@ -62,10 +63,11 @@ export const removeFromFragmentDisplayList = function(item, skipTracking = false
};
};
-export const setProteinList = function(proteinList) {
+export const setProteinList = function(proteinList, skipTracking = false) {
return {
type: constants.SET_PROTEIN_LIST,
- proteinList: proteinList
+ proteinList: proteinList,
+ skipTracking
};
};
@@ -84,10 +86,11 @@ export const removeFromProteinList = function(item, skipTracking = false) {
skipTracking: skipTracking
};
};
-export const setComplexList = function(complexList) {
+export const setComplexList = function(complexList, skipTracking = false) {
return {
type: constants.SET_COMPLEX_LIST,
- complexList: complexList
+ complexList: complexList,
+ skipTracking
};
};
@@ -107,10 +110,11 @@ export const removeFromComplexList = function(item, skipTracking = false) {
};
};
-export const setSurfaceList = function(surfaceList) {
+export const setSurfaceList = function(surfaceList, skipTracking = false) {
return {
type: constants.SET_SURFACE_LIST,
- surfaceList: surfaceList
+ surfaceList: surfaceList,
+ skipTracking
};
};
@@ -151,10 +155,11 @@ export const removeFromDensityList = function(item) {
};
};
-export const setVectorOnList = function(vectorOnList) {
+export const setVectorOnList = function(vectorOnList, skipTracking = false) {
return {
type: constants.SET_VECTOR_ON_LIST,
- vectorOnList: vectorOnList
+ vectorOnList: vectorOnList,
+ skipTracking
};
};
diff --git a/js/reducers/tracking/dispatchActions.js b/js/reducers/tracking/dispatchActions.js
index 6b992f11a..d1e0e2f89 100644
--- a/js/reducers/tracking/dispatchActions.js
+++ b/js/reducers/tracking/dispatchActions.js
@@ -116,6 +116,102 @@ export const saveCurrentActionsList = (snapshot, project, nglViewList, all = fal
const saveActionsList = (project, snapshot, actionList, nglViewList) => async (dispatch, getState) => {
const state = getState();
+ const currentTargetOn = state.apiReducers.target_on;
+ const currentSites = state.selectionReducers.mol_group_selection;
+ const currentLigands = state.selectionReducers.fragmentDisplayList;
+ const currentProteins = state.selectionReducers.proteinList;
+ const currentComplexes = state.selectionReducers.complexList;
+ const currentSelectionAll = state.selectionReducers.moleculeAllSelection;
+
+ const currentDatasetLigands = state.datasetsReducers.ligandLists;
+ const currentDatasetProteins = state.datasetsReducers.proteinLists;
+ const currentDatasetComplexes = state.datasetsReducers.complexLists;
+ const currentDatasetSelectionAll = state.datasetsReducers.moleculeAllSelection;
+
+ const currentTargets = (currentTargetOn && [currentTargetOn]) || [];
+
+ let orderedActionList = actionList.reverse((a, b) => a.timestamp - b.timestamp);
+
+ let currentActions = [];
+
+ getCurrentActionList(orderedActionList, actionType.TARGET_LOADED, getCollection(currentTargets), currentActions);
+ getCurrentActionList(orderedActionList, actionType.SITE_TURNED_ON, getCollection(currentSites), currentActions);
+ getCurrentActionList(orderedActionList, actionType.LIGAND_TURNED_ON, getCollection(currentLigands), currentActions);
+
+ getCurrentActionListOfAllSelection(
+ orderedActionList,
+ actionType.ALL_TURNED_ON,
+ getCollection(currentSelectionAll),
+ currentActions,
+ getCollection(currentLigands),
+ getCollection(currentProteins),
+ getCollection(currentComplexes)
+ );
+
+ getCurrentActionListOfAllSelectionByType(
+ orderedActionList,
+ actionType.ALL_TURNED_ON_BY_TYPE,
+ 'ligand',
+ getCollection(currentLigands),
+ currentActions
+ );
+
+ getCurrentActionListOfAllSelectionByType(
+ orderedActionList,
+ actionType.ALL_TURNED_ON_BY_TYPE,
+ 'protein',
+ getCollection(currentProteins),
+ currentActions
+ );
+
+ getCurrentActionListOfAllSelectionByType(
+ orderedActionList,
+ actionType.ALL_TURNED_ON_BY_TYPE,
+ 'complex',
+ getCollection(currentComplexes),
+ currentActions
+ );
+
+ getCurrentActionListOfAllSelectionByTypeOfDataset(
+ orderedActionList,
+ actionType.ALL_TURNED_ON_BY_TYPE,
+ 'ligand',
+ getCollectionOfDataset(currentDatasetLigands),
+ currentActions
+ );
+
+ getCurrentActionListOfAllSelectionByTypeOfDataset(
+ orderedActionList,
+ actionType.ALL_TURNED_ON_BY_TYPE,
+ 'protein',
+ getCollectionOfDataset(currentDatasetProteins),
+ currentActions
+ );
+
+ getCurrentActionListOfAllSelectionByTypeOfDataset(
+ orderedActionList,
+ actionType.ALL_TURNED_ON_BY_TYPE,
+ 'complex',
+ getCollectionOfDataset(currentDatasetComplexes),
+ currentActions
+ );
+
+ getCurrentActionListOfAllSelection(
+ orderedActionList,
+ actionType.ALL_TURNED_ON,
+ getCollectionOfDataset(currentDatasetSelectionAll),
+ currentActions,
+ getCollectionOfDataset(currentDatasetLigands),
+ getCollectionOfDataset(currentDatasetProteins),
+ getCollectionOfDataset(currentDatasetComplexes)
+ );
+
+ getCurrentActionList(
+ orderedActionList,
+ actionType.SIDECHAINS_TURNED_ON,
+ getCollection(currentProteins),
+ currentActions
+ );
const snapshotID = snapshot && snapshot.id;
if (snapshotID) {
const currentTargetOn = state.apiReducers.target_on;
@@ -359,6 +455,91 @@ const getCurrentActionList = (orderedActionList, type, collection, currentAction
}
};
+const getCurrentActionListOfAllSelection = (
+ orderedActionList,
+ type,
+ collection,
+ currentActions,
+ ligandList,
+ proteinList,
+ complexList
+) => {
+ let actionList = orderedActionList.filter(action => action.type === type);
+
+ if (collection) {
+ collection.forEach(data => {
+ let action = actionList.find(action => action.object_id === data.id && action.dataset_id === data.datasetId);
+
+ if (action) {
+ let ligandAction = ligandList.find(
+ data => data.id === action.object_id && action.dataset_id === data.datasetId
+ );
+ let proteinAction = proteinList.find(
+ data => data.id === action.object_id && action.dataset_id === data.datasetId
+ );
+ let complexAction = complexList.find(
+ data => data.id === action.object_id && action.dataset_id === data.datasetId
+ );
+
+ let isLigand = ligandAction && ligandAction != null ? true : false;
+ let isProtein = proteinAction && proteinAction != null ? true : false;
+ let isComplex = complexAction && complexAction != null ? true : false;
+ currentActions.push(
+ Object.assign({ ...action, isLigand: isLigand, isProtein: isProtein, isComplex: isComplex })
+ );
+ }
+ });
+ }
+};
+
+const getCurrentActionListOfAllSelectionByType = (orderedActionList, type, controlType, collection, currentActions) => {
+ let action = orderedActionList.find(
+ action =>
+ action.type === type &&
+ action.control_type === controlType &&
+ (action.object_type === actionObjectType.MOLECULE || action.object_type === actionObjectType.INSPIRATION)
+ );
+ if (action && collection) {
+ let actionItems = action.items;
+ let items = [];
+ collection.forEach(data => {
+ let item = actionItems.find(action => action.id === data.id && action.dataset_id === data.datasetId);
+ if (item) {
+ items.push(item);
+ }
+ });
+
+ currentActions.push(Object.assign({ ...action, items: items }));
+ }
+};
+
+const getCurrentActionListOfAllSelectionByTypeOfDataset = (
+ orderedActionList,
+ type,
+ controlType,
+ collection,
+ currentActions
+) => {
+ let action = orderedActionList.find(
+ action =>
+ action.type === type &&
+ action.control_type === controlType &&
+ (action.object_type === actionObjectType.COMPOUND || action.object_type === actionObjectType.CROSS_REFERENCE)
+ );
+ if (action && collection) {
+ let actionItems = action.items;
+ let items = [];
+ collection.forEach(data => {
+ let item = actionItems.find(item => item.molecule.id === data.id && item.datasetID === data.datasetId);
+ if (item) {
+ items.push(item);
+ }
+ });
+
+ currentActions.push(Object.assign({ ...action, items: items }));
+ }
+};
+
const getCollection = dataList => {
let list = [];
if (dataList) {
@@ -509,8 +690,8 @@ export const restoreAfterTargetActions = (stages, projectId) => async (dispatch,
.finally(() => {});
await dispatch(restoreSitesActions(orderedActionList, summaryView));
- await dispatch(loadAllMolecules(orderedActionList, targetId, majorView.stage));
- await dispatch(loadAllDatasets(orderedActionList, targetId, majorView.stage));
+ await dispatch(loadData(orderedActionList, targetId, majorView));
+ await dispatch(restoreActions(orderedActionList, majorView.stage));
await dispatch(restoreRepresentationActions(orderedActionList, stages));
await dispatch(restoreProject(projectId));
dispatch(restoreSnapshotImageActions(projectId));
@@ -533,21 +714,23 @@ const restoreNglStateAction = (orderedActionList, stages) => (dispatch, getState
}
};
+const restoreActions = (orderedActionList, stage) => (dispatch, getState) => {
+ dispatch(restoreMoleculesActions(orderedActionList, stage));
+};
+
+const loadData = (orderedActionList, targetId, majorView) => async (dispatch, getState) => {
+ await dispatch(loadAllMolecules(orderedActionList, targetId, majorView.stage));
+ await dispatch(loadAllDatasets(orderedActionList, targetId, majorView.stage));
+};
+
const loadAllDatasets = (orderedActionList, target_on, stage) => async (dispatch, getState) => {
dispatch(setMoleculeListIsLoading(true));
- await dispatch(loadDataSets(target_on))
- .then(results => {
- return dispatch(loadDatasetCompoundsWithScores());
- })
- .catch(error => {
- throw new Error(error);
- })
- .finally(() => {
- dispatch(restoreCompoundsActions(orderedActionList, stage));
- dispatch(setMoleculeListIsLoading(false));
- dispatch(restoreAllSelectionActions(orderedActionList, stage, false));
- dispatch(setIsTrackingCompoundsRestoring(false));
- });
+
+ await dispatch(loadDataSets(target_on));
+ await dispatch(loadDatasetCompoundsWithScores());
+ dispatch(setMoleculeListIsLoading(false));
+
+ dispatch(restoreCompoundsActions(orderedActionList, stage));
};
const loadAllMolecules = (orderedActionList, target_on, stage) => async (dispatch, getState) => {
@@ -574,8 +757,6 @@ const loadAllMolecules = (orderedActionList, target_on, stage) => async (dispatc
listToSet[molResult.mol_group] = molResult.molecules;
});
dispatch(setAllMolLists(listToSet));
- dispatch(restoreMoleculesActions(orderedActionList, stage));
- dispatch(setIsTrackingMoleculesRestoring(false));
} catch (error) {
throw new Error(error);
}
@@ -616,6 +797,8 @@ const restoreMoleculesActions = (orderedActionList, stage) => (dispatch, getStat
dispatch(restoreCartActions(moleculesAction));
dispatch(restoreAllSelectionActions(orderedActionList, stage, true));
+ dispatch(restoreAllSelectionByTypeActions(orderedActionList, stage, true));
+ dispatch(setIsTrackingMoleculesRestoring(false));
};
const restoreCartActions = moleculesAction => (dispatch, getState) => {
@@ -652,6 +835,14 @@ const restoreAllSelectionActions = (moleculesAction, stage, isSelection) => (dis
if (actions) {
actions.forEach(action => {
if (action) {
+ if (isSelection) {
+ dispatch(setSelectedAll(action.item, action.isLigand, action.isProtein, action.isComplex));
+ } else {
+ dispatch(
+ setSelectedAllOfDataset(action.dataset_id, action.item, action.isLigand, action.isProtein, action.isComplex)
+ );
+ }
+
if (action.isLigand) {
dispatch(handleMoleculeAction(action, 'ligand', true, stage, state, true));
}
@@ -668,6 +859,69 @@ const restoreAllSelectionActions = (moleculesAction, stage, isSelection) => (dis
}
};
+const restoreAllSelectionByTypeActions = (moleculesAction, stage, isSelection) => (dispatch, getState) => {
+
+ let actions =
+ isSelection === true
+ ? moleculesAction.filter(
+ action =>
+ action.type === actionType.ALL_TURNED_ON_BY_TYPE &&
+ (action.object_type === actionObjectType.INSPIRATION || action.object_type === actionObjectType.MOLECULE)
+ )
+ : moleculesAction.filter(
+ action =>
+ action.type === actionType.ALL_TURNED_ON_BY_TYPE &&
+ (action.object_type === actionObjectType.CROSS_REFERENCE ||
+ action.object_type === actionObjectType.COMPOUND)
+ );
+
+ if (actions) {
+ actions.forEach(action => {
+ if (action) {
+ let actionItems = action.items;
+ let type = action.control_type;
+
+ if (isSelection) {
+ dispatch(setSelectedAllByType(type, actionItems, action.object_type === actionObjectType.INSPIRATION));
+
+ actionItems.forEach(data => {
+ if (data) {
+ if (type === 'ligand') {
+ dispatch(addType[type](stage, data, colourList[data.id % colourList.length], true, true));
+ } else {
+ dispatch(addType[type](stage, data, colourList[data.id % colourList.length], true));
+ }
+ }
+ });
+ } else {
+ dispatch(
+ setSelectedAllByTypeOfDataset(
+ type,
+ action.dataset_id,
+ actionItems,
+ action.object_type === actionObjectType.CROSS_REFERENCE
+ )
+ );
+
+ actionItems.forEach(data => {
+ if (data && data.molecule) {
+ dispatch(
+ addTypeCompound[type](
+ stage,
+ data.molecule,
+ colourList[data.molecule.id % colourList.length],
+ data.datasetID,
+ true
+ )
+ );
+ }
+ });
+ }
+ }
+ });
+ }
+};
+
const restoreRepresentationActions = (moleculesAction, stages) => (dispatch, getState) => {
const nglView = stages.find(view => view.id === VIEWS.MAJOR_VIEW);
@@ -746,6 +1000,10 @@ const restoreCompoundsActions = (orderedActionList, stage) => (dispatch, getStat
dispatch(appendMoleculeToCompoundsOfDatasetToBuy(action.dataset_id, data.id, data.name));
}
});
+
+ dispatch(restoreAllSelectionActions(orderedActionList, stage, false));
+ dispatch(restoreAllSelectionByTypeActions(orderedActionList, stage, false));
+ dispatch(setIsTrackingCompoundsRestoring(false));
};
const addType = {
@@ -854,7 +1112,9 @@ const getCompound = (action, state) => {
if (moleculeList) {
let moleculeListOfDataset = moleculeList[datasetID];
- molecule = moleculeListOfDataset.find(m => m.name === name);
+ if (moleculeListOfDataset) {
+ molecule = moleculeListOfDataset.find(m => m.name === name);
+ }
}
return molecule;
};
@@ -1138,7 +1398,13 @@ const handleAllActionByType = (action, isAdd, stage) => (dispatch, getState) =>
actionItems.forEach(data => {
if (data && data.molecule) {
dispatch(
- addTypeCompound[type](stage, data.molecule, colourList[data.id % colourList.length], data.datasetID, true)
+ addTypeCompound[type](
+ stage,
+ data.molecule,
+ colourList[data.molecule.id % colourList.length],
+ data.datasetID,
+ true
+ )
);
}
});
@@ -1158,7 +1424,7 @@ const handleAllActionByType = (action, isAdd, stage) => (dispatch, getState) =>
removeTypeCompound[type](
stage,
data.molecule,
- colourList[data.id % colourList.length],
+ colourList[data.molecule.id % colourList.length],
data.datasetID,
true
)
@@ -1378,10 +1644,24 @@ const removeRepresentation = (parentKey, representation, nglView) => (dispatch,
const handleMoleculeGroupAction = (action, isSelected, stageSummaryView, majorViewStage) => (dispatch, getState) => {
const state = getState();
if (action) {
- let moleculeGroup = getMolGroup(action.object_name, state);
+ const { selectionGroups, object_name } = action;
+ let moleculeGroup = getMolGroup(object_name, state);
if (moleculeGroup) {
if (isSelected === true) {
dispatch(selectMoleculeGroup(moleculeGroup, stageSummaryView));
+
+ for (const type in selectionGroups) {
+ if (selectionGroups.hasOwnProperty(type)) {
+ const typeGroup = selectionGroups[type];
+ for (const mol of typeGroup) {
+ if (type === 'ligand') {
+ dispatch(addType[type](majorViewStage, mol, colourList[mol.id % colourList.length], true, true));
+ } else {
+ dispatch(addType[type](majorViewStage, mol, colourList[mol.id % colourList.length], true));
+ }
+ }
+ }
+ }
} else {
dispatch(onDeselectMoleculeGroup({ moleculeGroup, stageSummaryView, majorViewStage }));
}
diff --git a/js/reducers/tracking/trackingActions.js b/js/reducers/tracking/trackingActions.js
index 88eede735..637cf689e 100644
--- a/js/reducers/tracking/trackingActions.js
+++ b/js/reducers/tracking/trackingActions.js
@@ -44,6 +44,19 @@ export const findTrackAction = (action, state) => {
};
}
}
+ } else if (action.type.includes(apiConstants.SET_MOL_GROUP_OFF)) {
+ const { mol_group_off, selectionGroups } = action;
+ let molGroupName = getMolGroupName(mol_group_off, state);
+ trackAction = {
+ type: actionType.SITE_TURNED_OFF,
+ timestamp: Date.now(),
+ username: username,
+ object_type: actionObjectType.SITE,
+ object_name: molGroupName,
+ object_id: mol_group_off,
+ selectionGroups,
+ text: `${actionDescription.SITE} ${molGroupName} ${actionDescription.TURNED_OFF}`
+ };
} else if (action.type.includes(selectionConstants.SET_OBJECT_SELECTION)) {
let objectId = action.payload && action.payload[0];
if (objectId) {
diff --git a/package.json b/package.json
index 2ae362757..a7c112f0b 100755
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "fragalysis-frontend",
- "version": "0.9.30",
+ "version": "0.9.41",
"description": "Frontend for fragalysis",
"main": "webpack.config.js",
"scripts": {