Skip to content

Commit

Permalink
feat: adapt filter frontend to case detail variant annotations (#1104) (
Browse files Browse the repository at this point in the history
  • Loading branch information
stolpeo authored Sep 8, 2023
1 parent 1fbaf40 commit ed0652a
Show file tree
Hide file tree
Showing 34 changed files with 2,094 additions and 535 deletions.
11 changes: 7 additions & 4 deletions cases/tests/test_serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,12 @@ def testSerializeExisting(self):
class TestCaseSerializer(TestCase):
def setUp(self):
super().setUp()
self.maxDiff = None
self.case = CaseFactory()
self.smallvariantqueryresultset = SmallVariantQueryResultSetFactory(case=self.case)
self.svqueryresultset = SvQueryResultSetFactory(case=self.case)
self.smallvariantqueryresultset = SmallVariantQueryResultSetFactory(
case=self.case, smallvariantquery=None
)
self.svqueryresultset = SvQueryResultSetFactory(case=self.case, svquery=None)
self.maxDiff = None

def testSerializeExisting(self):
Expand Down Expand Up @@ -96,19 +99,19 @@ def testSerializeExisting(self):
"date_modified": self.smallvariantqueryresultset.date_modified.strftime(TIMEF),
"end_time": self.smallvariantqueryresultset.end_time.strftime(TIMEF),
"start_time": self.smallvariantqueryresultset.start_time.strftime(TIMEF),
"smallvariantquery": self.smallvariantqueryresultset.smallvariantquery.sodar_uuid,
"elapsed_seconds": self.smallvariantqueryresultset.elapsed_seconds,
"result_row_count": self.smallvariantqueryresultset.result_row_count,
"case": self.smallvariantqueryresultset.case.sodar_uuid,
}
expected["svqueryresultset"] = {
"sodar_uuid": str(self.svqueryresultset.sodar_uuid),
"date_created": self.svqueryresultset.date_created.strftime(TIMEF),
"date_modified": self.svqueryresultset.date_modified.strftime(TIMEF),
"end_time": self.svqueryresultset.end_time.strftime(TIMEF),
"start_time": self.svqueryresultset.start_time.strftime(TIMEF),
"svquery": self.svqueryresultset.svquery.sodar_uuid,
"elapsed_seconds": self.svqueryresultset.elapsed_seconds,
"result_row_count": self.svqueryresultset.result_row_count,
"case": self.svqueryresultset.case.sodar_uuid,
}
self.assertDictEqual(serializer.data, expected)

Expand Down
2 changes: 2 additions & 0 deletions cases/tests/test_views_ajax.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ def test_get(self):
"smallvariantquery": str(self.smallvariantqueryresultset.smallvariantquery.sodar_uuid),
"elapsed_seconds": self.smallvariantqueryresultset.elapsed_seconds,
"result_row_count": self.smallvariantqueryresultset.result_row_count,
"case": str(self.case.sodar_uuid),
}
expected0_svqueryresultset = {
"sodar_uuid": str(self.svqueryresultset.sodar_uuid),
Expand All @@ -68,6 +69,7 @@ def test_get(self):
"svquery": str(self.svqueryresultset.svquery.sodar_uuid),
"elapsed_seconds": self.svqueryresultset.elapsed_seconds,
"result_row_count": self.svqueryresultset.result_row_count,
"case": str(self.case.sodar_uuid),
}
expected0 = jsonmatch.compile(
{
Expand Down
64 changes: 34 additions & 30 deletions cases/vueapp/src/components/CaseDetail/Content.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,21 @@ import { computed, ref } from 'vue'
import PaneCase from '@cases/components/CaseDetail/PaneCase.vue'
import PaneQc from '@cases/components/CaseDetail/PaneQc.vue'
import PaneAnnotations from '@cases/components/CaseDetail/PaneAnnotations.vue'
import { useRouter } from 'vue-router'
import { useCaseDetailsStore } from '@cases/stores/caseDetails'
import GenomeBrowser from '@svs/components/GenomeBrowser.vue'
const router = useRouter()
const props = defineProps({
/** The case UUID. */
caseUuid: String,
currentTab: {
type: String,
default: 'overview', // keep in sync with Tabs.caseList
},
})
/** Define emits. */
const emit = defineEmits([
'addCaseCommentClick',
Expand All @@ -26,8 +38,6 @@ const Tabs = Object.freeze({
browser: 'browser',
})
const currentTab = ref('overview')
const caseDetailsStore = useCaseDetailsStore()
const annosLoading = computed(
Expand All @@ -45,28 +55,25 @@ const annoCount = computed(() => {
/** Update the current tab. */
const updateCurrentTab = (newValue) => {
currentTab.value = newValue
router.push({
name: 'case-detail-' + newValue,
params: { case: caseDetailsStore.caseObj.sodar_uuid },
})
}
defineExpose({
currentTab,
})
</script>

<template>
<div
:class="{
'flex-grow-1 d-flex flex-column': currentTab === Tabs.annotation,
'flex-grow-1 d-flex flex-column': props.currentTab === Tabs.annotation,
}"
>
<ul class="nav nav-tabs" id="case-tab" role="tablist">
<li class="nav-item">
<a
class="nav-link active"
id="overview-tab"
data-toggle="tab"
href="#overview"
role="tab"
class="nav-link"
:class="{ active: props.currentTab === Tabs.overview }"
role="button"
@click="updateCurrentTab(Tabs.overview)"
>
<i-mdi-account />
Expand All @@ -76,10 +83,8 @@ defineExpose({
<li class="nav-item">
<a
class="nav-link"
id="qc-tab"
data-toggle="tab"
href="#qc"
role="tab"
:class="{ active: props.currentTab === Tabs.qc }"
role="button"
@click="updateCurrentTab(Tabs.qc)"
>
<i-mdi-chart-multiple />
Expand All @@ -89,10 +94,8 @@ defineExpose({
<li class="nav-item">
<a
class="nav-link"
id="annotation-tab"
data-toggle="tab"
href="#annotation"
role="tab"
:class="{ active: props.currentTab === Tabs.annotation }"
role="button"
@click="updateCurrentTab(Tabs.annotation)"
>
<i-mdi-bookmark-multiple />
Expand All @@ -109,10 +112,8 @@ defineExpose({
<li class="nav-item">
<a
class="nav-link"
id="browser-tab"
data-toggle="tab"
href="#browser"
role="tab"
:class="{ active: props.currentTab === Tabs.browser }"
role="button"
@click="updateCurrentTab(Tabs.browser)"
>
<i-mdi-safety-goggles />
Expand All @@ -123,7 +124,7 @@ defineExpose({
</ul>
<div class="tab-content flex-grow-1 d-flex flex-column" id="cases-content">
<div
v-if="currentTab === Tabs.overview"
v-if="props.currentTab === Tabs.overview"
class="border border-top-0 tab-pane fade show active flex-grow-1 d-flex flex-column"
id="case-list"
role="tabpanel"
Expand All @@ -142,23 +143,26 @@ defineExpose({
/>
</div>
<div
v-if="currentTab === Tabs.qc"
v-if="props.currentTab === Tabs.qc"
class="border border-top-0 tab-pane fade show active flex-grow-1 d-flex flex-column"
id="case-list"
role="tabpanel"
>
<PaneQc />
</div>
<div
v-if="currentTab === Tabs.annotation"
v-if="props.currentTab === Tabs.annotation"
class="border border-top-0 tab-pane fade show active flex-grow-1 d-flex flex-column"
id="case-list"
role="tabpanel"
>
<PaneAnnotations />
<Suspense>
<PaneAnnotations :case-uuid="props.caseUuid" />
<template #fallback> Loading ... </template>
</Suspense>
</div>
<div
v-if="currentTab === Tabs.browser"
v-if="props.currentTab === Tabs.browser"
class="border border-top-0 tab-pane fade show active flex-grow-1 d-flex flex-column"
id="case-list"
role="tabpanel"
Expand Down
65 changes: 61 additions & 4 deletions cases/vueapp/src/components/CaseDetail/PaneAnnotations.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,68 @@
<script setup></script>
<script setup>
import { watch, ref, onMounted, nextTick, onBeforeMount } from 'vue'
import { useRouter } from 'vue-router'
import { useCaseDetailsStore } from '@cases/stores/caseDetails'
import { VariantClient } from '@variants/api/variantClient'
import {
DisplayColumns,
DisplayConstraints,
DisplayDetails,
DisplayFrequencies,
} from '@variants/enums'
import FilterResultsTable from '@variants/components/FilterResultsTable.vue'
import SvFilterResultsTable from '@svs/components/SvFilterResultsTable.vue'
const router = useRouter()
const props = defineProps({
/** The case UUID. */
caseUuid: String,
})
const caseDetailsStore = useCaseDetailsStore()
/** The details columns to show. */
const displayDetails = ref(DisplayDetails.Coordinates.value)
/** The frequency columns to show. */
const displayFrequency = ref(DisplayFrequencies.GnomadExomes.value)
/** The constraint columns to show. */
const displayConstraint = ref(DisplayConstraints.GnomadPli.value)
/** The additional columns to display. */
const displayColumns = ref([DisplayColumns.Effect.value])
const showSmallVariantDetails = async (event) => {
router.push({
name: 'variant-details',
params: {
row: event.smallvariantresultrow,
selectedSection: event.selectedSection ?? null,
},
})
}
const showStructuralVariantDetails = async (event) => {
router.push({
name: 'sv-details',
params: {
row: event.svresultrow,
selectedSection: event.selectedSection ?? null,
},
})
}
</script>
<template>
<div class="row pt-3 pb-3 flex-grow-1 d-flex flex-column">
<div class="col flex-grow-1 d-flex flex-column">
<h5>User Annotations</h5>

<p>TODO</p>
<h5>Small Variant User Annotations</h5>
<FilterResultsTable @variant-selected="showSmallVariantDetails" />
</div>
</div>
<div class="row pt-3 pb-3 flex-grow-1 d-flex flex-column">
<div class="col flex-grow-1 d-flex flex-column">
<h5>Structural Variant User Annotations</h5>
<SvFilterResultsTable @variant-selected="showStructuralVariantDetails" />
</div>
</div>
</template>
79 changes: 71 additions & 8 deletions cases/vueapp/src/components/CaseDetailApp.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ import { onMounted, nextTick, ref, watch } from 'vue'
import { QueryPresetsClient } from '@variants/api/queryPresetsClient'
import { useCaseListStore } from '@cases/stores/caseList'
import { useCaseDetailsStore } from '@cases/stores/caseDetails'
import { useVariantFlagsStore } from '@variants/stores/variantFlags'
import { useVariantCommentsStore } from '@variants/stores/variantComments'
import { useVariantAcmgRatingStore } from '@variants/stores/variantAcmgRating'
import { useVariantResultSetStore } from '@variants/stores/variantResultSet'
import { useSvResultSetStore } from '@svs/stores/svResultSet'
import { useSvFlagsStore } from '@svs/stores/svFlags'
import { useSvCommentsStore } from '@svs/stores/svComments'
import { overlayShow, overlayMessage } from '@cases/common'
import ModalSelect from '@varfish/components/ModalSelect.vue'
Expand All @@ -17,7 +24,12 @@ import Content from '@cases/components/CaseDetail/Content.vue'
import ModalPedigreeEditor from '@cases/components/ModalPedigreeEditor.vue'
import ModalTermsEditor from '@cases/components/ModalTermsEditor.vue'
const props = defineProps({ caseUuid: { type: String } })
const props = defineProps({
/** The case UUID. */
caseUuid: String,
/** The current tab. */
currentTab: String,
})
/** Obtain global application content (as for all entry level components) */
const appContext = JSON.parse(
Expand All @@ -27,18 +39,67 @@ const appContext = JSON.parse(
const caseListStore = useCaseListStore()
const caseDetailsStore = useCaseDetailsStore()
const refreshStores = () => {
const variantFlagsStore = useVariantFlagsStore()
const variantCommentsStore = useVariantCommentsStore()
const variantAcmgRatingStore = useVariantAcmgRatingStore()
const variantResultSetStore = useVariantResultSetStore()
const svResultSetStore = useSvResultSetStore()
const svFlagsStore = useSvFlagsStore()
const svCommentsStore = useSvCommentsStore()
const refreshStores = async () => {
if (
appContext?.csrf_token &&
appContext?.project?.sodar_uuid &&
props?.caseUuid
) {
caseDetailsStore.initialize(
appContext.csrf_token,
appContext.project.sodar_uuid,
props.caseUuid,
)
caseDetailsStore
.initialize(
appContext.csrf_token,
appContext.project.sodar_uuid,
props.caseUuid,
)
.then(async () => {
variantResultSetStore
.initialize(appContext.csrf_token)
.then(async () => {
await variantResultSetStore.loadResultSetViaCase(
caseDetailsStore.caseObj.sodar_uuid,
)
})
svResultSetStore.initialize(appContext.csrf_token).then(async () => {
await svResultSetStore.loadResultSetViaCase(
caseDetailsStore.caseObj.sodar_uuid,
)
})
await Promise.all([
variantFlagsStore.initialize(
appContext.csrf_token,
appContext.project.sodar_uuid,
caseDetailsStore.caseObj.sodar_uuid,
),
variantCommentsStore.initialize(
appContext.csrf_token,
appContext.project.sodar_uuid,
caseDetailsStore.caseObj.sodar_uuid,
),
variantAcmgRatingStore.initialize(
appContext.csrf_token,
appContext.project.sodar_uuid,
caseDetailsStore.caseObj.sodar_uuid,
),
svFlagsStore.initialize(
appContext.csrf_token,
appContext.project?.sodar_uuid,
caseDetailsStore.caseObj.sodar_uuid,
),
svCommentsStore.initialize(
appContext.csrf_token,
appContext.project?.sodar_uuid,
caseDetailsStore.caseObj.sodar_uuid,
),
])
})
}
}
Expand Down Expand Up @@ -410,6 +471,8 @@ onMounted(() => {
class="varfish-overlay-wrap position-relative flex-grow-1 d-flex flex-column"
>
<Content
:case-uuid="props.caseUuid"
:current-tab="props.currentTab"
@edit-case-status-click="handleEditCaseStatusClicked"
@edit-case-notes-click="handleEditCaseNotesClicked"
@edit-query-presets-click="handleEditQueryPresetsClicked"
Expand Down
Loading

0 comments on commit ed0652a

Please sign in to comment.