Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#1522, #1518 #455

Merged
merged 20 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
d651036
Squashed commit of the following:
boriskovar-m2ms Jul 31, 2024
8817d77
#1482 added TagName and CentroidRes columns for expanded view of obse…
matej-vavrek Aug 22, 2024
6af83d0
#1489 show warning toast message if is defined on target load
matej-vavrek Aug 27, 2024
5db8ab0
#1322 added longcode column
matej-vavrek Sep 4, 2024
c7c010d
updated general function for tag comparison
matej-vavrek Sep 5, 2024
63d44d6
Merge branch 'staging' into stagingcandidate
boriskovar-m2ms Sep 5, 2024
1b24e2a
#1505 adjusted getting of centroid_res
matej-vavrek Sep 5, 2024
fc9cd3e
#1458 allow to tag XCA sites, temp commit
matej-vavrek Jul 10, 2024
449eaa6
#1458 adjusted functionality and styling to proper change tag
matej-vavrek Sep 4, 2024
7193616
#1508 removed TagName column in expanded observation dialog, changed …
matej-vavrek Sep 12, 2024
da9ea84
Merge branch 'staging' into stagingcandidate
matej-vavrek Sep 12, 2024
12f8391
#1508 adjusted column order and width calculation
matej-vavrek Sep 13, 2024
f812106
Merge branch 'staging' into stagingcandidate
matej-vavrek Sep 13, 2024
e6b563b
#1501 added upload links to menu
matej-vavrek Sep 17, 2024
b24340d
#1520 show tag alias instead of upload_name on hit navigator CanonSit…
matej-vavrek Sep 25, 2024
dedd836
#1519 keep tag in edit window after save
matej-vavrek Sep 25, 2024
238b5c2
#1497 added Path column for extended view of observations
matej-vavrek Sep 30, 2024
cdbb897
#1518 properly remove tag from list after updating its object
matej-vavrek Oct 10, 2024
37b885d
#1522 allow to change XCA tags for selections but not for CanonSite
matej-vavrek Oct 10, 2024
4d8ea0c
#1463 initial implementation of new sort options for hit navigator
matej-vavrek Oct 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions js/components/header/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ import { AddProjectDetail } from '../projects/addProjectDetail';
import { ServicesStatusWrapper } from '../services';
import { COMPANIES, get_logo } from '../funders/constants';
import { setEditTargetDialogOpen } from '../target/redux/actions';
import { Upload } from '@mui/icons-material';

const useStyles = makeStyles(theme => ({
padding: {
Expand Down Expand Up @@ -272,8 +273,8 @@ export default memo(
targetName !== undefined ? (
<>
{currentProject.authorID === null ||
currentProject.projectID === null ||
currentProject.authorID === userId ? (
currentProject.projectID === null ||
currentProject.authorID === userId ? (
<Button
onClick={() => {
isProjectModalLoading === false
Expand Down Expand Up @@ -574,6 +575,29 @@ export default memo(
</ListItemIcon>
<ListItemText primary="Contributors" />
</ListItem>
{DJANGO_CONTEXT.pk &&
<>
<Divider />
<ListItem button onClick={() => openLink(URLS.lhsUpload)}>
<ListItemIcon>
<Upload />
</ListItemIcon>
<ListItemText primary="LHS upload" />
</ListItem>
<ListItem button onClick={() => openLink(URLS.rhsUpload)}>
<ListItemIcon>
<Upload />
</ListItemIcon>
<ListItemText primary="RHS upload" />
</ListItem>
<ListItem button onClick={() => openLink(URLS.metadataUpload)}>
<ListItemIcon>
<Upload />
</ListItemIcon>
<ListItemText primary="Metadata upload" />
</ListItem>
</>
}
<Divider />
{authListItem}
</Grid>
Expand Down
46 changes: 40 additions & 6 deletions js/components/preview/molecule/moleculeView/moleculeView.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ import { DJANGO_CONTEXT } from '../../../../utils/djangoContext';
import { getFontColorByBackgroundColor } from '../../../../utils/colors';
import { api, METHOD } from '../../../../utils/api';
import { base_url } from '../../../routes/constants';
import { ContentCopyRounded } from '@mui/icons-material';
import { ToastContext } from '../../../toast';

const useStyles = makeStyles(theme => ({
container: {
Expand Down Expand Up @@ -358,6 +360,8 @@ export const img_data_init = `<svg xmlns="http://www.w3.org/2000/svg" version="1
<animateTransform attributeName="transform" type="rotate" repeatCount="indefinite" dur="0.689655172413793s" values="0 50 50;360 50 50" keyTimes="0;1"></animateTransform>
</circle> '</svg>`;

export const XCA_TAGS_CATEGORIES = ['CanonSites', 'ConformerSites', 'Quatassemblies', 'Crystalforms', 'CrystalformSites'];

const MoleculeView = memo(
({
imageHeight,
Expand Down Expand Up @@ -409,6 +413,7 @@ const MoleculeView = memo(
const [tagEditModalOpenNew, setTagEditModalOpenNew] = useState(tagEditorOpenObs);

const { getNglView } = useContext(NglContext);
const { toastInfo } = useContext(ToastContext);
const stage = getNglView(VIEWS.MAJOR_VIEW) && getNglView(VIEWS.MAJOR_VIEW).stage;

const isLigandOn = L;
Expand Down Expand Up @@ -463,6 +468,7 @@ const MoleculeView = memo(
const [moleculeTooltipOpen, setMoleculeTooltipOpen] = useState(false);
const [tagPopoverOpen, setTagPopoverOpen] = useState(null);
const [centroidRes, setCentroidRes] = useState('');
const [experimentalPath, setExperimentalPath] = useState('');

const moleculeImgRef = useRef(null);

Expand All @@ -476,9 +482,6 @@ const MoleculeView = memo(
setTagEditModalOpenNew(tagEditorOpenObs);
}, [tagEditorOpenObs]);

const XCA_TAGS_CATEGORIES = ['CanonSites', 'ConformerSites', 'Quatassemblies', 'Crystalforms', 'CrystalformSites'];
const XCA_TAGS_CATEGORIES_EXPANDED = ['Quatassemblies', 'ConformerSites', 'Crystalforms', 'CrystalformSites', 'CanonSites'];

useEffect(() => {
api({
url: `${base_url}/api/canon_site_confs/`,
Expand Down Expand Up @@ -515,6 +518,26 @@ const MoleculeView = memo(
});
}, [data.canon_site_conf]);

useEffect(() => {
api({
url: `${base_url}/api/experiments/`,
method: METHOD.GET
})
.then(resp => {
const experiment = resp.data.results.find(experiment => experiment.id === data.experiment);
if (experiment) {
setExperimentalPath(experiment.pdb_info_source_file ?? '');
} else {
console.log('there is not any matching canonSiteConf object with ' + data.experiment + ' id');
setExperimentalPath('');
}
})
.catch(err => {
console.log('error fetching experiment from experiments api', err);
setExperimentalPath('');
});
}, [data.experiment]);

useEffect(() => {
if (showExpandedView) {
setHeaderWidthsHandler(centroidRes, 'CentroidRes');
Expand All @@ -523,7 +546,7 @@ const MoleculeView = memo(
setHeaderWidthsHandler(getTagLabel(tagCategory), tagCategory);
})
}
}, [showExpandedView, getTagType, getTagLabel, centroidRes, data.longcode, setHeaderWidthsHandler, XCA_TAGS_CATEGORIES]);
}, [showExpandedView, getTagType, getTagLabel, centroidRes, data.longcode, setHeaderWidthsHandler]);

const handlePopoverOpen = event => {
setTagPopoverOpen(event.currentTarget);
Expand Down Expand Up @@ -1135,6 +1158,11 @@ const MoleculeView = memo(
return tagTooltip;
}, [getTagType]);

const copyExperimentalPaths = async () => {
await navigator.clipboard.writeText(experimentalPath);
toastInfo('Link was copied to the clipboard', { autoHideDuration: 5000 });
};

return (
<>
<Grid
Expand Down Expand Up @@ -1428,7 +1456,6 @@ const MoleculeView = memo(
xs={5}
container
direction="row"
justifyContent="center"
alignItems="center"
// wrap="nowrap"
style={{ height: "100%" }}
Expand Down Expand Up @@ -1488,7 +1515,7 @@ const MoleculeView = memo(
</div>}
</Grid>
{showExpandedView && <Grid item container alignItems='center' wrap="nowrap">
{XCA_TAGS_CATEGORIES_EXPANDED.map((tagCategory, index) => {
{XCA_TAGS_CATEGORIES.map((tagCategory, index) => {
return <Tooltip title={`${PLURAL_TO_SINGULAR[tagCategory]} - ${getTagTooltip(tagCategory)}`} key={index}>
<Grid item align="center" className={classes.categoryCell} style={{ minWidth: headerWidths[tagCategory] }}>
{getTagLabel(tagCategory)}
Expand All @@ -1505,6 +1532,13 @@ const MoleculeView = memo(
{data.longcode}
</Grid>
</Tooltip>
<Tooltip title={experimentalPath.length > 0 ? experimentalPath : 'empty path'}>
<Grid item align="center" style={{ minWidth: headerWidths.Path }}>
<IconButton color="inherit" onClick={copyExperimentalPaths} size="small">
<ContentCopyRounded fontSize="small" />
</IconButton>
</Grid>
</Tooltip>
</Grid>}
</Grid >
<SvgTooltip
Expand Down
123 changes: 118 additions & 5 deletions js/components/preview/molecule/observationCmpList.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ import {
Divider,
Typography,
IconButton,
ButtonGroup
ButtonGroup,
Select,
MenuItem,
Checkbox
} from '@material-ui/core';
import React, { useState, useEffect, useCallback, memo, useRef, useContext, useMemo } from 'react';
import { useDispatch, useSelector } from 'react-redux';
Expand Down Expand Up @@ -321,6 +324,89 @@ export const ObservationCmpList = memo(({ hideProjects }) => {

const [predefinedFilter, setPredefinedFilter] = useState(filter !== undefined ? filter.predefined : DEFAULT_FILTER);

const [ascending, setAscending] = useState(true);
const handleAscendingChecked = (event) => setAscending(event.target.checked);
const SORT_OPTIONS = [
'POSE_NAME',
'COMPOUND_CODE',
'CANONSITE_NUMBER',
'CONFORMERSITE_NUMBER',
'OBSERVATION_COUNT'
];
const sortOptions = {
POSE_NAME: {
title: 'Pose name',
handler: (a, b, asc) => compareByPoseName(a, b, asc)
},
COMPOUND_CODE: {
title: 'Compound code',
handler: (a, b, asc) => compareByCompoundCode(a, b, asc)
},
CANONSITE_NUMBER: {
title: 'CanonSite number',
handler: (a, b, asc) => compareByCanonSiteNumber(a, b, asc)
},
CONFORMERSITE_NUMBER: {
title: 'ConformerSite number',
handler: (a, b, asc) => compareByConformerSiteNumber(a, b, asc)
},
OBSERVATION_COUNT: {
title: 'Observation count',
handler: (a, b, asc) => compareByObservationCount(a, b, asc)
}
};
const [sortOption, setSortOption] = useState(SORT_OPTIONS[0]);

const compareByPoseName = (a, b, asc) => {
const aName = a.code;
const bName = b.code;
return asc ? aName.localeCompare(bName, undefined, { numeric: true, sensitivity: 'base' })
: bName.localeCompare(aName, undefined, { numeric: true, sensitivity: 'base' });
};
const compareByCompoundCode = (a, b, asc) => {
const aName = a.main_site_observation_cmpd_code;
const bName = b.main_site_observation_cmpd_code;
return asc ? aName.localeCompare(bName, undefined, { numeric: true, sensitivity: 'base' })
: bName.localeCompare(aName, undefined, { numeric: true, sensitivity: 'base' });
};
const compareByCanonSiteNumber = (a, b, asc) => {
const aName = getCanonSiteTagPrefix(a);
const bName = getCanonSiteTagPrefix(b);
return asc ? aName.localeCompare(bName, undefined, { numeric: true, sensitivity: 'base' })
: bName.localeCompare(aName, undefined, { numeric: true, sensitivity: 'base' });
};
const compareByConformerSiteNumber = (a, b, asc) => {
const aName = getConformerSiteTagPrefix(a);
const bName = getConformerSiteTagPrefix(b);
return asc ? aName.localeCompare(bName, undefined, { numeric: true, sensitivity: 'base' })
: bName.localeCompare(aName, undefined, { numeric: true, sensitivity: 'base' });
};
const compareByObservationCount = (a, b, asc) => {
const aCount = a.site_observations.length;
const bCount = b.site_observations.length;
return asc ? aCount - bCount : bCount - aCount;
};

/**
* Get CanonSites tag for sorting
*/
const getCanonSiteTagPrefix = useCallback(pose => {
const mainObservation = pose.associatedObs.find(observation => observation.id === pose.main_site_observation);
const canonSitesTag = categories.find(tagCategory => tagCategory.category === 'CanonSites');
const canonSite = tags.find(tag => tag.category === canonSitesTag.id && tag.site_observations.includes(mainObservation.id));
return canonSite !== undefined ? canonSite.tag_prefix : '';
}, [categories, tags]);

/**
* Get ConformerSites tag for sorting
*/
const getConformerSiteTagPrefix = useCallback(pose => {
const mainObservation = pose.associatedObs.find(observation => observation.id === pose.main_site_observation);
const conformerSitesTag = categories.find(tagCategory => tagCategory.category === 'ConformerSites');
const conformerSite = tags.find(tag => tag.category === conformerSitesTag.id && tag.site_observations.includes(mainObservation.id));
return conformerSite !== undefined ? conformerSite.tag_prefix : '';
}, [categories, tags]);

const isActiveFilter = !!(filter || {}).active;

const { getNglView } = useContext(NglContext);
Expand Down Expand Up @@ -718,8 +804,9 @@ export const ObservationCmpList = memo(({ hideProjects }) => {
compounds.push(compound);
}
});
compounds.sort((a, b) => sortOptions[sortOption].handler(a, b, ascending));
return compounds;
}, [joinedMoleculeLists, lhsCompoundsList]);
}, [joinedMoleculeLists, lhsCompoundsList, sortOptions, sortOption, ascending]);

useEffect(() => {
if (isObservationDialogOpen && observationsForLHSCmp?.length > 0) {
Expand Down Expand Up @@ -1113,7 +1200,7 @@ export const ObservationCmpList = memo(({ hideProjects }) => {

{
<Tooltip title={selectAllHitsPressed ? 'Unselect all hits' : 'Select all hits'}>
<Grid item style={{ marginLeft: '20px' }}>
<Grid item style={{ marginLeft: '5px' }}>
<Button
variant="outlined"
className={classNames(classes.contColButton, {
Expand All @@ -1133,7 +1220,7 @@ export const ObservationCmpList = memo(({ hideProjects }) => {
}
{selectedDisplayHits === true ? (
<Tooltip title={'Unselect displayed hits'}>
<Grid item style={{ marginLeft: '20px' }}>
<Grid item style={{ marginLeft: '5px' }}>
<Button
variant="outlined"
className={classNames(classes.contColButton, {
Expand All @@ -1152,7 +1239,7 @@ export const ObservationCmpList = memo(({ hideProjects }) => {
</Tooltip>
) : (
<Tooltip title={'Select displayed hits'}>
<Grid item style={{ marginLeft: '20px' }}>
<Grid item style={{ marginLeft: '5px' }}>
<Button
variant="outlined"
className={classNames(classes.contColButton, {
Expand All @@ -1174,6 +1261,32 @@ export const ObservationCmpList = memo(({ hideProjects }) => {
<Typography variant="caption" className={classes.noOfSelectedHits}>{`Selected: ${allSelectedMolecules ? allSelectedMolecules.length : 0
}`}</Typography>
</Grid>
<Grid style={{ marginTop: '4px' }}>
<Typography variant="caption" className={classes.noOfSelectedHits}>Sort by</Typography>
</Grid>
<Grid style={{ marginTop: '4px', marginLeft: '4px' }}>
<Tooltip title={sortOption ? sortOptions[sortOption].title : "Sort by"}>
<Select
value={sortOption}
onChange={(event) => setSortOption(event.target.value)}
// fullWidth
size="small"
style={{ fontSize: 10, width: 75 }}
>
{SORT_OPTIONS.map((option, index) => (
<MenuItem key={`${index}-${option}`} value={option} style={{ fontSize: 12, padding: '3px 7px' }}>
{sortOptions[option].title}
</MenuItem>
))}
</Select>
</Tooltip>
</Grid>
<Tooltip title={ascending ? "Ascending" : "Descending"}>
<Grid style={{ marginTop: '4px' }}>
<Checkbox checked={ascending} onChange={handleAscendingChecked} size="small" style={{ padding: 3 }} />
<Typography variant="caption" className={classes.noOfSelectedHits}>ASC</Typography>
</Grid>
</Tooltip>
</Grid>
<Grid container spacing={1} direction="column" justifyContent="flex-start" className={classes.container}>
<Grid item>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1611,7 +1611,7 @@ const ObservationCmpView = memo(
{/* CanonSites */}
<Grid item xs container direction="column" justifyContent="center" alignItems="stretch" wrap="nowrap">
<Tooltip
title={<div style={{ whiteSpace: 'pre-line' }}>CanonSite - {getCanonSitesTag().upload_name}</div>}
title={<div style={{ whiteSpace: 'pre-line' }}>CanonSite - {getCanonSitesTag().tag}</div>}
>
<Grid
item
Expand All @@ -1631,7 +1631,7 @@ const ObservationCmpView = memo(
{getConformerSites().map((conformerSite, i, sites) => (
<Tooltip
key={conformerSite.id + i}
title={<div style={{ whiteSpace: 'pre-line' }}>ConformerSite - {conformerSite.upload_name}</div>}
title={<div style={{ whiteSpace: 'pre-line' }}>ConformerSite - {conformerSite.tag}</div>}
>
<Grid
item
Expand Down
Loading