diff --git a/js/components/datasets/datasetFilter.js b/js/components/datasets/datasetFilter.js index 39bdc6e5a..745f80381 100644 --- a/js/components/datasets/datasetFilter.js +++ b/js/components/datasets/datasetFilter.js @@ -8,6 +8,7 @@ import { setFilterDialogOpen, setFilterProperties, setFilterSettings, + setDatasetFilter, setFilterWithInspirations } from './redux/actions'; import { @@ -96,12 +97,17 @@ export const DatasetFilter = memo( return scoreDatasetList[Object.keys(scoreDatasetList).find(attrName => attrName === attr)]; }; - const handleFilterChange = (newFilterProperties, newFilterSettings) => { + const handleFilterChange = (newFilterProperties, newFilterSettings, key, prio, oldPrio) => { Object.keys(scoreDatasetList).forEach(attrKey => { if (newFilterProperties[attrKey].priority === undefined || newFilterProperties[attrKey].priority === '') { newFilterProperties[attrKey].priority = 0; } + if (attrKey === key && prio !== undefined && prio !== null) { + newFilterProperties[attrKey].newPrio = prio; + newFilterProperties[attrKey].oldPrio = oldPrio; + } }); + dispatch(setDatasetFilter(datasetID, newFilterProperties, newFilterSettings, key)); dispatch(setFilterProperties(datasetID, newFilterProperties)); dispatch(setFilterSettings(datasetID, newFilterSettings)); }; @@ -109,7 +115,7 @@ export const DatasetFilter = memo( const handleItemChange = key => setting => { const newFilterSettings = createFilterSettingsObject({ active: true, predefined, priorityOrder }); const newFilterProperties = { ...filterProperties, [key]: setting }; - handleFilterChange(newFilterProperties, newFilterSettings); + handleFilterChange(newFilterProperties, newFilterSettings, key); }; const handlePrioChange = key => inc => () => { @@ -124,13 +130,16 @@ export const DatasetFilter = memo( newFilterSettings.priorityOrder = localPriorityOrder; newFilterSettings.active = true; - handleFilterChange(filterProperties, newFilterSettings); + let oldPrio = index; + let newPrio = index + inc; + let newFilterProperties = { ...filterProperties }; + handleFilterChange(newFilterProperties, newFilterSettings, key, newPrio, oldPrio); } }; const handleClear = () => { setPredefinedFilter('none'); - handleFilterChange(defaultFilterProperties, defaultFilterSettings); + handleFilterChange(defaultFilterProperties, defaultFilterSettings, 'clear'); }; // Check for multiple attributes with same sorting priority diff --git a/js/components/datasets/datasetMoleculeListSortFilterItem.js b/js/components/datasets/datasetMoleculeListSortFilterItem.js index 35aec4d50..102924385 100644 --- a/js/components/datasets/datasetMoleculeListSortFilterItem.js +++ b/js/components/datasets/datasetMoleculeListSortFilterItem.js @@ -1,4 +1,4 @@ -import React, { memo, useState } from 'react'; +import React, { memo, useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import Button from '@material-ui/core/Button'; import Slider from '@material-ui/core/Slider'; @@ -120,6 +120,10 @@ export const DatasetMoleculeListSortFilter = memo( isString }; + useEffect(() => { + setSliderValue([normMinValue, normMaxValue]); + }, [normMinValue, normMaxValue]); + const handleCheckboxChange = e => { const isChecked = e.target.checked; @@ -142,7 +146,7 @@ export const DatasetMoleculeListSortFilter = memo( }; const handleCommitChangeSlider = (event, newValue) => { - setting.minValue = isBoolean ? 1 : (isFloat ? newValue[0] / MULT : newValue[0]); + setting.minValue = isFloat ? newValue[0] / MULT : newValue[0]; setting.maxValue = isFloat ? newValue[1] / MULT : newValue[1]; if (newValue === 1) { setting.isChecked = false; @@ -259,7 +263,7 @@ export const DatasetMoleculeListSortFilter = memo( {isBoolean && ( <> - {"False"} + {'False'} { - if (value === 0) { - return ""; - } else if (value === 100) { - return ""; - } else { - return "Ignore"; - } + marks={[ + { value: 1, label: '' }, + { value: 50, label: 'Ignore' }, + { value: 100, label: '' } + ]} + getAriaValueText={value => { + if (value === 0) { + return ''; + } else if (value === 100) { + return ''; + } else { + return 'Ignore'; } - } - getAriaLabel={ - index => { - if (index === 0) { - return "False"; - } else if (index === 1) { - return "Ignore"; - } else { - return "True"; - } + }} + getAriaLabel={index => { + if (index === 0) { + return 'False'; + } else if (index === 1) { + return 'Ignore'; + } else { + return 'True'; } - } - valueLabelFormat={ - value => { - if (value === 1) { - return "False"; - } else if (value === 50) { - return "Ignore"; - } else { - return "True"; - } + }} + valueLabelFormat={value => { + if (value === 1) { + return 'False'; + } else if (value === 50) { + return 'Ignore'; + } else { + return 'True'; } - } + }} /> - {"True"} + {'True'} )} diff --git a/js/components/datasets/datasetSelectorMenuButton.js b/js/components/datasets/datasetSelectorMenuButton.js index c969f0398..7bf3d2216 100644 --- a/js/components/datasets/datasetSelectorMenuButton.js +++ b/js/components/datasets/datasetSelectorMenuButton.js @@ -6,6 +6,7 @@ import Popper from '@material-ui/core/Popper'; import MenuItem from '@material-ui/core/MenuItem'; import MenuList from '@material-ui/core/MenuList'; import { makeStyles } from '@material-ui/core'; +import { useDispatch } from 'react-redux'; const useStyles = makeStyles(theme => ({ dropDown: { @@ -21,9 +22,12 @@ export const DatasetSelectorMenuButton = ({ setSelectedDatasetIndex }) => { const classes = useStyles(); + const dispatch = useDispatch(); const handleMenuItemClick = (event, index) => { - setSelectedDatasetIndex(index); + let oldDataset = customDatasets[selectedDatasetIndex]?.title; + let newDataset = customDatasets[index]?.title; + dispatch(setSelectedDatasetIndex(selectedDatasetIndex, index, newDataset, oldDataset)); setOpen(false); event.stopPropagation(); }; diff --git a/js/components/datasets/redux/actions.js b/js/components/datasets/redux/actions.js index 378e1f4df..c7f3d92c5 100644 --- a/js/components/datasets/redux/actions.js +++ b/js/components/datasets/redux/actions.js @@ -26,6 +26,17 @@ export const setMoleculeListIsLoading = isLoading => ({ payload: isLoading }); +export const setSelectedDatasetIndex = (oldValue, tabValue, tabName, oldName, skipTracking = false) => ({ + type: constants.SET_SELECTED_DATASET_INDEX, + payload: { oldValue: oldValue, value: tabValue, name: tabName, oldName: oldName }, + skipTracking: skipTracking +}); + +export const setTabValue = (oldValue, tabValue, tabName, oldName) => ({ + type: constants.SET_TAB_VALUE, + payload: { oldValue: oldValue, value: tabValue, name: tabName, oldName: oldName } +}); + export const replaceAllMoleculeLists = allMoleculeLists => ({ type: constants.REPLACE_ALL_MOLECULELISTS, payload: allMoleculeLists @@ -41,6 +52,11 @@ export const setFilterProperties = (datasetID, properties) => ({ payload: { datasetID, properties } }); +export const setDatasetFilter = (datasetID, properties, settings, key) => ({ + type: constants.SET_DATASET_FILTER, + payload: { datasetID, properties, settings, key } +}); + export const setFilterDialogOpen = filterDialogOpen => ({ type: constants.SET_FILTER_DIALOG_OPEN, payload: filterDialogOpen @@ -234,6 +250,11 @@ export const updateFilterShowedScoreProperties = ({ datasetID, scoreList = [] }) payload: { datasetID, scoreList } }); +export const setFilterShowedScoreProperties = ({ datasetID, scoreList = [], oldScoreList, isChecked, scoreName }) => ({ + type: constants.SET_FILTER_SHOWED_SCORE_PROPERTIES, + payload: { datasetID, scoreList, isChecked, scoreName, oldScoreList } +}); + export const removeFromFilterShowedScoreProperties = datasetID => ({ type: constants.REMOVE_FROM_FILTER_SHOWED_SCORE_PROPERTIES, payload: datasetID diff --git a/js/components/datasets/redux/constants.js b/js/components/datasets/redux/constants.js index a8fcd4cf9..5d901deb1 100644 --- a/js/components/datasets/redux/constants.js +++ b/js/components/datasets/redux/constants.js @@ -7,11 +7,14 @@ export const constants = { ADD_MOLECULELIST: prefix + 'ADD_MOLECULELIST', REMOVE_MOLECULELIST: prefix + 'REMOVE_MOLECULELIST', SET_IS_LOADING_MOLECULE_LIST: prefix + 'SET_IS_LOADING_MOLECULE_LIST', + SET_SELECTED_DATASET_INDEX: prefix + 'SET_SELECTED_DATASET_INDEX', + SET_TAB_VALUE: prefix + 'SET_TAB_VALUE', SET_FILTER_SETTINGS: prefix + 'SET_FILTER_SETTINGS', SET_FILTER_PROPERTIES: prefix + 'SET_FILTER_PROPERTIES', SET_FILTER_DIALOG_OPEN: prefix + 'SET_FILTER_DIALOG_OPEN', SET_FILTER_WITH_INSPIRATIONS: prefix + 'SET_FILTER_WITH_INSPIRATIONS', + SET_DATASET_FILTER: prefix + 'SET_DATASET_FILTER', SET_LIGAND_LIST: prefix + 'SET_LIGAND_LIST', APPEND_LIGAND_LIST: prefix + 'APPEND_LIGAND_LIST', @@ -39,6 +42,7 @@ export const constants = { APPEND_TO_SCORE_COMPOUND_MAP_BY_SCORE_CATEGORY: prefix + 'APPEND_TO_SCORE_COMPOUND_MAP_BY_SCORE_CATEGORY', CLEAR_SCORE_COMPOUND_MAP: prefix + 'CLEAR_SCORE_COMPOUND_MAP', + SET_FILTER_SHOWED_SCORE_PROPERTIES: prefix + 'SET_FILTER_SHOWED_SCORE_PROPERTIES', UPDATE_FILTER_SHOWED_SCORE_PROPERTIES: prefix + 'UPDATE_FILTER_SHOWED_SCORE_PROPERTIES', REMOVE_FROM_FILTER_SHOWED_SCORE_PROPERTIES: prefix + 'REMOVE_FROM_FILTER_SHOWED_SCORE_PROPERTIES', diff --git a/js/components/datasets/redux/dispatchActions.js b/js/components/datasets/redux/dispatchActions.js index 633efeaa7..16b76dea8 100644 --- a/js/components/datasets/redux/dispatchActions.js +++ b/js/components/datasets/redux/dispatchActions.js @@ -13,6 +13,7 @@ import { appendToScoreDatasetMap, appendToScoreCompoundMapByScoreCategory, updateFilterShowedScoreProperties, + setFilterShowedScoreProperties, setFilterProperties, setIsLoadingInspirationListOfMolecules, appendToInspirationMoleculeDataList, @@ -339,6 +340,8 @@ export const selectScoreProperty = ({ isChecked, datasetID, scoreName }) => (dis const state = getState(); const filteredScorePropertiesOfDataset = state.datasetsReducers.filteredScoreProperties[datasetID]; const scoreDatasetMap = state.datasetsReducers.scoreDatasetMap[datasetID]; + let scoreList = []; + let oldScoreList = [...filteredScorePropertiesOfDataset]; if (isChecked === true) { if (filteredScorePropertiesOfDataset.length === COUNT_OF_VISIBLE_SCORES) { @@ -348,6 +351,7 @@ export const selectScoreProperty = ({ isChecked, datasetID, scoreName }) => (dis // 2. select new property const selectedProperty = scoreDatasetMap[scoreName]; filteredScorePropertiesOfDataset.push(selectedProperty); + scoreList = filteredScorePropertiesOfDataset; dispatch( updateFilterShowedScoreProperties({ datasetID, @@ -355,6 +359,7 @@ export const selectScoreProperty = ({ isChecked, datasetID, scoreName }) => (dis }) ); } else { + scoreList = filteredScorePropertiesOfDataset.filter(item => item.name !== scoreName); dispatch( updateFilterShowedScoreProperties({ datasetID, @@ -362,6 +367,8 @@ export const selectScoreProperty = ({ isChecked, datasetID, scoreName }) => (dis }) ); } + + dispatch(setFilterShowedScoreProperties({ datasetID, scoreList, oldScoreList, isChecked, scoreName })); }; export const loadInspirationMoleculesDataList = (inspirationList = []) => (dispatch, getState) => { diff --git a/js/components/datasets/redux/reducer.js b/js/components/datasets/redux/reducer.js index 379e4298d..91f82738f 100644 --- a/js/components/datasets/redux/reducer.js +++ b/js/components/datasets/redux/reducer.js @@ -7,6 +7,9 @@ export const INITIAL_STATE = { scoreDatasetMap: {}, // map of $datasetID and its $scoreList scoreCompoundMap: {}, // map of $compoundID and its $scoreList + selectedDatasetIndex: 0, + tabValue: 0, + // filter filterDatasetMap: {}, // map of $datasetID and its $filterSettings filterPropertiesDatasetMap: {}, // map of $datasetID and its $filterProperties @@ -138,7 +141,7 @@ export const datasetsReducers = (state = INITIAL_STATE, action = {}) => { return Object.assign({}, state, { datasets: action.payload }); case constants.REPLACE_ALL_MOLECULELISTS: - return {...state, moleculeLists: action.payload}; + return { ...state, moleculeLists: action.payload }; case constants.ADD_MOLECULELIST: // initialize also control containers @@ -161,6 +164,12 @@ export const datasetsReducers = (state = INITIAL_STATE, action = {}) => { case constants.SET_IS_LOADING_MOLECULE_LIST: return Object.assign({}, state, { isLoadingMoleculeList: action.payload }); + case constants.SET_SELECTED_DATASET_INDEX: + return Object.assign({}, state, { selectedDatasetIndex: action.payload.value }); + + case constants.SET_TAB_VALUE: + return Object.assign({}, state, { tabValue: action.payload.value }); + case constants.SET_FILTER_SETTINGS: const { datasetID, filter } = action.payload; return { ...state, filterDatasetMap: { ...state.filterDatasetMap, [datasetID]: filter } }; @@ -347,7 +356,7 @@ export const datasetsReducers = (state = INITIAL_STATE, action = {}) => { return Object.assign({}, state, { inspirationFragmentList: [...diminishedInspirationFragmentList] }); case constants.SET_ALL_INSPIRATIONS: - return {...state, allInspirations: action.payload}; + return { ...state, allInspirations: action.payload }; case constants.APPEND_MOLECULE_TO_COMPOUNDS_TO_BUY_OF_DATASET: const setOfMolecules = new Set(state.compoundsToBuyDatasetMap[action.payload.datasetID]); diff --git a/js/components/preview/Preview.js b/js/components/preview/Preview.js index b85a4e7a2..a20b73c99 100644 --- a/js/components/preview/Preview.js +++ b/js/components/preview/Preview.js @@ -31,7 +31,12 @@ 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, setAllInspirations } from '../datasets/redux/actions'; +import { + setMoleculeListIsLoading, + setSelectedDatasetIndex, + setTabValue, + setAllInspirations +} from '../datasets/redux/actions'; const hitNavigatorWidth = 504; @@ -91,7 +96,7 @@ const Preview = memo(({ isStateLoaded, hideProjects }) => { const dispatch = useDispatch(); const customDatasets = useSelector(state => state.datasetsReducers.datasets); - const [selectedDatasetIndex, setSelectedDatasetIndex] = useState(0); + const selectedDatasetIndex = useSelector(state => state.datasetsReducers.selectedDatasetIndex); const currentDataset = customDatasets[selectedDatasetIndex]; const target_on = useSelector(state => state.apiReducers.target_on); const isTrackingRestoring = useSelector(state => state.trackingReducers.isTrackingCompoundsRestoring); @@ -99,6 +104,7 @@ const Preview = memo(({ isStateLoaded, hideProjects }) => { 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); + const tabValue = useSelector(state => state.datasetsReducers.tabValue); /* Loading datasets @@ -109,7 +115,8 @@ const Preview = memo(({ isStateLoaded, hideProjects }) => { dispatch(loadDataSets(target_on)) .then(results => { if (Array.isArray(results) && results.length > 0) { - setSelectedDatasetIndex(0); + let defaultDataset = results[0]?.unique_name; + dispatch(setSelectedDatasetIndex(0, 0, defaultDataset, defaultDataset, true)); } return dispatch(loadDatasetCompoundsWithScores()); }) @@ -189,7 +196,6 @@ const Preview = memo(({ isStateLoaded, hideProjects }) => { )}px - ${summaryViewHeight}px - ${projectHistoryHeight}px - ${TABS_HEADER_HEIGHT}px )`; const [showHistory, setShowHistory] = useState(false); - const [tabValue, setTabValue] = useState(0); const getTabValue = () => { if (tabValue === 2) { return tabValue + selectedDatasetIndex; @@ -197,6 +203,19 @@ const Preview = memo(({ isStateLoaded, hideProjects }) => { return tabValue; }; + const getTabName = () => { + if (tabValue === 0) { + return 'Vector selector'; + } + if (tabValue === 1) { + return 'Selected compounds'; + } + if (tabValue >= 2) { + return currentDataset?.title; + } + return ''; + }; + useEffect(() => { // Unmount Preview - reset NGL state return () => { @@ -253,13 +272,25 @@ const Preview = memo(({ isStateLoaded, hideProjects }) => { aria-label="outlined primary button group" className={classes.tabButtonGroup} > - - -