Skip to content

Commit

Permalink
feat: mtb gene centric search (#951)
Browse files Browse the repository at this point in the history
* feat: initial refacotring of mtb geneAlteration/variant form

* feat: adjust rendering query criteria summary

* feat: cleanup query geneAlterations building
  • Loading branch information
tada5hi authored Dec 4, 2024
1 parent e65cf58 commit 9047772
Show file tree
Hide file tree
Showing 16 changed files with 490 additions and 687 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,18 @@ export default defineComponent({
currentIndex.value = nextIndex < 0 ? 0 : nextIndex;
items.value.splice(index, 1);
if (items.value.length > 0) {
items.value.splice(index, 1);
}
} else {
currentIndex.value = index;
}
};
const toggleCurrent = () => {
toggle(currentIndex.value);
};
const handleUpdated = (data: Record<string, any>) => {
if (currentIndex.value === -1) {
items.value.push({ ...data });
Expand All @@ -110,6 +116,7 @@ export default defineComponent({
items,
add,
toggle,
toggleCurrent,
};
},
});
Expand All @@ -124,6 +131,7 @@ export default defineComponent({
<slot
:item="items[currentIndex]"
:updated="handleUpdated"
:toggle="toggleCurrent"
/>
</div>
<div
Expand Down
268 changes: 203 additions & 65 deletions packages/mtb/src/runtime/components/core/MMutationTabGroup.vue
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>
Loading

0 comments on commit 9047772

Please sign in to comment.