Skip to content

Commit

Permalink
add selectedMOIs to saved search (#4570)
Browse files Browse the repository at this point in the history
* add selectedMOIs to saved search

* componentdidupdate

* lockfile

* it WORKS

* single reduce method
  • Loading branch information
jklugherz authored Jan 14, 2025
1 parent 39ca35c commit 01899fa
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 30 deletions.
14 changes: 8 additions & 6 deletions ui/pages/Search/components/filters/LocusListSelector.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,26 +33,28 @@ class BaseLocusListDropdown extends React.Component {
locusListOptions: PropTypes.arrayOf(PropTypes.object),
loading: PropTypes.bool,
onChange: PropTypes.func,
selectedMOIs: PropTypes.arrayOf(PropTypes.string),
}

shouldComponentUpdate(nextProps) {
const { locusList, locusListOptions, onChange, loading } = this.props
const { locusList, locusListOptions, onChange, loading, selectedMOIs } = this.props
return nextProps.locusListOptions !== locusListOptions ||
nextProps.onChange !== onChange ||
nextProps.loading !== loading ||
nextProps.locusList.locusListGuid !== locusList.locusListGuid ||
(!!locusList.locusListGuid && nextProps.locusList.rawItems !== locusList.rawItems)
(!!locusList.locusListGuid && nextProps.locusList.rawItems !== locusList.rawItems) ||
nextProps.selectedMOIs !== selectedMOIs
}

componentDidUpdate(prevProps) {
const { locusList, onChange } = this.props
const { locusList, onChange, selectedMOIs } = this.props

if (prevProps.locusList.rawItems !== locusList.rawItems) {
const { locusListGuid } = locusList

if (locusList.paLocusList) {
const panelAppItems = formatPanelAppItems(locusList.items)
onChange({ locusListGuid, panelAppItems })
const panelAppItems = formatPanelAppItems(locusList.items, selectedMOIs)
onChange({ locusListGuid, panelAppItems, selectedMOIs })
} else {
const { rawItems } = locusList
onChange({ locusListGuid, rawItems })
Expand Down Expand Up @@ -96,7 +98,7 @@ const SUBSCRIPTION = { values: true }
const LocusListSelector = React.memo(({ value, ...props }) => (
<LocusListsLoader allProjectLists hideLoading>
<LocusListItemsLoader locusListGuid={value.locusListGuid} reloadOnIdUpdate content hideLoading>
<LocusListDropdown {...props} />
<LocusListDropdown selectedMOIs={value?.selectedMOIs} {...props} />
</LocusListItemsLoader>
</LocusListsLoader>
))
Expand Down
50 changes: 50 additions & 0 deletions ui/shared/components/panel/search/PaLocusListSelector.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react'
import { BaseSemanticInput } from 'shared/components/form/Inputs'
import { connect } from 'react-redux'
import { getLocusListsWithGenes } from 'redux/selectors'
import { formatPanelAppItems } from 'shared/utils/panelAppUtils'
import PropTypes from 'prop-types'

const EMPTY_STRING = ''

class PaLocusListSelector extends React.Component {

static propTypes = {
locus: PropTypes.object,
locusList: PropTypes.object,
onChange: PropTypes.func,
value: PropTypes.string,
color: PropTypes.string,
}

shouldComponentUpdate(nextProps) {
const { locus, value } = this.props
return nextProps.locus.selectedMOIs !== locus.selectedMOIs ||
nextProps.value !== value
}

componentDidUpdate(prevProps) {
const { locus, locusList, onChange, color } = this.props
const { selectedMOIs } = locus

if (prevProps.locus.selectedMOIs !== selectedMOIs) {
const panelAppItems = formatPanelAppItems(locusList?.items, selectedMOIs)
if (panelAppItems[color]) {
onChange(panelAppItems[color])
} else {
onChange(EMPTY_STRING)
}
}
}

render() {
return <BaseSemanticInput {...this.props} />
}

}

const mapStateToProps = (state, ownProps) => ({
locusList: getLocusListsWithGenes(state)[ownProps.locus.locusListGuid],
})

export default connect(mapStateToProps)(PaLocusListSelector)
26 changes: 4 additions & 22 deletions ui/shared/components/panel/search/PaMoiSelector.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { connect } from 'react-redux'

import { getLocusListsWithGenes } from 'redux/selectors'
import { Multiselect } from 'shared/components/form/Inputs'
import { moiToMoiInitials, formatPanelAppItems } from 'shared/utils/panelAppUtils'
import { moiToMoiInitials } from 'shared/utils/panelAppUtils'
import { PANEL_APP_MOI_OPTIONS } from 'shared/utils/constants'

const EMPTY_LIST = []
Expand All @@ -13,24 +13,6 @@ class PaMoiDropdown extends React.PureComponent {

static propTypes = {
locusList: PropTypes.object,
onChange: PropTypes.func,
}

handleMOIselect = (selectedMOIs) => {
const { locusList, onChange } = this.props

const panelAppItems = formatPanelAppItems(
locusList.items?.filter((item) => {
let result = true
const initials = moiToMoiInitials(item.pagene?.modeOfInheritance, false)
if (selectedMOIs && selectedMOIs.length !== 0) {
result = selectedMOIs.some(moi => initials.includes(moi))
}
return result
}),
)

onChange({ ...panelAppItems })
}

moiOptions = () => {
Expand All @@ -50,15 +32,15 @@ class PaMoiDropdown extends React.PureComponent {
}

render() {
const { selectedMOIs, label, width, locusList } = this.props || []
const { value, label, width, locusList, onChange } = this.props || []
const disabled = !locusList?.items
return (
<Multiselect
label={label}
value={selectedMOIs}
value={value}
width={width}
inline
onChange={this.handleMOIselect}
onChange={onChange}
placeholder="Showing all MOIs as listed in Panel App"
disabled={disabled}
options={disabled ? EMPTY_LIST : this.moiOptions()}
Expand Down
6 changes: 5 additions & 1 deletion ui/shared/components/panel/search/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import {

import LocusListItemsFilter from './LocusListItemsFilter'
import PaMoiSelector from './PaMoiSelector'
import PaLocusListSelector from './PaLocusListSelector'

export const getSelectedAnalysisGroups = (
analysisGroupsByGuid, familyGuids,
Expand Down Expand Up @@ -464,6 +465,7 @@ export const FREQUENCIES = [...SNP_FREQUENCIES, ...MITO_FREQUENCIES, ...SV_FREQU

export const LOCUS_FIELD_NAME = 'locus'
export const PANEL_APP_FIELD_NAME = 'panelAppItems'
export const SELECTED_MOIS_FIELD_NAME = 'selectedMOIs'
const VARIANT_FIELD_NAME = 'rawVariantItems'
const PANEL_APP_COLORS = [...new Set(
Object.entries(PANEL_APP_CONFIDENCE_LEVELS).sort((a, b) => b[0] - a[0]).map(config => config[1]),
Expand All @@ -485,9 +487,11 @@ export const LOCATION_FIELDS = [
label: color === 'none' ? 'Genes' : `${camelcaseToTitlecase(color)} Genes`,
labelHelp: 'A list of genes, can be separated by commas or whitespace',
component: LocusListItemsFilter,
filterComponent: PaLocusListSelector,
width: 3,
shouldShow: locus => !!locus[PANEL_APP_FIELD_NAME],
shouldDisable: locus => !!locus[VARIANT_FIELD_NAME],
color,
})),
{
name: VARIANT_FIELD_NAME,
Expand All @@ -498,7 +502,7 @@ export const LOCATION_FIELDS = [
shouldDisable: locus => !!locus[LOCUS_LIST_ITEMS_FIELD.name] || !!locus[PANEL_APP_FIELD_NAME],
},
{
name: PANEL_APP_FIELD_NAME,
name: SELECTED_MOIS_FIELD_NAME,
label: 'Modes of Inheritance',
labelHelp: 'Filter the Gene List based on Modes of Inheritance from Panel App',
component: LocusListItemsFilter,
Expand Down
18 changes: 17 additions & 1 deletion ui/shared/utils/panelAppUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export const panelAppUrl = (

export type PanelAppItem = {
pagene?: {
modeOfInheritance?: string;
confidenceLevel?: 0 | 1 | 2 | 3 | 4
}
display: string
Expand All @@ -74,15 +75,30 @@ export type PanelAppItem = {
* and concatenated item displays as values.
*
* @param {PanelAppItem[] | null | undefined} items - The array of PanelApp items to format.
* @param {string[] | null | undefined} selectedMOIs - Optional array of selected MOIs for filtering.
* @returns {Record<string, string> | never[]} A record where keys represent confidence levels and values
* are concatenated item displays, or an empty array if `items` is falsy.
*/
export const formatPanelAppItems = (items: PanelAppItem[] | null | undefined): Record<string, string> | never[] => {
export const formatPanelAppItems = (
items: PanelAppItem[] | null | undefined,
selectedMOIs?: string[] | null
): Record<string, string> | never[] => {
if (!items) {
return []
}

const hasSelectedMoi = (item: { pagene?: any; display?: string }, selectedMOIs: any[]) => {
if (!selectedMOIs || selectedMOIs.length === 0) {
return true
}
const initials = moiToMoiInitials(item.pagene?.modeOfInheritance, false)
return selectedMOIs.some((moi) => initials.includes(moi))
}

return items.reduce((acc, item) => {
if (!hasSelectedMoi(item, selectedMOIs)) {
return acc
}
const color: string = PANEL_APP_CONFIDENCE_LEVELS[item.pagene?.confidenceLevel] || PANEL_APP_CONFIDENCE_LEVELS[0]
return { ...acc, [color]: [acc[color], item.display].filter(val => val).join(', ') }
}, {} as Record<string, string>)
Expand Down

0 comments on commit 01899fa

Please sign in to comment.