From 63edc6d8684307e757ae32a1542c88849a5920ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1na=20Kohanov=C3=A1?= Date: Mon, 26 Oct 2020 16:06:33 +0100 Subject: [PATCH 01/35] #427 Track action history of the user --- js/components/datasets/datasetMoleculeView.js | 5 +- js/components/datasets/inspirationDialog.js | 51 ++-- js/components/datasets/redux/actions.js | 8 +- .../datasets/redux/dispatchActions.js | 18 +- js/components/nglView/generatingObjects.js | 10 +- .../preview/molecule/moleculeView.js | 1 - js/index.js | 5 +- js/reducers/rootReducer.js | 4 +- js/reducers/tracking/actions.js | 15 + js/reducers/tracking/constants.js | 39 +++ js/reducers/tracking/trackingMiddleware.js | 278 ++++++++++++++++++ js/reducers/tracking/trackingReducers.js | 21 ++ 12 files changed, 416 insertions(+), 39 deletions(-) create mode 100644 js/reducers/tracking/actions.js create mode 100644 js/reducers/tracking/constants.js create mode 100644 js/reducers/tracking/trackingMiddleware.js create mode 100644 js/reducers/tracking/trackingReducers.js diff --git a/js/components/datasets/datasetMoleculeView.js b/js/components/datasets/datasetMoleculeView.js index 74365ec00..3d92b3b1d 100644 --- a/js/components/datasets/datasetMoleculeView.js +++ b/js/components/datasets/datasetMoleculeView.js @@ -37,7 +37,6 @@ import { ArrowDownward, ArrowUpward, MyLocation } from '@material-ui/icons'; import { isNumber, isString } from 'lodash'; import { SvgTooltip } from '../common'; - const useStyles = makeStyles(theme => ({ container: { padding: theme.spacing(1) / 4, @@ -541,9 +540,9 @@ export const DatasetMoleculeView = memo( onChange={e => { const result = e.target.checked; if (result) { - dispatch(appendMoleculeToCompoundsOfDatasetToBuy(datasetID, currentID)); + dispatch(appendMoleculeToCompoundsOfDatasetToBuy(datasetID, currentID, moleculeTitle)); } else { - dispatch(removeMoleculeFromCompoundsOfDatasetToBuy(datasetID, currentID)); + dispatch(removeMoleculeFromCompoundsOfDatasetToBuy(datasetID, currentID, moleculeTitle)); } }} /> diff --git a/js/components/datasets/inspirationDialog.js b/js/components/datasets/inspirationDialog.js index 78e61c1c4..3a69ab162 100644 --- a/js/components/datasets/inspirationDialog.js +++ b/js/components/datasets/inspirationDialog.js @@ -220,27 +220,34 @@ export const InspirationDialog = memo( const removeOfAllSelectedTypes = () => { proteinList?.forEach(moleculeID => { - const foundedMolecule = moleculeList?.find(mol => mol.id === moleculeID); + let foundedMolecule = moleculeList?.find(mol => mol.id === moleculeID); + foundedMolecule = foundedMolecule && Object.assign({ isInspiration: true }, foundedMolecule); + dispatch(removeHitProtein(stage, foundedMolecule, colourList[foundedMolecule.id % colourList.length])); }); complexList?.forEach(moleculeID => { - const foundedMolecule = moleculeList?.find(mol => mol.id === moleculeID); + let foundedMolecule = moleculeList?.find(mol => mol.id === moleculeID); + foundedMolecule = foundedMolecule && Object.assign({ isInspiration: true }, foundedMolecule); dispatch(removeComplex(stage, foundedMolecule, colourList[foundedMolecule.id % colourList.length])); }); ligandList?.forEach(moleculeID => { - const foundedMolecule = moleculeList?.find(mol => mol.id === moleculeID); + let foundedMolecule = moleculeList?.find(mol => mol.id === moleculeID); + foundedMolecule = foundedMolecule && Object.assign({ isInspiration: true }, foundedMolecule); dispatch(removeLigand(stage, foundedMolecule, colourList[foundedMolecule.id % colourList.length])); }); surfaceList?.forEach(moleculeID => { - const foundedMolecule = moleculeList?.find(mol => mol.id === moleculeID); + let foundedMolecule = moleculeList?.find(mol => mol.id === moleculeID); + foundedMolecule = foundedMolecule && Object.assign({ isInspiration: true }, foundedMolecule); dispatch(removeSurface(stage, foundedMolecule, colourList[foundedMolecule.id % colourList.length])); }); densityList?.forEach(moleculeID => { - const foundedMolecule = moleculeList?.find(mol => mol.id === moleculeID); + let foundedMolecule = moleculeList?.find(mol => mol.id === moleculeID); + foundedMolecule = foundedMolecule && Object.assign({ isInspiration: true }, foundedMolecule); dispatch(removeDensity(stage, foundedMolecule, colourList[foundedMolecule.id % colourList.length])); }); vectorOnList?.forEach(moleculeID => { - const foundedMolecule = moleculeList?.find(mol => mol.id === moleculeID); + let foundedMolecule = moleculeList?.find(mol => mol.id === moleculeID); + foundedMolecule = foundedMolecule && Object.assign({ isInspiration: true }, foundedMolecule); dispatch(removeVector(stage, foundedMolecule, colourList[foundedMolecule.id % colourList.length])); }); }; @@ -386,19 +393,25 @@ export const InspirationDialog = memo(
{moleculeList.length > 0 && - moleculeList.map((molecule, index, array) => ( - 0 && array[index - 1]} - nextItemData={index < array?.length && array[index + 1]} - removeOfAllSelectedTypes={removeOfAllSelectedTypes} - /> - ))} + moleculeList.map((molecule, index, array) => { + let data = Object.assign({ isInspiration: true }, molecule); + let previousData = index > 0 && Object.assign({ isInspiration: true }, array[index - 1]); + let nextData = index < array?.length && Object.assign({ isInspiration: true }, array[index + 1]); + + return ( + + ); + })} {!(moleculeList.length > 0) && ( diff --git a/js/components/datasets/redux/actions.js b/js/components/datasets/redux/actions.js index c8044aacb..7159713be 100644 --- a/js/components/datasets/redux/actions.js +++ b/js/components/datasets/redux/actions.js @@ -278,14 +278,14 @@ export const setFilterWithInspirations = isChecked => ({ payload: isChecked }); -export const appendMoleculeToCompoundsOfDatasetToBuy = (datasetID, moleculeID) => ({ +export const appendMoleculeToCompoundsOfDatasetToBuy = (datasetID, moleculeID, moleculeTitle) => ({ type: constants.APPEND_MOLECULE_TO_COMPOUNDS_TO_BUY_OF_DATASET, - payload: { datasetID, moleculeID } + payload: { datasetID, moleculeID, moleculeTitle } }); -export const removeMoleculeFromCompoundsOfDatasetToBuy = (datasetID, moleculeID) => ({ +export const removeMoleculeFromCompoundsOfDatasetToBuy = (datasetID, moleculeID, moleculeTitle) => ({ type: constants.REMOVE_MOLECULE_FROM_COMPOUNDS_TO_BUY_OF_DATASET, - payload: { datasetID, moleculeID } + payload: { datasetID, moleculeID, moleculeTitle } }); export const reloadDatasetsReducer = savedDatasetsReducers => { diff --git a/js/components/datasets/redux/dispatchActions.js b/js/components/datasets/redux/dispatchActions.js index 166efe7e8..8a5ae26e6 100644 --- a/js/components/datasets/redux/dispatchActions.js +++ b/js/components/datasets/redux/dispatchActions.js @@ -28,7 +28,7 @@ import { } from './actions'; import { base_url } from '../../routes/constants'; import { - generateMoleculeId, + generateMoleculeCompoundId, generateHitProteinObject, generateComplexObject, generateSurfaceObject, @@ -64,7 +64,7 @@ export const addDatasetHitProtein = (stage, data, colourToggle, datasetID) => di const currentOrientation = stage.viewerControls.getOrientation(); dispatch(setOrientation(VIEWS.MAJOR_VIEW, currentOrientation)); }); - dispatch(appendProteinList(datasetID, generateMoleculeId(data))); + dispatch(appendProteinList(datasetID, generateMoleculeCompoundId(data))); }; export const removeDatasetHitProtein = (stage, data, colourToggle, datasetID) => dispatch => { @@ -77,7 +77,7 @@ export const removeDatasetHitProtein = (stage, data, colourToggle, datasetID) => stage ) ); - dispatch(removeFromProteinList(datasetID, generateMoleculeId(data))); + dispatch(removeFromProteinList(datasetID, generateMoleculeCompoundId(data))); }; export const addDatasetComplex = (stage, data, colourToggle, datasetID) => dispatch => { @@ -94,7 +94,7 @@ export const addDatasetComplex = (stage, data, colourToggle, datasetID) => dispa const currentOrientation = stage.viewerControls.getOrientation(); dispatch(setOrientation(VIEWS.MAJOR_VIEW, currentOrientation)); }); - dispatch(appendComplexList(datasetID, generateMoleculeId(data))); + dispatch(appendComplexList(datasetID, generateMoleculeCompoundId(data))); }; export const removeDatasetComplex = (stage, data, colourToggle, datasetID) => dispatch => { @@ -104,7 +104,7 @@ export const removeDatasetComplex = (stage, data, colourToggle, datasetID) => di stage ) ); - dispatch(removeFromComplexList(datasetID, generateMoleculeId(data))); + dispatch(removeFromComplexList(datasetID, generateMoleculeCompoundId(data))); }; export const addDatasetSurface = (stage, data, colourToggle, datasetID) => dispatch => { @@ -121,7 +121,7 @@ export const addDatasetSurface = (stage, data, colourToggle, datasetID) => dispa const currentOrientation = stage.viewerControls.getOrientation(); dispatch(setOrientation(VIEWS.MAJOR_VIEW, currentOrientation)); }); - dispatch(appendSurfaceList(datasetID, generateMoleculeId(data))); + dispatch(appendSurfaceList(datasetID, generateMoleculeCompoundId(data))); }; export const removeDatasetSurface = (stage, data, colourToggle, datasetID) => dispatch => { @@ -131,7 +131,7 @@ export const removeDatasetSurface = (stage, data, colourToggle, datasetID) => di stage ) ); - dispatch(removeFromSurfaceList(datasetID, generateMoleculeId(data))); + dispatch(removeFromSurfaceList(datasetID, generateMoleculeCompoundId(data))); }; export const addDatasetLigand = (stage, data, colourToggle, datasetID) => dispatch => { @@ -151,7 +151,7 @@ export const addDatasetLigand = (stage, data, colourToggle, datasetID) => dispat // keep current orientation of NGL View stage.viewerControls.orient(currentOrientation); }); - dispatch(appendLigandList(datasetID, generateMoleculeId(data))); + dispatch(appendLigandList(datasetID, generateMoleculeCompoundId(data))); }; export const removeDatasetLigand = (stage, data, colourToggle, datasetID) => dispatch => { @@ -161,7 +161,7 @@ export const removeDatasetLigand = (stage, data, colourToggle, datasetID) => dis stage ) ); - dispatch(removeFromLigandList(datasetID, generateMoleculeId(data))); + dispatch(removeFromLigandList(datasetID, generateMoleculeCompoundId(data))); }; export const loadDataSets = targetId => dispatch => diff --git a/js/components/nglView/generatingObjects.js b/js/components/nglView/generatingObjects.js index c7803af1b..1f2c1b8b8 100644 --- a/js/components/nglView/generatingObjects.js +++ b/js/components/nglView/generatingObjects.js @@ -178,7 +178,15 @@ export const generateDensityObject = (data, colourToggle, base_url) => { }; export const generateMoleculeId = data => ({ - id: data.id + id: data.id, + name: data.protein_code, + isInspiration: data.isInspiration +}); + +export const generateMoleculeCompoundId = data => ({ + id: data.id, + name: data.number, + isCrossReference: data.isCrossReference }); export const getVectorWithColorByCountOfCompounds = (item, currentVectorCompounds) => { diff --git a/js/components/preview/molecule/moleculeView.js b/js/components/preview/molecule/moleculeView.js index aaeccdf85..50adc629b 100644 --- a/js/components/preview/molecule/moleculeView.js +++ b/js/components/preview/molecule/moleculeView.js @@ -32,7 +32,6 @@ import { moleculeProperty } from './helperConstants'; import { centerOnLigandByMoleculeID } from '../../../reducers/ngl/dispatchActions'; import { SvgTooltip } from '../../common'; - const useStyles = makeStyles(theme => ({ container: { padding: theme.spacing(1) / 4, diff --git a/js/index.js b/js/index.js index a9250104e..fb8ddd49e 100644 --- a/js/index.js +++ b/js/index.js @@ -11,7 +11,9 @@ import { applyMiddleware, createStore } from 'redux'; import { rootReducer } from './reducers/rootReducer'; import { saveStore } from './components/helpers/globalStore'; import thunkMiddleware from 'redux-thunk'; +import trackingMiddleware from './reducers/tracking/trackingMiddleware'; import { composeWithDevTools } from 'redux-devtools-extension'; + require('react-hot-loader/patch'); if (process.env.NODE_ENV === 'production') { @@ -37,7 +39,8 @@ if (process.env.NODE_ENV === 'production') { const middlewareEnhancer = applyMiddleware( //loggerMiddleware, - thunkMiddleware + thunkMiddleware, + trackingMiddleware ); const enhancers = [middlewareEnhancer]; const composedEnhancers = composeWithDevTools(...enhancers); diff --git a/js/reducers/rootReducer.js b/js/reducers/rootReducer.js index 92c06c584..17933c666 100644 --- a/js/reducers/rootReducer.js +++ b/js/reducers/rootReducer.js @@ -11,6 +11,7 @@ import { previewReducers } from '../components/preview/redux'; import { projectReducers } from '../components/projects/redux/reducer'; import { issueReducers } from '../components/userFeedback/redux/reducer'; import { datasetsReducers } from '../components/datasets/redux/reducer'; +import trackingReducers from './tracking/trackingReducers'; const rootReducer = combineReducers({ apiReducers, @@ -21,7 +22,8 @@ const rootReducer = combineReducers({ previewReducers, projectReducers, issueReducers, - datasetsReducers + datasetsReducers, + trackingReducers }); export { rootReducer }; diff --git a/js/reducers/tracking/actions.js b/js/reducers/tracking/actions.js new file mode 100644 index 000000000..081ebb700 --- /dev/null +++ b/js/reducers/tracking/actions.js @@ -0,0 +1,15 @@ +import { constants } from './constants'; + +export const setActionsList = function(truck_actions_list) { + return { + type: constants.SET_ACTIONS_LIST, + truck_actions_list: truck_actions_list + }; +}; + +export const appendToActionList = function(truck_action) { + return { + type: constants.APPEND_ACTIONS_LIST, + truck_action: truck_action + }; +}; diff --git a/js/reducers/tracking/constants.js b/js/reducers/tracking/constants.js new file mode 100644 index 000000000..e76434e4e --- /dev/null +++ b/js/reducers/tracking/constants.js @@ -0,0 +1,39 @@ +const prefix = 'REDUCERS_SELECTION_'; + +export const constants = { + SET_ACTIONS_LIST: prefix + 'SET_ACTIONS_LIST', + APPEND_ACTIONS_LIST: prefix + 'APPEND_ACTIONS_LIST' +}; + +export const actionType = { + TARGET_LOADED: 'TARGET_LOADED', + SITE_TURNED_ON: 'SITE_TURNED_ON', + SITE_TURNED_OFF: 'SITE_TURNED_OFF', + LIGAND_TURNED_ON: 'LIGAND_TURNED_ON', + LIGAND_TURNED_OFF: 'LIGAND_TURNED_OFF', + SIDECHAINS_TURNED_ON: 'SIDECHAINS_TURNED_ON', + SIDECHAINS_TURNED_OFF: 'SIDECHAINS_TURNED_OFF', + INTERACTIONS_TURNED_ON: 'INTERACTIONS_TURNED_ON', + INTERACTIONS_TURNED_OFF: 'INTERACTIONS_TURNED_OFF', + SURFACE_TURNED_ON: 'SURFACE_TURNED_ON', + SURFACE_TURNED_OFF: 'SURFACE_TURNED_OFF', + VECTORS_TURNED_ON: 'VECTORS_TURNED_ON', + VECTORS_TURNED_OFF: 'VECTORS_TURNED_OFF', + VECTOR_SELECTED: 'VECTOR_SELECTED', + VECTOR_DESELECTED: 'VECTOR_DESELECTED', + MOLECULE_ADDED_TO_SHOPPING_CART: 'MOLECULE_ADDED_TO_SHOPPING_CART', + MOLECULE_REMOVED_FROM_SHOPPING_CART: 'MOLECULE_REMOVED_FROM_SHOPPING_CART', + COMPOUND_SELECTED: 'COMPOUND_SELECTED', + COMPOUND_DESELECTED: 'COMPOUND_DESELECTED', + REPRESENTATION_CHANGED: 'REPRESENTATION_CHANGED' +}; + +export const objectType = { + TARGET: 'TARGET', + SITE: 'SITE', + MOLECULE: 'MOLECULE', + COMPOUND: 'COMPOUND', + INSPIRATION: 'INSPIRATION', + CROSS_REFERENCE: 'CROSS_REFERENCE', + REPRESENTATION: 'REPRESENTATION' +}; diff --git a/js/reducers/tracking/trackingMiddleware.js b/js/reducers/tracking/trackingMiddleware.js new file mode 100644 index 000000000..7da1db30c --- /dev/null +++ b/js/reducers/tracking/trackingMiddleware.js @@ -0,0 +1,278 @@ +import { appendToActionList } from './actions'; +import { constants, actionType, objectType } from './constants'; +import { constants as apiConstants } from '../api/constants'; +import { CONSTANTS as nglConstants } from '../ngl/constants'; +import { constants as selectionConstants } from '../selection/constants'; +import { constants as customDatasetConstants } from '../../components/datasets/redux/constants'; + +const trackingMiddleware = ({ dispatch, getState }) => next => action => { + console.log(`Redux Log:`, action); + + const state = getState(); + if (!action.type.includes(constants.APPEND_ACTIONS_LIST)) { + let truckAction = findTruckAction(action, state); + if (truckAction != null) { + dispatch(appendToActionList(truckAction)); + } + } + + next(action); +}; + +const findTruckAction = (action, state) => { + let truckAction = null; + if (action.type.includes(apiConstants.SET_TARGET_ON)) { + let targetList = state.apiReducers.target_id_list; + let target = targetList.find(target => target.id === action.target_on); + let target_on_name = (target && target.title) || ''; + + truckAction = { + type: actionType.TARGET_LOADED, + timestamp: Date.now(), + object_type: objectType.TARGET, + object_name: target_on_name, + object_id: action.target_on + }; + } else if (action.type.includes(apiConstants.SET_MOL_GROUP_ON)) { + let mol_group_list = state.apiReducers.mol_group_list; + let mol_group = mol_group_list.find(group => group.id === action.mol_group_on); + let mol_group_on_name = (mol_group && mol_group.description) || ''; + + truckAction = { + type: actionType.SITE_TURNED_ON, + timestamp: Date.now(), + object_type: objectType.SITE, + object_name: mol_group_on_name, + object_id: action.mol_group_on + }; + } else if (action.type.includes(selectionConstants.SET_MOL_GROUP_SELECTION)) { + truckAction = { + type: actionType.SITE_TURNED_ON, + timestamp: Date.now(), + object_type: objectType.SITE + //object_name: mol_group_on_name, + //object_id: action.mol_group_on + }; + } else if (action.type.includes(selectionConstants.SET_OBJECT_SELECTION)) { + truckAction = { + type: actionType.SITE_TURNED_ON, + timestamp: Date.now(), + object_type: objectType.SITE + //object_name: mol_group_on_name, + //object_id: action.mol_group_on + }; + } else if (action.type.includes(selectionConstants.APPEND_FRAGMENT_DISPLAY_LIST)) { + truckAction = { + type: actionType.LIGAND_TURNED_ON, + timestamp: Date.now(), + object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, + object_name: action.item.name, + object_id: action.item.id + }; + } else if (action.type.includes(selectionConstants.REMOVE_FROM_FRAGMENT_DISPLAY_LIST)) { + truckAction = { + type: actionType.LIGAND_TURNED_OFF, + timestamp: Date.now(), + object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, + object_name: action.item.name, + object_id: action.item.id + }; + } else if (action.type.includes(selectionConstants.APPEND_PROTEIN_LIST)) { + truckAction = { + type: actionType.SIDECHAINS_TURNED_ON, + timestamp: Date.now(), + object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, + object_name: action.item.name, + object_id: action.item.id + }; + } else if (action.type.includes(selectionConstants.REMOVE_FROM_PROTEIN_LIST)) { + truckAction = { + type: actionType.SIDECHAINS_TURNED_OFF, + timestamp: Date.now(), + object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, + object_name: action.item.name, + object_id: action.item.id + }; + } else if (action.type.includes(selectionConstants.APPEND_COMPLEX_LIST)) { + truckAction = { + type: actionType.INTERACTIONS_TURNED_ON, + timestamp: Date.now(), + object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, + object_name: action.item.name, + object_id: action.item.id + }; + } else if (action.type.includes(selectionConstants.REMOVE_FROM_COMPLEX_LIST)) { + truckAction = { + type: actionType.INTERACTIONS_TURNED_OFF, + timestamp: Date.now(), + object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, + object_name: action.item.name, + object_id: action.item.id + }; + } else if (action.type.includes(selectionConstants.APPEND_SURFACE_LIST)) { + truckAction = { + type: actionType.SURFACE_TURNED_ON, + timestamp: Date.now(), + object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, + object_name: action.item.name, + object_id: action.item.id + }; + } else if (action.type.includes(selectionConstants.REMOVE_FROM_SURFACE_LIST)) { + truckAction = { + type: actionType.SURFACE_TURNED_OFF, + timestamp: Date.now(), + object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, + object_name: action.item.name, + object_id: action.item.id + }; + } else if (action.type.includes(selectionConstants.APPEND_VECTOR_ON_LIST)) { + truckAction = { + type: actionType.VECTORS_TURNED_ON, + timestamp: Date.now(), + object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, + object_name: action.item.name, + object_id: action.item.id + }; + } else if (action.type.includes(selectionConstants.REMOVE_FROM_VECTOR_ON_LIST)) { + truckAction = { + type: actionType.VECTORS_TURNED_OFF, + timestamp: Date.now(), + object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, + object_name: action.item.name, + object_id: action.item.id + }; + } else if (action.type.includes(selectionConstants.APPEND_TO_BUY_LIST)) { + truckAction = { + type: actionType.MOLECULE_ADDED_TO_SHOPPING_CART, + timestamp: Date.now(), + object_type: objectType.MOLECULE, + object_name: action.item.name, + object_id: action.item.id + }; + } else if (action.type.includes(selectionConstants.REMOVE_FROM_TO_BUY_LIST)) { + truckAction = { + type: actionType.MOLECULE_REMOVED_FROM_SHOPPING_CART, + timestamp: Date.now(), + object_type: objectType.MOLECULE, + object_name: action.item.name, + object_id: action.item.id + }; + } else if (action.type.includes(selectionConstants.SET_CURRENT_VECTOR)) { + truckAction = { + type: actionType.VECTOR_SELECTED, + timestamp: Date.now(), + object_type: objectType.MOLECULE, + object_name: action.payload, + object_id: action.payload + }; + } else if (action.type.includes(customDatasetConstants.APPEND_MOLECULE_TO_COMPOUNDS_TO_BUY_OF_DATASET)) { + truckAction = { + type: actionType.COMPOUND_SELECTED, + timestamp: Date.now(), + object_type: objectType.COMPOUND, + object_name: action.payload.moleculeTitle, + object_id: action.payload.moleculeID, + dataset_id: action.payload.datasetID + }; + } else if (action.type.includes(customDatasetConstants.REMOVE_MOLECULE_FROM_COMPOUNDS_TO_BUY_OF_DATASET)) { + truckAction = { + type: actionType.COMPOUND_DESELECTED, + timestamp: Date.now(), + object_type: objectType.COMPOUND, + object_name: action.payload.moleculeTitle, + object_id: action.payload.moleculeID, + dataset_id: action.payload.datasetID + }; + } else if (action.type.includes(customDatasetConstants.APPEND_LIGAND_LIST)) { + truckAction = { + type: actionType.LIGAND_TURNED_ON, + timestamp: Date.now(), + object_type: action.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, + object_name: action.item.name, + object_id: action.item.id + }; + } else if (action.type.includes(customDatasetConstants.REMOVE_FROM_LIGAND_LIST)) { + truckAction = { + type: actionType.LIGAND_TURNED_OFF, + timestamp: Date.now(), + object_type: objectType.COMPOUND, + object_name: action.item.name, + object_id: action.item.id + }; + } else if (action.type.includes(customDatasetConstants.APPEND_PROTEIN_LIST)) { + truckAction = { + type: actionType.SIDECHAINS_TURNED_ON, + timestamp: Date.now(), + object_type: action.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, + object_name: action.item.name, + object_id: action.item.id + }; + } else if (action.type.includes(customDatasetConstants.REMOVE_FROM_PROTEIN_LIST)) { + truckAction = { + type: actionType.SIDECHAINS_TURNED_OFF, + timestamp: Date.now(), + object_type: action.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, + object_name: action.item.name, + object_id: action.item.id + }; + } else if (action.type.includes(customDatasetConstants.APPEND_COMPLEX_LIST)) { + truckAction = { + type: actionType.INTERACTIONS_TURNED_ON, + timestamp: Date.now(), + object_type: action.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, + object_name: action.item.name, + object_id: action.item.id + }; + } else if (action.type.includes(customDatasetConstants.REMOVE_FROM_COMPLEX_LIST)) { + truckAction = { + type: actionType.INTERACTIONS_TURNED_OFF, + timestamp: Date.now(), + object_type: action.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, + object_name: action.item.name, + object_id: action.item.id + }; + } else if (action.type.includes(customDatasetConstants.APPEND_SURFACE_LIST)) { + truckAction = { + type: actionType.SURFACE_TURNED_ON, + timestamp: Date.now(), + object_type: action.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, + object_name: action.item.name, + object_id: action.item.id + }; + } else if (action.type.includes(customDatasetConstants.REMOVE_FROM_SURFACE_LIST)) { + truckAction = { + type: actionType.SURFACE_TURNED_OFF, + timestamp: Date.now(), + object_type: action.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, + object_name: action.item.name, + object_id: action.item.id + }; + } else if (action.type.includes(nglConstants.UPDATE_COMPONENT_REPRESENTATION)) { + truckAction = { + type: actionType.REPRESENTATION_CHANGED, + timestamp: Date.now() + //object_type: objectType.MOLECULE, + //object_name: mol_name, + //object_id: action.item.id + }; + } else if (action.type.includes(nglConstants.ADD_COMPONENT_REPRESENTATION)) { + truckAction = { + type: actionType.REPRESENTATION_CHANGED, + timestamp: Date.now() + //object_type: objectType.MOLECULE, + //object_name: mol_name, + //object_id: action.item.id + }; + } else if (action.type.includes(nglConstants.REMOVE_COMPONENT_REPRESENTATION)) { + truckAction = { + type: actionType.REPRESENTATION_CHANGED, + timestamp: Date.now() + //object_type: objectType.MOLECULE, + //object_name: mol_name, + //object_id: action.item.id + }; + } + + return truckAction; +}; +export default trackingMiddleware; diff --git a/js/reducers/tracking/trackingReducers.js b/js/reducers/tracking/trackingReducers.js new file mode 100644 index 000000000..a8f7d4590 --- /dev/null +++ b/js/reducers/tracking/trackingReducers.js @@ -0,0 +1,21 @@ +import { constants } from './constants'; + +export const INITIAL_STATE = { + truck_actions_list: [] +}; + +export default function trackingReducers(state = INITIAL_STATE, action = {}) { + switch (action.type) { + case constants.SET_ACTIONS_LIST: + return Object.assign({}, state, { + truck_actions_list: action.truck_actions_list + }); + + case constants.APPEND_ACTIONS_LIST: + return Object.assign({}, state, { + truck_actions_list: [...new Set([...state.truck_actions_list, action.truck_action])] + }); + default: + return state; + } +} From 96aade89016c22473275685af7156b2d22d33ec4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1na=20Kohanov=C3=A1?= Date: Tue, 27 Oct 2020 10:18:55 +0100 Subject: [PATCH 02/35] #427 Track action history of the user --- .../datasets/crossReferenceDialog.js | 36 +- js/components/nglView/generatingObjects.js | 2 +- js/reducers/tracking/trackingActions.js | 361 ++++++++++++++++++ js/reducers/tracking/trackingMiddleware.js | 263 +------------ 4 files changed, 385 insertions(+), 277 deletions(-) create mode 100644 js/reducers/tracking/trackingActions.js diff --git a/js/components/datasets/crossReferenceDialog.js b/js/components/datasets/crossReferenceDialog.js index d832ebb5c..5bd070d7d 100644 --- a/js/components/datasets/crossReferenceDialog.js +++ b/js/components/datasets/crossReferenceDialog.js @@ -317,21 +317,27 @@ export const CrossReferenceDialog = memo(
{moleculeList.length > 0 && - moleculeList.map((data, index, array) => ( - 0 && array[index - 1]} - nextItemData={index < array?.length && array[index + 1]} - removeOfAllSelectedTypes={removeOfAllSelectedTypes} - /> - ))} + moleculeList.map((data, index, array) => { + let molecule = Object.assign({ isCrossReference: true }, data.molecule); + let previousData = index > 0 && Object.assign({ isCrossReference: true }, array[index - 1]); + let nextData = index < array?.length && Object.assign({ isCrossReference: true }, array[index + 1]); + + return ( + + ); + })} {!(moleculeList.length > 0) && ( diff --git a/js/components/nglView/generatingObjects.js b/js/components/nglView/generatingObjects.js index 1f2c1b8b8..bb73083ec 100644 --- a/js/components/nglView/generatingObjects.js +++ b/js/components/nglView/generatingObjects.js @@ -185,7 +185,7 @@ export const generateMoleculeId = data => ({ export const generateMoleculeCompoundId = data => ({ id: data.id, - name: data.number, + name: data.name, isCrossReference: data.isCrossReference }); diff --git a/js/reducers/tracking/trackingActions.js b/js/reducers/tracking/trackingActions.js new file mode 100644 index 000000000..724ce8ee4 --- /dev/null +++ b/js/reducers/tracking/trackingActions.js @@ -0,0 +1,361 @@ +import { actionType, objectType } from './constants'; +import { constants as apiConstants } from '../api/constants'; +import { CONSTANTS as nglConstants } from '../ngl/constants'; +import { constants as selectionConstants } from '../selection/constants'; +import { constants as customDatasetConstants } from '../../components/datasets/redux/constants'; +import { DJANGO_CONTEXT } from '../../utils/djangoContext'; + +export const findTruckAction = (action, state) => { + const username = DJANGO_CONTEXT['username']; + let truckAction = null; + if (action.type.includes(apiConstants.SET_TARGET_ON)) { + if (action.target_on) { + let targetName = getTargetName(action.target_on, state); + truckAction = { + type: actionType.TARGET_LOADED, + timestamp: Date.now(), + username: username, + object_type: objectType.TARGET, + object_name: targetName, + object_id: action.target_on + }; + } + } else if (action.type.includes(apiConstants.SET_MOL_GROUP_ON)) { + if (action.mol_group_on) { + let molGroupSelection = state.selectionReducers.mol_group_selection; + let currentMolGroup = molGroupSelection && molGroupSelection.find(o => o === action.mol_group_on); + if (!currentMolGroup) { + let molGroupName = getMolGroupName(action.mol_group_on, state); + truckAction = { + type: actionType.SITE_TURNED_ON, + timestamp: Date.now(), + username: username, + object_type: objectType.SITE, + object_name: molGroupName, + object_id: action.mol_group_on + }; + } + } + } else if (action.type.includes(selectionConstants.SET_OBJECT_SELECTION)) { + let objectId = action.payload && action.payload[0]; + if (objectId) { + let molGroupName = getMolGroupName(objectId, state); + truckAction = { + type: actionType.SITE_TURNED_OFF, + timestamp: Date.now(), + username: username, + object_type: objectType.SITE, + object_name: molGroupName, + object_id: objectId + }; + } + } else if (action.type.includes(selectionConstants.APPEND_FRAGMENT_DISPLAY_LIST)) { + if (action.item) { + truckAction = { + type: actionType.LIGAND_TURNED_ON, + timestamp: Date.now(), + username: username, + object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, + object_name: action.item.name, + object_id: action.item.id + }; + } + } else if (action.type.includes(selectionConstants.REMOVE_FROM_FRAGMENT_DISPLAY_LIST)) { + if (action.item) { + truckAction = { + type: actionType.LIGAND_TURNED_OFF, + timestamp: Date.now(), + username: username, + object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, + object_name: action.item.name, + object_id: action.item.id + }; + } + } else if (action.type.includes(selectionConstants.APPEND_PROTEIN_LIST)) { + if (action.item) { + truckAction = { + type: actionType.SIDECHAINS_TURNED_ON, + timestamp: Date.now(), + username: username, + object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, + object_name: action.item.name, + object_id: action.item.id + }; + } + } else if (action.type.includes(selectionConstants.REMOVE_FROM_PROTEIN_LIST)) { + if (action.item) { + truckAction = { + type: actionType.SIDECHAINS_TURNED_OFF, + timestamp: Date.now(), + username: username, + object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, + object_name: action.item.name, + object_id: action.item.id + }; + } + } else if (action.type.includes(selectionConstants.APPEND_COMPLEX_LIST)) { + if (action.item) { + truckAction = { + type: actionType.INTERACTIONS_TURNED_ON, + timestamp: Date.now(), + username: username, + object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, + object_name: action.item.name, + object_id: action.item.id + }; + } + } else if (action.type.includes(selectionConstants.REMOVE_FROM_COMPLEX_LIST)) { + if (action.item) { + truckAction = { + type: actionType.INTERACTIONS_TURNED_OFF, + timestamp: Date.now(), + username: username, + object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, + object_name: action.item.name, + object_id: action.item.id + }; + } + } else if (action.type.includes(selectionConstants.APPEND_SURFACE_LIST)) { + if (action.item) { + truckAction = { + type: actionType.SURFACE_TURNED_ON, + timestamp: Date.now(), + username: username, + object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, + object_name: action.item.name, + object_id: action.item.id + }; + } + } else if (action.type.includes(selectionConstants.REMOVE_FROM_SURFACE_LIST)) { + if (action.item) { + truckAction = { + type: actionType.SURFACE_TURNED_OFF, + timestamp: Date.now(), + username: username, + object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, + object_name: action.item.name, + object_id: action.item.id + }; + } + } else if (action.type.includes(selectionConstants.APPEND_VECTOR_ON_LIST)) { + if (action.item) { + truckAction = { + type: actionType.VECTORS_TURNED_ON, + timestamp: Date.now(), + username: username, + object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, + object_name: action.item.name, + object_id: action.item.id + }; + } + } else if (action.type.includes(selectionConstants.REMOVE_FROM_VECTOR_ON_LIST)) { + if (action.item) { + truckAction = { + type: actionType.VECTORS_TURNED_OFF, + timestamp: Date.now(), + username: username, + object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, + object_name: action.item.name, + object_id: action.item.id + }; + } + } else if (action.type.includes(selectionConstants.APPEND_TO_BUY_LIST)) { + if (action.item) { + truckAction = { + type: actionType.MOLECULE_ADDED_TO_SHOPPING_CART, + timestamp: Date.now(), + username: username, + object_type: objectType.MOLECULE, + object_name: action.item.name, + object_id: action.item.id + }; + } + } else if (action.type.includes(selectionConstants.REMOVE_FROM_TO_BUY_LIST)) { + if (action.item) { + truckAction = { + type: actionType.MOLECULE_REMOVED_FROM_SHOPPING_CART, + timestamp: Date.now(), + username: username, + object_type: objectType.MOLECULE, + object_name: action.item.name, + object_id: action.item.id + }; + } + } else if (action.type.includes(selectionConstants.SET_CURRENT_VECTOR)) { + truckAction = { + type: actionType.VECTOR_SELECTED, + timestamp: Date.now(), + username: username, + object_type: objectType.MOLECULE, + object_name: action.payload, + object_id: action.payload + }; + } else if (action.type.includes(customDatasetConstants.APPEND_MOLECULE_TO_COMPOUNDS_TO_BUY_OF_DATASET)) { + if (action.payload) { + truckAction = { + type: actionType.COMPOUND_SELECTED, + timestamp: Date.now(), + username: username, + object_type: objectType.COMPOUND, + object_name: action.payload.moleculeTitle, + object_id: action.payload.moleculeID, + dataset_id: action.payload.datasetID + }; + } + } else if (action.type.includes(customDatasetConstants.REMOVE_MOLECULE_FROM_COMPOUNDS_TO_BUY_OF_DATASET)) { + if (action.payload) { + truckAction = { + type: actionType.COMPOUND_DESELECTED, + timestamp: Date.now(), + username: username, + object_type: objectType.COMPOUND, + object_name: action.payload.moleculeTitle, + object_id: action.payload.moleculeID, + dataset_id: action.payload.datasetID + }; + } + } else if (action.type.includes(customDatasetConstants.APPEND_LIGAND_LIST)) { + if (action.payload && action.payload.item) { + truckAction = { + type: actionType.LIGAND_TURNED_ON, + timestamp: Date.now(), + username: username, + object_type: action.payload.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, + object_name: action.payload.item.name, + object_id: action.payload.item.id, + dataset_id: action.payload.datasetID + }; + } + } else if (action.type.includes(customDatasetConstants.REMOVE_FROM_LIGAND_LIST)) { + if (action.payload && action.payload.item) { + truckAction = { + type: actionType.LIGAND_TURNED_OFF, + timestamp: Date.now(), + username: username, + object_type: action.payload.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, + object_name: action.payload.item.name, + object_id: action.payload.item.id, + dataset_id: action.payload.datasetID + }; + } + } else if (action.type.includes(customDatasetConstants.APPEND_PROTEIN_LIST)) { + if (action.payload && action.payload.item) { + truckAction = { + type: actionType.SIDECHAINS_TURNED_ON, + timestamp: Date.now(), + username: username, + object_type: action.payload.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, + object_name: action.payload.item.name, + object_id: action.payload.item.id, + dataset_id: action.payload.datasetID + }; + } + } else if (action.type.includes(customDatasetConstants.REMOVE_FROM_PROTEIN_LIST)) { + if (action.payload && action.payload.item) { + truckAction = { + type: actionType.SIDECHAINS_TURNED_OFF, + timestamp: Date.now(), + username: username, + object_type: action.payload.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, + object_name: action.payload.item.name, + object_id: action.payload.item.id, + dataset_id: action.payload.datasetID + }; + } + } else if (action.type.includes(customDatasetConstants.APPEND_COMPLEX_LIST)) { + if (action.payload && action.payload.item) { + truckAction = { + type: actionType.INTERACTIONS_TURNED_ON, + timestamp: Date.now(), + username: username, + object_type: action.payload.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, + object_name: action.payload.item.name, + object_id: action.payload.item.id, + dataset_id: action.payload.datasetID + }; + } + } else if (action.type.includes(customDatasetConstants.REMOVE_FROM_COMPLEX_LIST)) { + if (action.payload && action.payload.item) { + truckAction = { + type: actionType.INTERACTIONS_TURNED_OFF, + timestamp: Date.now(), + username: username, + object_type: action.payload.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, + object_name: action.payload.item.name, + object_id: action.payload.item.id, + dataset_id: action.payload.datasetID + }; + } else if (action.type.includes(customDatasetConstants.APPEND_SURFACE_LIST)) { + if (action.payload && action.payload.item) { + truckAction = { + type: actionType.SURFACE_TURNED_ON, + timestamp: Date.now(), + username: username, + object_type: action.payload.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, + object_name: action.payload.item.name, + object_id: action.payload.item.id, + dataset_id: action.payload.datasetID + }; + } + } + } else if (action.type.includes(customDatasetConstants.REMOVE_FROM_SURFACE_LIST)) { + if (action.payload && action.payload.item) { + truckAction = { + type: actionType.SURFACE_TURNED_OFF, + timestamp: Date.now(), + username: username, + object_type: action.payload.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, + object_name: action.payload.item.name, + object_id: action.payload.item.id, + dataset_id: action.payload.datasetID + }; + } + } else if (action.type.includes(nglConstants.UPDATE_COMPONENT_REPRESENTATION)) { + truckAction = { + type: actionType.REPRESENTATION_CHANGED, + timestamp: Date.now(), + username: username, + object_type: objectType.REPRESENTATION, + object_name: action.objectInViewID, + object_id: action.objectInViewID, + representation_id: action.representationID, + new_representation: action.newRepresentation + }; + } else if (action.type.includes(nglConstants.ADD_COMPONENT_REPRESENTATION)) { + truckAction = { + type: actionType.REPRESENTATION_CHANGED, + timestamp: Date.now(), + username: username, + object_type: objectType.REPRESENTATION, + object_name: action.objectInViewID, + object_id: action.objectInViewID, + new_representation: action.newRepresentation + }; + } else if (action.type.includes(nglConstants.REMOVE_COMPONENT_REPRESENTATION)) { + truckAction = { + type: actionType.REPRESENTATION_CHANGED, + timestamp: Date.now(), + username: username, + object_type: objectType.REPRESENTATION, + object_name: action.objectInViewID, + object_id: action.objectInViewID, + representation_id: action.representationID + }; + } + + return truckAction; +}; + +const getMolGroupName = (molGroupId, state) => { + let molGroupList = state.apiReducers.mol_group_list; + let molGroup = molGroupList.find(group => group.id === molGroupId); + let molGroupName = (molGroup && molGroup.description) || ''; + return molGroupName; +}; + +const getTargetName = (targetId, state) => { + let targetList = state.apiReducers.target_id_list; + let target = targetList.find(target => target.id === targetId); + let targetName = (target && target.title) || ''; + return targetName; +}; diff --git a/js/reducers/tracking/trackingMiddleware.js b/js/reducers/tracking/trackingMiddleware.js index 7da1db30c..f82542447 100644 --- a/js/reducers/tracking/trackingMiddleware.js +++ b/js/reducers/tracking/trackingMiddleware.js @@ -1,9 +1,6 @@ import { appendToActionList } from './actions'; -import { constants, actionType, objectType } from './constants'; -import { constants as apiConstants } from '../api/constants'; -import { CONSTANTS as nglConstants } from '../ngl/constants'; -import { constants as selectionConstants } from '../selection/constants'; -import { constants as customDatasetConstants } from '../../components/datasets/redux/constants'; +import { constants } from './constants'; +import { findTruckAction } from './trackingActions'; const trackingMiddleware = ({ dispatch, getState }) => next => action => { console.log(`Redux Log:`, action); @@ -19,260 +16,4 @@ const trackingMiddleware = ({ dispatch, getState }) => next => action => { next(action); }; -const findTruckAction = (action, state) => { - let truckAction = null; - if (action.type.includes(apiConstants.SET_TARGET_ON)) { - let targetList = state.apiReducers.target_id_list; - let target = targetList.find(target => target.id === action.target_on); - let target_on_name = (target && target.title) || ''; - - truckAction = { - type: actionType.TARGET_LOADED, - timestamp: Date.now(), - object_type: objectType.TARGET, - object_name: target_on_name, - object_id: action.target_on - }; - } else if (action.type.includes(apiConstants.SET_MOL_GROUP_ON)) { - let mol_group_list = state.apiReducers.mol_group_list; - let mol_group = mol_group_list.find(group => group.id === action.mol_group_on); - let mol_group_on_name = (mol_group && mol_group.description) || ''; - - truckAction = { - type: actionType.SITE_TURNED_ON, - timestamp: Date.now(), - object_type: objectType.SITE, - object_name: mol_group_on_name, - object_id: action.mol_group_on - }; - } else if (action.type.includes(selectionConstants.SET_MOL_GROUP_SELECTION)) { - truckAction = { - type: actionType.SITE_TURNED_ON, - timestamp: Date.now(), - object_type: objectType.SITE - //object_name: mol_group_on_name, - //object_id: action.mol_group_on - }; - } else if (action.type.includes(selectionConstants.SET_OBJECT_SELECTION)) { - truckAction = { - type: actionType.SITE_TURNED_ON, - timestamp: Date.now(), - object_type: objectType.SITE - //object_name: mol_group_on_name, - //object_id: action.mol_group_on - }; - } else if (action.type.includes(selectionConstants.APPEND_FRAGMENT_DISPLAY_LIST)) { - truckAction = { - type: actionType.LIGAND_TURNED_ON, - timestamp: Date.now(), - object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, - object_name: action.item.name, - object_id: action.item.id - }; - } else if (action.type.includes(selectionConstants.REMOVE_FROM_FRAGMENT_DISPLAY_LIST)) { - truckAction = { - type: actionType.LIGAND_TURNED_OFF, - timestamp: Date.now(), - object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, - object_name: action.item.name, - object_id: action.item.id - }; - } else if (action.type.includes(selectionConstants.APPEND_PROTEIN_LIST)) { - truckAction = { - type: actionType.SIDECHAINS_TURNED_ON, - timestamp: Date.now(), - object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, - object_name: action.item.name, - object_id: action.item.id - }; - } else if (action.type.includes(selectionConstants.REMOVE_FROM_PROTEIN_LIST)) { - truckAction = { - type: actionType.SIDECHAINS_TURNED_OFF, - timestamp: Date.now(), - object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, - object_name: action.item.name, - object_id: action.item.id - }; - } else if (action.type.includes(selectionConstants.APPEND_COMPLEX_LIST)) { - truckAction = { - type: actionType.INTERACTIONS_TURNED_ON, - timestamp: Date.now(), - object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, - object_name: action.item.name, - object_id: action.item.id - }; - } else if (action.type.includes(selectionConstants.REMOVE_FROM_COMPLEX_LIST)) { - truckAction = { - type: actionType.INTERACTIONS_TURNED_OFF, - timestamp: Date.now(), - object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, - object_name: action.item.name, - object_id: action.item.id - }; - } else if (action.type.includes(selectionConstants.APPEND_SURFACE_LIST)) { - truckAction = { - type: actionType.SURFACE_TURNED_ON, - timestamp: Date.now(), - object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, - object_name: action.item.name, - object_id: action.item.id - }; - } else if (action.type.includes(selectionConstants.REMOVE_FROM_SURFACE_LIST)) { - truckAction = { - type: actionType.SURFACE_TURNED_OFF, - timestamp: Date.now(), - object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, - object_name: action.item.name, - object_id: action.item.id - }; - } else if (action.type.includes(selectionConstants.APPEND_VECTOR_ON_LIST)) { - truckAction = { - type: actionType.VECTORS_TURNED_ON, - timestamp: Date.now(), - object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, - object_name: action.item.name, - object_id: action.item.id - }; - } else if (action.type.includes(selectionConstants.REMOVE_FROM_VECTOR_ON_LIST)) { - truckAction = { - type: actionType.VECTORS_TURNED_OFF, - timestamp: Date.now(), - object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, - object_name: action.item.name, - object_id: action.item.id - }; - } else if (action.type.includes(selectionConstants.APPEND_TO_BUY_LIST)) { - truckAction = { - type: actionType.MOLECULE_ADDED_TO_SHOPPING_CART, - timestamp: Date.now(), - object_type: objectType.MOLECULE, - object_name: action.item.name, - object_id: action.item.id - }; - } else if (action.type.includes(selectionConstants.REMOVE_FROM_TO_BUY_LIST)) { - truckAction = { - type: actionType.MOLECULE_REMOVED_FROM_SHOPPING_CART, - timestamp: Date.now(), - object_type: objectType.MOLECULE, - object_name: action.item.name, - object_id: action.item.id - }; - } else if (action.type.includes(selectionConstants.SET_CURRENT_VECTOR)) { - truckAction = { - type: actionType.VECTOR_SELECTED, - timestamp: Date.now(), - object_type: objectType.MOLECULE, - object_name: action.payload, - object_id: action.payload - }; - } else if (action.type.includes(customDatasetConstants.APPEND_MOLECULE_TO_COMPOUNDS_TO_BUY_OF_DATASET)) { - truckAction = { - type: actionType.COMPOUND_SELECTED, - timestamp: Date.now(), - object_type: objectType.COMPOUND, - object_name: action.payload.moleculeTitle, - object_id: action.payload.moleculeID, - dataset_id: action.payload.datasetID - }; - } else if (action.type.includes(customDatasetConstants.REMOVE_MOLECULE_FROM_COMPOUNDS_TO_BUY_OF_DATASET)) { - truckAction = { - type: actionType.COMPOUND_DESELECTED, - timestamp: Date.now(), - object_type: objectType.COMPOUND, - object_name: action.payload.moleculeTitle, - object_id: action.payload.moleculeID, - dataset_id: action.payload.datasetID - }; - } else if (action.type.includes(customDatasetConstants.APPEND_LIGAND_LIST)) { - truckAction = { - type: actionType.LIGAND_TURNED_ON, - timestamp: Date.now(), - object_type: action.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, - object_name: action.item.name, - object_id: action.item.id - }; - } else if (action.type.includes(customDatasetConstants.REMOVE_FROM_LIGAND_LIST)) { - truckAction = { - type: actionType.LIGAND_TURNED_OFF, - timestamp: Date.now(), - object_type: objectType.COMPOUND, - object_name: action.item.name, - object_id: action.item.id - }; - } else if (action.type.includes(customDatasetConstants.APPEND_PROTEIN_LIST)) { - truckAction = { - type: actionType.SIDECHAINS_TURNED_ON, - timestamp: Date.now(), - object_type: action.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, - object_name: action.item.name, - object_id: action.item.id - }; - } else if (action.type.includes(customDatasetConstants.REMOVE_FROM_PROTEIN_LIST)) { - truckAction = { - type: actionType.SIDECHAINS_TURNED_OFF, - timestamp: Date.now(), - object_type: action.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, - object_name: action.item.name, - object_id: action.item.id - }; - } else if (action.type.includes(customDatasetConstants.APPEND_COMPLEX_LIST)) { - truckAction = { - type: actionType.INTERACTIONS_TURNED_ON, - timestamp: Date.now(), - object_type: action.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, - object_name: action.item.name, - object_id: action.item.id - }; - } else if (action.type.includes(customDatasetConstants.REMOVE_FROM_COMPLEX_LIST)) { - truckAction = { - type: actionType.INTERACTIONS_TURNED_OFF, - timestamp: Date.now(), - object_type: action.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, - object_name: action.item.name, - object_id: action.item.id - }; - } else if (action.type.includes(customDatasetConstants.APPEND_SURFACE_LIST)) { - truckAction = { - type: actionType.SURFACE_TURNED_ON, - timestamp: Date.now(), - object_type: action.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, - object_name: action.item.name, - object_id: action.item.id - }; - } else if (action.type.includes(customDatasetConstants.REMOVE_FROM_SURFACE_LIST)) { - truckAction = { - type: actionType.SURFACE_TURNED_OFF, - timestamp: Date.now(), - object_type: action.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, - object_name: action.item.name, - object_id: action.item.id - }; - } else if (action.type.includes(nglConstants.UPDATE_COMPONENT_REPRESENTATION)) { - truckAction = { - type: actionType.REPRESENTATION_CHANGED, - timestamp: Date.now() - //object_type: objectType.MOLECULE, - //object_name: mol_name, - //object_id: action.item.id - }; - } else if (action.type.includes(nglConstants.ADD_COMPONENT_REPRESENTATION)) { - truckAction = { - type: actionType.REPRESENTATION_CHANGED, - timestamp: Date.now() - //object_type: objectType.MOLECULE, - //object_name: mol_name, - //object_id: action.item.id - }; - } else if (action.type.includes(nglConstants.REMOVE_COMPONENT_REPRESENTATION)) { - truckAction = { - type: actionType.REPRESENTATION_CHANGED, - timestamp: Date.now() - //object_type: objectType.MOLECULE, - //object_name: mol_name, - //object_id: action.item.id - }; - } - - return truckAction; -}; export default trackingMiddleware; From 552f2bc5b08d9333eaa850ba2a5735fd716d1402 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1na=20Kohanov=C3=A1?= Date: Wed, 28 Oct 2020 16:14:19 +0100 Subject: [PATCH 03/35] #430 Visualize users action history --- js/components/header/index.js | 16 +- js/reducers/tracking/actions.js | 5 + js/reducers/tracking/constants.js | 20 ++- js/reducers/tracking/trackingActions.js | 138 +++++++++++++----- js/reducers/tracking/trackingMiddleware.js | 2 +- .../tracking/trackingModal/trackingModal.js | 41 ++++++ js/reducers/tracking/trackingReducers.js | 4 + package.json | 3 +- 8 files changed, 185 insertions(+), 44 deletions(-) create mode 100644 js/reducers/tracking/trackingModal/trackingModal.js diff --git a/js/components/header/index.js b/js/components/header/index.js index 1b4af97b5..1db7582c9 100644 --- a/js/components/header/index.js +++ b/js/components/header/index.js @@ -26,7 +26,8 @@ import { SupervisorAccount, Menu as MenuIcon, Work, - Description + Description, + Timeline } from '@material-ui/icons'; import { HeaderContext } from './headerContext'; import { Button } from '../common'; @@ -39,6 +40,7 @@ import { useHistory } from 'react-router-dom'; import { IssueReport } from '../userFeedback/issueReport'; import { IdeaReport } from '../userFeedback/ideaReport'; import { FundersModal } from '../funders/fundersModal'; +import { TrackingModal } from '../../reducers/tracking/trackingModal/trackingModal'; // eslint-disable-next-line import/extensions import { version } from '../../../package.json'; @@ -94,6 +96,7 @@ export default memo( const [openMenu, setOpenMenu] = useState(false); const [openFunders, setOpenFunders] = useState(false); + const [openTrackingModal, setOpenTrackingModal] = useState(false); const openXchem = () => { // window.location.href = 'https://www.diamond.ac.uk/Instruments/Mx/Fragment-Screening.html'; @@ -211,6 +214,16 @@ export default memo( + + + @@ -275,6 +288,7 @@ export default memo( )} setOpenFunders(false)} /> + setOpenTrackingModal(false)} /> ({ +// type: constants.SET_TRACKING_MODAL_OPEN, +// payload: isOpen +// }); diff --git a/js/reducers/tracking/constants.js b/js/reducers/tracking/constants.js index e76434e4e..014dfcd15 100644 --- a/js/reducers/tracking/constants.js +++ b/js/reducers/tracking/constants.js @@ -2,7 +2,8 @@ const prefix = 'REDUCERS_SELECTION_'; export const constants = { SET_ACTIONS_LIST: prefix + 'SET_ACTIONS_LIST', - APPEND_ACTIONS_LIST: prefix + 'APPEND_ACTIONS_LIST' + APPEND_ACTIONS_LIST: prefix + 'APPEND_ACTIONS_LIST', + SET_TRACKING_MODAL_OPEN: prefix + 'SET_TRACKING_MODAL_OPEN' }; export const actionType = { @@ -25,7 +26,22 @@ export const actionType = { MOLECULE_REMOVED_FROM_SHOPPING_CART: 'MOLECULE_REMOVED_FROM_SHOPPING_CART', COMPOUND_SELECTED: 'COMPOUND_SELECTED', COMPOUND_DESELECTED: 'COMPOUND_DESELECTED', - REPRESENTATION_CHANGED: 'REPRESENTATION_CHANGED' + REPRESENTATION_CHANGED: 'REPRESENTATION_CHANGED', + REPRESENTATION_ADDED: 'REPRESENTATION_ADDED', + REPRESENTATION_REMOVED: 'REPRESENTATION_REMOVED' +}; + +export const actionDescription = { + LOADED: 'was loaded', + TURNED_ON: 'was turned on', + TURNED_OFF: 'was turned off', + SELECTED: 'was selected', + DESELECTED: 'was deselected', + ADDED: 'was added', + REMOVED: 'was removed', + CHANGED: 'was changed', + TO_SHOPPING_CART: 'to shopping cart', + FROM_SHOPPING_CART: 'from shopping cart' }; export const objectType = { diff --git a/js/reducers/tracking/trackingActions.js b/js/reducers/tracking/trackingActions.js index 724ce8ee4..4328d183e 100644 --- a/js/reducers/tracking/trackingActions.js +++ b/js/reducers/tracking/trackingActions.js @@ -1,4 +1,4 @@ -import { actionType, objectType } from './constants'; +import { actionType, objectType, actionDescription } from './constants'; import { constants as apiConstants } from '../api/constants'; import { CONSTANTS as nglConstants } from '../ngl/constants'; import { constants as selectionConstants } from '../selection/constants'; @@ -17,7 +17,8 @@ export const findTruckAction = (action, state) => { username: username, object_type: objectType.TARGET, object_name: targetName, - object_id: action.target_on + object_id: action.target_on, + text: `${objectType.TARGET.toLowerCase()} ${targetName} ${actionDescription.LOADED}` }; } } else if (action.type.includes(apiConstants.SET_MOL_GROUP_ON)) { @@ -32,7 +33,8 @@ export const findTruckAction = (action, state) => { username: username, object_type: objectType.SITE, object_name: molGroupName, - object_id: action.mol_group_on + object_id: action.mol_group_on, + text: `${objectType.SITE.toLowerCase()} ${molGroupName} ${actionDescription.TURNED_ON}` }; } } @@ -46,7 +48,8 @@ export const findTruckAction = (action, state) => { username: username, object_type: objectType.SITE, object_name: molGroupName, - object_id: objectId + object_id: objectId, + text: `${objectType.SITE.toLowerCase()} ${molGroupName} ${actionDescription.TURNED_OFF}` }; } } else if (action.type.includes(selectionConstants.APPEND_FRAGMENT_DISPLAY_LIST)) { @@ -57,18 +60,21 @@ export const findTruckAction = (action, state) => { username: username, object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, object_name: action.item.name, - object_id: action.item.id + object_id: action.item.id, + text: `Ligand ${actionDescription.TURNED_ON} for ${action.object_type.toLowerCase()} ${action.object_name}` }; } } else if (action.type.includes(selectionConstants.REMOVE_FROM_FRAGMENT_DISPLAY_LIST)) { if (action.item) { + let objectType = action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE; truckAction = { type: actionType.LIGAND_TURNED_OFF, timestamp: Date.now(), username: username, - object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, + object_type: objectType, object_name: action.item.name, - object_id: action.item.id + object_id: action.item.id, + text: `Ligand ${actionDescription.TURNED_OFF} for ${action.object_type.toLowerCase()} ${action.object_name}` }; } } else if (action.type.includes(selectionConstants.APPEND_PROTEIN_LIST)) { @@ -79,7 +85,8 @@ export const findTruckAction = (action, state) => { username: username, object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, object_name: action.item.name, - object_id: action.item.id + object_id: action.item.id, + text: `Protein ${actionDescription.TURNED_ON} for ${action.object_type.toLowerCase()} ${action.object_name}` }; } } else if (action.type.includes(selectionConstants.REMOVE_FROM_PROTEIN_LIST)) { @@ -90,7 +97,8 @@ export const findTruckAction = (action, state) => { username: username, object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, object_name: action.item.name, - object_id: action.item.id + object_id: action.item.id, + text: `Protein ${actionDescription.TURNED_OFF} for ${action.object_type.toLowerCase()} ${action.object_name}` }; } } else if (action.type.includes(selectionConstants.APPEND_COMPLEX_LIST)) { @@ -101,7 +109,8 @@ export const findTruckAction = (action, state) => { username: username, object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, object_name: action.item.name, - object_id: action.item.id + object_id: action.item.id, + text: `Complex ${actionDescription.TURNED_ON} for ${action.object_type.toLowerCase()} ${action.object_name}` }; } } else if (action.type.includes(selectionConstants.REMOVE_FROM_COMPLEX_LIST)) { @@ -112,7 +121,8 @@ export const findTruckAction = (action, state) => { username: username, object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, object_name: action.item.name, - object_id: action.item.id + object_id: action.item.id, + text: `Complex ${actionDescription.TURNED_OFF} for ${action.object_type.toLowerCase()} ${action.object_name}` }; } } else if (action.type.includes(selectionConstants.APPEND_SURFACE_LIST)) { @@ -123,7 +133,8 @@ export const findTruckAction = (action, state) => { username: username, object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, object_name: action.item.name, - object_id: action.item.id + object_id: action.item.id, + text: `Surface ${actionDescription.TURNED_OFF} for ${action.object_type.toLowerCase()} ${action.object_name}` }; } } else if (action.type.includes(selectionConstants.REMOVE_FROM_SURFACE_LIST)) { @@ -134,7 +145,8 @@ export const findTruckAction = (action, state) => { username: username, object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, object_name: action.item.name, - object_id: action.item.id + object_id: action.item.id, + text: `Surface ${actionDescription.TURNED_OFF} for ${action.object_type.toLowerCase()} ${action.object_name}` }; } } else if (action.type.includes(selectionConstants.APPEND_VECTOR_ON_LIST)) { @@ -145,7 +157,8 @@ export const findTruckAction = (action, state) => { username: username, object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, object_name: action.item.name, - object_id: action.item.id + object_id: action.item.id, + text: `Vector ${actionDescription.TURNED_ON} for ${action.object_type.toLowerCase()} ${action.object_name}` }; } } else if (action.type.includes(selectionConstants.REMOVE_FROM_VECTOR_ON_LIST)) { @@ -156,7 +169,8 @@ export const findTruckAction = (action, state) => { username: username, object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, object_name: action.item.name, - object_id: action.item.id + object_id: action.item.id, + text: `Vector ${actionDescription.TURNED_OFF} for ${action.object_type.toLowerCase()} ${action.object_name}` }; } } else if (action.type.includes(selectionConstants.APPEND_TO_BUY_LIST)) { @@ -169,6 +183,9 @@ export const findTruckAction = (action, state) => { object_name: action.item.name, object_id: action.item.id }; + truckAction.text = `${truckAction.object_type.toLowerCase()} ${truckAction.object_name} ${ + actionDescription.ADDED + } ${actionDescription.TO_SHOPPING_CART}`; } } else if (action.type.includes(selectionConstants.REMOVE_FROM_TO_BUY_LIST)) { if (action.item) { @@ -180,6 +197,9 @@ export const findTruckAction = (action, state) => { object_name: action.item.name, object_id: action.item.id }; + truckAction.text = `${truckAction.object_type.toLowerCase()} ${truckAction.object_name} ${ + actionDescription.REMOVED + } ${actionDescription.FROM_SHOPPING_CART}`; } } else if (action.type.includes(selectionConstants.SET_CURRENT_VECTOR)) { truckAction = { @@ -188,7 +208,8 @@ export const findTruckAction = (action, state) => { username: username, object_type: objectType.MOLECULE, object_name: action.payload, - object_id: action.payload + object_id: action.payload, + text: `Vector ${actionDescription.SELECTED} for ${action.object_type.toLowerCase()} ${action.object_name}` }; } else if (action.type.includes(customDatasetConstants.APPEND_MOLECULE_TO_COMPOUNDS_TO_BUY_OF_DATASET)) { if (action.payload) { @@ -199,7 +220,10 @@ export const findTruckAction = (action, state) => { object_type: objectType.COMPOUND, object_name: action.payload.moleculeTitle, object_id: action.payload.moleculeID, - dataset_id: action.payload.datasetID + dataset_id: action.payload.datasetID, + text: `${action.object_type.toLowerCase()} ${action.object_name} ${actionDescription.SELECTED} of dataset: ${ + action.payload.datasetID + }` }; } } else if (action.type.includes(customDatasetConstants.REMOVE_MOLECULE_FROM_COMPOUNDS_TO_BUY_OF_DATASET)) { @@ -211,7 +235,10 @@ export const findTruckAction = (action, state) => { object_type: objectType.COMPOUND, object_name: action.payload.moleculeTitle, object_id: action.payload.moleculeID, - dataset_id: action.payload.datasetID + dataset_id: action.payload.datasetID, + text: `${action.object_type.toLowerCase()} ${action.object_name} ${actionDescription.DESELECTED} of dataset: ${ + action.payload.datasetID + }` }; } } else if (action.type.includes(customDatasetConstants.APPEND_LIGAND_LIST)) { @@ -223,7 +250,10 @@ export const findTruckAction = (action, state) => { object_type: action.payload.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, object_name: action.payload.item.name, object_id: action.payload.item.id, - dataset_id: action.payload.datasetID + dataset_id: action.payload.datasetID, + text: `Ligand ${actionDescription.TURNED_ON} for ${action.object_type.toLowerCase()} ${ + action.object_name + } of dataset: ${action.payload.datasetID}` }; } } else if (action.type.includes(customDatasetConstants.REMOVE_FROM_LIGAND_LIST)) { @@ -235,7 +265,10 @@ export const findTruckAction = (action, state) => { object_type: action.payload.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, object_name: action.payload.item.name, object_id: action.payload.item.id, - dataset_id: action.payload.datasetID + dataset_id: action.payload.datasetID, + text: `Ligand ${actionDescription.TURNED_OF} for ${action.object_type.toLowerCase()} ${ + action.object_name + } of dataset: ${action.payload.datasetID}` }; } } else if (action.type.includes(customDatasetConstants.APPEND_PROTEIN_LIST)) { @@ -247,7 +280,10 @@ export const findTruckAction = (action, state) => { object_type: action.payload.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, object_name: action.payload.item.name, object_id: action.payload.item.id, - dataset_id: action.payload.datasetID + dataset_id: action.payload.datasetID, + text: `Protein ${actionDescription.TURNED_ON} for ${action.object_type.toLowerCase()} ${ + action.object_name + } of dataset: ${action.payload.datasetID}` }; } } else if (action.type.includes(customDatasetConstants.REMOVE_FROM_PROTEIN_LIST)) { @@ -259,7 +295,10 @@ export const findTruckAction = (action, state) => { object_type: action.payload.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, object_name: action.payload.item.name, object_id: action.payload.item.id, - dataset_id: action.payload.datasetID + dataset_id: action.payload.datasetID, + text: `Protein ${actionDescription.TURNED_OFF} for ${action.object_type.toLowerCase()} ${ + action.object_name + } of dataset: ${action.payload.datasetID}` }; } } else if (action.type.includes(customDatasetConstants.APPEND_COMPLEX_LIST)) { @@ -271,7 +310,10 @@ export const findTruckAction = (action, state) => { object_type: action.payload.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, object_name: action.payload.item.name, object_id: action.payload.item.id, - dataset_id: action.payload.datasetID + dataset_id: action.payload.datasetID, + text: `Complex ${actionDescription.TURNED_ON} for ${action.object_type.toLowerCase()} ${ + action.object_name + } of dataset: ${action.payload.datasetID}` }; } } else if (action.type.includes(customDatasetConstants.REMOVE_FROM_COMPLEX_LIST)) { @@ -283,20 +325,26 @@ export const findTruckAction = (action, state) => { object_type: action.payload.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, object_name: action.payload.item.name, object_id: action.payload.item.id, - dataset_id: action.payload.datasetID + dataset_id: action.payload.datasetID, + text: `Complex ${actionDescription.TURNED_OF} for ${action.object_type.toLowerCase()} ${ + action.object_name + } of dataset: ${action.payload.datasetID}` + }; + } + } else if (action.type.includes(customDatasetConstants.APPEND_SURFACE_LIST)) { + if (action.payload && action.payload.item) { + truckAction = { + type: actionType.SURFACE_TURNED_ON, + timestamp: Date.now(), + username: username, + object_type: action.payload.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, + object_name: action.payload.item.name, + object_id: action.payload.item.id, + dataset_id: action.payload.datasetID, + text: `Surface ${actionDescription.TURNED_ON} for ${action.object_type.toLowerCase()} ${ + action.object_name + } of dataset: ${action.payload.datasetID}` }; - } else if (action.type.includes(customDatasetConstants.APPEND_SURFACE_LIST)) { - if (action.payload && action.payload.item) { - truckAction = { - type: actionType.SURFACE_TURNED_ON, - timestamp: Date.now(), - username: username, - object_type: action.payload.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, - object_name: action.payload.item.name, - object_id: action.payload.item.id, - dataset_id: action.payload.datasetID - }; - } } } else if (action.type.includes(customDatasetConstants.REMOVE_FROM_SURFACE_LIST)) { if (action.payload && action.payload.item) { @@ -307,7 +355,10 @@ export const findTruckAction = (action, state) => { object_type: action.payload.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, object_name: action.payload.item.name, object_id: action.payload.item.id, - dataset_id: action.payload.datasetID + dataset_id: action.payload.datasetID, + text: `Surface ${actionDescription.TURNED_OFF} for ${action.object_type.toLowerCase()} ${ + action.object_name + } of dataset: ${action.payload.datasetID}` }; } } else if (action.type.includes(nglConstants.UPDATE_COMPONENT_REPRESENTATION)) { @@ -321,9 +372,12 @@ export const findTruckAction = (action, state) => { representation_id: action.representationID, new_representation: action.newRepresentation }; + truckAction.text = `${truckAction.object_type.toLowerCase()} of ${truckAction.object_name} ${ + actionDescription.CHANGED + }`; } else if (action.type.includes(nglConstants.ADD_COMPONENT_REPRESENTATION)) { truckAction = { - type: actionType.REPRESENTATION_CHANGED, + type: actionType.REPRESENTATION_ADDED, timestamp: Date.now(), username: username, object_type: objectType.REPRESENTATION, @@ -331,9 +385,12 @@ export const findTruckAction = (action, state) => { object_id: action.objectInViewID, new_representation: action.newRepresentation }; + truckAction.text = `${truckAction.object_type.toLowerCase()} of ${truckAction.object_name} ${ + actionDescription.ADDED + }`; } else if (action.type.includes(nglConstants.REMOVE_COMPONENT_REPRESENTATION)) { truckAction = { - type: actionType.REPRESENTATION_CHANGED, + type: actionType.REPRESENTATION_REMOVED, timestamp: Date.now(), username: username, object_type: objectType.REPRESENTATION, @@ -341,6 +398,9 @@ export const findTruckAction = (action, state) => { object_id: action.objectInViewID, representation_id: action.representationID }; + truckAction.text = `${truckAction.object_type.toLowerCase()} of ${truckAction.object_name} ${ + actionDescription.REMOVED + }`; } return truckAction; diff --git a/js/reducers/tracking/trackingMiddleware.js b/js/reducers/tracking/trackingMiddleware.js index f82542447..f40b3ff45 100644 --- a/js/reducers/tracking/trackingMiddleware.js +++ b/js/reducers/tracking/trackingMiddleware.js @@ -3,7 +3,7 @@ import { constants } from './constants'; import { findTruckAction } from './trackingActions'; const trackingMiddleware = ({ dispatch, getState }) => next => action => { - console.log(`Redux Log:`, action); + //console.log(`Redux Log:`, action); const state = getState(); if (!action.type.includes(constants.APPEND_ACTIONS_LIST)) { diff --git a/js/reducers/tracking/trackingModal/trackingModal.js b/js/reducers/tracking/trackingModal/trackingModal.js new file mode 100644 index 000000000..628ebda82 --- /dev/null +++ b/js/reducers/tracking/trackingModal/trackingModal.js @@ -0,0 +1,41 @@ +import React, { memo } from 'react'; +import { useSelector } from 'react-redux'; +import Modal from '../../../components/common/Modal'; +import { makeStyles, Typography } from '@material-ui/core'; +import { Timeline, TimelineEvent } from 'react-event-timeline'; +import { Check } from '@material-ui/icons'; + +const useStyles = makeStyles(theme => ({ + customModal: { + width: '90%', + height: '90%', + backgroundColor: '#ffffff', + overflow: scroll + } +})); + +export const TrackingModal = memo(({ openModal, onModalClose }) => { + const classes = useStyles(); + const actionList = useSelector(state => state.trackingReducers.truck_actions_list); + + if (openModal === undefined) { + console.log('undefined openModal'); + onModalClose(); + } + + return ( + onModalClose()}> + Action list + + {actionList.map((data, index) => ( + } + > + ))} + + + ); +}); diff --git a/js/reducers/tracking/trackingReducers.js b/js/reducers/tracking/trackingReducers.js index a8f7d4590..844023ccd 100644 --- a/js/reducers/tracking/trackingReducers.js +++ b/js/reducers/tracking/trackingReducers.js @@ -2,6 +2,7 @@ import { constants } from './constants'; export const INITIAL_STATE = { truck_actions_list: [] + // isTrackingModalOpen: false }; export default function trackingReducers(state = INITIAL_STATE, action = {}) { @@ -15,6 +16,9 @@ export default function trackingReducers(state = INITIAL_STATE, action = {}) { return Object.assign({}, state, { truck_actions_list: [...new Set([...state.truck_actions_list, action.truck_action])] }); + // case constants.SET_TRACKING_MODAL_OPEN: + // return Object.assign({}, state, { isTrackingModalOpen: action.payload }); + default: return state; } diff --git a/package.json b/package.json index e987b5964..3992ffb10 100755 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ "react-canvas-draw": "^1.1.0", "react-color": "^2.17.3", "react-dom": "^16.12.0", + "react-event-timeline": "^1.6.3", "react-hot-loader": "^4.12.18", "react-infinite-scroller": "^1.2.4", "react-redux": "^7.1.3", @@ -138,4 +139,4 @@ "git add" ] } -} \ No newline at end of file +} From 5cd88816e27edf60f6c5c29a07d83dceb1d901d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1na=20Kohanov=C3=A1?= Date: Thu, 29 Oct 2020 11:03:02 +0100 Subject: [PATCH 04/35] #430 Visualize users action history --- js/components/header/index.js | 2 +- .../tracking}/trackingModal.js | 14 +- js/reducers/tracking/actions.js | 5 - js/reducers/tracking/constants.js | 14 +- js/reducers/tracking/trackingActions.js | 307 +++++++++++------- js/reducers/tracking/trackingReducers.js | 3 - 6 files changed, 205 insertions(+), 140 deletions(-) rename js/{reducers/tracking/trackingModal => components/tracking}/trackingModal.js (77%) diff --git a/js/components/header/index.js b/js/components/header/index.js index 1db7582c9..30ea8e58b 100644 --- a/js/components/header/index.js +++ b/js/components/header/index.js @@ -40,7 +40,7 @@ import { useHistory } from 'react-router-dom'; import { IssueReport } from '../userFeedback/issueReport'; import { IdeaReport } from '../userFeedback/ideaReport'; import { FundersModal } from '../funders/fundersModal'; -import { TrackingModal } from '../../reducers/tracking/trackingModal/trackingModal'; +import { TrackingModal } from '../tracking/trackingModal'; // eslint-disable-next-line import/extensions import { version } from '../../../package.json'; diff --git a/js/reducers/tracking/trackingModal/trackingModal.js b/js/components/tracking/trackingModal.js similarity index 77% rename from js/reducers/tracking/trackingModal/trackingModal.js rename to js/components/tracking/trackingModal.js index 628ebda82..8797f887a 100644 --- a/js/reducers/tracking/trackingModal/trackingModal.js +++ b/js/components/tracking/trackingModal.js @@ -1,16 +1,20 @@ import React, { memo } from 'react'; import { useSelector } from 'react-redux'; -import Modal from '../../../components/common/Modal'; +import Modal from '../common/Modal'; import { makeStyles, Typography } from '@material-ui/core'; import { Timeline, TimelineEvent } from 'react-event-timeline'; import { Check } from '@material-ui/icons'; +import palette from '../../theme/palette'; const useStyles = makeStyles(theme => ({ customModal: { - width: '90%', + width: '70%', height: '90%', - backgroundColor: '#ffffff', - overflow: scroll + overflow: 'scroll' + }, + timelineEvent: { + borderBottom: '1px dashed ' + palette.divider, + paddingBottom: '10px' } })); @@ -33,6 +37,8 @@ export const TrackingModal = memo(({ openModal, onModalClose }) => { title={data.text} createdAt={new Date(data.timestamp).toLocaleString()} icon={} + iconColor={palette.primary.main} + className={classes.timelineEvent} > ))} diff --git a/js/reducers/tracking/actions.js b/js/reducers/tracking/actions.js index a524bc5f4..081ebb700 100644 --- a/js/reducers/tracking/actions.js +++ b/js/reducers/tracking/actions.js @@ -13,8 +13,3 @@ export const appendToActionList = function(truck_action) { truck_action: truck_action }; }; - -// export const setTrackingModalOpen = isOpen => ({ -// type: constants.SET_TRACKING_MODAL_OPEN, -// payload: isOpen -// }); diff --git a/js/reducers/tracking/constants.js b/js/reducers/tracking/constants.js index 014dfcd15..685411257 100644 --- a/js/reducers/tracking/constants.js +++ b/js/reducers/tracking/constants.js @@ -2,8 +2,7 @@ const prefix = 'REDUCERS_SELECTION_'; export const constants = { SET_ACTIONS_LIST: prefix + 'SET_ACTIONS_LIST', - APPEND_ACTIONS_LIST: prefix + 'APPEND_ACTIONS_LIST', - SET_TRACKING_MODAL_OPEN: prefix + 'SET_TRACKING_MODAL_OPEN' + APPEND_ACTIONS_LIST: prefix + 'APPEND_ACTIONS_LIST' }; export const actionType = { @@ -41,10 +40,17 @@ export const actionDescription = { REMOVED: 'was removed', CHANGED: 'was changed', TO_SHOPPING_CART: 'to shopping cart', - FROM_SHOPPING_CART: 'from shopping cart' + FROM_SHOPPING_CART: 'from shopping cart', + LIGAND: 'Ligand', + SIDECHAINS: 'Sidechain', + INTERACTIONS: 'Interaction', + VECTOR: 'Vector', + SURFACE: 'Surface', + SITE: 'Site', + TARGET: 'Target' }; -export const objectType = { +export const actionObjectType = { TARGET: 'TARGET', SITE: 'SITE', MOLECULE: 'MOLECULE', diff --git a/js/reducers/tracking/trackingActions.js b/js/reducers/tracking/trackingActions.js index 4328d183e..175f9a34f 100644 --- a/js/reducers/tracking/trackingActions.js +++ b/js/reducers/tracking/trackingActions.js @@ -1,4 +1,4 @@ -import { actionType, objectType, actionDescription } from './constants'; +import { actionType, actionObjectType, actionDescription } from './constants'; import { constants as apiConstants } from '../api/constants'; import { CONSTANTS as nglConstants } from '../ngl/constants'; import { constants as selectionConstants } from '../selection/constants'; @@ -15,10 +15,10 @@ export const findTruckAction = (action, state) => { type: actionType.TARGET_LOADED, timestamp: Date.now(), username: username, - object_type: objectType.TARGET, + object_type: actionObjectType.TARGET, object_name: targetName, object_id: action.target_on, - text: `${objectType.TARGET.toLowerCase()} ${targetName} ${actionDescription.LOADED}` + text: `${actionDescription.TARGET} ${targetName} ${actionDescription.LOADED}` }; } } else if (action.type.includes(apiConstants.SET_MOL_GROUP_ON)) { @@ -31,10 +31,10 @@ export const findTruckAction = (action, state) => { type: actionType.SITE_TURNED_ON, timestamp: Date.now(), username: username, - object_type: objectType.SITE, + object_type: actionObjectType.SITE, object_name: molGroupName, object_id: action.mol_group_on, - text: `${objectType.SITE.toLowerCase()} ${molGroupName} ${actionDescription.TURNED_ON}` + text: `${actionDescription.SITE} ${molGroupName} ${actionDescription.TURNED_ON}` }; } } @@ -46,361 +46,415 @@ export const findTruckAction = (action, state) => { type: actionType.SITE_TURNED_OFF, timestamp: Date.now(), username: username, - object_type: objectType.SITE, + object_type: actionObjectType.SITE, object_name: molGroupName, object_id: objectId, - text: `${objectType.SITE.toLowerCase()} ${molGroupName} ${actionDescription.TURNED_OFF}` + text: `${actionDescription.SITE} ${molGroupName} ${actionDescription.TURNED_OFF}` }; } } else if (action.type.includes(selectionConstants.APPEND_FRAGMENT_DISPLAY_LIST)) { if (action.item) { + let objectType = action.item.isInspiration === true ? actionObjectType.INSPIRATION : actionObjectType.MOLECULE; + let objectName = action.item.name || getMoleculeName(action.item.id, state); + truckAction = { type: actionType.LIGAND_TURNED_ON, timestamp: Date.now(), username: username, - object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, - object_name: action.item.name, + object_type: objectType, + object_name: objectName, object_id: action.item.id, - text: `Ligand ${actionDescription.TURNED_ON} for ${action.object_type.toLowerCase()} ${action.object_name}` + text: `${actionDescription.LIGAND} ${actionDescription.TURNED_ON} ${objectType} ${objectName}` }; } } else if (action.type.includes(selectionConstants.REMOVE_FROM_FRAGMENT_DISPLAY_LIST)) { if (action.item) { - let objectType = action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE; + let objectType = action.item.isInspiration === true ? actionObjectType.INSPIRATION : actionObjectType.MOLECULE; + let objectName = action.item.name || getMoleculeName(action.item.id, state); + truckAction = { type: actionType.LIGAND_TURNED_OFF, timestamp: Date.now(), username: username, object_type: objectType, - object_name: action.item.name, + object_name: objectName, object_id: action.item.id, - text: `Ligand ${actionDescription.TURNED_OFF} for ${action.object_type.toLowerCase()} ${action.object_name}` + text: `${actionDescription.LIGAND} ${actionDescription.TURNED_OFF} ${objectType} ${objectName}` }; } } else if (action.type.includes(selectionConstants.APPEND_PROTEIN_LIST)) { if (action.item) { + let objectType = action.item.isInspiration === true ? actionObjectType.INSPIRATION : actionObjectType.MOLECULE; + let objectName = action.item.name || getMoleculeName(action.item.id, state); + truckAction = { type: actionType.SIDECHAINS_TURNED_ON, timestamp: Date.now(), username: username, - object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, - object_name: action.item.name, + object_type: objectType, + object_name: objectName, object_id: action.item.id, - text: `Protein ${actionDescription.TURNED_ON} for ${action.object_type.toLowerCase()} ${action.object_name}` + text: `${actionDescription.SIDECHAINS} ${actionDescription.TURNED_ON} ${objectType} ${objectName}` }; } } else if (action.type.includes(selectionConstants.REMOVE_FROM_PROTEIN_LIST)) { if (action.item) { + let objectType = action.item.isInspiration === true ? actionObjectType.INSPIRATION : actionObjectType.MOLECULE; + let objectName = action.item.name || getMoleculeName(action.item.id, state); + truckAction = { type: actionType.SIDECHAINS_TURNED_OFF, timestamp: Date.now(), username: username, - object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, - object_name: action.item.name, + object_type: objectType, + object_name: objectName, object_id: action.item.id, - text: `Protein ${actionDescription.TURNED_OFF} for ${action.object_type.toLowerCase()} ${action.object_name}` + text: `${actionDescription.SIDECHAINS} ${actionDescription.TURNED_OFF} ${objectType} ${objectName}` }; } } else if (action.type.includes(selectionConstants.APPEND_COMPLEX_LIST)) { if (action.item) { + let objectType = action.item.isInspiration === true ? actionObjectType.INSPIRATION : actionObjectType.MOLECULE; + let objectName = action.item.name || getMoleculeName(action.item.id, state); + truckAction = { type: actionType.INTERACTIONS_TURNED_ON, timestamp: Date.now(), username: username, - object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, - object_name: action.item.name, + object_type: objectType, + object_name: objectName, object_id: action.item.id, - text: `Complex ${actionDescription.TURNED_ON} for ${action.object_type.toLowerCase()} ${action.object_name}` + text: `${actionDescription.INTERACTIONS} ${actionDescription.TURNED_ON} ${objectType} ${objectName}` }; } } else if (action.type.includes(selectionConstants.REMOVE_FROM_COMPLEX_LIST)) { if (action.item) { + let objectType = action.item.isInspiration === true ? actionObjectType.INSPIRATION : actionObjectType.MOLECULE; + let objectName = action.item.name || getMoleculeName(action.item.id, state); + truckAction = { type: actionType.INTERACTIONS_TURNED_OFF, timestamp: Date.now(), username: username, - object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, - object_name: action.item.name, + object_type: objectType, + object_name: objectName, object_id: action.item.id, - text: `Complex ${actionDescription.TURNED_OFF} for ${action.object_type.toLowerCase()} ${action.object_name}` + text: `${actionDescription.INTERACTIONS} ${actionDescription.TURNED_OFF} ${objectType} ${objectName}` }; } } else if (action.type.includes(selectionConstants.APPEND_SURFACE_LIST)) { if (action.item) { + let objectType = action.item.isInspiration === true ? actionObjectType.INSPIRATION : actionObjectType.MOLECULE; + let objectName = action.item.name || getMoleculeName(action.item.id, state); + truckAction = { type: actionType.SURFACE_TURNED_ON, timestamp: Date.now(), username: username, - object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, - object_name: action.item.name, + object_type: objectType, + object_name: objectName, object_id: action.item.id, - text: `Surface ${actionDescription.TURNED_OFF} for ${action.object_type.toLowerCase()} ${action.object_name}` + text: `${actionDescription.SURFACE} ${actionDescription.TURNED_OFF} ${objectType} ${objectName}` }; } } else if (action.type.includes(selectionConstants.REMOVE_FROM_SURFACE_LIST)) { if (action.item) { + let objectType = action.item.isInspiration === true ? actionObjectType.INSPIRATION : actionObjectType.MOLECULE; + let objectName = action.item.name || getMoleculeName(action.item.id, state); + truckAction = { type: actionType.SURFACE_TURNED_OFF, timestamp: Date.now(), username: username, - object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, - object_name: action.item.name, + object_type: objectType, + object_name: objectName, object_id: action.item.id, - text: `Surface ${actionDescription.TURNED_OFF} for ${action.object_type.toLowerCase()} ${action.object_name}` + text: `${actionDescription.SURFACE} ${actionDescription.TURNED_OFF} ${objectType} ${objectName}` }; } } else if (action.type.includes(selectionConstants.APPEND_VECTOR_ON_LIST)) { if (action.item) { + let objectType = action.item.isInspiration === true ? actionObjectType.INSPIRATION : actionObjectType.MOLECULE; + let objectName = action.item.name || getMoleculeName(action.item.id, state); + truckAction = { type: actionType.VECTORS_TURNED_ON, timestamp: Date.now(), username: username, - object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, - object_name: action.item.name, + object_type: objectType, + object_name: objectName, object_id: action.item.id, - text: `Vector ${actionDescription.TURNED_ON} for ${action.object_type.toLowerCase()} ${action.object_name}` + text: `${actionDescription.VECTOR} ${actionDescription.TURNED_ON} ${objectType} ${objectName}` }; } } else if (action.type.includes(selectionConstants.REMOVE_FROM_VECTOR_ON_LIST)) { if (action.item) { + let objectType = action.item.isInspiration === true ? actionObjectType.INSPIRATION : actionObjectType.MOLECULE; + let objectName = action.item.name || getMoleculeName(action.item.id, state); + truckAction = { type: actionType.VECTORS_TURNED_OFF, timestamp: Date.now(), username: username, - object_type: action.item.isInspiration === true ? objectType.INSPIRATION : objectType.MOLECULE, - object_name: action.item.name, + object_type: objectType, + object_name: objectName, object_id: action.item.id, - text: `Vector ${actionDescription.TURNED_OFF} for ${action.object_type.toLowerCase()} ${action.object_name}` + text: `${actionDescription.VECTOR} ${actionDescription.TURNED_OFF} ${objectType} ${objectName}` }; } } else if (action.type.includes(selectionConstants.APPEND_TO_BUY_LIST)) { if (action.item) { + let objectType = action.item.isInspiration === true ? actionObjectType.INSPIRATION : actionObjectType.MOLECULE; + let objectName = action.item.name || getMoleculeName(action.item.id, state); + truckAction = { type: actionType.MOLECULE_ADDED_TO_SHOPPING_CART, timestamp: Date.now(), username: username, - object_type: objectType.MOLECULE, - object_name: action.item.name, - object_id: action.item.id + object_type: actionObjectType.MOLECULE, + object_name: objectName, + object_id: action.item.id, + text: `${objectType} ${objectName} ${actionDescription.ADDED} ${actionDescription.TO_SHOPPING_CART}` }; - truckAction.text = `${truckAction.object_type.toLowerCase()} ${truckAction.object_name} ${ - actionDescription.ADDED - } ${actionDescription.TO_SHOPPING_CART}`; } } else if (action.type.includes(selectionConstants.REMOVE_FROM_TO_BUY_LIST)) { if (action.item) { + let objectType = actionObjectType.MOLECULE; + let objectName = action.item.name || getMoleculeName(action.item.id, state); + truckAction = { type: actionType.MOLECULE_REMOVED_FROM_SHOPPING_CART, timestamp: Date.now(), username: username, - object_type: objectType.MOLECULE, - object_name: action.item.name, - object_id: action.item.id + object_type: objectType, + object_name: objectName, + object_id: action.item.id, + text: `${objectType} ${objectName} ${actionDescription.REMOVED} ${actionDescription.FROM_SHOPPING_CART}` }; - truckAction.text = `${truckAction.object_type.toLowerCase()} ${truckAction.object_name} ${ - actionDescription.REMOVED - } ${actionDescription.FROM_SHOPPING_CART}`; } } else if (action.type.includes(selectionConstants.SET_CURRENT_VECTOR)) { - truckAction = { - type: actionType.VECTOR_SELECTED, - timestamp: Date.now(), - username: username, - object_type: objectType.MOLECULE, - object_name: action.payload, - object_id: action.payload, - text: `Vector ${actionDescription.SELECTED} for ${action.object_type.toLowerCase()} ${action.object_name}` - }; + if (action.payload) { + let objectType = actionObjectType.MOLECULE; + let objectName = action.payload; + + truckAction = { + type: actionType.VECTOR_SELECTED, + timestamp: Date.now(), + username: username, + object_type: objectType, + object_name: objectName, + object_id: action.payload, + text: `${actionDescription.VECTOR} ${objectName} ${actionDescription.SELECTED}` + }; + } } else if (action.type.includes(customDatasetConstants.APPEND_MOLECULE_TO_COMPOUNDS_TO_BUY_OF_DATASET)) { if (action.payload) { + let objectType = actionObjectType.COMPOUND; + let objectName = action.payload.moleculeTitle; + truckAction = { type: actionType.COMPOUND_SELECTED, timestamp: Date.now(), username: username, - object_type: objectType.COMPOUND, - object_name: action.payload.moleculeTitle, + object_type: objectType, + object_name: objectName, object_id: action.payload.moleculeID, dataset_id: action.payload.datasetID, - text: `${action.object_type.toLowerCase()} ${action.object_name} ${actionDescription.SELECTED} of dataset: ${ - action.payload.datasetID - }` + text: `${objectType} ${objectName} ${actionDescription.SELECTED} of dataset: ${action.payload.datasetID}` }; } } else if (action.type.includes(customDatasetConstants.REMOVE_MOLECULE_FROM_COMPOUNDS_TO_BUY_OF_DATASET)) { if (action.payload) { + let objectType = actionObjectType.COMPOUND; + let objectName = action.payload.moleculeTitle; + truckAction = { type: actionType.COMPOUND_DESELECTED, timestamp: Date.now(), username: username, - object_type: objectType.COMPOUND, - object_name: action.payload.moleculeTitle, + object_type: objectType, + object_name: objectName, object_id: action.payload.moleculeID, dataset_id: action.payload.datasetID, - text: `${action.object_type.toLowerCase()} ${action.object_name} ${actionDescription.DESELECTED} of dataset: ${ - action.payload.datasetID - }` + text: `${objectType} ${objectName} ${actionDescription.DESELECTED} of dataset: ${action.payload.datasetID}` }; } } else if (action.type.includes(customDatasetConstants.APPEND_LIGAND_LIST)) { if (action.payload && action.payload.item) { + let objectType = + action.payload.item.isCrossReference === true ? actionObjectType.CROSS_REFERENCE : actionObjectType.COMPOUND; + let objectName = action.payload.item.name; + truckAction = { type: actionType.LIGAND_TURNED_ON, timestamp: Date.now(), username: username, - object_type: action.payload.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, - object_name: action.payload.item.name, + object_type: objectType, + object_name: objectName, object_id: action.payload.item.id, dataset_id: action.payload.datasetID, - text: `Ligand ${actionDescription.TURNED_ON} for ${action.object_type.toLowerCase()} ${ - action.object_name - } of dataset: ${action.payload.datasetID}` + text: `${actionDescription.LIGAND} ${actionDescription.TURNED_ON} ${objectType} ${objectName} of dataset: ${action.payload.datasetID}` }; } } else if (action.type.includes(customDatasetConstants.REMOVE_FROM_LIGAND_LIST)) { if (action.payload && action.payload.item) { + let objectType = + action.payload.item.isCrossReference === true ? actionObjectType.CROSS_REFERENCE : actionObjectType.COMPOUND; + let objectName = action.payload.item.name; + truckAction = { type: actionType.LIGAND_TURNED_OFF, timestamp: Date.now(), username: username, - object_type: action.payload.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, - object_name: action.payload.item.name, + object_type: objectType, + object_name: objectName, object_id: action.payload.item.id, dataset_id: action.payload.datasetID, - text: `Ligand ${actionDescription.TURNED_OF} for ${action.object_type.toLowerCase()} ${ - action.object_name - } of dataset: ${action.payload.datasetID}` + text: `${actionDescription.LIGAND} ${actionDescription.TURNED_OFF} ${objectType} ${objectName} of dataset: ${action.payload.datasetID}` }; } } else if (action.type.includes(customDatasetConstants.APPEND_PROTEIN_LIST)) { if (action.payload && action.payload.item) { + let objectType = + action.payload.item.isCrossReference === true ? actionObjectType.CROSS_REFERENCE : actionObjectType.COMPOUND; + let objectName = action.payload.item.name; + truckAction = { type: actionType.SIDECHAINS_TURNED_ON, timestamp: Date.now(), username: username, - object_type: action.payload.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, - object_name: action.payload.item.name, + object_type: objectType, + object_name: objectName, object_id: action.payload.item.id, dataset_id: action.payload.datasetID, - text: `Protein ${actionDescription.TURNED_ON} for ${action.object_type.toLowerCase()} ${ - action.object_name - } of dataset: ${action.payload.datasetID}` + text: `${actionDescription.SIDECHAINS} ${actionDescription.TURNED_ON} ${objectType} ${objectName} of dataset: ${action.payload.datasetID}` }; } } else if (action.type.includes(customDatasetConstants.REMOVE_FROM_PROTEIN_LIST)) { if (action.payload && action.payload.item) { + let objectType = + action.payload.item.isCrossReference === true ? actionObjectType.CROSS_REFERENCE : actionObjectType.COMPOUND; + let objectName = action.payload.item.name; + truckAction = { type: actionType.SIDECHAINS_TURNED_OFF, timestamp: Date.now(), username: username, - object_type: action.payload.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, - object_name: action.payload.item.name, + object_type: objectType, + object_name: objectName, object_id: action.payload.item.id, dataset_id: action.payload.datasetID, - text: `Protein ${actionDescription.TURNED_OFF} for ${action.object_type.toLowerCase()} ${ - action.object_name - } of dataset: ${action.payload.datasetID}` + text: `${actionDescription.SIDECHAINS} ${actionDescription.TURNED_OFF} ${objectType} ${objectName} of dataset: ${action.payload.datasetID}` }; } } else if (action.type.includes(customDatasetConstants.APPEND_COMPLEX_LIST)) { if (action.payload && action.payload.item) { + let objectType = + action.payload.item.isCrossReference === true ? actionObjectType.CROSS_REFERENCE : actionObjectType.COMPOUND; + let objectName = action.payload.item.name; + truckAction = { type: actionType.INTERACTIONS_TURNED_ON, timestamp: Date.now(), username: username, - object_type: action.payload.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, - object_name: action.payload.item.name, + object_type: objectType, + object_name: objectName, object_id: action.payload.item.id, dataset_id: action.payload.datasetID, - text: `Complex ${actionDescription.TURNED_ON} for ${action.object_type.toLowerCase()} ${ - action.object_name - } of dataset: ${action.payload.datasetID}` + text: `${actionDescription.INTERACTIONS} ${actionDescription.TURNED_ON} ${objectType} ${objectName} of dataset: ${action.payload.datasetID}` }; } } else if (action.type.includes(customDatasetConstants.REMOVE_FROM_COMPLEX_LIST)) { if (action.payload && action.payload.item) { + let objectType = + action.payload.item.isCrossReference === true ? actionObjectType.CROSS_REFERENCE : actionObjectType.COMPOUND; + let objectName = action.payload.item.name; + truckAction = { type: actionType.INTERACTIONS_TURNED_OFF, timestamp: Date.now(), username: username, - object_type: action.payload.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, - object_name: action.payload.item.name, + object_type: objectType, + object_name: objectName, object_id: action.payload.item.id, dataset_id: action.payload.datasetID, - text: `Complex ${actionDescription.TURNED_OF} for ${action.object_type.toLowerCase()} ${ - action.object_name - } of dataset: ${action.payload.datasetID}` + text: `${actionDescription.INTERACTIONS} ${actionDescription.TURNED_OF} ${objectType} ${objectName} of dataset: ${action.payload.datasetID}` }; } } else if (action.type.includes(customDatasetConstants.APPEND_SURFACE_LIST)) { if (action.payload && action.payload.item) { + let objectType = + action.payload.item.isCrossReference === true ? actionObjectType.CROSS_REFERENCE : actionObjectType.COMPOUND; + let objectName = action.payload.item.name; + truckAction = { type: actionType.SURFACE_TURNED_ON, timestamp: Date.now(), username: username, - object_type: action.payload.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, - object_name: action.payload.item.name, + object_type: objectType, + object_name: objectName, object_id: action.payload.item.id, dataset_id: action.payload.datasetID, - text: `Surface ${actionDescription.TURNED_ON} for ${action.object_type.toLowerCase()} ${ - action.object_name - } of dataset: ${action.payload.datasetID}` + text: `${actionDescription.SURFACE} ${actionDescription.TURNED_ON} ${objectType} ${objectName} of dataset: ${action.payload.datasetID}` }; } } else if (action.type.includes(customDatasetConstants.REMOVE_FROM_SURFACE_LIST)) { if (action.payload && action.payload.item) { + let objectType = + action.payload.item.isCrossReference === true ? actionObjectType.CROSS_REFERENCE : actionObjectType.COMPOUND; + let objectName = action.payload.item.name; + truckAction = { type: actionType.SURFACE_TURNED_OFF, timestamp: Date.now(), username: username, - object_type: action.payload.item.isCrossReference === true ? objectType.CROSS_REFERENCE : objectType.COMPOUND, - object_name: action.payload.item.name, + object_type: objectType, + object_name: objectName, object_id: action.payload.item.id, dataset_id: action.payload.datasetID, - text: `Surface ${actionDescription.TURNED_OFF} for ${action.object_type.toLowerCase()} ${ - action.object_name - } of dataset: ${action.payload.datasetID}` + text: `${actionDescription.SURFACE} ${actionDescription.TURNED_OFF} ${objectType} ${objectName} of dataset: ${action.payload.datasetID}` }; } } else if (action.type.includes(nglConstants.UPDATE_COMPONENT_REPRESENTATION)) { + let objectType = actionObjectType.REPRESENTATION; + truckAction = { type: actionType.REPRESENTATION_CHANGED, timestamp: Date.now(), username: username, - object_type: objectType.REPRESENTATION, + object_type: actionObjectType.REPRESENTATION, object_name: action.objectInViewID, object_id: action.objectInViewID, representation_id: action.representationID, - new_representation: action.newRepresentation + new_representation: action.newRepresentation, + text: `${objectType} of ${action.objectInViewID} ${actionDescription.CHANGED}` }; - truckAction.text = `${truckAction.object_type.toLowerCase()} of ${truckAction.object_name} ${ - actionDescription.CHANGED - }`; } else if (action.type.includes(nglConstants.ADD_COMPONENT_REPRESENTATION)) { + let objectType = actionObjectType.REPRESENTATION; + truckAction = { type: actionType.REPRESENTATION_ADDED, timestamp: Date.now(), username: username, - object_type: objectType.REPRESENTATION, + object_type: actionObjectType.REPRESENTATION, object_name: action.objectInViewID, object_id: action.objectInViewID, - new_representation: action.newRepresentation + new_representation: action.newRepresentation, + text: `${objectType} of ${action.objectInViewID} ${actionDescription.ADDED}` }; - truckAction.text = `${truckAction.object_type.toLowerCase()} of ${truckAction.object_name} ${ - actionDescription.ADDED - }`; } else if (action.type.includes(nglConstants.REMOVE_COMPONENT_REPRESENTATION)) { + let objectType = actionObjectType.REPRESENTATION; + truckAction = { type: actionType.REPRESENTATION_REMOVED, timestamp: Date.now(), username: username, - object_type: objectType.REPRESENTATION, + object_type: objectType, object_name: action.objectInViewID, object_id: action.objectInViewID, - representation_id: action.representationID + representation_id: action.representationID, + text: `${objectType} of ${action.objectInViewID} ${actionDescription.REMOVED}` }; - truckAction.text = `${truckAction.object_type.toLowerCase()} of ${truckAction.object_name} ${ - actionDescription.REMOVED - }`; } return truckAction; @@ -419,3 +473,10 @@ const getTargetName = (targetId, state) => { let targetName = (target && target.title) || ''; return targetName; }; + +const getMoleculeName = (moleculeId, state) => { + let moleculeList = state.apiReducers.molecule_list; + let molecule = moleculeList.find(molecule => molecule.id === moleculeId); + let moleculeName = (molecule && molecule.protein_code) || ''; + return moleculeName; +}; diff --git a/js/reducers/tracking/trackingReducers.js b/js/reducers/tracking/trackingReducers.js index 844023ccd..7f7f49ca1 100644 --- a/js/reducers/tracking/trackingReducers.js +++ b/js/reducers/tracking/trackingReducers.js @@ -2,7 +2,6 @@ import { constants } from './constants'; export const INITIAL_STATE = { truck_actions_list: [] - // isTrackingModalOpen: false }; export default function trackingReducers(state = INITIAL_STATE, action = {}) { @@ -16,8 +15,6 @@ export default function trackingReducers(state = INITIAL_STATE, action = {}) { return Object.assign({}, state, { truck_actions_list: [...new Set([...state.truck_actions_list, action.truck_action])] }); - // case constants.SET_TRACKING_MODAL_OPEN: - // return Object.assign({}, state, { isTrackingModalOpen: action.payload }); default: return state; From bcee1f3a4584e2689e855f3ecf815a7753ab679c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1na=20Kohanov=C3=A1?= Date: Fri, 30 Oct 2020 09:15:19 +0100 Subject: [PATCH 05/35] #430 Visualize users action history --- js/components/common/Modal/index.js | 21 ++++++- js/components/common/Surfaces/Panel/index.js | 3 +- js/components/tracking/trackingModal.js | 64 ++++++++++++++------ 3 files changed, 66 insertions(+), 22 deletions(-) diff --git a/js/components/common/Modal/index.js b/js/components/common/Modal/index.js index 004fa7d7d..237b00452 100644 --- a/js/components/common/Modal/index.js +++ b/js/components/common/Modal/index.js @@ -24,7 +24,18 @@ const useStyles = makeStyles(theme => ({ })); export const Modal = memo( - ({ children, open, loading, onClose, noPadding, resizable, onResize, otherClasses, ...rest }) => { + ({ + children, + open, + loading, + onClose, + noPadding, + resizable, + onResize, + otherClasses, + otherContentClasses, + ...rest + }) => { const classes = useStyles(); const content = loading ? : children; @@ -48,7 +59,13 @@ export const Modal = memo( { [otherClasses]: !!otherClasses } )} > -
{content}
+
+ {content} +
); diff --git a/js/components/common/Surfaces/Panel/index.js b/js/components/common/Surfaces/Panel/index.js index 2c819e854..1191ee684 100644 --- a/js/components/common/Surfaces/Panel/index.js +++ b/js/components/common/Surfaces/Panel/index.js @@ -13,7 +13,8 @@ import ExpandLess from '@material-ui/icons/ExpandLess'; const useStyles = makeStyles(theme => ({ root: { - backgroundColor: theme.palette.background.paper + backgroundColor: theme.palette.background.paper, + height: '100%' }, body: { padding: theme.spacing(1) diff --git a/js/components/tracking/trackingModal.js b/js/components/tracking/trackingModal.js index 8797f887a..d26f364d5 100644 --- a/js/components/tracking/trackingModal.js +++ b/js/components/tracking/trackingModal.js @@ -1,21 +1,35 @@ import React, { memo } from 'react'; import { useSelector } from 'react-redux'; import Modal from '../common/Modal'; -import { makeStyles, Typography } from '@material-ui/core'; +import { Grid, makeStyles } from '@material-ui/core'; import { Timeline, TimelineEvent } from 'react-event-timeline'; -import { Check } from '@material-ui/icons'; +import { Check, Clear } from '@material-ui/icons'; import palette from '../../theme/palette'; +import { Panel } from '../common'; const useStyles = makeStyles(theme => ({ customModal: { width: '70%', - height: '90%', - overflow: 'scroll' + height: '90%' + }, + customContentModal: { + height: '100%' }, timelineEvent: { borderBottom: '1px dashed ' + palette.divider, paddingBottom: '10px' - } + }, + divContainer: { + height: '100%', + width: '100%', + paddingTop: theme.spacing(1) / 2 + }, + divScrollable: { + height: '100%', + width: '100%', + overflow: 'auto' + }, + containerExpanded: { height: '100%' } })); export const TrackingModal = memo(({ openModal, onModalClose }) => { @@ -28,20 +42,32 @@ export const TrackingModal = memo(({ openModal, onModalClose }) => { } return ( - onModalClose()}> - Action list - - {actionList.map((data, index) => ( - } - iconColor={palette.primary.main} - className={classes.timelineEvent} - > - ))} - + onModalClose()} + > + + +
+
+ + {actionList.map((data, index) => ( + : } + iconColor={palette.primary.main} + className={classes.timelineEvent} + > + ))} + +
+
+
+
); }); From aa1cbcf7e9017176e312ceeb1fe0d860fcd37c9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1na=20Kohanov=C3=A1?= Date: Fri, 30 Oct 2020 09:19:50 +0100 Subject: [PATCH 06/35] ave current state as a sequence of actions #428 --- js/reducers/tracking/actions.js | 7 +++++++ js/reducers/tracking/constants.js | 3 ++- js/reducers/tracking/dispatchActions.js | 18 ++++++++++++++++++ js/reducers/tracking/trackingReducers.js | 8 +++++++- 4 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 js/reducers/tracking/dispatchActions.js diff --git a/js/reducers/tracking/actions.js b/js/reducers/tracking/actions.js index 081ebb700..decfb1e3a 100644 --- a/js/reducers/tracking/actions.js +++ b/js/reducers/tracking/actions.js @@ -13,3 +13,10 @@ export const appendToActionList = function(truck_action) { truck_action: truck_action }; }; + +export const setCurrentActionsList = function(current_actions_list) { + return { + type: constants.SET_CURRENT_ACTIONS_LIST, + current_actions_list: current_actions_list + }; +}; diff --git a/js/reducers/tracking/constants.js b/js/reducers/tracking/constants.js index 685411257..7c2263692 100644 --- a/js/reducers/tracking/constants.js +++ b/js/reducers/tracking/constants.js @@ -2,7 +2,8 @@ const prefix = 'REDUCERS_SELECTION_'; export const constants = { SET_ACTIONS_LIST: prefix + 'SET_ACTIONS_LIST', - APPEND_ACTIONS_LIST: prefix + 'APPEND_ACTIONS_LIST' + APPEND_ACTIONS_LIST: prefix + 'APPEND_ACTIONS_LIST', + SET_CURRENT_ACTIONS_LIST: prefix + 'APPEND_ACTIONS_LIST' }; export const actionType = { diff --git a/js/reducers/tracking/dispatchActions.js b/js/reducers/tracking/dispatchActions.js new file mode 100644 index 000000000..dea65f1f0 --- /dev/null +++ b/js/reducers/tracking/dispatchActions.js @@ -0,0 +1,18 @@ +import { actionType, actionObjectType, actionDescription } from './constants'; + +export const selectCurrentActionsList = () => async (dispatch, getState) => { + const state = getState(); + + const actionList = state.trackingReducers.truck_actions_list; + + let currentActions = []; + let currentTargetList = actionList.map(function(action, index) { + if (action.type === actionType.TARGET_LOADED) { + return action; + } + }); + if (currentTargetList) { + let currentTarget = currentTargetList.pop(); + currentActions.push(Object.assign({ ...currentTarget })); + } +}; diff --git a/js/reducers/tracking/trackingReducers.js b/js/reducers/tracking/trackingReducers.js index 7f7f49ca1..a9e9e793b 100644 --- a/js/reducers/tracking/trackingReducers.js +++ b/js/reducers/tracking/trackingReducers.js @@ -1,7 +1,8 @@ import { constants } from './constants'; export const INITIAL_STATE = { - truck_actions_list: [] + truck_actions_list: [], + current_actions_list: [] }; export default function trackingReducers(state = INITIAL_STATE, action = {}) { @@ -16,6 +17,11 @@ export default function trackingReducers(state = INITIAL_STATE, action = {}) { truck_actions_list: [...new Set([...state.truck_actions_list, action.truck_action])] }); + case constants.SET_CURRENT_ACTIONS_LIST: + return Object.assign({}, state, { + current_actions_list: action.current_actions_list + }); + default: return state; } From db7f34639652d1556dda78074fc3967b795978c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1na=20Kohanov=C3=A1?= Date: Fri, 30 Oct 2020 09:20:26 +0100 Subject: [PATCH 07/35] #428 Save current state as a sequence of actions --- .vscode/launch.json | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 47adbadca..773c93a62 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,15 +1,23 @@ { - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "chrome", - "request": "launch", - "name": "Launch Chrome against localhost", - "url": "http://localhost:8080", - "webRoot": "${workspaceFolder}" - } - ] -} \ No newline at end of file + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Attach to Chrome", + "port": 9222, + "request": "attach", + "type": "pwa-chrome", + "urlFilter": "http://localhost:8080/*", + "webRoot": "${workspaceFolder}" + }, + { + "type": "chrome", + "request": "launch", + "name": "Launch Chrome against localhost", + "url": "http://localhost:8080", + "webRoot": "${workspaceFolder}" + } + ] +} From d4bec4c3093b1af6adda4aa2f58ff69de39c1e8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1na=20Kohanov=C3=A1?= Date: Fri, 30 Oct 2020 15:46:57 +0100 Subject: [PATCH 08/35] #428 Save current state as a sequence of actions --- js/reducers/tracking/dispatchActions.js | 99 ++++++++++++++++++++-- js/reducers/tracking/trackingMiddleware.js | 2 +- 2 files changed, 91 insertions(+), 10 deletions(-) diff --git a/js/reducers/tracking/dispatchActions.js b/js/reducers/tracking/dispatchActions.js index dea65f1f0..1dc42067c 100644 --- a/js/reducers/tracking/dispatchActions.js +++ b/js/reducers/tracking/dispatchActions.js @@ -1,18 +1,99 @@ -import { actionType, actionObjectType, actionDescription } from './constants'; +import { setCurrentActionsList } from './actions'; +import { actionType } from './constants'; -export const selectCurrentActionsList = () => async (dispatch, getState) => { +export const selectCurrentActionsList = () => (dispatch, getState) => { const state = getState(); const actionList = state.trackingReducers.truck_actions_list; + 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.complexLists; + const currentSurfaces = state.selectionReducers.surfaceList; + const currentVectors = state.selectionReducers.vectorOnList; + const currentBuyList = state.selectionReducers.to_buy_list; + const currentVector = state.selectionReducers.currentVector; + + const currentDatasetLigands = state.datasetsReducers.ligandLists; + const currentDatasetProteins = state.datasetsReducers.proteinList; + const currentDatasetComplexes = state.datasetsReducers.complexLists; + const currentDatasetSurfaces = state.datasetsReducers.surfaceLists; + const currentDatasets = state.datasetsReducers.datasets; + + const currentDatasetBuyList = state.datasetsReducers.compoundsToBuyDatasetMap; + + const orderedActionList = actionList.reverse((a, b) => a.timestamp - b.timestamp); + const currentTargets = (currentTargetOn && [currentTargetOn]) || []; + const currentVectorSmiles = (currentVector && [currentVector]) || []; let currentActions = []; - let currentTargetList = actionList.map(function(action, index) { - if (action.type === actionType.TARGET_LOADED) { - return action; - } + + getCurrentActionList(orderedActionList, actionType.TARGET_LOADED, currentTargets, currentActions); + + getCurrentActionList(orderedActionList, actionType.SITE_TURNED_ON, currentSites, currentActions); + getCurrentActionList(orderedActionList, actionType.LIGAND_TURNED_ON, currentLigands, currentActions); + getCurrentActionList(orderedActionList, actionType.SIDECHAINS_TURNED_ON, currentProteins, currentActions); + getCurrentActionList(orderedActionList, actionType.INTERACTIONS_TURNED_ON, currentComplexes, currentActions); + getCurrentActionList(orderedActionList, actionType.SURFACE_TURNED_ON, currentSurfaces, currentActions); + getCurrentActionList(orderedActionList, actionType.VECTORS_TURNED_ON, currentVectors, currentActions); + + getCurrentActionList( + orderedActionList, + actionType.LIGAND_TURNED_ON, + getCollectionOfDataset(currentDatasets, currentDatasetLigands), + currentActions + ); + getCurrentActionList( + orderedActionList, + actionType.SIDECHAINS_TURNED_ON, + getCollectionOfDataset(currentDatasets, currentDatasetProteins), + currentActions + ); + getCurrentActionList( + orderedActionList, + actionType.INTERACTIONS_TURNED_ON, + getCollectionOfDataset(currentDatasets, currentDatasetComplexes), + + currentActions + ); + getCurrentActionList( + orderedActionList, + actionType.SURFACE_TURNED_ON, + getCollectionOfDataset(currentDatasets, currentDatasetSurfaces), + currentActions + ); + + dispatch(setCurrentActionsList(currentActions)); +}; + +const getCurrentActionList = (orderedActionList, actionType, collection, currentActions) => { + let actionList = orderedActionList.filter(action => action.type === actionType); + if (collection) { + collection.forEach(data => { + let action = actionList.find(action => action.object_id === data); + + if (action) { + currentActions.push(Object.assign(mapCurrentAction(action))); + } + }); + } +}; + +const mapCurrentAction = action => { + return Object.assign({ + timestamp: action.timestamp, + object_name: action.object_name, + object_type: action.object_type, + action_type: action.type }); - if (currentTargetList) { - let currentTarget = currentTargetList.pop(); - currentActions.push(Object.assign({ ...currentTarget })); +}; + +const getCollectionOfDataset = (currentDatasets, dataList) => { + let list = []; + if (currentDatasets && dataList) { + currentDatasets.forEach(data => list.push(dataList[data.id])); } + + return list; }; diff --git a/js/reducers/tracking/trackingMiddleware.js b/js/reducers/tracking/trackingMiddleware.js index f40b3ff45..f284a210b 100644 --- a/js/reducers/tracking/trackingMiddleware.js +++ b/js/reducers/tracking/trackingMiddleware.js @@ -8,7 +8,7 @@ const trackingMiddleware = ({ dispatch, getState }) => next => action => { const state = getState(); if (!action.type.includes(constants.APPEND_ACTIONS_LIST)) { let truckAction = findTruckAction(action, state); - if (truckAction != null) { + if (truckAction && truckAction != null) { dispatch(appendToActionList(truckAction)); } } From ffb84ce53e168524fa681de087926d53a05fd719 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1na=20Kohanov=C3=A1?= Date: Mon, 2 Nov 2020 10:54:46 +0100 Subject: [PATCH 09/35] #428 Save current state as a sequence of actions --- js/reducers/tracking/constants.js | 4 +-- js/reducers/tracking/dispatchActions.js | 37 +++++++++++++++++++++++-- js/reducers/tracking/trackingActions.js | 10 +++---- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/js/reducers/tracking/constants.js b/js/reducers/tracking/constants.js index 7c2263692..18b77abef 100644 --- a/js/reducers/tracking/constants.js +++ b/js/reducers/tracking/constants.js @@ -1,9 +1,9 @@ -const prefix = 'REDUCERS_SELECTION_'; +const prefix = 'REDUCERS_TRACKING_'; export const constants = { SET_ACTIONS_LIST: prefix + 'SET_ACTIONS_LIST', APPEND_ACTIONS_LIST: prefix + 'APPEND_ACTIONS_LIST', - SET_CURRENT_ACTIONS_LIST: prefix + 'APPEND_ACTIONS_LIST' + SET_CURRENT_ACTIONS_LIST: prefix + 'SET_CURRENT_ACTIONS_LIST' }; export const actionType = { diff --git a/js/reducers/tracking/dispatchActions.js b/js/reducers/tracking/dispatchActions.js index 1dc42067c..8b6b2bbaa 100644 --- a/js/reducers/tracking/dispatchActions.js +++ b/js/reducers/tracking/dispatchActions.js @@ -30,13 +30,20 @@ export const selectCurrentActionsList = () => (dispatch, getState) => { let currentActions = []; getCurrentActionList(orderedActionList, actionType.TARGET_LOADED, currentTargets, currentActions); - getCurrentActionList(orderedActionList, actionType.SITE_TURNED_ON, currentSites, currentActions); getCurrentActionList(orderedActionList, actionType.LIGAND_TURNED_ON, currentLigands, currentActions); getCurrentActionList(orderedActionList, actionType.SIDECHAINS_TURNED_ON, currentProteins, currentActions); getCurrentActionList(orderedActionList, actionType.INTERACTIONS_TURNED_ON, currentComplexes, currentActions); getCurrentActionList(orderedActionList, actionType.SURFACE_TURNED_ON, currentSurfaces, currentActions); getCurrentActionList(orderedActionList, actionType.VECTORS_TURNED_ON, currentVectors, currentActions); + getCurrentActionList(orderedActionList, actionType.VECTOR_SELECTED, currentVectorSmiles, currentActions); + + getCurrentActionList( + orderedActionList, + actionType.MOLECULE_ADDED_TO_SHOPPING_CART, + getCollectionOfShoppingCart(currentBuyList), + currentActions + ); getCurrentActionList( orderedActionList, @@ -64,6 +71,13 @@ export const selectCurrentActionsList = () => (dispatch, getState) => { currentActions ); + getCurrentActionList( + orderedActionList, + actionType.COMPOUND_SELECTED, + getCollectionOfDataset(currentDatasets, currentDatasetBuyList), + currentActions + ); + dispatch(setCurrentActionsList(currentActions)); }; @@ -92,7 +106,26 @@ const mapCurrentAction = action => { const getCollectionOfDataset = (currentDatasets, dataList) => { let list = []; if (currentDatasets && dataList) { - currentDatasets.forEach(data => list.push(dataList[data.id])); + currentDatasets.forEach(data => { + let dataValues = dataList[data.id]; + if (dataValues) { + list.push(...dataValues); + } + }); + } + + return list; +}; + +const getCollectionOfShoppingCart = dataList => { + let list = []; + if (dataList) { + dataList.forEach(data => { + let dataValue = data.vector; + if (dataValue) { + list.push(dataValue); + } + }); } return list; diff --git a/js/reducers/tracking/trackingActions.js b/js/reducers/tracking/trackingActions.js index 175f9a34f..7d0eb3ac2 100644 --- a/js/reducers/tracking/trackingActions.js +++ b/js/reducers/tracking/trackingActions.js @@ -204,8 +204,8 @@ export const findTruckAction = (action, state) => { } } else if (action.type.includes(selectionConstants.APPEND_TO_BUY_LIST)) { if (action.item) { - let objectType = action.item.isInspiration === true ? actionObjectType.INSPIRATION : actionObjectType.MOLECULE; - let objectName = action.item.name || getMoleculeName(action.item.id, state); + let objectType = actionObjectType.MOLECULE; + let objectName = action.vector; truckAction = { type: actionType.MOLECULE_ADDED_TO_SHOPPING_CART, @@ -213,14 +213,14 @@ export const findTruckAction = (action, state) => { username: username, object_type: actionObjectType.MOLECULE, object_name: objectName, - object_id: action.item.id, + object_id: objectName, text: `${objectType} ${objectName} ${actionDescription.ADDED} ${actionDescription.TO_SHOPPING_CART}` }; } } else if (action.type.includes(selectionConstants.REMOVE_FROM_TO_BUY_LIST)) { if (action.item) { let objectType = actionObjectType.MOLECULE; - let objectName = action.item.name || getMoleculeName(action.item.id, state); + let objectName = action.vector; truckAction = { type: actionType.MOLECULE_REMOVED_FROM_SHOPPING_CART, @@ -228,7 +228,7 @@ export const findTruckAction = (action, state) => { username: username, object_type: objectType, object_name: objectName, - object_id: action.item.id, + object_id: objectName, text: `${objectType} ${objectName} ${actionDescription.REMOVED} ${actionDescription.FROM_SHOPPING_CART}` }; } From a8d590829d59c10fcecd248de86bb33b2f1e1a59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1na=20Kohanov=C3=A1?= Date: Mon, 2 Nov 2020 13:41:35 +0100 Subject: [PATCH 10/35] #428 Save current state as a sequence of actions --- js/reducers/tracking/dispatchActions.js | 109 ++++++++++++++++++------ 1 file changed, 81 insertions(+), 28 deletions(-) diff --git a/js/reducers/tracking/dispatchActions.js b/js/reducers/tracking/dispatchActions.js index 8b6b2bbaa..ae62942f7 100644 --- a/js/reducers/tracking/dispatchActions.js +++ b/js/reducers/tracking/dispatchActions.js @@ -1,5 +1,6 @@ import { setCurrentActionsList } from './actions'; import { actionType } from './constants'; +import { VIEWS } from '../../../js/constants/constants'; export const selectCurrentActionsList = () => (dispatch, getState) => { const state = getState(); @@ -19,9 +20,9 @@ export const selectCurrentActionsList = () => (dispatch, getState) => { const currentDatasetProteins = state.datasetsReducers.proteinList; const currentDatasetComplexes = state.datasetsReducers.complexLists; const currentDatasetSurfaces = state.datasetsReducers.surfaceLists; - const currentDatasets = state.datasetsReducers.datasets; const currentDatasetBuyList = state.datasetsReducers.compoundsToBuyDatasetMap; + const currentobjectsInView = state.nglReducers.objectsInView; const orderedActionList = actionList.reverse((a, b) => a.timestamp - b.timestamp); const currentTargets = (currentTargetOn && [currentTargetOn]) || []; @@ -29,14 +30,29 @@ export const selectCurrentActionsList = () => (dispatch, getState) => { let currentActions = []; - getCurrentActionList(orderedActionList, actionType.TARGET_LOADED, currentTargets, currentActions); - getCurrentActionList(orderedActionList, actionType.SITE_TURNED_ON, currentSites, currentActions); - getCurrentActionList(orderedActionList, actionType.LIGAND_TURNED_ON, currentLigands, currentActions); - getCurrentActionList(orderedActionList, actionType.SIDECHAINS_TURNED_ON, currentProteins, currentActions); - getCurrentActionList(orderedActionList, actionType.INTERACTIONS_TURNED_ON, currentComplexes, currentActions); - getCurrentActionList(orderedActionList, actionType.SURFACE_TURNED_ON, currentSurfaces, currentActions); - getCurrentActionList(orderedActionList, actionType.VECTORS_TURNED_ON, currentVectors, currentActions); - getCurrentActionList(orderedActionList, actionType.VECTOR_SELECTED, currentVectorSmiles, 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); + getCurrentActionList( + orderedActionList, + actionType.SIDECHAINS_TURNED_ON, + getCollection(currentProteins), + currentActions + ); + getCurrentActionList( + orderedActionList, + actionType.INTERACTIONS_TURNED_ON, + getCollection(currentComplexes), + currentActions + ); + getCurrentActionList(orderedActionList, actionType.SURFACE_TURNED_ON, getCollection(currentSurfaces), currentActions); + getCurrentActionList(orderedActionList, actionType.VECTORS_TURNED_ON, getCollection(currentVectors), currentActions); + getCurrentActionList( + orderedActionList, + actionType.VECTOR_SELECTED, + getCollection(currentVectorSmiles), + currentActions + ); getCurrentActionList( orderedActionList, @@ -48,44 +64,59 @@ export const selectCurrentActionsList = () => (dispatch, getState) => { getCurrentActionList( orderedActionList, actionType.LIGAND_TURNED_ON, - getCollectionOfDataset(currentDatasets, currentDatasetLigands), + getCollectionOfDataset(currentDatasetLigands), currentActions ); getCurrentActionList( orderedActionList, actionType.SIDECHAINS_TURNED_ON, - getCollectionOfDataset(currentDatasets, currentDatasetProteins), + getCollectionOfDataset(currentDatasetProteins), currentActions ); getCurrentActionList( orderedActionList, actionType.INTERACTIONS_TURNED_ON, - getCollectionOfDataset(currentDatasets, currentDatasetComplexes), + getCollectionOfDataset(currentDatasetComplexes), currentActions ); getCurrentActionList( orderedActionList, actionType.SURFACE_TURNED_ON, - getCollectionOfDataset(currentDatasets, currentDatasetSurfaces), + getCollectionOfDataset(currentDatasetSurfaces), currentActions ); getCurrentActionList( orderedActionList, actionType.COMPOUND_SELECTED, - getCollectionOfDataset(currentDatasets, currentDatasetBuyList), + getCollectionOfDataset(currentDatasetBuyList), + currentActions + ); + + getCurrentActionList( + orderedActionList, + actionType.REPRESENTATION_CHANGED, + getCollectionOfDatasetOfRepresentation(currentobjectsInView), currentActions ); dispatch(setCurrentActionsList(currentActions)); }; -const getCurrentActionList = (orderedActionList, actionType, collection, currentActions) => { - let actionList = orderedActionList.filter(action => action.type === actionType); +const getCurrentActionList = (orderedActionList, type, collection, currentActions) => { + let actionList = + type !== actionType.REPRESENTATION_CHANGED + ? orderedActionList.filter(action => action.type === type) + : orderedActionList.filter( + action => + action.type === actionType.REPRESENTATION_ADDED || + action.type === actionType.REPRESENTATION_REMOVED || + action.type === actionType.REPRESENTATION_CHANGED + ); if (collection) { collection.forEach(data => { - let action = actionList.find(action => action.object_id === data); + let action = actionList.find(action => action.object_id === data.id && action.dataset_id === data.datasetId); if (action) { currentActions.push(Object.assign(mapCurrentAction(action))); @@ -103,17 +134,26 @@ const mapCurrentAction = action => { }); }; -const getCollectionOfDataset = (currentDatasets, dataList) => { +const getCollection = dataList => { let list = []; - if (currentDatasets && dataList) { - currentDatasets.forEach(data => { - let dataValues = dataList[data.id]; - if (dataValues) { - list.push(...dataValues); - } - }); + if (dataList) { + var result = dataList.map(value => ({ id: value })); + list.push(...result); } + return list; +}; +const getCollectionOfDataset = dataList => { + let list = []; + if (dataList) { + for (const datasetId in dataList) { + let values = dataList[datasetId]; + if (values) { + var result = values.map(value => ({ id: value, datasetId: datasetId })); + list.push(...result); + } + } + } return list; }; @@ -121,12 +161,25 @@ const getCollectionOfShoppingCart = dataList => { let list = []; if (dataList) { dataList.forEach(data => { - let dataValue = data.vector; - if (dataValue) { - list.push(dataValue); + let value = data.vector; + if (value) { + list.push({ id: value }); } }); } + return list; +}; +const getCollectionOfDatasetOfRepresentation = dataList => { + let list = []; + for (const view in dataList) { + let objectView = dataList[view]; + if (objectView && objectView !== null && objectView.display_div === VIEWS.MAJOR_VIEW) { + let value = dataList[view].name; + if (value) { + list.push({ id: value }); + } + } + } return list; }; From d90cac8daf7967128d217453863f0072b8ef1dff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1na=20Kohanov=C3=A1?= Date: Tue, 3 Nov 2020 09:25:14 +0100 Subject: [PATCH 11/35] #430 Visualize users action history --- js/components/tracking/trackingModal.js | 30 ++++++++++++++++--------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/js/components/tracking/trackingModal.js b/js/components/tracking/trackingModal.js index d26f364d5..24d78e6fb 100644 --- a/js/components/tracking/trackingModal.js +++ b/js/components/tracking/trackingModal.js @@ -35,6 +35,7 @@ const useStyles = makeStyles(theme => ({ export const TrackingModal = memo(({ openModal, onModalClose }) => { const classes = useStyles(); const actionList = useSelector(state => state.trackingReducers.truck_actions_list); + const orderedActionList = actionList.sort((a, b) => a.timestamp - b.timestamp); if (openModal === undefined) { console.log('undefined openModal'); @@ -53,16 +54,25 @@ export const TrackingModal = memo(({ openModal, onModalClose }) => {
- {actionList.map((data, index) => ( - : } - iconColor={palette.primary.main} - className={classes.timelineEvent} - > - ))} + {orderedActionList && + orderedActionList.map((data, index) => ( + + ) : ( + + ) + } + iconColor={palette.primary.main} + className={classes.timelineEvent} + > + ))}
From e7ed359c268a9994e7eb2ab420bf150619c52a78 Mon Sep 17 00:00:00 2001 From: Boris Kovar Date: Tue, 3 Nov 2020 10:48:11 +0100 Subject: [PATCH 12/35] - fixed bug for direct links when the protein_code contains mix of lower and upper case characters - increased version number --- js/components/preview/molecule/redux/dispatchActions.js | 3 ++- package.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/js/components/preview/molecule/redux/dispatchActions.js b/js/components/preview/molecule/redux/dispatchActions.js index 9ace772fd..37a3eaaff 100644 --- a/js/components/preview/molecule/redux/dispatchActions.js +++ b/js/components/preview/molecule/redux/dispatchActions.js @@ -410,7 +410,8 @@ export const applyDirectSelection = (stage, stageSummaryView) => (dispatch, getS let molCount = molList.length; for (let molIndex = 0; molIndex < molCount; molIndex++) { let mol = molList[molIndex]; - if (mol.protein_code.includes(m.name) || mol.protein_code.includes(m.name.toLowerCase())) { + let proteinCodeModded = mol.protein_code.toLowerCase(); + if (proteinCodeModded.includes(m.name.toLowerCase())) { let molGroupId = groupId; if (!mol_group_selection.includes(parseInt(molGroupId))) { let molGroup = mol_group_list.find(g => g.id === parseInt(molGroupId)); diff --git a/package.json b/package.json index 638e75a79..da9b73aed 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fragalysis-frontend", - "version": "0.9.11", + "version": "0.9.12", "description": "Frontend for fragalysis", "main": "webpack.config.js", "scripts": { From f202f00c29f3dfdab9438f935de6706776f4a5c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1na=20Kohanov=C3=A1?= Date: Tue, 3 Nov 2020 14:26:44 +0100 Subject: [PATCH 13/35] #427 Track action history of the user --- js/components/datasets/datasetMoleculeView.js | 2 +- .../viewerControls/displayControls/index.js | 4 ++-- js/reducers/ngl/actions.js | 4 ++-- js/reducers/ngl/nglReducers.js | 4 ++-- js/reducers/tracking/trackingActions.js | 16 +++++++++------- 5 files changed, 16 insertions(+), 14 deletions(-) diff --git a/js/components/datasets/datasetMoleculeView.js b/js/components/datasets/datasetMoleculeView.js index 3d92b3b1d..8bc445a32 100644 --- a/js/components/datasets/datasetMoleculeView.js +++ b/js/components/datasets/datasetMoleculeView.js @@ -729,7 +729,7 @@ export const DatasetMoleculeView = memo( setRef(ref.current); } }} - disabled={disableUserInteraction} + disabled={true} > X diff --git a/js/components/preview/viewerControls/displayControls/index.js b/js/components/preview/viewerControls/displayControls/index.js index e33f11d8b..ef9653586 100644 --- a/js/components/preview/viewerControls/displayControls/index.js +++ b/js/components/preview/viewerControls/displayControls/index.js @@ -107,7 +107,7 @@ export default memo(({ open, onClose }) => { // remove from nglReducer and selectionReducer dispatch(deleteObject(targetObject, nglView.stage, true)); } else { - dispatch(removeComponentRepresentation(parentKey, representation.uuid)); + dispatch(removeComponentRepresentation(parentKey, representation)); } } }; @@ -118,7 +118,7 @@ export default memo(({ open, onClose }) => { const targetObject = objectsInView[parentKey]; const nglView = getNglView(objectsInView[parentKey].display_div); const comp = nglView.stage.getComponentsByName(parentKey).first; - comp.eachRepresentation(representation => dispatch(removeComponentRepresentation(parentKey, representation.uuid))); + comp.eachRepresentation(representation => dispatch(removeComponentRepresentation(parentKey, representation))); // remove from nglReducer and selectionReducer dispatch(deleteObject(targetObject, nglView.stage, true)); diff --git a/js/reducers/ngl/actions.js b/js/reducers/ngl/actions.js index 3ab83d5d5..000f43a5c 100644 --- a/js/reducers/ngl/actions.js +++ b/js/reducers/ngl/actions.js @@ -23,9 +23,9 @@ export const addComponentRepresentation = (objectInViewID, newRepresentation) => objectInViewID }); -export const removeComponentRepresentation = (objectInViewID, representationID) => ({ +export const removeComponentRepresentation = (objectInViewID, representation) => ({ type: CONSTANTS.REMOVE_COMPONENT_REPRESENTATION, - representationID, + representation, objectInViewID }); diff --git a/js/reducers/ngl/nglReducers.js b/js/reducers/ngl/nglReducers.js index 009f1981d..a187a370b 100644 --- a/js/reducers/ngl/nglReducers.js +++ b/js/reducers/ngl/nglReducers.js @@ -80,12 +80,12 @@ export default function nglReducers(state = INITIAL_STATE, action = {}) { }); case CONSTANTS.REMOVE_COMPONENT_REPRESENTATION: + const representationID = action.representation && action.representation.uuid; const newObjInViewWithRemovedRepresentation = JSON.parse(JSON.stringify(state.objectsInView)); if (newObjInViewWithRemovedRepresentation[action.objectInViewID].representations) { for (let i = 0; i < newObjInViewWithRemovedRepresentation[action.objectInViewID].representations.length; i++) { if ( - newObjInViewWithRemovedRepresentation[action.objectInViewID].representations[i].uuid === - action.representationID + newObjInViewWithRemovedRepresentation[action.objectInViewID].representations[i].uuid === representationID ) { newObjInViewWithRemovedRepresentation[action.objectInViewID].representations.splice(i, 1); break; diff --git a/js/reducers/tracking/trackingActions.js b/js/reducers/tracking/trackingActions.js index 7d0eb3ac2..86c379a61 100644 --- a/js/reducers/tracking/trackingActions.js +++ b/js/reducers/tracking/trackingActions.js @@ -154,7 +154,7 @@ export const findTruckAction = (action, state) => { object_type: objectType, object_name: objectName, object_id: action.item.id, - text: `${actionDescription.SURFACE} ${actionDescription.TURNED_OFF} ${objectType} ${objectName}` + text: `${actionDescription.SURFACE} ${actionDescription.TURNED_ON} ${objectType} ${objectName}` }; } } else if (action.type.includes(selectionConstants.REMOVE_FROM_SURFACE_LIST)) { @@ -378,7 +378,7 @@ export const findTruckAction = (action, state) => { object_name: objectName, object_id: action.payload.item.id, dataset_id: action.payload.datasetID, - text: `${actionDescription.INTERACTIONS} ${actionDescription.TURNED_OF} ${objectType} ${objectName} of dataset: ${action.payload.datasetID}` + text: `${actionDescription.INTERACTIONS} ${actionDescription.TURNED_OFF} ${objectType} ${objectName} of dataset: ${action.payload.datasetID}` }; } } else if (action.type.includes(customDatasetConstants.APPEND_SURFACE_LIST)) { @@ -427,33 +427,35 @@ export const findTruckAction = (action, state) => { object_id: action.objectInViewID, representation_id: action.representationID, new_representation: action.newRepresentation, - text: `${objectType} of ${action.objectInViewID} ${actionDescription.CHANGED}` + text: `${objectType} parameter of ${action.objectInViewID} ${actionDescription.CHANGED}` }; } else if (action.type.includes(nglConstants.ADD_COMPONENT_REPRESENTATION)) { let objectType = actionObjectType.REPRESENTATION; + let representationName = action.newRepresentation && action.newRepresentation.type; truckAction = { type: actionType.REPRESENTATION_ADDED, timestamp: Date.now(), username: username, object_type: actionObjectType.REPRESENTATION, - object_name: action.objectInViewID, + object_name: representationName, object_id: action.objectInViewID, new_representation: action.newRepresentation, - text: `${objectType} of ${action.objectInViewID} ${actionDescription.ADDED}` + text: `${objectType} ${representationName} of ${action.objectInViewID} ${actionDescription.ADDED}` }; } else if (action.type.includes(nglConstants.REMOVE_COMPONENT_REPRESENTATION)) { let objectType = actionObjectType.REPRESENTATION; + let representationName = action.representation && action.representation.type; truckAction = { type: actionType.REPRESENTATION_REMOVED, timestamp: Date.now(), username: username, object_type: objectType, - object_name: action.objectInViewID, + object_name: representationName, object_id: action.objectInViewID, representation_id: action.representationID, - text: `${objectType} of ${action.objectInViewID} ${actionDescription.REMOVED}` + text: `${objectType} ${representationName} of ${action.objectInViewID} ${actionDescription.REMOVED}` }; } From 96264fb94404d03c65ed7efba77b59d93929c97d Mon Sep 17 00:00:00 2001 From: Boris Kovar Date: Tue, 3 Nov 2020 14:36:07 +0100 Subject: [PATCH 14/35] - increased the version number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index da9b73aed..824b3c355 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fragalysis-frontend", - "version": "0.9.12", + "version": "0.9.13", "description": "Frontend for fragalysis", "main": "webpack.config.js", "scripts": { From fb9aba9934424436c652e02f99a65cef08527049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1na=20Kohanov=C3=A1?= Date: Tue, 3 Nov 2020 17:23:23 +0100 Subject: [PATCH 15/35] #427 Track action history of the user --- js/reducers/tracking/trackingActions.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/js/reducers/tracking/trackingActions.js b/js/reducers/tracking/trackingActions.js index 86c379a61..edb1a3313 100644 --- a/js/reducers/tracking/trackingActions.js +++ b/js/reducers/tracking/trackingActions.js @@ -477,8 +477,19 @@ const getTargetName = (targetId, state) => { }; const getMoleculeName = (moleculeId, state) => { - let moleculeList = state.apiReducers.molecule_list; - let molecule = moleculeList.find(molecule => molecule.id === moleculeId); - let moleculeName = (molecule && molecule.protein_code) || ''; + let moleculeList = state.apiReducers.all_mol_lists; + let moleculeName = ''; + + if (moleculeList) { + for (const group in moleculeList) { + let molecules = moleculeList[group]; + + let molecule = molecules.find(molecule => molecule.id === moleculeId); + if (molecule && molecule != null) { + moleculeName = molecule.protein_code; + break; + } + } + } return moleculeName; }; From 30ec6ff5de8d0d8580323d6b4c0afafb1791b2a9 Mon Sep 17 00:00:00 2001 From: Boris Kovar Date: Wed, 4 Nov 2020 06:27:19 +0100 Subject: [PATCH 16/35] - increased version number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 824b3c355..4edcbdd3a 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fragalysis-frontend", - "version": "0.9.13", + "version": "0.9.14", "description": "Frontend for fragalysis", "main": "webpack.config.js", "scripts": { From a0401fd2ab79e7fa4e3cfcce09f709370b747b3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1na=20Kohanov=C3=A1?= Date: Wed, 4 Nov 2020 09:18:19 +0100 Subject: [PATCH 17/35] #427 Track action history of the user --- js/components/preview/molecule/moleculeListSortFilterDialog.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/js/components/preview/molecule/moleculeListSortFilterDialog.js b/js/components/preview/molecule/moleculeListSortFilterDialog.js index bb2edd7ab..d37d34c70 100644 --- a/js/components/preview/molecule/moleculeListSortFilterDialog.js +++ b/js/components/preview/molecule/moleculeListSortFilterDialog.js @@ -190,6 +190,9 @@ export const MoleculeListSortFilterDialog = memo( }; const [initState] = useState(initialize()); + + filter = filter || initState; + const [filteredCount, setFilteredCount] = useState(getFilteredMoleculesCount(getListedMolecules(), filter)); const [predefinedFilter, setPredefinedFilter] = useState(filter.predefined); From 6330cbe79e72592f078aa8a3dde2f89e02999556 Mon Sep 17 00:00:00 2001 From: Boris Kovar Date: Wed, 4 Nov 2020 09:54:40 +0100 Subject: [PATCH 18/35] - updated version number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4edcbdd3a..db96c294a 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fragalysis-frontend", - "version": "0.9.14", + "version": "0.9.15", "description": "Frontend for fragalysis", "main": "webpack.config.js", "scripts": { From 70ac7ea1431f60750b0c38ce4b4d42402866ca2a Mon Sep 17 00:00:00 2001 From: ag-m2ms Date: Thu, 5 Nov 2020 13:57:42 +0100 Subject: [PATCH 19/35] Exact match for direct links --- js/components/direct/constants.js | 3 ++- js/components/direct/directDisplay.js | 10 +++++++--- .../preview/molecule/redux/dispatchActions.js | 5 ++++- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/js/components/direct/constants.js b/js/components/direct/constants.js index 04847abfd..bc48332c7 100644 --- a/js/components/direct/constants.js +++ b/js/components/direct/constants.js @@ -1,4 +1,5 @@ export const URL_TOKENS = { target: 'target', - molecules: 'mols' + molecules: 'mols', + exact: 'exact' }; \ No newline at end of file diff --git a/js/components/direct/directDisplay.js b/js/components/direct/directDisplay.js index 01b5c3103..3d99870cb 100644 --- a/js/components/direct/directDisplay.js +++ b/js/components/direct/directDisplay.js @@ -65,12 +65,16 @@ export const DirectDisplay = memo(props => { currentMolecule.V = true; break; default: - currentMolecule = { name: part, L: true, P: false, C: false, S: false, V: false }; - molecules.push(currentMolecule); + if (part.toLowerCase() === URL_TOKENS.exact) { + currentMolecule.exact = true; + } else { + currentMolecule = { name: part, L: true, P: false, C: false, S: false, V: false, exact: false }; + molecules.push(currentMolecule); + } break; } } else { - currentMolecule = { name: part, L: true, P: false, C: false, S: false, V: false }; + currentMolecule = { name: part, L: true, P: false, C: false, S: false, V: false, exact: false }; molecules.push(currentMolecule); } } else { diff --git a/js/components/preview/molecule/redux/dispatchActions.js b/js/components/preview/molecule/redux/dispatchActions.js index 9ace772fd..3da18b5a4 100644 --- a/js/components/preview/molecule/redux/dispatchActions.js +++ b/js/components/preview/molecule/redux/dispatchActions.js @@ -404,13 +404,16 @@ export const applyDirectSelection = (stage, stageSummaryView) => (dispatch, getS //const molGroupMap = getMolGroupNameToId(); directDisplay.molecules.forEach(m => { let keys = Object.keys(allMols); + let directProteinNameModded = m.name.toLowerCase(); + let directProteinCodeModded = `${directDisplay.target.toLowerCase()}-${directProteinNameModded}`; for (let groupIndex = 0; groupIndex < keys.length; groupIndex++) { let groupId = keys[groupIndex]; let molList = allMols[groupId]; let molCount = molList.length; for (let molIndex = 0; molIndex < molCount; molIndex++) { let mol = molList[molIndex]; - if (mol.protein_code.includes(m.name) || mol.protein_code.includes(m.name.toLowerCase())) { + let proteinCodeModded = mol.protein_code.toLowerCase(); + if (m.exact ? proteinCodeModded === directProteinCodeModded : proteinCodeModded.includes(directProteinNameModded)) { let molGroupId = groupId; if (!mol_group_selection.includes(parseInt(molGroupId))) { let molGroup = mol_group_list.find(g => g.id === parseInt(molGroupId)); From 2bf965337113abb2fac3d0167ab17b79389b4af3 Mon Sep 17 00:00:00 2001 From: Boris Kovar Date: Thu, 5 Nov 2020 14:30:47 +0100 Subject: [PATCH 20/35] - updated version number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index db96c294a..4cdac4c47 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fragalysis-frontend", - "version": "0.9.15", + "version": "0.9.16", "description": "Frontend for fragalysis", "main": "webpack.config.js", "scripts": { From 94db501713b1d07a72c6a74f5ffbd7163c5073f9 Mon Sep 17 00:00:00 2001 From: ag-m2ms Date: Fri, 6 Nov 2020 12:38:48 +0100 Subject: [PATCH 21/35] Fixed stale reads of mol_group_selection --- js/components/preview/molecule/redux/dispatchActions.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/components/preview/molecule/redux/dispatchActions.js b/js/components/preview/molecule/redux/dispatchActions.js index 9ace772fd..6cc997ae3 100644 --- a/js/components/preview/molecule/redux/dispatchActions.js +++ b/js/components/preview/molecule/redux/dispatchActions.js @@ -390,7 +390,6 @@ export const applyDirectSelection = (stage, stageSummaryView) => (dispatch, getS const state = getState(); const directDisplay = state.apiReducers.direct_access; - const mol_group_selection = state.selectionReducers.mol_group_selection; const fragmentDisplayList = state.selectionReducers.fragmentDisplayList; const proteinList = state.selectionReducers.proteinList; const complexList = state.selectionReducers.complexList; @@ -412,6 +411,8 @@ export const applyDirectSelection = (stage, stageSummaryView) => (dispatch, getS let mol = molList[molIndex]; if (mol.protein_code.includes(m.name) || mol.protein_code.includes(m.name.toLowerCase())) { let molGroupId = groupId; + // Has to be declared here because otherwise we read stale value + const mol_group_selection = getState().selectionReducers.mol_group_selection; if (!mol_group_selection.includes(parseInt(molGroupId))) { let molGroup = mol_group_list.find(g => g.id === parseInt(molGroupId)); dispatch(selectMoleculeGroup(molGroup, stageSummaryView)); From 34f36231e573dad917930c9cff0837c976282e78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1na=20Kohanov=C3=A1?= Date: Fri, 6 Nov 2020 14:01:58 +0100 Subject: [PATCH 22/35] #444 The button X needs to be fixed (related to #407) --- js/components/datasets/redux/selectors.js | 27 ++++++++++++++--------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/js/components/datasets/redux/selectors.js b/js/components/datasets/redux/selectors.js index 0b33faa5a..3ceaf3a7e 100644 --- a/js/components/datasets/redux/selectors.js +++ b/js/components/datasets/redux/selectors.js @@ -254,20 +254,24 @@ export const getFilteredDatasetMoleculeList = createSelector( for (let prioAttr of sortedAttributes) { const order = filterProperties[prioAttr].order; - const 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 = 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]); - - if (scoreValueOfA === "Y") { + const 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 = + 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]); + + if (scoreValueOfA === 'Y') { scoreValueOfA = 1; - } else if (scoreValueOfA === "N") { + } else if (scoreValueOfA === 'N') { scoreValueOfA = 0; } - if (scoreValueOfB === "Y") { + if (scoreValueOfB === 'Y') { scoreValueOfB = 1; - } else if (scoreValueOfB === "N") { + } else if (scoreValueOfB === 'N') { scoreValueOfB = 0; } @@ -314,7 +318,10 @@ export const getCrossReferenceCompoundListByCompoundName = createSelector( Object.keys(moleculesDatasetMap).forEach(datasetID => { const currentList = moleculesDatasetMap[datasetID]; if (currentList && Array.isArray(currentList)) { - results.push({ molecule: currentList.find(item => item.name === compoundName), datasetID }); + let molecule = currentList.find(item => item.name === compoundName); + if (molecule) { + results.push({ molecule, datasetID }); + } } }); return results; From e59a73bcf73ed646d745529cfe98857d2a76ee35 Mon Sep 17 00:00:00 2001 From: ag-m2ms Date: Fri, 6 Nov 2020 14:05:29 +0100 Subject: [PATCH 23/35] Fixed target name stripping from molecule title --- js/components/preview/molecule/moleculeView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/components/preview/molecule/moleculeView.js b/js/components/preview/molecule/moleculeView.js index aaeccdf85..0224b4400 100644 --- a/js/components/preview/molecule/moleculeView.js +++ b/js/components/preview/molecule/moleculeView.js @@ -530,7 +530,7 @@ const MoleculeView = memo( moveSelectedMolSettings(previousItemData); }; - let moleculeTitle = data?.protein_code.replace(`${target_on_name}-`, ''); + let moleculeTitle = data?.protein_code.replace(new RegExp(`${target_on_name}-`, 'i'), ''); return ( <> From 3f9b2c8cb66229fcac1d21ee6170a9618a252ed2 Mon Sep 17 00:00:00 2001 From: Boris Kovar Date: Fri, 6 Nov 2020 14:28:31 +0100 Subject: [PATCH 24/35] - updated version number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4cdac4c47..cf7236631 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fragalysis-frontend", - "version": "0.9.16", + "version": "0.9.17", "description": "Frontend for fragalysis", "main": "webpack.config.js", "scripts": { From ca0b33e24d6f81b3389c39a3e6dcb83fade39b03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1na=20Kohanov=C3=A1?= Date: Mon, 9 Nov 2020 11:10:56 +0100 Subject: [PATCH 25/35] #444 The button X needs to be fixed (related to #407) --- js/components/datasets/datasetMoleculeView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/components/datasets/datasetMoleculeView.js b/js/components/datasets/datasetMoleculeView.js index 8bc445a32..3d92b3b1d 100644 --- a/js/components/datasets/datasetMoleculeView.js +++ b/js/components/datasets/datasetMoleculeView.js @@ -729,7 +729,7 @@ export const DatasetMoleculeView = memo( setRef(ref.current); } }} - disabled={true} + disabled={disableUserInteraction} > X From 3a1ee1d5fc777a47e61defb27ba1b336a0aa1d15 Mon Sep 17 00:00:00 2001 From: Boris Kovar Date: Mon, 9 Nov 2020 13:01:05 +0100 Subject: [PATCH 26/35] -updated version number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f44f91aaf..ed2b56dc0 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fragalysis-frontend", - "version": "0.9.11", + "version": "0.9.18", "description": "Frontend for fragalysis", "main": "webpack.config.js", "scripts": { From bea0e70851637c17c96b804c849b71e924679e6c Mon Sep 17 00:00:00 2001 From: Boris Kovar Date: Mon, 9 Nov 2020 13:20:53 +0100 Subject: [PATCH 27/35] - updated version number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cf7236631..df3246da8 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fragalysis-frontend", - "version": "0.9.17", + "version": "0.9.19", "description": "Frontend for fragalysis", "main": "webpack.config.js", "scripts": { From 95701a31107ab321e7ecfc6a946ed8102f9c4822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1na=20Kohanov=C3=A1?= Date: Mon, 9 Nov 2020 14:04:48 +0100 Subject: [PATCH 28/35] #451 Compounds are not displayed for a vector --- .../preview/molecule/redux/dispatchActions.js | 5 ++--- js/reducers/api/selectors.js | 1 + js/reducers/selection/selectors.js | 12 +++++++----- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/js/components/preview/molecule/redux/dispatchActions.js b/js/components/preview/molecule/redux/dispatchActions.js index 9ace772fd..6659ce577 100644 --- a/js/components/preview/molecule/redux/dispatchActions.js +++ b/js/components/preview/molecule/redux/dispatchActions.js @@ -42,8 +42,8 @@ import { setCompoundImage } from '../../summary/redux/actions'; import { noCompoundImage } from '../../summary/redux/reducer'; import { getMoleculeOfCurrentVector } from '../../../../reducers/selection/selectors'; import { resetCurrentCompoundsSettings } from '../../compounds/redux/actions'; -import {selectMoleculeGroup} from '../../moleculeGroups/redux/dispatchActions'; -import {setDirectAccess, setDirectAccessProcessed} from '../../../../reducers/api/actions'; +import { selectMoleculeGroup } from '../../moleculeGroups/redux/dispatchActions'; +import { setDirectAccess, setDirectAccessProcessed } from '../../../../reducers/api/actions'; /** * Convert the JSON into a list of arrow objects @@ -438,5 +438,4 @@ export const applyDirectSelection = (stage, stageSummaryView) => (dispatch, getS // dispatch(setDirectAccess({})); dispatch(setDirectAccessProcessed(true)); } - }; diff --git a/js/reducers/api/selectors.js b/js/reducers/api/selectors.js index 409289146..3bca464a3 100644 --- a/js/reducers/api/selectors.js +++ b/js/reducers/api/selectors.js @@ -1 +1,2 @@ export const getMoleculeList = state => state.apiReducers.molecule_list; +export const getAllMoleculeList = state => state.apiReducers.all_mol_lists; diff --git a/js/reducers/selection/selectors.js b/js/reducers/selection/selectors.js index f54f9b288..8aa98b9d5 100644 --- a/js/reducers/selection/selectors.js +++ b/js/reducers/selection/selectors.js @@ -1,5 +1,5 @@ import { createSelector } from 'reselect'; -import { getMoleculeList } from '../api/selectors'; +import { getAllMoleculeList } from '../api/selectors'; const getCurrentCompoundClass = state => state.previewReducers.compounds.currentCompoundClass; const getVectorList = state => state.selectionReducers.vector_list; @@ -10,14 +10,16 @@ const getCompoundsOfVectors = state => state.selectionReducers.compoundsOfVector export const getMoleculeOfCurrentVector = createSelector( getCurrentVector, getVectorList, - getMoleculeList, + getAllMoleculeList, (selectedVectorSmile, vectorList, moleculeList) => { if (selectedVectorSmile !== null && vectorList && moleculeList) { const foundedVector = vectorList.find(vector => vector.name.includes(selectedVectorSmile)); if (foundedVector) { - for (const molecule in moleculeList) { - if (moleculeList.hasOwnProperty(molecule)) { - if (molecule.id === foundedVector.moleculeId) { + for (const moleculeProperty in moleculeList) { + if (moleculeList.hasOwnProperty(moleculeProperty)) { + let molecules = moleculeList[moleculeProperty]; + let molecule = molecules.find(m => m.id === foundedVector.moleculeId); + if (molecule) { return molecule; } } From fb6878bb53a4a5baca70c4f191cac346d1c8dc8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1na=20Kohanov=C3=A1?= Date: Mon, 9 Nov 2020 16:18:37 +0100 Subject: [PATCH 29/35] Fixed molecule view of inspiration dialog --- js/components/datasets/inspirationDialog.js | 3 +++ .../preview/molecule/moleculeView.js | 24 ++++++++++++++----- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/js/components/datasets/inspirationDialog.js b/js/components/datasets/inspirationDialog.js index 3a69ab162..007782ab3 100644 --- a/js/components/datasets/inspirationDialog.js +++ b/js/components/datasets/inspirationDialog.js @@ -218,6 +218,8 @@ export const InspirationDialog = memo( surface: removeSurface }; + const selectMoleculeSite = moleculeGroupSite => {}; + const removeOfAllSelectedTypes = () => { proteinList?.forEach(moleculeID => { let foundedMolecule = moleculeList?.find(mol => mol.id === moleculeID); @@ -409,6 +411,7 @@ export const InspirationDialog = memo( previousItemData={previousData} nextItemData={nextData} removeOfAllSelectedTypes={removeOfAllSelectedTypes} + selectMoleculeSite={selectMoleculeSite} /> ); })} diff --git a/js/components/preview/molecule/moleculeView.js b/js/components/preview/molecule/moleculeView.js index 59f5ba431..e6e3391aa 100644 --- a/js/components/preview/molecule/moleculeView.js +++ b/js/components/preview/molecule/moleculeView.js @@ -345,7 +345,9 @@ const MoleculeView = memo( isLigandOn || isProteinOn || isComplexOn || isSurfaceOn || isVectorOn ? selected_style : not_selected_style; const addNewLigand = () => { - selectMoleculeSite(data.site); + if (selectMoleculeSite) { + selectMoleculeSite(data.site); + } dispatch(addLigand(stage, data, colourToggle)); }; @@ -376,7 +378,9 @@ const MoleculeView = memo( }; const addNewProtein = () => { - selectMoleculeSite(data.site); + if (selectMoleculeSite) { + selectMoleculeSite(data.site); + } dispatch(addHitProtein(stage, data, colourToggle)); }; @@ -402,7 +406,9 @@ const MoleculeView = memo( }; const addNewComplex = () => { - selectMoleculeSite(data.site); + if (selectMoleculeSite) { + selectMoleculeSite(data.site); + } dispatch(addComplex(stage, data, colourToggle)); }; @@ -427,7 +433,9 @@ const MoleculeView = memo( }; const addNewSurface = () => { - selectMoleculeSite(data.site); + if (selectMoleculeSite) { + selectMoleculeSite(data.site); + } dispatch(addSurface(stage, data, colourToggle)); }; @@ -444,7 +452,9 @@ const MoleculeView = memo( }; const addNewDensity = () => { - selectMoleculeSite(data.site); + if (selectMoleculeSite) { + selectMoleculeSite(data.site); + } dispatch(addDensity(stage, data, colourToggle)); }; @@ -461,7 +471,9 @@ const MoleculeView = memo( }; const addNewVector = () => { - selectMoleculeSite(data.site); + if (selectMoleculeSite) { + selectMoleculeSite(data.site); + } dispatch(addVector(stage, data)).catch(error => { throw new Error(error); }); From 165a485df06370cd35e6e4a084fd918d219c70f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A1na=20Kohanov=C3=A1?= Date: Tue, 10 Nov 2020 12:10:27 +0100 Subject: [PATCH 30/35] Fixed molecule view of cross reference dialog --- js/components/datasets/crossReferenceDialog.js | 3 ++- js/components/datasets/datasetMoleculeView.js | 12 +++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/js/components/datasets/crossReferenceDialog.js b/js/components/datasets/crossReferenceDialog.js index 5bd070d7d..78361819d 100644 --- a/js/components/datasets/crossReferenceDialog.js +++ b/js/components/datasets/crossReferenceDialog.js @@ -60,7 +60,8 @@ const useStyles = makeStyles(theme => ({ }, content: { overflowY: 'auto', - height: 214 + height: 214, + width: 'fit-content' }, search: { margin: theme.spacing(1), diff --git a/js/components/datasets/datasetMoleculeView.js b/js/components/datasets/datasetMoleculeView.js index 3d92b3b1d..3f3588eac 100644 --- a/js/components/datasets/datasetMoleculeView.js +++ b/js/components/datasets/datasetMoleculeView.js @@ -161,6 +161,10 @@ const useStyles = makeStyles(theme => ({ inheritWidth: { width: 'inherit' }, + widthOverflow: { + maxWidth: '180px', + overflow: 'hidden' + }, rank: { fontStyle: 'italic', fontSize: 7 @@ -553,7 +557,13 @@ export const DatasetMoleculeView = memo(
{/* Title label */} - +
From e84da99f87df59f4a392db9810143e2b15b29efd Mon Sep 17 00:00:00 2001 From: Boris Kovar Date: Wed, 11 Nov 2020 06:19:26 +0100 Subject: [PATCH 31/35] - updated version number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index df3246da8..3f2053a6b 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fragalysis-frontend", - "version": "0.9.19", + "version": "0.9.21", "description": "Frontend for fragalysis", "main": "webpack.config.js", "scripts": { From b1dc90e43f5a1546cf575757f69fb4319f571319 Mon Sep 17 00:00:00 2001 From: ag-m2ms Date: Thu, 12 Nov 2020 15:44:17 +0100 Subject: [PATCH 32/35] Added download as CSV and SDF Slightly changed Panel layout --- js/components/common/Surfaces/Panel/index.js | 4 +- .../datasets/selectedCompoundsList.js | 61 +++++++++++++++++-- 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/js/components/common/Surfaces/Panel/index.js b/js/components/common/Surfaces/Panel/index.js index 1191ee684..db6b1bb84 100644 --- a/js/components/common/Surfaces/Panel/index.js +++ b/js/components/common/Surfaces/Panel/index.js @@ -114,7 +114,7 @@ export const Panel = memo( {title && ( 2 ? 4 : 6) : 12} + xs={hasExpansion || headerActions ? (headerActions && headerActions.length > 1 ? 5 : 6) : 12} className={classes.headerTitle} > {withTooltip ? ( @@ -136,7 +136,7 @@ export const Panel = memo( container direction="row" justify="flex-end" - xs={title ? (headerActions && headerActions.length > 2 ? 8 : 6) : 12} + xs={title ? (headerActions && headerActions.length > 1 ? 7 : 6) : 12} > {headerActions && headerActions.map((action, index) => ( diff --git a/js/components/datasets/selectedCompoundsList.js b/js/components/datasets/selectedCompoundsList.js index ee6979dad..bcc764b97 100644 --- a/js/components/datasets/selectedCompoundsList.js +++ b/js/components/datasets/selectedCompoundsList.js @@ -1,6 +1,7 @@ import React, { memo, useContext, useEffect, useRef, useState } from 'react'; import { Panel } from '../common/Surfaces/Panel'; -import { CircularProgress, Grid, makeStyles, Typography } from '@material-ui/core'; +import { CircularProgress, Grid, makeStyles, Typography, Button } from '@material-ui/core'; +import { CloudDownload } from '@material-ui/icons'; import { useDispatch, useSelector } from 'react-redux'; import { getMoleculesObjectIDListOfCompoundsToBuy } from './redux/selectors'; import InfiniteScroll from 'react-infinite-scroller'; @@ -19,6 +20,8 @@ import { import MoleculeView from '../preview/molecule/moleculeView'; import { NglContext } from '../nglView/nglProvider'; import { VIEWS } from '../../constants/constants'; +import FileSaver from 'file-saver'; +import JSZip from 'jszip'; const useStyles = makeStyles(theme => ({ container: { @@ -35,6 +38,9 @@ const useStyles = makeStyles(theme => ({ }, notFound: { paddingTop: theme.spacing(2) + }, + sdfButton: { + marginRight: theme.spacing(1) } })); @@ -46,8 +52,7 @@ export const SelectedCompoundList = memo(({ height }) => { const moleculesPerPage = 5; const dispatch = useDispatch(); const [currentPage, setCurrentPage] = useState(0); - const moleculesObjectIDListOfCompoundsToBuy = useSelector(getMoleculesObjectIDListOfCompoundsToBuy); - const isOpenInspirationDialog = useSelector(state => state.datasetsReducers.isOpenInspirationDialog); + const moleculesObjectIDListOfCompoundsToBuy = useSelector(getMoleculesObjectIDListOfCompoundsToBuy); const isOpenInspirationDialog = useSelector(state => state.datasetsReducers.isOpenInspirationDialog); const isOpenCrossReferenceDialog = useSelector(state => state.datasetsReducers.isOpenCrossReferenceDialog); const [selectedMoleculeRef, setSelectedMoleculeRef] = useState(null); const inspirationDialogRef = useRef(); @@ -132,8 +137,56 @@ export const SelectedCompoundList = memo(({ height }) => { }; }, [dispatch]); + const downloadAsCsv = () => { + let data = 'smiles,dataset'; + moleculesObjectIDListOfCompoundsToBuy.forEach(compound => { + data += `\n${compound.molecule.smiles},${compound.datasetID}`; + }); + const dataBlob = new Blob([data], {type: 'text/csv;charset=utf-8'}); + + FileSaver.saveAs(dataBlob, 'selectedCompounds.csv'); + }; + + const downloadAsSdf = async () => { + const zip = new JSZip(); + const folders = {}; + + moleculesObjectIDListOfCompoundsToBuy.forEach(compound => { + const datasetID = compound.datasetID; + let folder = folders[datasetID]; + if (!folder) { + folder = zip.folder(datasetID); + folders[datasetID] = folder; + } + + const { name, sdf_info } = compound.molecule; + folder.file(`${name}.sdf`, sdf_info); + }); + + const zipBlob = await zip.generateAsync({ type: 'blob' }); + FileSaver.saveAs(zipBlob, 'selectedCompounds.zip'); + }; + return ( - + } + > + Download CSV + , + + ]}> {isOpenInspirationDialog && ( Date: Thu, 19 Nov 2020 09:53:58 +0100 Subject: [PATCH 33/35] Fixed layout and cross reference button --- js/components/common/Surfaces/Panel/index.js | 4 ++-- js/components/datasets/datasetMoleculeView.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/js/components/common/Surfaces/Panel/index.js b/js/components/common/Surfaces/Panel/index.js index db6b1bb84..1d204e8b3 100644 --- a/js/components/common/Surfaces/Panel/index.js +++ b/js/components/common/Surfaces/Panel/index.js @@ -114,7 +114,7 @@ export const Panel = memo( {title && ( 1 ? 5 : 6) : 12} + xs={hasExpansion || headerActions ? (headerActions && headerActions.length > 1 ? 4 : 6) : 12} className={classes.headerTitle} > {withTooltip ? ( @@ -136,7 +136,7 @@ export const Panel = memo( container direction="row" justify="flex-end" - xs={title ? (headerActions && headerActions.length > 1 ? 7 : 6) : 12} + xs={title ? (headerActions && headerActions.length > 1 ? 8 : 6) : 12} > {headerActions && headerActions.map((action, index) => ( diff --git a/js/components/datasets/datasetMoleculeView.js b/js/components/datasets/datasetMoleculeView.js index dd051e902..3f3588eac 100644 --- a/js/components/datasets/datasetMoleculeView.js +++ b/js/components/datasets/datasetMoleculeView.js @@ -739,7 +739,7 @@ export const DatasetMoleculeView = memo( setRef(ref.current); } }} - disabled={true} + disabled={disableUserInteraction} > X From 049a52dcc67899006fd1e21c62579a32e99d12e3 Mon Sep 17 00:00:00 2001 From: Boris Kovar Date: Fri, 20 Nov 2020 14:08:06 +0100 Subject: [PATCH 34/35] - updated version number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3f2053a6b..feecf8c98 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fragalysis-frontend", - "version": "0.9.21", + "version": "0.9.26", "description": "Frontend for fragalysis", "main": "webpack.config.js", "scripts": { From a0a1996437398723f108633fbb3da3a61edb8cad Mon Sep 17 00:00:00 2001 From: Boris Kovar Date: Wed, 25 Nov 2020 06:35:38 +0100 Subject: [PATCH 35/35] - updated version number --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f44f91aaf..35e45318a 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fragalysis-frontend", - "version": "0.9.11", + "version": "0.9.29", "description": "Frontend for fragalysis", "main": "webpack.config.js", "scripts": {