From 2f3ea9d8c04990c53b692b961ffb2292ce1bbd98 Mon Sep 17 00:00:00 2001 From: Manuel Holtgrewe Date: Wed, 7 Feb 2024 08:36:58 +0100 Subject: [PATCH] fix: resolving issues with caseInfo storage and API (#454) (#456) --- .../versions/4f3b20f156c1_init_caseinfo.py | 2 +- backend/app/models/caseinfo.py | 4 +- backend/app/schemas/caseinfo.py | 2 +- backend/tests/api/api_v1/test_caseinfo.py | 4 +- backend/tests/crud/test_caseinfo.py | 8 +-- docs/dev_quickstart.rst | 17 +++++ frontend/src/api/caseInfo/api.spec.ts | 6 +- frontend/src/api/caseInfo/types.ts | 67 +++++++++++++------ .../CaseInformationCard.vue | 21 ++++-- .../src/components/PageHeader/PageHeader.vue | 21 +++--- .../ProfileCaseCard/ProfileCaseCard.vue | 4 +- .../SeqvarClinsigCard/SeqvarClinsigCard.vue | 1 - .../StrucvarClinsigCard.vue | 1 - frontend/src/stores/caseInfo/constants.ts | 10 +-- frontend/src/stores/caseInfo/store.spec.ts | 22 +++--- frontend/src/stores/caseInfo/store.ts | 21 +++++- frontend/src/stores/caseInfo/types.ts | 10 ++- 17 files changed, 151 insertions(+), 70 deletions(-) diff --git a/backend/alembic/versions/4f3b20f156c1_init_caseinfo.py b/backend/alembic/versions/4f3b20f156c1_init_caseinfo.py index beff7c45..ae048b17 100644 --- a/backend/alembic/versions/4f3b20f156c1_init_caseinfo.py +++ b/backend/alembic/versions/4f3b20f156c1_init_caseinfo.py @@ -44,7 +44,7 @@ def upgrade(): sa.Column("sex", sa.Enum("Male", "Female", "Unknown", name="sex"), nullable=True), sa.Column("age_of_onset_month", sa.Integer(), nullable=True), sa.Column( - "ethinicity", + "ethnicity", sa.Enum( "AfricanAmerican", "AshkenaziJewish", diff --git a/backend/app/models/caseinfo.py b/backend/app/models/caseinfo.py index 18fef30f..3e9b66c9 100644 --- a/backend/app/models/caseinfo.py +++ b/backend/app/models/caseinfo.py @@ -40,7 +40,7 @@ class CaseInfo(Base): affected_family_members: bool sex: Sex age_of_onset_month: int - ethinicity: Ethnicity + ethnicity: Ethnicity zygosity: Zygosity family_segregation: bool else: @@ -65,7 +65,7 @@ class CaseInfo(Base): #: Age of onset of the patient. age_of_onset_month = Column(Integer, nullable=True) #: Ethnicity of the patient. - ethinicity = Column(Enum(Ethnicity), nullable=True) + ethnicity = Column(Enum(Ethnicity), nullable=True) #: Zygosity of the patient. zygosity = Column(Enum(Zygosity), nullable=True) #: Family segregation of the patient. diff --git a/backend/app/schemas/caseinfo.py b/backend/app/schemas/caseinfo.py index b1647b55..91617df5 100644 --- a/backend/app/schemas/caseinfo.py +++ b/backend/app/schemas/caseinfo.py @@ -65,7 +65,7 @@ class CaseInfoBase(BaseModel): affected_family_members: bool | None = None sex: Sex = Sex.Unknown age_of_onset_month: int | None = None - ethinicity: Ethnicity = Ethnicity.Unknown + ethnicity: Ethnicity = Ethnicity.Unknown zygosity: Zygosity = Zygosity.Unknown family_segregation: bool | None = None diff --git a/backend/tests/api/api_v1/test_caseinfo.py b/backend/tests/api/api_v1/test_caseinfo.py index ae6b8dd5..ac436925 100644 --- a/backend/tests/api/api_v1/test_caseinfo.py +++ b/backend/tests/api/api_v1/test_caseinfo.py @@ -38,7 +38,7 @@ async def test_create_caseinfo( "affected_family_members": True, "sex": "reev:unknown_sex", "age_of_onset_month": 20, - "ethinicity": "reev:unknown_ethnicity", + "ethnicity": "reev:unknown_ethnicity", "zygosity": "reev:unknown_zygosity", "family_segregation": True, }, @@ -53,7 +53,7 @@ async def test_create_caseinfo( assert response.json()["affected_family_members"] == True assert response.json()["sex"] == "reev:unknown_sex" assert response.json()["age_of_onset_month"] == 20 - assert response.json()["ethinicity"] == "reev:unknown_ethnicity" + assert response.json()["ethnicity"] == "reev:unknown_ethnicity" assert response.json()["zygosity"] == "reev:unknown_zygosity" assert response.json()["family_segregation"] == True diff --git a/backend/tests/crud/test_caseinfo.py b/backend/tests/crud/test_caseinfo.py index ea779fb4..84705eca 100644 --- a/backend/tests/crud/test_caseinfo.py +++ b/backend/tests/crud/test_caseinfo.py @@ -25,7 +25,7 @@ def case_create() -> CaseInfoCreate: affected_family_members=True, sex=Sex.Unknown, age_of_onset_month=20, - ethinicity=Ethnicity.Unknown, + ethnicity=Ethnicity.Unknown, zygosity=Zygosity.Unknown, family_segregation=True, user=uuid.uuid4(), @@ -48,7 +48,7 @@ async def test_create_get_caseinfo(db_session: AsyncSession, case_create: CaseIn assert caseinfo_postcreate.affected_family_members == stored_item.affected_family_members assert caseinfo_postcreate.sex == stored_item.sex assert caseinfo_postcreate.age_of_onset_month == stored_item.age_of_onset_month - assert caseinfo_postcreate.ethinicity == stored_item.ethinicity + assert caseinfo_postcreate.ethnicity == stored_item.ethnicity assert caseinfo_postcreate.zygosity == stored_item.zygosity assert caseinfo_postcreate.family_segregation == stored_item.family_segregation @@ -81,7 +81,7 @@ async def test_get_multi_by_user(db_session: AsyncSession, case_create: CaseInfo assert caseinfo_postcreate.affected_family_members == stored_items[0].affected_family_members assert caseinfo_postcreate.sex == stored_items[0].sex assert caseinfo_postcreate.age_of_onset_month == stored_items[0].age_of_onset_month - assert caseinfo_postcreate.ethinicity == stored_items[0].ethinicity + assert caseinfo_postcreate.ethnicity == stored_items[0].ethnicity assert caseinfo_postcreate.zygosity == stored_items[0].zygosity assert caseinfo_postcreate.family_segregation == stored_items[0].family_segregation @@ -105,6 +105,6 @@ async def test_get_by_user(db_session: AsyncSession, case_create: CaseInfoCreate assert caseinfo_postcreate.affected_family_members == stored_item.affected_family_members assert caseinfo_postcreate.sex == stored_item.sex assert caseinfo_postcreate.age_of_onset_month == stored_item.age_of_onset_month - assert caseinfo_postcreate.ethinicity == stored_item.ethinicity + assert caseinfo_postcreate.ethnicity == stored_item.ethnicity assert caseinfo_postcreate.zygosity == stored_item.zygosity assert caseinfo_postcreate.family_segregation == stored_item.family_segregation diff --git a/docs/dev_quickstart.rst b/docs/dev_quickstart.rst index c0936a36..094bb9cf 100644 --- a/docs/dev_quickstart.rst +++ b/docs/dev_quickstart.rst @@ -128,6 +128,23 @@ You have to restart jupyterlab manually. Now you can navigate to the frontend development server at http://localhost:8081. This server will transparently forward the API requests to the backend server at http://localhost:8081. +--------------- +Troubleshooting +--------------- + +Issues with nested git submodules. + We have put the shared code into ``frontend/src/ext/reev-frontend-lib``. + Make sure that you get a fresh clone of the repository with the ``--recursive`` flag. + To initialize the submodules, use ``git submodule update --init --recursive``. + You can reset the submodule to the version stored in the main ``reev`` repository with ``git submodule foreach --recursive git reset --hard``. + +Issues with ``reev-frontend-lib`` as a submodule. + Having the library as a submodule is useful for development. + There are some drawbacks. + If you see **weird issues with typescript that you don't understand**, try to ``rm -rf frontend/src/ext/reev-frontend-lib/{node_modules,dist}``. + Such issues include problems with assigning the reactive classes from ``vue``, such as ``ref`` and ``computed``, or other weird stuff with types. + In this case, try to clear out the directories described above and restart VS Code. + ----- Notes ----- diff --git a/frontend/src/api/caseInfo/api.spec.ts b/frontend/src/api/caseInfo/api.spec.ts index d3367448..13498e44 100644 --- a/frontend/src/api/caseInfo/api.spec.ts +++ b/frontend/src/api/caseInfo/api.spec.ts @@ -12,12 +12,12 @@ const mockCaseInfo: CaseInfo = { diseases: [], hpoTerms: [], inheritance: Inheritance.Unknown, - affectedFamilyMembers: null, + affectedFamilyMembers: undefined, sex: Sex.Unknown, - ageOfOnsetMonths: null, + ageOfOnsetMonths: undefined, ethnicity: Ethnicity.Unknown, zygosity: Zygosity.Unknown, - familySegregation: null + familySegregation: undefined } describe.concurrent('CaseInfo Client', () => { diff --git a/frontend/src/api/caseInfo/types.ts b/frontend/src/api/caseInfo/types.ts index 039f8bb8..24ec7ea3 100644 --- a/frontend/src/api/caseInfo/types.ts +++ b/frontend/src/api/caseInfo/types.ts @@ -51,42 +51,46 @@ export enum Zygosity { /** Case Info as returned by API */ export interface CaseInfo$Api { + id?: string + user?: string affected_family_members: boolean | null age_of_onset_month: number | null diseases: any[] // Replace with the actual type from your API - ethinicity: string + ethnicity: string family_segregation: boolean | null hpo_terms: any[] // Replace with the actual type from your API - id: string inheritance: string | null pseudonym: string sex: string | null - user: string zygosity: string } /** Interface for the case data, for storage and API. */ export interface CaseInfo { - /* The case pseudonym. */ + /** The case info ID. */ + id?: string + /** The user ID. */ + user?: string + /** The case pseudonym. */ pseudonym: string - /* Orphanet / OMIM disease(s). */ + /** Orphanet / OMIM disease(s). */ diseases: OmimTerm[] - /* HPO terms. */ + /** HPO terms. */ hpoTerms: HpoTerm[] - /* Inheritance. */ + /** Inheritance. */ inheritance: Inheritance - /* Affected family members. */ - affectedFamilyMembers: boolean | null - /* Sex. */ + /** Affected family members. */ + affectedFamilyMembers?: boolean + /** Sex. */ sex: Sex - /* Age of onset in month. */ - ageOfOnsetMonths: number | null - /* Ethnicity. */ + /** Age of onset in month. */ + ageOfOnsetMonths?: number + /** Ethnicity. */ ethnicity: Ethnicity - /* Zygosity. */ + /** Zygosity. */ zygosity: Zygosity - /* Family segregation. */ - familySegregation: boolean | null + /** Family segregation. */ + familySegregation?: boolean } /** @@ -95,16 +99,35 @@ export interface CaseInfo { export class CaseInfo$Type { fromJson(apiResponse: CaseInfo$Api): CaseInfo { return { + id: apiResponse.id, + user: apiResponse.user, pseudonym: apiResponse.pseudonym, diseases: apiResponse.diseases, - hpoTerms: apiResponse.hpo_terms, + hpoTerms: apiResponse.hpo_terms ?? [], inheritance: apiResponse.inheritance as Inheritance, - affectedFamilyMembers: apiResponse.affected_family_members, - sex: apiResponse.sex as Sex, - ageOfOnsetMonths: apiResponse.age_of_onset_month, - ethnicity: apiResponse.ethinicity as Ethnicity, + affectedFamilyMembers: apiResponse.affected_family_members ?? undefined, + sex: (apiResponse.sex as Sex) ?? undefined, + ageOfOnsetMonths: apiResponse.age_of_onset_month ?? undefined, + ethnicity: apiResponse.ethnicity as Ethnicity, zygosity: apiResponse.zygosity as Zygosity, - familySegregation: apiResponse.family_segregation + familySegregation: apiResponse.family_segregation ?? undefined + } + } + + toJson(caseInfo: CaseInfo): CaseInfo$Api { + return { + id: caseInfo.id, + user: caseInfo.user, + pseudonym: caseInfo.pseudonym, + diseases: caseInfo.diseases, + hpo_terms: caseInfo.hpoTerms, + inheritance: caseInfo.inheritance, + affected_family_members: caseInfo.affectedFamilyMembers ?? null, + sex: caseInfo.sex, + age_of_onset_month: caseInfo.ageOfOnsetMonths ?? null, + ethnicity: caseInfo.ethnicity, + zygosity: caseInfo.zygosity, + family_segregation: caseInfo.familySegregation ?? null } } } diff --git a/frontend/src/components/CaseInformationCard/CaseInformationCard.vue b/frontend/src/components/CaseInformationCard/CaseInformationCard.vue index 9a95b251..786f2f35 100644 --- a/frontend/src/components/CaseInformationCard/CaseInformationCard.vue +++ b/frontend/src/components/CaseInformationCard/CaseInformationCard.vue @@ -13,11 +13,16 @@ import { StorageMode, Zygosity, ZygosityLabels, - ethinicityLabels, + ethnicityLabels, useCaseInfoStore } from '@/stores/caseInfo' import { useTermsStore } from '@/stores/terms' +/** This component's emits. */ +const emit = defineEmits<{ + (eventName: 'clickClose'): void +}>() + const caseStore = useCaseInfoStore() const termsStore = useTermsStore() const cadaPrioStore = useCadaPrioStore() @@ -41,7 +46,7 @@ const inheritanceOptions = computed(() => { const ethnicityOptions = computed(() => { return Object.values(Ethnicity).map((value) => { return { - text: ethinicityLabels.get(value), + text: ethnicityLabels.get(value), value: value } }) @@ -278,8 +283,16 @@ watch( /> - Save Changes - + Save Changes + + Close Window + + Delete Case info diff --git a/frontend/src/components/PageHeader/PageHeader.vue b/frontend/src/components/PageHeader/PageHeader.vue index f2bab3be..5dc2fbb3 100644 --- a/frontend/src/components/PageHeader/PageHeader.vue +++ b/frontend/src/components/PageHeader/PageHeader.vue @@ -44,6 +44,9 @@ const searchTermRef = ref('') /** Component state; genome build. */ const genomeBuildRef = ref('grch37') +/** Whether to show the case info box. */ +const showCaseInfo = ref(false) + /** Helper function to between light and dark theme. */ function toggleTheme() { theme.global.name.value = theme.global.current.value.dark ? 'customLightTheme' : 'dark' @@ -80,16 +83,12 @@ function toggleTheme() { mdi-theme-light-dark - - - - - - + + Case Info + + diff --git a/frontend/src/components/ProfileCaseCard/ProfileCaseCard.vue b/frontend/src/components/ProfileCaseCard/ProfileCaseCard.vue index af5e16a9..c74b55fe 100644 --- a/frontend/src/components/ProfileCaseCard/ProfileCaseCard.vue +++ b/frontend/src/components/ProfileCaseCard/ProfileCaseCard.vue @@ -13,7 +13,7 @@ import { SexLabels, Zygosity, ZygosityLabels, - ethinicityLabels, + ethnicityLabels, useCaseInfoStore } from '@/stores/caseInfo' import { useTermsStore } from '@/stores/terms' @@ -41,7 +41,7 @@ const inheritanceOptions = computed(() => { const ethnicityOptions = computed(() => { return Object.values(Ethnicity).map((value) => { return { - text: ethinicityLabels.get(value), + text: ethnicityLabels.get(value), value: value } }) diff --git a/frontend/src/components/SeqvarClinsigCard/SeqvarClinsigCard.vue b/frontend/src/components/SeqvarClinsigCard/SeqvarClinsigCard.vue index 9b7f8b04..0871e920 100644 --- a/frontend/src/components/SeqvarClinsigCard/SeqvarClinsigCard.vue +++ b/frontend/src/components/SeqvarClinsigCard/SeqvarClinsigCard.vue @@ -8,7 +8,6 @@ component via the `errorDisplay` event and are handled there.