Skip to content

Commit

Permalink
Update based on feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
calvinlu3 committed Sep 6, 2024
1 parent 929bcbf commit 0fbffb5
Show file tree
Hide file tree
Showing 9 changed files with 67 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,10 @@ import MutationConvertIcon from 'app/shared/icons/MutationConvertIcon';
import AddMutationModal from 'app/shared/modal/AddMutationModal';
import AddVusModal from 'app/shared/modal/AddVusModal';
import ModifyCancerTypeModal from 'app/shared/modal/ModifyCancerTypeModal';
import { Alteration, Mutation, Review, StringMutationInfo } from 'app/shared/model/firebase/firebase.model';
import { Alteration, Review, AlterationCategories } from 'app/shared/model/firebase/firebase.model';
import DefaultTooltip from 'app/shared/tooltip/DefaultTooltip';
import { FlattenedHistory } from 'app/shared/util/firebase/firebase-history-utils';
import {
getAlterationName,
getFirebaseGenePath,
getFirebaseVusPath,
getMutationName,
Expand Down Expand Up @@ -86,7 +85,7 @@ const MutationCollapsible = ({
const [mutationName, setMutationName] = useState<string>('');
const [mutationNameReview, setMutationNameReview] = useState<Review | null>(null);
const [mutationAlterations, setMutationAlterations] = useState<Alteration[] | null>(null);
const [stringMutationInfo, setStringMutationInfo] = useState<StringMutationInfo | null>(null);
const [alterationCategories, setAlterationCategories] = useState<AlterationCategories | null>(null);
const [isRemovableWithoutReview, setIsRemovableWithoutReview] = useState(false);
const [relatedAnnotationResult, setRelatedAnnotationResult] = useState<AlterationAnnotationStatus[]>([]);

Expand Down Expand Up @@ -173,9 +172,9 @@ const MutationCollapsible = ({
}),
);
callbacks.push(
onValue(ref(firebaseDb, `${mutationPath}/string_mutation_info`), snapshot => {
const info = snapshot.val() as StringMutationInfo;
setStringMutationInfo(info);
onValue(ref(firebaseDb, `${mutationPath}/alteration_categories`), snapshot => {
const info = snapshot.val() as AlterationCategories;
setAlterationCategories(info);
}),
);

Expand Down Expand Up @@ -233,7 +232,11 @@ const MutationCollapsible = ({
<RemovableCollapsible
idPrefix={title}
title={
<MutationCollapsibleTitle name={mutationName} mutationAlterations={mutationAlterations} stringMutationInfo={stringMutationInfo} />
<MutationCollapsibleTitle
name={mutationName}
mutationAlterations={mutationAlterations}
alterationCategories={alterationCategories}
/>
}
defaultOpen={open}
collapsibleClassName="mb-1"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,32 @@
import DefaultBadge from 'app/shared/badge/DefaultBadge';
import InfoIcon from 'app/shared/icons/InfoIcon';
import { Alteration, StringMutationInfo } from 'app/shared/model/firebase/firebase.model';
import { Alteration, AlterationCategories } from 'app/shared/model/firebase/firebase.model';
import { getAlterationName, isFlagEqualToIFlag } from 'app/shared/util/firebase/firebase-utils';
import { componentInject } from 'app/shared/util/typed-inject';
import { buildAlterationName, parseAlterationName } from 'app/shared/util/utils';
import { buildAlterationName, getAlterationNameComponent, parseAlterationName } from 'app/shared/util/utils';
import { IRootStore } from 'app/stores';
import { observer } from 'mobx-react';
import React from 'react';
import * as styles from './styles.module.scss';
import classNames from 'classnames';
import WithSeparator from 'react-with-separator';

export interface IMutationCollapsibleTitle extends StoreProps {
name: string | undefined;
mutationAlterations: Alteration[] | null | undefined;
stringMutationInfo: StringMutationInfo | null;
alterationCategories: AlterationCategories | null;
}
const MutationCollapsibleTitle = ({ name, mutationAlterations, stringMutationInfo, flags }: IMutationCollapsibleTitle) => {
const MutationCollapsibleTitle = ({ name, mutationAlterations, alterationCategories, flagEntities }: IMutationCollapsibleTitle) => {
const defaultName = 'No Name';
let stringMutationBadges: JSX.Element | undefined;
const shouldGroupBadges =
(stringMutationInfo?.flags?.length || 0) > 1 || (stringMutationInfo?.flags?.length === 1 && stringMutationInfo.comment !== '');
if (stringMutationInfo?.flags && flags) {
let tooltipOverlay: JSX.Element | undefined = undefined;
(alterationCategories?.flags?.length || 0) > 1 || (alterationCategories?.flags?.length === 1 && alterationCategories.comment !== '');
if (alterationCategories?.flags && flagEntities) {
const tooltipOverlay = alterationCategories.comment ? <span>{alterationCategories.comment}</span> : undefined;
stringMutationBadges = (
<div className={classNames(shouldGroupBadges ? styles.flagWrapper : undefined)}>
{stringMutationInfo.flags.map(flag => {
if (stringMutationInfo.comment) {
tooltipOverlay = <span>{stringMutationInfo.comment}</span>;
}
const matchedFlagEntity = flags.find(flagEntity => isFlagEqualToIFlag(flag, flagEntity));
{alterationCategories.flags.map(flag => {
const matchedFlagEntity = flagEntities.find(flagEntity => isFlagEqualToIFlag(flag, flagEntity));
return <DefaultBadge key={matchedFlagEntity?.flag || flag.flag} color={'primary'} text={matchedFlagEntity?.name || flag.flag} />;
})}
{tooltipOverlay ? <InfoIcon className="me-1" overlay={tooltipOverlay} /> : undefined}
Expand All @@ -38,15 +36,11 @@ const MutationCollapsibleTitle = ({ name, mutationAlterations, stringMutationInf
if (mutationAlterations) {
return (
<>
{mutationAlterations.map((alteration, index) => {
return (
<>
<span>{getAlterationName(alteration, true)}</span>
{alteration.comment && <InfoIcon className="ms-1" overlay={alteration.comment} />}
{index < mutationAlterations.length - 1 && <span>, </span>}
</>
);
})}
<WithSeparator separator={', '}>
{mutationAlterations.map((alteration, index) =>
getAlterationNameComponent(getAlterationName(alteration, true), alteration.comment),
)}
</WithSeparator>
{stringMutationBadges}
</>
);
Expand All @@ -55,15 +49,11 @@ const MutationCollapsibleTitle = ({ name, mutationAlterations, stringMutationInf
const parsedAlterations = parseAlterationName(name, true);
return (
<>
{parsedAlterations.map((pAlt, index) => {
return (
<>
<span>{buildAlterationName(pAlt.alteration, pAlt.name, pAlt.excluding)}</span>
{pAlt.comment && <InfoIcon className="ms-1" overlay={pAlt.comment} />}
{index < parsedAlterations.length - 1 && <span>, </span>}
</>
);
})}
<WithSeparator separator={', '}>
{parsedAlterations.map(pAlt =>
getAlterationNameComponent(buildAlterationName(pAlt.alteration, pAlt.name, pAlt.excluding), pAlt.comment),
)}
</WithSeparator>
{stringMutationBadges}
</>
);
Expand All @@ -72,7 +62,7 @@ const MutationCollapsibleTitle = ({ name, mutationAlterations, stringMutationInf
};

const mapStoreToProps = ({ flagStore }: IRootStore) => ({
flags: flagStore.alterationCategoryFlags,
flagEntities: flagStore.alterationCategoryFlags,
});

type StoreProps = Partial<ReturnType<typeof mapStoreToProps>>;
Expand Down
38 changes: 19 additions & 19 deletions src/main/webapp/app/shared/modal/AddMutationModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { FaChevronDown, FaChevronUp, FaExclamationTriangle, FaPlus } from 'react
import ReactSelect, { GroupBase, MenuPlacement } from 'react-select';
import CreatableSelect from 'react-select/creatable';
import { Alert, Button, Col, Input, Row, Spinner } from 'reactstrap';
import { Alteration, Flag, Mutation, StringMutationInfo, VusObjList } from '../model/firebase/firebase.model';
import { Alteration, Flag, Mutation, AlterationCategories, VusObjList } from '../model/firebase/firebase.model';
import {
AlterationAnnotationStatus,
AlterationTypeEnum,
Expand Down Expand Up @@ -102,7 +102,7 @@ function AddMutationModal({
const [flags, setFlags] = useState<readonly IFlag[]>([]);
const [vusList, setVusList] = useState<VusObjList | null>(null);

const [stringMutationInfo, setStringMutationInfo] = useState<StringMutationInfo | null>(null);
const [alterationCategories, setAlterationCategories] = useState<AlterationCategories | null>(null);
const [selectedStringMutationFlags, setSelectedStringMutationFlags] = useState<(IFlag | Omit<IFlag, 'id'>)[]>([]);
const [stringMutationComment, setStringMutationComment] = useState<string>('');

Expand Down Expand Up @@ -227,7 +227,7 @@ function AddMutationModal({

if (mutationToEdit) {
setExistingAlterations();
setStringMutationInfo(mutationToEdit?.string_mutation_info ?? null);
setAlterationCategories(mutationToEdit?.alteration_categories ?? null);
}
}, [mutationToEdit]);

Expand All @@ -253,7 +253,7 @@ function AddMutationModal({
useEffect(() => {
if (flags) {
setSelectedStringMutationFlags(
stringMutationInfo?.flags?.reduce((acc: IFlag[], flag) => {
alterationCategories?.flags?.reduce((acc: IFlag[], flag) => {
const matchedFlag = flags.find(flagEntity => isFlagEqualToIFlag(flag, flagEntity));

if (matchedFlag) {
Expand All @@ -264,8 +264,8 @@ function AddMutationModal({
}, []) ?? [],
);
}
setStringMutationComment(stringMutationInfo?.comment ?? '');
}, [stringMutationInfo, flags]);
setStringMutationComment(alterationCategories?.comment ?? '');
}, [alterationCategories, flags]);

const flagDropdownOptions = useMemo(() => {
if (!flags) return [];
Expand Down Expand Up @@ -1040,7 +1040,7 @@ function AddMutationModal({
setSelectedStringMutationFlags(prevState => [...prevState, newSelectedFlag]);
}

function handleStringMutationInfoField(field: keyof StringMutationInfo, value: unknown) {
function handleAlterationCategoriesField(field: keyof AlterationCategories, value: unknown) {
if (field === 'comment') {
setStringMutationComment(value as string);
} else if (field === 'flags') {
Expand Down Expand Up @@ -1100,14 +1100,14 @@ function AddMutationModal({
<Col>
<div className="d-flex align-items-center mb-3">
<Col className="px-0 col-3 me-3">
<span>Mutation String Name</span>
<span>String Name</span>
</Col>
<Col className="px-0">
<CreatableSelect
inputId="add-mutation-modal-flag-input"
isMulti
options={flagDropdownOptions}
onChange={newFlags => handleStringMutationInfoField('flags', newFlags)}
onChange={newFlags => handleAlterationCategoriesField('flags', newFlags)}
onCreateOption={handleMutationFlagAdded}
value={selectedStringMutationFlags.map(newFlag => ({ label: newFlag.name, value: newFlag }))}
/>
Expand All @@ -1122,7 +1122,7 @@ function AddMutationModal({
value={stringMutationComment ?? ''}
placeholder={'Input comment'}
onChange={value => {
handleStringMutationInfoField('comment', value);
handleAlterationCategoriesField('comment', value);
}}
disabled={selectedStringMutationFlags.length === 0}
/>
Expand Down Expand Up @@ -1197,18 +1197,18 @@ function AddMutationModal({
return oldFlags;
}

async function handleStringMutationInfoConfirm() {
let newStringMutationInfo: StringMutationInfo | null = new StringMutationInfo();
async function handleAlterationCategoriesConfirm() {
let newAlterationCategories: AlterationCategories | null = new AlterationCategories();
if (stringMutationComment === '' && selectedStringMutationFlags.length === 0) {
newStringMutationInfo = null;
newAlterationCategories = null;
} else {
newStringMutationInfo.comment = stringMutationComment;
newAlterationCategories.comment = stringMutationComment;
const finalFlagArray = await saveNewFlags();
if (selectedStringMutationFlags.length > 0) {
newStringMutationInfo.flags = finalFlagArray.map(flag => convertIFlagToFlag(flag));
newAlterationCategories.flags = finalFlagArray.map(flag => convertIFlagToFlag(flag));
}
}
return newStringMutationInfo;
return newAlterationCategories;
}

return (
Expand Down Expand Up @@ -1239,9 +1239,9 @@ function AddMutationModal({
const newAlterations = tabStates.map(state => convertAlterationDataToAlteration(state));
newMutation.name = newAlterations.map(alteration => alteration.name).join(', ');
newMutation.alterations = newAlterations;
const newStringMutationInfo = await handleStringMutationInfoConfirm();
if (newStringMutationInfo) {
newMutation.string_mutation_info = newStringMutationInfo;
const newAlterationCategories = await handleAlterationCategoriesConfirm();
if (newAlterationCategories) {
newMutation.alteration_categories = newAlterationCategories;
}

setErrorMessagesEnabled(false);
Expand Down
4 changes: 2 additions & 2 deletions src/main/webapp/app/shared/model/firebase/firebase.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ export class Mutation {
mutation_effect: MutationEffect = new MutationEffect();
mutation_effect_uuid: string = generateUuid();
mutation_effect_comments?: Comment[] = []; // used for somatic
string_mutation_info?: StringMutationInfo;
alteration_categories?: AlterationCategories;
name: string = '';
name_comments?: Comment[] = [];
name_review?: Review;
Expand All @@ -241,7 +241,7 @@ export type Flag = {
flag: string;
};

export class StringMutationInfo {
export class AlterationCategories {
flags?: Flag[];
comment = '';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ export const isSectionEmpty = (sectionValue: any, fullPath: string) => {
return true;
}

const ignoredKeySuffixes = ['_review', '_uuid', 'TIs', 'cancerTypes', 'name', 'alterations', 'string_mutation_info'];
const ignoredKeySuffixes = ['_review', '_uuid', 'TIs', 'cancerTypes', 'name', 'alterations', 'alteration_categories'];
const isEmpty = isNestedObjectEmpty(sectionValue, ignoredKeySuffixes);

if (!isEmpty) {
Expand Down
12 changes: 11 additions & 1 deletion src/main/webapp/app/shared/util/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ import EntityActionButton from '../button/EntityActionButton';
import { SORT } from './pagination.constants';
import { PaginationState } from '../table/OncoKBAsyncTable';
import { IUser } from '../model/user.model';
import { CancerType } from '../model/firebase/firebase.model';
import { Alteration, CancerType } from '../model/firebase/firebase.model';
import _ from 'lodash';
import { ParsedRef, parseReferences } from 'app/oncokb-commons/components/RefComponent';
import { IDrug } from 'app/shared/model/drug.model';
import { IRule } from 'app/shared/model/rule.model';
import { INTEGER_REGEX, REFERENCE_LINK_REGEX, SINGLE_NUCLEOTIDE_POS_REGEX, UUID_REGEX } from 'app/config/constants/regex';
import { ProteinExonDTO } from 'app/shared/api/generated/curation';
import { IQueryParams } from './jhipster-types';
import InfoIcon from '../icons/InfoIcon';

export const getCancerTypeName = (cancerType: ICancerType | CancerType, omitCode = false): string => {
if (!cancerType) return '';
Expand Down Expand Up @@ -316,6 +317,15 @@ export function buildAlterationName(alteration: string, name = '', excluding = [
return `${alteration}${name}${exclusionString}${comment}`;
}

export function getAlterationNameComponent(alterationName: string, comment?: string) {
return (
<>
<span>{alterationName}</span>
{comment && <InfoIcon className="ms-1" overlay={comment} />}
</>
);
}

export function findIndexOfFirstCapital(str: string) {
for (let i = 0; i < str.length; i++) {
if (str[i] >= 'A' && str[i] <= 'Z') {
Expand Down
5 changes: 3 additions & 2 deletions src/test/javascript/firebase/mock-data.json
Original file line number Diff line number Diff line change
Expand Up @@ -2773,14 +2773,15 @@
},
"mutation_effect_uuid": "45f48fdd-a2fa-44dc-86cb-b3fd8e4bc8c1",
"name": "V600E (comment), V600K",
"string_mutation_info": {
"alteration_categories": {
"flags": [
{
"type": "ALTERATION_CATEGORY",
"flag": "TEST_FLAG",
"name": "Test Flag"
}
]
],
"comment": "This is a test flag"
},
"name_review": {
"updateTime": 1493057315640
Expand Down
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.

0 comments on commit 0fbffb5

Please sign in to comment.