Skip to content

Commit

Permalink
Merge pull request #1009 from oncokb/rc
Browse files Browse the repository at this point in the history
Support cancer type search in the search box
  • Loading branch information
zhx828 authored Aug 1, 2023
2 parents 88d9e6f + cbe8e17 commit 2e62ace
Show file tree
Hide file tree
Showing 12 changed files with 199 additions and 49 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 4 additions & 2 deletions src/main/resources/config/application-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ spring:
indent-output: true
datasource:
type: com.zaxxer.hikari.HikariDataSource
url: jdbc:mysql://localhost:3306/oncokb_public?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC&createDatabaseIfNotExist=true
# changed database name
url: jdbc:mysql://localhost:3306/oncokb-public?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC&createDatabaseIfNotExist=true
username: root
password: root
hikari:
Expand Down Expand Up @@ -150,7 +151,8 @@ application:
user-registration-channel-id:
redis:
# Add the following if you want to opt in to using Redis
# enabled: true
# Not using Redis
enabled: false
type: 'single'
password: 'oncokb-public-redis-password'
address: 'redis://localhost:6379'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export default class OncoKBSearch extends React.Component<IOncoKBSearch, {}> {
<div className={'d-flex align-items-center'}>
<div className={'flex-grow-1'}>
<Select
placeholder="Search Gene / Alteration / Drug / Genomic Variant"
placeholder="Search Gene / Alteration / Cancer Type / Drug / Genomic Variant"
components={{
Option,
DropdownIndicator: () => null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export interface ISearchInfoIcon {
onSelectQuery: (query: string) => void
}

export default class SearchInfoIcon extends React.Component<ISearchInfoIcon> {
export default class SearchInfoIcon extends React.Component<ISearchInfoIcon, any> {

constructor(props: Readonly<ISearchInfoIcon>) {
super(props);
Expand Down Expand Up @@ -46,6 +46,12 @@ export default class SearchInfoIcon extends React.Component<ISearchInfoIcon> {
key: 'alteration-1',
content: this.getQueryLink('BRAF V600E')
}]
}, {
key: 'cancerType',
content: [{key: 'cancerType-0', content: 'Cancer Type'}, {
key: 'cancerType-1',
content: this.getQueryLink('Melanoma')
}]
}, {
key: 'drug',
content: [{key: 'drug-0', content: 'Drug'}, {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.subTitle {
color: $grey;
font-size: 0.9em;
display: flex;
}
.match {
line-height: 1.5rem;
Expand Down
175 changes: 139 additions & 36 deletions src/main/webapp/app/components/searchOption/SearchOption.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,17 @@ import classnames from 'classnames';
import AppStore from 'app/store/AppStore';
import { FeedbackIcon } from 'app/components/feedback/FeedbackIcon';
import { FeedbackType } from 'app/components/feedback/types';
import { ONCOKB_TM } from 'app/config/constants';
import {LEVEL_PRIORITY_BY_TYPE, ONCOKB_TM} from 'app/config/constants';
import { Alteration } from 'app/shared/api/generated/OncoKbPrivateAPI';
import {sortByLevel, sortByLevelWithLevels} from "app/shared/utils/ReactTableUtils";
import WithSeparator from "react-with-separator";

export enum SearchOptionType {
GENE = 'GENE',
VARIANT = 'VARIANT',
DRUG = 'DRUG',
GENOMIC = 'GENOMIC',
CANCER_TYPE = 'CANCER_TYPE',
TEXT = 'TEXT',
}
type SearchOptionProps = {
Expand All @@ -27,31 +31,16 @@ type SearchOptionProps = {
appStore: AppStore;
};
const LevelString: React.FunctionComponent<{
highestSensitiveLevel: string | undefined;
highestResistanceLevel: string | undefined;
level: string;
}> = props => {
const level = levelOfEvidence2Level(props.level)
return (
<>
{props.highestSensitiveLevel ? (
<span
className={`oncokb level-${levelOfEvidence2Level(
props.highestSensitiveLevel,
true
)}`}
>
Level {props.highestSensitiveLevel}
<span
className={`oncokb level-${level} text-nowrap`}
>
Level {level}
</span>
) : undefined}
{props.highestResistanceLevel ? (
<span
className={`oncokb level-${levelOfEvidence2Level(
props.highestResistanceLevel,
true
)}`}
>
Level {props.highestResistanceLevel}
</span>
) : undefined}
</>
);
};
Expand All @@ -61,20 +50,27 @@ const GeneSearchOption: React.FunctionComponent<{
}> = props => {
return (
<>
<div>
<div className={'d-flex'}>
<Highlighter
searchWords={[props.search]}
textToHighlight={`${props.data.gene.hugoSymbol} (Entrez Gene: ${props.data.gene.entrezGeneId})`}
/>
{props.data.highestSensitiveLevel ||
props.data.highestResistanceLevel ? (
<span className={styles.subTitle}>
{' '}
Highest level of evidence:
<LevelString
highestSensitiveLevel={props.data.highestSensitiveLevel}
highestResistanceLevel={props.data.highestResistanceLevel}
/>
<span className={classnames(styles.subTitle, 'ml-2')}>
<span className={'mr-2'}>Highest level of evidence:</span>
<WithSeparator separator={' '}>
{props.data.highestSensitiveLevel && (
<LevelString
level={props.data.highestSensitiveLevel}
/>
)}
{props.data.highestResistanceLevel && (
<LevelString
level={props.data.highestResistanceLevel}
/>
)}
</WithSeparator>
</span>
) : undefined}
</div>
Expand Down Expand Up @@ -180,10 +176,16 @@ const DrugSearchOption: React.FunctionComponent<{
/>
</div>
<div className={styles.subTitle}>
<LevelString
highestSensitiveLevel={props.data.highestSensitiveLevel}
highestResistanceLevel={props.data.highestResistanceLevel}
/> :{' '}
{props.data.highestSensitiveLevel && (
<LevelString
level={props.data.highestSensitiveLevel}
/>
)}
{props.data.highestResistanceLevel && (
<LevelString
level={props.data.highestResistanceLevel}
/>
)} :{' '}
{` ${props.data.gene.hugoSymbol} `}
{props.data.variants.length > 1
? `(${props.data.alterationsName})`
Expand All @@ -195,6 +197,97 @@ const DrugSearchOption: React.FunctionComponent<{
);
};

const CancerTypeSearchOption: React.FunctionComponent<{
search: string;
data: ExtendedTypeaheadSearchResp;
}> = props => {
const groupAlterationsByGene = (alterations: Alteration[]) => {
const groupedAlterations: { [key: string]: string[] } = {};
alterations.forEach(alteration => {
const gene = alteration.gene.hugoSymbol;
if (!groupedAlterations[gene]) {
groupedAlterations[gene] = [];
}
// Check for parentheses in the alteration name
const alterationName = alteration.name.replace(/[()]/g, '').trim();
groupedAlterations[gene].push(alterationName);
});
return groupedAlterations;
};

const renderAlterations = (alterationsByGene: {
[key: string]: string[];
}) => {
const maxElementsToDisplay = 3;
const geneKeys = Object.keys(alterationsByGene);
// TODO detect key of other biomarkers and change accordingly
const totalGenes = geneKeys.length;
const genesToDisplay = Math.min(maxElementsToDisplay, totalGenes);
// displaying 3 genes
return geneKeys.slice(0, genesToDisplay).map((gene, index) => {
const geneAlterations = alterationsByGene[gene];
const showAndMore = geneAlterations.length > maxElementsToDisplay;

const displayAlterations = showAndMore
? geneAlterations.slice(0, maxElementsToDisplay).join(', ') +
', and ' +
(geneAlterations.length - maxElementsToDisplay).toString() +
' other alterations'
: geneAlterations.join(', ');

const separator = index < genesToDisplay - 1 ? ', ' : '';

return (
<span key={index}>
{gene !== 'Other Biomarkers' ? (
<>
{gene} ({displayAlterations})
</>
) : (
<>{displayAlterations}</>
)}
{separator}
{totalGenes > maxElementsToDisplay && index === genesToDisplay - 1
? ', and more'
: ''}
</span>
);
});
};

return (
<>
<div>
<Highlighter
searchWords={[props.search]}
textToHighlight={props.data.tumorTypesName}
/>
</div>
{props.data.annotationByLevel !== null ? (
<div>
{Object.keys(props.data.annotationByLevel)
.sort((a, b) => sortByLevelWithLevels(a, b, LEVEL_PRIORITY_BY_TYPE))
.map(
(level) => {
const annotation = props.data.annotationByLevel[level]
return (
<div className={styles.subTitle} key={`${props.data.tumorTypesName}-${level}`}>
<LevelString
level={level}
/>
: {annotation}
</div>
)
}
)}
</div>
) : (
<div>No evidence found.</div>
)}
</>
);
};

export const SearchOption: React.FunctionComponent<SearchOptionProps> = props => {
const searchKeyword = props.search ? props.search : '';
return (
Expand Down Expand Up @@ -227,10 +320,20 @@ export const SearchOption: React.FunctionComponent<SearchOptionProps> = props =>
/>
</Then>
<Else>
<If condition={props.type === SearchOptionType.TEXT}>
<If condition={props.type === SearchOptionType.CANCER_TYPE}>
<Then>
<span>{props.data.annotation}</span>
<CancerTypeSearchOption
search={searchKeyword}
data={props.data}
/>
</Then>
<Else>
<If condition={props.type === SearchOptionType.TEXT}>
<Then>
<span>{props.data.annotation}</span>
</Then>
</If>
</Else>
</If>
</Else>
</If>
Expand Down
23 changes: 22 additions & 1 deletion src/main/webapp/app/config/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -230,11 +230,12 @@ export const DX_LEVELS = [LEVELS.Dx1, LEVELS.Dx2, LEVELS.Dx3];
export const PX_LEVELS = [LEVELS.Px1, LEVELS.Px2, LEVELS.Px3];
export const ONCOKB_LEVELS = TX_LEVELS.concat(DX_LEVELS).concat(PX_LEVELS);

// the bigger of the index, the higher the priority
// bigger the index, higher the priority
export const LEVEL_PRIORITY: LEVELS[] = [
LEVELS.Fda3,
LEVELS.Fda2,
LEVELS.Fda1,
LEVELS.Px3,
LEVELS.Px2,
LEVELS.Px1,
LEVELS.Dx3,
Expand All @@ -250,6 +251,26 @@ export const LEVEL_PRIORITY: LEVELS[] = [
LEVELS.Tx1,
];

export const LEVEL_PRIORITY_BY_TYPE: LEVELS[] = [
LEVELS.Fda3,
LEVELS.Fda2,
LEVELS.Fda1,
LEVELS.Px3,
LEVELS.Px2,
LEVELS.Px1,
LEVELS.Dx3,
LEVELS.Dx2,
LEVELS.Dx1,
LEVELS.R2,
LEVELS.R1,
LEVELS.Tx4,
LEVELS.Tx3B,
LEVELS.Tx3A,
LEVELS.Tx3,
LEVELS.Tx2,
LEVELS.Tx1,
];

export const LEVEL_BUTTON_DESCRIPTION: { [key in LEVELS]: string } = {
[LEVELS.Tx1]: EVIDENCE_TYPE.FDA_APPROVED,
[LEVELS.Tx2]: EVIDENCE_TYPE.STANDARD_CARE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@
{
"name": "query",
"in": "query",
"description": "The search query, it could be hugoSymbol, entrezGeneId or variant. At least two characters. Maximum two keywords are supported, separated by space",
"description": "The search query, it could be hugoSymbol, entrezGeneId, variant, or cancer type. At least two characters. Maximum two keywords are supported, separated by space",
"required": true,
"type": "string"
},
Expand Down Expand Up @@ -2949,6 +2949,12 @@
"annotation": {
"type": "string"
},
"annotationByLevel": {
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"drug": {
"$ref": "#/definitions/Drug"
},
Expand All @@ -2973,7 +2979,9 @@
"GENE",
"VARIANT",
"DRUG",
"TEXT"
"TEXT",
"GENOMIC",
"CANCER_TYPE"
]
},
"tumorTypes": {
Expand Down
Loading

0 comments on commit 2e62ace

Please sign in to comment.