Skip to content

Commit

Permalink
feat: adding StrucvarGeneListCard
Browse files Browse the repository at this point in the history
  • Loading branch information
holtgrewe committed Jan 30, 2024
1 parent 64807ef commit ca8d224
Show file tree
Hide file tree
Showing 13 changed files with 228 additions and 97 deletions.
3 changes: 3 additions & 0 deletions .storybook/HomeStorybook.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script setup lang="ts"></script>

<template></template>
5 changes: 3 additions & 2 deletions .storybook/plugins/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { App } from 'vue'

import vuetify from './vuetify'
import { router } from './router'
import { vuetify } from './vuetify'

export async function registerPlugins(app: App) {
app.use(vuetify)
app.use(vuetify).use(router)
}
21 changes: 21 additions & 0 deletions .storybook/plugins/router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { createRouter, createWebHistory } from 'vue-router'

import HomeStorybook from '../HomeStorybook.vue'

const routes = [
{
path: '/',
name: 'home',
component: HomeStorybook
},
{
path: '/gene-details/:gene',
name: 'gene-details',
component: HomeStorybook
}
]

export const router = createRouter({
history: createWebHistory(),
routes
})
2 changes: 1 addition & 1 deletion .storybook/plugins/vuetify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const customLightTheme: ThemeDefinition = {
}

// https://vuetifyjs.com/en/introduction/why-vuetify/#feature-guides
export default createVuetify({
export const vuetify = createVuetify({
blueprint: md3,
components: {
...components
Expand Down
19 changes: 16 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"vite-plugin-css-injected-by-js": "^3.3.1",
"vite-plugin-static-copy": "^1.0.1",
"vue": "^3.4.15",
"vue-router": "^4.2.5",
"vuetify": "^3.5.1"
},
"devDependencies": {
Expand Down
14 changes: 7 additions & 7 deletions src/components/StrucvarGeneListCard/GeneDosage.vue
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
<script setup lang="ts">
import {
CLINGEN_DOSAGE_COLOR,
CLINGEN_DOSAGE_SCORES
} from '@/components/GeneDetails/PathogenicityCard.c'
import { ClingenDosageScore } from '../../pbs/annonars/genes/base'
import { CLINGEN_DOSAGE_COLOR, CLINGEN_DOSAGE_SCORES } from '../GenePathogenicityCard/constants'
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const props = defineProps<{
dosage?: string
dosage?: ClingenDosageScore
geneSymbol?: string
}>()
</script>

<template>
<template v-if="dosage === 'CLINGEN_DOSAGE_SCORE_RECESSIVE'">
<template v-if="dosage === ClingenDosageScore.CLINGEN_DOSAGE_SCORE_RECESSIVE">
<a
:href="`https://search.clinicalgenome.org/kb/gene-dosage/${geneSymbol ?? ''}`"
target="_blank"
Expand All @@ -23,7 +21,9 @@ const props = defineProps<{
<small class="pl-1"><v-icon>mdi-launch</v-icon></small>
</a>
</template>
<template v-else-if="!dosage || dosage === 'CLINGEN_DOSAGE_SCORE_UNKNOWN'">
<template
v-else-if="dosage === undefined || dosage === ClingenDosageScore.CLINGEN_DOSAGE_SCORE_UNKNOWN"
>
<v-chip density="compact" rounded="xl" :class="`bg-grey-lighten-5`"> N/A </v-chip>
<small class="pl-1">
<v-icon><!--spacer only--></v-icon>
Expand Down
19 changes: 7 additions & 12 deletions src/components/StrucvarGeneListCard/GeneListEntry.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
<script setup lang="ts">
import { computed } from 'vue'
import { useRouter } from 'vue-router'
import { type GenomeBuild } from '../../lib/genomeBuilds'
import GeneDosage from './GeneDosage.vue'
import ScoreChip from './ScoreChip.vue'
import { type GenomeBuild } from '../../lib/genomeBuilds'
/** This component's props. */
const props = defineProps<{
Expand All @@ -19,8 +18,6 @@ const props = defineProps<{
/** This component's emits. */
const emit = defineEmits(['toggleSelected'])
const router = useRouter()
/**
* Pick smallest of the shortest RefSeq transcript IDs.
*
Expand Down Expand Up @@ -79,18 +76,16 @@ const sortIcon = computed<string>(() => {
<div>
{{ pickRefSeqId(item.raw.dbnsfp?.refseqId) }}
|
<a
<router-link
style="cursor: pointer"
title="go to Gene details page"
@click.prevent="
router.push({
name: 'gene-details',
params: { gene: item.raw.hgnc.symbol }
})
"
:to="{
name: 'gene-details',
params: { gene: item.raw.hgnc.symbol }
}"
>
<v-icon>mdi-arrow-right-circle-outline</v-icon>
</a>
</router-link>
</div>
</div>
</v-col>
Expand Down
39 changes: 21 additions & 18 deletions src/components/StrucvarGeneListCard/ScoreChip.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,27 @@ import { computed } from 'vue'
import { roundIt } from '../../lib/utils'
/** This component's props. */
const props = withDefaults(defineProps<{
value: number | undefined
useRounded?: boolean
naValue?: string | number
hrefUrl?: string | undefined
rangeGray?: [number, number] | undefined
rangeGreen?: [number, number] | undefined
rangeOrange?: [number, number] | undefined
rangeRed?: [number, number] | undefined
}>(), {
naValue: 'N/A',
useRounded: true,
hrefUrl: undefined,
rangeGray: undefined,
rangeGreen: undefined,
rangeOrange: undefined,
rangeRed: undefined
})
const props = withDefaults(
defineProps<{
value: number | undefined
useRounded?: boolean
naValue?: string | number
hrefUrl?: string | undefined
rangeGray?: [number, number] | undefined
rangeGreen?: [number, number] | undefined
rangeOrange?: [number, number] | undefined
rangeRed?: [number, number] | undefined
}>(),
{
naValue: 'N/A',
useRounded: true,
hrefUrl: undefined,
rangeGray: undefined,
rangeGreen: undefined,
rangeOrange: undefined,
rangeRed: undefined
}
)
/**
* The computed chip color - based on the value and the ranges.
Expand Down
90 changes: 70 additions & 20 deletions src/components/StrucvarGeneListCard/StrucvarGeneListCard.spec.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,72 @@
import fs from 'fs'
import path from 'path'
import { describe, expect, it } from 'vitest'
import { nextTick } from 'vue'
import { h, nextTick } from 'vue'
import { RouterView } from 'vue-router'

import * as BRCA1GeneInfo from '@/assets/__tests__/BRCA1GeneInfo.json'
import * as CurrentSV from '@/assets/__tests__/ExampleSV.json'
import GeneListCard from '@/components/StrucvarDetails/GeneListCard.vue'
import { setupMountedComponents } from '@/lib/testUtils'
import { StoreState } from '@/stores/misc'
import { StrucvarResult } from '../../api/mehari/types'
import { type Strucvar } from '../../lib/genomicVars'
import { setupMountedComponents } from '../../lib/testUtils'
import { Record as GeneInfoRecord } from '../../pbs/annonars/genes/base'
import { StoreState } from '../../store'
import StrucvarGeneListCard from './StrucvarGeneListCard.vue'

describe.concurrent('GeneListCard', async () => {
it('renders the GeneListCard table', async () => {
/** Example Strucvar */
const strucvarInfo: Strucvar = {
genomeBuild: 'grch37',
svType: 'DEL',
chrom: '17',
start: 41176312,
stop: 41277500,
userRepr: 'DEL-grch37-17-41176312-41277500'
}

// Load fixture data.
const geneInfoBrca1 = GeneInfoRecord.fromJson(
JSON.parse(
fs.readFileSync(
path.resolve(__dirname, '../../components/GenePathogenicityCard/fixture.geneInfo.BRCA1.json'),
'utf8'
)
)
)
const strucvarResultBrca1 = StrucvarResult.fromJson(
JSON.parse(
fs.readFileSync(
path.resolve(__dirname, '../../api/mehari/fixture.strucvarCsqResponse.BRCA1.json'),
'utf8'
)
)
)

/** Routes to use in the tests. */
const routes = [
{
path: '/',
name: 'home',
component: h(RouterView)
},
{
path: '/gene-details/:gene',
name: 'gene-details',
component: h(RouterView)
}
]

describe.concurrent('StrucvarGeneListCard.vue', async () => {
it('renders the table', async () => {
// arrange:
const { wrapper } = await setupMountedComponents(
{ component: GeneListCard },
{ component: StrucvarGeneListCard },
{
props: {
genesInfos: JSON.parse(JSON.stringify([BRCA1GeneInfo['genes']['HGNC:1100']])),
currentSvRecord: JSON.parse(JSON.stringify(CurrentSV)),
selectedGeneHgncId: 'HGNC:1100',
storeState: StoreState.Active
}
currentStrucvarRecord: strucvarInfo,
csq: strucvarResultBrca1.result,
genesInfos: [geneInfoBrca1],
storeState: StoreState.Active,
selectGeneHgncId: undefined
},
routes
}
)

Expand All @@ -33,14 +81,16 @@ describe.concurrent('GeneListCard', async () => {
it('shows the gene info on row click', async () => {
// arrange:
const { wrapper } = await setupMountedComponents(
{ component: GeneListCard },
{ component: StrucvarGeneListCard },
{
props: {
genesInfos: JSON.parse(JSON.stringify([BRCA1GeneInfo['genes']['HGNC:1100']])),
currentSvRecord: JSON.parse(JSON.stringify(CurrentSV)),
selectedGeneHgncId: 'HGNC:1100',
storeState: StoreState.Active
}
currentStrucvarRecord: strucvarInfo,
csq: strucvarResultBrca1.result,
genesInfos: [geneInfoBrca1],
storeState: StoreState.Active,
selectGeneHgncId: undefined
},
routes
}
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { JsonValue } from '@protobuf-ts/runtime'
import type { Meta, StoryObj } from '@storybook/vue3'

import { StrucvarResult } from '../../api/mehari'
import strucvarResultBrca1Json from '../../api/mehari/fixture.strucvarCsqResponse.BRCA1.json'
import geneInfoBrca1Json from '../../components/GenePathogenicityCard/fixture.geneInfo.BRCA1.json'
import { Strucvar } from '../../lib/genomicVars'
import StrucvarToolsCard from './StrucvarToolsCard.vue'
import { Record as GeneInfoRecord } from '../../pbs/annonars/genes/base'
import { StoreState } from '../../store'
import StrucvarGeneListCard from './StrucvarGeneListCard.vue'

// We define the fixtures inline here as they are small.
const delBrca1: Strucvar = {
Expand All @@ -13,24 +19,37 @@ const delBrca1: Strucvar = {
userRepr: 'DEL:chr17:41176312:41277500'
}

// @ts-ignore
const geneInfoBrca1 = GeneInfoRecord.fromJson(geneInfoBrca1Json as JsonValue)
// @ts-ignore
const strucvarResultBrca1 = StrucvarResult.fromJson(strucvarResultBrca1Json as JsonValue)

const meta = {
title: 'Strucvar/StrucvarToolsCard',
component: StrucvarToolsCard,
title: 'Strucvar/StrucvarGeneListCard',
component: StrucvarGeneListCard,
tags: ['autodocs'],
argTypes: {
strucvar: { control: { type: 'object' } }
currentStrucvarRecord: { control: { type: 'object' } },
csq: { control: { type: 'object' } },
genesInfos: { control: { type: 'object' } },
storeState: { control: { type: 'object' } },
selectedGeneHgncId: { control: { type: 'object' } }
},
args: {
strucvar: delBrca1
currentStrucvarRecord: delBrca1,
csq: strucvarResultBrca1.result,
genesInfos: [geneInfoBrca1],
storeState: StoreState.Active,
selectedGeneHgncId: undefined
}
} satisfies Meta<typeof StrucvarToolsCard>
} satisfies Meta<typeof StrucvarGeneListCard>

export default meta

type Story = StoryObj<typeof meta>

export const DelBRCA1: Story = {
args: {
strucvar: delBrca1
currentStrucvarRecord: delBrca1
}
}
Loading

0 comments on commit ca8d224

Please sign in to comment.