Skip to content

Commit 530c672

Browse files
committed
allow curators to add description to range
1 parent 1fd1741 commit 530c672

File tree

6 files changed

+85
-29
lines changed

6 files changed

+85
-29
lines changed

src/main/webapp/app/pages/curation/collapsible/MutationCollapsible.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import {
2626
getFirebaseRangesPath,
2727
getFirebaseVusPath,
2828
getMutationName,
29-
getMutationNameFromRange,
3029
isMutationEffectCuratable,
3130
isSectionRemovableWithoutReview,
3231
} from 'app/shared/util/firebase/firebase-utils';
@@ -634,16 +633,16 @@ const MutationCollapsible = ({
634633
onCancel={() => {
635634
setIsEditingRange(false);
636635
}}
637-
onConfirm={async (alias, start, end, oncogenicities, mutationTypes) => {
636+
onConfirm={async (alias, start, end, oncogenicities, mutationTypes, description) => {
638637
if (!firebaseDb) {
639638
return;
640639
}
641640
const newMutation = (await get(ref(firebaseDb, mutationPath))).val() as Mutation;
642-
newMutation.name = getMutationNameFromRange(alias, start, end, oncogenicities, mutationTypes);
641+
newMutation.name = `${description} [${alias}]`;
643642
try {
644643
await Promise.all([
645644
updateMutationName?.(mutationPath, firebaseMutationsPath, mutationName, newMutation),
646-
updateRange?.(hugoSymbol, associatedRangeId, alias, start, end, oncogenicities, mutationTypes, isGermline),
645+
updateRange?.(hugoSymbol, associatedRangeId, alias, start, end, oncogenicities, mutationTypes, description, isGermline),
647646
]);
648647
} catch (error) {
649648
notifyError(error);

src/main/webapp/app/pages/curation/mutation/MutationsSection.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import {
88
compareMutationsByProteinChangePosition,
99
compareMutationsDefault,
1010
getFirebaseGenePath,
11-
getMutationNameFromRange,
1211
} from 'app/shared/util/firebase/firebase-utils';
1312
import { componentInject } from 'app/shared/util/typed-inject';
1413
import { IRootStore } from 'app/stores';
@@ -251,10 +250,10 @@ function MutationsSection({
251250
hugoSymbol={hugoSymbol}
252251
isGermline={isGermline}
253252
onCancel={() => setShowAddRangeModal(false)}
254-
onConfirm={async (alias, start, end, oncogenicities, mutationTypes) => {
255-
const range = await addRange?.(hugoSymbol, alias, start, end, oncogenicities, mutationTypes, isGermline);
253+
onConfirm={async (alias, start, end, oncogenicities, mutationTypes, description) => {
254+
const range = await addRange?.(hugoSymbol, alias, start, end, oncogenicities, mutationTypes, description, isGermline);
256255
if (range?.pushKey) {
257-
const mutation = new Mutation(getMutationNameFromRange(alias, start, end, oncogenicities, mutationTypes));
256+
const mutation = new Mutation(`${description} [${alias}]`);
258257
mutation.associatedRangeId = range.pushKey;
259258
await addMutation?.(`${getFirebaseGenePath(isGermline, hugoSymbol)}/mutations`, mutation, isGermline, false);
260259
}

src/main/webapp/app/service/firebase/firebase-range-service.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export class FirebaseRangeService {
1515
end: number,
1616
oncogenicities: string[],
1717
mutationTypes: string[],
18+
description: string,
1819
isGermline: boolean,
1920
) => {
2021
return await this.firebaseRepository.push(getFirebaseRangesPath(isGermline, hugoSymbol), {
@@ -23,6 +24,7 @@ export class FirebaseRangeService {
2324
end,
2425
oncogenicities: oncogenicities.join(','),
2526
mutationTypes: mutationTypes.join(','),
27+
description,
2628
});
2729
};
2830

@@ -39,6 +41,7 @@ export class FirebaseRangeService {
3941
end: number,
4042
oncogenicities: string[],
4143
mutationTypes: string[],
44+
description: string,
4245
isGermline: boolean,
4346
) => {
4447
return await this.firebaseRepository.update(`${getFirebaseRangesPath(isGermline, hugoSymbol)}/${rangeId}`, {
@@ -47,6 +50,7 @@ export class FirebaseRangeService {
4750
end,
4851
oncogenicities: oncogenicities.join(','),
4952
mutationTypes: mutationTypes.join(','),
53+
description,
5054
});
5155
};
5256
}

src/main/webapp/app/shared/modal/AddRangeModal.tsx

Lines changed: 68 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
1-
import React, { useEffect, useState } from 'react';
2-
import { Button, FormGroup, Input, Label, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';
31
import { ONCOGENICITY_OPTIONS } from 'app/config/constants/firebase';
42
import { IRootStore } from 'app/stores';
3+
import { onValue, ref, Unsubscribe } from 'firebase/database';
54
import { observer } from 'mobx-react';
5+
import React, { useEffect, useState } from 'react';
6+
import { Button, FormGroup, Input, Label, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap';
7+
import { FIREBASE_ONCOGENICITY, MutationRange, RangeList } from '../model/firebase/firebase.model';
8+
import { getDescriptionFromRange, getFirebaseRangesPath } from '../util/firebase/firebase-utils';
69
import { componentInject } from '../util/typed-inject';
7-
import { onValue, ref, Unsubscribe } from 'firebase/database';
8-
import { getFirebaseRangesPath } from '../util/firebase/firebase-utils';
9-
import { MutationRange, RangeList } from '../model/firebase/firebase.model';
1010

1111
enum AddRangeStep {
1212
POSITION = 1,
1313
CRITERIA,
1414
ALIAS,
15+
DESCRIPTION,
1516
}
1617
const addRangeStepLength = Object.keys(AddRangeStep).length / 2;
1718
const mutationTypes = ['Missense', 'Insertion', 'Deletion'];
@@ -20,20 +21,30 @@ export interface IAddRangeModalProps extends StoreProps {
2021
hugoSymbol: string;
2122
isGermline: boolean;
2223
onCancel: () => void;
23-
onConfirm: (alias: string, start: number, end: number, oncogenicities: string[], mutationTypes: string[]) => void;
24+
onConfirm: (alias: string, start: number, end: number, oncogenicities: string[], mutationTypes: string[], description: string) => void;
2425
rangeToEditPath?: string;
2526
}
2627

2728
function AddRangeModal({ hugoSymbol, isGermline, onCancel, onConfirm, rangeToEditPath, firebaseDb }: IAddRangeModalProps) {
2829
const [currentStep, setCurrentStep] = useState(AddRangeStep.POSITION);
2930
const [position, setPosition] = useState<[number | undefined, number | undefined]>([undefined, undefined]);
30-
const [selectedOncogenicity, setSelectedOncogenicity] = useState<string[]>([]);
31+
const [selectedOncogenicity, setSelectedOncogenicity] = useState<FIREBASE_ONCOGENICITY[]>([]);
3132
const [selectedMutationTypes, setSelectedMutationTypes] = useState<string[]>([]);
3233
const [alias, setAlias] = useState('');
3334
const [existingAliases, setExistingAliases] = useState<string[]>([]);
34-
35+
const [editedDescription, setEditedDescription] = useState('');
36+
const [description, setDescription] = useState('');
3537
const [initialAlias, setInitialAlias] = useState<string | undefined>(undefined);
3638

39+
function updateEditedDescription(newDescription: string, ...args: Parameters<typeof getDescriptionFromRange>) {
40+
const generatedDescription = getDescriptionFromRange(...args);
41+
if (newDescription === generatedDescription) {
42+
setEditedDescription('');
43+
} else {
44+
setEditedDescription(newDescription);
45+
}
46+
}
47+
3748
useEffect(() => {
3849
if (!firebaseDb) {
3950
return;
@@ -52,11 +63,15 @@ function AddRangeModal({ hugoSymbol, isGermline, onCancel, onConfirm, rangeToEdi
5263
onValue(ref(firebaseDb, rangeToEditPath), snapshot => {
5364
const range = snapshot.val() as MutationRange;
5465
setPosition([range.start, range.end]);
55-
setSelectedOncogenicity(range.oncogenicities.split(','));
56-
setSelectedMutationTypes(range.mutationTypes.split(','));
66+
const oncogencities = range.oncogenicities.split(',') as FIREBASE_ONCOGENICITY[];
67+
setSelectedOncogenicity(oncogencities);
68+
const existingMutationTypes = range.mutationTypes.split(',');
69+
setSelectedMutationTypes(existingMutationTypes);
5770
setAlias(range.alias);
5871
setInitialAlias(range.alias);
59-
setCurrentStep(AddRangeStep.ALIAS);
72+
setDescription(range.description);
73+
updateEditedDescription(range.description, range.start, range.end, oncogencities, existingMutationTypes);
74+
setCurrentStep(AddRangeStep.DESCRIPTION);
6075
}),
6176
);
6277
}
@@ -76,19 +91,30 @@ function AddRangeModal({ hugoSymbol, isGermline, onCancel, onConfirm, rangeToEdi
7691
case AddRangeStep.ALIAS:
7792
errorMessage = validateAlias(alias, existingAliases, initialAlias);
7893
break;
94+
case AddRangeStep.DESCRIPTION:
95+
errorMessage = validateDescription(description);
96+
break;
7997
default:
8098
}
8199

82100
function nextStep() {
101+
if (currentStep.valueOf() === AddRangeStep.DESCRIPTION.valueOf() - 1 && !editedDescription) {
102+
setDescription(getDescriptionFromRange(position[0]!, position[1]!, selectedOncogenicity, selectedMutationTypes));
103+
}
83104
setCurrentStep(step => step.valueOf() + 1);
84105
}
85106

86107
function prevStep() {
87108
setCurrentStep(step => step.valueOf() - 1);
88109
}
89110

90-
function toggleOncogenicity(value: string) {
91-
setSelectedOncogenicity(prev => (prev.includes(value) ? prev.filter(v => v !== value) : [...prev, value]));
111+
function toggleOncogenicity(value: FIREBASE_ONCOGENICITY) {
112+
setSelectedOncogenicity(prev => {
113+
const newSelectedOncogenicities = prev.includes(value) ? prev.filter(v => v !== value) : [...prev, value];
114+
return newSelectedOncogenicities.sort(
115+
(a, b) => Object.values(FIREBASE_ONCOGENICITY).indexOf(a) - Object.values(FIREBASE_ONCOGENICITY).indexOf(b),
116+
);
117+
});
92118
}
93119

94120
function toggleMutationType(value: string) {
@@ -156,9 +182,27 @@ function AddRangeModal({ hugoSymbol, isGermline, onCancel, onConfirm, rangeToEdi
156182
</>
157183
)}
158184
{currentStep.valueOf() >= AddRangeStep.ALIAS.valueOf() && (
159-
<>
185+
<div className="mb-2">
160186
<Label>Alias</Label>
161-
<Input value={alias} placeholder="Enter an alias for the range" onChange={event => setAlias(event.target.value)} />
187+
<Input
188+
disabled={currentStep !== AddRangeStep.ALIAS}
189+
value={alias}
190+
placeholder="Enter an alias for the range"
191+
onChange={event => setAlias(event.target.value)}
192+
/>
193+
</div>
194+
)}
195+
{currentStep.valueOf() >= AddRangeStep.DESCRIPTION.valueOf() && (
196+
<>
197+
<Label>Description</Label>
198+
<Input
199+
value={description}
200+
placeholder="Enter an alias for the range"
201+
onChange={event => {
202+
setDescription(event.target.value);
203+
updateEditedDescription(event.target.value, position[0]!, position[1]!, selectedOncogenicity, selectedMutationTypes);
204+
}}
205+
/>
162206
</>
163207
)}
164208
</ModalBody>
@@ -182,7 +226,7 @@ function AddRangeModal({ hugoSymbol, isGermline, onCancel, onConfirm, rangeToEdi
182226
disabled={!!errorMessage}
183227
color="primary"
184228
onClick={() => {
185-
onConfirm(alias, position[0]!, position[1]!, selectedOncogenicity, selectedMutationTypes);
229+
onConfirm(alias, position[0]!, position[1]!, selectedOncogenicity, selectedMutationTypes, editedDescription || description);
186230
}}
187231
>
188232
Confirm
@@ -226,3 +270,11 @@ function validateAlias(alias: string, existingAliases: string[], existingAlias?:
226270
}
227271
return undefined;
228272
}
273+
274+
function validateDescription(description: string) {
275+
description = description.trim();
276+
if (!description) {
277+
return 'Description must be specified';
278+
}
279+
return undefined;
280+
}

src/main/webapp/app/shared/model/firebase/firebase.model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,4 +531,5 @@ export type MutationRange = {
531531
end: number;
532532
oncogenicities: string;
533533
mutationTypes: string;
534+
description: string;
534535
};

src/main/webapp/app/shared/util/firebase/firebase-utils.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,14 +1019,15 @@ export function isStringEmpty(string: string | undefined | null) {
10191019
return string === '' || _.isNil(string);
10201020
}
10211021

1022-
export function getMutationNameFromRange(alias: string, start: number, end: number, oncogenicities: string[], mutationTypes: string[]) {
1022+
export function getDescriptionFromRange(start: number, end: number, oncogenicities: string[], mutationTypes: string[]) {
10231023
let mutationName = '';
10241024
if (oncogenicities.length > 0) {
1025-
mutationName += oncogenicities.map(onc => FIREBASE_ONCOGENICITY_MAPPING[onc]).join('/') + ' ';
1025+
mutationName += oncogenicities.map(onc => FIREBASE_ONCOGENICITY_MAPPING[onc]).join('/');
1026+
} else {
1027+
mutationName += 'All';
10261028
}
10271029
if (mutationTypes.length > 0) {
1028-
mutationName += mutationTypes.join('/') + ' ';
1030+
mutationName += ' ' + mutationTypes.join('/');
10291031
}
1030-
mutationName += `mutations at positions ${start}-${end}`;
1031-
return `${mutationName} [${alias}]`; // add comma to make it a string mutation
1032+
return (mutationName = `${mutationName} mutations at positions ${start}-${end}`);
10321033
}

0 commit comments

Comments
 (0)