Skip to content

Commit

Permalink
#1458 (#446)
Browse files Browse the repository at this point in the history
* Squashed commit of the following:

commit e613216
Author: Boris Kovar <boris.kovar@m2ms.sk>
Date:   Wed Jul 31 13:57:02 2024 +0200

    - implemented #1251

* #1482 added TagName and CentroidRes columns for expanded view of observation dialog

* #1489 show warning toast message if is defined on target load

* #1322 added longcode column

* updated general function for tag comparison

* #1505 adjusted getting of centroid_res

* #1458 allow to tag XCA sites, temp commit

# Conflicts:
#	js/components/preview/molecule/observationsDialog.js

* #1458 adjusted functionality and styling to proper change tag

---------

Co-authored-by: matej <matej.vavrek@m2ms.sk>
  • Loading branch information
boriskovar-m2ms and matej-vavrek authored Sep 10, 2024
1 parent 0e308b8 commit b32a185
Show file tree
Hide file tree
Showing 10 changed files with 344 additions and 61 deletions.
3 changes: 2 additions & 1 deletion js/components/preview/molecule/moleculeView/moleculeView.js
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,8 @@ const MoleculeView = memo(
* Get tag for render
*/
const getTagType = useCallback((type) => {
const defaultTagObject = { tag_prefix: '-', color: 'orange' };
// TODO change this to null maybe?
const defaultTagObject = { tag_prefix: '-', color: 'orange', upload_name: '-' };
const tagCategory = tagCategories.find(tag => tag.category === type);
const tagObject = tagCategory ? getAllTags().find(tag => tag.category === tagCategory.id) : defaultTagObject;
return tagObject ?? defaultTagObject;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,7 @@ const ObservationCmpView = memo(
}, [getConformerSitesTagCategory, observations, tagList]);

/**
* Get ConformerSites tag for render
* Get CanonSites tag for render
*/
const getCanonSitesTag = useCallback(() => {
const canonSitesCategory = getCanonSitesTagCategory();
Expand Down Expand Up @@ -749,7 +749,7 @@ const ObservationCmpView = memo(
}
}}
style={{ padding: 0, paddingBottom: 3, marginRight: 5, position: 'right' }}
// className={classes.editIcon}
// className={classes.editIcon}
>
<Tooltip title="Edit tag" className={classes.editButtonIcon}>
<Edit />
Expand Down Expand Up @@ -814,7 +814,7 @@ const ObservationCmpView = memo(
}
}}
style={{ padding: 0, paddingBottom: 3, paddingRight: 5, cursor: 'pointer' }}
// className={classes.editIcon}
// className={classes.editIcon}
>
<Tooltip title="Edit tags" className={classes.editButtonIcon}>
<Edit />
Expand Down Expand Up @@ -893,7 +893,7 @@ const ObservationCmpView = memo(
}
}}
style={{ padding: 0, paddingBottom: 8, paddingRight: 5, cursor: 'pointer' }}
// className={classes.editIcon}
// className={classes.editIcon}
>
<Tooltip title="Edit tags" className={classes.editButtonIcon}>
<Edit />
Expand Down Expand Up @@ -1294,7 +1294,7 @@ const ObservationCmpView = memo(
[classes.siteOpenObservations]: poseIdForObservationsDialog === data.id && isObservationDialogOpen
})}
wrap="nowrap"
// ref={ref}
// ref={ref}
>
{/* Site number */}
<Grid item container justifyContent="space-between" direction="column" className={classes.site}>
Expand Down
253 changes: 248 additions & 5 deletions js/components/preview/molecule/observationsDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { makeStyles } from '@material-ui/styles';
import { useDispatch, useSelector } from 'react-redux';
import classNames from 'classnames';
import { NglContext } from '../../nglView/nglProvider';
import { PLURAL_TO_SINGULAR, VIEWS } from '../../../constants/constants';
import { PLURAL_TO_SINGULAR, VIEWS, XCA_TAG_CATEGORIES } from '../../../constants/constants';
import { changeButtonClassname } from '../../datasets/helpers';
import {
addComplex,
Expand All @@ -16,6 +16,8 @@ import {
copyPoseToPoseDTO,
createNewPose,
getAllCompatiblePoses,
getCategoryById,
prepareEmptyPoseDTO,
removeComplex,
removeHitProtein,
removeLigand,
Expand All @@ -36,7 +38,8 @@ import {
setOpenObservationsDialog,
setPoseIdForObservationsDialog,
setSelectedAllByType,
setTagEditorOpenObs
setTagEditorOpenObs,
updateMoleculeInLHSObservations
} from '../../../reducers/selection/actions';
import useDisableNglControlButtons from './useDisableNglControlButtons';
import { Button, Panel } from '../../common';
Expand All @@ -46,8 +49,10 @@ import MoleculeView from './moleculeView';
import { TagEditor } from '../tags/modal/tagEditor';
import { ToastContext } from '../../toast';
import { DJANGO_CONTEXT } from '../../../utils/djangoContext';
import { updateLHSCompound } from '../../../reducers/api/actions';
import { updateLHSCompound, updateMoleculeInMolLists, updateMoleculeTag, updateTag } from '../../../reducers/api/actions';
import { createPoseErrorMessage } from './api/poseApi';
import { augumentTagObjectWithId, createMoleculeTagObject, DEFAULT_TAG_COLOR, getMoleculeTagForTag } from '../tags/utils/tagUtils';
import { updateExistingTag } from '../tags/api/tagsApi';

const MIN_PANEL_HEIGHT = 250;

Expand Down Expand Up @@ -166,6 +171,7 @@ const useStyles = makeStyles(theme => ({
},
dropdownItem: {
fontSize: 12,
width: '100%',
// fontWeight: 'bold',
paddingLeft: theme.spacing(1) / 4,
paddingRight: theme.spacing(1) / 4,
Expand All @@ -174,8 +180,16 @@ const useStyles = makeStyles(theme => ({
backgroundColor: theme.palette.primary.light
}
},
dropdownContentSide: {
left: 148,
marginTop: -18,
maxWidth: 260,
width: 260,
overflowY: 'auto',
maxHeight: 100
},
dropdown: {
'&:hover $dropdownContent': {
'&:hover > $dropdownContent': {
display: 'flex'
}
},
Expand Down Expand Up @@ -228,6 +242,10 @@ export const ObservationsDialog = memo(
const informationList = useSelector(state => state.selectionReducers.informationList);
const molForTagEditId = useSelector(state => state.selectionReducers.molForTagEdit);
const moleculesToEditIds = useSelector(state => state.selectionReducers.moleculesToEdit);
const tagCategoriesList = useSelector(state => state.apiReducers.categoryList);
// const tagList = useSelector(state => state.apiReducers.tagList);
const tagList = useSelector(state => state.apiReducers.moleculeTags);
const targetId = useSelector(state => state.apiReducers.target_on);

const poses = useSelector(state => state.apiReducers.lhs_compounds_list);
const compatiblePoses = useMemo(() => {
Expand Down Expand Up @@ -605,7 +623,6 @@ export const ObservationsDialog = memo(
const observationsApproximateHeight = moleculeList.length * 47;
const headerFooterApproximateHeight = 87;
const totalApproximateHeight = observationsApproximateHeight + headerFooterApproximateHeight;

if (totalApproximateHeight > maxHeight) {
height = maxHeight;
} else if (totalApproximateHeight < MIN_PANEL_HEIGHT) {
Expand All @@ -620,6 +637,206 @@ export const ObservationsDialog = memo(
return height;
}, [anchorEl, moleculeList.length]);

/**
* @param {string} category
* @return {array}
*/
const getTagsForCategory = useCallback(category => {
const tagCategory = tagCategoriesList.find(tagCategory => tagCategory.category === category);
return tagCategory ? tagList.filter(tag => {
if (tag.category === tagCategory.id) {
// console.log('good tag', { ...tag });
return true;
} else return false;
}) : [];
}, [tagCategoriesList, tagList]);

const updateCmp = (cmp, obs) => {
let newCmp = { ...cmp };
const index = newCmp.associatedObs.findIndex(o => o.id === obs.id);
if (index >= 0) {
newCmp.associatedObs[index] = obs;
dispatch(updateLHSCompound(newCmp));
}
};

const tagObservations = async (tag, tagToExclude) => {
try {
// setTaggingInProgress(true);

let tagColor = DEFAULT_TAG_COLOR;
if (tag.colour && tag.colour !== '') {
tagColor = tag.colour;
} else {
const tagCategory = dispatch(getCategoryById(tag.category));
if (tagCategory) {
tagColor = `#${tagCategory.colour}`;
}
}

let molTagObjects = [];
observationsDataList.forEach(m => {
if (!m.tags_set.some(id => id === tag.id)) {
let newMol = { ...m };
newMol.tags_set.push(tag.id);
// due to same cycle of tag and untag operations we need to exclude untagged tag because of "old" data
newMol.tags_set = newMol.tags_set.filter(id => id !== tagToExclude.id);

const pose = poses.find(p => p.site_observations.includes(m.id));
updateCmp(pose, newMol);
dispatch(updateMoleculeInMolLists(newMol));
dispatch(updateMoleculeInLHSObservations(newMol));
const moleculeTag = getMoleculeTagForTag(tagList, tag.id);
let mtObject = molTagObjects.find(mto => mto.tag === tag.tag);

if (mtObject) {
mtObject.site_observations.push(newMol.id);
} else {
mtObject = createMoleculeTagObject(
tag.tag,
targetId,
tag.category,
DJANGO_CONTEXT.pk,
tagColor,
tag.discourse_url,
[...moleculeTag.site_observations, newMol.id], // molecules:
tag.create_date,
tag.additional_info,
tag.mol_group,
tag.hidden,
tag.tag_prefix,
tag.upload_name
);
molTagObjects.push(mtObject);
}
}
});
if (molTagObjects) {
for (const mto of molTagObjects) {
let molTagObject = { ...mto };
let augMolTagObject = augumentTagObjectWithId(molTagObject, tag.id);
await updateExistingTag(molTagObject, tag.id);
dispatch(updateMoleculeTag(augMolTagObject));
dispatch(updateTag(augMolTagObject));
}
}
} catch (e) {
console.log(e);
//dispatch(setIsErrorDuringTagging(true));
} finally {
// setTaggingInProgress(false);
}
};

const untagObservations = async tag => {
try {
// setTaggingInProgress(true);

let tagColor = DEFAULT_TAG_COLOR;
if (tag.colour && tag.colour !== '') {
tagColor = tag.colour;
} else {
const tagCategory = dispatch(getCategoryById(tag.category));
if (tagCategory) {
tagColor = `#${tagCategory.colour}`;
}
}

let molTagObjects = [];
observationsDataList.forEach(m => {
let newMol = { ...m };
newMol.tags_set = newMol.tags_set.filter(id => id !== tag.id);

const pose = poses.find(p => p.site_observations.includes(m.id));
updateCmp(pose, newMol);
dispatch(updateMoleculeInMolLists(newMol));
dispatch(updateMoleculeInLHSObservations(newMol));
const moleculeTag = getMoleculeTagForTag(tagList, tag.id);
let mtObject = molTagObjects.find(mto => mto.tag === tag.tag);

if (mtObject) {
mtObject.site_observations = mtObject.site_observations.filter(id => id !== m.id);
} else {
let newMolList = [...moleculeTag.site_observations];
newMolList = newMolList.filter(id => id !== m.id);
mtObject = createMoleculeTagObject(
tag.tag,
targetId,
tag.category,
DJANGO_CONTEXT.pk,
tagColor,
tag.discourse_url,
newMolList, // molecules:
tag.create_date,
tag.additional_info,
tag.mol_group,
tag.hidden,
tag.tag_prefix,
tag.upload_name
);
molTagObjects.push(mtObject);
}
});
if (molTagObjects) {
for (const mto of molTagObjects) {
let molTagObject = { ...mto };
let augMolTagObject = augumentTagObjectWithId(molTagObject, tag.id);
await updateExistingTag(molTagObject, tag.id);
dispatch(updateMoleculeTag(augMolTagObject));
dispatch(updateTag(augMolTagObject));
}
}
} catch (e) {
console.log(e);
//dispatch(setIsErrorDuringTagging(true));
} finally {
// setTaggingInProgress(false);
}
};

const getMainTagByCategory = categoryId => {
const firstSelectedObs = observationsDataList[0];
if (firstSelectedObs) {
// console.log('firstSelectedObs?', { ...firstSelectedObs });
const pose = poses.find(pose => pose.id === firstSelectedObs.pose);
const mainObservation = observationsDataList.find(observation => observation.id === pose.main_site_observation);
if (mainObservation) {
// tagList.filter(tag => {

// if (tag.category === categoryId && mainObservation.tags_set.includes(tag.id)) {
// console.log('tag.category', tag.category)
// console.log('categoryId', categoryId)
// console.log('mainObservation.tags_set', mainObservation.tags_set)
// console.log('tag.id', tag.id)
// return true;
// } else {
// return false;
// }
// }).forEach(tag => console.log('in list', { ...tag }));
return tagList.find(tag => tag.category === categoryId && mainObservation.tags_set.includes(tag.id));
}
}
return null;
};

/**
* Change the generated tags for all observations in a pose
*
* @param {*} tag
*/
const handleXCAtagChange = async tag => {
const mainObservationTag = getMainTagByCategory(tag.category);
// do not retag same tag
if (mainObservationTag && mainObservationTag.id === tag.id) return;
// untag first
if (mainObservationTag) {
await untagObservations(mainObservationTag);
}
// then tag
await tagObservations(tag, mainObservationTag);
toastInfo(`Tag for observations was changed from "${mainObservationTag.upload_name}" to "${tag.upload_name}". They could disappear based on your tag selection`, { autoHideDuration: 5000 });
};

return (
<Popper id={id} open={open} anchorEl={anchorEl} placement="left-start" ref={ref}>
<Panel
Expand Down Expand Up @@ -904,6 +1121,32 @@ export const ObservationsDialog = memo(
))}
</Grid>
</Grid>
<Grid item className={classNames({ [classes.dropdown]: true })} style={{ marginRight: 9 }}>
<Button
color="inherit"
variant="text"
size="small"
data-id="manageGrouping"
endIcon={<KeyboardArrowDown />}
className={classNames(classes.contColButton, classes.contColButtonBottomRow)}
>
Change XCA tags
</Button>
<Grid container direction="row" className={classes.dropdownContent}>
{XCA_TAG_CATEGORIES.map(category =>
<Grid key={category} item className={classNames(classes.dropdown, classes.dropdownItem)}>
Change {PLURAL_TO_SINGULAR[category]}
<Grid container direction="row" className={classNames(classes.dropdownContent, classes.dropdownContentSide)}>
{getTagsForCategory(category)?.map(tag => (
<Grid key={tag.id} item className={classes.dropdownItem} onClick={() => handleXCAtagChange(tag)}>
{tag.upload_name}
</Grid>
))}
</Grid>
</Grid>
)}
</Grid>
</Grid>
</Grid>
</Grid>
)}
Expand Down
Loading

0 comments on commit b32a185

Please sign in to comment.