diff --git a/js/components/datasets/datasetMoleculeList.js b/js/components/datasets/datasetMoleculeList.js index d1ec6f7f0..828b1b2bd 100644 --- a/js/components/datasets/datasetMoleculeList.js +++ b/js/components/datasets/datasetMoleculeList.js @@ -34,10 +34,9 @@ import { removeDatasetComplex, addDatasetSurface, removeDatasetSurface, - resetCrossReferenceDialog, autoHideDatasetDialogsOnScroll } from './redux/dispatchActions'; -import { setFilterDialogOpen, setIsOpenInspirationDialog, setSearchStringOfCompoundSet } from './redux/actions'; +import { setFilterDialogOpen, setSearchStringOfCompoundSet } from './redux/actions'; import { DatasetFilter } from './datasetFilter'; import { FilterList, Search, Link } from '@material-ui/icons'; import { getFilteredDatasetMoleculeList } from './redux/selectors'; @@ -45,6 +44,7 @@ import { debounce } from 'lodash'; import { InspirationDialog } from './inspirationDialog'; import { CrossReferenceDialog } from './crossReferenceDialog'; import { AlertModal } from '../common/Modal/AlertModal'; +import { setSelectedAllByType, setDeselectedAllByType } from './redux/actions'; const useStyles = makeStyles(theme => ({ container: { @@ -311,15 +311,17 @@ export const DatasetMoleculeList = memo( // TODO so this could lead to inconsistend behaviour while scrolling // TODO maybe change "currentMolecules.forEach" to "{type}List.forEach" - const removeSelectedType = type => { + const removeSelectedType = (type, skipTracking) => { joinedMoleculeLists.forEach(molecule => { - dispatch(removeType[type](stage, molecule, colourList[molecule.id % colourList.length], datasetID)); + dispatch( + removeType[type](stage, molecule, colourList[molecule.id % colourList.length], datasetID, skipTracking) + ); }); selectedAll.current = false; }; - const addNewType = type => { + const addNewType = (type, skipTracking) => { joinedMoleculeLists.forEach(molecule => { - dispatch(addType[type](stage, molecule, colourList[molecule.id % colourList.length], datasetID)); + dispatch(addType[type](stage, molecule, colourList[molecule.id % colourList.length], datasetID, skipTracking)); }); }; const ucfirst = string => { @@ -335,12 +337,46 @@ export const DatasetMoleculeList = memo( removeSelectedType(type); } else if (!calledFromSelectAll) { if (eval('is' + ucfirst(type) + 'On') === false) { - addNewType(type); + let molecules = getSelectedMoleculesByType(type, true); + dispatch(setSelectedAllByType(type, datasetID, molecules)); + addNewType(type, true); } else { - removeSelectedType(type); + let molecules = getSelectedMoleculesByType(type, false); + dispatch(setDeselectedAllByType(type, datasetID, molecules)); + removeSelectedType(type, true); } } }; + + const getSelectedMoleculesByType = (type, isAdd) => { + switch (type) { + case 'ligand': + return isAdd ? getMoleculesToSelect(ligandList) : getMoleculesToDeselect(ligandList); + case 'protein': + return isAdd ? getMoleculesToSelect(proteinList) : getMoleculesToDeselect(proteinList); + case 'complex': + return isAdd ? getMoleculesToSelect(complexList) : getMoleculesToDeselect(complexList); + default: + return null; + } + }; + + const getMoleculesToSelect = list => { + let molecules = joinedMoleculeLists.filter(m => !list.includes(m.id)); + let data = molecules.map(m => { + return { datasetID, molecule: m }; + }); + return data; + }; + + const getMoleculesToDeselect = list => { + let molecules = joinedMoleculeLists.filter(m => list.includes(m.id)); + let data = molecules.map(m => { + return { datasetID, molecule: m }; + }); + return data; + }; + let debouncedFn; const handleSearch = event => { @@ -456,7 +492,7 @@ export const DatasetMoleculeList = memo( diff --git a/js/components/datasets/datasetMoleculeView.js b/js/components/datasets/datasetMoleculeView.js index eb42095d3..d834c70d1 100644 --- a/js/components/datasets/datasetMoleculeView.js +++ b/js/components/datasets/datasetMoleculeView.js @@ -470,9 +470,9 @@ export const DatasetMoleculeView = memo( const setCalledFromAll = () => { let isSelected = selectedAll.current === true; if (isSelected) { - dispatch(setSelectedAll(datasetID, data)); + dispatch(setSelectedAll(datasetID, data, true, true, true)); } else { - dispatch(setDeselectedAll(datasetID, data)); + dispatch(setDeselectedAll(datasetID, data, isLigandOn, isProteinOn, isComplexOn)); } }; diff --git a/js/components/datasets/inspirationDialog.js b/js/components/datasets/inspirationDialog.js index 007782ab3..867090fd3 100644 --- a/js/components/datasets/inspirationDialog.js +++ b/js/components/datasets/inspirationDialog.js @@ -37,6 +37,7 @@ import { NglContext } from '../nglView/nglProvider'; import { VIEWS } from '../../constants/constants'; import { Panel } from '../common/Surfaces/Panel'; import { changeButtonClassname } from './helpers'; +import { setSelectedAllByType, setDeselectedAllByType } from '../../reducers/selection/actions'; const useStyles = makeStyles(theme => ({ paper: { @@ -254,17 +255,30 @@ export const InspirationDialog = memo( }); }; - const removeSelectedType = type => { - moleculeList.forEach(molecule => { - dispatch(removeType[type](stage, molecule, colourList[molecule.id % colourList.length], datasetID)); - }); + const removeSelectedType = (type, skipTracking = false) => { + if (type === 'ligand') { + moleculeList.forEach(molecule => { + dispatch(removeType[type](stage, molecule, colourList[molecule.id % colourList.length], false, skipTracking)); + }); + } else { + moleculeList.forEach(molecule => { + dispatch(removeType[type](stage, molecule, colourList[molecule.id % colourList.length], skipTracking)); + }); + } + selectedAll.current = false; }; - const addNewType = type => { - moleculeList.forEach(molecule => { - dispatch(addType[type](stage, molecule, colourList[molecule.id % colourList.length])); - }); + const addNewType = (type, skipTracking = false) => { + if (type === 'ligand') { + moleculeList.forEach(molecule => { + dispatch(addType[type](stage, molecule, colourList[molecule.id % colourList.length], false, skipTracking)); + }); + } else { + moleculeList.forEach(molecule => { + dispatch(addType[type](stage, molecule, colourList[molecule.id % colourList.length], skipTracking)); + }); + } }; const ucfirst = string => { @@ -281,12 +295,40 @@ export const InspirationDialog = memo( removeSelectedType(type); } else if (!calledFromSelectAll) { if (eval('is' + ucfirst(type) + 'On') === false) { - addNewType(type); + let molecules = getSelectedMoleculesByType(type, true); + dispatch(setSelectedAllByType(type, molecules, true)); + addNewType(type, true); } else { - removeSelectedType(type); + let molecules = getSelectedMoleculesByType(type, false); + dispatch(setDeselectedAllByType(type, molecules, true)); + removeSelectedType(type, true); } } }; + + const getSelectedMoleculesByType = (type, isAdd) => { + switch (type) { + case 'ligand': + return isAdd ? getMoleculesToSelect(ligandList) : getMoleculesToDeselect(ligandList); + case 'protein': + return isAdd ? getMoleculesToSelect(proteinList) : getMoleculesToDeselect(proteinList); + case 'complex': + return isAdd ? getMoleculesToSelect(complexList) : getMoleculesToDeselect(complexList); + default: + return null; + } + }; + + const getMoleculesToSelect = list => { + let molecules = moleculeList.filter(m => !list.includes(m.id)); + return molecules; + }; + + const getMoleculesToDeselect = list => { + let molecules = moleculeList.filter(m => list.includes(m.id)); + return molecules; + }; + // TODO refactor to this line return ( diff --git a/js/components/datasets/redux/actions.js b/js/components/datasets/redux/actions.js index 469cd049e..75d7f144a 100644 --- a/js/components/datasets/redux/actions.js +++ b/js/components/datasets/redux/actions.js @@ -307,18 +307,44 @@ export const resetDatasetsState = () => { }; }; -export const setSelectedAll = (datsetID, item) => ({ +export const setSelectedAll = (datsetID, item, isLigand, isProtein, isComplex) => ({ type: constants.SET_SELECTED_ALL, payload: { datasetID: datsetID, - item: item + item: item, + isLigand: isLigand, + isProtein: isProtein, + isComplex: isComplex } }); -export const setDeselectedAll = (datsetID, item) => ({ +export const setDeselectedAll = (datsetID, item, isLigand, isProtein, isComplex) => ({ type: constants.SET_DESELECTED_ALL, payload: { datasetID: datsetID, - item: item + item: item, + isLigand: isLigand, + isProtein: isProtein, + isComplex: isComplex + } +}); + +export const setSelectedAllByType = (type, datsetID, items, isCrossReference) => ({ + type: constants.SET_SELECTED_ALL_BY_TYPE, + payload: { + type: type, + datasetID: datsetID, + items: items, + isCrossReference: isCrossReference + } +}); + +export const setDeselectedAllByType = (type, datsetID, items, isCrossReference) => ({ + type: constants.SET_DESELECTED_ALL_BY_TYPE, + payload: { + type: type, + datasetID: datsetID, + items: items, + isCrossReference: isCrossReference } }); diff --git a/js/components/datasets/redux/constants.js b/js/components/datasets/redux/constants.js index 8653a8364..9d47c6ad3 100644 --- a/js/components/datasets/redux/constants.js +++ b/js/components/datasets/redux/constants.js @@ -62,7 +62,10 @@ export const constants = { RESET_DATASETS_STATE: prefix + 'RESET_DATASETS_STATE', SET_SELECTED_ALL: prefix + 'SET_SELECTED_ALL', - SET_DESELECTED_ALL: prefix + 'SET_DESELECTED_ALL' + SET_DESELECTED_ALL: prefix + 'SET_DESELECTED_ALL', + + SET_SELECTED_ALL_BY_TYPE: prefix + 'SET_SELECTED_ALL_BY_TYPE', + SET_DESELECTED_ALL_BY_TYPE: prefix + 'SET_DESELECTED_ALL_BY_TYPE' }; export const COUNT_OF_VISIBLE_SCORES = 7; diff --git a/js/components/datasets/redux/dispatchActions.js b/js/components/datasets/redux/dispatchActions.js index 4072d9a2b..9c72c45a8 100644 --- a/js/components/datasets/redux/dispatchActions.js +++ b/js/components/datasets/redux/dispatchActions.js @@ -41,6 +41,7 @@ import { getInitialDatasetFilterProperties, getInitialDatasetFilterSettings } fr import { COUNT_OF_VISIBLE_SCORES } from './constants'; import { colourList } from '../../preview/molecule/moleculeView'; import { appendMoleculeOrientation } from '../../../reducers/ngl/actions'; +import { setSelectedAllByType, setDeselectedAllByType } from './actions'; export const initializeDatasetFilter = datasetID => (dispatch, getState) => { const initFilterSettings = getInitialDatasetFilterSettings(getState(), datasetID); @@ -381,107 +382,163 @@ export const loadScoresOfCrossReferenceCompounds = (datasetIDList = []) => (disp // ); }; -const addAllLigandsFromList = (moleculeList = [], stage) => dispatch => { +const addAllLigandsFromList = (moleculeList = [], stage, skipTracking = false) => dispatch => { moleculeList.forEach(molecule => { dispatch( addDatasetLigand( stage, molecule.molecule, colourList[molecule.molecule.id % colourList.length], - molecule.datasetID + molecule.datasetID, + skipTracking ) ); }); }; -const removeAllLigandsFromList = (moleculeList = [], stage) => dispatch => { +const removeAllLigandsFromList = (moleculeList = [], stage, skipTracking = false) => dispatch => { moleculeList.forEach(molecule => { dispatch( addDatasetLigand( stage, molecule.molecule, colourList[molecule.molecule.id % colourList.length], - molecule.datasetID + molecule.datasetID, + skipTracking ) ); }); }; export const handleAllLigandsOfCrossReferenceDialog = (areAllSelected, moleculeList = [], stage) => dispatch => { + let type = 'ligand'; if (areAllSelected) { - dispatch(removeAllLigandsFromList(moleculeList, stage)); + let molecules = dispatch(getSelectedMoleculesByType(type, false, moleculeList)); + dispatch(setDeselectedAllByType(type, null, molecules, true)); + dispatch(removeAllLigandsFromList(moleculeList, stage, true)); } else { - dispatch(addAllLigandsFromList(moleculeList, stage)); + let molecules = dispatch(getSelectedMoleculesByType(type, true, moleculeList)); + dispatch(setSelectedAllByType(type, null, molecules, true)); + dispatch(addAllLigandsFromList(moleculeList, stage, true)); } }; -const addAllHitProteins = (moleculeList = [], stage) => dispatch => { +const addAllHitProteins = (moleculeList = [], stage, skipTracking = false) => dispatch => { moleculeList.forEach(molecule => { dispatch( addDatasetHitProtein( stage, molecule.molecule, colourList[molecule.molecule.id % colourList.length], - molecule.datasetID + molecule.datasetID, + skipTracking ) ); }); }; -const removeAllHitProteins = (moleculeList = [], stage) => dispatch => { +const removeAllHitProteins = (moleculeList = [], stage, skipTracking = false) => dispatch => { moleculeList.forEach(molecule => { dispatch( removeDatasetHitProtein( stage, molecule.molecule, colourList[molecule.molecule.id % colourList.length], - molecule.datasetID + molecule.datasetID, + skipTracking ) ); }); }; export const removeOrAddAllHitProteinsOfList = (areAllSelected, moleculeList = [], stage) => dispatch => { + let type = 'protein'; + if (areAllSelected) { - dispatch(removeAllHitProteins(moleculeList, stage)); + let molecules = dispatch(getSelectedMoleculesByType(type, false, moleculeList)); + dispatch(setDeselectedAllByType(type, molecules)); + dispatch(removeAllHitProteins(moleculeList, stage, true)); } else { - dispatch(addAllHitProteins(moleculeList, stage)); + let molecules = dispatch(getSelectedMoleculesByType(type, true, moleculeList)); + dispatch(setSelectedAllByType(type, molecules)); + dispatch(addAllHitProteins(moleculeList, stage, true)); } }; -const addAllComplexes = (moleculeList = [], stage) => dispatch => { +const addAllComplexes = (moleculeList = [], stage, skipTracking = false) => dispatch => { moleculeList.forEach(molecule => { dispatch( addDatasetComplex( stage, molecule.molecule, colourList[molecule.molecule.id % colourList.length], - molecule.datasetID + molecule.datasetID, + skipTracking ) ); }); }; -const removeAllComplexes = (moleculeList = [], stage) => dispatch => { +const removeAllComplexes = (moleculeList = [], stage, skipTracking = false) => dispatch => { moleculeList.forEach(molecule => { dispatch( removeDatasetComplex( stage, molecule.molecule, colourList[molecule.molecule.id % colourList.length], - molecule.datasetID + molecule.datasetID, + skipTracking ) ); }); }; export const removeOrAddAllComplexesOfList = (areAllSelected, moleculeList = [], stage) => dispatch => { + let type = 'complex'; + if (areAllSelected) { - dispatch(removeAllComplexes(moleculeList, stage)); + let molecules = dispatch(getSelectedMoleculesByType(type, false, moleculeList)); + dispatch(setDeselectedAllByType(type, molecules)); + dispatch(removeAllComplexes(moleculeList, stage, true)); } else { - dispatch(addAllComplexes(moleculeList, stage)); + let molecules = dispatch(getSelectedMoleculesByType(type, true, moleculeList)); + dispatch(setSelectedAllByType(type, molecules)); + dispatch(addAllComplexes(moleculeList, stage, true)); } }; +const getSelectedMoleculesByType = (type, isAdd, moleculeList, datasetID) => (dispatch, getState) => { + const state = getState(); + + const ligandList = state.datasetsReducers.ligandLists; + const proteinList = state.datasetsReducers.proteinLists; + const complexList = state.datasetsReducers.complexLists; + + switch (type) { + case 'ligand': + return isAdd ? getMoleculesToSelect(moleculeList, ligandList) : getMoleculesToDeselect(moleculeList, ligandList); + case 'protein': + return isAdd + ? getMoleculesToSelect(moleculeList, proteinList) + : getMoleculesToDeselect(moleculeList, proteinList); + case 'complex': + return isAdd + ? getMoleculesToSelect(moleculeList, complexList) + : getMoleculesToDeselect(moleculeList, complexList); + default: + return null; + } +}; + +const getMoleculesToSelect = (moleculeList, list) => { + let molecules = moleculeList.filter(m => !list[m.datasetID].includes(m.molecule.id)); + return molecules; +}; + +const getMoleculesToDeselect = (moleculeList, list) => { + let molecules = moleculeList.filter(m => list[m.datasetID].includes(m.molecule.id)); + return molecules; +}; + export const autoHideDatasetDialogsOnScroll = ({ inspirationDialogRef, crossReferenceDialogRef, scrollBarRef }) => ( dispatch, getState diff --git a/js/components/datasets/redux/reducer.js b/js/components/datasets/redux/reducer.js index c69b1a892..1f4544304 100644 --- a/js/components/datasets/redux/reducer.js +++ b/js/components/datasets/redux/reducer.js @@ -24,6 +24,9 @@ export const INITIAL_STATE = { molecule_all_selection: null, molecule_all_deselection: null, + molecule_all_type_selection: {}, + molecule_all_type_deselection: {}, + // search searchString: null, @@ -385,6 +388,16 @@ export const datasetsReducers = (state = INITIAL_STATE, action = {}) => { return Object.assign({}, state, { molecule_all_deselection: action.payload }); + + case constants.SET_SELECTED_ALL_BY_TYPE: + return Object.assign({}, state, { + molecule_all_type_selection: action.payload + }); + + case constants.SET_DESELECTED_ALL_BY_TYPE: + return Object.assign({}, state, { + molecule_all_type_deselection: action.payload + }); default: return state; } diff --git a/js/components/preview/molecule/moleculeList.js b/js/components/preview/molecule/moleculeList.js index 7fc860be7..a72b1e46e 100644 --- a/js/components/preview/molecule/moleculeList.js +++ b/js/components/preview/molecule/moleculeList.js @@ -61,6 +61,7 @@ import { setSortDialogOpen } from './redux/actions'; import { setMoleculeList, setAllMolLists } from '../../../reducers/api/actions'; import { AlertModal } from '../../common/Modal/AlertModal'; import { onSelectMoleculeGroup } from '../moleculeGroups/redux/dispatchActions'; +import { setSelectedAllByType, setDeselectedAllByType } from '../../../reducers/selection/actions'; const useStyles = makeStyles(theme => ({ container: { @@ -446,11 +447,18 @@ export const MoleculeList = memo(({ height, setFilterItemsHeight, filterItemsHei handleFilterChange(newFilter);*/ }; - const joinedGivenMatch = useCallback((givenList) => { - return givenList.filter(element => joinedMoleculeLists.filter(element2 => element2.id === element).length > 0).length; - }, [joinedMoleculeLists]); + const joinedGivenMatch = useCallback( + givenList => { + return givenList.filter(element => joinedMoleculeLists.filter(element2 => element2.id === element).length > 0) + .length; + }, + [joinedMoleculeLists] + ); - const joinedLigandMatchLength = useMemo(() => joinedGivenMatch(fragmentDisplayList), [fragmentDisplayList, joinedGivenMatch]); + const joinedLigandMatchLength = useMemo(() => joinedGivenMatch(fragmentDisplayList), [ + fragmentDisplayList, + joinedGivenMatch + ]); const joinedProteinMatchLength = useMemo(() => joinedGivenMatch(proteinList), [proteinList, joinedGivenMatch]); const joinedComplexMatchLength = useMemo(() => joinedGivenMatch(complexList), [complexList, joinedGivenMatch]); @@ -489,10 +497,17 @@ export const MoleculeList = memo(({ height, setFilterItemsHeight, filterItemsHei // TODO so this could lead to inconsistend behaviour while scrolling // TODO maybe change "currentMolecules.forEach" to "{type}List.forEach" - const removeSelectedType = type => { - joinedMoleculeLists.forEach(molecule => { - dispatch(removeType[type](majorViewStage, molecule, colourList[molecule.id % colourList.length])); - }); + const removeSelectedType = (type, skipTracking = false) => { + if (type === 'ligand') { + joinedMoleculeLists.forEach(molecule => { + dispatch(removeType[type](majorViewStage, molecule, skipTracking)); + }); + } else { + joinedMoleculeLists.forEach(molecule => { + dispatch(removeType[type](majorViewStage, molecule, colourList[molecule.id % colourList.length], skipTracking)); + }); + } + selectedAll.current = false; }; @@ -523,16 +538,25 @@ export const MoleculeList = memo(({ height, setFilterItemsHeight, filterItemsHei }); }; - const selectMoleculeSite = (moleculeGroupSite) => { + const selectMoleculeSite = moleculeGroupSite => { const moleculeGroup = mol_group_list[moleculeGroupSite - 1]; dispatch(onSelectMoleculeGroup({ moleculeGroup, stageSummaryView, majorViewStage, selectGroup: true })); - } + }; - const addNewType = type => { - joinedMoleculeLists.forEach(molecule => { - selectMoleculeSite(molecule.site); - dispatch(addType[type](majorViewStage, molecule, colourList[molecule.id % colourList.length])); - }); + const addNewType = (type, skipTracking = false) => { + if (type === 'ligand') { + joinedMoleculeLists.forEach(molecule => { + selectMoleculeSite(molecule.site); + dispatch( + addType[type](majorViewStage, molecule, colourList[molecule.id % colourList.length], false, skipTracking) + ); + }); + } else { + joinedMoleculeLists.forEach(molecule => { + selectMoleculeSite(molecule.site); + dispatch(addType[type](majorViewStage, molecule, colourList[molecule.id % colourList.length], skipTracking)); + }); + } }; const ucfirst = string => { @@ -543,19 +567,46 @@ export const MoleculeList = memo(({ height, setFilterItemsHeight, filterItemsHei if (calledFromSelectAll === true && selectedAll.current === true) { // REDO if (eval('is' + ucfirst(type) + 'On') === false) { - addNewType(type); + addNewType(type, true); } } else if (calledFromSelectAll && selectedAll.current === false) { - removeSelectedType(type); + removeSelectedType(type, true); } else if (!calledFromSelectAll) { if (eval('is' + ucfirst(type) + 'On') === false) { - addNewType(type); + let molecules = getSelectedMoleculesByType(type, true); + dispatch(setSelectedAllByType(type, molecules)); + addNewType(type, true); } else { - removeSelectedType(type); + let molecules = getSelectedMoleculesByType(type, false); + dispatch(setDeselectedAllByType(type, molecules)); + removeSelectedType(type, true); } } }; + const getSelectedMoleculesByType = (type, isAdd) => { + switch (type) { + case 'ligand': + return isAdd ? getMoleculesToSelect(fragmentDisplayList) : getMoleculesToDeselect(fragmentDisplayList); + case 'protein': + return isAdd ? getMoleculesToSelect(proteinList) : getMoleculesToDeselect(proteinList); + case 'complex': + return isAdd ? getMoleculesToSelect(complexList) : getMoleculesToDeselect(complexList); + default: + return null; + } + }; + + const getMoleculesToSelect = list => { + let molecules = joinedMoleculeLists.filter(m => !list.includes(m.id)); + return molecules; + }; + + const getMoleculesToDeselect = list => { + let molecules = joinedMoleculeLists.filter(m => list.includes(m.id)); + return molecules; + }; + let debouncedFn; const handleSearch = event => { @@ -734,7 +785,9 @@ export const MoleculeList = memo(({ height, setFilterItemsHeight, filterItemsHei [classes.contColButtonSelected]: isLigandOn === true, [classes.contColButtonHalfSelected]: isLigandOn === null })} - onClick={() => onButtonToggle('ligand')} + onClick={() => { + onButtonToggle('ligand'); + }} disabled={disableUserInteraction} > L @@ -749,7 +802,9 @@ export const MoleculeList = memo(({ height, setFilterItemsHeight, filterItemsHei [classes.contColButtonSelected]: isProteinOn, [classes.contColButtonHalfSelected]: isProteinOn === null })} - onClick={() => onButtonToggle('protein')} + onClick={() => { + onButtonToggle('protein'); + }} disabled={disableUserInteraction} > P @@ -765,7 +820,9 @@ export const MoleculeList = memo(({ height, setFilterItemsHeight, filterItemsHei [classes.contColButtonSelected]: isComplexOn, [classes.contColButtonHalfSelected]: isComplexOn === null })} - onClick={() => onButtonToggle('complex')} + onClick={() => { + onButtonToggle('complex'); + }} disabled={disableUserInteraction} > C diff --git a/js/components/preview/molecule/moleculeView.js b/js/components/preview/molecule/moleculeView.js index 6a98693ee..efaa161b2 100644 --- a/js/components/preview/molecule/moleculeView.js +++ b/js/components/preview/molecule/moleculeView.js @@ -491,9 +491,9 @@ const MoleculeView = memo( const setCalledFromAll = () => { let isSelected = selectedAll.current === true; if (isSelected) { - dispatch(setSelectedAll(data)); + dispatch(setSelectedAll(data, true, true, true)); } else { - dispatch(setDeselectedAll(data)); + dispatch(setDeselectedAll(data, isLigandOn, isProteinOn, isComplexOn)); } }; diff --git a/js/reducers/selection/actions.js b/js/reducers/selection/actions.js index d612fed13..54f92371e 100644 --- a/js/reducers/selection/actions.js +++ b/js/reducers/selection/actions.js @@ -228,12 +228,28 @@ export const updateBondColorMapOfCompounds = (key, value) => ({ payload: { key, value } }); -export const setSelectedAll = item => ({ +export const setSelectedAll = (item, isLigand, isProtein, isComplex) => ({ type: constants.SET_SELECTED_ALL, - item: item + item: item, + isLigand: isLigand, + isProtein: isProtein, + isComplex: isComplex }); -export const setDeselectedAll = item => ({ +export const setDeselectedAll = (item, isLigand, isProtein, isComplex) => ({ type: constants.SET_DESELECTED_ALL, - item: item + item: item, + isLigand: isLigand, + isProtein: isProtein, + isComplex: isComplex +}); + +export const setSelectedAllByType = (type, items, isInspiration) => ({ + type: constants.SET_SELECTED_ALL_BY_TYPE, + payload: { type, items, isInspiration } +}); + +export const setDeselectedAllByType = (type, items, isInspiration) => ({ + type: constants.SET_DESELECTED_ALL_BY_TYPE, + payload: { type, items, isInspiration } }); diff --git a/js/reducers/selection/constants.js b/js/reducers/selection/constants.js index c4711c111..6d64dce57 100644 --- a/js/reducers/selection/constants.js +++ b/js/reducers/selection/constants.js @@ -34,6 +34,8 @@ export const constants = { SET_FILTER: prefix + 'SET_FILTER', SET_SELECTED_ALL: prefix + 'SET_SELECTED_ALL', SET_DESELECTED_ALL: prefix + 'SET_DESELECTED_ALL', + SET_SELECTED_ALL_BY_TYPE: prefix + 'SET_SELECTED_ALL_BY_TYPE', + SET_DESELECTED_ALL_BY_TYPE: prefix + 'SET_DESELECTED_ALL_BY_TYPE', RESET_COMPOUNDS_OF_VECTORS: prefix + 'RESET_COMPOUNDS_OF_VECTORS', UPDATE_VECTOR_COMPOUNDS: prefix + 'UPDATE_VECTOR_COMPOUNDS', diff --git a/js/reducers/selection/selectionReducers.js b/js/reducers/selection/selectionReducers.js index e8ee6b074..90805180d 100644 --- a/js/reducers/selection/selectionReducers.js +++ b/js/reducers/selection/selectionReducers.js @@ -18,6 +18,8 @@ export const INITIAL_STATE = { filter: undefined, molecule_all_selection: null, molecule_all_deselection: null, + molecule_all_type_selection: [], + molecule_all_type_deselection: [], compoundsOfVectors: null, // list of all vector's compounds to pick // compoundsOfVectors: { @@ -287,6 +289,16 @@ export function selectionReducers(state = INITIAL_STATE, action = {}) { return Object.assign({}, state, { molecule_all_deselection: action.item }); + + case constants.SET_SELECTED_ALL_BY_TYPE: + return Object.assign({}, state, { + molecule_all_type_selection: action.payload.items + }); + + case constants.SET_DESELECTED_ALL_BY_TYPE: + return Object.assign({}, state, { + molecule_all_type_deselection: action.payload.items + }); // Cases like: @@redux/INIT default: return state; diff --git a/js/reducers/tracking/constants.js b/js/reducers/tracking/constants.js index 321b1f98c..7352a1c7b 100644 --- a/js/reducers/tracking/constants.js +++ b/js/reducers/tracking/constants.js @@ -40,7 +40,9 @@ export const actionType = { UNDO: 'UNDO', REDO: 'REDO', ALL_TURNED_ON: 'ALL_TURNED_ON', - ALL_TURNED_OFF: 'ALL_TURNED_OFF' + ALL_TURNED_OFF: 'ALL_TURNED_OFF', + ALL_TURNED_ON_BY_TYPE: 'ALL_TURNED_ON_BY_TYPE', + ALL_TURNED_OFF_BY_TYPE: 'ALL_TURNED_OFF_BY_TYPE' }; export const actionDescription = { diff --git a/js/reducers/tracking/dispatchActions.js b/js/reducers/tracking/dispatchActions.js index 5577e41c7..7ae391bcb 100644 --- a/js/reducers/tracking/dispatchActions.js +++ b/js/reducers/tracking/dispatchActions.js @@ -557,6 +557,12 @@ const handleUndoAction = (action, stages) => (dispatch, getState) => { case actionType.ALL_TURNED_OFF: dispatch(handleAllAction(action, true, majorViewStage, state)); break; + case actionType.ALL_TURNED_ON_BY_TYPE: + dispatch(handleAllActionByType(action, false, majorViewStage)); + break; + case actionType.ALL_TURNED_OFF_BY_TYPE: + dispatch(handleAllActionByType(action, true, majorViewStage)); + break; case actionType.LIGAND_TURNED_ON: dispatch(handleMoleculeAction(action, 'ligand', false, majorViewStage, state)); break; @@ -646,6 +652,12 @@ const handleRedoAction = (action, stages) => (dispatch, getState) => { case actionType.ALL_TURNED_OFF: dispatch(handleAllAction(action, false, majorViewStage, state)); break; + case actionType.ALL_TURNED_ON_BY_TYPE: + dispatch(handleAllActionByType(action, true, majorViewStage)); + break; + case actionType.ALL_TURNED_OFF_BY_TYPE: + dispatch(handleAllActionByType(action, false, majorViewStage)); + break; case actionType.LIGAND_TURNED_ON: dispatch(handleMoleculeAction(action, 'ligand', true, majorViewStage, state)); break; @@ -718,10 +730,63 @@ const handleRedoAction = (action, stages) => (dispatch, getState) => { } }; +const handleAllActionByType = (action, isAdd, stage) => (dispatch, getState) => { + let actionItems = action.items; + let type = action.control_type; + if (action.object_type === actionObjectType.MOLECULE || action.object_type === actionObjectType.INSPIRATION) { + if (isAdd) { + actionItems.forEach(data => { + if (data) { + if (type === 'ligand') { + dispatch(addType[type](stage, data, colourList[data.id % colourList.length], true)); + } else { + dispatch(addType[type](stage, data, colourList[data.id % colourList.length])); + } + } + }); + } else { + actionItems.forEach(data => { + if (data) { + dispatch(removeType[type](stage, data, colourList[data.id % colourList.length])); + } + }); + } + } else if ( + action.object_type === actionObjectType.COMPOUND || + action.object_type === actionObjectType.CROSS_REFERENCE + ) { + if (isAdd) { + actionItems.forEach(data => { + if (data && data.molecule) { + dispatch( + addTypeCompound[type](stage, data.molecule, colourList[data.id % colourList.length], data.datasetID) + ); + } + }); + } else { + actionItems.forEach(data => { + if (data && data.molecule) { + dispatch( + removeTypeCompound[type](stage, data.molecule, colourList[data.id % colourList.length], data.datasetID) + ); + } + }); + } + } +}; + const handleAllAction = (action, isSelected, majorViewStage, state) => (dispatch, getState) => { - dispatch(handleMoleculeAction(action, 'ligand', isSelected, majorViewStage, state)); - dispatch(handleMoleculeAction(action, 'protein', isSelected, majorViewStage, state)); - dispatch(handleMoleculeAction(action, 'complex', isSelected, majorViewStage, state)); + if (action.isLigand) { + dispatch(handleMoleculeAction(action, 'ligand', isSelected, majorViewStage, state)); + } + + if (action.isProtein) { + dispatch(handleMoleculeAction(action, 'protein', isSelected, majorViewStage, state)); + } + + if (action.isComplex) { + dispatch(handleMoleculeAction(action, 'complex', isSelected, majorViewStage, state)); + } }; const handleTargetAction = (action, isSelected, stages) => (dispatch, getState) => { diff --git a/js/reducers/tracking/trackingActions.js b/js/reducers/tracking/trackingActions.js index 65d2159a4..391b6fdfc 100644 --- a/js/reducers/tracking/trackingActions.js +++ b/js/reducers/tracking/trackingActions.js @@ -63,7 +63,7 @@ export const findTruckAction = (action, state) => { text: `${actionDescription.SITE} ${molGroupName} ${actionDescription.TURNED_OFF}` }; } - } else if (action.type.includes(selectionConstants.SET_SELECTED_ALL)) { + } else if (action.type === selectionConstants.SET_SELECTED_ALL) { if (action.item) { let objectType = action.item.isInspiration === true ? actionObjectType.INSPIRATION : actionObjectType.MOLECULE; let objectName = action.item.name || getMoleculeName(action.item.id, state); @@ -76,13 +76,16 @@ export const findTruckAction = (action, state) => { object_type: objectType, object_name: objectName, object_id: action.item.id, + isLigand: action.isLigand, + isProtein: action.isProtein, + isComplex: action.isComplex, text: `${actionDescription.ALL} ${actionDescription.TURNED_ON} ${objectType} ${getMoleculeTitle( objectName, target_on_name )}` }; } - } else if (action.type.includes(selectionConstants.SET_DESELECTED_ALL)) { + } else if (action.type === selectionConstants.SET_DESELECTED_ALL) { if (action.item) { let objectType = action.item.isInspiration === true ? actionObjectType.INSPIRATION : actionObjectType.MOLECULE; let objectName = action.item.name || getMoleculeName(action.item.id, state); @@ -95,12 +98,47 @@ export const findTruckAction = (action, state) => { object_type: objectType, object_name: objectName, object_id: action.item.id, + isLigand: action.isLigand, + isProtein: action.isProtein, + isComplex: action.isComplex, text: `${actionDescription.ALL} ${actionDescription.TURNED_OFF} ${objectType} ${getMoleculeTitle( objectName, target_on_name )}` }; } + } else if (action.type === selectionConstants.SET_SELECTED_ALL_BY_TYPE) { + if (action.payload) { + let payload = action.payload; + let objectType = payload.isInspiration === true ? actionObjectType.INSPIRATION : actionObjectType.MOLECULE; + + truckAction = { + type: actionType.ALL_TURNED_ON_BY_TYPE, + timestamp: Date.now(), + username: username, + project: project, + object_type: objectType, + control_type: payload.type, + items: payload.items, + text: `${actionDescription.ALL} ${payload.type} ${actionDescription.TURNED_ON} ${objectType}` + }; + } + } else if (action.type === selectionConstants.SET_DESELECTED_ALL_BY_TYPE) { + if (action.payload) { + let payload = action.payload; + let objectType = payload.isInspiration === true ? actionObjectType.INSPIRATION : actionObjectType.MOLECULE; + + truckAction = { + type: actionType.ALL_TURNED_OFF_BY_TYPE, + timestamp: Date.now(), + username: username, + project: project, + object_type: objectType, + control_type: payload.type, + items: payload.items, + text: `${actionDescription.ALL} ${payload.type} ${actionDescription.TURNED_OFF} ${objectType}` + }; + } } else if (action.type.includes(selectionConstants.APPEND_FRAGMENT_DISPLAY_LIST)) { if (action.item) { let objectType = action.item.isInspiration === true ? actionObjectType.INSPIRATION : actionObjectType.MOLECULE; @@ -375,7 +413,7 @@ export const findTruckAction = (action, state) => { text: `${objectType} ${objectName} ${actionDescription.DESELECTED} of dataset: ${action.payload.datasetID}` }; } - } else if (action.type.includes(customDatasetConstants.SET_SELECTED_ALL)) { + } else if (action.type === customDatasetConstants.SET_SELECTED_ALL) { if (action.payload && action.payload.item) { let objectType = action.payload.item.isCrossReference === true ? actionObjectType.CROSS_REFERENCE : actionObjectType.COMPOUND; @@ -390,10 +428,13 @@ export const findTruckAction = (action, state) => { object_name: objectName, object_id: action.payload.item.id, dataset_id: action.payload.datasetID, + isLigand: action.payload.isLigand, + isProtein: action.payload.isProtein, + isComplex: action.payload.isComplex, text: `${actionDescription.ALL} ${actionDescription.TURNED_ON} ${objectType} ${objectName} of dataset: ${action.payload.datasetID}` }; } - } else if (action.type.includes(customDatasetConstants.SET_DESELECTED_ALL)) { + } else if (action.type === customDatasetConstants.SET_DESELECTED_ALL) { if (action.payload && action.payload.item) { let objectType = action.payload.item.isCrossReference === true ? actionObjectType.CROSS_REFERENCE : actionObjectType.COMPOUND; @@ -408,7 +449,44 @@ export const findTruckAction = (action, state) => { object_name: objectName, object_id: action.payload.item.id, dataset_id: action.payload.datasetID, - text: `${actionDescription.ALL} ${actionDescription.ALL_TURNED_OFF} ${objectType} ${objectName} of dataset: ${action.payload.datasetID}` + isLigand: action.payload.isLigand, + isProtein: action.payload.isProtein, + isComplex: action.payload.isComplex, + text: `${actionDescription.ALL} ${actionDescription.TURNED_OFF} ${objectType} ${objectName} of dataset: ${action.payload.datasetID}` + }; + } + } else if (action.type === customDatasetConstants.SET_SELECTED_ALL_BY_TYPE) { + if (action.payload) { + let payload = action.payload; + let objectType = + payload.isCrossReference === true ? actionObjectType.CROSS_REFERENCE : actionObjectType.COMPOUND; + + truckAction = { + type: actionType.ALL_TURNED_ON_BY_TYPE, + timestamp: Date.now(), + username: username, + project: project, + object_type: objectType, + control_type: payload.type, + items: payload.items, + text: `${actionDescription.ALL} ${payload.type} ${actionDescription.ALL_TURNED_ON} ${objectType} of dataset: ${action.payload.datasetID}` + }; + } + } else if (action.type === customDatasetConstants.SET_DESELECTED_ALL_BY_TYPE) { + if (action.payload) { + let payload = action.payload; + let objectType = + payload.isCrossReference === true ? actionObjectType.CROSS_REFERENCE : actionObjectType.COMPOUND; + + truckAction = { + type: actionType.ALL_TURNED_OFF_BY_TYPE, + timestamp: Date.now(), + username: username, + project: project, + object_type: objectType, + control_type: payload.type, + items: payload.items, + text: `${actionDescription.ALL} ${payload.type} ${actionDescription.ALL_TURNED_OFF} ${objectType} of dataset: ${action.payload.datasetID}` }; } } else if (action.type.includes(customDatasetConstants.APPEND_LIGAND_LIST)) {