diff --git a/packages/demo/public/catalogues/catalogue-dktk.json b/packages/demo/public/catalogues/catalogue-dktk.json index f35f8b62..524e928d 100644 --- a/packages/demo/public/catalogues/catalogue-dktk.json +++ b/packages/demo/public/catalogues/catalogue-dktk.json @@ -2,6 +2,7 @@ { "key": "patient", "name": "Patient", + "description": "Hier könnte ihre Werbung stehen!", "childCategories": [ { "key": "gender", @@ -9,6 +10,7 @@ "system": "", "fieldType": "single-select", "type": "EQUALS", + "description": "Hier ebenfalls!", "criteria": [ { "key": "male", @@ -7181,7 +7183,7 @@ "name": "Klassifikation von Tumoren", "childCategories": [ { - "key": "year_of_diagnosis", + "key": "year_of_primary_diagnosis", "name": "Diagnosejahr", "system": "", "fieldType": "number", @@ -7189,7 +7191,7 @@ "criteria": [] }, { - "key": "age_at_diagnosis", + "key": "age_at_primary_diagnosis", "name": "Alter bei Erstdiagnose", "system": "", "fieldType": "number", @@ -11357,7 +11359,7 @@ }, { "key": "urn:oid:2.16.840.1.113883.6.43.1", - "name": "Lokalisation (ICD-O-3 Klassifizierung)", + "name": "Lokalisation ICD-O-3", "system": "http://fhir.de/CodeSystem/bfarm/icd-10-gm", "fieldType": "autocomplete", "type": "EQUALS", @@ -17889,150 +17891,12 @@ { "key": "21908-9", "name": "UICC Stadium", - "system": "http://dktk.dkfz.de/fhir/onco/core/CodeSystem/UiccstadiumCS", - "fieldType": "single-select", - "type": "EQUALS", - "criteria": [ - { - "key": "0is", - "name": "0is", - "description": "0is" - }, - { - "key": "0a", - "name": "0a", - "description": "0a" - }, - { - "key": "0", - "name": "0", - "description": "0" - }, - { - "key": "IA2", - "name": "IA2", - "description": "IA2" - }, - { - "key": "IA1", - "name": "IA1", - "description": "IA1" - }, - { - "key": "IA", - "name": "IA", - "description": "IA" - }, - { - "key": "IB2", - "name": "IB2", - "description": "IB2" - }, - { - "key": "IB1", - "name": "IB1", - "description": "IB1" - }, - { - "key": "IB", - "name": "IB", - "description": "IB" - }, - { - "key": "IIC", - "name": "IIC", - "description": "IIC" - }, - { - "key": "IIB", - "name": "IIB", - "description": "IIB" - }, - { - "key": "IIA2", - "name": "IIA2", - "description": "IIA2" - }, - { - "key": "IIA1", - "name": "IIA1", - "description": "IIA1" - }, - { - "key": "IIA", - "name": "IIA", - "description": "IIA" - }, - { - "key": "II", - "name": "II", - "description": "II" - }, - { - "key": "IIIC2", - "name": "IIIC2", - "description": "IIIC2" - }, - { - "key": "IIIC1", - "name": "IIIC1", - "description": "IIIC1" - }, - { - "key": "IIIC", - "name": "IIIC", - "description": "IIIC" - }, - { - "key": "IIIB", - "name": "IIIB", - "description": "IIIB" - }, - { - "key": "IIIA", - "name": "IIIA", - "description": "IIIA" - }, - { - "key": "III", - "name": "III", - "description": "III" - }, - { - "key": "IVC", - "name": "IVC", - "description": "IVC" - }, - { - "key": "IVB", - "name": "IVB", - "description": "IVB" - }, - { - "key": "IVA", - "name": "IVA", - "description": "IVA" - }, - { - "key": "IV", - "name": "IV", - "description": "IV" - }, - { - "key": "IS", - "name": "IS", - "description": "IS" - } - ] - }, - { - "key": "tnm", - "name": "TNM(c)", "childCategories": [ { - "key": "21905-5", - "name": "TNM-T", - "system": "", + "key": "21908-9", + "subCategoryName": "0", + "name": "UICC Stadium", + "system": "http://dktk.dkfz.de/fhir/onco/core/CodeSystem/UiccstadiumCS", "fieldType": "single-select", "type": "EQUALS", "criteria": [ @@ -18042,199 +17906,466 @@ "description": "0" }, { - "key": "1", - "name": "1", - "description": "1" - }, - { - "key": "1a", - "name": "1a", - "description": "1a" - }, - { - "key": "1a1", - "name": "1a1", - "description": "1a1" - }, - { - "key": "1a2", - "name": "1a2", - "description": "1a2" + "key": "0is", + "name": "0is", + "description": "0is" }, { - "key": "1b", - "name": "1b", - "description": "1b" - }, - { - "key": "1b1", - "name": "1b1", - "description": "1b1" - }, - { - "key": "1b2", - "name": "1b2", - "description": "1b2" - }, + "key": "0a", + "name": "0a", + "description": "0a" + } + ] + }, + { + "key": "21908-9", + "subCategoryName": "I", + "name": "UICC Stadium", + "system": "http://dktk.dkfz.de/fhir/onco/core/CodeSystem/UiccstadiumCS", + "fieldType": "single-select", + "type": "EQUALS", + "criteria": [ { - "key": "1c", - "name": "1c", - "description": "1c" + "key": "I", + "name": "I", + "description": "I" }, { - "key": "1c1", - "name": "1c1", - "description": "1c1" + "key": "IA", + "name": "IA", + "description": "IA" }, { - "key": "1c2", - "name": "1c2", - "description": "1c2" + "key": "IA1", + "name": "IA1", + "description": "IA1" }, { - "key": "1c3", - "name": "1c3", - "description": "1c3" + "key": "IA2", + "name": "IA2", + "description": "IA2" }, { - "key": "1d", - "name": "1d", - "description": "1d" + "key": "IB", + "name": "IB", + "description": "IB" }, { - "key": "1mi", - "name": "1mi", - "description": "1mi" + "key": "IB1", + "name": "IB1", + "description": "IB1" }, { - "key": "2", - "name": "2", - "description": "2" + "key": "IB2", + "name": "IB2", + "description": "IB2" }, { - "key": "2a", - "name": "2a", - "description": "2a" - }, + "key": "IS", + "name": "IS", + "description": "IS" + } + ] + }, + { + "key": "21908-9", + "subCategoryName": "II", + "name": "UICC Stadium", + "system": "http://dktk.dkfz.de/fhir/onco/core/CodeSystem/UiccstadiumCS", + "fieldType": "single-select", + "type": "EQUALS", + "criteria": [ { - "key": "2a1", - "name": "2a1", - "description": "2a1" + "key": "II", + "name": "II", + "description": "II" }, { - "key": "2a2", - "name": "2a2", - "description": "2a2" + "key": "IIA", + "name": "IIA", + "description": "IIA" }, { - "key": "2b", - "name": "2b", - "description": "2b" + "key": "IIA1", + "name": "IIA1", + "description": "IIA1" }, { - "key": "2c", - "name": "2c", - "description": "2c" + "key": "IIA2", + "name": "IIA2", + "description": "IIA2" }, { - "key": "2d", - "name": "2d", - "description": "2d" + "key": "IIB", + "name": "IIB", + "description": "IIB" }, { - "key": "3", - "name": "3", - "description": "3" - }, + "key": "IIC", + "name": "IIC", + "description": "IIC" + } + ] + }, + { + "key": "21908-9", + "subCategoryName": "III", + "name": "UICC Stadium", + "system": "http://dktk.dkfz.de/fhir/onco/core/CodeSystem/UiccstadiumCS", + "fieldType": "single-select", + "type": "EQUALS", + "criteria": [ { - "key": "3a", - "name": "3a", - "description": "3a" + "key": "III", + "name": "III", + "description": "III" }, { - "key": "3b", - "name": "3b", - "description": "3b" + "key": "IIIA", + "name": "IIIA", + "description": "IIIA" }, { - "key": "3c", - "name": "3c", - "description": "3c" + "key": "IIIB", + "name": "IIIB", + "description": "IIIB" }, { - "key": "3d", - "name": "3d", - "description": "3d" + "key": "IIIC", + "name": "IIIC", + "description": "IIIC" }, { - "key": "4", - "name": "4", - "description": "4" + "key": "IIIC1", + "name": "IIIC1", + "description": "IIIC1" }, { - "key": "4a", - "name": "4a", - "description": "4a" - }, + "key": "IIIC2", + "name": "IIIC2", + "description": "IIIC2" + } + ] + }, + { + "key": "21908-9", + "subCategoryName": "IV", + "name": "UICC Stadium", + "system": "http://dktk.dkfz.de/fhir/onco/core/CodeSystem/UiccstadiumCS", + "fieldType": "single-select", + "type": "EQUALS", + "criteria": [ { - "key": "4b", - "name": "4b", - "description": "4b" + "key": "IV", + "name": "IV", + "description": "IV" }, { - "key": "4c", - "name": "4c", - "description": "4c" + "key": "IVA", + "name": "IVA", + "description": "IVA" }, { - "key": "4d", - "name": "4d", - "description": "4d" + "key": "IVB", + "name": "IVB", + "description": "IVB" }, { - "key": "4e", - "name": "4e", - "description": "4e" - }, + "key": "IVC", + "name": "IVC", + "description": "IVC" + } + ] + } + ] + }, + { + "key": "tnm", + "name": "TNM(c)", + "childCategories": [ + { + "key": "21905-5", + "name": "TNM-T", + "childCategories": [ { - "key": "a", - "name": "a", - "description": "a" + "key": "21905-5", + "name": "TNM-T", + "subCategoryName": "0", + "system": "", + "fieldType": "single-select", + "type": "EQUALS", + "criteria": [ + { + "key": "0", + "name": "0", + "description": "0" + } + ] }, { - "key": "is", - "name": "is", - "description": "is" + "key": "21905-5", + "name": "TNM-T", + "subCategoryName": "1", + "system": "", + "fieldType": "single-select", + "type": "EQUALS", + "criteria": [ + { + "key": "1", + "name": "1", + "description": "1" + }, + { + "key": "1a", + "name": "1a", + "description": "1a" + }, + { + "key": "1a1", + "name": "1a1", + "description": "1a1" + }, + { + "key": "1a2", + "name": "1a2", + "description": "1a2" + }, + { + "key": "1b", + "name": "1b", + "description": "1b" + }, + { + "key": "1b1", + "name": "1b1", + "description": "1b1" + }, + { + "key": "1b2", + "name": "1b2", + "description": "1b2" + }, + { + "key": "1c", + "name": "1c", + "description": "1c" + }, + { + "key": "1c1", + "name": "1c1", + "description": "1c1" + }, + { + "key": "1c2", + "name": "1c2", + "description": "1c2" + }, + { + "key": "1c3", + "name": "1c3", + "description": "1c3" + }, + { + "key": "1d", + "name": "1d", + "description": "1d" + }, + { + "key": "1mi", + "name": "1mi", + "description": "1mi" + } + ] }, { - "key": "is(DCIS)", - "name": "is(DCIS)", - "description": "is(DCIS)" + "key": "21905-5", + "name": "TNM-T", + "subCategoryName": "2", + "system": "", + "fieldType": "single-select", + "type": "EQUALS", + "criteria": [ + { + "key": "2", + "name": "2", + "description": "2" + }, + { + "key": "2a", + "name": "2a", + "description": "2a" + }, + { + "key": "2a1", + "name": "2a1", + "description": "2a1" + }, + { + "key": "2a2", + "name": "2a2", + "description": "2a2" + }, + { + "key": "2b", + "name": "2b", + "description": "2b" + }, + { + "key": "2c", + "name": "2c", + "description": "2c" + }, + { + "key": "2d", + "name": "2d", + "description": "2d" + } + ] }, { - "key": "is(LCIS)", - "name": "is(LCIS)", - "description": "is(LCIS)" + "key": "21905-5", + "name": "TNM-T", + "subCategoryName": "3", + "system": "", + "fieldType": "single-select", + "type": "EQUALS", + "criteria": [ + { + "key": "3", + "name": "3", + "description": "3" + }, + { + "key": "3a", + "name": "3a", + "description": "3a" + }, + { + "key": "3b", + "name": "3b", + "description": "3b" + }, + { + "key": "3c", + "name": "3c", + "description": "3c" + }, + { + "key": "3d", + "name": "3d", + "description": "3d" + } + ] }, { - "key": "is(Paget)", - "name": "is(Paget)", - "description": "is(Paget)" + "key": "21905-5", + "name": "TNM-T", + "subCategoryName": "4", + "system": "", + "fieldType": "single-select", + "type": "EQUALS", + "criteria": [ + { + "key": "4", + "name": "4", + "description": "4" + }, + { + "key": "4a", + "name": "4a", + "description": "4a" + }, + { + "key": "4b", + "name": "4b", + "description": "4b" + }, + { + "key": "4c", + "name": "4c", + "description": "4c" + }, + { + "key": "4d", + "name": "4d", + "description": "4d" + }, + { + "key": "4e", + "name": "4e", + "description": "4e" + } + ] }, { - "key": "is(pd)", - "name": "is(pd)", - "description": "is(pd)" + "key": "21905-5", + "name": "TNM-T", + "subCategoryName": "a", + "system": "", + "fieldType": "single-select", + "type": "EQUALS", + "criteria": [ + { + "key": "a", + "name": "a", + "description": "a" + } + ] }, { - "key": "is(pu)", - "name": "is(pu)", - "description": "is(pu)" + "key": "21905-5", + "name": "TNM-T", + "subCategoryName": "is", + "system": "", + "fieldType": "single-select", + "type": "EQUALS", + "criteria": [ + { + "key": "is", + "name": "is", + "description": "is" + }, + { + "key": "is(DCIS)", + "name": "is(DCIS)", + "description": "is(DCIS)" + }, + { + "key": "is(LCIS)", + "name": "is(LCIS)", + "description": "is(LCIS)" + }, + { + "key": "is(Paget)", + "name": "is(Paget)", + "description": "is(Paget)" + }, + { + "key": "is(pd", + "name": "is(pd)", + "description": "is(pd)" + }, + { + "key": "is(pu)", + "name": "is(pu)", + "description": "is(pu)" + } + ] }, { - "key": "X", - "name": "X", - "description": "X" + "key": "21905-5", + "name": "TNM-T", + "subCategoryName": "X", + "system": "", + "fieldType": "single-select", + "type": "EQUALS", + "criteria": [ + { + "key": "X", + "name": "X", + "description": "X" + } + ] } ] }, @@ -18471,11 +18602,6 @@ "key": "y", "name": "Klassifikation erfolgte während oder nach initialer multimodaler Therapie", "description": "Klassifikation erfolgte während oder nach initialer multimodaler Therapie" - }, - { - "key": "9", - "name": "native Klassifikation", - "description": "native Klassifikation" } ] }, @@ -18490,11 +18616,6 @@ "key": "r", "name": "Klassifikation erfolgte zur Beurteilung eines Rezidivs", "description": "Klassifikation erfolgte zur Beurteilung eines Rezidivs" - }, - { - "key": "9", - "name": "native Klassifikation vor Eintreten eines Rezidivs", - "description": "native Klassifikation vor Eintreten eines Rezidivs" } ] } @@ -18955,4 +19076,4 @@ } ] } -] +] \ No newline at end of file diff --git a/packages/demo/src/AppCCP.svelte b/packages/demo/src/AppCCP.svelte index e2421e42..f7caa232 100644 --- a/packages/demo/src/AppCCP.svelte +++ b/packages/demo/src/AppCCP.svelte @@ -122,9 +122,59 @@ catalogueKeyToResponseKeyMap: catalogueKeyToResponseKeyMap, }; - - - + const genderHeaders: Map = new Map() + .set('male', 'männlich') + .set('female', 'weiblich') + .set('other', 'divers, intersexuell') + .set('unknown', 'unbekannt'); + + const vitalStateHeaders: Map = new Map() + .set('lebend', 'alive') + .set('verstorben', 'deceased') + .set('unbekannt', 'unknown'); + + const therapyHeaders: Map = new Map() + .set('medicationStatements', 'Sys. T'); + + const therapyTooltips: Map = new Map() + .set('OP', 'Operationen') + .set('ST', 'Strahlentherapien') + .set('medicationStatements', 'Systemische Therapien'); + + const systemicTherapyTooltips: Map = new Map() + .set('CH', 'Chemotherapie') + .set('HO', 'Hormontherapie') + .set('IM', 'Immun- und Antikörpertherapie') + .set('KM', 'Knochenmarkstransplantation') + .set('WS', 'Wait and see') + .set('AS', 'Active Surveillance') + .set('ZS', 'Zielgerichtete Substanzen') + .set('SO', 'Sonstiges') + .set('ST', 'Strahlentherapie') + .set('OP', 'Operation') + + const specimenHeaders: Map = new Map() + .set('whole-blood','Whole blood') + .set('bone-marrow','Bone marrow') + .set('buffy-coat','Buffy-Coat') + .set('dried-whole-blood','Dried whole blood') + .set('peripheral-blood-cells-vital','Peripheral blood mononuclear cells (PBMCs, viable)') + .set('blood-plasma','Plasma') + .set('blood-serum','Serum') + .set('ascites','Ascites') + .set('csf-liquor','CSF/Liquor') + .set('saliva','Saliva') + .set('stool-faeces','Stool/Faeces') + .set('urine','Urine') + .set('swab','Swab') + .set('liquid-other','Other liquid biosample/storage') + .set('tissue-ffpe','Tissue FFPE') + .set('tissue-frozen','Tissue frozen') + .set('tissue-other','Other tissue storage') + .set('dna','DNA') + .set('rna','RNA') + .set('derivative-other','Other derivative') +
@@ -144,7 +194,7 @@ measures={[dktkPatientsMeasure, dktkDiagnosisMeasure, dktkSpecimenMeasure, dktkPatientsMeasure, dktkMedicationStatementsMeasure]} > - +
@@ -200,7 +252,8 @@ groupingDivider='.' groupingLabel='.%' filterRegex='^[CD].*' - + xAxisTitle="Anzahl der Diagnosen" + yAxisTitle="ICD-10-Codes" />
@@ -210,6 +263,8 @@ chartType="bar" clickToAddState={true} groupRange={10} + xAxisTitle="Alter" + yAxisTitle="Anzahl der Primärdiagnosen" />
@@ -219,6 +274,7 @@ chartType="pie" displayLegends={true} clickToAddState={true} + headers={vitalStateHeaders} />
@@ -227,6 +283,9 @@ catalogueGroupCode="therapy_of_tumor" chartType="bar" clickToAddState={true} + headers={therapyHeaders} + tooltips={therapyTooltips} + yAxisTitle="Anzahl der Therapien" />
@@ -235,6 +294,8 @@ catalogueGroupCode="medicationStatements" chartType="bar" clickToAddState={true} + tooltips={systemicTherapyTooltips} + yAxisTitle="Anzahl der Therapien" />
@@ -243,6 +304,9 @@ catalogueGroupCode="sample_kind" chartType="bar" clickToAddState={true} + xAxisTitle="Probentypen" + yAxisTitle="Probenanzahl" + tooltips={specimenHeaders} />
diff --git a/packages/demo/src/ccp.css b/packages/demo/src/ccp.css index 68180a81..ed0e0fca 100644 --- a/packages/demo/src/ccp.css +++ b/packages/demo/src/ccp.css @@ -10,7 +10,7 @@ @font-face { font-family: 'Open Sans'; font-style: normal; - src: url('../public/fonts/Open_Sans/OpenSans-VariableFont_wdth\,wght.ttf') format('truetype'); + src: url('../fonts/Open_Sans/OpenSans-VariableFont_wdth\,wght.ttf') format('truetype'); } :root { diff --git a/packages/demo/src/measures.ts b/packages/demo/src/measures.ts index 28360b04..4791be30 100644 --- a/packages/demo/src/measures.ts +++ b/packages/demo/src/measures.ts @@ -58,8 +58,16 @@ export const patientsMeasure = { define Gender: if (Patient.gender is null) then 'unknown' else Patient.gender +define PrimaryDiagnosis: +First( + from [Condition] C + where C.extension.where(url='http://hl7.org/fhir/StructureDefinition/condition-related').empty() + sort by date from onset asc +) + define AgeClass: if (Patient.birthDate is null) then 'unknown' else ToString((AgeInYears() div 10) * 10) +if (PrimaryDiagnosis.onset is null) then 'unknown' else ToString((AgeInYearsAt(FHIRHelpers.ToDateTime(PrimaryDiagnosis.onset)) div 10) * 10) define PatientDeceased: First (from [Observation: Code '75186-7' from loinc] O return O.value.coding.where(system = 'http://dktk.dkfz.de/fhir/onco/core/CodeSystem/VitalstatusCS').code.first()) diff --git a/packages/demo/src/styles/default/catalogue.css b/packages/demo/src/styles/default/catalogue.css index be435bcc..30bbeb50 100644 --- a/packages/demo/src/styles/default/catalogue.css +++ b/packages/demo/src/styles/default/catalogue.css @@ -13,6 +13,7 @@ lens-catalogue::part(lens-catalogue-toggle-button) { cursor: pointer; display: flex; gap: var(--gap-xs); + width: 100%; } lens-catalogue::part(lens-catalogue-toggle-button):hover { @@ -23,7 +24,6 @@ lens-catalogue::part(toggle-button-open-icon) { transform: rotate(180deg); } - lens-catalogue::part(data-tree-element-name) { font-size: var(--font-size-m); color: var(--dark-gray); @@ -36,6 +36,7 @@ lens-catalogue::part(data-tree-element-name) { lens-catalogue::part(data-tree-element-name) { padding-left: var(--gap-s); + padding-right: 0; font-size: var(--font-size-m); color: var(--dark-gray); margin-bottom: 10px; @@ -60,8 +61,43 @@ lens-catalogue::part(data-tree-element-toggle-icon-open) { transform: rotate(0deg); } + +lens-catalogue::part(info-button) { + position: relative; + cursor: pointer; + background-color: var(--white); + border: none; + padding: 0; +} + +lens-catalogue::part(info-button-icon) { + position: absolute; + bottom: var(--gap-xxs); + width: 16px; + height: 16px; +} + +lens-catalogue::part(info-button-dialogue) { + position: absolute; + border: none; + background-color: var(--white); + width: max-content; + max-width: 80vw; + z-index: 100; + padding: var(--gap-xs); + top: 0; + left: var(--gap-xxs); + border: solid 1px var(--light-blue); + border-radius: var(--border-radius-small); +} + + +lens-catalogue::part(data-tree-element-info-icon):hover lens-catalogue::part(data-tree-element-info-text) { + display: block; +} + lens-catalogue::part(data-tree-element-child-category) { - padding: var(--gap-xs) var(--gap-s) 0; + padding: var(--gap-xs) 0 0 var(--gap-s); border-left: solid 1px var(--lightest-gray); } @@ -285,4 +321,4 @@ lens-catalogue::part(criterion-autocomplete-tooltip) { lens-catalogue::part(formfield-error) { color: var(--red); border-color: var(--red); -} \ No newline at end of file +} diff --git a/packages/lib/index.ts b/packages/lib/index.ts index 3592adc3..f2816b81 100644 --- a/packages/lib/index.ts +++ b/packages/lib/index.ts @@ -8,4 +8,4 @@ export { default as ResutSummaryComponent } from './src/components/results/Resul export { default as ResultTableComponent } from './src/components/results/ResultTableComponent.wc.svelte' export { default as SearchBarMultipleComponent } from './src/components/search-bar/SearchBarMultipleComponent.wc.svelte' export { default as NegotiateButtonComponent } from './src/components/buttons/NegotiateButtonComponent.wc.svelte' -export { default as QueryInfoButton } from './src/components/buttons/QueryInfoButtonComponent.wc.svelte' \ No newline at end of file +export { default as InfoButton } from './src/components/buttons/InfoButtonComponent.wc.svelte' \ No newline at end of file diff --git a/packages/lib/src/components/buttons/QueryInfoButtonComponent.wc.svelte b/packages/lib/src/components/buttons/InfoButtonComponent.wc.svelte similarity index 55% rename from packages/lib/src/components/buttons/QueryInfoButtonComponent.wc.svelte rename to packages/lib/src/components/buttons/InfoButtonComponent.wc.svelte index 7cc19014..cb47b388 100644 --- a/packages/lib/src/components/buttons/QueryInfoButtonComponent.wc.svelte +++ b/packages/lib/src/components/buttons/InfoButtonComponent.wc.svelte @@ -1,42 +1,58 @@ diff --git a/packages/lib/src/components/catalogue/Catalogue.wc.svelte b/packages/lib/src/components/catalogue/Catalogue.wc.svelte index d9fb6f0e..3c8a633d 100644 --- a/packages/lib/src/components/catalogue/Catalogue.wc.svelte +++ b/packages/lib/src/components/catalogue/Catalogue.wc.svelte @@ -23,6 +23,7 @@ export let texts: CatalogueText = {}; export let addIconUrl: string | null = null; export let toggleIconUrl: string | null = null; + export let infoIconUrl: string | null = null; iconStore.update((store: Map) => { if (addIconUrl) { @@ -31,6 +32,9 @@ if (toggleIconUrl) { store.set('toggleIconUrl', toggleIconUrl); } + if (infoIconUrl) { + store.set('infoIconUrl', infoIconUrl); + } return store; }) diff --git a/packages/lib/src/components/catalogue/DataTreeElement.svelte b/packages/lib/src/components/catalogue/DataTreeElement.svelte index 5b90b991..32ce26cf 100644 --- a/packages/lib/src/components/catalogue/DataTreeElement.svelte +++ b/packages/lib/src/components/catalogue/DataTreeElement.svelte @@ -8,40 +8,77 @@ import { activeNumberInputs, openTreeNodes } from "../../stores/catalogue"; import type { QueryItem } from "../../types/queryData"; import { iconStore } from "../../stores/icons"; + import InfoButtonComponent from "../buttons/InfoButtonComponent.wc.svelte"; export let element: Category; - + const subCategoryName: string | null = ("subCategoryName" in element && element.subCategoryName !== undefined && element.subCategoryName !== null) ? element.subCategoryName : null; /** * defines the layer of the element in the tree */ export let layer: number = 1; - + /** * defines if the subcategorys are open, iterates over the whole tree */ export let treeOpen: boolean = false; - + if (treeOpen) { - openTreeNodes.update((store: string[]): string[] => { - store = [...store, element.key]; - return store; - }); + /** + * DISCUSS: open all subcategorys on creation needed? + */ } - + /** * toggles the open state of the subcategorys */ - $: open = $openTreeNodes.includes(element.key); - + let open: boolean = false; + + $: { + if(subCategoryName){ + open = $openTreeNodes.get(element.key).subCategoryNames?.includes(subCategoryName) + } else { + open = $openTreeNodes.get(element.key) ? true : false; + } + } + + + const toggleChildren = () => { - openTreeNodes.update((store: string[]): string[] => { - if (store.includes(element.key)) { - return store.filter( - (item: string): Boolean => item !== element.key - ); - } else { - return [...store, element.key]; + openTreeNodes.update((store) => { + + let storeTreeNode = store.get(element.key); + + if(!storeTreeNode){ + store.set(element.key, {key: element.key, subCategoryNames: null }) + return store; } + + if(subCategoryName === null) { + store.delete(element.key); + return store; + } + + if(storeTreeNode.subCategoryNames === null){ + storeTreeNode.subCategoryNames = [subCategoryName]; + store.set(element.key, storeTreeNode); + return store; + } + + if(storeTreeNode.subCategoryNames.includes(subCategoryName)){ + storeTreeNode.subCategoryNames = storeTreeNode.subCategoryNames.filter((name) => name !== subCategoryName); + store.set(element.key, storeTreeNode); + return store; + } + + if(!storeTreeNode.subCategoryNames.includes(subCategoryName)){ + storeTreeNode.subCategoryNames.push(subCategoryName); + store.set(element.key, storeTreeNode); + return store; + } + + console.log(store); + + return store; }); }; @@ -128,8 +165,12 @@ ⌄ {/if} - {element.name} + {'subCategoryName' in element && element.subCategoryName ? element.subCategoryName : element.name} + {#if element.description} + + {/if} + {#if open} {#if "childCategories" in element} {#each element.childCategories as child} @@ -146,7 +187,7 @@ {:else}
{#if "fieldType" in element && element.fieldType === "single-select"} - + {:else if "fieldType" in element && element.fieldType === "autocomplete"} {:else if "fieldType" in element && element.fieldType === "number"} diff --git a/packages/lib/src/components/catalogue/SingleSelectComponent.svelte b/packages/lib/src/components/catalogue/SingleSelectComponent.svelte index 9a9e2026..f33f7c45 100644 --- a/packages/lib/src/components/catalogue/SingleSelectComponent.svelte +++ b/packages/lib/src/components/catalogue/SingleSelectComponent.svelte @@ -1,14 +1,65 @@
{#if "criteria" in element} + {#if subgrouping && element.criteria.length > 1} +
+ + alle hinzufügen + +
+ + {/if} {#each element.criteria as criterion} - + {/each} {/if}
diff --git a/packages/lib/src/components/results/ChartComponent.wc.svelte b/packages/lib/src/components/results/ChartComponent.wc.svelte index da399eb2..1bc6ee69 100644 --- a/packages/lib/src/components/results/ChartComponent.wc.svelte +++ b/packages/lib/src/components/results/ChartComponent.wc.svelte @@ -31,12 +31,16 @@ export let title: string = ""; // e.g. 'Gender Distribution' export let catalogueGroupCode: string = ""; // e.g. "gender" export let indexAxis: string = "x"; + export let xAxisTitle: string = ""; + export let yAxisTitle: string = ""; export let clickToAddState: boolean = false; let responseGroupCode: string; $: responseGroupCode = $catalogueKeyToResponseKeyMap.get(catalogueGroupCode); export let hintText: string = ""; + export let tooltips: Map = new Map(); + export let headers: Map = new Map(); export let displayLegends: boolean = false; export let chartType: keyof ChartTypeRegistry = "pie"; export let perSite: boolean = false; @@ -97,7 +101,44 @@ display: displayLegends, position: "bottom", }, + tooltip: { + callbacks: { + title: (context: any) => { + const key = context[0].label || ''; + let result = (tooltips.get(key)) + ? tooltips.get(key) : key; + return result + } + } + } }, + scales: { + y: { + display: true, + title: { + display: true, + text: yAxisTitle + } + }, + x: { + display: true, + title: { + display: true, + text: xAxisTitle + }, + ticks: (chartType === "bar") ? { + callback: (val: any) => { + if (typeof val === 'string') return val.toString() + const key: unknown = (initialChartData.data.labels[val]) + ? initialChartData.data.labels[val] : val.toString(); + if (typeof key !== 'string') return val.toString() + let result = (headers.get(key)) + ? headers.get(key) : key; + return result + } + } : [] + } + } }, }; diff --git a/packages/lib/src/cql-translator-service/ast-to-cql-translator.ts b/packages/lib/src/cql-translator-service/ast-to-cql-translator.ts index ba2b0a45..9dcc246c 100644 --- a/packages/lib/src/cql-translator-service/ast-to-cql-translator.ts +++ b/packages/lib/src/cql-translator-service/ast-to-cql-translator.ts @@ -161,12 +161,23 @@ const getSingleton = (criterion: AstBottomLayerValue): string => { break } - case "conditionRangeDate": + case "conditionRangeDate": { + expression += substituteRangeCQLExpression(criterion, myCriterion, "condition", "Date", myCQL); + break + } + + case "primaryConditionRangeDate": { + expression += substituteRangeCQLExpression(criterion, myCriterion, "primaryCondition", "Date", myCQL); + break + } + case "conditionRangeAge": { - if (typeof criterion.value == "object" - && !(criterion.value instanceof Array)) { - expression += substituteCQLExpression(criterion.key, myCriterion.alias, myCQL, "", criterion.value.min as number, criterion.value.max as number) - } + expression += substituteRangeCQLExpression(criterion, myCriterion, "condition", "Age", myCQL); + break + } + + case "primaryConditionRangeAge": { + expression += substituteRangeCQLExpression(criterion, myCriterion, "primaryCondition", "Age", myCQL); break } } @@ -175,11 +186,34 @@ const getSingleton = (criterion: AstBottomLayerValue): string => { return expression } - - - - - +const substituteRangeCQLExpression = ( + criterion: AstBottomLayerValue, + myCriterion: {type: string; alias?: string[]}, + criterionPrefix: string, + criterionSuffix: string, + rangeCQL: string +): string => { + const input = criterion.value as { min: number, max: number } + if (input === null) { + console.warn(`Throwing away a ${criterionPrefix}Range${criterionSuffix} criterion, as it is not of type {min: number, max: number}!`) + return + } + if (input.min === 0 && input.max === 0) { + console.warn(`Throwing away a ${criterionPrefix}Range${criterionSuffix} criterion, as both dates are undefined!`) + return + } else if (input.min === 0) { + const lowerThanDateTemplate = cqltemplate.get(`${criterionPrefix}LowerThan${criterionSuffix}`) + if (lowerThanDateTemplate) + return substituteCQLExpression(criterion.key, myCriterion.alias, lowerThanDateTemplate, "", input.min, input.max) + } else if (input.max === 0) { + const greaterThanDateTemplate = cqltemplate.get(`${criterionPrefix}GreaterThan${criterionSuffix}`) + if (greaterThanDateTemplate) + return substituteCQLExpression(criterion.key, myCriterion.alias, greaterThanDateTemplate, "", input.min, input.max) + } else { + return substituteCQLExpression(criterion.key, myCriterion.alias, rangeCQL, "", input.min, input.max) + } + return +} const substituteCQLExpression = (key: string, alias: string[] | undefined, cql: string, value?: string, min?: number, max?: number): string => { let cqlString: string diff --git a/packages/lib/src/cql-translator-service/cqlquery-mappings.ts b/packages/lib/src/cql-translator-service/cqlquery-mappings.ts index f57cdefa..6b624225 100644 --- a/packages/lib/src/cql-translator-service/cqlquery-mappings.ts +++ b/packages/lib/src/cql-translator-service/cqlquery-mappings.ts @@ -35,7 +35,17 @@ export const alias = new Map([ // ["conditionLocalization", "exists from [Condition] C\nwhere C.bodySite.coding contains Code '{{C}}' from {{A1}}"], ["conditionLocalization", "exists from [Condition] C\nwhere C.bodySite.coding.code contains '{{C}}'"], ["conditionRangeDate", "exists from [Condition] C\nwhere year from C.onset between {{D1}} and {{D2}}"], + ["conditionLowerThanDate", "exists from [Condition] C\nwhere year from C.onset <= {{D2}}"], + ["conditionGreaterThanDate", "exists from [Condition] C\nwhere year from C.onset >= {{D1}}"], ["conditionRangeAge", "exists [Condition] C\nwhere AgeInYearsAt(FHIRHelpers.ToDateTime(C.onset)) between {{D1}} and {{D2}}"], + ["conditionLowerThanAge", "exists [Condition] C\nwhere AgeInYearsAt(FHIRHelpers.ToDateTime(C.onset)) <= {{D2}}"], + ["conditionGreaterThanAge", "exists [Condition] C\nwhere AgeInYearsAt(FHIRHelpers.ToDateTime(C.onset)) >= {{D1}}"], + ["primaryConditionRangeDate", "year from PrimaryDiagnosis.onset between {{D1}} and {{D2}}"], + ["primaryConditionLowerThanDate", "year from PrimaryDiagnosis.onset <= {{D2}}"], + ["primaryConditionGreaterThanDate", "year from PrimaryDiagnosis.onset >= {{D1}}"], + ["primaryConditionRangeAge", "AgeInYearsAt(FHIRHelpers.ToDateTime(PrimaryDiagnosis.onset)) between {{D1}} and {{D2}}"], + ["primaryConditionLowerThanAge", "AgeInYearsAt(FHIRHelpers.ToDateTime(PrimaryDiagnosis.onset)) <= {{D2}}"], + ["primaryConditionGreaterThanAge", "AgeInYearsAt(FHIRHelpers.ToDateTime(PrimaryDiagnosis.onset)) >= {{D1}}"], //TODO Revert to first expression if https://github.com/samply/blaze/issues/808 is solved // ["observation", "exists from [Observation: Code '{{K}}' from {{A1}}] O\nwhere O.value.coding contains Code '{{C}}' from {{A2}}"], ["observation", "exists from [Observation: Code '{{K}}' from {{A1}}] O\nwhere O.value.coding.code contains '{{C}}'"], @@ -73,9 +83,11 @@ export const alias = new Map([ ["KM", {type: "medicationStatement", alias: ["Therapieart"]}], //Knochenmarktransplantation ["59847-4", {type: "observation", alias: ["loinc", "morph"]}], //Morphologie ["year_of_diagnosis", {type: "conditionRangeDate"}], + ["year_of_primary_diagnosis", {type: "primaryConditionRangeDate"}], ["sample_kind", {type: "specimen", alias: ["specimentype"]}], ["pat_with_samples", {type: "hasSpecimen"}], ["age_at_diagnosis", {type: "conditionRangeAge"}], + ["age_at_primary_diagnosis", {type: "primaryConditionRangeAge"}], ["21908-9", {type: "observation", alias: ["loinc", "uiccstadiumcs"]}], //uicc TODO 2 profiles TNMc and TNMp is that a problem? ["21905-5", {type: "TNM-x", alias: ["loinc", "TNMTCS"]}], //tnm component ["21906-3", {type: "TNM-x", alias: ["loinc", "TNMNCS"]}], //tnm component @@ -99,4 +111,4 @@ export const alias = new Map([ ["75186-7", {type: "observation", alias: ["loinc", "vitalstatuscs"]}], //Vitalstatus //["Organization", {type: "Organization"}], ["Organization", {type: "department"}], - ]) \ No newline at end of file + ]) diff --git a/packages/lib/src/stores/catalogue.ts b/packages/lib/src/stores/catalogue.ts index d10286d2..a457a5fd 100644 --- a/packages/lib/src/stores/catalogue.ts +++ b/packages/lib/src/stores/catalogue.ts @@ -10,7 +10,7 @@ import type { QueryItem } from "../types/queryData"; */ export const catalogue = writable([]); -export const openTreeNodes = writable([]); +export const openTreeNodes = writable>(new Map()); export const activeNumberInputs = writable([]); diff --git a/packages/lib/src/types/treeData.ts b/packages/lib/src/types/treeData.ts index 4b134127..f12d6fdc 100644 --- a/packages/lib/src/types/treeData.ts +++ b/packages/lib/src/types/treeData.ts @@ -3,7 +3,10 @@ export type TreeNode = Category[] |Category | Criteria | AggregatedValue[] | Agg export type Category = { key: string; name: string; - childCategories?: Category[] + childCategories?: Category[]; + // TODO: Discuss naming with Mats, as this has another meaning than descrtiption in criteria + description?: string; + subCategoryName?: string; } | { key: string; name: string; @@ -11,6 +14,7 @@ export type Category = { fieldType: 'single-select' | 'autocomplete' | 'number'; type: 'EQUALS' | 'BETWEEN'; criteria: | Criteria[]; + description?: string; }