Skip to content

Commit

Permalink
Fix adding CDx biomarker association (#450)
Browse files Browse the repository at this point in the history
  • Loading branch information
calvinlu3 authored Sep 30, 2024
1 parent 8200d24 commit 88e15ca
Show file tree
Hide file tree
Showing 9 changed files with 60 additions and 73 deletions.
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';
import { Menu } from 'react-pro-sidebar';
import { Button, Form } from 'reactstrap';
import { Button, Container, Form } from 'reactstrap';
import { ENTITY_ACTION, ENTITY_TYPE, SearchOptionType } from 'app/config/constants/constants';
import { useHistory, useLocation } from 'react-router-dom';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faPlus, width } from '@fortawesome/free-solid-svg-icons/faPlus';
import { faPlus } from '@fortawesome/free-solid-svg-icons/faPlus';
import DefaultTooltip from 'app/shared/tooltip/DefaultTooltip';
import CancerTypeSelect, { CancerTypeSelectOption } from 'app/shared/select/CancerTypeSelect';
import { SaveButton } from 'app/shared/button/SaveButton';
import GeneSelect from 'app/shared/select/GeneSelect';
import GeneSelect, { GeneSelectOption } from 'app/shared/select/GeneSelect';
import AlterationSelect, { AlterationSelectOption } from 'app/shared/select/AlterationSelect';
import DrugSelect, { DrugSelectOption } from 'app/shared/select/DrugSelect';
import FdaSubmissionSelect, { FdaSubmissionSelectOption } from 'app/shared/select/FdaSubmissionSelect';
import { connect } from 'app/shared/util/typed-inject';
import { IRootStore } from 'app/stores';
import { getEntityActionRoute } from 'app/shared/util/RouteUtils';
import { Alteration, Association, CancerType, Drug, FdaSubmission } from 'app/shared/api/generated/curation';
import { associationClient } from 'app/shared/api/clients';
import { notifyError, notifySuccess } from 'app/oncokb-commons/components/util/NotificationUtils';
import { IFdaSubmission } from 'app/shared/model/fda-submission.model';
import { IRootStore } from 'app/stores';
import { connect } from 'app/shared/util/typed-inject';

const SidebarMenuItem: React.FunctionComponent<{ style?: React.CSSProperties; children: React.ReactNode }> = ({ style, children }) => {
return <div style={{ padding: '0.5rem 1rem', ...style }}>{children}</div>;
Expand All @@ -29,8 +28,8 @@ export const defaultAdditional = {
type: SearchOptionType.GENE,
};

const CompanionDiagnosticDevicePanel: React.FunctionComponent<StoreProps> = props => {
const [selectedGeneId, setSelectedGeneId] = useState<string>();
const CompanionDiagnosticDevicePanel: React.FunctionComponent<StoreProps> = ({ getEntity }: StoreProps) => {
const [geneValue, setGeneValue] = useState<GeneSelectOption | null>(null);
const [alterationValue, onAlterationChange] = useState<readonly AlterationSelectOption[]>();
const [cancerTypeValue, onCancerTypeChange] = useState<CancerTypeSelectOption | null>(null);
const [drugValue, onDrugChange] = useState<readonly DrugSelectOption[]>([]);
Expand All @@ -40,6 +39,20 @@ const CompanionDiagnosticDevicePanel: React.FunctionComponent<StoreProps> = prop
const location = useLocation();
const id = parseInt(location.pathname.split('/')[2], 10);

useEffect(() => {
if (geneValue === null) {
onAlterationChange([]);
}
}, [geneValue]);

const resetValues = () => {
onAlterationChange([]);
setGeneValue(null);
onCancerTypeChange(null);
onDrugChange([]);
onFdaSubmissionChange([]);
};

const createBiomarkerAssociation = (e: any) => {
e.preventDefault();
const association: Association = {
Expand Down Expand Up @@ -76,6 +89,8 @@ const CompanionDiagnosticDevicePanel: React.FunctionComponent<StoreProps> = prop
associationClient
.createAssociation(association)
.then(() => {
getEntity(id); // Refresh CDx association table
resetValues();
notifySuccess('Biomarker association added.');
})
.catch(error => notifyError(error));
Expand All @@ -90,23 +105,23 @@ const CompanionDiagnosticDevicePanel: React.FunctionComponent<StoreProps> = prop
};

return (
<div>
<Container>
<h4 style={{ marginBottom: '2rem', marginLeft: '1rem' }}>Curation Panel</h4>
<Menu>
<Form onSubmit={createBiomarkerAssociation}>
<SidebarMenuItem>Add Biomarker Association</SidebarMenuItem>
<SidebarMenuItem>
<GeneSelect
onChange={option => {
const geneId = option ? option.value : null;
setSelectedGeneId(geneId?.toString());
}}
/>
<GeneSelect onChange={setGeneValue} value={geneValue} />
</SidebarMenuItem>
<SidebarMenuItem>
<div style={{ display: 'flex' }}>
<div className="d-flex align-items-start">
<div style={{ flex: 1 }}>
<AlterationSelect isMulti geneId={selectedGeneId ?? ''} onChange={onAlterationChange} />
<AlterationSelect
isMulti
geneId={geneValue?.value?.toString() ?? ''}
onChange={onAlterationChange}
value={alterationValue}
/>
</div>
<DefaultTooltip overlay={'Create new alteration'}>
<Button className="ms-1" color="primary" onClick={redirectToCreateAlteration}>
Expand All @@ -116,17 +131,23 @@ const CompanionDiagnosticDevicePanel: React.FunctionComponent<StoreProps> = prop
</div>
</SidebarMenuItem>
<SidebarMenuItem>
<CancerTypeSelect onChange={onCancerTypeChange} />
<CancerTypeSelect onChange={onCancerTypeChange} value={cancerTypeValue} />
</SidebarMenuItem>
<SidebarMenuItem>
<DrugSelect isMulti onChange={onDrugChange} />
<DrugSelect isMulti onChange={onDrugChange} value={drugValue} placeholder={'Select drug(s)'} />
</SidebarMenuItem>
<SidebarMenuItem>
<div style={{ display: 'flex' }}>
<div className="d-flex align-items-start">
<div style={{ flex: 1 }}>
<FdaSubmissionSelect cdxId={id} isMulti onChange={onFdaSubmissionChange} />
<FdaSubmissionSelect
cdxId={id}
isMulti
onChange={onFdaSubmissionChange}
value={fdaSubmissionValue}
placeholder={'Select FDA submission(s)'}
/>
</div>
<DefaultTooltip overlay={'Create new Fda Submission'}>
<DefaultTooltip overlay={'Create new FDA submission'}>
<Button className="ms-1" color="primary" onClick={redirectToCreateFdaSubmission}>
<FontAwesomeIcon icon={faPlus} size="sm" />
</Button>
Expand All @@ -138,11 +159,13 @@ const CompanionDiagnosticDevicePanel: React.FunctionComponent<StoreProps> = prop
</SidebarMenuItem>
</Form>
</Menu>
</div>
</Container>
);
};

const mapStoreToProps = ({ associationStore }: IRootStore) => ({});
const mapStoreToProps = ({ companionDiagnosticDeviceStore }: IRootStore) => ({
getEntity: companionDiagnosticDeviceStore.getEntity,
});

type StoreProps = ReturnType<typeof mapStoreToProps>;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ import { notifyError } from 'app/oncokb-commons/components/util/NotificationUtil
import _ from 'lodash';
import LoadingIndicator, { LoaderSize } from 'app/oncokb-commons/components/loadingIndicator/LoadingIndicator';
import { convertDateTimeFromServer, convertDateTimeToServer } from 'app/shared/util/date-utils';
import GenericSidebar from 'app/components/sidebar/OncoKBSidebar';
import CompanionDiagnosticDevicePanel from 'app/components/panels/CompanionDiagnosticDevicePanel';
import { WHOLE_NUMBER_REGEX } from 'app/config/constants/regex';
import { ISpecimenType } from 'app/shared/model/specimen-type.model';
import OncoKBSidebar from 'app/components/sidebar/OncoKBSidebar';

export interface ICompanionDiagnosticDeviceUpdateProps extends StoreProps, RouteComponentProps<{ id: string }> {}

Expand Down Expand Up @@ -185,9 +185,9 @@ export const CompanionDiagnosticDeviceUpdate = (props: ICompanionDiagnosticDevic
) : undefined}
</>
)}
<GenericSidebar>
<OncoKBSidebar>
<CompanionDiagnosticDevicePanel />
</GenericSidebar>
</OncoKBSidebar>
</>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { TextFormat } from 'react-jhipster';
import _ from 'lodash';
import { filterByKeyword, getEntityTableActionsColumn } from 'app/shared/util/utils';
import OncoKBTable, { SearchColumn } from 'app/shared/table/OncoKBTable';
import { IDrug } from 'app/shared/model/drug.model';
export interface ICompanionDiagnosticDeviceProps extends StoreProps, RouteComponentProps<{ url: string }> {}

export const getFdaSubmissionNumber = (primaryNumber: string | undefined, supplementNumber: string | undefined) => {
Expand Down
19 changes: 3 additions & 16 deletions src/main/webapp/app/shared/select/AlterationSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react';
import { ActionMeta, OnChangeValue, Props as SelectProps, SingleValue } from 'react-select';
import { OnChangeValue, Props as SelectProps } from 'react-select';
import { IRootStore } from 'app/stores/createStore';
import { InjectProps, connect } from '../util/typed-inject';
import { IAlteration } from '../model/alteration.model';
Expand All @@ -18,7 +18,6 @@ interface IAlterationSelectProps extends SelectProps<AlterationSelectOption, tru
const AlterationSelect = (props: IAlterationSelectProps) => {
const { geneId, getAlterationsByGeneId, ...selectProps } = props;
const [alterationList, setAlterationList] = useState<OnChangeValue<AlterationSelectOption, true>>([]);
const [alterationValue, setAlterationValue] = useState<OnChangeValue<AlterationSelectOption, true> | null>(null);

useEffect(() => {
const loadAlterationOptions = async (id: string) => {
Expand All @@ -36,28 +35,16 @@ const AlterationSelect = (props: IAlterationSelectProps) => {
}
};
loadAlterationOptions(geneId);
if (!geneId) {
setAlterationValue(null);
}
}, [geneId]);

const onAlterationChange: (
newValue: OnChangeValue<AlterationSelectOption, true>,
actionMeta: ActionMeta<AlterationSelectOption>,
) => void = (option, actionMeta) => {
setAlterationValue(option);
props.onChange?.(option, actionMeta);
};

return (
<Select
{...selectProps}
isMulti
name={'alterations'}
value={alterationValue}
options={alterationList}
onChange={onAlterationChange}
placeholder="Select an alteration..."
onChange={props.onChange}
placeholder="Select alteration(s)"
isDisabled={!geneId}
isClearable
/>
Expand Down
2 changes: 1 addition & 1 deletion src/main/webapp/app/shared/select/CancerTypeSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ const CancerTypeSelect = <IsMulti extends boolean>(props: ICancerTypeSelectProps
disabledOptions?.some(disabled => disabled !== undefined && option !== undefined && disabled.value === option.value) || false
}
cacheUniqs={[props.value]}
placeholder="Select a cancer type..."
placeholder="Select cancer type"
isClearable
/>
);
Expand Down
4 changes: 2 additions & 2 deletions src/main/webapp/app/shared/select/DrugSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ const DrugSelect = <IsMulti extends boolean>(props: IDrugSelectProps<IsMulti>) =

return (
<AsyncSelect
{...selectProps}
placeholder="Select drug"
components={{
Option,
}}
Expand All @@ -147,8 +147,8 @@ const DrugSelect = <IsMulti extends boolean>(props: IDrugSelectProps<IsMulti>) =
onInputChange={setInput}
loadOptions={loadOptions}
options={drugOptions}
placeholder="Select a drug..."
isClearable
{...selectProps}
/>
);
};
Expand Down
24 changes: 1 addition & 23 deletions src/main/webapp/app/shared/select/FdaSubmissionSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ const FdaSubmissionSelect = <IsMulti extends boolean>(props: IFdaSubmissionSelec
const [fdaSubmissionList, setFdaSubmissionList] = useState<
OptionsOrGroups<FdaSubmissionSelectOption, GroupBase<FdaSubmissionSelectOption>> | undefined
>([]);
const [fdaSubmissionValue, setFdaSubmissionValue] = useState<OnChangeValue<FdaSubmissionSelectOption, IsMulti> | null>(null);

useEffect(() => {
const loadFdaSubmissionOptions = async (id: number) => {
Expand All @@ -37,30 +36,9 @@ const FdaSubmissionSelect = <IsMulti extends boolean>(props: IFdaSubmissionSelec
}
};
loadFdaSubmissionOptions(cdxId);
if (!cdxId) {
setFdaSubmissionValue(null);
}
}, [cdxId]);

const onFdaSubmissionChange: (
newValue: OnChangeValue<FdaSubmissionSelectOption, IsMulti>,
actionMeta: ActionMeta<FdaSubmissionSelectOption>,
) => void = (option, actionMeta) => {
setFdaSubmissionValue(option);
props.onChange?.(option, actionMeta);
};

return (
<Select
{...selectProps}
name={'fdaSubmissions'}
value={fdaSubmissionValue}
options={fdaSubmissionList}
onChange={onFdaSubmissionChange}
placeholder="Select an fda submission..."
isClearable
/>
);
return <Select placeholder="Select FDA submission" name={'fdaSubmissions'} options={fdaSubmissionList} isClearable {...selectProps} />;
};

const mapStoreToProps = ({ fdaSubmissionStore }: IRootStore) => ({
Expand Down
4 changes: 2 additions & 2 deletions src/main/webapp/app/shared/select/GeneSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const GeneSelect = <IsMulti extends boolean>(props: IGeneSelectProps<IsMulti>) =
const loadGeneOptions: LoadOptions<GeneSelectOption, GroupBase<GeneSelectOption>, { page: number; type: SearchOptionType }> = async (
searchWord,
_,
{ page, type } = { page: 0, type: SearchOptionType.CDX },
{ page, type } = { page: 0, type: SearchOptionType.GENE },
) => {
let result: Awaited<ReturnType<typeof getGenes>> | undefined = undefined;
let options: GeneSelectOption[] = [];
Expand Down Expand Up @@ -92,7 +92,7 @@ const GeneSelect = <IsMulti extends boolean>(props: IGeneSelectProps<IsMulti>) =
additional={{ ...defaultAdditional, type: SearchOptionType.GENE }}
loadOptions={loadGeneOptions}
cacheUniqs={[props.value]}
placeholder="Select a gene..."
placeholder="Select gene"
onInputChange={input => setSearchInput(input)}
isClearable
/>
Expand Down
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 88e15ca

Please sign in to comment.