-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: mtb gene centric search (#951)
* feat: initial refacotring of mtb geneAlteration/variant form * feat: adjust rendering query criteria summary * feat: cleanup query geneAlterations building
- Loading branch information
Showing
16 changed files
with
490 additions
and
687 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
268 changes: 203 additions & 65 deletions
268
packages/mtb/src/runtime/components/core/MMutationTabGroup.vue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,134 +1,272 @@ | ||
<script lang="ts"> | ||
import { VCFormSelect } from '@vuecs/form-controls'; | ||
import { | ||
type CodeSystemConcept, | ||
DCodeSystem, | ||
DCollectionTransform, | ||
DTags, toCoding, | ||
transformConceptToFormSelectOption, | ||
} from '@dnpm-dip/core'; | ||
import { VCFormSelect, VCFormSelectSearch } from '@vuecs/form-controls'; | ||
import type { FormSelectOption } from '@vuecs/form-controls'; | ||
import { | ||
type PropType, type Ref, computed, watch, | ||
type PropType, type Ref, computed, reactive, toRef, watch, | ||
} from 'vue'; | ||
import { | ||
defineComponent, markRaw, ref, toRef, | ||
defineComponent, markRaw, ref, | ||
} from 'vue'; | ||
import { FormMutationType, type MutationDefinition } from '../../domains'; | ||
import { | ||
type QueryGeneAlterationCriteria, | ||
type QueryGeneAlterationVariantCriteria, | ||
QueryMutationType, | ||
} from '../../domains'; | ||
import MSearchCNVForm from './search/MSearchCNVForm.vue'; | ||
import MSearchFusionForm from './search/MSearchFusionForm.vue'; | ||
import MSearchSNVForm from './search/MSearchSNVForm.vue'; | ||
export default defineComponent({ | ||
components: { VCFormSelect }, | ||
emit: ['updated'], | ||
components: { | ||
DCollectionTransform, DTags, VCFormSelectSearch, DCodeSystem, VCFormSelect, | ||
}, | ||
emit: ['updated', 'toggle'], | ||
props: { | ||
entity: { | ||
type: Object as PropType<MutationDefinition>, | ||
type: Object as PropType<QueryGeneAlterationCriteria>, | ||
}, | ||
}, | ||
setup(props, { emit }) { | ||
const entityRef = toRef(props, 'entity'); | ||
const entity = toRef(props, 'entity'); | ||
const form = reactive<Partial<QueryGeneAlterationCriteria<string>>>({ | ||
gene: '', | ||
supporting: false, | ||
negated: false, | ||
}); | ||
const mutationType = ref<null | `${QueryMutationType}`>(null); | ||
const mutationData = ref<null | QueryGeneAlterationVariantCriteria>(null); | ||
const options : FormSelectOption[] = [ | ||
{ id: FormMutationType.CNV, value: 'CNV' }, | ||
{ id: FormMutationType.SNV, value: 'SNV' }, | ||
{ id: FormMutationType.DNA_FUSION, value: 'DNA Fusion' }, | ||
{ id: FormMutationType.RNA_FUSION, value: 'RNA Fusion' }, | ||
const mutationOptions : FormSelectOption[] = [ | ||
{ id: QueryMutationType.CNV, value: 'CNV' }, | ||
{ id: QueryMutationType.SNV, value: 'SNV' }, | ||
{ id: QueryMutationType.FUSION, value: 'Fusion' }, | ||
]; | ||
const comp = ref(null) as Ref<null | Record<string, any>>; | ||
const changeComp = (type: FormMutationType) => { | ||
const changeMutationType = (type: `${QueryMutationType}` | null) => { | ||
switch (type) { | ||
case FormMutationType.CNV: { | ||
case QueryMutationType.CNV: { | ||
comp.value = markRaw(MSearchCNVForm); | ||
mutationData.value = { | ||
type: QueryMutationType.CNV, | ||
}; | ||
mutationType.value = QueryMutationType.CNV; | ||
break; | ||
} | ||
case FormMutationType.SNV: { | ||
case QueryMutationType.SNV: { | ||
comp.value = markRaw(MSearchSNVForm); | ||
mutationData.value = { | ||
type: QueryMutationType.SNV, | ||
}; | ||
mutationType.value = QueryMutationType.SNV; | ||
break; | ||
} | ||
case FormMutationType.RNA_FUSION: | ||
case FormMutationType.DNA_FUSION: { | ||
case QueryMutationType.FUSION: { | ||
comp.value = markRaw(MSearchFusionForm); | ||
mutationData.value = { | ||
type: QueryMutationType.FUSION, | ||
}; | ||
mutationType.value = QueryMutationType.FUSION; | ||
break; | ||
} | ||
default: { | ||
comp.value = null; | ||
mutationData.value = null; | ||
mutationType.value = null; | ||
break; | ||
} | ||
} | ||
}; | ||
const changeCompByEvent = (event: Event) => { | ||
if (!event.target) return; | ||
const changeMutationTypeByEvent = (event: Event) => { | ||
if (!event.target) { | ||
return; | ||
} | ||
changeComp((event.target as Record<string, any>).value); | ||
changeMutationType((event.target as Record<string, any>).value || null); | ||
}; | ||
const compData = ref(null); | ||
const compType = ref(null); | ||
const isEditing = computed(() => !!props.entity && Object.keys(props.entity).length > 0); | ||
const init = () => { | ||
if (props.entity) { | ||
changeComp(props.entity.type); | ||
compType.value = props.entity.type; | ||
compData.value = props.entity.data; | ||
if (!props.entity) { | ||
return; | ||
} | ||
compType.value = null; | ||
compData.value = null; | ||
if ( | ||
props.entity.variant && | ||
props.entity.variant.type | ||
) { | ||
changeMutationType(props.entity.variant.type); | ||
} else { | ||
changeMutationType(null); | ||
} | ||
if (props.entity.gene) { | ||
form.gene = props.entity.gene.code; | ||
} else { | ||
form.gene = ''; | ||
} | ||
if (typeof props.entity.supporting !== 'undefined') { | ||
form.supporting = props.entity.supporting; | ||
} else { | ||
form.supporting = false; | ||
} | ||
if (typeof props.entity.negated !== 'undefined') { | ||
form.negated = props.entity.negated; | ||
} else { | ||
form.negated = false; | ||
} | ||
}; | ||
init(); | ||
watch(entityRef, () => { | ||
watch(entity, () => { | ||
init(); | ||
}, { deep: true }); | ||
const isEditing = computed(() => !!props.entity && | ||
!!props.entity.type && | ||
!!props.entity.data); | ||
const handleUpdated = (data: Record<string, any>) => { | ||
compData.value = data; | ||
const submit = () => { | ||
if (form.gene) { | ||
emit('updated', { | ||
gene: form.gene ? toCoding(form.gene) : undefined, | ||
supporting: form.supporting, | ||
negated: form.negated, | ||
...(mutationData.value ? { variant: mutationData.value } : {}), | ||
} satisfies QueryGeneAlterationCriteria); | ||
} else { | ||
emit('toggle'); | ||
} | ||
}; | ||
emit('updated', { | ||
type: compType.value, | ||
data: compData.value, | ||
}); | ||
const handleVariantChanged = (data: QueryGeneAlterationVariantCriteria | null) => { | ||
mutationData.value = data; | ||
}; | ||
const transformConcepts = ( | ||
concept: CodeSystemConcept, | ||
) => transformConceptToFormSelectOption(concept); | ||
return { | ||
changeCompByEvent, | ||
form, | ||
changeMutationTypeByEvent, | ||
comp, | ||
compData, | ||
compType, | ||
options, | ||
mutationType, | ||
mutationOptions, | ||
handleUpdated, | ||
handleVariantChanged, | ||
isEditing, | ||
transformConcepts, | ||
submit, | ||
}; | ||
}, | ||
}); | ||
</script> | ||
<template> | ||
<VCFormGroup> | ||
<template #label> | ||
Mutationsart | ||
</template> | ||
<template #default> | ||
<VCFormSelect | ||
v-model="compType" | ||
:disabled="isEditing" | ||
:options="options" | ||
@change="changeCompByEvent" | ||
<div class="d-flex flex-column gap-2"> | ||
<VCFormGroup> | ||
<template #label> | ||
Gen | ||
</template> | ||
<template #default> | ||
<DCodeSystem | ||
:code="'https://www.genenames.org/'" | ||
:lazy-load="true" | ||
> | ||
<template #default="{ data }"> | ||
<DCollectionTransform | ||
:items="data.concepts" | ||
:transform="transformConcepts" | ||
> | ||
<template #default="options"> | ||
<VCFormSelectSearch | ||
v-model="form.gene" | ||
:options="options" | ||
placeholder="HGNC" | ||
> | ||
<template #selected="{ items, toggle }"> | ||
<DTags | ||
:emit-only="true" | ||
:items="items" | ||
tag-variant="dark" | ||
@deleted="toggle" | ||
/> | ||
</template> | ||
</VCFormSelectSearch> | ||
</template> | ||
</DCollectionTransform> | ||
</template> | ||
<template #loading> | ||
<VCFormSelectSearch | ||
:options="[]" | ||
:disabled="true" | ||
placeholder="HGNC" | ||
/> | ||
</template> | ||
</DCodeSystem> | ||
</template> | ||
</VCFormGroup> | ||
<VCFormGroup> | ||
<template #label> | ||
Mutationsart | ||
</template> | ||
<template #default> | ||
<VCFormSelect | ||
v-model="mutationType" | ||
:options="mutationOptions" | ||
@change="changeMutationTypeByEvent" | ||
/> | ||
</template> | ||
</VCFormGroup> | ||
<template v-if="comp && mutationType"> | ||
<component | ||
:is="comp" | ||
:entity="entity" | ||
@updated="handleVariantChanged" | ||
/> | ||
</template> | ||
</VCFormGroup> | ||
<template v-if="comp && compType"> | ||
<component | ||
:is="comp" | ||
:entity="compData" | ||
@updated="handleUpdated" | ||
/> | ||
</template> | ||
<div class="d-flex flex-row gap-2"> | ||
<div> | ||
<VCFormInputCheckbox | ||
v-model="form.supporting" | ||
:group-class="'form-switch'" | ||
:label="true" | ||
:label-content="'Stützend?'" | ||
/> | ||
</div> | ||
<div> | ||
<VCFormInputCheckbox | ||
v-model="form.negated" | ||
:group-class="'form-switch'" | ||
:label="true" | ||
:label-content="'Negiert?'" | ||
/> | ||
</div> | ||
</div> | ||
<div> | ||
<button | ||
type="button" | ||
class="btn btn-secondary btn-xs" | ||
@click.prevent="submit()" | ||
> | ||
{{ isEditing ? 'Aktualisieren' : 'Hinzufügen' }} | ||
</button> | ||
</div> | ||
</div> | ||
</template> |
Oops, something went wrong.