diff --git a/client/src/components/Pages/Structure/Input/StaticElement/StaticElement.tsx b/client/src/components/Pages/Structure/Input/StaticElement/StaticElement.tsx index c97b963f..ea8a1f9d 100644 --- a/client/src/components/Pages/Structure/Input/StaticElement/StaticElement.tsx +++ b/client/src/components/Pages/Structure/Input/StaticElement/StaticElement.tsx @@ -12,7 +12,7 @@ const StaticElement: React.FC = ({ handleDelete, validated: true, icon, - pendingResponse: false + pendingResponse: false, }); export default StaticElement; diff --git a/client/src/components/Pages/Structure/Input/StructuralElementInputProps.tsx b/client/src/components/Pages/Structure/Input/StructuralElementInputProps.tsx index ef4aa869..354e8913 100644 --- a/client/src/components/Pages/Structure/Input/StructuralElementInputProps.tsx +++ b/client/src/components/Pages/Structure/Input/StructuralElementInputProps.tsx @@ -4,7 +4,7 @@ export interface BaseStructuralElementProps { element: ClientElementUnion; handleDelete?: (id?: string) => void; icon: JSX.Element; - pendingResponse?: boolean + pendingResponse?: boolean; } export interface StructuralElementInputProps diff --git a/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx b/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx index 537b1a9e..b0b1cb44 100644 --- a/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx +++ b/client/src/components/Pages/Structure/Input/TxSegmentElementInput/TxSegmentElementInput.tsx @@ -1,16 +1,18 @@ -import { TextField, MenuItem, Typography } from "@material-ui/core"; +import { + TextField, + MenuItem, + Typography, + Box, + FormControl, + InputLabel, + Select, +} from "@material-ui/core"; import { ClientTranscriptSegmentElement, TranscriptSegmentElement, TxSegmentElementResponse, } from "../../../../../services/ResponseModels"; -import React, { - useEffect, - useState, - KeyboardEvent, - useContext, - ChangeEvent, -} from "react"; +import React, { useEffect, useState, KeyboardEvent, ChangeEvent } from "react"; import { getTxSegmentElementEC, getTxSegmentElementGC, @@ -20,16 +22,19 @@ import { import { GeneAutocomplete } from "../../../../main/shared/GeneAutocomplete/GeneAutocomplete"; import { StructuralElementInputProps } from "../StructuralElementInputProps"; import StructuralElementInputAccordion from "../StructuralElementInputAccordion"; -import { FusionContext } from "../../../../../global/contexts/FusionContext"; import HelpTooltip from "../../../../main/shared/HelpTooltip/HelpTooltip"; import ChromosomeField from "../../../../main/shared/ChromosomeField/ChromosomeField"; import TranscriptField from "../../../../main/shared/TranscriptField/TranscriptField"; -import { Box, FormControl, InputLabel, Select } from "@mui/material"; interface TxSegmentElementInputProps extends StructuralElementInputProps { element: ClientTranscriptSegmentElement; } +enum GenomicInputType { + GENE = "gene", + TRANSCRIPT = "transcript", +} + const TxSegmentCompInput: React.FC = ({ element, index, @@ -37,12 +42,19 @@ const TxSegmentCompInput: React.FC = ({ handleDelete, icon, }) => { - const { fusion } = useContext(FusionContext); - const [txInputType, setTxInputType] = useState( (element.inputType as TxElementInputType) || TxElementInputType.default ); + const [genomicInputType, setGenomicInputType] = + useState( + element.inputGene + ? GenomicInputType.GENE + : element.inputTx + ? GenomicInputType.TRANSCRIPT + : null + ); + // "Text" variables refer to helper or warning text to set under input fields // TODO: this needs refactored so badly const [txAc, setTxAc] = useState(element.inputTx || ""); @@ -80,19 +92,25 @@ const TxSegmentCompInput: React.FC = ({ const [endingExonOffsetText, setEndingExonOffsetText] = useState(""); const [geneTranscripts, setGeneTranscripts] = useState([]); - const [selectedTranscript, setSelectedTranscript] = useState(""); + const [selectedTranscript, setSelectedTranscript] = useState( + element.inputTx || "" + ); const [pendingResponse, setPendingResponse] = useState(false); const hasRequiredEnds = txEndingGenomic || endingExon || txStartingGenomic || startingExon; + const genomicInputComplete = + genomicInputType === GenomicInputType.GENE + ? txGene !== "" && selectedTranscript !== "" + : txAc !== ""; + // programming horror const inputComplete = (txInputType === TxElementInputType.gc && - txGene !== "" && + genomicInputComplete && txChrom !== "" && - selectedTranscript !== "" && (txStartingGenomic !== "" || txEndingGenomic !== "")) || (txInputType === TxElementInputType.ec && txAc !== "" && @@ -201,8 +219,6 @@ const TxSegmentCompInput: React.FC = ({ setEndingExonOffsetText(""); }; - console.log(pendingResponse); - /** * Request construction of tx segment element from server and handle response */ @@ -400,40 +416,53 @@ const TxSegmentCompInput: React.FC = ({ ); const renderTxOptions = () => { + if (!genomicInputType) { + return <>; + } switch (txInputType) { case TxElementInputType.gc: return ( - - - Transcript - - + {genomicInputType === GenomicInputType.GENE ? ( + <> + + + + Transcript + + + + + ) : ( + <> + {txInputField} + + )} {genomicCoordinateInfo} @@ -606,9 +635,10 @@ const TxSegmentCompInput: React.FC = ({ } > - + Select input data + {txInputType === TxElementInputType.gc ? ( + + + Gene or Transcript? + + + + ) : ( + <> + )} diff --git a/client/src/components/Utilities/GetSequence/GetSequence.tsx b/client/src/components/Utilities/GetSequence/GetSequence.tsx index 0c6bd707..52bf4132 100644 --- a/client/src/components/Utilities/GetSequence/GetSequence.tsx +++ b/client/src/components/Utilities/GetSequence/GetSequence.tsx @@ -189,7 +189,9 @@ const GetSequenceIds: React.FC = () => { ); - const renderedIdInfo = isLoading ? () : ( + const renderedIdInfo = isLoading ? ( + + ) : ( diff --git a/client/src/components/Utilities/GetTranscripts/GetTranscripts.tsx b/client/src/components/Utilities/GetTranscripts/GetTranscripts.tsx index 6b89cf53..a81ace03 100644 --- a/client/src/components/Utilities/GetTranscripts/GetTranscripts.tsx +++ b/client/src/components/Utilities/GetTranscripts/GetTranscripts.tsx @@ -123,7 +123,7 @@ export const GetTranscripts: React.FC = () => { const renderTranscripts = () => { if (isLoading) { - return () + return ; } if (transcriptWarnings.length > 0) { // TODO more error handling here diff --git a/client/src/components/main/shared/GeneAutocomplete/GeneAutocomplete.tsx b/client/src/components/main/shared/GeneAutocomplete/GeneAutocomplete.tsx index c0773f8a..d15bca10 100644 --- a/client/src/components/main/shared/GeneAutocomplete/GeneAutocomplete.tsx +++ b/client/src/components/main/shared/GeneAutocomplete/GeneAutocomplete.tsx @@ -3,8 +3,16 @@ import { TextField, Typography, makeStyles } from "@material-ui/core"; import Autocomplete, { AutocompleteRenderGroupParams, } from "@material-ui/lab/Autocomplete"; -import { getGeneSuggestions, getTranscripts, getTranscriptsForGene } from "../../../../services/main"; -import { GetGeneTranscriptsResponse, GetTranscriptsResponse, SuggestGeneResponse } from "../../../../services/ResponseModels"; +import { + getGeneSuggestions, + getTranscripts, + getTranscriptsForGene, +} from "../../../../services/main"; +import { + GetGeneTranscriptsResponse, + GetTranscriptsResponse, + SuggestGeneResponse, +} from "../../../../services/ResponseModels"; import HelpTooltip from "../HelpTooltip/HelpTooltip"; import { useColorTheme } from "../../../../global/contexts/Theme/ColorThemeContext"; @@ -27,7 +35,7 @@ const defaultGeneOption: SuggestedGeneOption = { value: "", type: GeneSuggestionType.none, chromosome: "", - strand: "" + strand: "", }; interface Props { @@ -96,7 +104,9 @@ export const GeneAutocomplete: React.FC = ({ setGeneValue(selection); if (setChromosome) { // substring is to remove identifier from beginning of chromosome (ex: result in NC_000007.14 instead of NCBI:NC_000007.14) - setChromosome(selection.chromosome?.substring(selection.chromosome.indexOf(":") + 1)); + setChromosome( + selection.chromosome?.substring(selection.chromosome.indexOf(":") + 1) + ); } if (setStrand) { setStrand(selection.strand); @@ -104,24 +114,31 @@ export const GeneAutocomplete: React.FC = ({ if (setTranscripts) { // if user is pressing the X button to clear the autocomplete input, set tx info to default if (selection === defaultGeneOption) { - setTranscripts([]) + setTranscripts([]); if (setDefaultTranscript) { - setDefaultTranscript("") + setDefaultTranscript(""); } return; } - getTranscriptsForGene(selection.value).then((transcriptsResponse: GetGeneTranscriptsResponse) => { - const transcripts = transcriptsResponse.transcripts - const sortedTranscripts = transcripts.sort((a, b) => a.localeCompare(b)) - setTranscripts(sortedTranscripts); - if (setDefaultTranscript) { - // get preferred default transcript from MANE endpoint - getTranscripts(selection.value).then((transcriptsResponse: GetTranscriptsResponse) => { - const preferredTx = transcriptsResponse?.transcripts?.[0].RefSeq_nuc - setDefaultTranscript(preferredTx || transcripts[0]) - }); + getTranscriptsForGene(selection.value).then( + (transcriptsResponse: GetGeneTranscriptsResponse) => { + const transcripts = transcriptsResponse.transcripts; + const sortedTranscripts = transcripts.sort((a, b) => + a.localeCompare(b) + ); + setTranscripts(sortedTranscripts); + if (setDefaultTranscript) { + // get preferred default transcript from MANE endpoint + getTranscripts(selection.value).then( + (transcriptsResponse: GetTranscriptsResponse) => { + const preferredTx = + transcriptsResponse?.transcripts?.[0].RefSeq_nuc; + setDefaultTranscript(preferredTx || transcripts[0]); + } + ); + } } - }); + ); } }; @@ -130,7 +147,7 @@ export const GeneAutocomplete: React.FC = ({ if (inputValue.value === "") { setGeneText(""); setGeneOptions([]); - updateSelection(defaultGeneOption) + updateSelection(defaultGeneOption); setLoading(false); } else { setLoading(true); diff --git a/client/src/components/main/shared/LoadingMessage/LoadingMessage.tsx b/client/src/components/main/shared/LoadingMessage/LoadingMessage.tsx index 955bd158..9274dbb7 100644 --- a/client/src/components/main/shared/LoadingMessage/LoadingMessage.tsx +++ b/client/src/components/main/shared/LoadingMessage/LoadingMessage.tsx @@ -8,11 +8,17 @@ interface LoadingMessageProps { export default function StrandSwitch( props: LoadingMessageProps ): React.ReactElement { - const loadingMessage = props?.message ? props.message : "Loading..." + const loadingMessage = props?.message ? props.message : "Loading..."; return ( - + {loadingMessage} - + ); } diff --git a/client/src/services/ResponseModels.ts b/client/src/services/ResponseModels.ts index bf63b2d7..d6d40e28 100644 --- a/client/src/services/ResponseModels.ts +++ b/client/src/services/ResponseModels.ts @@ -538,7 +538,7 @@ export interface ClientTranscriptSegmentElement { gene: Gene; elementGenomicStart?: SequenceLocation | null; elementGenomicEnd?: SequenceLocation | null; - inputType: "genomic_coords_gene" | "genomic_coords_tx" | "exon_coords"; + inputType: "genomic_coords" | "exon_coords"; inputTx?: string | null; inputStrand?: Strand | null; inputGene?: string | null; @@ -769,7 +769,7 @@ export interface GetDomainResponse { domain: FunctionalDomain | null; } /** - * Response model for MANE transcript retrieval endpoint. + * Response model for retrieving list of transcripts for a given gene */ export interface GetGeneTranscriptsResponse { warnings?: string[] | null; diff --git a/server/src/curfu/schemas.py b/server/src/curfu/schemas.py index 8c8e5667..43f92051 100644 --- a/server/src/curfu/schemas.py +++ b/server/src/curfu/schemas.py @@ -51,11 +51,7 @@ class ClientStructuralElement(BaseModel): class ClientTranscriptSegmentElement(TranscriptSegmentElement, ClientStructuralElement): """TranscriptSegment element class used client-side.""" - inputType: ( - Literal["genomic_coords_gene"] - | Literal["genomic_coords_tx"] - | Literal["exon_coords"] - ) + inputType: Literal["genomic_coords"] | Literal["exon_coords"] inputTx: str | None = None inputStrand: Strand | None = None inputGene: str | None = None