Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cancel request class component #36

Merged
merged 2 commits into from
Aug 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions src/frontend/static/frontend/src/components/Base.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'
import React, { useEffect, useRef, useState } from 'react'
import { MainNavbar, ActiveItemOptions } from './MainNavbar'
import ky from 'ky'
import { DjangoUser } from '../utils/django_interfaces'
Expand Down Expand Up @@ -28,25 +28,32 @@ const CurrentUserContext = React.createContext<Nullable<DjangoUser>>(null)
* @returns Component
*/
const Base = (props: BaseProps) => {
const abortController = useRef(new AbortController())
const [currentUser, setUser] = useState<Nullable<DjangoUser>>(null)

/**
* Method which is executed when the component has mounted
*/
useEffect(getCurrentUser, [])
useEffect(() => {
getCurrentUser()
return () => {
// Cleanup: cancel the ongoing request when component unmounts
abortController.current.abort()
}
}, [])

/**
* Fetches logged User data
*/
function getCurrentUser () {
ky.get(urlCurrentUser, { retry: 5 }).then((response) => {
ky.get(urlCurrentUser, { retry: 5, signal: abortController.current.signal }).then((response) => {
response.json().then((currentUser: DjangoUser) => {
setUser(currentUser)
}).catch((err) => {
console.log('Error parsing JSON ->', err)
})
}).catch((err) => {
if (err.response.status === 403) {
if (err.response.status === 403 && !abortController.current.signal.aborted) {
// It's an anonymous user
setUser({
id: null,
Expand All @@ -66,7 +73,7 @@ const Base = (props: BaseProps) => {
return (
<CurrentUserContext.Provider value={currentUser}>
{/* Navbar */}
<MainNavbar activeItem={props.activeItem}/>
<MainNavbar activeItem={props.activeItem} />

{/* Composition part */}
<div className={props.wrapperClass}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,16 @@ interface BiomarkersPanelState {
selectedBiomarker: Nullable<Biomarker>,
alert: CustomAlert,
featureSelection: FeatureSelectionPanelData,
submittingFSExperiment: boolean
submittingFSExperiment: boolean,
openDetailsModal2: boolean

}

/**
* Renders a CRUD panel for a Biomarker.
*/
export class BiomarkersPanel extends React.Component<{}, BiomarkersPanelState> {
abortController = new AbortController()
constructor (props) {
super(props)

Expand All @@ -112,10 +115,19 @@ export class BiomarkersPanel extends React.Component<{}, BiomarkersPanelState> {
selectedBiomarker: null,
alert: this.getDefaultAlertProps(),
featureSelection: this.getDefaultFeatureSelectionProps(),
submittingFSExperiment: false
submittingFSExperiment: false,
openDetailsModal2: false
}
}

/**
* Abort controller if component is render
*/

componentWillUnmount () {
this.abortController.abort()
}

/**
* Generates default feature selection creation structure
* @returns Default the default Alert
Expand Down Expand Up @@ -428,16 +440,22 @@ export class BiomarkersPanel extends React.Component<{}, BiomarkersPanelState> {
getBiomarkerFullInstance = (biomarkerSimple: BiomarkerSimple): Promise<Biomarker> => {
return new Promise((resolve, reject) => {
this.setState({ loadingFullBiomarkerId: biomarkerSimple.id })
ky.get(urlBiomarkersCRUD + '/' + biomarkerSimple.id + '/').then((response) => {
response.json().then(resolve).catch((err) => {
ky.get(urlBiomarkersCRUD + '/' + biomarkerSimple.id + '/', { signal: this.abortController.signal }).then((response) => {
response.json().then((jsonResponse: Biomarker | PromiseLike<Biomarker>) => {
resolve(jsonResponse)
}).catch((err) => {
console.error('Error parsing JSON on Biomarker retrieval:', err)
reject(err)
})
}).catch((err) => {
console.error('Error getting Biomarker:', err)
reject(err)
if (!this.abortController.signal.aborted) {
reject(err)
}
}).finally(() => {
this.setState({ loadingFullBiomarkerId: null })
if (!this.abortController.signal.aborted) {
this.setState({ loadingFullBiomarkerId: null })
}
})
})
}
Expand Down Expand Up @@ -548,7 +566,7 @@ export class BiomarkersPanel extends React.Component<{}, BiomarkersPanelState> {

this.setState({ formBiomarker: formBiomarkerPreLoad })

ky.get(urlToFind, { searchParams: { query, limit: 5 }, timeout: REQUEST_TIMEOUT }).then((response) => {
ky.get(urlToFind, { searchParams: { query, limit: 5 }, signal: this.abortController.signal, timeout: REQUEST_TIMEOUT }).then((response) => {
response.json().then((jsonResponse: MoleculeFinderResult[]) => {
const formBiomarker = this.state.formBiomarker
const checkedIgnoreProposedAlias = this.state.checkedIgnoreProposedAlias // For short
Expand All @@ -571,9 +589,11 @@ export class BiomarkersPanel extends React.Component<{}, BiomarkersPanelState> {
}).catch((err) => {
console.error('Error getting genes ->', err)
}).finally(() => {
const formBiomarker = this.state.formBiomarker
formBiomarker.moleculesSymbolsFinder.isLoading = false
this.setState({ formBiomarker })
if (!this.abortController.signal.aborted) {
const formBiomarker = this.state.formBiomarker
formBiomarker.moleculesSymbolsFinder.isLoading = false
this.setState({ formBiomarker })
}
})
}

Expand Down Expand Up @@ -1283,7 +1303,7 @@ export class BiomarkersPanel extends React.Component<{}, BiomarkersPanelState> {
this.setState({ cloningBiomarker: true })

const url = `${urlCloneBiomarker}/${this.state.biomarkerToClone.id}/`
ky.get(url, { searchParams: { limit: 5 }, timeout: REQUEST_TIMEOUT }).then((response) => {
ky.get(url, { searchParams: { limit: 5 }, signal: this.abortController.signal, timeout: REQUEST_TIMEOUT }).then((response) => {
response.json().then((responseJSON: OkResponse) => {
if (responseJSON.ok) {
this.closeModalToClone()
Expand All @@ -1296,9 +1316,13 @@ export class BiomarkersPanel extends React.Component<{}, BiomarkersPanelState> {
})
}).catch((err) => {
console.error('Error cloning Biomarker ->', err)
alertGeneralError()
if (!this.abortController.signal.aborted) {
alertGeneralError()
}
}).finally(() => {
this.setState({ cloningBiomarker: false })
if (!this.abortController.signal.aborted) {
this.setState({ cloningBiomarker: false })
}
})
}

Expand Down Expand Up @@ -1410,7 +1434,7 @@ export class BiomarkersPanel extends React.Component<{}, BiomarkersPanelState> {
type: TagType.FILE
}

ky.get(urlTagsCRUD, { searchParams }).then((response) => {
ky.get(urlTagsCRUD, { searchParams, signal: this.abortController.signal }).then((response) => {
response.json().then((tags: DjangoTag[]) => {
this.setState({ tags })
}).catch((err) => {
Expand Down Expand Up @@ -1441,7 +1465,7 @@ export class BiomarkersPanel extends React.Component<{}, BiomarkersPanelState> {
<Base activeItem='biomarkers' wrapperClass='wrapper'>
{/* Biomarker deletion modal */}
{deletionConfirmModal}

<button onClick={() => this.setState({ openDetailsModal2: true })}>test</button>
<PaginatedTable<BiomarkerSimple>
headerTitle='Biomarkers'
headers={[
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'
import React, { useEffect, useRef, useState } from 'react'
import { List, Placeholder, Segment } from 'semantic-ui-react'
import { ClusteringAlgorithmLabel } from '../labels/ClusteringAlgorithmLabel'
import { ClusteringScoringMethodLabel } from '../labels/ClusteringScoringMethodLabel'
Expand Down Expand Up @@ -178,30 +178,39 @@ interface ModelDetailsModelDetailsPanelProps {
* @returns Component.
*/
export const ModelDetailsPanel = (props: ModelDetailsModelDetailsPanelProps) => {
const abortController = useRef(new AbortController())
const [modelDetails, setModelDetails] = useState<Nullable<ModelDetails>>(null)
const [loadingModelDetails, setLoadingModelDetails] = useState(false)

useEffect(() => {
getModelDetails()
return () => {
// Cleanup: cancel the ongoing request when component unmounts
abortController.current.abort()
}
}, [props.trainedModelPk])

/** Retrieve all the details of the selected StatisticalValidation's Trained model. */
const getModelDetails = () => {
setLoadingModelDetails(true)

const searchParams = { trained_model_pk: props.trainedModelPk }
ky.get(urlStatisticalValidationModalDetails, { searchParams }).then((response) => {
ky.get(urlStatisticalValidationModalDetails, { searchParams, signal: abortController.current.signal }).then((response) => {
response.json().then((modelDetails: ModelDetails) => {
setModelDetails(modelDetails)
}).catch((err) => {
alertGeneralError()
console.log('Error parsing JSON ->', err)
})
}).catch((err) => {
alertGeneralError()
if (!abortController.current.signal.aborted) {
alertGeneralError()
}
console.log('Error getting model details data', err)
}).finally(() => {
setLoadingModelDetails(false)
if (!abortController.current.signal.aborted) {
setLoadingModelDetails(false)
}
})
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react'
import React, { useEffect, useRef, useState } from 'react'
import { InferenceExperimentsTable } from './InferenceExperimentsTable'
import { Biomarker, InferenceExperimentForTable } from '../../types'
import { Header, Icon, Modal } from 'semantic-ui-react'
Expand All @@ -22,6 +22,8 @@ interface BiomarkerInferenceExperimentsPanelProps {
* @returns Component.
*/
export const BiomarkerInferenceExperimentsPanel = (props: BiomarkerInferenceExperimentsPanelProps) => {
const abortController = useRef(new AbortController())

const [openModalNewInferenceExperiment, setOpenModalNewInferenceExperiment] = useState(false)
const [openModalResultInferenceExperiment, setOpenModalResultInferenceExperiment] = useState(false)
const [selectedInferenceExperiment, setSelectedInferenceExperiment] = useState<Nullable<InferenceExperimentForTable>>(null)
Expand Down Expand Up @@ -51,19 +53,26 @@ export const BiomarkerInferenceExperimentsPanel = (props: BiomarkerInferenceExpe

const url = `${urlBiomarkerInferenceExperiments}/${selectedInferenceExperiment.id}/`
const searchParams = { biomarker_pk: props.selectedBiomarker.id as number }
ky.get(url, { searchParams }).then((response) => {
ky.get(url, { searchParams, signal: abortController.current.signal }).then((response) => {
response.json().then((experiment: InferenceExperimentForTable) => {
setSelectedInferenceExperiment(experiment)
}).catch((err) => {
alertGeneralError()
console.log('Error parsing JSON ->', err)
})
}).catch((err) => {
alertGeneralError()
if (!abortController.current.signal.aborted) {
alertGeneralError()
}
console.log('Error getting experiment', err)
})
}

useEffect(() => {
return () => {
// Cleanup: cancel the ongoing request when component unmounts
abortController.current.abort()
}
}, [])
// Shows modal to add a new inference experiment analysis
if (openModalNewInferenceExperiment) {
return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import ky from 'ky'
import React, { useEffect, useState } from 'react'
import React, { useEffect, useRef, useState } from 'react'
import { Form } from 'semantic-ui-react'
import { alertGeneralError, listToDropdownOptions } from '../../../../utils/util_functions'
import { InferenceExperimentForTable } from '../../types'
Expand All @@ -23,41 +23,48 @@ interface InferenceExperimentClinicalAttributeSelectProps {
* @returns Component.
*/
export const InferenceExperimentClinicalAttributeSelect = (props: InferenceExperimentClinicalAttributeSelectProps) => {
const abortController = useRef(new AbortController())
const [loadingClinicalAttributes, setLoadingClinicalAttributes] = useState(false)
const [clinicalAttributes, setClinicalAttributes] = useState<string[]>([])

/**
* Every time the StatisticalValidation changes retrieves
* its data from the backend
*/
useEffect(() => {
if (props.selectedInferenceExperiment.id) {
getInferenceExperimentClinicalAttrs()
}
}, [props.selectedInferenceExperiment.id])

/** Retrieve all the clinical attributes of the selected StatisticalValidation instance. */
const getInferenceExperimentClinicalAttrs = () => {
setLoadingClinicalAttributes(true)

const searchParams = { inference_experiment_pk: props.selectedInferenceExperiment.id }
ky.get(urlInferenceExperimentClinicalAttrs, { searchParams, timeout: 60000 }).then((response) => {
ky.get(urlInferenceExperimentClinicalAttrs, { searchParams, timeout: 60000, signal: abortController.current.signal }).then((response) => {
response.json().then((clinicalAttributes: string[]) => {
setClinicalAttributes(clinicalAttributes)
}).catch((err) => {
alertGeneralError()
console.log('Error parsing JSON ->', err)
})
}).catch((err) => {
alertGeneralError()
if (!abortController.current.signal.aborted) {
alertGeneralError()
}
console.log('Error getting InferenceExperiments clinical attributes', err)
}).finally(() => {
setLoadingClinicalAttributes(false)
if (!abortController.current.signal.aborted) {
setLoadingClinicalAttributes(false)
}
})
}

const clinicalAttributesOptions = listToDropdownOptions(clinicalAttributes)

/**
* Every time the StatisticalValidation changes retrieves
* its data from the backend
*/
useEffect(() => {
if (props.selectedInferenceExperiment.id) {
getInferenceExperimentClinicalAttrs()
}
return () => {
// Cleanup: cancel the ongoing request when component unmounts
abortController.current.abort()
}
}, [props.selectedInferenceExperiment.id])
return (
<>
<InputLabel label='Group by clinical attribute' />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'
import React, { useEffect, useRef, useState } from 'react'
import { BoxPlotSeries, XAxis, YAxis, PatternLines } from '@data-ui/xy-chart'
import { InferenceExperimentForTable } from '../../types'
import { NoClinicalData } from '../../../pipeline/experiment-result/gene-gem-details/survival-analysis/NoClinicalData'
Expand Down Expand Up @@ -38,6 +38,7 @@ interface SamplesAndTimeInferenceChartsProps {
* @returns Component.
*/
export const SamplesAndTimeInferenceCharts = (props: SamplesAndTimeInferenceChartsProps) => {
const abortController = useRef(new AbortController())
const [loadingChartData, setLoadingChartData] = useState(false)
const [chartData, setChartData] = useState<ChartData[]>([]) // TODO: type

Expand All @@ -46,6 +47,10 @@ export const SamplesAndTimeInferenceCharts = (props: SamplesAndTimeInferenceChar
if (props.selectedClinicalAttribute) {
getStatValidationKaplanMeierByAttr(props.selectedClinicalAttribute)
}
return () => {
// Cleanup: cancel the ongoing request when component unmounts
abortController.current.abort()
}
}, [props.selectedClinicalAttribute])

if (!props.inferenceExperiment.clinical_source_id) {
Expand Down Expand Up @@ -86,18 +91,22 @@ export const SamplesAndTimeInferenceCharts = (props: SamplesAndTimeInferenceChar
clinical_attribute: clinicalAttribute
}

ky.get(urlChartDataByAttribute, { searchParams, timeout: 60000 }).then((response) => {
ky.get(urlChartDataByAttribute, { searchParams, timeout: 60000, signal: abortController.current.signal }).then((response) => {
response.json().then((kaplanMeierResult/*: TODO: add type */) => {
setChartData(kaplanMeierResult)
}).catch((err) => {
alertGeneralError()
console.log('Error parsing JSON ->', err)
})
}).catch((err) => {
alertGeneralError()
if (!abortController.current.signal.aborted) {
alertGeneralError()
}
console.log('Error getting InferenceExperiment data grouped by a clinical attribute', err)
}).finally(() => {
setLoadingChartData(false)
if (!abortController.current.signal.aborted) {
setLoadingChartData(false)
}
})
}

Expand Down
Loading
Loading