Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/origin/#453' into #455
Browse files Browse the repository at this point in the history
# Conflicts:
#	js/components/snapshot/redux/dispatchActions.js
  • Loading branch information
Adriána Kohanová committed Nov 25, 2020
2 parents efb869e + 39da154 commit 36f49fe
Show file tree
Hide file tree
Showing 9 changed files with 246 additions and 106 deletions.
4 changes: 2 additions & 2 deletions js/components/common/Surfaces/Panel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export const Panel = memo(
{title && (
<Grid
item
xs={hasExpansion || headerActions ? (headerActions && headerActions.length > 2 ? 4 : 6) : 12}
xs={hasExpansion || headerActions ? (headerActions && headerActions.length > 1 ? 4 : 6) : 12}
className={classes.headerTitle}
>
{withTooltip ? (
Expand All @@ -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 ? 8 : 6) : 12}
>
{headerActions &&
headerActions.map((action, index) => (
Expand Down
2 changes: 1 addition & 1 deletion js/components/datasets/datasetMoleculeView.js
Original file line number Diff line number Diff line change
Expand Up @@ -739,7 +739,7 @@ export const DatasetMoleculeView = memo(
setRef(ref.current);
}
}}
disabled={true}
disabled={disableUserInteraction}
>
X
</Button>
Expand Down
61 changes: 57 additions & 4 deletions js/components/datasets/selectedCompoundsList.js
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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: {
Expand All @@ -35,6 +38,9 @@ const useStyles = makeStyles(theme => ({
},
notFound: {
paddingTop: theme.spacing(2)
},
sdfButton: {
marginRight: theme.spacing(1)
}
}));

Expand All @@ -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();
Expand Down Expand Up @@ -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 (
<Panel hasHeader title="Selected Compounds" withTooltip>
<Panel hasHeader title="Selected Compounds" withTooltip headerActions={[
<Button
color="inherit"
variant="text"
onClick={downloadAsCsv}
startIcon={<CloudDownload />}
>
Download CSV
</Button>,
<Button
color="inherit"
variant="text"
className={classes.sdfButton}
onClick={downloadAsSdf}
startIcon={<CloudDownload />}
>
Download SDF
</Button>
]}>
{isOpenInspirationDialog && (
<InspirationDialog
open
Expand Down
44 changes: 27 additions & 17 deletions js/components/preview/molecule/moleculeList.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ import { useRouteMatch } from 'react-router-dom';
import { setSortDialogOpen } from './redux/actions';
import { setMoleculeList, setAllMolLists } from '../../../reducers/api/actions';
import { AlertModal } from '../../common/Modal/AlertModal';
import {selectMoleculeGroup} from '../moleculeGroups/redux/dispatchActions';
import { onSelectMoleculeGroup } from '../moleculeGroups/redux/dispatchActions';

const useStyles = makeStyles(theme => ({
Expand Down Expand Up @@ -279,14 +278,18 @@ export const MoleculeList = memo(({ height, setFilterItemsHeight, filterItemsHei
// setCurrentPage(0);
}, [object_selection]);*/

let joinedMoleculeLists = [];
if (searchString !== null) {
joinedMoleculeLists = getAllMoleculeList.filter(molecule =>
molecule.protein_code.toLowerCase().includes(searchString.toLowerCase())
);
} else {
joinedMoleculeLists = getJoinedMoleculeList;
}
let joinedMoleculeLists = useMemo(() => {
if (searchString) {
return getAllMoleculeList.filter(molecule =>
molecule.protein_code.toLowerCase().includes(searchString.toLowerCase())
);
} else {
return getJoinedMoleculeList;
}
}, [getJoinedMoleculeList, getAllMoleculeList, searchString]);

// Used for MoleculeListSortFilterDialog when using textSearch
const joinedMoleculeListsCopy = useMemo(() => [...joinedMoleculeLists], [joinedMoleculeLists]);

if (isActiveFilter) {
joinedMoleculeLists = filterMolecules(joinedMoleculeLists, filter);
Expand Down Expand Up @@ -443,18 +446,26 @@ export const MoleculeList = memo(({ height, setFilterItemsHeight, filterItemsHei
handleFilterChange(newFilter);*/
};

const changeButtonClassname = (givenList = []) => {
if (joinedMoleculeLists.length === givenList.length) {
const joinedGivenMatch = useCallback((givenList) => {
return givenList.filter(element => joinedMoleculeLists.filter(element2 => element2.id === element).length > 0).length;
}, [joinedMoleculeLists]);

const joinedLigandMatchLength = useMemo(() => joinedGivenMatch(fragmentDisplayList), [fragmentDisplayList, joinedGivenMatch]);
const joinedProteinMatchLength = useMemo(() => joinedGivenMatch(proteinList), [proteinList, joinedGivenMatch]);
const joinedComplexMatchLength = useMemo(() => joinedGivenMatch(complexList), [complexList, joinedGivenMatch]);

const changeButtonClassname = (givenList = [], matchListLength) => {
if (joinedMoleculeLists.length === matchListLength) {
return true;
} else if (givenList.length > 0) {
} else if (givenList.length > 0 && matchListLength > 0) {
return null;
}
return false;
};

const isLigandOn = changeButtonClassname(fragmentDisplayList);
const isProteinOn = changeButtonClassname(proteinList);
const isComplexOn = changeButtonClassname(complexList);
const isLigandOn = changeButtonClassname(fragmentDisplayList, joinedLigandMatchLength);
const isProteinOn = changeButtonClassname(proteinList, joinedProteinMatchLength);
const isComplexOn = changeButtonClassname(complexList, joinedComplexMatchLength);

const addType = {
ligand: addLigand,
Expand Down Expand Up @@ -648,10 +659,9 @@ export const MoleculeList = memo(({ height, setFilterItemsHeight, filterItemsHei
<MoleculeListSortFilterDialog
open={sortDialogOpen}
anchorEl={sortDialogAnchorEl}
molGroupSelection={object_selection}
cachedMolList={all_mol_lists}
filter={filter}
setSortDialogAnchorEl={setSortDialogAnchorEl}
joinedMoleculeLists={joinedMoleculeListsCopy}
/>
)}
<div ref={filterRef}>
Expand Down
91 changes: 55 additions & 36 deletions js/components/preview/molecule/moleculeListSortFilterDialog.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import React, { memo, useState } from 'react';
import React, { memo, useState, useEffect, useCallback } from 'react';
import PropTypes from 'prop-types';
import { Popper, Tooltip, IconButton } from '@material-ui/core';
import { Close, Delete } from '@material-ui/icons';
import Grid from '@material-ui/core/Grid';
import MoleculeListSortFilterItem from './moleculeListSortFilterItem';
import WarningIcon from '@material-ui/icons/Warning';
import { makeStyles } from '@material-ui/styles';
import { useDispatch, useSelector } from 'react-redux';
import { useDispatch } from 'react-redux';
import { MOL_ATTRIBUTES } from './redux/constants';
import { setFilter } from '../../../reducers/selection/actions';
import { Panel } from '../../common/Surfaces/Panel';
Expand Down Expand Up @@ -62,6 +62,7 @@ export const getFilteredMoleculesCount = (molecules, filter) => {
for (let molecule of molecules) {
let add = true; // By default molecule passes filter
for (let attr of MOL_ATTRIBUTES) {
if (!attr.filter) continue;
const lowAttr = attr.key.toLowerCase();
const attrValue = molecule[lowAttr];
if (attrValue < filter.filter[attr.key].minValue || attrValue > filter.filter[attr.key].maxValue) {
Expand Down Expand Up @@ -129,35 +130,18 @@ export const filterMolecules = (molecules, filter) => {

export const MoleculeListSortFilterDialog = memo(
({
molGroupSelection,
cachedMolList,
filter,
anchorEl,
open,
parentID = 'default',
placement = 'right-start',
setSortDialogAnchorEl
setSortDialogAnchorEl,
joinedMoleculeLists
}) => {
let classes = useStyles();
const dispatch = useDispatch();
const moleculeGroupList = useSelector(state => state.apiReducers.mol_group_list);

const getListedMolecules = () => {
let molecules = [];
for (let molGroupId of molGroupSelection) {
// Selected molecule groups
const molGroup = cachedMolList[molGroupId];
if (molGroup) {
molecules = molecules.concat(molGroup);
} else {
console.log(`Molecule group ${molGroupId} not found in cached list`);
}
}

return molecules;
};

const initialize = () => {
const initialize = useCallback(() => {
let initObject = {
active: false,
predefined: 'none',
Expand All @@ -169,9 +153,8 @@ export const MoleculeListSortFilterDialog = memo(
const lowAttr = attr.key.toLowerCase();
let minValue = -999999;
let maxValue = 0;
const moleculeList = getListedMolecules();

moleculeList.forEach(molecule => {
joinedMoleculeLists.forEach(molecule => {
const attrValue = molecule[lowAttr];
if (attrValue > maxValue) maxValue = attrValue;
if (minValue === -999999) minValue = maxValue;
Expand All @@ -187,31 +170,70 @@ export const MoleculeListSortFilterDialog = memo(
};
}
return initObject;
};

const [initState] = useState(initialize());
}, [joinedMoleculeLists]);

filter = filter || initState;

const [filteredCount, setFilteredCount] = useState(getFilteredMoleculesCount(getListedMolecules(), filter));
const [initState, setInitState] = useState(initialize());
const [filteredCount, setFilteredCount] = useState(getFilteredMoleculesCount(joinedMoleculeLists, filter));
const [predefinedFilter, setPredefinedFilter] = useState(filter.predefined);

const handleFilterChange = filter => {
const handleFilterChange = useCallback(filter => {
const filterSet = Object.assign({}, filter);
for (let attr of MOL_ATTRIBUTES) {
if (filterSet.filter[attr.key].priority === undefined || filterSet.filter[attr.key].priority === '') {
filterSet.filter[attr.key].priority = 0;
}
}
dispatch(setFilter(filterSet));
};
}, [dispatch]);

useEffect(() => {
const init = initialize();

setInitState(init);

if (!filter.active) {
const initCopy = { ...init };
dispatch(setFilter(initCopy));
handleFilterChange(initCopy);
}
}, [initialize, dispatch, joinedMoleculeLists, handleFilterChange, filter.active]);

useEffect(() => {
setFilteredCount(getFilteredMoleculesCount(joinedMoleculeLists, filter));
}, [joinedMoleculeLists, filter]);

useEffect(() => {
let changed = false;
const newFilter = { ...filter };

for (let attr of MOL_ATTRIBUTES) {
if (!attr.filter) continue;
const key = attr.key;
const filterValue = newFilter.filter[key];
const initValue = initState.filter[key];

if (filterValue.minValue < initValue.minValue || filterValue.minValue > initValue.maxValue) {
filterValue.minValue = initValue.minValue;
changed = true;
}

if (filterValue.maxValue > initValue.maxValue || filterValue.maxValue < initValue.minValue) {
filterValue.maxValue = initValue.maxValue;
changed = true;
}
}

if (changed) {
dispatch(setFilter(newFilter));
handleFilterChange(newFilter);
}
}, [initState, filter, dispatch, handleFilterChange]);

const handleItemChange = key => setting => {
let newFilter = Object.assign({}, filter);
newFilter.filter[key] = setting;
newFilter.active = true;
dispatch(setFilter(newFilter));
setFilteredCount(getFilteredMoleculesCount(getListedMolecules(), newFilter));
handleFilterChange(newFilter);
};

Expand All @@ -235,7 +257,6 @@ export const MoleculeListSortFilterDialog = memo(
const resetFilter = initialize();
setPredefinedFilter('none');
dispatch(setFilter(resetFilter));
setFilteredCount(getFilteredMoleculesCount(getListedMolecules(), resetFilter));
handleFilterChange(resetFilter);
};

Expand Down Expand Up @@ -338,8 +359,6 @@ export const MoleculeListSortFilterDialog = memo(
);

MoleculeListSortFilterDialog.propTypes = {
molGroupSelection: PropTypes.arrayOf(PropTypes.number).isRequired,
cachedMolList: PropTypes.object.isRequired,
filter: PropTypes.object,
setFilter: PropTypes.func,
anchorEl: PropTypes.object,
Expand Down
Loading

0 comments on commit 36f49fe

Please sign in to comment.