diff --git a/apps/directory/src/components/report-components/ReportStudyDetails.vue b/apps/directory/src/components/report-components/ReportStudyDetails.vue
new file mode 100644
index 0000000000..a354d09940
--- /dev/null
+++ b/apps/directory/src/components/report-components/ReportStudyDetails.vue
@@ -0,0 +1,38 @@
+
+
+
+
+
diff --git a/apps/directory/src/components/report-components/StudyReportInfoCard.vue b/apps/directory/src/components/report-components/StudyReportInfoCard.vue
new file mode 100644
index 0000000000..1ade81678e
--- /dev/null
+++ b/apps/directory/src/components/report-components/StudyReportInfoCard.vue
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+ Also Known In
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/directory/src/functions/viewmodelMapper.js b/apps/directory/src/functions/viewmodelMapper.js
index 776957ab25..d81b0dd593 100644
--- a/apps/directory/src/functions/viewmodelMapper.js
+++ b/apps/directory/src/functions/viewmodelMapper.js
@@ -265,6 +265,16 @@ export function getCollectionDetails(collection, isBiobankWithdrawn) {
};
}
+export function getStudyDetails(study) {
+ const settingsStore = useSettingsStore();
+ const viewmodel = getViewmodel(study, settingsStore.config.studyColumns);
+
+ return {
+ ...study,
+ viewmodel,
+ };
+}
+
export const getBiobankDetails = (biobank) => {
const settingsStore = useSettingsStore();
@@ -336,6 +346,16 @@ export const collectionReportInformation = (collection) => {
collectionReport.certifications = mapQualityStandards(collection.quality);
}
+ if (collection.studies) {
+ collectionReport.studies = collection.studies.map((study) => {
+ return {
+ id: study.id,
+ title: study.title,
+ report: `/study/${study.id}`,
+ };
+ });
+ }
+
collectionReport.collaboration = [];
if (collection.collaboration_commercial) {
@@ -357,6 +377,14 @@ export const collectionReportInformation = (collection) => {
return collectionReport;
};
+export const getStudyReportInformation = (study) => {
+ const studyReport = {};
+
+ studyReport.also_known = study.also_known ? mapAlsoKnownIn(study) : undefined;
+
+ return studyReport;
+};
+
export const mapNetworkInfo = (data) => {
return data.network.map((network) => {
return {
diff --git a/apps/directory/src/property-config/initialCollectionColumns.js b/apps/directory/src/property-config/initialCollectionColumns.js
index a707dcbb58..ec115e3b26 100644
--- a/apps/directory/src/property-config/initialCollectionColumns.js
+++ b/apps/directory/src/property-config/initialCollectionColumns.js
@@ -107,6 +107,8 @@ const initialCollectionColumns = [
"sub_collections.withdrawn",
"collaboration_commercial",
"collaboration_non_for_profit",
+ "studies.id",
+ "studies.title",
...ContactInfoColumns,
...HeadInfoColumns,
],
diff --git a/apps/directory/src/property-config/initialStudyColumns.js b/apps/directory/src/property-config/initialStudyColumns.js
new file mode 100644
index 0000000000..4dfc45d951
--- /dev/null
+++ b/apps/directory/src/property-config/initialStudyColumns.js
@@ -0,0 +1,23 @@
+const initialStudyColumns = [
+ { label: "Id:", column: "id", type: "string", showCopyIcon: true },
+ { label: "Title:", column: "title", type: "string" },
+ { label: "Description:", column: "description", type: "string" },
+ { label: "Type:", column: "type", type: "string" },
+ { label: "Sex:", column: { sex: ["label"] }, type: "array" },
+ { label: "Number of subjects:", column: "number_of_subjects", type: "int" },
+ {
+ label: "Age:",
+ type: "range",
+ min: "age_high",
+ max: "age_low",
+ unit: "age_unit",
+ unit_column: { age_unit: ["label"] },
+ },
+ {
+ label: "Also Known In:",
+ column: { also_known: ["name_system", "url"] },
+ type: "object",
+ },
+];
+
+export default initialStudyColumns;
diff --git a/apps/directory/src/router/index.js b/apps/directory/src/router/index.js
index 69ab8141dc..f9728b66b9 100644
--- a/apps/directory/src/router/index.js
+++ b/apps/directory/src/router/index.js
@@ -5,6 +5,7 @@ import Landingpage from "../views/Landingpage.vue";
import BiobankReport from "../views/BiobankReport.vue";
import NetworkReport from "../views/NetworkReport.vue";
import CollectionReport from "../views/CollectionReport.vue";
+import StudyReport from "../views/StudyReport.vue";
import ConfigurationScreen from "../views/ConfigurationScreen.vue";
import { useSettingsStore } from "../stores/settingsStore";
@@ -32,6 +33,11 @@ const router = createRouter({
component: BiobankReport,
},
{ path: "/network/:id", name: "networkdetails", component: NetworkReport },
+ {
+ path: "/study/:id",
+ name: "studydetails",
+ component: StudyReport,
+ },
{
path: "/configuration",
component: ConfigurationScreen,
diff --git a/apps/directory/src/stores/settingsStore.js b/apps/directory/src/stores/settingsStore.js
index dbccd45892..a0f7e08d84 100644
--- a/apps/directory/src/stores/settingsStore.js
+++ b/apps/directory/src/stores/settingsStore.js
@@ -7,6 +7,7 @@ import initialBiobankColumns from "../property-config/initialBiobankColumns";
import initialBiobankReportColumns from "../property-config/initialBiobankReportColumns";
import initialLandingpage from "../property-config/initialLandingpage";
import { QueryEMX2 } from "molgenis-components";
+import initialStudyColumns from "../property-config/initialStudyColumns";
/**
* Settings store is where all the configuration of the application is handled.
* This means that user config from the database is merged with the defaults here.
@@ -27,6 +28,7 @@ export const useSettingsStore = defineStore("settingsStore", () => {
biobankColumns: initialBiobankColumns,
biobankReportColumns: initialBiobankReportColumns,
collectionColumns: initialCollectionColumns,
+ studyColumns: initialStudyColumns,
filterFacets: initialFilterFacets,
filterMenuInitiallyFolded: false,
biobankCardShowCollections: true,
diff --git a/apps/directory/src/stores/studyStore.ts b/apps/directory/src/stores/studyStore.ts
new file mode 100644
index 0000000000..fcf31377ab
--- /dev/null
+++ b/apps/directory/src/stores/studyStore.ts
@@ -0,0 +1,41 @@
+import { defineStore } from "pinia";
+//@ts-ignore
+import { QueryEMX2 } from "molgenis-components";
+import { useSettingsStore } from "./settingsStore";
+
+export const useStudyStore = defineStore("studyStore", () => {
+ const settingsStore = useSettingsStore();
+
+ const studyColumns = settingsStore.config.studyColumns;
+ const graphqlEndpoint = settingsStore.config.graphqlEndpoint;
+
+ function getStudyColumns() {
+ const properties = studyColumns
+ .filter((column) => column.column)
+ .flatMap((studyColumn) => studyColumn.column);
+
+ const rangeProperties = studyColumns.filter(
+ (column) => column.type === "range"
+ );
+ for (const property of rangeProperties) {
+ properties.push(property.min, property.max, property.unit_column);
+ }
+ return properties;
+ }
+
+ async function getStudyReport(id: string) {
+ const studyReportQuery = new QueryEMX2(graphqlEndpoint)
+ .table("Studies")
+ .select(getStudyColumns())
+ .orderBy("Studies", "id", "asc")
+ .where("id")
+ .like(id);
+ const reportResults = await studyReportQuery.execute();
+
+ return reportResults;
+ }
+
+ return {
+ getStudyReport,
+ };
+});
diff --git a/apps/directory/src/views/StudyReport.vue b/apps/directory/src/views/StudyReport.vue
new file mode 100644
index 0000000000..c198547b01
--- /dev/null
+++ b/apps/directory/src/views/StudyReport.vue
@@ -0,0 +1,77 @@
+
+
+
+
+
diff --git a/backend/molgenis-emx2-datamodels/src/test/java/org/molgenis/emx2/datamodels/TestLoaders.java b/backend/molgenis-emx2-datamodels/src/test/java/org/molgenis/emx2/datamodels/TestLoaders.java
index 02c7837667..5be2e34617 100644
--- a/backend/molgenis-emx2-datamodels/src/test/java/org/molgenis/emx2/datamodels/TestLoaders.java
+++ b/backend/molgenis-emx2-datamodels/src/test/java/org/molgenis/emx2/datamodels/TestLoaders.java
@@ -93,7 +93,7 @@ public void test08DataCatalogueNetworkStagingLoader() {
public void test09DirectoryLoader() {
Schema directory = database.createSchema(DIRECTORY_TEST);
DataModels.Regular.BIOBANK_DIRECTORY.getImportTask(directory, true).run();
- assertEquals(10, directory.getTableNames().size());
+ assertEquals(11, directory.getTableNames().size());
}
@Test
diff --git a/data/biobank-directory/demo/AlsoKnownIn.csv b/data/biobank-directory/demo/AlsoKnownIn.csv
index 33f9241956..6b313bd33c 100644
--- a/data/biobank-directory/demo/AlsoKnownIn.csv
+++ b/data/biobank-directory/demo/AlsoKnownIn.csv
@@ -1,4 +1,5 @@
id,name_system,pid,url,national_node,label
bbmri-eric:akiID:NL_00001,Catalogue in The Netherlands,cat_neth_biobank2,https://linktopid/cat_neth_biobank2.nl,NL,Catalogue in The Netherlands
bbmri-eric:akiID:NL_00002,Collection catalogue of The Netherlands,,https://collections@catalogue.nl,NL,Collection catalogue of The Netherlands
-bbmri-eric:akiID:DE_00001,Another DataCatalogue,,https://another_data_catalogue.eu,DE,Another DataCatalogue
\ No newline at end of file
+bbmri-eric:akiID:DE_00001,Another DataCatalogue,,https://another_data_catalogue.eu,DE,Another DataCatalogue
+bbmri-eric:akiID:DE_00002,A catalogue of studies,,https://a_study_catalogue.eu/112233,EXT,A Catalogue With Studies
\ No newline at end of file
diff --git a/data/biobank-directory/demo/Collections.csv b/data/biobank-directory/demo/Collections.csv
index cdf6c25ff2..edb9db446b 100644
--- a/data/biobank-directory/demo/Collections.csv
+++ b/data/biobank-directory/demo/Collections.csv
@@ -1,4 +1,4 @@
-id,name,acronym,description,url,location,country,latitude,longitude,head,contact,national_node,withdrawn,parent_collection,biobank,biobank_label,network,combined_network,also_known,type,data_categories,order_of_magnitude,size,categories,timestamp,number_of_donors,order_of_magnitude_donors,sex,diagnosis_available,age_low,age_high,age_unit,materials,storage_temperatures,body_part_examined,imaging_modality,image_dataset_type,collaboration_commercial,collaboration_non_for_profit,data_use,commercial_use,access_fee,access_joint_project,access_description,access_uri,sop,combined_quality
-bbmri-eric:ID:DE_biobank1:collection:coll1,Collection1 of biobank1,coll1,The first collection of biobank1,,Berlin,DE,,,bbmri-eric:contactID:DE_collection1,bbmri-eric:contactID:DE_collection1,DE,false,,bbmri-eric:ID:DE_biobank1,Biobank1,bbmri-eric:networkID:DE_nw_coll1,"bbmri-eric:networkID:DE_network1,bbmri-eric:networkID:DE_nw_coll1",bbmri-eric:akiID:DE_00001,"COHORT,RD","MEDICAL_RECORDS,BLOOD",3,1333,"rare_disease,oncology",,600,2,"MALE,NEUTERED_MALE","ORPHA:100001,ORPHA:101009",2,88,YEAR,"DNA,PERIPHERAL_BLOOD_CELLS",temperature2to10,T-04000,BDUS,1.2.840.10008.5.1.4.1.1.104.2,true,true,DUO_0000003,true,"samples,data,images","data,images",,,"sample_transport_sop,data_processing_sop",accredited
-bbmri-eric:ID:NL_biobank2:collection:coll2,The second collection of biobank2,coll2_bb2,This is the description of the second collection of biobank2,,Amsterdam,NL,,,bbmri-eric:contactID:head_coll2,bbmri-eric:contactID:NL_person1,NL,false,,bbmri-eric:ID:NL_biobank2,Biobank2,bbmri-eric:networkID:EU_network,bbmri-eric:networkID:EU_network,bbmri-eric:akiID:NL_00001,"CASE_CONTROL,QUALITY_CONTROL","BIOLOGICAL_SAMPLES,IMAGING_DATA,NATIONAL_REGISTRIES",4,11000,"covid19,paediatrics,autoimmune",,9000,3,FEMALE,"urn:miriam:icd:W00,ORPHA:3000",0,90,YEAR,"FECES,PATHOGEN,URINE",temperatureLN,T-58200,CR,1.2.840.10008.5.1.4.1.1.130,true,true,DUO_0000042,false,"samples,data,images","samples,data,images",Access is possible need to pay a fee,,"sample_processing_sop,sample_transport_sop,data_transport_sop,data_storage_sop",accredited
-bbmri-eric:ID:NL_biobank2:collection:coll2a,Subcollection1,sub_col1,The first sub collection of collection2,,Amsterdam,NL,,,bbmri-eric:contactID:head_coll2,bbmri-eric:contactID:NL_person1,NL,false,bbmri-eric:ID:NL_biobank2:collection:coll2,bbmri-eric:ID:NL_biobank2,Biobank2,bbmri-eric:networkID:EU_network,bbmri-eric:networkID:EU_network,bbmri-eric:akiID:NL_00002,"CROSS_SECTIONAL,POPULATION_BASED","ANTIBODIES,PHYSIOLOGICAL_BIOCHEMICAL_MEASUREMENTS",2,589,covid19,,133,2,MALE,"ORPHA:1388,ORPHA:139552,urn:miriam:icd:A00.9",5,67,YEAR,"NASAL_SWAB,PLASMA","temperature2to10,temperature-18to-35",T-15710,BMD,1.2.840.10008.5.1.4.1.1.11.1,true,true,DUO_0000024,true,data,data,,,"sample_storage_sop,data_processing_sop,data_transport_sop,data_storage_sop",accredited
\ No newline at end of file
+id,name,acronym,description,url,location,country,latitude,longitude,head,contact,national_node,withdrawn,parent_collection,biobank,biobank_label,network,combined_network,also_known,type,data_categories,order_of_magnitude,size,categories,timestamp,number_of_donors,order_of_magnitude_donors,sex,diagnosis_available,age_low,age_high,age_unit,materials,storage_temperatures,body_part_examined,imaging_modality,image_dataset_type,collaboration_commercial,collaboration_non_for_profit,data_use,commercial_use,access_fee,access_joint_project,access_description,access_uri,sop,combined_quality,studies
+bbmri-eric:ID:DE_biobank1:collection:coll1,Collection1 of biobank1,coll1,The first collection of biobank1,,Berlin,DE,,,bbmri-eric:contactID:DE_collection1,bbmri-eric:contactID:DE_collection1,DE,false,,bbmri-eric:ID:DE_biobank1,Biobank1,bbmri-eric:networkID:DE_nw_coll1,"bbmri-eric:networkID:DE_network1,bbmri-eric:networkID:DE_nw_coll1",bbmri-eric:akiID:DE_00001,"COHORT,RD","MEDICAL_RECORDS,BLOOD",3,1333,"rare_disease,oncology",,600,2,"MALE,NEUTERED_MALE","ORPHA:100001,ORPHA:101009",2,88,YEAR,"DNA,PERIPHERAL_BLOOD_CELLS",temperature2to10,T-04000,BDUS,1.2.840.10008.5.1.4.1.1.104.2,true,true,DUO_0000003,true,"samples,data,images","data,images",,,"sample_transport_sop,data_processing_sop",accredited,bbmri-eric:studyID:DE_112233
+bbmri-eric:ID:NL_biobank2:collection:coll2,The second collection of biobank2,coll2_bb2,This is the description of the second collection of biobank2,,Amsterdam,NL,,,bbmri-eric:contactID:head_coll2,bbmri-eric:contactID:NL_person1,NL,false,,bbmri-eric:ID:NL_biobank2,Biobank2,bbmri-eric:networkID:EU_network,bbmri-eric:networkID:EU_network,bbmri-eric:akiID:NL_00001,"CASE_CONTROL,QUALITY_CONTROL","BIOLOGICAL_SAMPLES,IMAGING_DATA,NATIONAL_REGISTRIES",4,11000,"covid19,paediatrics",,9000,3,FEMALE,"urn:miriam:icd:W00,ORPHA:3000",0,90,YEAR,"FECES,PATHOGEN,URINE",temperatureLN,T-58200,CR,1.2.840.10008.5.1.4.1.1.130,true,true,DUO_0000042,false,"samples,data,images","samples,data,images",Access is possible need to pay a fee,,"sample_processing_sop,sample_transport_sop,data_transport_sop,data_storage_sop",accredited,
+bbmri-eric:ID:NL_biobank2:collection:coll2a,Subcollection1,sub_col1,The first sub collection of collection2,,Amsterdam,NL,,,bbmri-eric:contactID:head_coll2,bbmri-eric:contactID:NL_person1,NL,false,bbmri-eric:ID:NL_biobank2:collection:coll2,bbmri-eric:ID:NL_biobank2,Biobank2,bbmri-eric:networkID:EU_network,bbmri-eric:networkID:EU_network,bbmri-eric:akiID:NL_00002,"CROSS_SECTIONAL,POPULATION_BASED","ANTIBODIES,PHYSIOLOGICAL_BIOCHEMICAL_MEASUREMENTS",2,589,covid19,,133,2,MALE,"ORPHA:1388,ORPHA:139552,urn:miriam:icd:A00.9",5,67,YEAR,"NASAL_SWAB,PLASMA","temperature2to10,temperature-18to-35",T-15710,BMD,1.2.840.10008.5.1.4.1.1.11.1,true,true,DUO_0000024,true,data,data,,,"sample_storage_sop,data_processing_sop,data_transport_sop,data_storage_sop",accredited,
\ No newline at end of file
diff --git a/data/biobank-directory/demo/NationalNodes.csv b/data/biobank-directory/demo/NationalNodes.csv
index b63fd03f19..742f894130 100644
--- a/data/biobank-directory/demo/NationalNodes.csv
+++ b/data/biobank-directory/demo/NationalNodes.csv
@@ -1,4 +1,5 @@
id,description,dns,contact_persons,data_refresh,date_start,date_end
DE,Germany,,,manual,,
EU,European Union,,,manual,,
-NL,Netherlands,https://external_server.nl,,external_server,,
\ No newline at end of file
+NL,Netherlands,https://external_server.nl,,external_server,,
+EXT,External Countries,,,manual,,
\ No newline at end of file
diff --git a/data/biobank-directory/demo/Studies.csv b/data/biobank-directory/demo/Studies.csv
new file mode 100644
index 0000000000..d709f2bd36
--- /dev/null
+++ b/data/biobank-directory/demo/Studies.csv
@@ -0,0 +1,2 @@
+id,title,description,type,sex,age_high,age_low,age_unit,also_known,national_node
+bbmri-eric:studyID:DE_112233,Dummy study,This is just a fake study with demo data,Interventional,"FEMALE,MALE",10,50,YEAR,bbmri-eric:akiID:DE_00002,EXT
diff --git a/data/biobank-directory/molgenis.csv b/data/biobank-directory/molgenis.csv
index 2ececb3b89..7887562cdc 100644
--- a/data/biobank-directory/molgenis.csv
+++ b/data/biobank-directory/molgenis.csv
@@ -79,6 +79,7 @@ Collections,,biobank_label,Biobank Label,string,,true,,"Name of the biobank, to
Collections,,network,Network,ref_array,,false,,"Reference to a network ID, to which the collection belongs to.",,Networks,,${name},,,,,
Collections,,combined_network,Combined Network,ref_array,,false,,"Reference to one or more network IDs, to which the collection belongs directly or indirectly (i.e., either the collection is explicitly marked as part of the network or its biobank is).",,Networks,,${name},,,,,
Collections,,also_known,Also Known In,ref_array,,false,,The collection also exists in …,,AlsoKnownIn,,${name_system},,,,,
+Collections,,studies,Studies,ref_array,,false,,A link to studies during which the collection was generated,,Studies,,${title},,,,,
Collections,,characteristics,Characteristics,heading,,false,,Collection Characteristics,,,,,,,,,
Collections,,type,Collection Types,ontology_array,,true,,Type(s) of the collection - MIABIS-2.0-19.,DirectoryOntologies,CollectionTypes,,${label},,,,,
Collections,,data_categories,Data Categories,ontology_array,,true,,Denotes which types of data are available (MIABIS-2.0-13).,DirectoryOntologies,DataCategories,,${label},,,,,
@@ -161,4 +162,17 @@ Persons,,role,Role of the Person,text,,false,,Official role of the person.,,,,,,
Persons,,biobanks,Biobanks,refback,,false,true,Biobanks the person is connected to.,,Biobanks,contact,,,,,,
Persons,,collections,Collections,refback,,false,true,Collections the person is connected to.,,Collections,contact,,,,,,
Persons,,networks,Networks,refback,,false,true,Networks the person is connected to.,,Networks,contact,,,,,,
-Persons,,national_node,National Node,ref,,true,,The person originates from this national node.,,NationalNodes,,${description},,,,,
\ No newline at end of file
+Persons,,national_node,National Node,ref,,true,,The person originates from this national node.,,NationalNodes,,${description},,,,,
+Studies,,,,,,,,Table with information about the studies in which context the collection was generated,,,,,,,,,
+Studies,,id,ID,string,1,true,,"Unique ID of the study, prefixed with bbmri-eric:studyID:
",,,,,,,,,
+Studies,,title,Title,text,,true,,The title of the study,,,,,,,,,
+Studies,,description,Description,text,,false,,A text describing the study,,,,,,,,,
+Studies,,type,Type,string,,false,,"The type of study (Observational, Interventional).",,,,,,,,,
+Studies,,sex,Sex,ontology_array,,false,,"The sex of the individuals that participated to the study",DirectoryOntologies,SexTypes,,,,,,,
+Studies,,age_low,Age Low,int,,false,,Age of youngest sample donor at time of sample donation - MIABIS-2.0-10.,,,,,,,,,
+Studies,,age_high,Age High,int,,false,,Age of oldest sample donor at time of sample donation - MIABIS-2.0-11.,,,,,,,,,
+Studies,,age_unit,Age Unit,ontology,,false,,"Unit defining Age Low and Age High. Can be one of the following values: YEAR, MONTH, WEEK, DAY - MIABIS-2.0-08.",DirectoryOntologies,AgeUnits,,${label},,,,,
+Studies,,number_of_subjects,Number of subjects,int,,false,,"The number of subjects that participated to the study",,,,,,,,,
+Studies,,also_known,Also Known In,ref_array,,false,,The study also exists in …,,AlsoKnownIn,,${name_system},,,,,
+Studies,,collections,Collections,refback,,false,true,,,Collections,studies,,,,,,
+Studies,,national_node,National Node,ref,,true,,The study originates from this national node.,,NationalNodes,,${description},,,,,
\ No newline at end of file