Skip to content

Commit

Permalink
pass around formatted fusion to reduce repeated code
Browse files Browse the repository at this point in the history
  • Loading branch information
katiestahl committed Jul 30, 2024
1 parent c8dd15b commit de83ee9
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 162 deletions.
107 changes: 6 additions & 101 deletions client/src/components/Pages/Summary/JSON/SummaryJSON.tsx
Original file line number Diff line number Diff line change
@@ -1,118 +1,23 @@
import copy from "clipboard-copy";
import React, { useEffect, useState } from "react";
import { validateFusion } from "../../../../services/main";
import {
ClientElementUnion,
ElementUnion,
validateFusion,
} from "../../../../services/main";
import {
AssayedFusion,
CategoricalFusion,
FunctionalDomain,
GeneElement,
LinkerElement,
MultiplePossibleGenesElement,
TemplatedSequenceElement,
TranscriptSegmentElement,
UnknownGeneElement,
FormattedAssayedFusion,
FormattedCategoricalFusion,
} from "../../../../services/ResponseModels";
import { FusionType } from "../Main/Summary";
import "./SummaryJSON.scss";

interface Props {
fusion: FusionType;
formattedFusion: FormattedAssayedFusion | FormattedCategoricalFusion;
}

export const SummaryJSON: React.FC<Props> = ({ fusion }) => {
export const SummaryJSON: React.FC<Props> = ({ formattedFusion }) => {
const [isDown, setIsDown] = useState<boolean>(false);
const [isCopied, setIsCopied] = useState<boolean>(false);
const [printedFusion, setPrintedFusion] = useState<string>("");
const [validationErrors, setValidationErrors] = useState<string[]>([]);

/**
* On component render, restructure fusion to drop properties used for client state purposes,
* transmit to validation endpoint, and update local copy.
*/
useEffect(() => {
const structuralElements: ElementUnion[] = fusion.structure?.map(
(element: ClientElementUnion) => {
switch (element.type) {
case "GeneElement":
const geneElement: GeneElement = {
type: element.type,
gene: element.gene,
};
return geneElement;
case "LinkerSequenceElement":
const linkerElement: LinkerElement = {
type: element.type,
linker_sequence: element.linker_sequence,
};
return linkerElement;
case "TemplatedSequenceElement":
const templatedSequenceElement: TemplatedSequenceElement = {
type: element.type,
region: element.region,
strand: element.strand,
};
return templatedSequenceElement;
case "TranscriptSegmentElement":
const txSegmentElement: TranscriptSegmentElement = {
type: element.type,
transcript: element.transcript,
exon_start: element.exon_start,
exon_start_offset: element.exon_start_offset,
exon_end: element.exon_end,
exon_end_offset: element.exon_end_offset,
gene: element.gene,
element_genomic_start: element.element_genomic_start,
element_genomic_end: element.element_genomic_end,
};
return txSegmentElement;
case "MultiplePossibleGenesElement":
case "UnknownGeneElement":
const newElement:
| MultiplePossibleGenesElement
| UnknownGeneElement = {
type: element.type,
};
return newElement;
default:
throw new Error("Unrecognized element type");
}
}
);
const regulatoryElements = fusion.regulatoryElements?.map((re) => ({
type: re.type,
associated_gene: re.associated_gene,
regulatory_class: re.regulatory_class,
featureId: re.featureId,
genomic_location: re.genomic_location,
}));
let formattedFusion: AssayedFusion | CategoricalFusion;
if (fusion.type === "AssayedFusion") {
formattedFusion = {
...fusion,
structure: structuralElements,
regulatoryElements: regulatoryElements,
};
} else {
const criticalDomains: FunctionalDomain[] =
fusion.criticalFunctionalDomains?.map((domain) => ({
_id: domain._id,
label: domain.label,
status: domain.status,
associated_gene: domain.associated_gene,
sequence_location: domain.sequence_location,
}));
formattedFusion = {
...fusion,
structure: structuralElements,
regulatoryElements: regulatoryElements,
criticalFunctionalDomains: criticalDomains,
};
}

// make request
validateFusion(formattedFusion).then((response) => {
if (response.warnings && response.warnings?.length > 0) {
Expand All @@ -126,7 +31,7 @@ export const SummaryJSON: React.FC<Props> = ({ fusion }) => {
setPrintedFusion(JSON.stringify(response.fusion, null, 2));
}
});
}, [fusion]); // should be blank?
}, [formattedFusion]);

const handleCopy = () => {
copy(printedFusion);
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/Pages/Summary/Success/Success.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export const Success: React.FC<Props> = ({ fusion }) => {
</TabPanel>
<TabPanel value={currentTab} index={1}>
<div className="summary-sub-tab">
{fusion && <SummaryJSON fusion={fusion} />}
{fusion && <SummaryJSON formattedFusion={fusion} />}
</div>
</TabPanel>
</div>
Expand Down
86 changes: 28 additions & 58 deletions client/src/services/ResponseModels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
*/

/**
* Specify possible Fusion types.
* Form of evidence supporting identification of the fusion.
*/
export type FusionType = "CategoricalFusion" | "AssayedFusion";
export type Evidence = "observed" | "inferred";
/**
* Define possible classes of Regulatory Elements. Options are the possible values
* for /regulatory_class value property in the INSDC controlled vocabulary:
Expand Down Expand Up @@ -66,20 +66,6 @@ export type Range = [number | null, number | null];
* A character string of Residues that represents a biological sequence using the conventional sequence order (5'-to-3' for nucleic acid sequences, and amino-to-carboxyl for amino acid sequences). IUPAC ambiguity codes are permitted in Sequence Strings.
*/
export type SequenceString = string;
/**
* Define possible structural element type values.
*/
export type StructuralElementType =
| "TranscriptSegmentElement"
| "TemplatedSequenceElement"
| "LinkerSequenceElement"
| "GeneElement"
| "UnknownGeneElement"
| "MultiplePossibleGenesElement";
/**
* Form of evidence supporting identification of the fusion.
*/
export type Evidence = "observed" | "inferred";
/**
* Create enum for positive and negative strand
*/
Expand All @@ -95,13 +81,34 @@ export type EventType = "rearrangement" | "read-through" | "trans-splicing";
export type DomainStatus = "lost" | "preserved";

/**
* Define Fusion class
* Information pertaining to the assay used in identifying the fusion.
*/
export interface Assay {
type?: "Assay";
assayName?: string | null;
assayId?: string | null;
methodUri?: string | null;
fusionDetection?: Evidence | null;
}
/**
* Assayed gene fusions from biological specimens are directly detected using
* RNA-based gene fusion assays, or alternatively may be inferred from genomic
* rearrangements detected by whole genome sequencing or by coarser-scale cytogenomic
* assays. Example: an EWSR1 fusion inferred from a breakapart FISH assay.
*/
export interface AbstractFusion {
type: FusionType;
export interface AssayedFusion {
type?: "AssayedFusion";
regulatoryElement?: RegulatoryElement | null;
structure: BaseStructuralElement[];
structure: (
| TranscriptSegmentElement
| GeneElement
| TemplatedSequenceElement
| LinkerElement
| UnknownGeneElement
)[];
readingFramePreserved?: boolean | null;
causativeEvent?: CausativeEvent | null;
assay?: Assay | null;
}
/**
* Define RegulatoryElement class.
Expand Down Expand Up @@ -318,43 +325,6 @@ export interface SequenceReference {
circular?: boolean | null;
[k: string]: unknown;
}
/**
* Define base structural element class.
*/
export interface BaseStructuralElement {
type: StructuralElementType;
[k: string]: unknown;
}
/**
* Information pertaining to the assay used in identifying the fusion.
*/
export interface Assay {
type?: "Assay";
assayName?: string | null;
assayId?: string | null;
methodUri?: string | null;
fusionDetection?: Evidence | null;
}
/**
* Assayed gene fusions from biological specimens are directly detected using
* RNA-based gene fusion assays, or alternatively may be inferred from genomic
* rearrangements detected by whole genome sequencing or by coarser-scale cytogenomic
* assays. Example: an EWSR1 fusion inferred from a breakapart FISH assay.
*/
export interface AssayedFusion {
type?: "AssayedFusion";
regulatoryElement?: RegulatoryElement | null;
structure: (
| TranscriptSegmentElement
| GeneElement
| TemplatedSequenceElement
| LinkerElement
| UnknownGeneElement
)[];
readingFramePreserved?: boolean | null;
causativeEvent?: CausativeEvent | null;
assay?: Assay | null;
}
/**
* Define TranscriptSegment class
*/
Expand Down Expand Up @@ -849,5 +819,5 @@ export interface TxSegmentElementResponse {
*/
export interface ValidateFusionResponse {
warnings?: string[] | null;
fusion: AbstractFusion | null;
fusion: CategoricalFusion | AssayedFusion | null;
}
4 changes: 2 additions & 2 deletions server/src/curfu/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@

from cool_seq_tool.schemas import GenomicData
from fusor.models import (
AbstractFusion,
Assay,
AssayedFusion,
AssayedFusionElements,
CategoricalFusion,
CategoricalFusionElements,
CausativeEvent,
FunctionalDomain,
Fusion,
GeneElement,
LinkerElement,
MultiplePossibleGenesElement,
Expand Down Expand Up @@ -180,7 +180,7 @@ class AssociatedDomainResponse(Response):
class ValidateFusionResponse(Response):
"""Response model for Fusion validation endpoint."""

fusion: AbstractFusion | None
fusion: Fusion | None


class ExonCoordsRequest(BaseModel):
Expand Down

0 comments on commit de83ee9

Please sign in to comment.