Skip to content

Commit a4ecd71

Browse files
mwinokanboriskovar-m2msmatej-vavrek
authored
Merge staging changes into production for 2024.11.1 (#458)
* 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 * #1508 removed TagName column in expanded observation dialog, changed order of columns, adjusted labels and tooltips, show observation dialog in its full height * #1508 adjusted column order and width calculation * #1501 added upload links to menu * #1501 (#451) * 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 * #1508 removed TagName column in expanded observation dialog, changed order of columns, adjusted labels and tooltips, show observation dialog in its full height * #1508 adjusted column order and width calculation * #1501 added upload links to menu --------- Co-authored-by: Boris Kovar <boris.kovar@m2ms.sk> * #1520 show tag alias instead of upload_name on hit navigator CanonSites & ConformerSites box tooltip * #1519 keep tag in edit window after save * #1519 and #1520 (#453) * 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 * #1508 removed TagName column in expanded observation dialog, changed order of columns, adjusted labels and tooltips, show observation dialog in its full height * #1508 adjusted column order and width calculation * #1501 added upload links to menu * #1520 show tag alias instead of upload_name on hit navigator CanonSites & ConformerSites box tooltip * #1519 keep tag in edit window after save --------- Co-authored-by: Boris Kovar <boris.kovar@m2ms.sk> * #1497 added Path column for extended view of observations * #1497 (#454) * 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 * #1508 removed TagName column in expanded observation dialog, changed order of columns, adjusted labels and tooltips, show observation dialog in its full height * #1508 adjusted column order and width calculation * #1501 added upload links to menu * #1520 show tag alias instead of upload_name on hit navigator CanonSites & ConformerSites box tooltip * #1519 keep tag in edit window after save * #1497 added Path column for extended view of observations --------- Co-authored-by: Boris Kovar <boris.kovar@m2ms.sk> * #1518 properly remove tag from list after updating its object * #1522 allow to change XCA tags for selections but not for CanonSite * #1463 initial implementation of new sort options for hit navigator * #1514 (#456) * #1514 replaced project_id occurrences with project and adjusted functionality with current B/E * #1514 added target_access_string to /api/download_structures, replaced /api/molgroup with /api/siteobservationgroup, minor fixes * #1523 #1463 (#457) * #1514 replaced project_id occurrences with project and adjusted functionality with current B/E * #1514 added target_access_string to /api/download_structures, replaced /api/molgroup with /api/siteobservationgroup, minor fixes * #1523 adjusted inspiration dialog layout and removed molecular properties headers from it too * #1463 show "Ascending" instead of "ASC" when there is a possible space for it * removed unnecessary setter and comments --------- Co-authored-by: Boris Kovar <boris.kovar@m2ms.sk> Co-authored-by: matej <matej.vavrek@m2ms.sk> Co-authored-by: matej <60509086+matej-vavrek@users.noreply.github.com>
1 parent df41858 commit a4ecd71

File tree

17 files changed

+334
-106
lines changed

17 files changed

+334
-106
lines changed

js/components/datasets/inspirationDialog.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ import GroupNglControlButtonsContext from '../preview/molecule/groupNglControlBu
3232

3333
const useStyles = makeStyles(theme => ({
3434
paper: {
35-
width: 472,
36-
height: 294,
35+
width: 505,
36+
// height: 294,
3737
overflowY: 'hidden'
3838
},
3939
molHeader: {
@@ -382,11 +382,11 @@ export const InspirationDialog = memo(
382382
<>
383383
<Grid container justifyContent="flex-start" direction="row" className={classes.molHeader} wrap="nowrap">
384384
<Grid item container justifyContent="flex-start" direction="row">
385-
{Object.keys(moleculeProperty).map(key => (
385+
{/* {Object.keys(moleculeProperty).map(key => (
386386
<Grid item key={key} className={classes.rightBorder}>
387387
{moleculeProperty[key]}
388388
</Grid>
389-
))}
389+
))} */}
390390
{allSelectedMolecules.length > 0 && (
391391
<Grid item>
392392
<Grid

js/components/preview/molecule/moleculeView/moleculeView.js

+38-2
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ import { DJANGO_CONTEXT } from '../../../../utils/djangoContext';
5858
import { getFontColorByBackgroundColor } from '../../../../utils/colors';
5959
import { api, METHOD } from '../../../../utils/api';
6060
import { base_url } from '../../../routes/constants';
61+
import { ContentCopyRounded } from '@mui/icons-material';
62+
import { ToastContext } from '../../../toast';
6163

6264
const useStyles = makeStyles(theme => ({
6365
container: {
@@ -145,7 +147,7 @@ const useStyles = makeStyles(theme => ({
145147
image: {
146148
border: 'solid 1px',
147149
borderColor: theme.palette.background.divider,
148-
borderStyle: 'solid solid solid none',
150+
borderStyle: 'none none none solid',
149151
position: 'relative'
150152
},
151153
imageMargin: {
@@ -411,6 +413,7 @@ const MoleculeView = memo(
411413
const [tagEditModalOpenNew, setTagEditModalOpenNew] = useState(tagEditorOpenObs);
412414

413415
const { getNglView } = useContext(NglContext);
416+
const { toastInfo } = useContext(ToastContext);
414417
const stage = getNglView(VIEWS.MAJOR_VIEW) && getNglView(VIEWS.MAJOR_VIEW).stage;
415418

416419
const isLigandOn = L;
@@ -465,6 +468,7 @@ const MoleculeView = memo(
465468
const [moleculeTooltipOpen, setMoleculeTooltipOpen] = useState(false);
466469
const [tagPopoverOpen, setTagPopoverOpen] = useState(null);
467470
const [centroidRes, setCentroidRes] = useState('');
471+
const [experimentalPath, setExperimentalPath] = useState('');
468472

469473
const moleculeImgRef = useRef(null);
470474

@@ -514,6 +518,26 @@ const MoleculeView = memo(
514518
});
515519
}, [data.canon_site_conf]);
516520

521+
useEffect(() => {
522+
api({
523+
url: `${base_url}/api/experiments/`,
524+
method: METHOD.GET
525+
})
526+
.then(resp => {
527+
const experiment = resp.data.results.find(experiment => experiment.id === data.experiment);
528+
if (experiment) {
529+
setExperimentalPath(experiment.pdb_info_source_file ?? '');
530+
} else {
531+
console.log('there is not any matching canonSiteConf object with ' + data.experiment + ' id');
532+
setExperimentalPath('');
533+
}
534+
})
535+
.catch(err => {
536+
console.log('error fetching experiment from experiments api', err);
537+
setExperimentalPath('');
538+
});
539+
}, [data.experiment]);
540+
517541
useEffect(() => {
518542
if (showExpandedView) {
519543
setHeaderWidthsHandler(centroidRes, 'CentroidRes');
@@ -1134,6 +1158,11 @@ const MoleculeView = memo(
11341158
return tagTooltip;
11351159
}, [getTagType]);
11361160

1161+
const copyExperimentalPaths = async () => {
1162+
await navigator.clipboard.writeText(experimentalPath);
1163+
toastInfo('Link was copied to the clipboard', { autoHideDuration: 5000 });
1164+
};
1165+
11371166
return (
11381167
<>
11391168
<Grid
@@ -1174,7 +1203,7 @@ const MoleculeView = memo(
11741203
</Grid>
11751204
<Grid item container className={classes.detailsCol} justifyContent="space-between" direction="row">
11761205
<Grid item container direction="column" alignItems="center" xs>
1177-
<Grid item container justifyContent="flex-start" alignItems="center" direction="row">
1206+
<Grid item container justifyContent="flex-start" alignItems="center" direction="row" xs>
11781207
<Grid item container justifyContent="space-between" direction="column" xs={3}>
11791208
{/* Title label */}
11801209
<Tooltip title={data.prefix_tooltip ?? '-' + (data.id === pose?.main_site_observation ? " - main observation" : "")} placement="bottom-start">
@@ -1503,6 +1532,13 @@ const MoleculeView = memo(
15031532
{data.longcode}
15041533
</Grid>
15051534
</Tooltip>
1535+
<Tooltip title={experimentalPath.length > 0 ? experimentalPath : 'empty path'}>
1536+
<Grid item align="center" style={{ minWidth: headerWidths.Path }}>
1537+
<IconButton color="inherit" onClick={copyExperimentalPaths} size="small">
1538+
<ContentCopyRounded fontSize="small" />
1539+
</IconButton>
1540+
</Grid>
1541+
</Tooltip>
15061542
</Grid>}
15071543
</Grid >
15081544
<SvgTooltip

js/components/preview/molecule/observationCmpList.js

+142-7
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ import {
1010
Divider,
1111
Typography,
1212
IconButton,
13-
ButtonGroup
13+
ButtonGroup,
14+
Select,
15+
MenuItem,
16+
Checkbox
1417
} from '@material-ui/core';
1518
import React, { useState, useEffect, useCallback, memo, useRef, useContext, useMemo } from 'react';
1619
import { useDispatch, useSelector } from 'react-redux';
@@ -222,6 +225,9 @@ const useStyles = makeStyles(theme => ({
222225
//color: theme.palette.black
223226
}
224227
},
228+
selectButton: {
229+
padding: '4px 2px !important'
230+
},
225231
formControl: {
226232
color: 'inherit',
227233
margin: theme.spacing(1),
@@ -321,6 +327,89 @@ export const ObservationCmpList = memo(({ hideProjects }) => {
321327

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

330+
const [ascending, setAscending] = useState(true);
331+
const handleAscendingChecked = (event) => setAscending(event.target.checked);
332+
const SORT_OPTIONS = [
333+
'POSE_NAME',
334+
'COMPOUND_CODE',
335+
'CANONSITE_NUMBER',
336+
'CONFORMERSITE_NUMBER',
337+
'OBSERVATION_COUNT'
338+
];
339+
const sortOptions = {
340+
POSE_NAME: {
341+
title: 'Pose name',
342+
handler: (a, b, asc) => compareByPoseName(a, b, asc)
343+
},
344+
COMPOUND_CODE: {
345+
title: 'Compound code',
346+
handler: (a, b, asc) => compareByCompoundCode(a, b, asc)
347+
},
348+
CANONSITE_NUMBER: {
349+
title: 'CanonSite number',
350+
handler: (a, b, asc) => compareByCanonSiteNumber(a, b, asc)
351+
},
352+
CONFORMERSITE_NUMBER: {
353+
title: 'ConformerSite number',
354+
handler: (a, b, asc) => compareByConformerSiteNumber(a, b, asc)
355+
},
356+
OBSERVATION_COUNT: {
357+
title: 'Observation count',
358+
handler: (a, b, asc) => compareByObservationCount(a, b, asc)
359+
}
360+
};
361+
const [sortOption, setSortOption] = useState(SORT_OPTIONS[0]);
362+
363+
const compareByPoseName = (a, b, asc) => {
364+
const aName = a.code;
365+
const bName = b.code;
366+
return asc ? aName.localeCompare(bName, undefined, { numeric: true, sensitivity: 'base' })
367+
: bName.localeCompare(aName, undefined, { numeric: true, sensitivity: 'base' });
368+
};
369+
const compareByCompoundCode = (a, b, asc) => {
370+
const aName = a.main_site_observation_cmpd_code;
371+
const bName = b.main_site_observation_cmpd_code;
372+
return asc ? aName.localeCompare(bName, undefined, { numeric: true, sensitivity: 'base' })
373+
: bName.localeCompare(aName, undefined, { numeric: true, sensitivity: 'base' });
374+
};
375+
const compareByCanonSiteNumber = (a, b, asc) => {
376+
const aName = getCanonSiteTagPrefix(a);
377+
const bName = getCanonSiteTagPrefix(b);
378+
return asc ? aName.localeCompare(bName, undefined, { numeric: true, sensitivity: 'base' })
379+
: bName.localeCompare(aName, undefined, { numeric: true, sensitivity: 'base' });
380+
};
381+
const compareByConformerSiteNumber = (a, b, asc) => {
382+
const aName = getConformerSiteTagPrefix(a);
383+
const bName = getConformerSiteTagPrefix(b);
384+
return asc ? aName.localeCompare(bName, undefined, { numeric: true, sensitivity: 'base' })
385+
: bName.localeCompare(aName, undefined, { numeric: true, sensitivity: 'base' });
386+
};
387+
const compareByObservationCount = (a, b, asc) => {
388+
const aCount = a.site_observations.length;
389+
const bCount = b.site_observations.length;
390+
return asc ? aCount - bCount : bCount - aCount;
391+
};
392+
393+
/**
394+
* Get CanonSites tag for sorting
395+
*/
396+
const getCanonSiteTagPrefix = useCallback(pose => {
397+
const mainObservation = pose.associatedObs.find(observation => observation.id === pose.main_site_observation);
398+
const canonSitesTag = categories.find(tagCategory => tagCategory.category === 'CanonSites');
399+
const canonSite = tags.find(tag => tag.category === canonSitesTag.id && tag.site_observations.includes(mainObservation.id));
400+
return canonSite !== undefined ? canonSite.tag_prefix : '';
401+
}, [categories, tags]);
402+
403+
/**
404+
* Get ConformerSites tag for sorting
405+
*/
406+
const getConformerSiteTagPrefix = useCallback(pose => {
407+
const mainObservation = pose.associatedObs.find(observation => observation.id === pose.main_site_observation);
408+
const conformerSitesTag = categories.find(tagCategory => tagCategory.category === 'ConformerSites');
409+
const conformerSite = tags.find(tag => tag.category === conformerSitesTag.id && tag.site_observations.includes(mainObservation.id));
410+
return conformerSite !== undefined ? conformerSite.tag_prefix : '';
411+
}, [categories, tags]);
412+
324413
const isActiveFilter = !!(filter || {}).active;
325414

326415
const { getNglView } = useContext(NglContext);
@@ -330,10 +419,29 @@ export const ObservationCmpList = memo(({ hideProjects }) => {
330419
const filterRef = useRef();
331420
const tagEditorRef = useRef();
332421
const scrollBarRef = useRef();
422+
const hitNavigatorRef = useRef();
333423
const [tagEditorAnchorEl, setTagEditorAnchorEl] = useState(null);
424+
const [hitNavigatorWidth, setHitNavigatorWidth] = useState(0);
334425

335426
const areLSHCompoundsInitialized = useSelector(state => state.selectionReducers.areLSHCompoundsInitialized);
336427

428+
useEffect(() => {
429+
if (hitNavigatorRef && hitNavigatorRef.current) {
430+
431+
const resizeObserver = new ResizeObserver(() => {
432+
if (hitNavigatorRef.current.offsetWidth !== hitNavigatorWidth) {
433+
setHitNavigatorWidth(hitNavigatorRef.current.offsetWidth);
434+
}
435+
});
436+
437+
resizeObserver.observe(hitNavigatorRef.current);
438+
439+
return function cleanup() {
440+
resizeObserver.disconnect();
441+
}
442+
}
443+
}, [hitNavigatorRef, hitNavigatorWidth]);
444+
337445
if (directDisplay && directDisplay.target) {
338446
target = directDisplay.target;
339447
}
@@ -718,8 +826,9 @@ export const ObservationCmpList = memo(({ hideProjects }) => {
718826
compounds.push(compound);
719827
}
720828
});
829+
compounds.sort((a, b) => sortOptions[sortOption].handler(a, b, ascending));
721830
return compounds;
722-
}, [joinedMoleculeLists, lhsCompoundsList]);
831+
}, [joinedMoleculeLists, lhsCompoundsList, sortOptions, sortOption, ascending]);
723832

724833
useEffect(() => {
725834
if (isObservationDialogOpen && observationsForLHSCmp?.length > 0) {
@@ -973,7 +1082,7 @@ export const ObservationCmpList = memo(({ hideProjects }) => {
9731082
};
9741083

9751084
return (
976-
<Panel hasHeader title="Hit navigator" headerActions={actions}>
1085+
<Panel hasHeader title="Hit navigator" headerActions={actions} ref={hitNavigatorRef}>
9771086
<AlertModal
9781087
title="Are you sure?"
9791088
description={`Loading of ${joinedMoleculeLists?.length} may take a long time`}
@@ -1113,7 +1222,7 @@ export const ObservationCmpList = memo(({ hideProjects }) => {
11131222

11141223
{
11151224
<Tooltip title={selectAllHitsPressed ? 'Unselect all hits' : 'Select all hits'}>
1116-
<Grid item style={{ marginLeft: '20px' }}>
1225+
<Grid item style={{ marginLeft: '2px' }} className={classes.selectButton}>
11171226
<Button
11181227
variant="outlined"
11191228
className={classNames(classes.contColButton, {
@@ -1133,7 +1242,7 @@ export const ObservationCmpList = memo(({ hideProjects }) => {
11331242
}
11341243
{selectedDisplayHits === true ? (
11351244
<Tooltip title={'Unselect displayed hits'}>
1136-
<Grid item style={{ marginLeft: '20px' }}>
1245+
<Grid item className={classes.selectButton}>
11371246
<Button
11381247
variant="outlined"
11391248
className={classNames(classes.contColButton, {
@@ -1152,7 +1261,7 @@ export const ObservationCmpList = memo(({ hideProjects }) => {
11521261
</Tooltip>
11531262
) : (
11541263
<Tooltip title={'Select displayed hits'}>
1155-
<Grid item style={{ marginLeft: '20px' }}>
1264+
<Grid item className={classes.selectButton}>
11561265
<Button
11571266
variant="outlined"
11581267
className={classNames(classes.contColButton, {
@@ -1171,9 +1280,35 @@ export const ObservationCmpList = memo(({ hideProjects }) => {
11711280
</Tooltip>
11721281
)}
11731282
<Grid style={{ marginTop: '4px' }}>
1174-
<Typography variant="caption" className={classes.noOfSelectedHits}>{`Selected: ${allSelectedMolecules ? allSelectedMolecules.length : 0
1283+
<Typography variant="caption">{`Selected: ${allSelectedMolecules ? allSelectedMolecules.length : 0
11751284
}`}</Typography>
11761285
</Grid>
1286+
<Grid style={{ marginTop: '4px' }}>
1287+
<Typography variant="caption" style={{ paddingLeft: 3 }}>Sort by</Typography>
1288+
</Grid>
1289+
<Grid style={{ marginTop: '4px', marginLeft: '4px' }}>
1290+
<Tooltip title={sortOption ? sortOptions[sortOption].title : "Sort by"}>
1291+
<Select
1292+
value={sortOption}
1293+
onChange={(event) => setSortOption(event.target.value)}
1294+
// fullWidth
1295+
size="small"
1296+
style={{ fontSize: 10, width: 75 }}
1297+
>
1298+
{SORT_OPTIONS.map((option, index) => (
1299+
<MenuItem key={`${index}-${option}`} value={option} style={{ fontSize: 12, padding: '3px 7px' }}>
1300+
{sortOptions[option].title}
1301+
</MenuItem>
1302+
))}
1303+
</Select>
1304+
</Tooltip>
1305+
</Grid>
1306+
<Tooltip title={ascending ? "Ascending" : "Descending"}>
1307+
<Grid style={{ marginTop: '4px' }}>
1308+
<Checkbox checked={ascending} onChange={handleAscendingChecked} size="small" style={{ padding: 0 }} />
1309+
<Typography variant="caption">{(selectAllHitsPressed && hitNavigatorWidth > 508) || (!selectAllHitsPressed && hitNavigatorWidth > 491) ? 'Ascending' : 'ASC'}</Typography>
1310+
</Grid>
1311+
</Tooltip>
11771312
</Grid>
11781313
<Grid container spacing={1} direction="column" justifyContent="flex-start" className={classes.container}>
11791314
<Grid item>

js/components/preview/molecule/observationCmpView/observationCmpView.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1611,7 +1611,7 @@ const ObservationCmpView = memo(
16111611
{/* CanonSites */}
16121612
<Grid item xs container direction="column" justifyContent="center" alignItems="stretch" wrap="nowrap">
16131613
<Tooltip
1614-
title={<div style={{ whiteSpace: 'pre-line' }}>CanonSite - {getCanonSitesTag().upload_name}</div>}
1614+
title={<div style={{ whiteSpace: 'pre-line' }}>CanonSite - {getCanonSitesTag().tag}</div>}
16151615
>
16161616
<Grid
16171617
item
@@ -1631,7 +1631,7 @@ const ObservationCmpView = memo(
16311631
{getConformerSites().map((conformerSite, i, sites) => (
16321632
<Tooltip
16331633
key={conformerSite.id + i}
1634-
title={<div style={{ whiteSpace: 'pre-line' }}>ConformerSite - {conformerSite.upload_name}</div>}
1634+
title={<div style={{ whiteSpace: 'pre-line' }}>ConformerSite - {conformerSite.tag}</div>}
16351635
>
16361636
<Grid
16371637
item

0 commit comments

Comments
 (0)